summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:48:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:48:59 +0000
commitc484829272cd13a738e35412498e12f2c9a194ac (patch)
treea1f5ec09629ee895bd3963fa8820b45f2f4c574b /src
parentInitial commit. (diff)
downloadliborcus-c484829272cd13a738e35412498e12f2c9a194ac.tar.xz
liborcus-c484829272cd13a738e35412498e12f2c9a194ac.zip
Adding upstream version 0.19.2.upstream/0.19.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am721
-rw-r--r--src/Makefile.in2986
-rw-r--r--src/cli_global.cpp63
-rw-r--r--src/cli_global.hpp39
-rw-r--r--src/include/Makefile.am9
-rw-r--r--src/include/Makefile.in726
-rw-r--r--src/include/cpu_features.hpp44
-rw-r--r--src/include/filesystem_env.hpp23
-rw-r--r--src/include/mock_spreadsheet.hpp179
-rw-r--r--src/include/mso/Makefile.am3
-rw-r--r--src/include/mso/Makefile.in542
-rw-r--r--src/include/mso/encryption_info.hpp37
-rw-r--r--src/include/numeric_parser.hpp216
-rw-r--r--src/include/ostream_utils.hpp34
-rw-r--r--src/include/test_global.hpp57
-rw-r--r--src/liborcus/Makefile.am590
-rw-r--r--src/liborcus/Makefile.in4283
-rw-r--r--src/liborcus/common_test.cpp245
-rw-r--r--src/liborcus/config.cpp54
-rw-r--r--src/liborcus/constants.inl.in4
-rw-r--r--src/liborcus/css_document_tree.cpp647
-rw-r--r--src/liborcus/css_document_tree_test.cpp690
-rw-r--r--src/liborcus/css_selector.cpp214
-rw-r--r--src/liborcus/detection_result.cpp20
-rw-r--r--src/liborcus/detection_result.hpp26
-rw-r--r--src/liborcus/dom_tree.cpp741
-rw-r--r--src/liborcus/dom_tree_test.cpp123
-rw-r--r--src/liborcus/format_detection.cpp135
-rw-r--r--src/liborcus/formula_result.cpp120
-rw-r--r--src/liborcus/formula_result.hpp72
-rw-r--r--src/liborcus/gnumeric_cell_context.cpp377
-rw-r--r--src/liborcus/gnumeric_cell_context.hpp85
-rw-r--r--src/liborcus/gnumeric_cell_context_test.cpp386
-rw-r--r--src/liborcus/gnumeric_context.cpp453
-rw-r--r--src/liborcus/gnumeric_context.hpp67
-rw-r--r--src/liborcus/gnumeric_detection_handler.cpp83
-rw-r--r--src/liborcus/gnumeric_detection_handler.hpp31
-rw-r--r--src/liborcus/gnumeric_filter_context.cpp256
-rw-r--r--src/liborcus/gnumeric_filter_context.hpp54
-rw-r--r--src/liborcus/gnumeric_handler.cpp32
-rw-r--r--src/liborcus/gnumeric_handler.hpp36
-rw-r--r--src/liborcus/gnumeric_names_context.cpp110
-rw-r--r--src/liborcus/gnumeric_names_context.hpp49
-rw-r--r--src/liborcus/gnumeric_namespace_types.cpp38
-rw-r--r--src/liborcus/gnumeric_namespace_types.hpp26
-rw-r--r--src/liborcus/gnumeric_sheet_context.cpp819
-rw-r--r--src/liborcus/gnumeric_sheet_context.hpp112
-rw-r--r--src/liborcus/gnumeric_sheet_context_test.cpp119
-rw-r--r--src/liborcus/gnumeric_styles_context.cpp342
-rw-r--r--src/liborcus/gnumeric_styles_context.hpp59
-rw-r--r--src/liborcus/gnumeric_token_constants.hpp21
-rw-r--r--src/liborcus/gnumeric_token_constants.inl258
-rw-r--r--src/liborcus/gnumeric_tokens.cpp20
-rw-r--r--src/liborcus/gnumeric_tokens.hpp23
-rw-r--r--src/liborcus/gnumeric_tokens.inl263
-rw-r--r--src/liborcus/gnumeric_types.cpp174
-rw-r--r--src/liborcus/gnumeric_types.hpp149
-rw-r--r--src/liborcus/gnumeric_value_format_parser.cpp131
-rw-r--r--src/liborcus/gnumeric_value_format_parser.hpp46
-rw-r--r--src/liborcus/impl_utils.hpp18
-rw-r--r--src/liborcus/info.cpp31
-rw-r--r--src/liborcus/interface.cpp37
-rw-r--r--src/liborcus/json_document_tree.cpp1777
-rw-r--r--src/liborcus/json_document_tree_test.cpp862
-rw-r--r--src/liborcus/json_map_tree.cpp786
-rw-r--r--src/liborcus/json_map_tree.hpp197
-rw-r--r--src/liborcus/json_map_tree_test.cpp130
-rw-r--r--src/liborcus/json_structure_mapper.cpp77
-rw-r--r--src/liborcus/json_structure_mapper.hpp37
-rw-r--r--src/liborcus/json_structure_tree.cpp720
-rw-r--r--src/liborcus/json_structure_tree_test.cpp201
-rw-r--r--src/liborcus/json_util.cpp27
-rw-r--r--src/liborcus/json_util.hpp21
-rw-r--r--src/liborcus/measurement.cpp214
-rw-r--r--src/liborcus/number_utils.cpp74
-rw-r--r--src/liborcus/number_utils.hpp22
-rw-r--r--src/liborcus/odf_document_styles_context.cpp73
-rw-r--r--src/liborcus/odf_document_styles_context.hpp50
-rw-r--r--src/liborcus/odf_helper.cpp260
-rw-r--r--src/liborcus/odf_helper.hpp55
-rw-r--r--src/liborcus/odf_helper_test.cpp51
-rw-r--r--src/liborcus/odf_namespace_types.cpp12
-rw-r--r--src/liborcus/odf_namespace_types.hpp16
-rw-r--r--src/liborcus/odf_namespace_types_cpp.inl63
-rw-r--r--src/liborcus/odf_namespace_types_hpp.inl31
-rw-r--r--src/liborcus/odf_number_format_context.cpp1126
-rw-r--r--src/liborcus/odf_number_format_context.hpp180
-rw-r--r--src/liborcus/odf_para_context.cpp165
-rw-r--r--src/liborcus/odf_para_context.hpp62
-rw-r--r--src/liborcus/odf_style_context.cpp774
-rw-r--r--src/liborcus/odf_style_context.hpp51
-rw-r--r--src/liborcus/odf_styles.cpp110
-rw-r--r--src/liborcus/odf_styles.hpp127
-rw-r--r--src/liborcus/odf_styles_context.cpp403
-rw-r--r--src/liborcus/odf_styles_context.hpp70
-rw-r--r--src/liborcus/odf_token_constants.hpp21
-rw-r--r--src/liborcus/odf_token_constants.inl2280
-rw-r--r--src/liborcus/odf_tokens.cpp23
-rw-r--r--src/liborcus/odf_tokens.hpp23
-rw-r--r--src/liborcus/odf_tokens.inl2285
-rw-r--r--src/liborcus/ods_content_xml_context.cpp900
-rw-r--r--src/liborcus/ods_content_xml_context.hpp138
-rw-r--r--src/liborcus/ods_dde_links_context.cpp49
-rw-r--r--src/liborcus/ods_dde_links_context.hpp42
-rw-r--r--src/liborcus/ods_session_data.cpp42
-rw-r--r--src/liborcus/ods_session_data.hpp82
-rw-r--r--src/liborcus/ooxml_content_types.cpp74
-rw-r--r--src/liborcus/ooxml_content_types.hpp49
-rw-r--r--src/liborcus/ooxml_global.cpp97
-rw-r--r--src/liborcus/ooxml_global.hpp48
-rw-r--r--src/liborcus/ooxml_namespace_types.cpp52
-rw-r--r--src/liborcus/ooxml_namespace_types.hpp44
-rw-r--r--src/liborcus/ooxml_schemas.cpp70
-rw-r--r--src/liborcus/ooxml_schemas.hpp47
-rw-r--r--src/liborcus/ooxml_token_constants.hpp21
-rw-r--r--src/liborcus/ooxml_token_constants.inl3519
-rw-r--r--src/liborcus/ooxml_tokens.cpp29
-rw-r--r--src/liborcus/ooxml_tokens.hpp21
-rw-r--r--src/liborcus/ooxml_tokens.inl3524
-rw-r--r--src/liborcus/ooxml_types.cpp27
-rw-r--r--src/liborcus/ooxml_types.hpp73
-rw-r--r--src/liborcus/opc_context.cpp310
-rw-r--r--src/liborcus/opc_context.hpp90
-rw-r--r--src/liborcus/opc_reader.cpp306
-rw-r--r--src/liborcus/opc_reader.hpp127
-rw-r--r--src/liborcus/opc_token_constants.hpp20
-rw-r--r--src/liborcus/opc_token_constants.inl31
-rw-r--r--src/liborcus/opc_tokens.inl36
-rw-r--r--src/liborcus/orcus_csv.cpp196
-rw-r--r--src/liborcus/orcus_gnumeric.cpp163
-rw-r--r--src/liborcus/orcus_import_ods.cpp51
-rw-r--r--src/liborcus/orcus_import_xlsx.cpp51
-rw-r--r--src/liborcus/orcus_json.cpp513
-rw-r--r--src/liborcus/orcus_ods.cpp230
-rw-r--r--src/liborcus/orcus_parquet.cpp547
-rw-r--r--src/liborcus/orcus_xls_xml.cpp134
-rw-r--r--src/liborcus/orcus_xlsx.cpp824
-rw-r--r--src/liborcus/orcus_xml.cpp702
-rw-r--r--src/liborcus/orcus_xml_impl.cpp22
-rw-r--r--src/liborcus/orcus_xml_impl.hpp51
-rw-r--r--src/liborcus/orcus_xml_map_def.cpp299
-rw-r--r--src/liborcus/session_context.cpp30
-rw-r--r--src/liborcus/session_context.hpp58
-rw-r--r--src/liborcus/spreadsheet_iface_util.cpp53
-rw-r--r--src/liborcus/spreadsheet_iface_util.hpp36
-rw-r--r--src/liborcus/spreadsheet_impl_types.cpp50
-rw-r--r--src/liborcus/spreadsheet_impl_types.hpp39
-rw-r--r--src/liborcus/spreadsheet_interface.cpp159
-rw-r--r--src/liborcus/spreadsheet_types.cpp763
-rw-r--r--src/liborcus/string_helper.cpp40
-rw-r--r--src/liborcus/string_helper.hpp21
-rw-r--r--src/liborcus/xls_xml_context.cpp2396
-rw-r--r--src/liborcus/xls_xml_context.hpp334
-rw-r--r--src/liborcus/xls_xml_detection_handler.cpp113
-rw-r--r--src/liborcus/xls_xml_detection_handler.hpp31
-rw-r--r--src/liborcus/xls_xml_handler.cpp22
-rw-r--r--src/liborcus/xls_xml_handler.hpp35
-rw-r--r--src/liborcus/xls_xml_namespace_types.cpp32
-rw-r--r--src/liborcus/xls_xml_namespace_types.hpp28
-rw-r--r--src/liborcus/xls_xml_token_constants.hpp20
-rw-r--r--src/liborcus/xls_xml_token_constants.inl992
-rw-r--r--src/liborcus/xls_xml_tokens.cpp21
-rw-r--r--src/liborcus/xls_xml_tokens.hpp20
-rw-r--r--src/liborcus/xls_xml_tokens.inl997
-rw-r--r--src/liborcus/xlsx_autofilter_context.cpp140
-rw-r--r--src/liborcus/xlsx_autofilter_context.hpp64
-rw-r--r--src/liborcus/xlsx_conditional_format_context.cpp878
-rw-r--r--src/liborcus/xlsx_conditional_format_context.hpp68
-rw-r--r--src/liborcus/xlsx_drawing_context.cpp173
-rw-r--r--src/liborcus/xlsx_drawing_context.hpp48
-rw-r--r--src/liborcus/xlsx_handler.cpp76
-rw-r--r--src/liborcus/xlsx_handler.hpp91
-rw-r--r--src/liborcus/xlsx_helper.cpp33
-rw-r--r--src/liborcus/xlsx_helper.hpp18
-rw-r--r--src/liborcus/xlsx_pivot_context.cpp1734
-rw-r--r--src/liborcus/xlsx_pivot_context.hpp118
-rw-r--r--src/liborcus/xlsx_revision_context.cpp578
-rw-r--r--src/liborcus/xlsx_revision_context.hpp53
-rw-r--r--src/liborcus/xlsx_session_data.cpp47
-rw-r--r--src/liborcus/xlsx_session_data.hpp92
-rw-r--r--src/liborcus/xlsx_shared_strings_context.cpp253
-rw-r--r--src/liborcus/xlsx_shared_strings_context.hpp48
-rw-r--r--src/liborcus/xlsx_sheet_context.cpp943
-rw-r--r--src/liborcus/xlsx_sheet_context.hpp141
-rw-r--r--src/liborcus/xlsx_sheet_context_test.cpp281
-rw-r--r--src/liborcus/xlsx_styles_context.cpp1055
-rw-r--r--src/liborcus/xlsx_styles_context.hpp86
-rw-r--r--src/liborcus/xlsx_table_context.cpp319
-rw-r--r--src/liborcus/xlsx_table_context.hpp52
-rw-r--r--src/liborcus/xlsx_types.cpp116
-rw-r--r--src/liborcus/xlsx_types.hpp93
-rw-r--r--src/liborcus/xlsx_workbook_context.cpp253
-rw-r--r--src/liborcus/xlsx_workbook_context.hpp65
-rw-r--r--src/liborcus/xml_context_base.cpp348
-rw-r--r--src/liborcus/xml_context_base.hpp192
-rw-r--r--src/liborcus/xml_context_global.cpp106
-rw-r--r--src/liborcus/xml_context_global.hpp71
-rw-r--r--src/liborcus/xml_element_types.cpp19
-rw-r--r--src/liborcus/xml_element_types.hpp30
-rw-r--r--src/liborcus/xml_element_validator.cpp60
-rw-r--r--src/liborcus/xml_element_validator.hpp50
-rw-r--r--src/liborcus/xml_empty_context.cpp44
-rw-r--r--src/liborcus/xml_empty_context.hpp39
-rw-r--r--src/liborcus/xml_map_tree.cpp772
-rw-r--r--src/liborcus/xml_map_tree.hpp316
-rw-r--r--src/liborcus/xml_map_tree_test.cpp274
-rw-r--r--src/liborcus/xml_simple_stream_handler.cpp54
-rw-r--r--src/liborcus/xml_simple_stream_handler.hpp40
-rw-r--r--src/liborcus/xml_stream_handler.cpp139
-rw-r--r--src/liborcus/xml_stream_handler.hpp66
-rw-r--r--src/liborcus/xml_stream_parser.cpp96
-rw-r--r--src/liborcus/xml_stream_parser.hpp84
-rw-r--r--src/liborcus/xml_structure_mapper.cpp84
-rw-r--r--src/liborcus/xml_structure_mapper.hpp40
-rw-r--r--src/liborcus/xml_structure_tree.cpp625
-rw-r--r--src/liborcus/xml_structure_tree_test.cpp286
-rw-r--r--src/liborcus/xml_util.cpp70
-rw-r--r--src/liborcus/xml_util.hpp43
-rw-r--r--src/liborcus/xpath_parser.cpp90
-rw-r--r--src/liborcus/xpath_parser.hpp49
-rw-r--r--src/liborcus/xpath_parser_test.cpp74
-rw-r--r--src/liborcus/yaml_document_tree.cpp856
-rw-r--r--src/liborcus/yaml_document_tree_test.cpp642
-rw-r--r--src/mso/Makefile.am13
-rw-r--r--src/mso/Makefile.in702
-rw-r--r--src/mso/encryption_info.cpp227
-rw-r--r--src/orcus_css_dump.cpp35
-rw-r--r--src/orcus_csv_main.cpp80
-rw-r--r--src/orcus_detect_main.cpp70
-rw-r--r--src/orcus_env_dump.cpp33
-rw-r--r--src/orcus_filter_global.cpp240
-rw-r--r--src/orcus_filter_global.hpp53
-rw-r--r--src/orcus_gnumeric_main.cpp36
-rw-r--r--src/orcus_json_cli.cpp443
-rw-r--r--src/orcus_json_cli.hpp54
-rw-r--r--src/orcus_json_cli_map.cpp57
-rw-r--r--src/orcus_mso_encryption.cpp34
-rw-r--r--src/orcus_ods_main.cpp38
-rw-r--r--src/orcus_ods_styles.cpp44
-rw-r--r--src/orcus_parquet_main.cpp35
-rw-r--r--src/orcus_test_csv.cpp253
-rw-r--r--src/orcus_test_global.cpp98
-rw-r--r--src/orcus_test_global.hpp42
-rw-r--r--src/orcus_test_gnumeric.cpp1386
-rw-r--r--src/orcus_test_import_ods.cpp1065
-rw-r--r--src/orcus_test_json_mapped.cpp99
-rw-r--r--src/orcus_test_ods.cpp958
-rw-r--r--src/orcus_test_parquet.cpp134
-rw-r--r--src/orcus_test_xls_xml.cpp2455
-rw-r--r--src/orcus_test_xlsx.cpp2401
-rw-r--r--src/orcus_test_xml.cpp226
-rw-r--r--src/orcus_test_xml_mapped.cpp321
-rw-r--r--src/orcus_xls_xml_main.cpp38
-rw-r--r--src/orcus_xlsx_main.cpp42
-rw-r--r--src/orcus_xml_main.cpp350
-rw-r--r--src/orcus_yaml_main.cpp195
-rw-r--r--src/orcus_zip_dump.cpp52
-rw-r--r--src/parser/Makefile.am338
-rw-r--r--src/parser/Makefile.in2328
-rw-r--r--src/parser/base64.cpp70
-rw-r--r--src/parser/base64_test.cpp44
-rw-r--r--src/parser/cell_buffer.cpp61
-rw-r--r--src/parser/css_parser_base.cpp337
-rw-r--r--src/parser/css_parser_test.cpp28
-rw-r--r--src/parser/css_types.cpp198
-rw-r--r--src/parser/csv_parser_base.cpp47
-rw-r--r--src/parser/csv_parser_test.cpp29
-rw-r--r--src/parser/exception.cpp141
-rw-r--r--src/parser/json_global.cpp46
-rw-r--r--src/parser/json_parser_base.cpp104
-rw-r--r--src/parser/json_parser_test.cpp28
-rw-r--r--src/parser/json_parser_thread.cpp294
-rw-r--r--src/parser/parser_base.cpp222
-rw-r--r--src/parser/parser_base_test.cpp74
-rw-r--r--src/parser/parser_global.cpp515
-rw-r--r--src/parser/parser_global_test.cpp175
-rw-r--r--src/parser/parser_test_json_validation.cpp439
-rw-r--r--src/parser/parser_test_numeric.cpp105
-rw-r--r--src/parser/parser_test_xml_validation.cpp95
-rw-r--r--src/parser/sax_ns_parser_test.cpp78
-rw-r--r--src/parser/sax_parser_base.cpp421
-rw-r--r--src/parser/sax_parser_test.cpp67
-rw-r--r--src/parser/sax_token_parser.cpp110
-rw-r--r--src/parser/sax_token_parser_test.cpp239
-rw-r--r--src/parser/sax_token_parser_thread.cpp204
-rw-r--r--src/parser/stream.cpp447
-rw-r--r--src/parser/stream_test.cpp144
-rw-r--r--src/parser/string_pool.cpp137
-rw-r--r--src/parser/string_pool_test.cpp134
-rw-r--r--src/parser/threaded_json_parser_test.cpp187
-rw-r--r--src/parser/threaded_sax_token_parser_test.cpp190
-rw-r--r--src/parser/tokens.cpp44
-rw-r--r--src/parser/types.cpp1454
-rw-r--r--src/parser/types_test.cpp47
-rw-r--r--src/parser/utf8.cpp524
-rw-r--r--src/parser/utf8.hpp28
-rw-r--r--src/parser/utf8_test.cpp170
-rw-r--r--src/parser/win_stdint.h46
-rw-r--r--src/parser/xml_namespace.cpp490
-rw-r--r--src/parser/xml_namespace_test.cpp239
-rw-r--r--src/parser/xml_writer.cpp326
-rw-r--r--src/parser/xml_writer_test.cpp106
-rw-r--r--src/parser/yaml_parser_base.cpp512
-rw-r--r--src/parser/yaml_parser_test.cpp32
-rw-r--r--src/parser/zip_archive.cpp601
-rw-r--r--src/parser/zip_archive_stream.cpp113
-rw-r--r--src/parser/zip_archive_test.cpp98
-rw-r--r--src/python/Makefile.am140
-rw-r--r--src/python/Makefile.in1405
-rw-r--r--src/python/cell.cpp349
-rw-r--r--src/python/cell.hpp44
-rw-r--r--src/python/csv.cpp105
-rw-r--r--src/python/csv.hpp21
-rw-r--r--src/python/document.cpp330
-rw-r--r--src/python/document.hpp83
-rw-r--r--src/python/formula_token.cpp250
-rw-r--r--src/python/formula_token.hpp40
-rw-r--r--src/python/formula_tokens.cpp200
-rw-r--r--src/python/formula_tokens.hpp39
-rw-r--r--src/python/global.cpp65
-rw-r--r--src/python/global.hpp26
-rw-r--r--src/python/gnumeric.cpp58
-rw-r--r--src/python/gnumeric.hpp21
-rw-r--r--src/python/json.cpp290
-rw-r--r--src/python/memory.cpp46
-rw-r--r--src/python/memory.hpp41
-rw-r--r--src/python/named_expression.cpp215
-rw-r--r--src/python/named_expression.hpp42
-rw-r--r--src/python/named_expressions.cpp218
-rw-r--r--src/python/named_expressions.hpp41
-rw-r--r--src/python/ods.cpp58
-rw-r--r--src/python/ods.hpp21
-rw-r--r--src/python/orcus/__init__.py111
-rw-r--r--src/python/orcus/csv.py10
-rw-r--r--src/python/orcus/gnumeric.py10
-rw-r--r--src/python/orcus/json.py10
-rw-r--r--src/python/orcus/ods.py10
-rw-r--r--src/python/orcus/tools/__init__.py9
-rw-r--r--src/python/orcus/tools/bugzilla.py219
-rw-r--r--src/python/orcus/tools/file_processor.py295
-rw-r--r--src/python/orcus/xls_xml.py10
-rw-r--r--src/python/orcus/xlsx.py10
-rw-r--r--src/python/python.cpp186
-rw-r--r--src/python/root.cpp68
-rw-r--r--src/python/root.hpp21
-rw-r--r--src/python/sheet.cpp327
-rw-r--r--src/python/sheet.hpp43
-rw-r--r--src/python/sheet_rows.cpp209
-rw-r--r--src/python/sheet_rows.hpp54
-rw-r--r--src/python/xls_xml.cpp58
-rw-r--r--src/python/xls_xml.hpp21
-rw-r--r--src/python/xlsx.cpp58
-rw-r--r--src/python/xlsx.hpp21
-rw-r--r--src/spreadsheet/Makefile.am90
-rw-r--r--src/spreadsheet/Makefile.in1134
-rw-r--r--src/spreadsheet/auto_filter.cpp116
-rw-r--r--src/spreadsheet/check_dumper.cpp209
-rw-r--r--src/spreadsheet/check_dumper.hpp38
-rw-r--r--src/spreadsheet/config.cpp28
-rw-r--r--src/spreadsheet/csv_dumper.cpp95
-rw-r--r--src/spreadsheet/csv_dumper.hpp38
-rw-r--r--src/spreadsheet/debug_state_dumper.cpp460
-rw-r--r--src/spreadsheet/debug_state_dumper.hpp61
-rw-r--r--src/spreadsheet/document.cpp526
-rw-r--r--src/spreadsheet/document_impl.cpp232
-rw-r--r--src/spreadsheet/document_impl.hpp104
-rw-r--r--src/spreadsheet/document_types.cpp77
-rw-r--r--src/spreadsheet/dumper_global.cpp87
-rw-r--r--src/spreadsheet/dumper_global.hpp31
-rw-r--r--src/spreadsheet/factory.cpp410
-rw-r--r--src/spreadsheet/factory_pivot.cpp303
-rw-r--r--src/spreadsheet/factory_pivot.hpp120
-rw-r--r--src/spreadsheet/factory_shared_strings.cpp118
-rw-r--r--src/spreadsheet/factory_shared_strings.hpp64
-rw-r--r--src/spreadsheet/factory_sheet.cpp640
-rw-r--r--src/spreadsheet/factory_sheet.hpp275
-rw-r--r--src/spreadsheet/factory_styles.cpp870
-rw-r--r--src/spreadsheet/factory_table.cpp213
-rw-r--r--src/spreadsheet/factory_table.hpp60
-rw-r--r--src/spreadsheet/flat_dumper.cpp208
-rw-r--r--src/spreadsheet/flat_dumper.hpp36
-rw-r--r--src/spreadsheet/formula_global.cpp56
-rw-r--r--src/spreadsheet/formula_global.hpp48
-rw-r--r--src/spreadsheet/global_settings.cpp50
-rw-r--r--src/spreadsheet/global_settings.hpp41
-rw-r--r--src/spreadsheet/html_dumper.cpp695
-rw-r--r--src/spreadsheet/html_dumper.hpp49
-rw-r--r--src/spreadsheet/impl_types.hpp40
-rw-r--r--src/spreadsheet/json_dumper.cpp95
-rw-r--r--src/spreadsheet/json_dumper.hpp36
-rw-r--r--src/spreadsheet/number_format.cpp25
-rw-r--r--src/spreadsheet/number_format.hpp28
-rw-r--r--src/spreadsheet/pivot.cpp371
-rw-r--r--src/spreadsheet/shared_formula.cpp32
-rw-r--r--src/spreadsheet/shared_formula.hpp36
-rw-r--r--src/spreadsheet/shared_strings.cpp61
-rw-r--r--src/spreadsheet/sheet.cpp555
-rw-r--r--src/spreadsheet/sheet_impl.cpp53
-rw-r--r--src/spreadsheet/sheet_impl.hpp72
-rw-r--r--src/spreadsheet/styles.cpp485
-rw-r--r--src/spreadsheet/view.cpp201
-rw-r--r--src/test/Makefile.am10
-rw-r--r--src/test/Makefile.in704
-rw-r--r--src/test/mock_spreadsheet.cpp319
-rw-r--r--src/test/test_global.cpp75
405 files changed, 107223 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..4e47d44
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,721 @@
+SUBDIRS = include test parser mso liborcus spreadsheet
+
+if BUILD_PYTHON
+SUBDIRS += python
+endif
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include
+
+bin_PROGRAMS =
+
+EXTRA_PROGRAMS = \
+ orcus-test-xml \
+ orcus-env-dump
+
+AM_CPPFLAGS += $(BOOST_CPPFLAGS) $(LIBIXION_CFLAGS)
+
+if HAVE_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_FILESYSTEM=1"
+endif
+
+if HAVE_EXPERIMENTAL_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+endif
+
+if HAVE_STATIC_LIB
+AM_CPPFLAGS += -D__ORCUS_STATIC_LIB=1
+endif
+
+# orcus-test-xml
+
+orcus_test_xml_SOURCES = orcus_test_xml.cpp
+orcus_test_xml_LDADD = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la
+
+orcus_test_xml_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS) -DSRCDIR=\""$(top_srcdir)"\"
+
+# orcus-env-dump
+
+orcus_env_dump_SOURCES = orcus_env_dump.cpp
+orcus_env_dump_LDADD = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la
+orcus_env_dump_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+TESTS = \
+ orcus-test-xml \
+ orcus-env-dump
+
+if WITH_TOOLS
+
+bin_PROGRAMS += \
+ orcus-css-dump \
+ orcus-zip-dump \
+ orcus-mso-encryption \
+ orcus-detect \
+ orcus-json \
+ orcus-yaml
+
+# orcus-css-dump
+
+orcus_css_dump_SOURCES = \
+ orcus_css_dump.cpp
+
+orcus_css_dump_LDADD = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la
+
+orcus_css_dump_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-zip-dump
+
+orcus_zip_dump_SOURCES = \
+ orcus_zip_dump.cpp
+
+orcus_zip_dump_LDADD = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la
+
+orcus_zip_dump_CPPFLAGS = $(AM_CPPFLAGS)
+
+# orcus-json
+
+orcus_json_SOURCES = \
+ orcus_json_cli.hpp \
+ orcus_json_cli.cpp \
+ cli_global.hpp \
+ cli_global.cpp \
+ orcus_json_cli_map.cpp
+
+orcus_json_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+orcus_json_LDADD = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_json_LDADD += -lstdc++fs
+else
+orcus_json_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_json_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_json_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-yaml
+
+orcus_yaml_SOURCES = \
+ orcus_yaml_main.cpp
+
+orcus_yaml_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+orcus_yaml_LDADD = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_yaml_LDADD += -lstdc++fs
+else
+orcus_yaml_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_yaml_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_yaml_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+#----------------------------------------------------------------------------
+
+# orcus-mso-encryption
+
+orcus_mso_encryption_SOURCES = orcus_mso_encryption.cpp
+orcus_mso_encryption_LDFLAGS = $(BOOST_SYSTEM_LDFLAGS)
+orcus_mso_encryption_LDADD = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ mso/liborcus-mso-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+orcus_mso_encryption_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+#----------------------------------------------------------------------------
+
+# orcus-detect
+
+orcus_detect_SOURCES = orcus_detect_main.cpp
+orcus_detect_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+orcus_detect_LDADD = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_detect_LDADD += -lstdc++fs
+else
+orcus_detect_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_detect_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_detect_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+#----------------------------------------------------------------------------
+
+if BUILD_SPREADSHEET_MODEL
+
+orcus_json_LDADD += \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la
+
+bin_PROGRAMS += \
+ orcus-csv orcus-xml
+
+# orcus-csv
+
+orcus_csv_SOURCES = \
+ orcus_filter_global.hpp \
+ orcus_filter_global.cpp \
+ orcus_csv_main.cpp
+
+orcus_csv_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+orcus_csv_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_csv_LDADD += -lstdc++fs
+else
+orcus_csv_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_csv_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_csv_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-xml
+
+orcus_xml_SOURCES = \
+ orcus_filter_global.cpp \
+ cli_global.hpp \
+ cli_global.cpp \
+ orcus_xml_main.cpp
+
+orcus_xml_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+orcus_xml_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_xml_LDADD += -lstdc++fs
+else
+orcus_xml_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_xml_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_xml_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+if WITH_ODS_FILTER
+
+bin_PROGRAMS += \
+ orcus-ods \
+ orcus-styles-ods
+
+# orcus-ods
+
+orcus_ods_SOURCES = \
+ orcus_filter_global.hpp \
+ orcus_filter_global.cpp \
+ orcus_ods_main.cpp
+
+orcus_ods_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+orcus_ods_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_ods_LDADD += -lstdc++fs
+else
+orcus_ods_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_ods_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_ods_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-styles-ods
+
+orcus_styles_ods_SOURCES = \
+ orcus_filter_global.hpp \
+ orcus_filter_global.cpp \
+ orcus_ods_styles.cpp
+
+orcus_styles_ods_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+orcus_styles_ods_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_styles_ods_LDADD += -lstdc++fs
+else
+orcus_styles_ods_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_styles_ods_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_styles_ods_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+endif # WITH_ODS_FILTER
+
+if WITH_XLSX_FILTER
+
+bin_PROGRAMS += \
+ orcus-xlsx
+
+# orcus-xlsx
+
+orcus_xlsx_SOURCES = \
+ orcus_filter_global.hpp \
+ orcus_filter_global.cpp \
+ orcus_xlsx_main.cpp
+
+orcus_xlsx_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+orcus_xlsx_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_xlsx_LDADD += -lstdc++fs
+else
+orcus_xlsx_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_xlsx_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_xlsx_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+endif # WITH_XLSX_FILTER
+
+if WITH_XLS_XML_FILTER
+
+bin_PROGRAMS += \
+ orcus-xls-xml
+
+# orcus-xls-xml
+
+orcus_xls_xml_SOURCES = \
+ orcus_filter_global.hpp \
+ orcus_filter_global.cpp \
+ orcus_xls_xml_main.cpp
+
+orcus_xls_xml_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+orcus_xls_xml_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_xls_xml_LDADD += -lstdc++fs
+else
+orcus_xls_xml_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_xls_xml_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_xls_xml_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+endif # WITH_XLS_XML_FILTER
+
+if WITH_GNUMERIC_FILTER
+
+bin_PROGRAMS += \
+ orcus-gnumeric
+
+# orcus-gnumeric
+
+orcus_gnumeric_SOURCES = \
+ orcus_filter_global.hpp \
+ orcus_filter_global.cpp \
+ orcus_gnumeric_main.cpp
+
+orcus_gnumeric_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+orcus_gnumeric_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_gnumeric_LDADD += -lstdc++fs
+else
+orcus_gnumeric_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_gnumeric_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_gnumeric_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+endif # WITH_GNUMERIC_FILTER
+
+if WITH_PARQUET_FILTER
+
+bin_PROGRAMS += \
+ orcus-parquet
+
+# orcus-parquet
+
+orcus_parquet_SOURCES = \
+ orcus_filter_global.hpp \
+ orcus_filter_global.cpp \
+ orcus_parquet_main.cpp
+
+orcus_parquet_LDFLAGS = \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(BOOST_FILESYSTEM_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+orcus_parquet_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_FILESYSTEM_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+endif # WITH_PARQUET_FILTER
+
+endif # BUILD_SPREADSHEET_MODEL
+
+endif # WITH_TOOLS
+
+#----------------------------------------------------------------------------
+# Orcus Filter Tests
+#----------------------------------------------------------------------------
+
+if BUILD_SPREADSHEET_MODEL
+
+EXTRA_PROGRAMS += \
+ orcus-test-csv \
+ orcus-test-xml-mapped \
+ orcus-test-json-mapped
+
+# orcus-test-csv
+
+orcus_test_csv_SOURCES = \
+ orcus_test_csv.cpp \
+ orcus_test_global.hpp \
+ orcus_test_global.cpp
+
+orcus_test_csv_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ./test/liborcus-test.a \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la
+
+orcus_test_csv_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS) -DSRCDIR=\""$(top_srcdir)"\"
+
+# orcus-test-xml-mapped
+
+orcus_test_xml_mapped_SOURCES = \
+ orcus_test_xml_mapped.cpp \
+ orcus_test_global.hpp \
+ orcus_test_global.cpp
+
+orcus_test_xml_mapped_LDFLAGS = \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+orcus_test_xml_mapped_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ./test/liborcus-test.a \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_test_xml_mapped_LDADD += -lstdc++fs
+else
+orcus_test_xml_mapped_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_test_xml_mapped_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_test_xml_mapped_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS) -DSRCDIR=\""$(top_srcdir)"\"
+
+# orcus-test-json-mapped
+
+orcus_test_json_mapped_SOURCES = \
+ orcus_test_json_mapped.cpp
+
+orcus_test_json_mapped_LDFLAGS = \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+orcus_test_json_mapped_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_test_json_mapped_LDADD += -lstdc++fs
+else
+orcus_test_json_mapped_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_test_json_mapped_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_test_json_mapped_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS) -DSRCDIR=\""$(top_srcdir)"\"
+
+TESTS += \
+ orcus-test-csv \
+ orcus-test-xml-mapped \
+ orcus-test-json-mapped
+
+if WITH_ODS_FILTER
+
+EXTRA_PROGRAMS += \
+ orcus-test-ods
+
+# orcus-test-ods
+
+orcus_test_ods_SOURCES = \
+ orcus_test_ods.cpp
+
+orcus_test_ods_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS) \
+ ./test/liborcus-test.a
+
+orcus_test_ods_LDFLAGS = \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_test_ods_LDADD += -lstdc++fs
+else
+orcus_test_ods_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_test_ods_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_test_ods_CPPFLAGS = $(AM_CPPFLAGS) \
+ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+TESTS += orcus-test-ods
+
+# orcus-test-import-ods
+
+EXTRA_PROGRAMS += \
+ orcus-test-import-ods
+
+orcus_test_import_ods_SOURCES = \
+ orcus_test_import_ods.cpp
+
+orcus_test_import_ods_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ ./test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+
+orcus_test_import_ods_LDFLAGS = \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_test_import_ods_LDADD += -lstdc++fs
+else
+orcus_test_import_ods_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_test_import_ods_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_test_import_ods_CPPFLAGS = $(AM_CPPFLAGS) \
+ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+TESTS += \
+ orcus-test-import-ods
+
+endif # WITH_ODS_FILTER
+
+if WITH_XLSX_FILTER
+
+EXTRA_PROGRAMS += \
+ orcus-test-xlsx
+
+# orcus-test-xlsx
+
+orcus_test_xlsx_SOURCES = \
+ orcus_test_xlsx.cpp
+
+orcus_test_xlsx_LDFLAGS = \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+orcus_test_xlsx_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ test/liborcus-test.a \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ @LIBIXION_LIBS@ \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+orcus_test_xlsx_LDADD += -lstdc++fs
+else
+orcus_test_xlsx_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+orcus_test_xlsx_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+orcus_test_xlsx_CPPFLAGS = \
+ @LIBIXION_CFLAGS@ $(AM_CPPFLAGS) \
+ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+TESTS += \
+ orcus-test-xlsx
+
+endif # WITH_XLSX_FILTER
+
+if WITH_XLS_XML_FILTER
+
+EXTRA_PROGRAMS += orcus-test-xls-xml
+
+# orcus-test-xls-xml
+
+orcus_test_xls_xml_SOURCES = \
+ orcus_test_xls_xml.cpp \
+ orcus_test_global.cpp
+
+orcus_test_xls_xml_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ./test/liborcus-test.a \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ @LIBIXION_LIBS@
+
+orcus_test_xls_xml_CPPFLAGS = \
+ @LIBIXION_CFLAGS@ $(AM_CPPFLAGS) \
+ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+TESTS += \
+ orcus-test-xls-xml
+
+endif # WITH_XLS_XML_FILTER
+
+if WITH_GNUMERIC_FILTER
+
+EXTRA_PROGRAMS += orcus-test-gnumeric
+
+orcus_test_gnumeric_SOURCES = \
+ orcus_test_gnumeric.cpp \
+ orcus_test_global.cpp
+
+orcus_test_gnumeric_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ./test/liborcus-test.a \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ @LIBIXION_LIBS@ \
+ $(BOOST_FILESYSTEM_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+orcus_test_gnumeric_LDFLAGS = \
+ $(BOOST_FILESYSTEM_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+orcus_test_gnumeric_CPPFLAGS = \
+ @LIBIXION_CFLAGS@ $(AM_CPPFLAGS) \
+ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+TESTS += orcus-test-gnumeric
+
+endif # WITH_GNUMERIC_FILTER
+
+if WITH_PARQUET_FILTER
+
+EXTRA_PROGRAMS += orcus-test-parquet
+
+orcus_test_parquet_SOURCES = \
+ orcus_test_parquet.cpp
+
+orcus_test_parquet_LDADD = \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ./test/liborcus-test.a \
+ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ @LIBIXION_LIBS@ \
+ $(BOOST_FILESYSTEM_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
+orcus_test_parquet_CPPFLAGS = \
+ @LIBIXION_CFLAGS@ $(AM_CPPFLAGS) \
+ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+TESTS += \
+ orcus-test-parquet
+
+endif #WITH_PARQUET_FILTER
+
+endif # BUILD_SPREADSHEET_MODEL
+
+distclean-local:
+ rm -rf $(TESTS)
+
+@VALGRIND_CHECK_RULES@
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..d4386b7
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,2986 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@BUILD_PYTHON_TRUE@am__append_1 = python
+bin_PROGRAMS = $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \
+ $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \
+ $(am__EXEEXT_13)
+EXTRA_PROGRAMS = orcus-test-xml$(EXEEXT) orcus-env-dump$(EXEEXT) \
+ $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6)
+@HAVE_FILESYSTEM_TRUE@am__append_2 = "-DHAVE_FILESYSTEM=1"
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@am__append_3 = "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+@HAVE_STATIC_LIB_TRUE@am__append_4 = -D__ORCUS_STATIC_LIB=1
+TESTS = orcus-test-xml$(EXEEXT) orcus-env-dump$(EXEEXT) \
+ $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6)
+@WITH_TOOLS_TRUE@am__append_5 = \
+@WITH_TOOLS_TRUE@ orcus-css-dump \
+@WITH_TOOLS_TRUE@ orcus-zip-dump \
+@WITH_TOOLS_TRUE@ orcus-mso-encryption \
+@WITH_TOOLS_TRUE@ orcus-detect \
+@WITH_TOOLS_TRUE@ orcus-json \
+@WITH_TOOLS_TRUE@ orcus-yaml
+
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_6 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_7 = $(BOOST_FILESYSTEM_LDFLAGS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_8 = $(BOOST_FILESYSTEM_LIBS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_9 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_10 = $(BOOST_FILESYSTEM_LDFLAGS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_11 = $(BOOST_FILESYSTEM_LIBS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_12 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_13 = $(BOOST_FILESYSTEM_LDFLAGS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_14 = $(BOOST_FILESYSTEM_LIBS)
+
+#----------------------------------------------------------------------------
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@am__append_15 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@am__append_16 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ orcus-csv orcus-xml
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_17 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_18 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_19 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_20 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_21 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__append_22 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_23 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus-ods \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus-styles-ods
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_24 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_25 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_26 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_27 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_28 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_29 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@am__append_30 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ orcus-xlsx
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@am__append_31 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@am__append_32 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@am__append_33 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@am__append_34 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ orcus-xls-xml
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@am__append_35 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@am__append_36 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@am__append_37 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_38 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus-gnumeric
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_39 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_40 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_41 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@am__append_42 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus-parquet
+
+
+#----------------------------------------------------------------------------
+# Orcus Filter Tests
+#----------------------------------------------------------------------------
+@BUILD_SPREADSHEET_MODEL_TRUE@am__append_43 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus-test-csv \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus-test-xml-mapped \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus-test-json-mapped
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_44 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_45 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_46 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_47 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_48 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_49 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@am__append_50 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus-test-csv \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus-test-xml-mapped \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus-test-json-mapped
+
+
+# orcus-test-import-ods
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@am__append_51 = orcus-test-ods \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ orcus-test-import-ods
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@am__append_52 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@am__append_53 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@am__append_54 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@am__append_55 = orcus-test-ods \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ orcus-test-import-ods
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@am__append_56 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@am__append_57 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@am__append_58 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@am__append_59 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ orcus-test-xlsx
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@@WITH_XLSX_FILTER_TRUE@am__append_60 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_XLSX_FILTER_TRUE@am__append_61 = $(BOOST_FILESYSTEM_LDFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_XLSX_FILTER_TRUE@am__append_62 = $(BOOST_FILESYSTEM_LIBS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@am__append_63 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ orcus-test-xlsx
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@am__append_64 = orcus-test-xls-xml
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@am__append_65 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ orcus-test-xls-xml
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@am__append_66 = orcus-test-gnumeric
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@am__append_67 = orcus-test-gnumeric
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@am__append_68 = orcus-test-parquet
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@am__append_69 = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ orcus-test-parquet
+
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@BUILD_SPREADSHEET_MODEL_TRUE@am__EXEEXT_1 = orcus-test-csv$(EXEEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus-test-xml-mapped$(EXEEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus-test-json-mapped$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@am__EXEEXT_2 = orcus-test-ods$(EXEEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ orcus-test-import-ods$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@am__EXEEXT_3 = orcus-test-xlsx$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@am__EXEEXT_4 = orcus-test-xls-xml$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@am__EXEEXT_5 = orcus-test-gnumeric$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@am__EXEEXT_6 = orcus-test-parquet$(EXEEXT)
+@WITH_TOOLS_TRUE@am__EXEEXT_7 = orcus-css-dump$(EXEEXT) \
+@WITH_TOOLS_TRUE@ orcus-zip-dump$(EXEEXT) \
+@WITH_TOOLS_TRUE@ orcus-mso-encryption$(EXEEXT) \
+@WITH_TOOLS_TRUE@ orcus-detect$(EXEEXT) orcus-json$(EXEEXT) \
+@WITH_TOOLS_TRUE@ orcus-yaml$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@am__EXEEXT_8 = orcus-csv$(EXEEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ orcus-xml$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am__EXEEXT_9 = orcus-ods$(EXEEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus-styles-ods$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@am__EXEEXT_10 = orcus-xlsx$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@am__EXEEXT_11 = orcus-xls-xml$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@am__EXEEXT_12 = orcus-gnumeric$(EXEEXT)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@am__EXEEXT_13 = orcus-parquet$(EXEEXT)
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am__orcus_css_dump_SOURCES_DIST = orcus_css_dump.cpp
+@WITH_TOOLS_TRUE@am_orcus_css_dump_OBJECTS = \
+@WITH_TOOLS_TRUE@ orcus_css_dump-orcus_css_dump.$(OBJEXT)
+orcus_css_dump_OBJECTS = $(am_orcus_css_dump_OBJECTS)
+@WITH_TOOLS_TRUE@orcus_css_dump_DEPENDENCIES = parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am__orcus_csv_SOURCES_DIST = orcus_filter_global.hpp \
+ orcus_filter_global.cpp orcus_csv_main.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@am_orcus_csv_OBJECTS = orcus_csv-orcus_filter_global.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ orcus_csv-orcus_csv_main.$(OBJEXT)
+orcus_csv_OBJECTS = $(am_orcus_csv_OBJECTS)
+am__DEPENDENCIES_1 =
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@orcus_csv_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_2)
+orcus_csv_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(orcus_csv_LDFLAGS) $(LDFLAGS) -o $@
+am__orcus_detect_SOURCES_DIST = orcus_detect_main.cpp
+@WITH_TOOLS_TRUE@am_orcus_detect_OBJECTS = \
+@WITH_TOOLS_TRUE@ orcus_detect-orcus_detect_main.$(OBJEXT)
+orcus_detect_OBJECTS = $(am_orcus_detect_OBJECTS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
+@WITH_TOOLS_TRUE@orcus_detect_DEPENDENCIES = parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_3)
+orcus_detect_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(orcus_detect_LDFLAGS) $(LDFLAGS) -o $@
+am_orcus_env_dump_OBJECTS = orcus_env_dump-orcus_env_dump.$(OBJEXT)
+orcus_env_dump_OBJECTS = $(am_orcus_env_dump_OBJECTS)
+orcus_env_dump_DEPENDENCIES = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la
+am__orcus_gnumeric_SOURCES_DIST = orcus_filter_global.hpp \
+ orcus_filter_global.cpp orcus_gnumeric_main.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@am_orcus_gnumeric_OBJECTS = orcus_gnumeric-orcus_filter_global.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_gnumeric-orcus_gnumeric_main.$(OBJEXT)
+orcus_gnumeric_OBJECTS = $(am_orcus_gnumeric_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_gnumeric_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_4)
+orcus_gnumeric_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_gnumeric_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am__orcus_json_SOURCES_DIST = orcus_json_cli.hpp orcus_json_cli.cpp \
+ cli_global.hpp cli_global.cpp orcus_json_cli_map.cpp
+@WITH_TOOLS_TRUE@am_orcus_json_OBJECTS = \
+@WITH_TOOLS_TRUE@ orcus_json-orcus_json_cli.$(OBJEXT) \
+@WITH_TOOLS_TRUE@ orcus_json-cli_global.$(OBJEXT) \
+@WITH_TOOLS_TRUE@ orcus_json-orcus_json_cli_map.$(OBJEXT)
+orcus_json_OBJECTS = $(am_orcus_json_OBJECTS)
+@WITH_TOOLS_TRUE@orcus_json_DEPENDENCIES = parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_3) \
+@WITH_TOOLS_TRUE@ $(am__append_15)
+orcus_json_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(orcus_json_LDFLAGS) $(LDFLAGS) -o $@
+am__orcus_mso_encryption_SOURCES_DIST = orcus_mso_encryption.cpp
+@WITH_TOOLS_TRUE@am_orcus_mso_encryption_OBJECTS = orcus_mso_encryption-orcus_mso_encryption.$(OBJEXT)
+orcus_mso_encryption_OBJECTS = $(am_orcus_mso_encryption_OBJECTS)
+@WITH_TOOLS_TRUE@orcus_mso_encryption_DEPENDENCIES = parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ mso/liborcus-mso-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1)
+orcus_mso_encryption_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_mso_encryption_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am__orcus_ods_SOURCES_DIST = orcus_filter_global.hpp \
+ orcus_filter_global.cpp orcus_ods_main.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am_orcus_ods_OBJECTS = orcus_ods-orcus_filter_global.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_ods-orcus_ods_main.$(OBJEXT)
+orcus_ods_OBJECTS = $(am_orcus_ods_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_ods_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_5)
+orcus_ods_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(orcus_ods_LDFLAGS) $(LDFLAGS) -o $@
+am__orcus_parquet_SOURCES_DIST = orcus_filter_global.hpp \
+ orcus_filter_global.cpp orcus_parquet_main.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@am_orcus_parquet_OBJECTS = orcus_filter_global.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_parquet_main.$(OBJEXT)
+orcus_parquet_OBJECTS = $(am_orcus_parquet_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_parquet_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1)
+orcus_parquet_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_parquet_LDFLAGS) $(LDFLAGS) \
+ -o $@
+am__orcus_styles_ods_SOURCES_DIST = orcus_filter_global.hpp \
+ orcus_filter_global.cpp orcus_ods_styles.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@am_orcus_styles_ods_OBJECTS = orcus_styles_ods-orcus_filter_global.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_styles_ods-orcus_ods_styles.$(OBJEXT)
+orcus_styles_ods_OBJECTS = $(am_orcus_styles_ods_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_styles_ods_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_5)
+orcus_styles_ods_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_styles_ods_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am__orcus_test_csv_SOURCES_DIST = orcus_test_csv.cpp \
+ orcus_test_global.hpp orcus_test_global.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@am_orcus_test_csv_OBJECTS = orcus_test_csv-orcus_test_csv.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus_test_csv-orcus_test_global.$(OBJEXT)
+orcus_test_csv_OBJECTS = $(am_orcus_test_csv_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_csv_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la
+am__orcus_test_gnumeric_SOURCES_DIST = orcus_test_gnumeric.cpp \
+ orcus_test_global.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@am_orcus_test_gnumeric_OBJECTS = orcus_test_gnumeric-orcus_test_gnumeric.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ orcus_test_gnumeric-orcus_test_global.$(OBJEXT)
+orcus_test_gnumeric_OBJECTS = $(am_orcus_test_gnumeric_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@orcus_test_gnumeric_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ $(am__DEPENDENCIES_1)
+orcus_test_gnumeric_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_test_gnumeric_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am__orcus_test_import_ods_SOURCES_DIST = orcus_test_import_ods.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@am_orcus_test_import_ods_OBJECTS = orcus_test_import_ods-orcus_test_import_ods.$(OBJEXT)
+orcus_test_import_ods_OBJECTS = $(am_orcus_test_import_ods_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_ODS_FILTER_TRUE@am__DEPENDENCIES_6 = $(am__DEPENDENCIES_1)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@orcus_test_import_ods_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__DEPENDENCIES_6)
+orcus_test_import_ods_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_test_import_ods_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am__orcus_test_json_mapped_SOURCES_DIST = orcus_test_json_mapped.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@am_orcus_test_json_mapped_OBJECTS = orcus_test_json_mapped-orcus_test_json_mapped.$(OBJEXT)
+orcus_test_json_mapped_OBJECTS = $(am_orcus_test_json_mapped_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__DEPENDENCIES_7 = $(am__DEPENDENCIES_1)
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_json_mapped_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_7)
+orcus_test_json_mapped_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_test_json_mapped_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am__orcus_test_ods_SOURCES_DIST = orcus_test_ods.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@am_orcus_test_ods_OBJECTS = orcus_test_ods-orcus_test_ods.$(OBJEXT)
+orcus_test_ods_OBJECTS = $(am_orcus_test_ods_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@orcus_test_ods_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__DEPENDENCIES_6)
+orcus_test_ods_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_test_ods_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am__orcus_test_parquet_SOURCES_DIST = orcus_test_parquet.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@am_orcus_test_parquet_OBJECTS = orcus_test_parquet-orcus_test_parquet.$(OBJEXT)
+orcus_test_parquet_OBJECTS = $(am_orcus_test_parquet_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@orcus_test_parquet_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ $(am__DEPENDENCIES_1)
+am__orcus_test_xls_xml_SOURCES_DIST = orcus_test_xls_xml.cpp \
+ orcus_test_global.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@am_orcus_test_xls_xml_OBJECTS = orcus_test_xls_xml-orcus_test_xls_xml.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ orcus_test_xls_xml-orcus_test_global.$(OBJEXT)
+orcus_test_xls_xml_OBJECTS = $(am_orcus_test_xls_xml_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@orcus_test_xls_xml_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la
+am__orcus_test_xlsx_SOURCES_DIST = orcus_test_xlsx.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@am_orcus_test_xlsx_OBJECTS = orcus_test_xlsx-orcus_test_xlsx.$(OBJEXT)
+orcus_test_xlsx_OBJECTS = $(am_orcus_test_xlsx_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_XLSX_FILTER_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@orcus_test_xlsx_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__DEPENDENCIES_8)
+orcus_test_xlsx_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_test_xlsx_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am_orcus_test_xml_OBJECTS = orcus_test_xml-orcus_test_xml.$(OBJEXT)
+orcus_test_xml_OBJECTS = $(am_orcus_test_xml_OBJECTS)
+orcus_test_xml_DEPENDENCIES = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la
+am__orcus_test_xml_mapped_SOURCES_DIST = orcus_test_xml_mapped.cpp \
+ orcus_test_global.hpp orcus_test_global.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@am_orcus_test_xml_mapped_OBJECTS = orcus_test_xml_mapped-orcus_test_xml_mapped.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus_test_xml_mapped-orcus_test_global.$(OBJEXT)
+orcus_test_xml_mapped_OBJECTS = $(am_orcus_test_xml_mapped_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_xml_mapped_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_7)
+orcus_test_xml_mapped_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_test_xml_mapped_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am__orcus_xls_xml_SOURCES_DIST = orcus_filter_global.hpp \
+ orcus_filter_global.cpp orcus_xls_xml_main.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@am_orcus_xls_xml_OBJECTS = orcus_xls_xml-orcus_filter_global.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ orcus_xls_xml-orcus_xls_xml_main.$(OBJEXT)
+orcus_xls_xml_OBJECTS = $(am_orcus_xls_xml_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@am__DEPENDENCIES_9 = $(am__DEPENDENCIES_1)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@orcus_xls_xml_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ $(am__DEPENDENCIES_9)
+orcus_xls_xml_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(orcus_xls_xml_LDFLAGS) $(LDFLAGS) \
+ -o $@
+am__orcus_xlsx_SOURCES_DIST = orcus_filter_global.hpp \
+ orcus_filter_global.cpp orcus_xlsx_main.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@am_orcus_xlsx_OBJECTS = orcus_xlsx-orcus_filter_global.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ orcus_xlsx-orcus_xlsx_main.$(OBJEXT)
+orcus_xlsx_OBJECTS = $(am_orcus_xlsx_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@am__DEPENDENCIES_10 = $(am__DEPENDENCIES_1)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@orcus_xlsx_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__DEPENDENCIES_10)
+orcus_xlsx_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(orcus_xlsx_LDFLAGS) $(LDFLAGS) -o $@
+am__orcus_xml_SOURCES_DIST = orcus_filter_global.cpp cli_global.hpp \
+ cli_global.cpp orcus_xml_main.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@am_orcus_xml_OBJECTS = orcus_xml-orcus_filter_global.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ orcus_xml-cli_global.$(OBJEXT) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ orcus_xml-orcus_xml_main.$(OBJEXT)
+orcus_xml_OBJECTS = $(am_orcus_xml_OBJECTS)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@orcus_xml_DEPENDENCIES = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_2)
+orcus_xml_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(orcus_xml_LDFLAGS) $(LDFLAGS) -o $@
+am__orcus_yaml_SOURCES_DIST = orcus_yaml_main.cpp
+@WITH_TOOLS_TRUE@am_orcus_yaml_OBJECTS = \
+@WITH_TOOLS_TRUE@ orcus_yaml-orcus_yaml_main.$(OBJEXT)
+orcus_yaml_OBJECTS = $(am_orcus_yaml_OBJECTS)
+@WITH_TOOLS_TRUE@orcus_yaml_DEPENDENCIES = parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@WITH_TOOLS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_3)
+orcus_yaml_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(orcus_yaml_LDFLAGS) $(LDFLAGS) -o $@
+am__orcus_zip_dump_SOURCES_DIST = orcus_zip_dump.cpp
+@WITH_TOOLS_TRUE@am_orcus_zip_dump_OBJECTS = \
+@WITH_TOOLS_TRUE@ orcus_zip_dump-orcus_zip_dump.$(OBJEXT)
+orcus_zip_dump_OBJECTS = $(am_orcus_zip_dump_OBJECTS)
+@WITH_TOOLS_TRUE@orcus_zip_dump_DEPENDENCIES = parser/liborcus-parser-@ORCUS_API_VERSION@.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/orcus_css_dump-orcus_css_dump.Po \
+ ./$(DEPDIR)/orcus_csv-orcus_csv_main.Po \
+ ./$(DEPDIR)/orcus_csv-orcus_filter_global.Po \
+ ./$(DEPDIR)/orcus_detect-orcus_detect_main.Po \
+ ./$(DEPDIR)/orcus_env_dump-orcus_env_dump.Po \
+ ./$(DEPDIR)/orcus_filter_global.Po \
+ ./$(DEPDIR)/orcus_gnumeric-orcus_filter_global.Po \
+ ./$(DEPDIR)/orcus_gnumeric-orcus_gnumeric_main.Po \
+ ./$(DEPDIR)/orcus_json-cli_global.Po \
+ ./$(DEPDIR)/orcus_json-orcus_json_cli.Po \
+ ./$(DEPDIR)/orcus_json-orcus_json_cli_map.Po \
+ ./$(DEPDIR)/orcus_mso_encryption-orcus_mso_encryption.Po \
+ ./$(DEPDIR)/orcus_ods-orcus_filter_global.Po \
+ ./$(DEPDIR)/orcus_ods-orcus_ods_main.Po \
+ ./$(DEPDIR)/orcus_parquet_main.Po \
+ ./$(DEPDIR)/orcus_styles_ods-orcus_filter_global.Po \
+ ./$(DEPDIR)/orcus_styles_ods-orcus_ods_styles.Po \
+ ./$(DEPDIR)/orcus_test_csv-orcus_test_csv.Po \
+ ./$(DEPDIR)/orcus_test_csv-orcus_test_global.Po \
+ ./$(DEPDIR)/orcus_test_gnumeric-orcus_test_global.Po \
+ ./$(DEPDIR)/orcus_test_gnumeric-orcus_test_gnumeric.Po \
+ ./$(DEPDIR)/orcus_test_import_ods-orcus_test_import_ods.Po \
+ ./$(DEPDIR)/orcus_test_json_mapped-orcus_test_json_mapped.Po \
+ ./$(DEPDIR)/orcus_test_ods-orcus_test_ods.Po \
+ ./$(DEPDIR)/orcus_test_parquet-orcus_test_parquet.Po \
+ ./$(DEPDIR)/orcus_test_xls_xml-orcus_test_global.Po \
+ ./$(DEPDIR)/orcus_test_xls_xml-orcus_test_xls_xml.Po \
+ ./$(DEPDIR)/orcus_test_xlsx-orcus_test_xlsx.Po \
+ ./$(DEPDIR)/orcus_test_xml-orcus_test_xml.Po \
+ ./$(DEPDIR)/orcus_test_xml_mapped-orcus_test_global.Po \
+ ./$(DEPDIR)/orcus_test_xml_mapped-orcus_test_xml_mapped.Po \
+ ./$(DEPDIR)/orcus_xls_xml-orcus_filter_global.Po \
+ ./$(DEPDIR)/orcus_xls_xml-orcus_xls_xml_main.Po \
+ ./$(DEPDIR)/orcus_xlsx-orcus_filter_global.Po \
+ ./$(DEPDIR)/orcus_xlsx-orcus_xlsx_main.Po \
+ ./$(DEPDIR)/orcus_xml-cli_global.Po \
+ ./$(DEPDIR)/orcus_xml-orcus_filter_global.Po \
+ ./$(DEPDIR)/orcus_xml-orcus_xml_main.Po \
+ ./$(DEPDIR)/orcus_yaml-orcus_yaml_main.Po \
+ ./$(DEPDIR)/orcus_zip_dump-orcus_zip_dump.Po
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(orcus_css_dump_SOURCES) $(orcus_csv_SOURCES) \
+ $(orcus_detect_SOURCES) $(orcus_env_dump_SOURCES) \
+ $(orcus_gnumeric_SOURCES) $(orcus_json_SOURCES) \
+ $(orcus_mso_encryption_SOURCES) $(orcus_ods_SOURCES) \
+ $(orcus_parquet_SOURCES) $(orcus_styles_ods_SOURCES) \
+ $(orcus_test_csv_SOURCES) $(orcus_test_gnumeric_SOURCES) \
+ $(orcus_test_import_ods_SOURCES) \
+ $(orcus_test_json_mapped_SOURCES) $(orcus_test_ods_SOURCES) \
+ $(orcus_test_parquet_SOURCES) $(orcus_test_xls_xml_SOURCES) \
+ $(orcus_test_xlsx_SOURCES) $(orcus_test_xml_SOURCES) \
+ $(orcus_test_xml_mapped_SOURCES) $(orcus_xls_xml_SOURCES) \
+ $(orcus_xlsx_SOURCES) $(orcus_xml_SOURCES) \
+ $(orcus_yaml_SOURCES) $(orcus_zip_dump_SOURCES)
+DIST_SOURCES = $(am__orcus_css_dump_SOURCES_DIST) \
+ $(am__orcus_csv_SOURCES_DIST) $(am__orcus_detect_SOURCES_DIST) \
+ $(orcus_env_dump_SOURCES) $(am__orcus_gnumeric_SOURCES_DIST) \
+ $(am__orcus_json_SOURCES_DIST) \
+ $(am__orcus_mso_encryption_SOURCES_DIST) \
+ $(am__orcus_ods_SOURCES_DIST) \
+ $(am__orcus_parquet_SOURCES_DIST) \
+ $(am__orcus_styles_ods_SOURCES_DIST) \
+ $(am__orcus_test_csv_SOURCES_DIST) \
+ $(am__orcus_test_gnumeric_SOURCES_DIST) \
+ $(am__orcus_test_import_ods_SOURCES_DIST) \
+ $(am__orcus_test_json_mapped_SOURCES_DIST) \
+ $(am__orcus_test_ods_SOURCES_DIST) \
+ $(am__orcus_test_parquet_SOURCES_DIST) \
+ $(am__orcus_test_xls_xml_SOURCES_DIST) \
+ $(am__orcus_test_xlsx_SOURCES_DIST) $(orcus_test_xml_SOURCES) \
+ $(am__orcus_test_xml_mapped_SOURCES_DIST) \
+ $(am__orcus_xls_xml_SOURCES_DIST) \
+ $(am__orcus_xlsx_SOURCES_DIST) $(am__orcus_xml_SOURCES_DIST) \
+ $(am__orcus_yaml_SOURCES_DIST) \
+ $(am__orcus_zip_dump_SOURCES_DIST)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ check recheck distdir distdir-am
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+DIST_SUBDIRS = include test parser mso liborcus spreadsheet python
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+SUBDIRS = include test parser mso liborcus spreadsheet $(am__append_1)
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/include \
+ $(BOOST_CPPFLAGS) $(LIBIXION_CFLAGS) $(am__append_2) \
+ $(am__append_3) $(am__append_4)
+
+# orcus-test-xml
+orcus_test_xml_SOURCES = orcus_test_xml.cpp
+orcus_test_xml_LDADD = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la
+
+orcus_test_xml_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS) -DSRCDIR=\""$(top_srcdir)"\"
+
+# orcus-env-dump
+orcus_env_dump_SOURCES = orcus_env_dump.cpp
+orcus_env_dump_LDADD = \
+ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ liborcus/liborcus-@ORCUS_API_VERSION@.la
+
+orcus_env_dump_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-css-dump
+@WITH_TOOLS_TRUE@orcus_css_dump_SOURCES = \
+@WITH_TOOLS_TRUE@ orcus_css_dump.cpp
+
+@WITH_TOOLS_TRUE@orcus_css_dump_LDADD = \
+@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la
+
+@WITH_TOOLS_TRUE@orcus_css_dump_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-zip-dump
+@WITH_TOOLS_TRUE@orcus_zip_dump_SOURCES = \
+@WITH_TOOLS_TRUE@ orcus_zip_dump.cpp
+
+@WITH_TOOLS_TRUE@orcus_zip_dump_LDADD = \
+@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la
+
+@WITH_TOOLS_TRUE@orcus_zip_dump_CPPFLAGS = $(AM_CPPFLAGS)
+
+# orcus-json
+@WITH_TOOLS_TRUE@orcus_json_SOURCES = \
+@WITH_TOOLS_TRUE@ orcus_json_cli.hpp \
+@WITH_TOOLS_TRUE@ orcus_json_cli.cpp \
+@WITH_TOOLS_TRUE@ cli_global.hpp \
+@WITH_TOOLS_TRUE@ cli_global.cpp \
+@WITH_TOOLS_TRUE@ orcus_json_cli_map.cpp
+
+@WITH_TOOLS_TRUE@orcus_json_LDFLAGS = \
+@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LDFLAGS) $(am__append_7)
+@WITH_TOOLS_TRUE@orcus_json_LDADD = parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LIBS) $(am__append_6) \
+@WITH_TOOLS_TRUE@ $(am__append_8) $(am__append_15)
+@WITH_TOOLS_TRUE@orcus_json_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-yaml
+@WITH_TOOLS_TRUE@orcus_yaml_SOURCES = \
+@WITH_TOOLS_TRUE@ orcus_yaml_main.cpp
+
+@WITH_TOOLS_TRUE@orcus_yaml_LDFLAGS = \
+@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LDFLAGS) $(am__append_10)
+@WITH_TOOLS_TRUE@orcus_yaml_LDADD = parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LIBS) $(am__append_9) \
+@WITH_TOOLS_TRUE@ $(am__append_11)
+@WITH_TOOLS_TRUE@orcus_yaml_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+#----------------------------------------------------------------------------
+
+# orcus-mso-encryption
+@WITH_TOOLS_TRUE@orcus_mso_encryption_SOURCES = orcus_mso_encryption.cpp
+@WITH_TOOLS_TRUE@orcus_mso_encryption_LDFLAGS = $(BOOST_SYSTEM_LDFLAGS)
+@WITH_TOOLS_TRUE@orcus_mso_encryption_LDADD = \
+@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ mso/liborcus-mso-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LIBS)
+
+@WITH_TOOLS_TRUE@orcus_mso_encryption_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+#----------------------------------------------------------------------------
+
+# orcus-detect
+@WITH_TOOLS_TRUE@orcus_detect_SOURCES = orcus_detect_main.cpp
+@WITH_TOOLS_TRUE@orcus_detect_LDFLAGS = \
+@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LDFLAGS) $(am__append_13)
+@WITH_TOOLS_TRUE@orcus_detect_LDADD = parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LIBS) $(am__append_12) \
+@WITH_TOOLS_TRUE@ $(am__append_14)
+@WITH_TOOLS_TRUE@orcus_detect_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-csv
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@orcus_csv_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ orcus_csv_main.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@orcus_csv_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__append_18)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@orcus_csv_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__append_17) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__append_19)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@orcus_csv_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-xml
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@orcus_xml_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ cli_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ cli_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ orcus_xml_main.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@orcus_xml_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__append_21)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@orcus_xml_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__append_20) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@ $(am__append_22)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@orcus_xml_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-ods
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_ods_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_ods_main.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_ods_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__append_25)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_ods_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__append_24) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__append_26)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_ods_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-styles-ods
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_styles_ods_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_ods_styles.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_styles_ods_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__append_28)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_styles_ods_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__append_27) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__append_29)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_styles_ods_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-xlsx
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@orcus_xlsx_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ orcus_filter_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ orcus_filter_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ orcus_xlsx_main.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@orcus_xlsx_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__append_32)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@orcus_xlsx_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__append_31) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__append_33)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLSX_FILTER_TRUE@orcus_xlsx_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-xls-xml
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@orcus_xls_xml_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ orcus_filter_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ orcus_filter_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ orcus_xls_xml_main.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@orcus_xls_xml_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ $(am__append_36)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@orcus_xls_xml_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ $(am__append_35) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@ $(am__append_37)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_TOOLS_TRUE@@WITH_XLS_XML_FILTER_TRUE@orcus_xls_xml_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-gnumeric
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_gnumeric_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_gnumeric_main.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_gnumeric_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__append_40)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_gnumeric_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__append_39) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(am__append_41)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_gnumeric_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# orcus-parquet
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_parquet_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_filter_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ orcus_parquet_main.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_parquet_LDFLAGS = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_FILESYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LDFLAGS)
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@orcus_parquet_LDADD = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_FILESYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@@WITH_TOOLS_TRUE@ $(BOOST_SYSTEM_LIBS)
+
+
+# orcus-test-csv
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_csv_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus_test_csv.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus_test_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus_test_global.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_csv_LDADD = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la
+
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_csv_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS) -DSRCDIR=\""$(top_srcdir)"\"
+
+# orcus-test-xml-mapped
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_xml_mapped_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus_test_xml_mapped.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus_test_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus_test_global.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_xml_mapped_LDFLAGS = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_45)
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_xml_mapped_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_44) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_46)
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_xml_mapped_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS) -DSRCDIR=\""$(top_srcdir)"\"
+
+# orcus-test-json-mapped
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_json_mapped_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ orcus_test_json_mapped.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_json_mapped_LDFLAGS = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_48)
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_json_mapped_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_47) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_49)
+@BUILD_SPREADSHEET_MODEL_TRUE@orcus_test_json_mapped_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS) -DSRCDIR=\""$(top_srcdir)"\"
+
+# orcus-test-ods
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@orcus_test_ods_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ orcus_test_ods.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@orcus_test_ods_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__append_52) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__append_54)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@orcus_test_ods_LDFLAGS = $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__append_53)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@orcus_test_ods_CPPFLAGS = $(AM_CPPFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@orcus_test_import_ods_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ orcus_test_import_ods.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@orcus_test_import_ods_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__append_56) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__append_58)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@orcus_test_import_ods_LDFLAGS = $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ $(am__append_57)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@orcus_test_import_ods_CPPFLAGS = $(AM_CPPFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_ODS_FILTER_TRUE@ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+
+# orcus-test-xlsx
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@orcus_test_xlsx_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ orcus_test_xlsx.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@orcus_test_xlsx_LDFLAGS = $(BOOST_SYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__append_61)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@orcus_test_xlsx_LDADD = liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ @LIBIXION_LIBS@ \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__append_60) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ $(am__append_62)
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@orcus_test_xlsx_CPPFLAGS = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ @LIBIXION_CFLAGS@ $(AM_CPPFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLSX_FILTER_TRUE@ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+
+# orcus-test-xls-xml
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@orcus_test_xls_xml_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ orcus_test_xls_xml.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ orcus_test_global.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@orcus_test_xls_xml_LDADD = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ @LIBIXION_LIBS@
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@orcus_test_xls_xml_CPPFLAGS = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ @LIBIXION_CFLAGS@ $(AM_CPPFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_XLS_XML_FILTER_TRUE@ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@orcus_test_gnumeric_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ orcus_test_gnumeric.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ orcus_test_global.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@orcus_test_gnumeric_LDADD = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ @LIBIXION_LIBS@ \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ $(BOOST_FILESYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ $(BOOST_SYSTEM_LIBS)
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@orcus_test_gnumeric_LDFLAGS = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ $(BOOST_FILESYSTEM_LDFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ $(BOOST_SYSTEM_LDFLAGS)
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@orcus_test_gnumeric_CPPFLAGS = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ @LIBIXION_CFLAGS@ $(AM_CPPFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_GNUMERIC_FILTER_TRUE@ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@orcus_test_parquet_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ orcus_test_parquet.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@orcus_test_parquet_LDADD = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ ./test/liborcus-test.a \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ @LIBIXION_LIBS@ \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ $(BOOST_FILESYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ $(BOOST_SYSTEM_LIBS)
+
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@orcus_test_parquet_CPPFLAGS = \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ @LIBIXION_CFLAGS@ $(AM_CPPFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@@WITH_PARQUET_FILTER_TRUE@ -I$(top_builddir)/lib/liborcus/liborcus.la -DSRCDIR=\""$(top_srcdir)"\"
+
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+orcus-css-dump$(EXEEXT): $(orcus_css_dump_OBJECTS) $(orcus_css_dump_DEPENDENCIES) $(EXTRA_orcus_css_dump_DEPENDENCIES)
+ @rm -f orcus-css-dump$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(orcus_css_dump_OBJECTS) $(orcus_css_dump_LDADD) $(LIBS)
+
+orcus-csv$(EXEEXT): $(orcus_csv_OBJECTS) $(orcus_csv_DEPENDENCIES) $(EXTRA_orcus_csv_DEPENDENCIES)
+ @rm -f orcus-csv$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_csv_LINK) $(orcus_csv_OBJECTS) $(orcus_csv_LDADD) $(LIBS)
+
+orcus-detect$(EXEEXT): $(orcus_detect_OBJECTS) $(orcus_detect_DEPENDENCIES) $(EXTRA_orcus_detect_DEPENDENCIES)
+ @rm -f orcus-detect$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_detect_LINK) $(orcus_detect_OBJECTS) $(orcus_detect_LDADD) $(LIBS)
+
+orcus-env-dump$(EXEEXT): $(orcus_env_dump_OBJECTS) $(orcus_env_dump_DEPENDENCIES) $(EXTRA_orcus_env_dump_DEPENDENCIES)
+ @rm -f orcus-env-dump$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(orcus_env_dump_OBJECTS) $(orcus_env_dump_LDADD) $(LIBS)
+
+orcus-gnumeric$(EXEEXT): $(orcus_gnumeric_OBJECTS) $(orcus_gnumeric_DEPENDENCIES) $(EXTRA_orcus_gnumeric_DEPENDENCIES)
+ @rm -f orcus-gnumeric$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_gnumeric_LINK) $(orcus_gnumeric_OBJECTS) $(orcus_gnumeric_LDADD) $(LIBS)
+
+orcus-json$(EXEEXT): $(orcus_json_OBJECTS) $(orcus_json_DEPENDENCIES) $(EXTRA_orcus_json_DEPENDENCIES)
+ @rm -f orcus-json$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_json_LINK) $(orcus_json_OBJECTS) $(orcus_json_LDADD) $(LIBS)
+
+orcus-mso-encryption$(EXEEXT): $(orcus_mso_encryption_OBJECTS) $(orcus_mso_encryption_DEPENDENCIES) $(EXTRA_orcus_mso_encryption_DEPENDENCIES)
+ @rm -f orcus-mso-encryption$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_mso_encryption_LINK) $(orcus_mso_encryption_OBJECTS) $(orcus_mso_encryption_LDADD) $(LIBS)
+
+orcus-ods$(EXEEXT): $(orcus_ods_OBJECTS) $(orcus_ods_DEPENDENCIES) $(EXTRA_orcus_ods_DEPENDENCIES)
+ @rm -f orcus-ods$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_ods_LINK) $(orcus_ods_OBJECTS) $(orcus_ods_LDADD) $(LIBS)
+
+orcus-parquet$(EXEEXT): $(orcus_parquet_OBJECTS) $(orcus_parquet_DEPENDENCIES) $(EXTRA_orcus_parquet_DEPENDENCIES)
+ @rm -f orcus-parquet$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_parquet_LINK) $(orcus_parquet_OBJECTS) $(orcus_parquet_LDADD) $(LIBS)
+
+orcus-styles-ods$(EXEEXT): $(orcus_styles_ods_OBJECTS) $(orcus_styles_ods_DEPENDENCIES) $(EXTRA_orcus_styles_ods_DEPENDENCIES)
+ @rm -f orcus-styles-ods$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_styles_ods_LINK) $(orcus_styles_ods_OBJECTS) $(orcus_styles_ods_LDADD) $(LIBS)
+
+orcus-test-csv$(EXEEXT): $(orcus_test_csv_OBJECTS) $(orcus_test_csv_DEPENDENCIES) $(EXTRA_orcus_test_csv_DEPENDENCIES)
+ @rm -f orcus-test-csv$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(orcus_test_csv_OBJECTS) $(orcus_test_csv_LDADD) $(LIBS)
+
+orcus-test-gnumeric$(EXEEXT): $(orcus_test_gnumeric_OBJECTS) $(orcus_test_gnumeric_DEPENDENCIES) $(EXTRA_orcus_test_gnumeric_DEPENDENCIES)
+ @rm -f orcus-test-gnumeric$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_test_gnumeric_LINK) $(orcus_test_gnumeric_OBJECTS) $(orcus_test_gnumeric_LDADD) $(LIBS)
+
+orcus-test-import-ods$(EXEEXT): $(orcus_test_import_ods_OBJECTS) $(orcus_test_import_ods_DEPENDENCIES) $(EXTRA_orcus_test_import_ods_DEPENDENCIES)
+ @rm -f orcus-test-import-ods$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_test_import_ods_LINK) $(orcus_test_import_ods_OBJECTS) $(orcus_test_import_ods_LDADD) $(LIBS)
+
+orcus-test-json-mapped$(EXEEXT): $(orcus_test_json_mapped_OBJECTS) $(orcus_test_json_mapped_DEPENDENCIES) $(EXTRA_orcus_test_json_mapped_DEPENDENCIES)
+ @rm -f orcus-test-json-mapped$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_test_json_mapped_LINK) $(orcus_test_json_mapped_OBJECTS) $(orcus_test_json_mapped_LDADD) $(LIBS)
+
+orcus-test-ods$(EXEEXT): $(orcus_test_ods_OBJECTS) $(orcus_test_ods_DEPENDENCIES) $(EXTRA_orcus_test_ods_DEPENDENCIES)
+ @rm -f orcus-test-ods$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_test_ods_LINK) $(orcus_test_ods_OBJECTS) $(orcus_test_ods_LDADD) $(LIBS)
+
+orcus-test-parquet$(EXEEXT): $(orcus_test_parquet_OBJECTS) $(orcus_test_parquet_DEPENDENCIES) $(EXTRA_orcus_test_parquet_DEPENDENCIES)
+ @rm -f orcus-test-parquet$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(orcus_test_parquet_OBJECTS) $(orcus_test_parquet_LDADD) $(LIBS)
+
+orcus-test-xls-xml$(EXEEXT): $(orcus_test_xls_xml_OBJECTS) $(orcus_test_xls_xml_DEPENDENCIES) $(EXTRA_orcus_test_xls_xml_DEPENDENCIES)
+ @rm -f orcus-test-xls-xml$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(orcus_test_xls_xml_OBJECTS) $(orcus_test_xls_xml_LDADD) $(LIBS)
+
+orcus-test-xlsx$(EXEEXT): $(orcus_test_xlsx_OBJECTS) $(orcus_test_xlsx_DEPENDENCIES) $(EXTRA_orcus_test_xlsx_DEPENDENCIES)
+ @rm -f orcus-test-xlsx$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_test_xlsx_LINK) $(orcus_test_xlsx_OBJECTS) $(orcus_test_xlsx_LDADD) $(LIBS)
+
+orcus-test-xml$(EXEEXT): $(orcus_test_xml_OBJECTS) $(orcus_test_xml_DEPENDENCIES) $(EXTRA_orcus_test_xml_DEPENDENCIES)
+ @rm -f orcus-test-xml$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(orcus_test_xml_OBJECTS) $(orcus_test_xml_LDADD) $(LIBS)
+
+orcus-test-xml-mapped$(EXEEXT): $(orcus_test_xml_mapped_OBJECTS) $(orcus_test_xml_mapped_DEPENDENCIES) $(EXTRA_orcus_test_xml_mapped_DEPENDENCIES)
+ @rm -f orcus-test-xml-mapped$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_test_xml_mapped_LINK) $(orcus_test_xml_mapped_OBJECTS) $(orcus_test_xml_mapped_LDADD) $(LIBS)
+
+orcus-xls-xml$(EXEEXT): $(orcus_xls_xml_OBJECTS) $(orcus_xls_xml_DEPENDENCIES) $(EXTRA_orcus_xls_xml_DEPENDENCIES)
+ @rm -f orcus-xls-xml$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_xls_xml_LINK) $(orcus_xls_xml_OBJECTS) $(orcus_xls_xml_LDADD) $(LIBS)
+
+orcus-xlsx$(EXEEXT): $(orcus_xlsx_OBJECTS) $(orcus_xlsx_DEPENDENCIES) $(EXTRA_orcus_xlsx_DEPENDENCIES)
+ @rm -f orcus-xlsx$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_xlsx_LINK) $(orcus_xlsx_OBJECTS) $(orcus_xlsx_LDADD) $(LIBS)
+
+orcus-xml$(EXEEXT): $(orcus_xml_OBJECTS) $(orcus_xml_DEPENDENCIES) $(EXTRA_orcus_xml_DEPENDENCIES)
+ @rm -f orcus-xml$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_xml_LINK) $(orcus_xml_OBJECTS) $(orcus_xml_LDADD) $(LIBS)
+
+orcus-yaml$(EXEEXT): $(orcus_yaml_OBJECTS) $(orcus_yaml_DEPENDENCIES) $(EXTRA_orcus_yaml_DEPENDENCIES)
+ @rm -f orcus-yaml$(EXEEXT)
+ $(AM_V_CXXLD)$(orcus_yaml_LINK) $(orcus_yaml_OBJECTS) $(orcus_yaml_LDADD) $(LIBS)
+
+orcus-zip-dump$(EXEEXT): $(orcus_zip_dump_OBJECTS) $(orcus_zip_dump_DEPENDENCIES) $(EXTRA_orcus_zip_dump_DEPENDENCIES)
+ @rm -f orcus-zip-dump$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(orcus_zip_dump_OBJECTS) $(orcus_zip_dump_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_css_dump-orcus_css_dump.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_csv-orcus_csv_main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_csv-orcus_filter_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_detect-orcus_detect_main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_env_dump-orcus_env_dump.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_filter_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_gnumeric-orcus_filter_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_gnumeric-orcus_gnumeric_main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_json-cli_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_json-orcus_json_cli.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_json-orcus_json_cli_map.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_mso_encryption-orcus_mso_encryption.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_ods-orcus_filter_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_ods-orcus_ods_main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_parquet_main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_styles_ods-orcus_filter_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_styles_ods-orcus_ods_styles.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_csv-orcus_test_csv.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_csv-orcus_test_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_gnumeric-orcus_test_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_gnumeric-orcus_test_gnumeric.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_import_ods-orcus_test_import_ods.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_json_mapped-orcus_test_json_mapped.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_ods-orcus_test_ods.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_parquet-orcus_test_parquet.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_xls_xml-orcus_test_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_xls_xml-orcus_test_xls_xml.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_xlsx-orcus_test_xlsx.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_xml-orcus_test_xml.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_xml_mapped-orcus_test_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_test_xml_mapped-orcus_test_xml_mapped.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_xls_xml-orcus_filter_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_xls_xml-orcus_xls_xml_main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_xlsx-orcus_filter_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_xlsx-orcus_xlsx_main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_xml-cli_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_xml-orcus_filter_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_xml-orcus_xml_main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_yaml-orcus_yaml_main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orcus_zip_dump-orcus_zip_dump.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+orcus_css_dump-orcus_css_dump.o: orcus_css_dump.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_css_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_css_dump-orcus_css_dump.o -MD -MP -MF $(DEPDIR)/orcus_css_dump-orcus_css_dump.Tpo -c -o orcus_css_dump-orcus_css_dump.o `test -f 'orcus_css_dump.cpp' || echo '$(srcdir)/'`orcus_css_dump.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_css_dump-orcus_css_dump.Tpo $(DEPDIR)/orcus_css_dump-orcus_css_dump.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_css_dump.cpp' object='orcus_css_dump-orcus_css_dump.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_css_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_css_dump-orcus_css_dump.o `test -f 'orcus_css_dump.cpp' || echo '$(srcdir)/'`orcus_css_dump.cpp
+
+orcus_css_dump-orcus_css_dump.obj: orcus_css_dump.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_css_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_css_dump-orcus_css_dump.obj -MD -MP -MF $(DEPDIR)/orcus_css_dump-orcus_css_dump.Tpo -c -o orcus_css_dump-orcus_css_dump.obj `if test -f 'orcus_css_dump.cpp'; then $(CYGPATH_W) 'orcus_css_dump.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_css_dump.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_css_dump-orcus_css_dump.Tpo $(DEPDIR)/orcus_css_dump-orcus_css_dump.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_css_dump.cpp' object='orcus_css_dump-orcus_css_dump.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_css_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_css_dump-orcus_css_dump.obj `if test -f 'orcus_css_dump.cpp'; then $(CYGPATH_W) 'orcus_css_dump.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_css_dump.cpp'; fi`
+
+orcus_csv-orcus_filter_global.o: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_csv-orcus_filter_global.o -MD -MP -MF $(DEPDIR)/orcus_csv-orcus_filter_global.Tpo -c -o orcus_csv-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_csv-orcus_filter_global.Tpo $(DEPDIR)/orcus_csv-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_csv-orcus_filter_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_csv-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+
+orcus_csv-orcus_filter_global.obj: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_csv-orcus_filter_global.obj -MD -MP -MF $(DEPDIR)/orcus_csv-orcus_filter_global.Tpo -c -o orcus_csv-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_csv-orcus_filter_global.Tpo $(DEPDIR)/orcus_csv-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_csv-orcus_filter_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_csv-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+
+orcus_csv-orcus_csv_main.o: orcus_csv_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_csv-orcus_csv_main.o -MD -MP -MF $(DEPDIR)/orcus_csv-orcus_csv_main.Tpo -c -o orcus_csv-orcus_csv_main.o `test -f 'orcus_csv_main.cpp' || echo '$(srcdir)/'`orcus_csv_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_csv-orcus_csv_main.Tpo $(DEPDIR)/orcus_csv-orcus_csv_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_csv_main.cpp' object='orcus_csv-orcus_csv_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_csv-orcus_csv_main.o `test -f 'orcus_csv_main.cpp' || echo '$(srcdir)/'`orcus_csv_main.cpp
+
+orcus_csv-orcus_csv_main.obj: orcus_csv_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_csv-orcus_csv_main.obj -MD -MP -MF $(DEPDIR)/orcus_csv-orcus_csv_main.Tpo -c -o orcus_csv-orcus_csv_main.obj `if test -f 'orcus_csv_main.cpp'; then $(CYGPATH_W) 'orcus_csv_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_csv_main.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_csv-orcus_csv_main.Tpo $(DEPDIR)/orcus_csv-orcus_csv_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_csv_main.cpp' object='orcus_csv-orcus_csv_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_csv-orcus_csv_main.obj `if test -f 'orcus_csv_main.cpp'; then $(CYGPATH_W) 'orcus_csv_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_csv_main.cpp'; fi`
+
+orcus_detect-orcus_detect_main.o: orcus_detect_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_detect_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_detect-orcus_detect_main.o -MD -MP -MF $(DEPDIR)/orcus_detect-orcus_detect_main.Tpo -c -o orcus_detect-orcus_detect_main.o `test -f 'orcus_detect_main.cpp' || echo '$(srcdir)/'`orcus_detect_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_detect-orcus_detect_main.Tpo $(DEPDIR)/orcus_detect-orcus_detect_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_detect_main.cpp' object='orcus_detect-orcus_detect_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_detect_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_detect-orcus_detect_main.o `test -f 'orcus_detect_main.cpp' || echo '$(srcdir)/'`orcus_detect_main.cpp
+
+orcus_detect-orcus_detect_main.obj: orcus_detect_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_detect_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_detect-orcus_detect_main.obj -MD -MP -MF $(DEPDIR)/orcus_detect-orcus_detect_main.Tpo -c -o orcus_detect-orcus_detect_main.obj `if test -f 'orcus_detect_main.cpp'; then $(CYGPATH_W) 'orcus_detect_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_detect_main.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_detect-orcus_detect_main.Tpo $(DEPDIR)/orcus_detect-orcus_detect_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_detect_main.cpp' object='orcus_detect-orcus_detect_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_detect_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_detect-orcus_detect_main.obj `if test -f 'orcus_detect_main.cpp'; then $(CYGPATH_W) 'orcus_detect_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_detect_main.cpp'; fi`
+
+orcus_env_dump-orcus_env_dump.o: orcus_env_dump.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_env_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_env_dump-orcus_env_dump.o -MD -MP -MF $(DEPDIR)/orcus_env_dump-orcus_env_dump.Tpo -c -o orcus_env_dump-orcus_env_dump.o `test -f 'orcus_env_dump.cpp' || echo '$(srcdir)/'`orcus_env_dump.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_env_dump-orcus_env_dump.Tpo $(DEPDIR)/orcus_env_dump-orcus_env_dump.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_env_dump.cpp' object='orcus_env_dump-orcus_env_dump.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_env_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_env_dump-orcus_env_dump.o `test -f 'orcus_env_dump.cpp' || echo '$(srcdir)/'`orcus_env_dump.cpp
+
+orcus_env_dump-orcus_env_dump.obj: orcus_env_dump.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_env_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_env_dump-orcus_env_dump.obj -MD -MP -MF $(DEPDIR)/orcus_env_dump-orcus_env_dump.Tpo -c -o orcus_env_dump-orcus_env_dump.obj `if test -f 'orcus_env_dump.cpp'; then $(CYGPATH_W) 'orcus_env_dump.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_env_dump.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_env_dump-orcus_env_dump.Tpo $(DEPDIR)/orcus_env_dump-orcus_env_dump.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_env_dump.cpp' object='orcus_env_dump-orcus_env_dump.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_env_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_env_dump-orcus_env_dump.obj `if test -f 'orcus_env_dump.cpp'; then $(CYGPATH_W) 'orcus_env_dump.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_env_dump.cpp'; fi`
+
+orcus_gnumeric-orcus_filter_global.o: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_gnumeric-orcus_filter_global.o -MD -MP -MF $(DEPDIR)/orcus_gnumeric-orcus_filter_global.Tpo -c -o orcus_gnumeric-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_gnumeric-orcus_filter_global.Tpo $(DEPDIR)/orcus_gnumeric-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_gnumeric-orcus_filter_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_gnumeric-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+
+orcus_gnumeric-orcus_filter_global.obj: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_gnumeric-orcus_filter_global.obj -MD -MP -MF $(DEPDIR)/orcus_gnumeric-orcus_filter_global.Tpo -c -o orcus_gnumeric-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_gnumeric-orcus_filter_global.Tpo $(DEPDIR)/orcus_gnumeric-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_gnumeric-orcus_filter_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_gnumeric-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+
+orcus_gnumeric-orcus_gnumeric_main.o: orcus_gnumeric_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_gnumeric-orcus_gnumeric_main.o -MD -MP -MF $(DEPDIR)/orcus_gnumeric-orcus_gnumeric_main.Tpo -c -o orcus_gnumeric-orcus_gnumeric_main.o `test -f 'orcus_gnumeric_main.cpp' || echo '$(srcdir)/'`orcus_gnumeric_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_gnumeric-orcus_gnumeric_main.Tpo $(DEPDIR)/orcus_gnumeric-orcus_gnumeric_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_gnumeric_main.cpp' object='orcus_gnumeric-orcus_gnumeric_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_gnumeric-orcus_gnumeric_main.o `test -f 'orcus_gnumeric_main.cpp' || echo '$(srcdir)/'`orcus_gnumeric_main.cpp
+
+orcus_gnumeric-orcus_gnumeric_main.obj: orcus_gnumeric_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_gnumeric-orcus_gnumeric_main.obj -MD -MP -MF $(DEPDIR)/orcus_gnumeric-orcus_gnumeric_main.Tpo -c -o orcus_gnumeric-orcus_gnumeric_main.obj `if test -f 'orcus_gnumeric_main.cpp'; then $(CYGPATH_W) 'orcus_gnumeric_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_gnumeric_main.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_gnumeric-orcus_gnumeric_main.Tpo $(DEPDIR)/orcus_gnumeric-orcus_gnumeric_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_gnumeric_main.cpp' object='orcus_gnumeric-orcus_gnumeric_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_gnumeric-orcus_gnumeric_main.obj `if test -f 'orcus_gnumeric_main.cpp'; then $(CYGPATH_W) 'orcus_gnumeric_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_gnumeric_main.cpp'; fi`
+
+orcus_json-orcus_json_cli.o: orcus_json_cli.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_json-orcus_json_cli.o -MD -MP -MF $(DEPDIR)/orcus_json-orcus_json_cli.Tpo -c -o orcus_json-orcus_json_cli.o `test -f 'orcus_json_cli.cpp' || echo '$(srcdir)/'`orcus_json_cli.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_json-orcus_json_cli.Tpo $(DEPDIR)/orcus_json-orcus_json_cli.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_json_cli.cpp' object='orcus_json-orcus_json_cli.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_json-orcus_json_cli.o `test -f 'orcus_json_cli.cpp' || echo '$(srcdir)/'`orcus_json_cli.cpp
+
+orcus_json-orcus_json_cli.obj: orcus_json_cli.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_json-orcus_json_cli.obj -MD -MP -MF $(DEPDIR)/orcus_json-orcus_json_cli.Tpo -c -o orcus_json-orcus_json_cli.obj `if test -f 'orcus_json_cli.cpp'; then $(CYGPATH_W) 'orcus_json_cli.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_json_cli.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_json-orcus_json_cli.Tpo $(DEPDIR)/orcus_json-orcus_json_cli.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_json_cli.cpp' object='orcus_json-orcus_json_cli.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_json-orcus_json_cli.obj `if test -f 'orcus_json_cli.cpp'; then $(CYGPATH_W) 'orcus_json_cli.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_json_cli.cpp'; fi`
+
+orcus_json-cli_global.o: cli_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_json-cli_global.o -MD -MP -MF $(DEPDIR)/orcus_json-cli_global.Tpo -c -o orcus_json-cli_global.o `test -f 'cli_global.cpp' || echo '$(srcdir)/'`cli_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_json-cli_global.Tpo $(DEPDIR)/orcus_json-cli_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cli_global.cpp' object='orcus_json-cli_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_json-cli_global.o `test -f 'cli_global.cpp' || echo '$(srcdir)/'`cli_global.cpp
+
+orcus_json-cli_global.obj: cli_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_json-cli_global.obj -MD -MP -MF $(DEPDIR)/orcus_json-cli_global.Tpo -c -o orcus_json-cli_global.obj `if test -f 'cli_global.cpp'; then $(CYGPATH_W) 'cli_global.cpp'; else $(CYGPATH_W) '$(srcdir)/cli_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_json-cli_global.Tpo $(DEPDIR)/orcus_json-cli_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cli_global.cpp' object='orcus_json-cli_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_json-cli_global.obj `if test -f 'cli_global.cpp'; then $(CYGPATH_W) 'cli_global.cpp'; else $(CYGPATH_W) '$(srcdir)/cli_global.cpp'; fi`
+
+orcus_json-orcus_json_cli_map.o: orcus_json_cli_map.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_json-orcus_json_cli_map.o -MD -MP -MF $(DEPDIR)/orcus_json-orcus_json_cli_map.Tpo -c -o orcus_json-orcus_json_cli_map.o `test -f 'orcus_json_cli_map.cpp' || echo '$(srcdir)/'`orcus_json_cli_map.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_json-orcus_json_cli_map.Tpo $(DEPDIR)/orcus_json-orcus_json_cli_map.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_json_cli_map.cpp' object='orcus_json-orcus_json_cli_map.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_json-orcus_json_cli_map.o `test -f 'orcus_json_cli_map.cpp' || echo '$(srcdir)/'`orcus_json_cli_map.cpp
+
+orcus_json-orcus_json_cli_map.obj: orcus_json_cli_map.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_json-orcus_json_cli_map.obj -MD -MP -MF $(DEPDIR)/orcus_json-orcus_json_cli_map.Tpo -c -o orcus_json-orcus_json_cli_map.obj `if test -f 'orcus_json_cli_map.cpp'; then $(CYGPATH_W) 'orcus_json_cli_map.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_json_cli_map.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_json-orcus_json_cli_map.Tpo $(DEPDIR)/orcus_json-orcus_json_cli_map.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_json_cli_map.cpp' object='orcus_json-orcus_json_cli_map.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_json_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_json-orcus_json_cli_map.obj `if test -f 'orcus_json_cli_map.cpp'; then $(CYGPATH_W) 'orcus_json_cli_map.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_json_cli_map.cpp'; fi`
+
+orcus_mso_encryption-orcus_mso_encryption.o: orcus_mso_encryption.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_mso_encryption_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_mso_encryption-orcus_mso_encryption.o -MD -MP -MF $(DEPDIR)/orcus_mso_encryption-orcus_mso_encryption.Tpo -c -o orcus_mso_encryption-orcus_mso_encryption.o `test -f 'orcus_mso_encryption.cpp' || echo '$(srcdir)/'`orcus_mso_encryption.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_mso_encryption-orcus_mso_encryption.Tpo $(DEPDIR)/orcus_mso_encryption-orcus_mso_encryption.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_mso_encryption.cpp' object='orcus_mso_encryption-orcus_mso_encryption.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_mso_encryption_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_mso_encryption-orcus_mso_encryption.o `test -f 'orcus_mso_encryption.cpp' || echo '$(srcdir)/'`orcus_mso_encryption.cpp
+
+orcus_mso_encryption-orcus_mso_encryption.obj: orcus_mso_encryption.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_mso_encryption_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_mso_encryption-orcus_mso_encryption.obj -MD -MP -MF $(DEPDIR)/orcus_mso_encryption-orcus_mso_encryption.Tpo -c -o orcus_mso_encryption-orcus_mso_encryption.obj `if test -f 'orcus_mso_encryption.cpp'; then $(CYGPATH_W) 'orcus_mso_encryption.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_mso_encryption.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_mso_encryption-orcus_mso_encryption.Tpo $(DEPDIR)/orcus_mso_encryption-orcus_mso_encryption.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_mso_encryption.cpp' object='orcus_mso_encryption-orcus_mso_encryption.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_mso_encryption_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_mso_encryption-orcus_mso_encryption.obj `if test -f 'orcus_mso_encryption.cpp'; then $(CYGPATH_W) 'orcus_mso_encryption.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_mso_encryption.cpp'; fi`
+
+orcus_ods-orcus_filter_global.o: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_ods-orcus_filter_global.o -MD -MP -MF $(DEPDIR)/orcus_ods-orcus_filter_global.Tpo -c -o orcus_ods-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_ods-orcus_filter_global.Tpo $(DEPDIR)/orcus_ods-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_ods-orcus_filter_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_ods-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+
+orcus_ods-orcus_filter_global.obj: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_ods-orcus_filter_global.obj -MD -MP -MF $(DEPDIR)/orcus_ods-orcus_filter_global.Tpo -c -o orcus_ods-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_ods-orcus_filter_global.Tpo $(DEPDIR)/orcus_ods-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_ods-orcus_filter_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_ods-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+
+orcus_ods-orcus_ods_main.o: orcus_ods_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_ods-orcus_ods_main.o -MD -MP -MF $(DEPDIR)/orcus_ods-orcus_ods_main.Tpo -c -o orcus_ods-orcus_ods_main.o `test -f 'orcus_ods_main.cpp' || echo '$(srcdir)/'`orcus_ods_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_ods-orcus_ods_main.Tpo $(DEPDIR)/orcus_ods-orcus_ods_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_ods_main.cpp' object='orcus_ods-orcus_ods_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_ods-orcus_ods_main.o `test -f 'orcus_ods_main.cpp' || echo '$(srcdir)/'`orcus_ods_main.cpp
+
+orcus_ods-orcus_ods_main.obj: orcus_ods_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_ods-orcus_ods_main.obj -MD -MP -MF $(DEPDIR)/orcus_ods-orcus_ods_main.Tpo -c -o orcus_ods-orcus_ods_main.obj `if test -f 'orcus_ods_main.cpp'; then $(CYGPATH_W) 'orcus_ods_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_ods_main.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_ods-orcus_ods_main.Tpo $(DEPDIR)/orcus_ods-orcus_ods_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_ods_main.cpp' object='orcus_ods-orcus_ods_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_ods-orcus_ods_main.obj `if test -f 'orcus_ods_main.cpp'; then $(CYGPATH_W) 'orcus_ods_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_ods_main.cpp'; fi`
+
+orcus_styles_ods-orcus_filter_global.o: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_styles_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_styles_ods-orcus_filter_global.o -MD -MP -MF $(DEPDIR)/orcus_styles_ods-orcus_filter_global.Tpo -c -o orcus_styles_ods-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_styles_ods-orcus_filter_global.Tpo $(DEPDIR)/orcus_styles_ods-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_styles_ods-orcus_filter_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_styles_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_styles_ods-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+
+orcus_styles_ods-orcus_filter_global.obj: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_styles_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_styles_ods-orcus_filter_global.obj -MD -MP -MF $(DEPDIR)/orcus_styles_ods-orcus_filter_global.Tpo -c -o orcus_styles_ods-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_styles_ods-orcus_filter_global.Tpo $(DEPDIR)/orcus_styles_ods-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_styles_ods-orcus_filter_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_styles_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_styles_ods-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+
+orcus_styles_ods-orcus_ods_styles.o: orcus_ods_styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_styles_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_styles_ods-orcus_ods_styles.o -MD -MP -MF $(DEPDIR)/orcus_styles_ods-orcus_ods_styles.Tpo -c -o orcus_styles_ods-orcus_ods_styles.o `test -f 'orcus_ods_styles.cpp' || echo '$(srcdir)/'`orcus_ods_styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_styles_ods-orcus_ods_styles.Tpo $(DEPDIR)/orcus_styles_ods-orcus_ods_styles.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_ods_styles.cpp' object='orcus_styles_ods-orcus_ods_styles.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_styles_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_styles_ods-orcus_ods_styles.o `test -f 'orcus_ods_styles.cpp' || echo '$(srcdir)/'`orcus_ods_styles.cpp
+
+orcus_styles_ods-orcus_ods_styles.obj: orcus_ods_styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_styles_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_styles_ods-orcus_ods_styles.obj -MD -MP -MF $(DEPDIR)/orcus_styles_ods-orcus_ods_styles.Tpo -c -o orcus_styles_ods-orcus_ods_styles.obj `if test -f 'orcus_ods_styles.cpp'; then $(CYGPATH_W) 'orcus_ods_styles.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_ods_styles.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_styles_ods-orcus_ods_styles.Tpo $(DEPDIR)/orcus_styles_ods-orcus_ods_styles.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_ods_styles.cpp' object='orcus_styles_ods-orcus_ods_styles.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_styles_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_styles_ods-orcus_ods_styles.obj `if test -f 'orcus_ods_styles.cpp'; then $(CYGPATH_W) 'orcus_ods_styles.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_ods_styles.cpp'; fi`
+
+orcus_test_csv-orcus_test_csv.o: orcus_test_csv.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_csv-orcus_test_csv.o -MD -MP -MF $(DEPDIR)/orcus_test_csv-orcus_test_csv.Tpo -c -o orcus_test_csv-orcus_test_csv.o `test -f 'orcus_test_csv.cpp' || echo '$(srcdir)/'`orcus_test_csv.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_csv-orcus_test_csv.Tpo $(DEPDIR)/orcus_test_csv-orcus_test_csv.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_csv.cpp' object='orcus_test_csv-orcus_test_csv.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_csv-orcus_test_csv.o `test -f 'orcus_test_csv.cpp' || echo '$(srcdir)/'`orcus_test_csv.cpp
+
+orcus_test_csv-orcus_test_csv.obj: orcus_test_csv.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_csv-orcus_test_csv.obj -MD -MP -MF $(DEPDIR)/orcus_test_csv-orcus_test_csv.Tpo -c -o orcus_test_csv-orcus_test_csv.obj `if test -f 'orcus_test_csv.cpp'; then $(CYGPATH_W) 'orcus_test_csv.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_csv.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_csv-orcus_test_csv.Tpo $(DEPDIR)/orcus_test_csv-orcus_test_csv.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_csv.cpp' object='orcus_test_csv-orcus_test_csv.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_csv-orcus_test_csv.obj `if test -f 'orcus_test_csv.cpp'; then $(CYGPATH_W) 'orcus_test_csv.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_csv.cpp'; fi`
+
+orcus_test_csv-orcus_test_global.o: orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_csv-orcus_test_global.o -MD -MP -MF $(DEPDIR)/orcus_test_csv-orcus_test_global.Tpo -c -o orcus_test_csv-orcus_test_global.o `test -f 'orcus_test_global.cpp' || echo '$(srcdir)/'`orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_csv-orcus_test_global.Tpo $(DEPDIR)/orcus_test_csv-orcus_test_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_global.cpp' object='orcus_test_csv-orcus_test_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_csv-orcus_test_global.o `test -f 'orcus_test_global.cpp' || echo '$(srcdir)/'`orcus_test_global.cpp
+
+orcus_test_csv-orcus_test_global.obj: orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_csv-orcus_test_global.obj -MD -MP -MF $(DEPDIR)/orcus_test_csv-orcus_test_global.Tpo -c -o orcus_test_csv-orcus_test_global.obj `if test -f 'orcus_test_global.cpp'; then $(CYGPATH_W) 'orcus_test_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_csv-orcus_test_global.Tpo $(DEPDIR)/orcus_test_csv-orcus_test_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_global.cpp' object='orcus_test_csv-orcus_test_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_csv_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_csv-orcus_test_global.obj `if test -f 'orcus_test_global.cpp'; then $(CYGPATH_W) 'orcus_test_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_global.cpp'; fi`
+
+orcus_test_gnumeric-orcus_test_gnumeric.o: orcus_test_gnumeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_gnumeric-orcus_test_gnumeric.o -MD -MP -MF $(DEPDIR)/orcus_test_gnumeric-orcus_test_gnumeric.Tpo -c -o orcus_test_gnumeric-orcus_test_gnumeric.o `test -f 'orcus_test_gnumeric.cpp' || echo '$(srcdir)/'`orcus_test_gnumeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_gnumeric-orcus_test_gnumeric.Tpo $(DEPDIR)/orcus_test_gnumeric-orcus_test_gnumeric.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_gnumeric.cpp' object='orcus_test_gnumeric-orcus_test_gnumeric.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_gnumeric-orcus_test_gnumeric.o `test -f 'orcus_test_gnumeric.cpp' || echo '$(srcdir)/'`orcus_test_gnumeric.cpp
+
+orcus_test_gnumeric-orcus_test_gnumeric.obj: orcus_test_gnumeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_gnumeric-orcus_test_gnumeric.obj -MD -MP -MF $(DEPDIR)/orcus_test_gnumeric-orcus_test_gnumeric.Tpo -c -o orcus_test_gnumeric-orcus_test_gnumeric.obj `if test -f 'orcus_test_gnumeric.cpp'; then $(CYGPATH_W) 'orcus_test_gnumeric.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_gnumeric.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_gnumeric-orcus_test_gnumeric.Tpo $(DEPDIR)/orcus_test_gnumeric-orcus_test_gnumeric.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_gnumeric.cpp' object='orcus_test_gnumeric-orcus_test_gnumeric.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_gnumeric-orcus_test_gnumeric.obj `if test -f 'orcus_test_gnumeric.cpp'; then $(CYGPATH_W) 'orcus_test_gnumeric.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_gnumeric.cpp'; fi`
+
+orcus_test_gnumeric-orcus_test_global.o: orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_gnumeric-orcus_test_global.o -MD -MP -MF $(DEPDIR)/orcus_test_gnumeric-orcus_test_global.Tpo -c -o orcus_test_gnumeric-orcus_test_global.o `test -f 'orcus_test_global.cpp' || echo '$(srcdir)/'`orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_gnumeric-orcus_test_global.Tpo $(DEPDIR)/orcus_test_gnumeric-orcus_test_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_global.cpp' object='orcus_test_gnumeric-orcus_test_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_gnumeric-orcus_test_global.o `test -f 'orcus_test_global.cpp' || echo '$(srcdir)/'`orcus_test_global.cpp
+
+orcus_test_gnumeric-orcus_test_global.obj: orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_gnumeric-orcus_test_global.obj -MD -MP -MF $(DEPDIR)/orcus_test_gnumeric-orcus_test_global.Tpo -c -o orcus_test_gnumeric-orcus_test_global.obj `if test -f 'orcus_test_global.cpp'; then $(CYGPATH_W) 'orcus_test_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_gnumeric-orcus_test_global.Tpo $(DEPDIR)/orcus_test_gnumeric-orcus_test_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_global.cpp' object='orcus_test_gnumeric-orcus_test_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_gnumeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_gnumeric-orcus_test_global.obj `if test -f 'orcus_test_global.cpp'; then $(CYGPATH_W) 'orcus_test_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_global.cpp'; fi`
+
+orcus_test_import_ods-orcus_test_import_ods.o: orcus_test_import_ods.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_import_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_import_ods-orcus_test_import_ods.o -MD -MP -MF $(DEPDIR)/orcus_test_import_ods-orcus_test_import_ods.Tpo -c -o orcus_test_import_ods-orcus_test_import_ods.o `test -f 'orcus_test_import_ods.cpp' || echo '$(srcdir)/'`orcus_test_import_ods.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_import_ods-orcus_test_import_ods.Tpo $(DEPDIR)/orcus_test_import_ods-orcus_test_import_ods.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_import_ods.cpp' object='orcus_test_import_ods-orcus_test_import_ods.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_import_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_import_ods-orcus_test_import_ods.o `test -f 'orcus_test_import_ods.cpp' || echo '$(srcdir)/'`orcus_test_import_ods.cpp
+
+orcus_test_import_ods-orcus_test_import_ods.obj: orcus_test_import_ods.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_import_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_import_ods-orcus_test_import_ods.obj -MD -MP -MF $(DEPDIR)/orcus_test_import_ods-orcus_test_import_ods.Tpo -c -o orcus_test_import_ods-orcus_test_import_ods.obj `if test -f 'orcus_test_import_ods.cpp'; then $(CYGPATH_W) 'orcus_test_import_ods.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_import_ods.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_import_ods-orcus_test_import_ods.Tpo $(DEPDIR)/orcus_test_import_ods-orcus_test_import_ods.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_import_ods.cpp' object='orcus_test_import_ods-orcus_test_import_ods.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_import_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_import_ods-orcus_test_import_ods.obj `if test -f 'orcus_test_import_ods.cpp'; then $(CYGPATH_W) 'orcus_test_import_ods.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_import_ods.cpp'; fi`
+
+orcus_test_json_mapped-orcus_test_json_mapped.o: orcus_test_json_mapped.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_json_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_json_mapped-orcus_test_json_mapped.o -MD -MP -MF $(DEPDIR)/orcus_test_json_mapped-orcus_test_json_mapped.Tpo -c -o orcus_test_json_mapped-orcus_test_json_mapped.o `test -f 'orcus_test_json_mapped.cpp' || echo '$(srcdir)/'`orcus_test_json_mapped.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_json_mapped-orcus_test_json_mapped.Tpo $(DEPDIR)/orcus_test_json_mapped-orcus_test_json_mapped.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_json_mapped.cpp' object='orcus_test_json_mapped-orcus_test_json_mapped.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_json_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_json_mapped-orcus_test_json_mapped.o `test -f 'orcus_test_json_mapped.cpp' || echo '$(srcdir)/'`orcus_test_json_mapped.cpp
+
+orcus_test_json_mapped-orcus_test_json_mapped.obj: orcus_test_json_mapped.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_json_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_json_mapped-orcus_test_json_mapped.obj -MD -MP -MF $(DEPDIR)/orcus_test_json_mapped-orcus_test_json_mapped.Tpo -c -o orcus_test_json_mapped-orcus_test_json_mapped.obj `if test -f 'orcus_test_json_mapped.cpp'; then $(CYGPATH_W) 'orcus_test_json_mapped.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_json_mapped.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_json_mapped-orcus_test_json_mapped.Tpo $(DEPDIR)/orcus_test_json_mapped-orcus_test_json_mapped.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_json_mapped.cpp' object='orcus_test_json_mapped-orcus_test_json_mapped.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_json_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_json_mapped-orcus_test_json_mapped.obj `if test -f 'orcus_test_json_mapped.cpp'; then $(CYGPATH_W) 'orcus_test_json_mapped.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_json_mapped.cpp'; fi`
+
+orcus_test_ods-orcus_test_ods.o: orcus_test_ods.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_ods-orcus_test_ods.o -MD -MP -MF $(DEPDIR)/orcus_test_ods-orcus_test_ods.Tpo -c -o orcus_test_ods-orcus_test_ods.o `test -f 'orcus_test_ods.cpp' || echo '$(srcdir)/'`orcus_test_ods.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_ods-orcus_test_ods.Tpo $(DEPDIR)/orcus_test_ods-orcus_test_ods.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_ods.cpp' object='orcus_test_ods-orcus_test_ods.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_ods-orcus_test_ods.o `test -f 'orcus_test_ods.cpp' || echo '$(srcdir)/'`orcus_test_ods.cpp
+
+orcus_test_ods-orcus_test_ods.obj: orcus_test_ods.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_ods-orcus_test_ods.obj -MD -MP -MF $(DEPDIR)/orcus_test_ods-orcus_test_ods.Tpo -c -o orcus_test_ods-orcus_test_ods.obj `if test -f 'orcus_test_ods.cpp'; then $(CYGPATH_W) 'orcus_test_ods.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_ods.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_ods-orcus_test_ods.Tpo $(DEPDIR)/orcus_test_ods-orcus_test_ods.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_ods.cpp' object='orcus_test_ods-orcus_test_ods.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_ods_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_ods-orcus_test_ods.obj `if test -f 'orcus_test_ods.cpp'; then $(CYGPATH_W) 'orcus_test_ods.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_ods.cpp'; fi`
+
+orcus_test_parquet-orcus_test_parquet.o: orcus_test_parquet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_parquet_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_parquet-orcus_test_parquet.o -MD -MP -MF $(DEPDIR)/orcus_test_parquet-orcus_test_parquet.Tpo -c -o orcus_test_parquet-orcus_test_parquet.o `test -f 'orcus_test_parquet.cpp' || echo '$(srcdir)/'`orcus_test_parquet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_parquet-orcus_test_parquet.Tpo $(DEPDIR)/orcus_test_parquet-orcus_test_parquet.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_parquet.cpp' object='orcus_test_parquet-orcus_test_parquet.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_parquet_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_parquet-orcus_test_parquet.o `test -f 'orcus_test_parquet.cpp' || echo '$(srcdir)/'`orcus_test_parquet.cpp
+
+orcus_test_parquet-orcus_test_parquet.obj: orcus_test_parquet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_parquet_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_parquet-orcus_test_parquet.obj -MD -MP -MF $(DEPDIR)/orcus_test_parquet-orcus_test_parquet.Tpo -c -o orcus_test_parquet-orcus_test_parquet.obj `if test -f 'orcus_test_parquet.cpp'; then $(CYGPATH_W) 'orcus_test_parquet.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_parquet.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_parquet-orcus_test_parquet.Tpo $(DEPDIR)/orcus_test_parquet-orcus_test_parquet.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_parquet.cpp' object='orcus_test_parquet-orcus_test_parquet.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_parquet_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_parquet-orcus_test_parquet.obj `if test -f 'orcus_test_parquet.cpp'; then $(CYGPATH_W) 'orcus_test_parquet.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_parquet.cpp'; fi`
+
+orcus_test_xls_xml-orcus_test_xls_xml.o: orcus_test_xls_xml.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xls_xml-orcus_test_xls_xml.o -MD -MP -MF $(DEPDIR)/orcus_test_xls_xml-orcus_test_xls_xml.Tpo -c -o orcus_test_xls_xml-orcus_test_xls_xml.o `test -f 'orcus_test_xls_xml.cpp' || echo '$(srcdir)/'`orcus_test_xls_xml.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xls_xml-orcus_test_xls_xml.Tpo $(DEPDIR)/orcus_test_xls_xml-orcus_test_xls_xml.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_xls_xml.cpp' object='orcus_test_xls_xml-orcus_test_xls_xml.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xls_xml-orcus_test_xls_xml.o `test -f 'orcus_test_xls_xml.cpp' || echo '$(srcdir)/'`orcus_test_xls_xml.cpp
+
+orcus_test_xls_xml-orcus_test_xls_xml.obj: orcus_test_xls_xml.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xls_xml-orcus_test_xls_xml.obj -MD -MP -MF $(DEPDIR)/orcus_test_xls_xml-orcus_test_xls_xml.Tpo -c -o orcus_test_xls_xml-orcus_test_xls_xml.obj `if test -f 'orcus_test_xls_xml.cpp'; then $(CYGPATH_W) 'orcus_test_xls_xml.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_xls_xml.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xls_xml-orcus_test_xls_xml.Tpo $(DEPDIR)/orcus_test_xls_xml-orcus_test_xls_xml.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_xls_xml.cpp' object='orcus_test_xls_xml-orcus_test_xls_xml.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xls_xml-orcus_test_xls_xml.obj `if test -f 'orcus_test_xls_xml.cpp'; then $(CYGPATH_W) 'orcus_test_xls_xml.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_xls_xml.cpp'; fi`
+
+orcus_test_xls_xml-orcus_test_global.o: orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xls_xml-orcus_test_global.o -MD -MP -MF $(DEPDIR)/orcus_test_xls_xml-orcus_test_global.Tpo -c -o orcus_test_xls_xml-orcus_test_global.o `test -f 'orcus_test_global.cpp' || echo '$(srcdir)/'`orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xls_xml-orcus_test_global.Tpo $(DEPDIR)/orcus_test_xls_xml-orcus_test_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_global.cpp' object='orcus_test_xls_xml-orcus_test_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xls_xml-orcus_test_global.o `test -f 'orcus_test_global.cpp' || echo '$(srcdir)/'`orcus_test_global.cpp
+
+orcus_test_xls_xml-orcus_test_global.obj: orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xls_xml-orcus_test_global.obj -MD -MP -MF $(DEPDIR)/orcus_test_xls_xml-orcus_test_global.Tpo -c -o orcus_test_xls_xml-orcus_test_global.obj `if test -f 'orcus_test_global.cpp'; then $(CYGPATH_W) 'orcus_test_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xls_xml-orcus_test_global.Tpo $(DEPDIR)/orcus_test_xls_xml-orcus_test_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_global.cpp' object='orcus_test_xls_xml-orcus_test_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xls_xml-orcus_test_global.obj `if test -f 'orcus_test_global.cpp'; then $(CYGPATH_W) 'orcus_test_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_global.cpp'; fi`
+
+orcus_test_xlsx-orcus_test_xlsx.o: orcus_test_xlsx.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xlsx-orcus_test_xlsx.o -MD -MP -MF $(DEPDIR)/orcus_test_xlsx-orcus_test_xlsx.Tpo -c -o orcus_test_xlsx-orcus_test_xlsx.o `test -f 'orcus_test_xlsx.cpp' || echo '$(srcdir)/'`orcus_test_xlsx.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xlsx-orcus_test_xlsx.Tpo $(DEPDIR)/orcus_test_xlsx-orcus_test_xlsx.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_xlsx.cpp' object='orcus_test_xlsx-orcus_test_xlsx.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xlsx-orcus_test_xlsx.o `test -f 'orcus_test_xlsx.cpp' || echo '$(srcdir)/'`orcus_test_xlsx.cpp
+
+orcus_test_xlsx-orcus_test_xlsx.obj: orcus_test_xlsx.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xlsx-orcus_test_xlsx.obj -MD -MP -MF $(DEPDIR)/orcus_test_xlsx-orcus_test_xlsx.Tpo -c -o orcus_test_xlsx-orcus_test_xlsx.obj `if test -f 'orcus_test_xlsx.cpp'; then $(CYGPATH_W) 'orcus_test_xlsx.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_xlsx.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xlsx-orcus_test_xlsx.Tpo $(DEPDIR)/orcus_test_xlsx-orcus_test_xlsx.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_xlsx.cpp' object='orcus_test_xlsx-orcus_test_xlsx.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xlsx-orcus_test_xlsx.obj `if test -f 'orcus_test_xlsx.cpp'; then $(CYGPATH_W) 'orcus_test_xlsx.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_xlsx.cpp'; fi`
+
+orcus_test_xml-orcus_test_xml.o: orcus_test_xml.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xml-orcus_test_xml.o -MD -MP -MF $(DEPDIR)/orcus_test_xml-orcus_test_xml.Tpo -c -o orcus_test_xml-orcus_test_xml.o `test -f 'orcus_test_xml.cpp' || echo '$(srcdir)/'`orcus_test_xml.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xml-orcus_test_xml.Tpo $(DEPDIR)/orcus_test_xml-orcus_test_xml.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_xml.cpp' object='orcus_test_xml-orcus_test_xml.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xml-orcus_test_xml.o `test -f 'orcus_test_xml.cpp' || echo '$(srcdir)/'`orcus_test_xml.cpp
+
+orcus_test_xml-orcus_test_xml.obj: orcus_test_xml.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xml-orcus_test_xml.obj -MD -MP -MF $(DEPDIR)/orcus_test_xml-orcus_test_xml.Tpo -c -o orcus_test_xml-orcus_test_xml.obj `if test -f 'orcus_test_xml.cpp'; then $(CYGPATH_W) 'orcus_test_xml.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_xml.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xml-orcus_test_xml.Tpo $(DEPDIR)/orcus_test_xml-orcus_test_xml.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_xml.cpp' object='orcus_test_xml-orcus_test_xml.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xml-orcus_test_xml.obj `if test -f 'orcus_test_xml.cpp'; then $(CYGPATH_W) 'orcus_test_xml.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_xml.cpp'; fi`
+
+orcus_test_xml_mapped-orcus_test_xml_mapped.o: orcus_test_xml_mapped.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xml_mapped-orcus_test_xml_mapped.o -MD -MP -MF $(DEPDIR)/orcus_test_xml_mapped-orcus_test_xml_mapped.Tpo -c -o orcus_test_xml_mapped-orcus_test_xml_mapped.o `test -f 'orcus_test_xml_mapped.cpp' || echo '$(srcdir)/'`orcus_test_xml_mapped.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xml_mapped-orcus_test_xml_mapped.Tpo $(DEPDIR)/orcus_test_xml_mapped-orcus_test_xml_mapped.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_xml_mapped.cpp' object='orcus_test_xml_mapped-orcus_test_xml_mapped.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xml_mapped-orcus_test_xml_mapped.o `test -f 'orcus_test_xml_mapped.cpp' || echo '$(srcdir)/'`orcus_test_xml_mapped.cpp
+
+orcus_test_xml_mapped-orcus_test_xml_mapped.obj: orcus_test_xml_mapped.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xml_mapped-orcus_test_xml_mapped.obj -MD -MP -MF $(DEPDIR)/orcus_test_xml_mapped-orcus_test_xml_mapped.Tpo -c -o orcus_test_xml_mapped-orcus_test_xml_mapped.obj `if test -f 'orcus_test_xml_mapped.cpp'; then $(CYGPATH_W) 'orcus_test_xml_mapped.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_xml_mapped.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xml_mapped-orcus_test_xml_mapped.Tpo $(DEPDIR)/orcus_test_xml_mapped-orcus_test_xml_mapped.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_xml_mapped.cpp' object='orcus_test_xml_mapped-orcus_test_xml_mapped.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xml_mapped-orcus_test_xml_mapped.obj `if test -f 'orcus_test_xml_mapped.cpp'; then $(CYGPATH_W) 'orcus_test_xml_mapped.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_xml_mapped.cpp'; fi`
+
+orcus_test_xml_mapped-orcus_test_global.o: orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xml_mapped-orcus_test_global.o -MD -MP -MF $(DEPDIR)/orcus_test_xml_mapped-orcus_test_global.Tpo -c -o orcus_test_xml_mapped-orcus_test_global.o `test -f 'orcus_test_global.cpp' || echo '$(srcdir)/'`orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xml_mapped-orcus_test_global.Tpo $(DEPDIR)/orcus_test_xml_mapped-orcus_test_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_global.cpp' object='orcus_test_xml_mapped-orcus_test_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xml_mapped-orcus_test_global.o `test -f 'orcus_test_global.cpp' || echo '$(srcdir)/'`orcus_test_global.cpp
+
+orcus_test_xml_mapped-orcus_test_global.obj: orcus_test_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_test_xml_mapped-orcus_test_global.obj -MD -MP -MF $(DEPDIR)/orcus_test_xml_mapped-orcus_test_global.Tpo -c -o orcus_test_xml_mapped-orcus_test_global.obj `if test -f 'orcus_test_global.cpp'; then $(CYGPATH_W) 'orcus_test_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_test_xml_mapped-orcus_test_global.Tpo $(DEPDIR)/orcus_test_xml_mapped-orcus_test_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_test_global.cpp' object='orcus_test_xml_mapped-orcus_test_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_test_xml_mapped_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_test_xml_mapped-orcus_test_global.obj `if test -f 'orcus_test_global.cpp'; then $(CYGPATH_W) 'orcus_test_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_test_global.cpp'; fi`
+
+orcus_xls_xml-orcus_filter_global.o: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xls_xml-orcus_filter_global.o -MD -MP -MF $(DEPDIR)/orcus_xls_xml-orcus_filter_global.Tpo -c -o orcus_xls_xml-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xls_xml-orcus_filter_global.Tpo $(DEPDIR)/orcus_xls_xml-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_xls_xml-orcus_filter_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xls_xml-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+
+orcus_xls_xml-orcus_filter_global.obj: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xls_xml-orcus_filter_global.obj -MD -MP -MF $(DEPDIR)/orcus_xls_xml-orcus_filter_global.Tpo -c -o orcus_xls_xml-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xls_xml-orcus_filter_global.Tpo $(DEPDIR)/orcus_xls_xml-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_xls_xml-orcus_filter_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xls_xml-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+
+orcus_xls_xml-orcus_xls_xml_main.o: orcus_xls_xml_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xls_xml-orcus_xls_xml_main.o -MD -MP -MF $(DEPDIR)/orcus_xls_xml-orcus_xls_xml_main.Tpo -c -o orcus_xls_xml-orcus_xls_xml_main.o `test -f 'orcus_xls_xml_main.cpp' || echo '$(srcdir)/'`orcus_xls_xml_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xls_xml-orcus_xls_xml_main.Tpo $(DEPDIR)/orcus_xls_xml-orcus_xls_xml_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xls_xml_main.cpp' object='orcus_xls_xml-orcus_xls_xml_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xls_xml-orcus_xls_xml_main.o `test -f 'orcus_xls_xml_main.cpp' || echo '$(srcdir)/'`orcus_xls_xml_main.cpp
+
+orcus_xls_xml-orcus_xls_xml_main.obj: orcus_xls_xml_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xls_xml-orcus_xls_xml_main.obj -MD -MP -MF $(DEPDIR)/orcus_xls_xml-orcus_xls_xml_main.Tpo -c -o orcus_xls_xml-orcus_xls_xml_main.obj `if test -f 'orcus_xls_xml_main.cpp'; then $(CYGPATH_W) 'orcus_xls_xml_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_xls_xml_main.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xls_xml-orcus_xls_xml_main.Tpo $(DEPDIR)/orcus_xls_xml-orcus_xls_xml_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xls_xml_main.cpp' object='orcus_xls_xml-orcus_xls_xml_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xls_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xls_xml-orcus_xls_xml_main.obj `if test -f 'orcus_xls_xml_main.cpp'; then $(CYGPATH_W) 'orcus_xls_xml_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_xls_xml_main.cpp'; fi`
+
+orcus_xlsx-orcus_filter_global.o: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xlsx-orcus_filter_global.o -MD -MP -MF $(DEPDIR)/orcus_xlsx-orcus_filter_global.Tpo -c -o orcus_xlsx-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xlsx-orcus_filter_global.Tpo $(DEPDIR)/orcus_xlsx-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_xlsx-orcus_filter_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xlsx-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+
+orcus_xlsx-orcus_filter_global.obj: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xlsx-orcus_filter_global.obj -MD -MP -MF $(DEPDIR)/orcus_xlsx-orcus_filter_global.Tpo -c -o orcus_xlsx-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xlsx-orcus_filter_global.Tpo $(DEPDIR)/orcus_xlsx-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_xlsx-orcus_filter_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xlsx-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+
+orcus_xlsx-orcus_xlsx_main.o: orcus_xlsx_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xlsx-orcus_xlsx_main.o -MD -MP -MF $(DEPDIR)/orcus_xlsx-orcus_xlsx_main.Tpo -c -o orcus_xlsx-orcus_xlsx_main.o `test -f 'orcus_xlsx_main.cpp' || echo '$(srcdir)/'`orcus_xlsx_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xlsx-orcus_xlsx_main.Tpo $(DEPDIR)/orcus_xlsx-orcus_xlsx_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xlsx_main.cpp' object='orcus_xlsx-orcus_xlsx_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xlsx-orcus_xlsx_main.o `test -f 'orcus_xlsx_main.cpp' || echo '$(srcdir)/'`orcus_xlsx_main.cpp
+
+orcus_xlsx-orcus_xlsx_main.obj: orcus_xlsx_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xlsx-orcus_xlsx_main.obj -MD -MP -MF $(DEPDIR)/orcus_xlsx-orcus_xlsx_main.Tpo -c -o orcus_xlsx-orcus_xlsx_main.obj `if test -f 'orcus_xlsx_main.cpp'; then $(CYGPATH_W) 'orcus_xlsx_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_xlsx_main.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xlsx-orcus_xlsx_main.Tpo $(DEPDIR)/orcus_xlsx-orcus_xlsx_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xlsx_main.cpp' object='orcus_xlsx-orcus_xlsx_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xlsx_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xlsx-orcus_xlsx_main.obj `if test -f 'orcus_xlsx_main.cpp'; then $(CYGPATH_W) 'orcus_xlsx_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_xlsx_main.cpp'; fi`
+
+orcus_xml-orcus_filter_global.o: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xml-orcus_filter_global.o -MD -MP -MF $(DEPDIR)/orcus_xml-orcus_filter_global.Tpo -c -o orcus_xml-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xml-orcus_filter_global.Tpo $(DEPDIR)/orcus_xml-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_xml-orcus_filter_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xml-orcus_filter_global.o `test -f 'orcus_filter_global.cpp' || echo '$(srcdir)/'`orcus_filter_global.cpp
+
+orcus_xml-orcus_filter_global.obj: orcus_filter_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xml-orcus_filter_global.obj -MD -MP -MF $(DEPDIR)/orcus_xml-orcus_filter_global.Tpo -c -o orcus_xml-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xml-orcus_filter_global.Tpo $(DEPDIR)/orcus_xml-orcus_filter_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_filter_global.cpp' object='orcus_xml-orcus_filter_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xml-orcus_filter_global.obj `if test -f 'orcus_filter_global.cpp'; then $(CYGPATH_W) 'orcus_filter_global.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_filter_global.cpp'; fi`
+
+orcus_xml-cli_global.o: cli_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xml-cli_global.o -MD -MP -MF $(DEPDIR)/orcus_xml-cli_global.Tpo -c -o orcus_xml-cli_global.o `test -f 'cli_global.cpp' || echo '$(srcdir)/'`cli_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xml-cli_global.Tpo $(DEPDIR)/orcus_xml-cli_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cli_global.cpp' object='orcus_xml-cli_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xml-cli_global.o `test -f 'cli_global.cpp' || echo '$(srcdir)/'`cli_global.cpp
+
+orcus_xml-cli_global.obj: cli_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xml-cli_global.obj -MD -MP -MF $(DEPDIR)/orcus_xml-cli_global.Tpo -c -o orcus_xml-cli_global.obj `if test -f 'cli_global.cpp'; then $(CYGPATH_W) 'cli_global.cpp'; else $(CYGPATH_W) '$(srcdir)/cli_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xml-cli_global.Tpo $(DEPDIR)/orcus_xml-cli_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cli_global.cpp' object='orcus_xml-cli_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xml-cli_global.obj `if test -f 'cli_global.cpp'; then $(CYGPATH_W) 'cli_global.cpp'; else $(CYGPATH_W) '$(srcdir)/cli_global.cpp'; fi`
+
+orcus_xml-orcus_xml_main.o: orcus_xml_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xml-orcus_xml_main.o -MD -MP -MF $(DEPDIR)/orcus_xml-orcus_xml_main.Tpo -c -o orcus_xml-orcus_xml_main.o `test -f 'orcus_xml_main.cpp' || echo '$(srcdir)/'`orcus_xml_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xml-orcus_xml_main.Tpo $(DEPDIR)/orcus_xml-orcus_xml_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xml_main.cpp' object='orcus_xml-orcus_xml_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xml-orcus_xml_main.o `test -f 'orcus_xml_main.cpp' || echo '$(srcdir)/'`orcus_xml_main.cpp
+
+orcus_xml-orcus_xml_main.obj: orcus_xml_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_xml-orcus_xml_main.obj -MD -MP -MF $(DEPDIR)/orcus_xml-orcus_xml_main.Tpo -c -o orcus_xml-orcus_xml_main.obj `if test -f 'orcus_xml_main.cpp'; then $(CYGPATH_W) 'orcus_xml_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_xml_main.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_xml-orcus_xml_main.Tpo $(DEPDIR)/orcus_xml-orcus_xml_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xml_main.cpp' object='orcus_xml-orcus_xml_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_xml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_xml-orcus_xml_main.obj `if test -f 'orcus_xml_main.cpp'; then $(CYGPATH_W) 'orcus_xml_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_xml_main.cpp'; fi`
+
+orcus_yaml-orcus_yaml_main.o: orcus_yaml_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_yaml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_yaml-orcus_yaml_main.o -MD -MP -MF $(DEPDIR)/orcus_yaml-orcus_yaml_main.Tpo -c -o orcus_yaml-orcus_yaml_main.o `test -f 'orcus_yaml_main.cpp' || echo '$(srcdir)/'`orcus_yaml_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_yaml-orcus_yaml_main.Tpo $(DEPDIR)/orcus_yaml-orcus_yaml_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_yaml_main.cpp' object='orcus_yaml-orcus_yaml_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_yaml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_yaml-orcus_yaml_main.o `test -f 'orcus_yaml_main.cpp' || echo '$(srcdir)/'`orcus_yaml_main.cpp
+
+orcus_yaml-orcus_yaml_main.obj: orcus_yaml_main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_yaml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_yaml-orcus_yaml_main.obj -MD -MP -MF $(DEPDIR)/orcus_yaml-orcus_yaml_main.Tpo -c -o orcus_yaml-orcus_yaml_main.obj `if test -f 'orcus_yaml_main.cpp'; then $(CYGPATH_W) 'orcus_yaml_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_yaml_main.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_yaml-orcus_yaml_main.Tpo $(DEPDIR)/orcus_yaml-orcus_yaml_main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_yaml_main.cpp' object='orcus_yaml-orcus_yaml_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_yaml_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_yaml-orcus_yaml_main.obj `if test -f 'orcus_yaml_main.cpp'; then $(CYGPATH_W) 'orcus_yaml_main.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_yaml_main.cpp'; fi`
+
+orcus_zip_dump-orcus_zip_dump.o: orcus_zip_dump.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_zip_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_zip_dump-orcus_zip_dump.o -MD -MP -MF $(DEPDIR)/orcus_zip_dump-orcus_zip_dump.Tpo -c -o orcus_zip_dump-orcus_zip_dump.o `test -f 'orcus_zip_dump.cpp' || echo '$(srcdir)/'`orcus_zip_dump.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_zip_dump-orcus_zip_dump.Tpo $(DEPDIR)/orcus_zip_dump-orcus_zip_dump.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_zip_dump.cpp' object='orcus_zip_dump-orcus_zip_dump.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_zip_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_zip_dump-orcus_zip_dump.o `test -f 'orcus_zip_dump.cpp' || echo '$(srcdir)/'`orcus_zip_dump.cpp
+
+orcus_zip_dump-orcus_zip_dump.obj: orcus_zip_dump.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_zip_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT orcus_zip_dump-orcus_zip_dump.obj -MD -MP -MF $(DEPDIR)/orcus_zip_dump-orcus_zip_dump.Tpo -c -o orcus_zip_dump-orcus_zip_dump.obj `if test -f 'orcus_zip_dump.cpp'; then $(CYGPATH_W) 'orcus_zip_dump.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_zip_dump.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/orcus_zip_dump-orcus_zip_dump.Tpo $(DEPDIR)/orcus_zip_dump-orcus_zip_dump.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_zip_dump.cpp' object='orcus_zip_dump-orcus_zip_dump.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(orcus_zip_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o orcus_zip_dump-orcus_zip_dump.obj `if test -f 'orcus_zip_dump.cpp'; then $(CYGPATH_W) 'orcus_zip_dump.cpp'; else $(CYGPATH_W) '$(srcdir)/orcus_zip_dump.cpp'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+orcus-test-xml.log: orcus-test-xml$(EXEEXT)
+ @p='orcus-test-xml$(EXEEXT)'; \
+ b='orcus-test-xml'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+orcus-env-dump.log: orcus-env-dump$(EXEEXT)
+ @p='orcus-env-dump$(EXEEXT)'; \
+ b='orcus-env-dump'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+orcus-test-csv.log: orcus-test-csv$(EXEEXT)
+ @p='orcus-test-csv$(EXEEXT)'; \
+ b='orcus-test-csv'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+orcus-test-xml-mapped.log: orcus-test-xml-mapped$(EXEEXT)
+ @p='orcus-test-xml-mapped$(EXEEXT)'; \
+ b='orcus-test-xml-mapped'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+orcus-test-json-mapped.log: orcus-test-json-mapped$(EXEEXT)
+ @p='orcus-test-json-mapped$(EXEEXT)'; \
+ b='orcus-test-json-mapped'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+orcus-test-ods.log: orcus-test-ods$(EXEEXT)
+ @p='orcus-test-ods$(EXEEXT)'; \
+ b='orcus-test-ods'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+orcus-test-import-ods.log: orcus-test-import-ods$(EXEEXT)
+ @p='orcus-test-import-ods$(EXEEXT)'; \
+ b='orcus-test-import-ods'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+orcus-test-xlsx.log: orcus-test-xlsx$(EXEEXT)
+ @p='orcus-test-xlsx$(EXEEXT)'; \
+ b='orcus-test-xlsx'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+orcus-test-xls-xml.log: orcus-test-xls-xml$(EXEEXT)
+ @p='orcus-test-xls-xml$(EXEEXT)'; \
+ b='orcus-test-xls-xml'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+orcus-test-gnumeric.log: orcus-test-gnumeric$(EXEEXT)
+ @p='orcus-test-gnumeric$(EXEEXT)'; \
+ b='orcus-test-gnumeric'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+orcus-test-parquet.log: orcus-test-parquet$(EXEEXT)
+ @p='orcus-test-parquet$(EXEEXT)'; \
+ b='orcus-test-parquet'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile $(PROGRAMS)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-recursive
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-recursive
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-recursive
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-recursive
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-recursive
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-recursive
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/orcus_css_dump-orcus_css_dump.Po
+ -rm -f ./$(DEPDIR)/orcus_csv-orcus_csv_main.Po
+ -rm -f ./$(DEPDIR)/orcus_csv-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_detect-orcus_detect_main.Po
+ -rm -f ./$(DEPDIR)/orcus_env_dump-orcus_env_dump.Po
+ -rm -f ./$(DEPDIR)/orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_gnumeric-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_gnumeric-orcus_gnumeric_main.Po
+ -rm -f ./$(DEPDIR)/orcus_json-cli_global.Po
+ -rm -f ./$(DEPDIR)/orcus_json-orcus_json_cli.Po
+ -rm -f ./$(DEPDIR)/orcus_json-orcus_json_cli_map.Po
+ -rm -f ./$(DEPDIR)/orcus_mso_encryption-orcus_mso_encryption.Po
+ -rm -f ./$(DEPDIR)/orcus_ods-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_ods-orcus_ods_main.Po
+ -rm -f ./$(DEPDIR)/orcus_parquet_main.Po
+ -rm -f ./$(DEPDIR)/orcus_styles_ods-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_styles_ods-orcus_ods_styles.Po
+ -rm -f ./$(DEPDIR)/orcus_test_csv-orcus_test_csv.Po
+ -rm -f ./$(DEPDIR)/orcus_test_csv-orcus_test_global.Po
+ -rm -f ./$(DEPDIR)/orcus_test_gnumeric-orcus_test_global.Po
+ -rm -f ./$(DEPDIR)/orcus_test_gnumeric-orcus_test_gnumeric.Po
+ -rm -f ./$(DEPDIR)/orcus_test_import_ods-orcus_test_import_ods.Po
+ -rm -f ./$(DEPDIR)/orcus_test_json_mapped-orcus_test_json_mapped.Po
+ -rm -f ./$(DEPDIR)/orcus_test_ods-orcus_test_ods.Po
+ -rm -f ./$(DEPDIR)/orcus_test_parquet-orcus_test_parquet.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xls_xml-orcus_test_global.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xls_xml-orcus_test_xls_xml.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xlsx-orcus_test_xlsx.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xml-orcus_test_xml.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xml_mapped-orcus_test_global.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xml_mapped-orcus_test_xml_mapped.Po
+ -rm -f ./$(DEPDIR)/orcus_xls_xml-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_xls_xml-orcus_xls_xml_main.Po
+ -rm -f ./$(DEPDIR)/orcus_xlsx-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_xlsx-orcus_xlsx_main.Po
+ -rm -f ./$(DEPDIR)/orcus_xml-cli_global.Po
+ -rm -f ./$(DEPDIR)/orcus_xml-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_xml-orcus_xml_main.Po
+ -rm -f ./$(DEPDIR)/orcus_yaml-orcus_yaml_main.Po
+ -rm -f ./$(DEPDIR)/orcus_zip_dump-orcus_zip_dump.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-local distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/orcus_css_dump-orcus_css_dump.Po
+ -rm -f ./$(DEPDIR)/orcus_csv-orcus_csv_main.Po
+ -rm -f ./$(DEPDIR)/orcus_csv-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_detect-orcus_detect_main.Po
+ -rm -f ./$(DEPDIR)/orcus_env_dump-orcus_env_dump.Po
+ -rm -f ./$(DEPDIR)/orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_gnumeric-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_gnumeric-orcus_gnumeric_main.Po
+ -rm -f ./$(DEPDIR)/orcus_json-cli_global.Po
+ -rm -f ./$(DEPDIR)/orcus_json-orcus_json_cli.Po
+ -rm -f ./$(DEPDIR)/orcus_json-orcus_json_cli_map.Po
+ -rm -f ./$(DEPDIR)/orcus_mso_encryption-orcus_mso_encryption.Po
+ -rm -f ./$(DEPDIR)/orcus_ods-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_ods-orcus_ods_main.Po
+ -rm -f ./$(DEPDIR)/orcus_parquet_main.Po
+ -rm -f ./$(DEPDIR)/orcus_styles_ods-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_styles_ods-orcus_ods_styles.Po
+ -rm -f ./$(DEPDIR)/orcus_test_csv-orcus_test_csv.Po
+ -rm -f ./$(DEPDIR)/orcus_test_csv-orcus_test_global.Po
+ -rm -f ./$(DEPDIR)/orcus_test_gnumeric-orcus_test_global.Po
+ -rm -f ./$(DEPDIR)/orcus_test_gnumeric-orcus_test_gnumeric.Po
+ -rm -f ./$(DEPDIR)/orcus_test_import_ods-orcus_test_import_ods.Po
+ -rm -f ./$(DEPDIR)/orcus_test_json_mapped-orcus_test_json_mapped.Po
+ -rm -f ./$(DEPDIR)/orcus_test_ods-orcus_test_ods.Po
+ -rm -f ./$(DEPDIR)/orcus_test_parquet-orcus_test_parquet.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xls_xml-orcus_test_global.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xls_xml-orcus_test_xls_xml.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xlsx-orcus_test_xlsx.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xml-orcus_test_xml.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xml_mapped-orcus_test_global.Po
+ -rm -f ./$(DEPDIR)/orcus_test_xml_mapped-orcus_test_xml_mapped.Po
+ -rm -f ./$(DEPDIR)/orcus_xls_xml-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_xls_xml-orcus_xls_xml_main.Po
+ -rm -f ./$(DEPDIR)/orcus_xlsx-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_xlsx-orcus_xlsx_main.Po
+ -rm -f ./$(DEPDIR)/orcus_xml-cli_global.Po
+ -rm -f ./$(DEPDIR)/orcus_xml-orcus_filter_global.Po
+ -rm -f ./$(DEPDIR)/orcus_xml-orcus_xml_main.Po
+ -rm -f ./$(DEPDIR)/orcus_yaml-orcus_yaml_main.Po
+ -rm -f ./$(DEPDIR)/orcus_zip_dump-orcus_zip_dump.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-TESTS check-am check-valgrind-am \
+ check-valgrind-drd-am check-valgrind-drd-local \
+ check-valgrind-helgrind-am check-valgrind-helgrind-local \
+ check-valgrind-local check-valgrind-memcheck-am \
+ check-valgrind-memcheck-local check-valgrind-sgcheck-am \
+ check-valgrind-sgcheck-local clean clean-binPROGRAMS \
+ clean-generic clean-libtool cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-local distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \
+ uninstall uninstall-am uninstall-binPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+distclean-local:
+ rm -rf $(TESTS)
+
+@VALGRIND_CHECK_RULES@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/cli_global.cpp b/src/cli_global.cpp
new file mode 100644
index 0000000..85e37c6
--- /dev/null
+++ b/src/cli_global.cpp
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "cli_global.hpp"
+
+#include <iostream>
+#include <fstream>
+
+#include "filesystem_env.hpp"
+
+namespace po = boost::program_options;
+
+namespace orcus {
+
+output_stream::output_stream(const boost::program_options::variables_map& vm) :
+ m_os(&std::cout)
+{
+ if (!vm.count("output"))
+ // No output parameter given. Output to stdout.
+ return;
+
+ std::string output_path = vm["output"].as<std::string>();
+
+ if (output_path.empty())
+ // Specified output path is empty.
+ return;
+
+ // Check to make sure the output path doesn't point to an existing
+ // directory.
+ if (fs::is_directory(output_path))
+ {
+ std::ostringstream os;
+ os << "Output file path points to an existing directory.";
+ throw std::invalid_argument(os.str());
+ }
+
+ // Output to stdout when output path is not given.
+ m_ofs = std::make_unique<std::ofstream>(output_path.data());
+ m_os = m_ofs.get();
+}
+
+output_stream::output_stream(output_stream&& other) :
+ m_ofs(std::move(other.m_ofs)),
+ m_os(other.m_os)
+{
+ if (m_ofs)
+ m_os = m_ofs.get();
+
+ other.m_os = nullptr;
+}
+
+std::ostream& output_stream::get()
+{
+ return *m_os;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/cli_global.hpp b/src/cli_global.hpp
new file mode 100644
index 0000000..75f6cf6
--- /dev/null
+++ b/src/cli_global.hpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_CLI_GLOBAL_HPP
+#define INCLUDED_ORCUS_CLI_GLOBAL_HPP
+
+#include <boost/program_options.hpp>
+#include <iosfwd>
+
+namespace orcus {
+
+/**
+ * This class abstracts away an instance of std::ostream. It's either
+ * std::cout (if no output file path is specified) or std::ofstream if an
+ * output file path is specified via CLI.
+ */
+class output_stream
+{
+ std::unique_ptr<std::ofstream> m_ofs;
+ std::ostream* m_os;
+
+public:
+ output_stream(const boost::program_options::variables_map& vm);
+ output_stream(output_stream&& other);
+ output_stream(const output_stream&) = delete;
+ output_stream& operator=(const output_stream&) = delete;
+
+ std::ostream& get();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
new file mode 100644
index 0000000..e4006c8
--- /dev/null
+++ b/src/include/Makefile.am
@@ -0,0 +1,9 @@
+SUBDIRS = mso
+
+EXTRA_DIST = \
+ cpu_features.hpp \
+ filesystem_env.hpp \
+ mock_spreadsheet.hpp \
+ numeric_parser.hpp \
+ ostream_utils.hpp \
+ test_global.hpp
diff --git a/src/include/Makefile.in b/src/include/Makefile.in
new file mode 100644
index 0000000..9c77c71
--- /dev/null
+++ b/src/include/Makefile.in
@@ -0,0 +1,726 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/include
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+SUBDIRS = mso
+EXTRA_DIST = \
+ cpu_features.hpp \
+ filesystem_env.hpp \
+ mock_spreadsheet.hpp \
+ numeric_parser.hpp \
+ ostream_utils.hpp \
+ test_global.hpp
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/include/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/include/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-recursive
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-recursive
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-recursive
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-recursive
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-recursive
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am check-valgrind-am check-valgrind-drd-am \
+ check-valgrind-drd-local check-valgrind-helgrind-am \
+ check-valgrind-helgrind-local check-valgrind-local \
+ check-valgrind-memcheck-am check-valgrind-memcheck-local \
+ check-valgrind-sgcheck-am check-valgrind-sgcheck-local clean \
+ clean-generic clean-libtool cscopelist-am ctags ctags-am \
+ distclean distclean-generic distclean-libtool distclean-tags \
+ distdir dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/include/cpu_features.hpp b/src/include/cpu_features.hpp
new file mode 100644
index 0000000..4bdee9c
--- /dev/null
+++ b/src/include/cpu_features.hpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_DETAIL_CPU_FEATURES_HPP
+#define INCLUDED_ORCUS_DETAIL_CPU_FEATURES_HPP
+
+namespace orcus { namespace detail { namespace cpu {
+
+#ifdef __ORCUS_CPU_FEATURES
+
+constexpr bool has_sse42()
+{
+#if defined(__SSE4_2__) || defined(__AVX2__)
+ return true;
+#else
+ return false;
+#endif
+}
+
+constexpr bool has_avx2()
+{
+#ifdef __AVX2__
+ return true;
+#else
+ return false;
+#endif
+}
+
+#else
+
+constexpr bool has_sse42() { return false; }
+constexpr bool has_avx2() { return false; }
+
+#endif
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/include/filesystem_env.hpp b/src/include/filesystem_env.hpp
new file mode 100644
index 0000000..fea82b5
--- /dev/null
+++ b/src/include/filesystem_env.hpp
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#ifdef HAVE_FILESYSTEM
+#include <filesystem>
+namespace fs = std::filesystem;
+#else
+#ifdef HAVE_EXPERIMENTAL_FILESYSTEM
+#include <experimental/filesystem>
+namespace fs = std::experimental::filesystem;
+#else
+#include <boost/filesystem.hpp>
+namespace fs = boost::filesystem;
+#endif
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/include/mock_spreadsheet.hpp b/src/include/mock_spreadsheet.hpp
new file mode 100644
index 0000000..5f6a332
--- /dev/null
+++ b/src/include/mock_spreadsheet.hpp
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_SPREADSHEET_MOCK_IMPORT_INTERFACE_HPP__
+#define __ORCUS_SPREADSHEET_MOCK_IMPORT_INTERFACE_HPP__
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+
+namespace orcus { namespace spreadsheet { namespace mock {
+
+class import_shared_strings : public orcus::spreadsheet::iface::import_shared_strings
+{
+public:
+ virtual ~import_shared_strings() override;
+
+ virtual size_t append(std::string_view s) override;
+
+ virtual size_t add(std::string_view s) override;
+
+ virtual void set_segment_font(size_t font_index) override;
+ virtual void set_segment_bold(bool b) override;
+ virtual void set_segment_italic(bool b) override;
+ virtual void set_segment_font_name(std::string_view s) override;
+ virtual void set_segment_font_size(double point) override;
+ virtual void set_segment_font_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void append_segment(std::string_view s) override;
+ virtual size_t commit_segments() override;
+};
+
+class import_styles : public orcus::spreadsheet::iface::import_styles
+{
+public:
+ virtual ~import_styles() override;
+
+ // font
+
+ virtual void set_font_count(size_t n) override;
+ virtual iface::import_font_style* start_font_style() override;
+
+ // fill
+
+ virtual void set_fill_count(size_t n) override;
+ virtual iface::import_fill_style* start_fill_style() override;
+
+ // border
+
+ virtual void set_border_count(size_t n) override;
+ virtual iface::import_border_style* start_border_style() override;
+
+ virtual void set_xf_count(xf_category_t cat, size_t n) = 0;
+ virtual void set_cell_style_count(size_t n) override;
+};
+
+class import_sheet_properties : public orcus::spreadsheet::iface::import_sheet_properties
+{
+public:
+ virtual ~import_sheet_properties() override;
+
+ virtual void set_column_width(
+ orcus::spreadsheet::col_t col, orcus::spreadsheet::col_t col_span, double width, orcus::length_unit_t unit) override;
+
+ virtual void set_column_hidden(
+ orcus::spreadsheet::col_t col, orcus::spreadsheet::col_t col_span, bool hidden) override;
+
+ virtual void set_row_height(orcus::spreadsheet::row_t row, double height, orcus::length_unit_t unit) override;
+
+ virtual void set_row_hidden(orcus::spreadsheet::row_t row, bool hidden) override;
+
+ virtual void set_merge_cell_range(const range_t& range) override;
+};
+
+class import_reference_resolver : public orcus::spreadsheet::iface::import_reference_resolver
+{
+public:
+ virtual ~import_reference_resolver() override;
+
+ virtual src_address_t resolve_address(std::string_view address) override;
+
+ virtual src_range_t resolve_range(std::string_view range) override;
+};
+
+class import_array_formula : public orcus::spreadsheet::iface::import_array_formula
+{
+public:
+ virtual ~import_array_formula() override;
+
+ virtual void set_range(const range_t& range) override;
+
+ virtual void set_formula(formula_grammar_t grammar, std::string_view formula) override;
+
+ virtual void set_result_value(row_t row, col_t col, double value) override;
+
+ virtual void set_result_string(row_t row, col_t col, std::string_view value) override;
+
+ virtual void set_result_empty(row_t row, col_t col) override;
+
+ virtual void set_result_bool(row_t row, col_t col, bool value) override;
+
+ virtual void commit() override;
+};
+
+class import_formula : public orcus::spreadsheet::iface::import_formula
+{
+public:
+ virtual ~import_formula() override;
+ virtual void set_position(row_t row, col_t col) override;
+ virtual void set_formula(formula_grammar_t grammar, std::string_view formula) override;
+ virtual void set_shared_formula_index(size_t index) override;
+ virtual void set_result_value(double value) override;
+ virtual void set_result_string(std::string_view value) override;
+ virtual void set_result_bool(bool value) override;
+ virtual void set_result_empty() override;
+ virtual void commit() override;
+};
+
+/**
+ * Interface for sheet.
+ */
+class import_sheet : public orcus::spreadsheet::iface::import_sheet
+{
+public:
+ virtual ~import_sheet() override;
+
+ virtual void set_auto(orcus::spreadsheet::row_t row, orcus::spreadsheet::col_t col, std::string_view s) override;
+
+ virtual void set_string(orcus::spreadsheet::row_t row, orcus::spreadsheet::col_t col, orcus::spreadsheet::string_id_t sindex) override;
+
+ virtual void set_value(orcus::spreadsheet::row_t row, orcus::spreadsheet::col_t col, double value) override;
+
+ virtual void set_bool(orcus::spreadsheet::row_t row, orcus::spreadsheet::col_t col, bool value) override;
+
+ virtual void set_date_time(
+ orcus::spreadsheet::row_t row, orcus::spreadsheet::col_t col,
+ int year, int month, int day, int hours, int minutes, double seconds) override;
+
+ virtual void set_format(orcus::spreadsheet::row_t row, orcus::spreadsheet::col_t col, size_t xf_index) override;
+
+ virtual void set_format(orcus::spreadsheet::row_t row_start, orcus::spreadsheet::col_t col_start,
+ orcus::spreadsheet::row_t row_end, orcus::spreadsheet::col_t col_end, size_t xf_index) override;
+
+ virtual void set_column_format(col_t col, col_t col_span, std::size_t xf_index) override;
+
+ virtual void set_row_format(row_t col, std::size_t xf_index) override;
+
+ virtual void fill_down_cells(row_t src_row, col_t src_col, row_t range_size) override;
+
+ virtual orcus::spreadsheet::range_size_t get_sheet_size() const override;
+};
+
+class import_factory : public orcus::spreadsheet::iface::import_factory
+{
+public:
+ virtual ~import_factory() override;
+
+ virtual orcus::spreadsheet::iface::import_global_settings* get_global_settings() override;
+
+ virtual orcus::spreadsheet::iface::import_shared_strings* get_shared_strings() override;
+
+ virtual orcus::spreadsheet::iface::import_styles* get_styles() override;
+
+ virtual orcus::spreadsheet::iface::import_sheet* append_sheet(
+ orcus::spreadsheet::sheet_t sheet_index, std::string_view name) override;
+
+ virtual orcus::spreadsheet::iface::import_sheet* get_sheet(std::string_view name) override;
+
+ virtual orcus::spreadsheet::iface::import_sheet* get_sheet(orcus::spreadsheet::sheet_t sheet_index) override;
+
+ virtual void finalize() override;
+};
+
+}}}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/include/mso/Makefile.am b/src/include/mso/Makefile.am
new file mode 100644
index 0000000..0865972
--- /dev/null
+++ b/src/include/mso/Makefile.am
@@ -0,0 +1,3 @@
+
+EXTRA_DIST = \
+ encryption_info.hpp
diff --git a/src/include/mso/Makefile.in b/src/include/mso/Makefile.in
new file mode 100644
index 0000000..c4f6e99
--- /dev/null
+++ b/src/include/mso/Makefile.in
@@ -0,0 +1,542 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/include/mso
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+EXTRA_DIST = \
+ encryption_info.hpp
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/include/mso/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/include/mso/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-am
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-am
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-am
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-am
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-am
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am check-valgrind-am \
+ check-valgrind-drd-am check-valgrind-drd-local \
+ check-valgrind-helgrind-am check-valgrind-helgrind-local \
+ check-valgrind-local check-valgrind-memcheck-am \
+ check-valgrind-memcheck-local check-valgrind-sgcheck-am \
+ check-valgrind-sgcheck-local clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/include/mso/encryption_info.hpp b/src/include/mso/encryption_info.hpp
new file mode 100644
index 0000000..efda244
--- /dev/null
+++ b/src/include/mso/encryption_info.hpp
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_MSO_ENCRYPTION_INFO_HPP__
+#define __ORCUS_MSO_ENCRYPTION_INFO_HPP__
+
+#include <orcus/env.hpp>
+
+#include <cstdlib>
+
+namespace orcus { namespace mso {
+
+struct encryption_info_reader_impl;
+
+class ORCUS_MSO_DLLPUBLIC encryption_info_reader
+{
+ encryption_info_reader(const encryption_info_reader&); // disabled
+ encryption_info_reader& operator= (const encryption_info_reader&); // disabled
+
+public:
+ encryption_info_reader();
+ ~encryption_info_reader();
+
+ void read(const char* p, size_t n);
+
+private:
+ encryption_info_reader_impl* mp_impl;
+};
+
+}}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/include/numeric_parser.hpp b/src/include/numeric_parser.hpp
new file mode 100644
index 0000000..fc047b6
--- /dev/null
+++ b/src/include/numeric_parser.hpp
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_DETAIL_NUMERIC_PARSER_HPP
+#define INCLUDED_ORCUS_DETAIL_NUMERIC_PARSER_HPP
+
+#include <mdds/global.hpp>
+#include <limits>
+#include <cmath>
+
+namespace orcus { namespace detail {
+
+struct generic_parser_trait {};
+
+struct json_parser_trait {};
+
+struct parser_state
+{
+ /** number of digits before the decimal point. */
+ int int_digit_count = 0;
+ /** number of digits after the decimal point. */
+ int frac_digit_count = 0;
+ /** first digit before the decimal point. */
+ char first_int_digit = 0;
+ double parsed_value = 0.0;
+ double divisor = 1.0;
+ bool has_digit = false;
+ bool has_decimal = false;
+ bool negative_sign = false;
+};
+
+template<typename _Trait>
+double make_final_value(const parser_state& state);
+
+template<>
+inline double make_final_value<generic_parser_trait>(const parser_state& state)
+{
+ return state.negative_sign ? -state.parsed_value : state.parsed_value;
+}
+
+template<>
+inline double make_final_value<json_parser_trait>(const parser_state& state)
+{
+ if (state.int_digit_count > 1 && state.first_int_digit == 0)
+ // leading zeros not allowed.
+ return std::numeric_limits<double>::quiet_NaN();
+
+ if (state.has_decimal && (state.frac_digit_count == 0 || state.int_digit_count == 0))
+ // at least one digit is required both before and after the decimal point.
+ return std::numeric_limits<double>::quiet_NaN();
+
+ return state.negative_sign ? -state.parsed_value : state.parsed_value;
+}
+
+template<typename _Trait>
+class numeric_parser
+{
+ using trait_type = _Trait;
+
+ const char* mp_char;
+ const char* mp_end;
+
+ parser_state m_state;
+
+ bool check_sign()
+ {
+ bool negative_sign = false;
+
+ // Check for presence of a sign.
+ if (mp_char != mp_end)
+ {
+ switch (*mp_char)
+ {
+ case '+':
+ ++mp_char;
+ break;
+ case '-':
+ negative_sign = true;
+ ++mp_char;
+ break;
+ default:
+ ;
+ }
+ }
+
+ return negative_sign;
+ }
+
+ /**
+ * Parse the exponent part of a numeric string.
+ *
+ * @return extra divisor to multiply to the original divisor, or 0.0 if the
+ * parsing fails.
+ */
+ double parse_exponent()
+ {
+ const char* p0 = mp_char - 1; // original position to restore to in case of parsing failure. The e needs to be added back as well.
+ double exponent = 0.0;
+ bool valid = false;
+
+ bool negative_sign = check_sign();
+
+ for (; mp_char != mp_end; ++mp_char)
+ {
+ if (*mp_char < '0' || '9' < *mp_char)
+ {
+ // Non-digit encountered.
+ break;
+ }
+
+ valid = true;
+ exponent *= 10.0;
+ exponent += *mp_char - '0';
+ }
+
+ if (!valid)
+ {
+ // Restore the original position on failed parsing.
+ mp_char = p0;
+ return 0.0;
+ }
+
+ if (!negative_sign)
+ exponent = -exponent;
+
+ return std::pow(10.0, exponent);
+ }
+
+public:
+ numeric_parser(const char* p, const char* p_end) :
+ mp_char(p),
+ mp_end(p_end) {}
+
+ /**
+ * Start parsing the string.
+ *
+ * @return a finite value upon successful parsing, else NaN is returned.
+ */
+ double parse()
+ {
+ m_state.negative_sign = check_sign();
+
+ for (; mp_char != mp_end; ++mp_char)
+ {
+ if (*mp_char == '.')
+ {
+ if (m_state.has_decimal)
+ {
+ // Second '.' encountered. Terminate the parsing.
+ m_state.parsed_value /= m_state.divisor;
+ return make_final_value<trait_type>(m_state);
+ }
+
+ m_state.has_decimal = true;
+ continue;
+ }
+
+ if (m_state.has_digit && (*mp_char == 'e' || *mp_char == 'E'))
+ {
+ ++mp_char;
+ double extra_divisor = parse_exponent();
+ if (extra_divisor)
+ m_state.divisor *= extra_divisor;
+ break;
+ }
+
+ if (*mp_char < '0' || '9' < *mp_char)
+ {
+ if (!m_state.has_digit) // without a digit we have no numbers
+ return std::numeric_limits<double>::quiet_NaN();
+
+ m_state.parsed_value /= m_state.divisor;
+ return make_final_value<trait_type>(m_state);
+ }
+
+ m_state.has_digit = true;
+ char digit = *mp_char - '0';
+
+ if (m_state.has_decimal)
+ ++m_state.frac_digit_count;
+ else
+ {
+ if (!m_state.int_digit_count)
+ m_state.first_int_digit = digit;
+
+ ++m_state.int_digit_count;
+ }
+
+ m_state.parsed_value *= 10.0;
+ m_state.parsed_value += digit;
+
+ if (m_state.has_decimal)
+ m_state.divisor *= 10.0;
+ }
+ if (!m_state.has_digit) // without a digit we have no numbers
+ return std::numeric_limits<double>::quiet_NaN();
+
+ m_state.parsed_value /= m_state.divisor;
+ return make_final_value<trait_type>(m_state);
+ }
+
+ const char* get_char_position() const
+ {
+ return mp_char;
+ }
+};
+
+}} // namespace orcus::detail
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/include/ostream_utils.hpp b/src/include/ostream_utils.hpp
new file mode 100644
index 0000000..634b1f5
--- /dev/null
+++ b/src/include/ostream_utils.hpp
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <ostream>
+#include <string_view>
+
+namespace orcus { namespace detail {
+
+class ostream_format_guard
+{
+ std::ostream& m_os;
+ std::ios_base::fmtflags m_flags;
+public:
+ ostream_format_guard(std::ostream& os) :
+ m_os(os)
+ {
+ m_flags = m_os.flags();
+ }
+
+ ~ostream_format_guard()
+ {
+ m_os.setf(m_flags);
+ }
+};
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/include/test_global.hpp b/src/include/test_global.hpp
new file mode 100644
index 0000000..e217086
--- /dev/null
+++ b/src/include/test_global.hpp
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_TEST_GLOBAL_HPP
+#define INCLUDED_ORCUS_TEST_GLOBAL_HPP
+
+#ifdef NDEBUG
+// release build
+#undef NDEBUG
+#include <cassert>
+#else
+// debug build
+#include <cassert>
+#endif
+
+#include <iostream>
+#include <chrono>
+
+namespace orcus { namespace test {
+
+class stack_printer
+{
+public:
+ explicit stack_printer(const char* msg);
+ ~stack_printer();
+
+private:
+ double get_time() const;
+
+ std::string m_msg;
+ double m_start_time;
+};
+
+class assert_error : public std::exception
+{
+ std::string m_msg;
+
+public:
+ assert_error(const char* filename, size_t line_no, const char* msg);
+
+ virtual const char* what() const noexcept override;
+};
+
+void verify_content(
+ const char* filename, size_t line_no, std::string_view expected, const std::string& actual);
+
+}} // namespace orcus::test
+
+#define ORCUS_TEST_FUNC_SCOPE orcus::test::stack_printer __sp__(__func__)
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/Makefile.am b/src/liborcus/Makefile.am
new file mode 100644
index 0000000..4f42193
--- /dev/null
+++ b/src/liborcus/Makefile.am
@@ -0,0 +1,590 @@
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include \
+ -I./include $(BOOST_CPPFLAGS)
+
+EXTRA_PROGRAMS = \
+ css-document-tree-test \
+ json-document-tree-test \
+ yaml-document-tree-test \
+ xml-map-tree-test \
+ common-test \
+ dom-tree-test \
+ json-structure-tree-test \
+ json-map-tree-test \
+ xml-structure-tree-test \
+ xpath-parser-test
+
+TESTS =
+
+EXTRA_DIST = \
+ xml_element_types.hpp
+
+if HAVE_STATIC_LIB
+AM_CPPFLAGS += -D__ORCUS_STATIC_LIB=1
+else
+AM_CPPFLAGS += -D__ORCUS_BUILDING_DLL=1
+endif
+
+if HAVE_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_FILESYSTEM=1"
+endif
+
+if HAVE_EXPERIMENTAL_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+endif
+
+liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS = \
+ $(ZLIB_CFLAGS)
+
+liborcus_@ORCUS_API_VERSION@_la_LDFLAGS = \
+ -no-undefined $(BOOST_SYSTEM_LDFLAGS)
+
+liborcus_@ORCUS_API_VERSION@_la_LIBADD = \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS) $(ZLIB_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+liborcus_@ORCUS_API_VERSION@_la_LDFLAGS += -lstdc++fs
+else
+liborcus_@ORCUS_API_VERSION@_la_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+liborcus_@ORCUS_API_VERSION@_la_LIBADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+AM_CPPFLAGS += -DSRCDIR=\""$(top_srcdir)"\"
+
+lib_LTLIBRARIES = liborcus-@ORCUS_API_VERSION@.la
+liborcus_@ORCUS_API_VERSION@_la_SOURCES = \
+ config.cpp \
+ css_document_tree.cpp \
+ css_selector.cpp \
+ detection_result.hpp \
+ detection_result.cpp \
+ dom_tree.cpp \
+ format_detection.cpp \
+ formula_result.hpp \
+ formula_result.cpp \
+ impl_utils.hpp \
+ info.cpp \
+ interface.cpp \
+ json_document_tree.cpp \
+ json_map_tree.hpp \
+ json_map_tree.cpp \
+ json_structure_mapper.hpp \
+ json_structure_mapper.cpp \
+ json_structure_tree.cpp \
+ json_util.hpp \
+ json_util.cpp \
+ spreadsheet_interface.cpp \
+ orcus_csv.cpp \
+ orcus_json.cpp \
+ orcus_xml.cpp \
+ orcus_xml_impl.hpp \
+ orcus_xml_impl.cpp \
+ orcus_xml_map_def.cpp \
+ measurement.cpp \
+ number_utils.cpp \
+ number_utils.hpp \
+ xml_context_base.hpp \
+ xml_context_base.cpp \
+ xml_context_global.hpp \
+ xml_context_global.cpp \
+ xml_element_types.cpp \
+ xml_element_validator.hpp \
+ xml_element_validator.cpp \
+ xml_empty_context.hpp \
+ xml_empty_context.cpp \
+ xml_map_tree.hpp \
+ xml_map_tree.cpp \
+ xml_stream_handler.hpp \
+ xml_stream_handler.cpp \
+ xml_stream_parser.hpp \
+ xml_stream_parser.cpp \
+ xml_simple_stream_handler.hpp \
+ xml_simple_stream_handler.cpp \
+ xml_structure_mapper.hpp \
+ xml_structure_mapper.cpp \
+ xml_structure_tree.cpp \
+ xml_util.hpp \
+ xml_util.cpp \
+ xpath_parser.cpp \
+ yaml_document_tree.cpp \
+ ooxml_namespace_types.cpp \
+ ooxml_namespace_types.hpp \
+ odf_namespace_types.hpp \
+ odf_namespace_types_hpp.inl \
+ odf_namespace_types.cpp \
+ odf_namespace_types_cpp.inl \
+ gnumeric_namespace_types.hpp \
+ gnumeric_namespace_types.cpp \
+ xls_xml_namespace_types.hpp \
+ xls_xml_namespace_types.cpp \
+ session_context.hpp \
+ session_context.cpp \
+ spreadsheet_impl_types.hpp \
+ spreadsheet_impl_types.cpp \
+ spreadsheet_types.cpp \
+ spreadsheet_iface_util.hpp \
+ spreadsheet_iface_util.cpp \
+ string_helper.hpp \
+ string_helper.cpp
+
+if WITH_XLSX_FILTER
+
+EXTRA_PROGRAMS += \
+ xlsx-sheet-context-test
+
+liborcus_@ORCUS_API_VERSION@_la_SOURCES += \
+ ooxml_content_types.cpp \
+ ooxml_content_types.hpp \
+ ooxml_global.cpp \
+ ooxml_global.hpp \
+ ooxml_schemas.cpp \
+ ooxml_schemas.hpp \
+ ooxml_token_constants.hpp \
+ ooxml_token_constants.inl \
+ ooxml_tokens.cpp \
+ ooxml_tokens.hpp \
+ ooxml_tokens.inl \
+ ooxml_types.hpp \
+ ooxml_types.cpp \
+ opc_context.cpp \
+ opc_context.hpp \
+ opc_reader.cpp \
+ opc_reader.hpp \
+ opc_reader.hpp \
+ opc_token_constants.hpp \
+ opc_token_constants.inl \
+ opc_tokens.inl \
+ orcus_xlsx.cpp \
+ orcus_import_xlsx.cpp \
+ xlsx_shared_strings_context.cpp \
+ xlsx_shared_strings_context.hpp \
+ xlsx_drawing_context.hpp \
+ xlsx_drawing_context.cpp \
+ xlsx_handler.cpp \
+ xlsx_handler.hpp \
+ xlsx_helper.cpp \
+ xlsx_helper.hpp \
+ xlsx_session_data.hpp \
+ xlsx_session_data.cpp \
+ xlsx_revision_context.cpp \
+ xlsx_revision_context.hpp \
+ xlsx_pivot_context.cpp \
+ xlsx_pivot_context.hpp \
+ xlsx_sheet_context.cpp \
+ xlsx_sheet_context.hpp \
+ xlsx_styles_context.cpp \
+ xlsx_styles_context.hpp \
+ xlsx_conditional_format_context.cpp \
+ xlsx_conditional_format_context.hpp \
+ xlsx_table_context.cpp \
+ xlsx_table_context.hpp \
+ xlsx_autofilter_context.cpp \
+ xlsx_autofilter_context.hpp \
+ xlsx_types.hpp \
+ xlsx_types.cpp \
+ xlsx_workbook_context.cpp \
+ xlsx_workbook_context.hpp
+
+# xlsx-sheet-context-test
+
+xlsx_sheet_context_test_SOURCES = \
+ formula_result.cpp \
+ ooxml_global.cpp \
+ ooxml_namespace_types.cpp \
+ ooxml_schemas.cpp \
+ ooxml_tokens.cpp \
+ ooxml_types.cpp \
+ session_context.cpp \
+ spreadsheet_interface.cpp \
+ xlsx_autofilter_context.cpp \
+ xlsx_conditional_format_context.cpp \
+ xlsx_helper.cpp \
+ xlsx_session_data.cpp \
+ xlsx_sheet_context.cpp \
+ xlsx_sheet_context_test.cpp \
+ xlsx_types.cpp \
+ xml_context_base.cpp \
+ xml_context_global.cpp \
+ xml_element_types.cpp \
+ xml_element_validator.cpp \
+ xml_empty_context.cpp \
+ xml_util.cpp
+
+xlsx_sheet_context_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+
+xlsx_sheet_context_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+TESTS += \
+ xlsx-sheet-context-test
+
+endif # WITH_XLSX_FILTER
+
+if WITH_XLS_XML_FILTER
+
+liborcus_@ORCUS_API_VERSION@_la_SOURCES += \
+ xls_xml_tokens.hpp \
+ xls_xml_tokens.inl \
+ xls_xml_tokens.cpp \
+ xls_xml_token_constants.hpp \
+ xls_xml_token_constants.inl \
+ orcus_xls_xml.cpp \
+ xls_xml_detection_handler.hpp \
+ xls_xml_detection_handler.cpp \
+ xls_xml_handler.hpp \
+ xls_xml_handler.cpp \
+ xls_xml_context.hpp \
+ xls_xml_context.cpp
+
+endif # WITH_XLS_XML_FILTER
+
+if WITH_ODS_FILTER
+
+liborcus_@ORCUS_API_VERSION@_la_SOURCES += \
+ odf_document_styles_context.hpp \
+ odf_document_styles_context.cpp \
+ odf_para_context.hpp \
+ odf_para_context.cpp \
+ odf_styles.hpp \
+ odf_styles.cpp \
+ odf_styles_context.hpp \
+ odf_styles_context.cpp \
+ odf_style_context.hpp \
+ odf_style_context.cpp \
+ odf_number_format_context.hpp \
+ odf_number_format_context.cpp \
+ odf_token_constants.hpp \
+ odf_token_constants.inl \
+ odf_tokens.hpp \
+ odf_tokens.inl \
+ odf_tokens.cpp \
+ ods_content_xml_context.hpp \
+ ods_content_xml_context.cpp \
+ ods_dde_links_context.hpp \
+ ods_dde_links_context.cpp \
+ ods_session_data.hpp \
+ ods_session_data.cpp \
+ odf_helper.hpp \
+ odf_helper.cpp \
+ orcus_ods.cpp \
+ orcus_import_ods.cpp
+
+# odf-helper-test
+
+EXTRA_PROGRAMS += \
+ odf-helper-test
+
+odf_helper_test_SOURCES = \
+ odf_helper.cpp \
+ string_helper.cpp \
+ odf_helper_test.cpp
+
+odf_helper_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+
+odf_helper_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+TESTS += \
+ odf-helper-test
+
+endif # WITH_ODS_FILTER
+
+if WITH_GNUMERIC_FILTER
+
+liborcus_@ORCUS_API_VERSION@_la_SOURCES += \
+ gnumeric_cell_context.cpp \
+ gnumeric_cell_context.hpp \
+ gnumeric_context.cpp \
+ gnumeric_context.hpp \
+ gnumeric_detection_handler.cpp \
+ gnumeric_detection_handler.hpp \
+ gnumeric_filter_context.cpp \
+ gnumeric_filter_context.hpp \
+ gnumeric_handler.cpp \
+ gnumeric_handler.hpp \
+ gnumeric_names_context.cpp \
+ gnumeric_names_context.hpp \
+ gnumeric_sheet_context.cpp \
+ gnumeric_sheet_context.hpp \
+ gnumeric_styles_context.cpp \
+ gnumeric_styles_context.hpp \
+ gnumeric_token_constants.hpp \
+ gnumeric_token_constants.inl \
+ gnumeric_tokens.cpp \
+ gnumeric_tokens.hpp \
+ gnumeric_tokens.inl \
+ gnumeric_types.cpp \
+ gnumeric_types.hpp \
+ gnumeric_value_format_parser.cpp \
+ gnumeric_value_format_parser.hpp \
+ orcus_gnumeric.cpp
+
+liborcus_@ORCUS_API_VERSION@_la_LDFLAGS += \
+ $(BOOST_IOSTREAMS_LDFLAGS)
+
+liborcus_@ORCUS_API_VERSION@_la_LIBADD += \
+ $(BOOST_IOSTREAMS_LIBS)
+
+# gnumeric-cell-context-test
+
+EXTRA_PROGRAMS += \
+ gnumeric-cell-context-test \
+ gnumeric-sheet-context-test
+
+gnumeric_cell_context_test_SOURCES = \
+ number_utils.cpp \
+ session_context.cpp \
+ gnumeric_cell_context_test.cpp \
+ gnumeric_cell_context.cpp \
+ gnumeric_value_format_parser.cpp \
+ xml_context_base.cpp \
+ xml_element_types.cpp \
+ xml_element_validator.cpp \
+ xml_empty_context.cpp \
+ xml_util.cpp \
+ gnumeric_namespace_types.cpp \
+ gnumeric_tokens.cpp \
+ gnumeric_types.cpp \
+ odf_namespace_types.cpp \
+ spreadsheet_interface.cpp
+
+gnumeric_cell_context_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+
+orcus_gnumeric_cell_context_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+TESTS += gnumeric-cell-context-test
+
+# gnumeric-sheet-context-test
+
+gnumeric_sheet_context_test_SOURCES = \
+ session_context.cpp \
+ gnumeric_sheet_context_test.cpp \
+ gnumeric_sheet_context.cpp \
+ gnumeric_names_context.cpp \
+ gnumeric_cell_context.cpp \
+ gnumeric_filter_context.cpp \
+ gnumeric_styles_context.cpp \
+ gnumeric_value_format_parser.cpp \
+ gnumeric_types.cpp \
+ number_utils.cpp \
+ xml_context_base.cpp \
+ xml_element_types.cpp \
+ xml_element_validator.cpp \
+ xml_empty_context.cpp \
+ xml_util.cpp \
+ gnumeric_namespace_types.cpp \
+ gnumeric_tokens.cpp \
+ odf_namespace_types.cpp \
+ spreadsheet_interface.cpp \
+ string_helper.cpp
+
+gnumeric_sheet_context_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+
+gnumeric_sheet_context_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+TESTS += gnumeric-sheet-context-test
+
+endif # WITH_GNUMERIC_FILTER
+
+if WITH_PARQUET_FILTER
+
+liborcus_@ORCUS_API_VERSION@_la_SOURCES += \
+ orcus_parquet.cpp
+
+liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS += \
+ $(PARQUET_CFLAGS)
+
+liborcus_@ORCUS_API_VERSION@_la_LDFLAGS += \
+ $(PARQUET_LDFLAGS)
+
+liborcus_@ORCUS_API_VERSION@_la_LIBADD += \
+ $(PARQUET_LIBS)
+
+endif # WITH_PARQUET_FILTER
+
+# css-document-tree-test
+
+css_document_tree_test_SOURCES = \
+ css_document_tree.cpp \
+ css_document_tree_test.cpp
+
+css_document_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+css_document_tree_test_LDADD += -lstdc++fs
+else
+css_document_tree_test_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+# json-document-tree-test
+
+json_document_tree_test_SOURCES = \
+ json_document_tree.cpp \
+ json_util.cpp \
+ json_document_tree_test.cpp
+
+json_document_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+json_document_tree_test_LDADD += -lstdc++fs
+else
+json_document_tree_test_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+json_document_tree_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# yaml-document-tree-test
+
+yaml_document_tree_test_SOURCES = \
+ yaml_document_tree.cpp \
+ json_util.cpp \
+ yaml_document_tree_test.cpp
+
+yaml_document_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+yaml_document_tree_test_LDADD += -lstdc++fs
+else
+yaml_document_tree_test_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+yaml_document_tree_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# xml-map-tree-test
+
+xml_map_tree_test_SOURCES = \
+ xml_map_tree.cpp \
+ xml_map_tree.hpp \
+ xpath_parser.hpp \
+ xpath_parser.cpp \
+ spreadsheet_impl_types.hpp \
+ spreadsheet_impl_types.cpp \
+ xml_map_tree_test.cpp
+
+xml_map_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+
+# xml-structure-tree-test
+
+xml_structure_tree_test_SOURCES = \
+ string_helper.cpp \
+ xml_structure_tree.cpp \
+ xml_structure_mapper.cpp \
+ xml_structure_tree_test.cpp
+
+xml_structure_tree_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+xml_structure_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+xml_structure_tree_test_LDADD += -lstdc++fs
+else
+xml_structure_tree_test_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+# common-test
+
+common_test_SOURCES = \
+ common_test.cpp
+
+common_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+
+# dom-tree-test
+
+dom_tree_test_SOURCES = dom_tree_test.cpp
+dom_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+
+# json-structure-tree-test
+
+json_structure_tree_test_SOURCES = json_structure_tree_test.cpp
+json_structure_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+json_structure_tree_test_LDADD += -lstdc++fs
+else
+json_structure_tree_test_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+# json-map-tree-test
+
+json_map_tree_test_SOURCES = json_map_tree_test.cpp \
+ json_map_tree.cpp \
+ spreadsheet_impl_types.cpp
+json_map_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+# xpath-parser-test
+
+xpath_parser_test_SOURCES = \
+ xpath_parser_test.cpp \
+ xpath_parser.cpp
+xpath_parser_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+TESTS += \
+ css-document-tree-test \
+ json-document-tree-test \
+ yaml-document-tree-test \
+ xml-map-tree-test \
+ common-test \
+ dom-tree-test \
+ json-structure-tree-test \
+ json-map-tree-test \
+ xml-structure-tree-test \
+ xpath-parser-test
+
+distclean-local:
+ rm -rf $(TESTS)
+
+@VALGRIND_CHECK_RULES@
diff --git a/src/liborcus/Makefile.in b/src/liborcus/Makefile.in
new file mode 100644
index 0000000..2b75863
--- /dev/null
+++ b/src/liborcus/Makefile.in
@@ -0,0 +1,4283 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = css-document-tree-test$(EXEEXT) \
+ json-document-tree-test$(EXEEXT) \
+ yaml-document-tree-test$(EXEEXT) xml-map-tree-test$(EXEEXT) \
+ common-test$(EXEEXT) dom-tree-test$(EXEEXT) \
+ json-structure-tree-test$(EXEEXT) json-map-tree-test$(EXEEXT) \
+ xml-structure-tree-test$(EXEEXT) xpath-parser-test$(EXEEXT) \
+ $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
+TESTS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ css-document-tree-test$(EXEEXT) \
+ json-document-tree-test$(EXEEXT) \
+ yaml-document-tree-test$(EXEEXT) xml-map-tree-test$(EXEEXT) \
+ common-test$(EXEEXT) dom-tree-test$(EXEEXT) \
+ json-structure-tree-test$(EXEEXT) json-map-tree-test$(EXEEXT) \
+ xml-structure-tree-test$(EXEEXT) xpath-parser-test$(EXEEXT)
+@HAVE_STATIC_LIB_TRUE@am__append_1 = -D__ORCUS_STATIC_LIB=1
+@HAVE_STATIC_LIB_FALSE@am__append_2 = -D__ORCUS_BUILDING_DLL=1
+@HAVE_FILESYSTEM_TRUE@am__append_3 = "-DHAVE_FILESYSTEM=1"
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@am__append_4 = "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_5 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_6 = $(BOOST_FILESYSTEM_LDFLAGS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_7 = $(BOOST_FILESYSTEM_LIBS)
+@WITH_XLSX_FILTER_TRUE@am__append_8 = \
+@WITH_XLSX_FILTER_TRUE@ xlsx-sheet-context-test
+
+@WITH_XLSX_FILTER_TRUE@am__append_9 = \
+@WITH_XLSX_FILTER_TRUE@ ooxml_content_types.cpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_content_types.hpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_global.cpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_global.hpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_schemas.cpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_schemas.hpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_token_constants.hpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_token_constants.inl \
+@WITH_XLSX_FILTER_TRUE@ ooxml_tokens.cpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_tokens.hpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_tokens.inl \
+@WITH_XLSX_FILTER_TRUE@ ooxml_types.hpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_types.cpp \
+@WITH_XLSX_FILTER_TRUE@ opc_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ opc_context.hpp \
+@WITH_XLSX_FILTER_TRUE@ opc_reader.cpp \
+@WITH_XLSX_FILTER_TRUE@ opc_reader.hpp \
+@WITH_XLSX_FILTER_TRUE@ opc_reader.hpp \
+@WITH_XLSX_FILTER_TRUE@ opc_token_constants.hpp \
+@WITH_XLSX_FILTER_TRUE@ opc_token_constants.inl \
+@WITH_XLSX_FILTER_TRUE@ opc_tokens.inl \
+@WITH_XLSX_FILTER_TRUE@ orcus_xlsx.cpp \
+@WITH_XLSX_FILTER_TRUE@ orcus_import_xlsx.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_shared_strings_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_shared_strings_context.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_drawing_context.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_drawing_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_handler.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_handler.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_helper.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_helper.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_session_data.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_session_data.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_revision_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_revision_context.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_pivot_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_pivot_context.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_styles_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_styles_context.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_conditional_format_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_conditional_format_context.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_table_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_table_context.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_autofilter_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_autofilter_context.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_types.hpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_types.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_workbook_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_workbook_context.hpp
+
+@WITH_XLSX_FILTER_TRUE@am__append_10 = \
+@WITH_XLSX_FILTER_TRUE@ xlsx-sheet-context-test
+
+@WITH_XLS_XML_FILTER_TRUE@am__append_11 = \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_tokens.hpp \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_tokens.inl \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_tokens.cpp \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_token_constants.hpp \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_token_constants.inl \
+@WITH_XLS_XML_FILTER_TRUE@ orcus_xls_xml.cpp \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_detection_handler.hpp \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_detection_handler.cpp \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_handler.hpp \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_handler.cpp \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_context.hpp \
+@WITH_XLS_XML_FILTER_TRUE@ xls_xml_context.cpp
+
+@WITH_ODS_FILTER_TRUE@am__append_12 = \
+@WITH_ODS_FILTER_TRUE@ odf_document_styles_context.hpp \
+@WITH_ODS_FILTER_TRUE@ odf_document_styles_context.cpp \
+@WITH_ODS_FILTER_TRUE@ odf_para_context.hpp \
+@WITH_ODS_FILTER_TRUE@ odf_para_context.cpp \
+@WITH_ODS_FILTER_TRUE@ odf_styles.hpp \
+@WITH_ODS_FILTER_TRUE@ odf_styles.cpp \
+@WITH_ODS_FILTER_TRUE@ odf_styles_context.hpp \
+@WITH_ODS_FILTER_TRUE@ odf_styles_context.cpp \
+@WITH_ODS_FILTER_TRUE@ odf_style_context.hpp \
+@WITH_ODS_FILTER_TRUE@ odf_style_context.cpp \
+@WITH_ODS_FILTER_TRUE@ odf_number_format_context.hpp \
+@WITH_ODS_FILTER_TRUE@ odf_number_format_context.cpp \
+@WITH_ODS_FILTER_TRUE@ odf_token_constants.hpp \
+@WITH_ODS_FILTER_TRUE@ odf_token_constants.inl \
+@WITH_ODS_FILTER_TRUE@ odf_tokens.hpp \
+@WITH_ODS_FILTER_TRUE@ odf_tokens.inl \
+@WITH_ODS_FILTER_TRUE@ odf_tokens.cpp \
+@WITH_ODS_FILTER_TRUE@ ods_content_xml_context.hpp \
+@WITH_ODS_FILTER_TRUE@ ods_content_xml_context.cpp \
+@WITH_ODS_FILTER_TRUE@ ods_dde_links_context.hpp \
+@WITH_ODS_FILTER_TRUE@ ods_dde_links_context.cpp \
+@WITH_ODS_FILTER_TRUE@ ods_session_data.hpp \
+@WITH_ODS_FILTER_TRUE@ ods_session_data.cpp \
+@WITH_ODS_FILTER_TRUE@ odf_helper.hpp \
+@WITH_ODS_FILTER_TRUE@ odf_helper.cpp \
+@WITH_ODS_FILTER_TRUE@ orcus_ods.cpp \
+@WITH_ODS_FILTER_TRUE@ orcus_import_ods.cpp
+
+
+# odf-helper-test
+@WITH_ODS_FILTER_TRUE@am__append_13 = \
+@WITH_ODS_FILTER_TRUE@ odf-helper-test
+
+@WITH_ODS_FILTER_TRUE@am__append_14 = \
+@WITH_ODS_FILTER_TRUE@ odf-helper-test
+
+@WITH_GNUMERIC_FILTER_TRUE@am__append_15 = \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_cell_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_cell_context.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_context.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_detection_handler.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_detection_handler.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_filter_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_filter_context.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_handler.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_handler.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_names_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_names_context.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_styles_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_styles_context.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_token_constants.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_token_constants.inl \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_tokens.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_tokens.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_tokens.inl \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_types.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_types.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_value_format_parser.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_value_format_parser.hpp \
+@WITH_GNUMERIC_FILTER_TRUE@ orcus_gnumeric.cpp
+
+@WITH_GNUMERIC_FILTER_TRUE@am__append_16 = \
+@WITH_GNUMERIC_FILTER_TRUE@ $(BOOST_IOSTREAMS_LDFLAGS)
+
+@WITH_GNUMERIC_FILTER_TRUE@am__append_17 = \
+@WITH_GNUMERIC_FILTER_TRUE@ $(BOOST_IOSTREAMS_LIBS)
+
+
+# gnumeric-cell-context-test
+@WITH_GNUMERIC_FILTER_TRUE@am__append_18 = \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric-cell-context-test \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric-sheet-context-test
+
+@WITH_GNUMERIC_FILTER_TRUE@am__append_19 = gnumeric-cell-context-test \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric-sheet-context-test
+@WITH_PARQUET_FILTER_TRUE@am__append_20 = \
+@WITH_PARQUET_FILTER_TRUE@ orcus_parquet.cpp
+
+@WITH_PARQUET_FILTER_TRUE@am__append_21 = \
+@WITH_PARQUET_FILTER_TRUE@ $(PARQUET_CFLAGS)
+
+@WITH_PARQUET_FILTER_TRUE@am__append_22 = \
+@WITH_PARQUET_FILTER_TRUE@ $(PARQUET_LDFLAGS)
+
+@WITH_PARQUET_FILTER_TRUE@am__append_23 = \
+@WITH_PARQUET_FILTER_TRUE@ $(PARQUET_LIBS)
+
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_24 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_25 = $(BOOST_FILESYSTEM_LIBS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_26 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_27 = $(BOOST_FILESYSTEM_LIBS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_28 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_29 = $(BOOST_FILESYSTEM_LIBS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_30 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_31 = $(BOOST_FILESYSTEM_LIBS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_32 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_33 = $(BOOST_FILESYSTEM_LIBS)
+subdir = src/liborcus
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = constants.inl
+CONFIG_CLEAN_VPATH_FILES =
+@WITH_XLSX_FILTER_TRUE@am__EXEEXT_1 = \
+@WITH_XLSX_FILTER_TRUE@ xlsx-sheet-context-test$(EXEEXT)
+@WITH_ODS_FILTER_TRUE@am__EXEEXT_2 = odf-helper-test$(EXEEXT)
+@WITH_GNUMERIC_FILTER_TRUE@am__EXEEXT_3 = gnumeric-cell-context-test$(EXEEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric-sheet-context-test$(EXEEXT)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+@WITH_GNUMERIC_FILTER_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
+@WITH_PARQUET_FILTER_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
+liborcus_@ORCUS_API_VERSION@_la_DEPENDENCIES = \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_4)
+am__liborcus_@ORCUS_API_VERSION@_la_SOURCES_DIST = config.cpp \
+ css_document_tree.cpp css_selector.cpp detection_result.hpp \
+ detection_result.cpp dom_tree.cpp format_detection.cpp \
+ formula_result.hpp formula_result.cpp impl_utils.hpp info.cpp \
+ interface.cpp json_document_tree.cpp json_map_tree.hpp \
+ json_map_tree.cpp json_structure_mapper.hpp \
+ json_structure_mapper.cpp json_structure_tree.cpp \
+ json_util.hpp json_util.cpp spreadsheet_interface.cpp \
+ orcus_csv.cpp orcus_json.cpp orcus_xml.cpp orcus_xml_impl.hpp \
+ orcus_xml_impl.cpp orcus_xml_map_def.cpp measurement.cpp \
+ number_utils.cpp number_utils.hpp xml_context_base.hpp \
+ xml_context_base.cpp xml_context_global.hpp \
+ xml_context_global.cpp xml_element_types.cpp \
+ xml_element_validator.hpp xml_element_validator.cpp \
+ xml_empty_context.hpp xml_empty_context.cpp xml_map_tree.hpp \
+ xml_map_tree.cpp xml_stream_handler.hpp xml_stream_handler.cpp \
+ xml_stream_parser.hpp xml_stream_parser.cpp \
+ xml_simple_stream_handler.hpp xml_simple_stream_handler.cpp \
+ xml_structure_mapper.hpp xml_structure_mapper.cpp \
+ xml_structure_tree.cpp xml_util.hpp xml_util.cpp \
+ xpath_parser.cpp yaml_document_tree.cpp \
+ ooxml_namespace_types.cpp ooxml_namespace_types.hpp \
+ odf_namespace_types.hpp odf_namespace_types_hpp.inl \
+ odf_namespace_types.cpp odf_namespace_types_cpp.inl \
+ gnumeric_namespace_types.hpp gnumeric_namespace_types.cpp \
+ xls_xml_namespace_types.hpp xls_xml_namespace_types.cpp \
+ session_context.hpp session_context.cpp \
+ spreadsheet_impl_types.hpp spreadsheet_impl_types.cpp \
+ spreadsheet_types.cpp spreadsheet_iface_util.hpp \
+ spreadsheet_iface_util.cpp string_helper.hpp string_helper.cpp \
+ ooxml_content_types.cpp ooxml_content_types.hpp \
+ ooxml_global.cpp ooxml_global.hpp ooxml_schemas.cpp \
+ ooxml_schemas.hpp ooxml_token_constants.hpp \
+ ooxml_token_constants.inl ooxml_tokens.cpp ooxml_tokens.hpp \
+ ooxml_tokens.inl ooxml_types.hpp ooxml_types.cpp \
+ opc_context.cpp opc_context.hpp opc_reader.cpp opc_reader.hpp \
+ opc_token_constants.hpp opc_token_constants.inl opc_tokens.inl \
+ orcus_xlsx.cpp orcus_import_xlsx.cpp \
+ xlsx_shared_strings_context.cpp \
+ xlsx_shared_strings_context.hpp xlsx_drawing_context.hpp \
+ xlsx_drawing_context.cpp xlsx_handler.cpp xlsx_handler.hpp \
+ xlsx_helper.cpp xlsx_helper.hpp xlsx_session_data.hpp \
+ xlsx_session_data.cpp xlsx_revision_context.cpp \
+ xlsx_revision_context.hpp xlsx_pivot_context.cpp \
+ xlsx_pivot_context.hpp xlsx_sheet_context.cpp \
+ xlsx_sheet_context.hpp xlsx_styles_context.cpp \
+ xlsx_styles_context.hpp xlsx_conditional_format_context.cpp \
+ xlsx_conditional_format_context.hpp xlsx_table_context.cpp \
+ xlsx_table_context.hpp xlsx_autofilter_context.cpp \
+ xlsx_autofilter_context.hpp xlsx_types.hpp xlsx_types.cpp \
+ xlsx_workbook_context.cpp xlsx_workbook_context.hpp \
+ xls_xml_tokens.hpp xls_xml_tokens.inl xls_xml_tokens.cpp \
+ xls_xml_token_constants.hpp xls_xml_token_constants.inl \
+ orcus_xls_xml.cpp xls_xml_detection_handler.hpp \
+ xls_xml_detection_handler.cpp xls_xml_handler.hpp \
+ xls_xml_handler.cpp xls_xml_context.hpp xls_xml_context.cpp \
+ odf_document_styles_context.hpp \
+ odf_document_styles_context.cpp odf_para_context.hpp \
+ odf_para_context.cpp odf_styles.hpp odf_styles.cpp \
+ odf_styles_context.hpp odf_styles_context.cpp \
+ odf_style_context.hpp odf_style_context.cpp \
+ odf_number_format_context.hpp odf_number_format_context.cpp \
+ odf_token_constants.hpp odf_token_constants.inl odf_tokens.hpp \
+ odf_tokens.inl odf_tokens.cpp ods_content_xml_context.hpp \
+ ods_content_xml_context.cpp ods_dde_links_context.hpp \
+ ods_dde_links_context.cpp ods_session_data.hpp \
+ ods_session_data.cpp odf_helper.hpp odf_helper.cpp \
+ orcus_ods.cpp orcus_import_ods.cpp gnumeric_cell_context.cpp \
+ gnumeric_cell_context.hpp gnumeric_context.cpp \
+ gnumeric_context.hpp gnumeric_detection_handler.cpp \
+ gnumeric_detection_handler.hpp gnumeric_filter_context.cpp \
+ gnumeric_filter_context.hpp gnumeric_handler.cpp \
+ gnumeric_handler.hpp gnumeric_names_context.cpp \
+ gnumeric_names_context.hpp gnumeric_sheet_context.cpp \
+ gnumeric_sheet_context.hpp gnumeric_styles_context.cpp \
+ gnumeric_styles_context.hpp gnumeric_token_constants.hpp \
+ gnumeric_token_constants.inl gnumeric_tokens.cpp \
+ gnumeric_tokens.hpp gnumeric_tokens.inl gnumeric_types.cpp \
+ gnumeric_types.hpp gnumeric_value_format_parser.cpp \
+ gnumeric_value_format_parser.hpp orcus_gnumeric.cpp \
+ orcus_parquet.cpp
+@WITH_XLSX_FILTER_TRUE@am__objects_1 = liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-ooxml_global.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-ooxml_types.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-opc_context.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-opc_reader.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_types.lo \
+@WITH_XLSX_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.lo
+@WITH_XLS_XML_FILTER_TRUE@am__objects_2 = liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.lo \
+@WITH_XLS_XML_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.lo \
+@WITH_XLS_XML_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.lo \
+@WITH_XLS_XML_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.lo \
+@WITH_XLS_XML_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.lo
+@WITH_ODS_FILTER_TRUE@am__objects_3 = liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-odf_para_context.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-odf_styles.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-odf_style_context.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-odf_tokens.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-ods_session_data.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-odf_helper.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-orcus_ods.lo \
+@WITH_ODS_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.lo
+@WITH_GNUMERIC_FILTER_TRUE@am__objects_4 = liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.lo \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.lo
+@WITH_PARQUET_FILTER_TRUE@am__objects_5 = liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.lo
+am_liborcus_@ORCUS_API_VERSION@_la_OBJECTS = \
+ liborcus_@ORCUS_API_VERSION@_la-config.lo \
+ liborcus_@ORCUS_API_VERSION@_la-css_document_tree.lo \
+ liborcus_@ORCUS_API_VERSION@_la-css_selector.lo \
+ liborcus_@ORCUS_API_VERSION@_la-detection_result.lo \
+ liborcus_@ORCUS_API_VERSION@_la-dom_tree.lo \
+ liborcus_@ORCUS_API_VERSION@_la-format_detection.lo \
+ liborcus_@ORCUS_API_VERSION@_la-formula_result.lo \
+ liborcus_@ORCUS_API_VERSION@_la-info.lo \
+ liborcus_@ORCUS_API_VERSION@_la-interface.lo \
+ liborcus_@ORCUS_API_VERSION@_la-json_document_tree.lo \
+ liborcus_@ORCUS_API_VERSION@_la-json_map_tree.lo \
+ liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.lo \
+ liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.lo \
+ liborcus_@ORCUS_API_VERSION@_la-json_util.lo \
+ liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.lo \
+ liborcus_@ORCUS_API_VERSION@_la-orcus_csv.lo \
+ liborcus_@ORCUS_API_VERSION@_la-orcus_json.lo \
+ liborcus_@ORCUS_API_VERSION@_la-orcus_xml.lo \
+ liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.lo \
+ liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.lo \
+ liborcus_@ORCUS_API_VERSION@_la-measurement.lo \
+ liborcus_@ORCUS_API_VERSION@_la-number_utils.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_context_base.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_context_global.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_element_types.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xml_util.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xpath_parser.lo \
+ liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.lo \
+ liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.lo \
+ liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.lo \
+ liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.lo \
+ liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.lo \
+ liborcus_@ORCUS_API_VERSION@_la-session_context.lo \
+ liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.lo \
+ liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.lo \
+ liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.lo \
+ liborcus_@ORCUS_API_VERSION@_la-string_helper.lo \
+ $(am__objects_1) $(am__objects_2) $(am__objects_3) \
+ $(am__objects_4) $(am__objects_5)
+liborcus_@ORCUS_API_VERSION@_la_OBJECTS = \
+ $(am_liborcus_@ORCUS_API_VERSION@_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+liborcus_@ORCUS_API_VERSION@_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) \
+ $(liborcus_@ORCUS_API_VERSION@_la_LDFLAGS) $(LDFLAGS) -o $@
+am_common_test_OBJECTS = common_test.$(OBJEXT)
+common_test_OBJECTS = $(am_common_test_OBJECTS)
+common_test_DEPENDENCIES = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+am_css_document_tree_test_OBJECTS = css_document_tree.$(OBJEXT) \
+ css_document_tree_test.$(OBJEXT)
+css_document_tree_test_OBJECTS = $(am_css_document_tree_test_OBJECTS)
+css_document_tree_test_DEPENDENCIES = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+am_dom_tree_test_OBJECTS = dom_tree_test.$(OBJEXT)
+dom_tree_test_OBJECTS = $(am_dom_tree_test_OBJECTS)
+dom_tree_test_DEPENDENCIES = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+am__gnumeric_cell_context_test_SOURCES_DIST = number_utils.cpp \
+ session_context.cpp gnumeric_cell_context_test.cpp \
+ gnumeric_cell_context.cpp gnumeric_value_format_parser.cpp \
+ xml_context_base.cpp xml_element_types.cpp \
+ xml_element_validator.cpp xml_empty_context.cpp xml_util.cpp \
+ gnumeric_namespace_types.cpp gnumeric_tokens.cpp \
+ gnumeric_types.cpp odf_namespace_types.cpp \
+ spreadsheet_interface.cpp
+@WITH_GNUMERIC_FILTER_TRUE@am_gnumeric_cell_context_test_OBJECTS = \
+@WITH_GNUMERIC_FILTER_TRUE@ number_utils.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ session_context.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_cell_context_test.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_cell_context.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_value_format_parser.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_context_base.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_element_types.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_element_validator.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_empty_context.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_util.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_namespace_types.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_tokens.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_types.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ odf_namespace_types.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ spreadsheet_interface.$(OBJEXT)
+gnumeric_cell_context_test_OBJECTS = \
+ $(am_gnumeric_cell_context_test_OBJECTS)
+@WITH_GNUMERIC_FILTER_TRUE@gnumeric_cell_context_test_DEPENDENCIES = \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus-@ORCUS_API_VERSION@.la \
+@WITH_GNUMERIC_FILTER_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_GNUMERIC_FILTER_TRUE@ ../test/liborcus-test.a
+am__gnumeric_sheet_context_test_SOURCES_DIST = session_context.cpp \
+ gnumeric_sheet_context_test.cpp gnumeric_sheet_context.cpp \
+ gnumeric_names_context.cpp gnumeric_cell_context.cpp \
+ gnumeric_filter_context.cpp gnumeric_styles_context.cpp \
+ gnumeric_value_format_parser.cpp gnumeric_types.cpp \
+ number_utils.cpp xml_context_base.cpp xml_element_types.cpp \
+ xml_element_validator.cpp xml_empty_context.cpp xml_util.cpp \
+ gnumeric_namespace_types.cpp gnumeric_tokens.cpp \
+ odf_namespace_types.cpp spreadsheet_interface.cpp \
+ string_helper.cpp
+@WITH_GNUMERIC_FILTER_TRUE@am_gnumeric_sheet_context_test_OBJECTS = gnumeric_sheet_context_test-session_context.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-gnumeric_sheet_context_test.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-gnumeric_sheet_context.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-gnumeric_names_context.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-gnumeric_cell_context.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-gnumeric_filter_context.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-gnumeric_styles_context.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-gnumeric_value_format_parser.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-gnumeric_types.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-number_utils.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-xml_context_base.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-xml_element_types.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-xml_element_validator.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-xml_empty_context.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-xml_util.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-gnumeric_namespace_types.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-gnumeric_tokens.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-odf_namespace_types.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-spreadsheet_interface.$(OBJEXT) \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test-string_helper.$(OBJEXT)
+gnumeric_sheet_context_test_OBJECTS = \
+ $(am_gnumeric_sheet_context_test_OBJECTS)
+@WITH_GNUMERIC_FILTER_TRUE@gnumeric_sheet_context_test_DEPENDENCIES = \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus-@ORCUS_API_VERSION@.la \
+@WITH_GNUMERIC_FILTER_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_GNUMERIC_FILTER_TRUE@ ../test/liborcus-test.a
+am_json_document_tree_test_OBJECTS = \
+ json_document_tree_test-json_document_tree.$(OBJEXT) \
+ json_document_tree_test-json_util.$(OBJEXT) \
+ json_document_tree_test-json_document_tree_test.$(OBJEXT)
+json_document_tree_test_OBJECTS = \
+ $(am_json_document_tree_test_OBJECTS)
+json_document_tree_test_DEPENDENCIES = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+am_json_map_tree_test_OBJECTS = json_map_tree_test.$(OBJEXT) \
+ json_map_tree.$(OBJEXT) spreadsheet_impl_types.$(OBJEXT)
+json_map_tree_test_OBJECTS = $(am_json_map_tree_test_OBJECTS)
+json_map_tree_test_DEPENDENCIES = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(am__DEPENDENCIES_1)
+am_json_structure_tree_test_OBJECTS = \
+ json_structure_tree_test.$(OBJEXT)
+json_structure_tree_test_OBJECTS = \
+ $(am_json_structure_tree_test_OBJECTS)
+json_structure_tree_test_DEPENDENCIES = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+am__odf_helper_test_SOURCES_DIST = odf_helper.cpp string_helper.cpp \
+ odf_helper_test.cpp
+@WITH_ODS_FILTER_TRUE@am_odf_helper_test_OBJECTS = \
+@WITH_ODS_FILTER_TRUE@ odf_helper_test-odf_helper.$(OBJEXT) \
+@WITH_ODS_FILTER_TRUE@ odf_helper_test-string_helper.$(OBJEXT) \
+@WITH_ODS_FILTER_TRUE@ odf_helper_test-odf_helper_test.$(OBJEXT)
+odf_helper_test_OBJECTS = $(am_odf_helper_test_OBJECTS)
+@WITH_ODS_FILTER_TRUE@odf_helper_test_DEPENDENCIES = \
+@WITH_ODS_FILTER_TRUE@ liborcus-@ORCUS_API_VERSION@.la \
+@WITH_ODS_FILTER_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+am__xlsx_sheet_context_test_SOURCES_DIST = formula_result.cpp \
+ ooxml_global.cpp ooxml_namespace_types.cpp ooxml_schemas.cpp \
+ ooxml_tokens.cpp ooxml_types.cpp session_context.cpp \
+ spreadsheet_interface.cpp xlsx_autofilter_context.cpp \
+ xlsx_conditional_format_context.cpp xlsx_helper.cpp \
+ xlsx_session_data.cpp xlsx_sheet_context.cpp \
+ xlsx_sheet_context_test.cpp xlsx_types.cpp \
+ xml_context_base.cpp xml_context_global.cpp \
+ xml_element_types.cpp xml_element_validator.cpp \
+ xml_empty_context.cpp xml_util.cpp
+@WITH_XLSX_FILTER_TRUE@am_xlsx_sheet_context_test_OBJECTS = xlsx_sheet_context_test-formula_result.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-ooxml_global.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-ooxml_namespace_types.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-ooxml_schemas.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-ooxml_tokens.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-ooxml_types.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-session_context.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-spreadsheet_interface.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xlsx_autofilter_context.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xlsx_conditional_format_context.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xlsx_helper.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xlsx_session_data.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xlsx_sheet_context.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xlsx_sheet_context_test.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xlsx_types.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xml_context_base.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xml_context_global.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xml_element_types.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xml_element_validator.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xml_empty_context.$(OBJEXT) \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test-xml_util.$(OBJEXT)
+xlsx_sheet_context_test_OBJECTS = \
+ $(am_xlsx_sheet_context_test_OBJECTS)
+@WITH_XLSX_FILTER_TRUE@xlsx_sheet_context_test_DEPENDENCIES = \
+@WITH_XLSX_FILTER_TRUE@ liborcus-@ORCUS_API_VERSION@.la \
+@WITH_XLSX_FILTER_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_XLSX_FILTER_TRUE@ ../test/liborcus-test.a
+am_xml_map_tree_test_OBJECTS = xml_map_tree.$(OBJEXT) \
+ xpath_parser.$(OBJEXT) spreadsheet_impl_types.$(OBJEXT) \
+ xml_map_tree_test.$(OBJEXT)
+xml_map_tree_test_OBJECTS = $(am_xml_map_tree_test_OBJECTS)
+xml_map_tree_test_DEPENDENCIES = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a $(am__DEPENDENCIES_1)
+am_xml_structure_tree_test_OBJECTS = \
+ xml_structure_tree_test-string_helper.$(OBJEXT) \
+ xml_structure_tree_test-xml_structure_tree.$(OBJEXT) \
+ xml_structure_tree_test-xml_structure_mapper.$(OBJEXT) \
+ xml_structure_tree_test-xml_structure_tree_test.$(OBJEXT)
+xml_structure_tree_test_OBJECTS = \
+ $(am_xml_structure_tree_test_OBJECTS)
+xml_structure_tree_test_DEPENDENCIES = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+am_xpath_parser_test_OBJECTS = xpath_parser_test.$(OBJEXT) \
+ xpath_parser.$(OBJEXT)
+xpath_parser_test_OBJECTS = $(am_xpath_parser_test_OBJECTS)
+xpath_parser_test_DEPENDENCIES = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(am__DEPENDENCIES_1)
+am_yaml_document_tree_test_OBJECTS = \
+ yaml_document_tree_test-yaml_document_tree.$(OBJEXT) \
+ yaml_document_tree_test-json_util.$(OBJEXT) \
+ yaml_document_tree_test-yaml_document_tree_test.$(OBJEXT)
+yaml_document_tree_test_OBJECTS = \
+ $(am_yaml_document_tree_test_OBJECTS)
+yaml_document_tree_test_DEPENDENCIES = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/common_test.Po \
+ ./$(DEPDIR)/css_document_tree.Po \
+ ./$(DEPDIR)/css_document_tree_test.Po \
+ ./$(DEPDIR)/dom_tree_test.Po \
+ ./$(DEPDIR)/gnumeric_cell_context.Po \
+ ./$(DEPDIR)/gnumeric_cell_context_test.Po \
+ ./$(DEPDIR)/gnumeric_namespace_types.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_cell_context.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_filter_context.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_names_context.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_namespace_types.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context_test.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_styles_context.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_tokens.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_types.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_value_format_parser.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-number_utils.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-odf_namespace_types.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-session_context.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-spreadsheet_interface.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-string_helper.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-xml_context_base.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-xml_element_types.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-xml_element_validator.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-xml_empty_context.Po \
+ ./$(DEPDIR)/gnumeric_sheet_context_test-xml_util.Po \
+ ./$(DEPDIR)/gnumeric_tokens.Po ./$(DEPDIR)/gnumeric_types.Po \
+ ./$(DEPDIR)/gnumeric_value_format_parser.Po \
+ ./$(DEPDIR)/json_document_tree_test-json_document_tree.Po \
+ ./$(DEPDIR)/json_document_tree_test-json_document_tree_test.Po \
+ ./$(DEPDIR)/json_document_tree_test-json_util.Po \
+ ./$(DEPDIR)/json_map_tree.Po ./$(DEPDIR)/json_map_tree_test.Po \
+ ./$(DEPDIR)/json_structure_tree_test.Po \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-config.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_document_tree.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_selector.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-detection_result.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-dom_tree.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-format_detection.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-formula_result.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-info.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-interface.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_document_tree.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_map_tree.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_util.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-measurement.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-number_utils.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_helper.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_para_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_style_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_tokens.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_session_data.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_global.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_reader.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_csv.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_json.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_ods.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-session_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-string_helper.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_base.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_global.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_types.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_util.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xpath_parser.Plo \
+ ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.Plo \
+ ./$(DEPDIR)/number_utils.Po \
+ ./$(DEPDIR)/odf_helper_test-odf_helper.Po \
+ ./$(DEPDIR)/odf_helper_test-odf_helper_test.Po \
+ ./$(DEPDIR)/odf_helper_test-string_helper.Po \
+ ./$(DEPDIR)/odf_namespace_types.Po \
+ ./$(DEPDIR)/session_context.Po \
+ ./$(DEPDIR)/spreadsheet_impl_types.Po \
+ ./$(DEPDIR)/spreadsheet_interface.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-formula_result.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_global.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_namespace_types.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_schemas.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_tokens.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_types.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-session_context.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-spreadsheet_interface.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_autofilter_context.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_conditional_format_context.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_helper.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_session_data.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context_test.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_types.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xml_context_base.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xml_context_global.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xml_element_types.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xml_element_validator.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xml_empty_context.Po \
+ ./$(DEPDIR)/xlsx_sheet_context_test-xml_util.Po \
+ ./$(DEPDIR)/xml_context_base.Po \
+ ./$(DEPDIR)/xml_element_types.Po \
+ ./$(DEPDIR)/xml_element_validator.Po \
+ ./$(DEPDIR)/xml_empty_context.Po ./$(DEPDIR)/xml_map_tree.Po \
+ ./$(DEPDIR)/xml_map_tree_test.Po \
+ ./$(DEPDIR)/xml_structure_tree_test-string_helper.Po \
+ ./$(DEPDIR)/xml_structure_tree_test-xml_structure_mapper.Po \
+ ./$(DEPDIR)/xml_structure_tree_test-xml_structure_tree.Po \
+ ./$(DEPDIR)/xml_structure_tree_test-xml_structure_tree_test.Po \
+ ./$(DEPDIR)/xml_util.Po ./$(DEPDIR)/xpath_parser.Po \
+ ./$(DEPDIR)/xpath_parser_test.Po \
+ ./$(DEPDIR)/yaml_document_tree_test-json_util.Po \
+ ./$(DEPDIR)/yaml_document_tree_test-yaml_document_tree.Po \
+ ./$(DEPDIR)/yaml_document_tree_test-yaml_document_tree_test.Po
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(liborcus_@ORCUS_API_VERSION@_la_SOURCES) \
+ $(common_test_SOURCES) $(css_document_tree_test_SOURCES) \
+ $(dom_tree_test_SOURCES) $(gnumeric_cell_context_test_SOURCES) \
+ $(gnumeric_sheet_context_test_SOURCES) \
+ $(json_document_tree_test_SOURCES) \
+ $(json_map_tree_test_SOURCES) \
+ $(json_structure_tree_test_SOURCES) $(odf_helper_test_SOURCES) \
+ $(xlsx_sheet_context_test_SOURCES) \
+ $(xml_map_tree_test_SOURCES) \
+ $(xml_structure_tree_test_SOURCES) \
+ $(xpath_parser_test_SOURCES) \
+ $(yaml_document_tree_test_SOURCES)
+DIST_SOURCES = $(am__liborcus_@ORCUS_API_VERSION@_la_SOURCES_DIST) \
+ $(common_test_SOURCES) $(css_document_tree_test_SOURCES) \
+ $(dom_tree_test_SOURCES) \
+ $(am__gnumeric_cell_context_test_SOURCES_DIST) \
+ $(am__gnumeric_sheet_context_test_SOURCES_DIST) \
+ $(json_document_tree_test_SOURCES) \
+ $(json_map_tree_test_SOURCES) \
+ $(json_structure_tree_test_SOURCES) \
+ $(am__odf_helper_test_SOURCES_DIST) \
+ $(am__xlsx_sheet_context_test_SOURCES_DIST) \
+ $(xml_map_tree_test_SOURCES) \
+ $(xml_structure_tree_test_SOURCES) \
+ $(xpath_parser_test_SOURCES) \
+ $(yaml_document_tree_test_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/constants.inl.in \
+ $(top_srcdir)/depcomp $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/include \
+ -I./include $(BOOST_CPPFLAGS) $(am__append_1) $(am__append_2) \
+ $(am__append_3) $(am__append_4) -DSRCDIR=\""$(top_srcdir)"\"
+EXTRA_DIST = \
+ xml_element_types.hpp
+
+liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS = $(ZLIB_CFLAGS) \
+ $(am__append_21)
+liborcus_@ORCUS_API_VERSION@_la_LDFLAGS = -no-undefined \
+ $(BOOST_SYSTEM_LDFLAGS) $(am__append_5) $(am__append_6) \
+ $(am__append_16) $(am__append_22)
+liborcus_@ORCUS_API_VERSION@_la_LIBADD = \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS) $(ZLIB_LIBS) $(am__append_7) \
+ $(am__append_17) $(am__append_23)
+lib_LTLIBRARIES = liborcus-@ORCUS_API_VERSION@.la
+liborcus_@ORCUS_API_VERSION@_la_SOURCES = config.cpp \
+ css_document_tree.cpp css_selector.cpp detection_result.hpp \
+ detection_result.cpp dom_tree.cpp format_detection.cpp \
+ formula_result.hpp formula_result.cpp impl_utils.hpp info.cpp \
+ interface.cpp json_document_tree.cpp json_map_tree.hpp \
+ json_map_tree.cpp json_structure_mapper.hpp \
+ json_structure_mapper.cpp json_structure_tree.cpp \
+ json_util.hpp json_util.cpp spreadsheet_interface.cpp \
+ orcus_csv.cpp orcus_json.cpp orcus_xml.cpp orcus_xml_impl.hpp \
+ orcus_xml_impl.cpp orcus_xml_map_def.cpp measurement.cpp \
+ number_utils.cpp number_utils.hpp xml_context_base.hpp \
+ xml_context_base.cpp xml_context_global.hpp \
+ xml_context_global.cpp xml_element_types.cpp \
+ xml_element_validator.hpp xml_element_validator.cpp \
+ xml_empty_context.hpp xml_empty_context.cpp xml_map_tree.hpp \
+ xml_map_tree.cpp xml_stream_handler.hpp xml_stream_handler.cpp \
+ xml_stream_parser.hpp xml_stream_parser.cpp \
+ xml_simple_stream_handler.hpp xml_simple_stream_handler.cpp \
+ xml_structure_mapper.hpp xml_structure_mapper.cpp \
+ xml_structure_tree.cpp xml_util.hpp xml_util.cpp \
+ xpath_parser.cpp yaml_document_tree.cpp \
+ ooxml_namespace_types.cpp ooxml_namespace_types.hpp \
+ odf_namespace_types.hpp odf_namespace_types_hpp.inl \
+ odf_namespace_types.cpp odf_namespace_types_cpp.inl \
+ gnumeric_namespace_types.hpp gnumeric_namespace_types.cpp \
+ xls_xml_namespace_types.hpp xls_xml_namespace_types.cpp \
+ session_context.hpp session_context.cpp \
+ spreadsheet_impl_types.hpp spreadsheet_impl_types.cpp \
+ spreadsheet_types.cpp spreadsheet_iface_util.hpp \
+ spreadsheet_iface_util.cpp string_helper.hpp string_helper.cpp \
+ $(am__append_9) $(am__append_11) $(am__append_12) \
+ $(am__append_15) $(am__append_20)
+
+# xlsx-sheet-context-test
+@WITH_XLSX_FILTER_TRUE@xlsx_sheet_context_test_SOURCES = \
+@WITH_XLSX_FILTER_TRUE@ formula_result.cpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_global.cpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_namespace_types.cpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_schemas.cpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_tokens.cpp \
+@WITH_XLSX_FILTER_TRUE@ ooxml_types.cpp \
+@WITH_XLSX_FILTER_TRUE@ session_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ spreadsheet_interface.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_autofilter_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_conditional_format_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_helper.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_session_data.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_sheet_context_test.cpp \
+@WITH_XLSX_FILTER_TRUE@ xlsx_types.cpp \
+@WITH_XLSX_FILTER_TRUE@ xml_context_base.cpp \
+@WITH_XLSX_FILTER_TRUE@ xml_context_global.cpp \
+@WITH_XLSX_FILTER_TRUE@ xml_element_types.cpp \
+@WITH_XLSX_FILTER_TRUE@ xml_element_validator.cpp \
+@WITH_XLSX_FILTER_TRUE@ xml_empty_context.cpp \
+@WITH_XLSX_FILTER_TRUE@ xml_util.cpp
+
+@WITH_XLSX_FILTER_TRUE@xlsx_sheet_context_test_LDADD = \
+@WITH_XLSX_FILTER_TRUE@ liborcus-@ORCUS_API_VERSION@.la \
+@WITH_XLSX_FILTER_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_XLSX_FILTER_TRUE@ ../test/liborcus-test.a
+
+@WITH_XLSX_FILTER_TRUE@xlsx_sheet_context_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+@WITH_ODS_FILTER_TRUE@odf_helper_test_SOURCES = \
+@WITH_ODS_FILTER_TRUE@ odf_helper.cpp \
+@WITH_ODS_FILTER_TRUE@ string_helper.cpp \
+@WITH_ODS_FILTER_TRUE@ odf_helper_test.cpp
+
+@WITH_ODS_FILTER_TRUE@odf_helper_test_LDADD = \
+@WITH_ODS_FILTER_TRUE@ liborcus-@ORCUS_API_VERSION@.la \
+@WITH_ODS_FILTER_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+
+@WITH_ODS_FILTER_TRUE@odf_helper_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+@WITH_GNUMERIC_FILTER_TRUE@gnumeric_cell_context_test_SOURCES = \
+@WITH_GNUMERIC_FILTER_TRUE@ number_utils.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ session_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_cell_context_test.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_cell_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_value_format_parser.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_context_base.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_element_types.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_element_validator.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_empty_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_util.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_namespace_types.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_tokens.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_types.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ odf_namespace_types.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ spreadsheet_interface.cpp
+
+@WITH_GNUMERIC_FILTER_TRUE@gnumeric_cell_context_test_LDADD = \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus-@ORCUS_API_VERSION@.la \
+@WITH_GNUMERIC_FILTER_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_GNUMERIC_FILTER_TRUE@ ../test/liborcus-test.a
+
+@WITH_GNUMERIC_FILTER_TRUE@orcus_gnumeric_cell_context_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# gnumeric-sheet-context-test
+@WITH_GNUMERIC_FILTER_TRUE@gnumeric_sheet_context_test_SOURCES = \
+@WITH_GNUMERIC_FILTER_TRUE@ session_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context_test.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_sheet_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_names_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_cell_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_filter_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_styles_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_value_format_parser.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_types.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ number_utils.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_context_base.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_element_types.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_element_validator.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_empty_context.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ xml_util.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_namespace_types.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ gnumeric_tokens.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ odf_namespace_types.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ spreadsheet_interface.cpp \
+@WITH_GNUMERIC_FILTER_TRUE@ string_helper.cpp
+
+@WITH_GNUMERIC_FILTER_TRUE@gnumeric_sheet_context_test_LDADD = \
+@WITH_GNUMERIC_FILTER_TRUE@ liborcus-@ORCUS_API_VERSION@.la \
+@WITH_GNUMERIC_FILTER_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@WITH_GNUMERIC_FILTER_TRUE@ ../test/liborcus-test.a
+
+@WITH_GNUMERIC_FILTER_TRUE@gnumeric_sheet_context_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# css-document-tree-test
+css_document_tree_test_SOURCES = \
+ css_document_tree.cpp \
+ css_document_tree_test.cpp
+
+css_document_tree_test_LDADD = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS) $(am__append_24) $(am__append_25)
+
+# json-document-tree-test
+json_document_tree_test_SOURCES = \
+ json_document_tree.cpp \
+ json_util.cpp \
+ json_document_tree_test.cpp
+
+json_document_tree_test_LDADD = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a $(BOOST_SYSTEM_LIBS) $(am__append_26) \
+ $(am__append_27)
+json_document_tree_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# yaml-document-tree-test
+yaml_document_tree_test_SOURCES = \
+ yaml_document_tree.cpp \
+ json_util.cpp \
+ yaml_document_tree_test.cpp
+
+yaml_document_tree_test_LDADD = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS) $(am__append_28) $(am__append_29)
+yaml_document_tree_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+
+# xml-map-tree-test
+xml_map_tree_test_SOURCES = \
+ xml_map_tree.cpp \
+ xml_map_tree.hpp \
+ xpath_parser.hpp \
+ xpath_parser.cpp \
+ spreadsheet_impl_types.hpp \
+ spreadsheet_impl_types.cpp \
+ xml_map_tree_test.cpp
+
+xml_map_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+
+
+# xml-structure-tree-test
+xml_structure_tree_test_SOURCES = \
+ string_helper.cpp \
+ xml_structure_tree.cpp \
+ xml_structure_mapper.cpp \
+ xml_structure_tree_test.cpp
+
+xml_structure_tree_test_CPPFLAGS = -I$(top_builddir)/lib/liborcus/liborcus.la $(AM_CPPFLAGS)
+xml_structure_tree_test_LDADD = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS) $(am__append_30) $(am__append_31)
+
+# common-test
+common_test_SOURCES = \
+ common_test.cpp
+
+common_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+
+
+# dom-tree-test
+dom_tree_test_SOURCES = dom_tree_test.cpp
+dom_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+
+
+# json-structure-tree-test
+json_structure_tree_test_SOURCES = json_structure_tree_test.cpp
+json_structure_tree_test_LDADD = liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS) $(am__append_32) $(am__append_33)
+
+# json-map-tree-test
+json_map_tree_test_SOURCES = json_map_tree_test.cpp \
+ json_map_tree.cpp \
+ spreadsheet_impl_types.cpp
+
+json_map_tree_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+
+# xpath-parser-test
+xpath_parser_test_SOURCES = \
+ xpath_parser_test.cpp \
+ xpath_parser.cpp
+
+xpath_parser_test_LDADD = \
+ liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/liborcus/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/liborcus/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+constants.inl: $(top_builddir)/config.status $(srcdir)/constants.inl.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+liborcus-@ORCUS_API_VERSION@.la: $(liborcus_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_@ORCUS_API_VERSION@_la_DEPENDENCIES) $(EXTRA_liborcus_@ORCUS_API_VERSION@_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(liborcus_@ORCUS_API_VERSION@_la_LINK) -rpath $(libdir) $(liborcus_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_@ORCUS_API_VERSION@_la_LIBADD) $(LIBS)
+
+common-test$(EXEEXT): $(common_test_OBJECTS) $(common_test_DEPENDENCIES) $(EXTRA_common_test_DEPENDENCIES)
+ @rm -f common-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(common_test_OBJECTS) $(common_test_LDADD) $(LIBS)
+
+css-document-tree-test$(EXEEXT): $(css_document_tree_test_OBJECTS) $(css_document_tree_test_DEPENDENCIES) $(EXTRA_css_document_tree_test_DEPENDENCIES)
+ @rm -f css-document-tree-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(css_document_tree_test_OBJECTS) $(css_document_tree_test_LDADD) $(LIBS)
+
+dom-tree-test$(EXEEXT): $(dom_tree_test_OBJECTS) $(dom_tree_test_DEPENDENCIES) $(EXTRA_dom_tree_test_DEPENDENCIES)
+ @rm -f dom-tree-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(dom_tree_test_OBJECTS) $(dom_tree_test_LDADD) $(LIBS)
+
+gnumeric-cell-context-test$(EXEEXT): $(gnumeric_cell_context_test_OBJECTS) $(gnumeric_cell_context_test_DEPENDENCIES) $(EXTRA_gnumeric_cell_context_test_DEPENDENCIES)
+ @rm -f gnumeric-cell-context-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(gnumeric_cell_context_test_OBJECTS) $(gnumeric_cell_context_test_LDADD) $(LIBS)
+
+gnumeric-sheet-context-test$(EXEEXT): $(gnumeric_sheet_context_test_OBJECTS) $(gnumeric_sheet_context_test_DEPENDENCIES) $(EXTRA_gnumeric_sheet_context_test_DEPENDENCIES)
+ @rm -f gnumeric-sheet-context-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(gnumeric_sheet_context_test_OBJECTS) $(gnumeric_sheet_context_test_LDADD) $(LIBS)
+
+json-document-tree-test$(EXEEXT): $(json_document_tree_test_OBJECTS) $(json_document_tree_test_DEPENDENCIES) $(EXTRA_json_document_tree_test_DEPENDENCIES)
+ @rm -f json-document-tree-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(json_document_tree_test_OBJECTS) $(json_document_tree_test_LDADD) $(LIBS)
+
+json-map-tree-test$(EXEEXT): $(json_map_tree_test_OBJECTS) $(json_map_tree_test_DEPENDENCIES) $(EXTRA_json_map_tree_test_DEPENDENCIES)
+ @rm -f json-map-tree-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(json_map_tree_test_OBJECTS) $(json_map_tree_test_LDADD) $(LIBS)
+
+json-structure-tree-test$(EXEEXT): $(json_structure_tree_test_OBJECTS) $(json_structure_tree_test_DEPENDENCIES) $(EXTRA_json_structure_tree_test_DEPENDENCIES)
+ @rm -f json-structure-tree-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(json_structure_tree_test_OBJECTS) $(json_structure_tree_test_LDADD) $(LIBS)
+
+odf-helper-test$(EXEEXT): $(odf_helper_test_OBJECTS) $(odf_helper_test_DEPENDENCIES) $(EXTRA_odf_helper_test_DEPENDENCIES)
+ @rm -f odf-helper-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(odf_helper_test_OBJECTS) $(odf_helper_test_LDADD) $(LIBS)
+
+xlsx-sheet-context-test$(EXEEXT): $(xlsx_sheet_context_test_OBJECTS) $(xlsx_sheet_context_test_DEPENDENCIES) $(EXTRA_xlsx_sheet_context_test_DEPENDENCIES)
+ @rm -f xlsx-sheet-context-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(xlsx_sheet_context_test_OBJECTS) $(xlsx_sheet_context_test_LDADD) $(LIBS)
+
+xml-map-tree-test$(EXEEXT): $(xml_map_tree_test_OBJECTS) $(xml_map_tree_test_DEPENDENCIES) $(EXTRA_xml_map_tree_test_DEPENDENCIES)
+ @rm -f xml-map-tree-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(xml_map_tree_test_OBJECTS) $(xml_map_tree_test_LDADD) $(LIBS)
+
+xml-structure-tree-test$(EXEEXT): $(xml_structure_tree_test_OBJECTS) $(xml_structure_tree_test_DEPENDENCIES) $(EXTRA_xml_structure_tree_test_DEPENDENCIES)
+ @rm -f xml-structure-tree-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(xml_structure_tree_test_OBJECTS) $(xml_structure_tree_test_LDADD) $(LIBS)
+
+xpath-parser-test$(EXEEXT): $(xpath_parser_test_OBJECTS) $(xpath_parser_test_DEPENDENCIES) $(EXTRA_xpath_parser_test_DEPENDENCIES)
+ @rm -f xpath-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(xpath_parser_test_OBJECTS) $(xpath_parser_test_LDADD) $(LIBS)
+
+yaml-document-tree-test$(EXEEXT): $(yaml_document_tree_test_OBJECTS) $(yaml_document_tree_test_DEPENDENCIES) $(EXTRA_yaml_document_tree_test_DEPENDENCIES)
+ @rm -f yaml-document-tree-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(yaml_document_tree_test_OBJECTS) $(yaml_document_tree_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/css_document_tree.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/css_document_tree_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dom_tree_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_cell_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_cell_context_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_namespace_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_cell_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_filter_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_names_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_namespace_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_styles_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_tokens.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_value_format_parser.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-number_utils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-odf_namespace_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-session_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-spreadsheet_interface.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-string_helper.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-xml_context_base.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-xml_element_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-xml_element_validator.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-xml_empty_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_sheet_context_test-xml_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_tokens.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric_value_format_parser.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_document_tree_test-json_document_tree.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_document_tree_test-json_document_tree_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_document_tree_test-json_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_map_tree.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_map_tree_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_structure_tree_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-config.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_document_tree.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_selector.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-detection_result.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-dom_tree.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-format_detection.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-formula_result.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-info.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-interface.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_document_tree.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_map_tree.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_util.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-measurement.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-number_utils.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_helper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_para_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_style_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_tokens.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_session_data.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_reader.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_csv.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_json.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_ods.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-session_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-string_helper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_util.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xpath_parser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/number_utils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/odf_helper_test-odf_helper.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/odf_helper_test-odf_helper_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/odf_helper_test-string_helper.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/odf_namespace_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spreadsheet_impl_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spreadsheet_interface.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-formula_result.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-ooxml_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-ooxml_namespace_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-ooxml_schemas.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-ooxml_tokens.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-ooxml_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-session_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-spreadsheet_interface.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xlsx_autofilter_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xlsx_conditional_format_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xlsx_helper.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xlsx_session_data.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xlsx_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xml_context_base.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xml_context_global.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xml_element_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xml_element_validator.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xml_empty_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx_sheet_context_test-xml_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_context_base.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_element_types.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_element_validator.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_empty_context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_map_tree.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_map_tree_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_structure_tree_test-string_helper.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_structure_tree_test-xml_structure_mapper.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_structure_tree_test-xml_structure_tree.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_structure_tree_test-xml_structure_tree_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xpath_parser.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xpath_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yaml_document_tree_test-json_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yaml_document_tree_test-yaml_document_tree.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yaml_document_tree_test-yaml_document_tree_test.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+liborcus_@ORCUS_API_VERSION@_la-config.lo: config.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-config.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-config.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-config.lo `test -f 'config.cpp' || echo '$(srcdir)/'`config.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-config.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-config.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config.cpp' object='liborcus_@ORCUS_API_VERSION@_la-config.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-config.lo `test -f 'config.cpp' || echo '$(srcdir)/'`config.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-css_document_tree.lo: css_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-css_document_tree.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_document_tree.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-css_document_tree.lo `test -f 'css_document_tree.cpp' || echo '$(srcdir)/'`css_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_document_tree.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_document_tree.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='css_document_tree.cpp' object='liborcus_@ORCUS_API_VERSION@_la-css_document_tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-css_document_tree.lo `test -f 'css_document_tree.cpp' || echo '$(srcdir)/'`css_document_tree.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-css_selector.lo: css_selector.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-css_selector.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_selector.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-css_selector.lo `test -f 'css_selector.cpp' || echo '$(srcdir)/'`css_selector.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_selector.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_selector.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='css_selector.cpp' object='liborcus_@ORCUS_API_VERSION@_la-css_selector.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-css_selector.lo `test -f 'css_selector.cpp' || echo '$(srcdir)/'`css_selector.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-detection_result.lo: detection_result.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-detection_result.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-detection_result.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-detection_result.lo `test -f 'detection_result.cpp' || echo '$(srcdir)/'`detection_result.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-detection_result.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-detection_result.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='detection_result.cpp' object='liborcus_@ORCUS_API_VERSION@_la-detection_result.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-detection_result.lo `test -f 'detection_result.cpp' || echo '$(srcdir)/'`detection_result.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-dom_tree.lo: dom_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-dom_tree.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-dom_tree.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-dom_tree.lo `test -f 'dom_tree.cpp' || echo '$(srcdir)/'`dom_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-dom_tree.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-dom_tree.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dom_tree.cpp' object='liborcus_@ORCUS_API_VERSION@_la-dom_tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-dom_tree.lo `test -f 'dom_tree.cpp' || echo '$(srcdir)/'`dom_tree.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-format_detection.lo: format_detection.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-format_detection.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-format_detection.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-format_detection.lo `test -f 'format_detection.cpp' || echo '$(srcdir)/'`format_detection.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-format_detection.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-format_detection.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='format_detection.cpp' object='liborcus_@ORCUS_API_VERSION@_la-format_detection.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-format_detection.lo `test -f 'format_detection.cpp' || echo '$(srcdir)/'`format_detection.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-formula_result.lo: formula_result.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-formula_result.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-formula_result.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-formula_result.lo `test -f 'formula_result.cpp' || echo '$(srcdir)/'`formula_result.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-formula_result.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-formula_result.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='formula_result.cpp' object='liborcus_@ORCUS_API_VERSION@_la-formula_result.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-formula_result.lo `test -f 'formula_result.cpp' || echo '$(srcdir)/'`formula_result.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-info.lo: info.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-info.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-info.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-info.lo `test -f 'info.cpp' || echo '$(srcdir)/'`info.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-info.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-info.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='info.cpp' object='liborcus_@ORCUS_API_VERSION@_la-info.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-info.lo `test -f 'info.cpp' || echo '$(srcdir)/'`info.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-interface.lo: interface.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-interface.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-interface.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-interface.lo `test -f 'interface.cpp' || echo '$(srcdir)/'`interface.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-interface.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-interface.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='interface.cpp' object='liborcus_@ORCUS_API_VERSION@_la-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-interface.lo `test -f 'interface.cpp' || echo '$(srcdir)/'`interface.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-json_document_tree.lo: json_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-json_document_tree.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_document_tree.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-json_document_tree.lo `test -f 'json_document_tree.cpp' || echo '$(srcdir)/'`json_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_document_tree.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_document_tree.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_document_tree.cpp' object='liborcus_@ORCUS_API_VERSION@_la-json_document_tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-json_document_tree.lo `test -f 'json_document_tree.cpp' || echo '$(srcdir)/'`json_document_tree.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-json_map_tree.lo: json_map_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-json_map_tree.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_map_tree.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-json_map_tree.lo `test -f 'json_map_tree.cpp' || echo '$(srcdir)/'`json_map_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_map_tree.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_map_tree.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_map_tree.cpp' object='liborcus_@ORCUS_API_VERSION@_la-json_map_tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-json_map_tree.lo `test -f 'json_map_tree.cpp' || echo '$(srcdir)/'`json_map_tree.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.lo: json_structure_mapper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.lo `test -f 'json_structure_mapper.cpp' || echo '$(srcdir)/'`json_structure_mapper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_structure_mapper.cpp' object='liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.lo `test -f 'json_structure_mapper.cpp' || echo '$(srcdir)/'`json_structure_mapper.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.lo: json_structure_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.lo `test -f 'json_structure_tree.cpp' || echo '$(srcdir)/'`json_structure_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_structure_tree.cpp' object='liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.lo `test -f 'json_structure_tree.cpp' || echo '$(srcdir)/'`json_structure_tree.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-json_util.lo: json_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-json_util.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_util.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-json_util.lo `test -f 'json_util.cpp' || echo '$(srcdir)/'`json_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_util.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_util.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_util.cpp' object='liborcus_@ORCUS_API_VERSION@_la-json_util.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-json_util.lo `test -f 'json_util.cpp' || echo '$(srcdir)/'`json_util.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.lo: spreadsheet_interface.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.lo `test -f 'spreadsheet_interface.cpp' || echo '$(srcdir)/'`spreadsheet_interface.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='spreadsheet_interface.cpp' object='liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.lo `test -f 'spreadsheet_interface.cpp' || echo '$(srcdir)/'`spreadsheet_interface.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_csv.lo: orcus_csv.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_csv.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_csv.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_csv.lo `test -f 'orcus_csv.cpp' || echo '$(srcdir)/'`orcus_csv.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_csv.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_csv.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_csv.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_csv.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_csv.lo `test -f 'orcus_csv.cpp' || echo '$(srcdir)/'`orcus_csv.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_json.lo: orcus_json.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_json.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_json.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_json.lo `test -f 'orcus_json.cpp' || echo '$(srcdir)/'`orcus_json.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_json.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_json.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_json.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_json.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_json.lo `test -f 'orcus_json.cpp' || echo '$(srcdir)/'`orcus_json.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_xml.lo: orcus_xml.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_xml.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_xml.lo `test -f 'orcus_xml.cpp' || echo '$(srcdir)/'`orcus_xml.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xml.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_xml.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_xml.lo `test -f 'orcus_xml.cpp' || echo '$(srcdir)/'`orcus_xml.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.lo: orcus_xml_impl.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.lo `test -f 'orcus_xml_impl.cpp' || echo '$(srcdir)/'`orcus_xml_impl.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xml_impl.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.lo `test -f 'orcus_xml_impl.cpp' || echo '$(srcdir)/'`orcus_xml_impl.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.lo: orcus_xml_map_def.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.lo `test -f 'orcus_xml_map_def.cpp' || echo '$(srcdir)/'`orcus_xml_map_def.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xml_map_def.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.lo `test -f 'orcus_xml_map_def.cpp' || echo '$(srcdir)/'`orcus_xml_map_def.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-measurement.lo: measurement.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-measurement.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-measurement.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-measurement.lo `test -f 'measurement.cpp' || echo '$(srcdir)/'`measurement.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-measurement.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-measurement.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='measurement.cpp' object='liborcus_@ORCUS_API_VERSION@_la-measurement.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-measurement.lo `test -f 'measurement.cpp' || echo '$(srcdir)/'`measurement.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-number_utils.lo: number_utils.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-number_utils.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-number_utils.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-number_utils.lo `test -f 'number_utils.cpp' || echo '$(srcdir)/'`number_utils.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-number_utils.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-number_utils.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='number_utils.cpp' object='liborcus_@ORCUS_API_VERSION@_la-number_utils.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-number_utils.lo `test -f 'number_utils.cpp' || echo '$(srcdir)/'`number_utils.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_context_base.lo: xml_context_base.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_context_base.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_base.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_context_base.lo `test -f 'xml_context_base.cpp' || echo '$(srcdir)/'`xml_context_base.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_base.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_base.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_context_base.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_context_base.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_context_base.lo `test -f 'xml_context_base.cpp' || echo '$(srcdir)/'`xml_context_base.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_context_global.lo: xml_context_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_context_global.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_global.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_context_global.lo `test -f 'xml_context_global.cpp' || echo '$(srcdir)/'`xml_context_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_global.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_global.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_context_global.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_context_global.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_context_global.lo `test -f 'xml_context_global.cpp' || echo '$(srcdir)/'`xml_context_global.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_element_types.lo: xml_element_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_element_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_element_types.lo `test -f 'xml_element_types.cpp' || echo '$(srcdir)/'`xml_element_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_element_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_element_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_element_types.lo `test -f 'xml_element_types.cpp' || echo '$(srcdir)/'`xml_element_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.lo: xml_element_validator.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.lo `test -f 'xml_element_validator.cpp' || echo '$(srcdir)/'`xml_element_validator.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_element_validator.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.lo `test -f 'xml_element_validator.cpp' || echo '$(srcdir)/'`xml_element_validator.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.lo: xml_empty_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.lo `test -f 'xml_empty_context.cpp' || echo '$(srcdir)/'`xml_empty_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_empty_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.lo `test -f 'xml_empty_context.cpp' || echo '$(srcdir)/'`xml_empty_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.lo: xml_map_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.lo `test -f 'xml_map_tree.cpp' || echo '$(srcdir)/'`xml_map_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_map_tree.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.lo `test -f 'xml_map_tree.cpp' || echo '$(srcdir)/'`xml_map_tree.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.lo: xml_stream_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.lo `test -f 'xml_stream_handler.cpp' || echo '$(srcdir)/'`xml_stream_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_stream_handler.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.lo `test -f 'xml_stream_handler.cpp' || echo '$(srcdir)/'`xml_stream_handler.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.lo: xml_stream_parser.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.lo `test -f 'xml_stream_parser.cpp' || echo '$(srcdir)/'`xml_stream_parser.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_stream_parser.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.lo `test -f 'xml_stream_parser.cpp' || echo '$(srcdir)/'`xml_stream_parser.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.lo: xml_simple_stream_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.lo `test -f 'xml_simple_stream_handler.cpp' || echo '$(srcdir)/'`xml_simple_stream_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_simple_stream_handler.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.lo `test -f 'xml_simple_stream_handler.cpp' || echo '$(srcdir)/'`xml_simple_stream_handler.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.lo: xml_structure_mapper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.lo `test -f 'xml_structure_mapper.cpp' || echo '$(srcdir)/'`xml_structure_mapper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_structure_mapper.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.lo `test -f 'xml_structure_mapper.cpp' || echo '$(srcdir)/'`xml_structure_mapper.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.lo: xml_structure_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.lo `test -f 'xml_structure_tree.cpp' || echo '$(srcdir)/'`xml_structure_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_structure_tree.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.lo `test -f 'xml_structure_tree.cpp' || echo '$(srcdir)/'`xml_structure_tree.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xml_util.lo: xml_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xml_util.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_util.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xml_util.lo `test -f 'xml_util.cpp' || echo '$(srcdir)/'`xml_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_util.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_util.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_util.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xml_util.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xml_util.lo `test -f 'xml_util.cpp' || echo '$(srcdir)/'`xml_util.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xpath_parser.lo: xpath_parser.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xpath_parser.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xpath_parser.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xpath_parser.lo `test -f 'xpath_parser.cpp' || echo '$(srcdir)/'`xpath_parser.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xpath_parser.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xpath_parser.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xpath_parser.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xpath_parser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xpath_parser.lo `test -f 'xpath_parser.cpp' || echo '$(srcdir)/'`xpath_parser.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.lo: yaml_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.lo `test -f 'yaml_document_tree.cpp' || echo '$(srcdir)/'`yaml_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='yaml_document_tree.cpp' object='liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.lo `test -f 'yaml_document_tree.cpp' || echo '$(srcdir)/'`yaml_document_tree.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.lo: ooxml_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.lo `test -f 'ooxml_namespace_types.cpp' || echo '$(srcdir)/'`ooxml_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_namespace_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.lo `test -f 'ooxml_namespace_types.cpp' || echo '$(srcdir)/'`ooxml_namespace_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.lo: odf_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.lo `test -f 'odf_namespace_types.cpp' || echo '$(srcdir)/'`odf_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_namespace_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.lo `test -f 'odf_namespace_types.cpp' || echo '$(srcdir)/'`odf_namespace_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.lo: gnumeric_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.lo `test -f 'gnumeric_namespace_types.cpp' || echo '$(srcdir)/'`gnumeric_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_namespace_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.lo `test -f 'gnumeric_namespace_types.cpp' || echo '$(srcdir)/'`gnumeric_namespace_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.lo: xls_xml_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.lo `test -f 'xls_xml_namespace_types.cpp' || echo '$(srcdir)/'`xls_xml_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xls_xml_namespace_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.lo `test -f 'xls_xml_namespace_types.cpp' || echo '$(srcdir)/'`xls_xml_namespace_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-session_context.lo: session_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-session_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-session_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-session_context.lo `test -f 'session_context.cpp' || echo '$(srcdir)/'`session_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-session_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-session_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='session_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-session_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-session_context.lo `test -f 'session_context.cpp' || echo '$(srcdir)/'`session_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.lo: spreadsheet_impl_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.lo `test -f 'spreadsheet_impl_types.cpp' || echo '$(srcdir)/'`spreadsheet_impl_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='spreadsheet_impl_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.lo `test -f 'spreadsheet_impl_types.cpp' || echo '$(srcdir)/'`spreadsheet_impl_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.lo: spreadsheet_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.lo `test -f 'spreadsheet_types.cpp' || echo '$(srcdir)/'`spreadsheet_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='spreadsheet_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.lo `test -f 'spreadsheet_types.cpp' || echo '$(srcdir)/'`spreadsheet_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.lo: spreadsheet_iface_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.lo `test -f 'spreadsheet_iface_util.cpp' || echo '$(srcdir)/'`spreadsheet_iface_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='spreadsheet_iface_util.cpp' object='liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.lo `test -f 'spreadsheet_iface_util.cpp' || echo '$(srcdir)/'`spreadsheet_iface_util.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-string_helper.lo: string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-string_helper.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-string_helper.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-string_helper.lo `test -f 'string_helper.cpp' || echo '$(srcdir)/'`string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-string_helper.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-string_helper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_helper.cpp' object='liborcus_@ORCUS_API_VERSION@_la-string_helper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-string_helper.lo `test -f 'string_helper.cpp' || echo '$(srcdir)/'`string_helper.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.lo: ooxml_content_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.lo `test -f 'ooxml_content_types.cpp' || echo '$(srcdir)/'`ooxml_content_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_content_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.lo `test -f 'ooxml_content_types.cpp' || echo '$(srcdir)/'`ooxml_content_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-ooxml_global.lo: ooxml_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-ooxml_global.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_global.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_global.lo `test -f 'ooxml_global.cpp' || echo '$(srcdir)/'`ooxml_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_global.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_global.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_global.cpp' object='liborcus_@ORCUS_API_VERSION@_la-ooxml_global.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_global.lo `test -f 'ooxml_global.cpp' || echo '$(srcdir)/'`ooxml_global.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.lo: ooxml_schemas.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.lo `test -f 'ooxml_schemas.cpp' || echo '$(srcdir)/'`ooxml_schemas.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_schemas.cpp' object='liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.lo `test -f 'ooxml_schemas.cpp' || echo '$(srcdir)/'`ooxml_schemas.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.lo: ooxml_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.lo `test -f 'ooxml_tokens.cpp' || echo '$(srcdir)/'`ooxml_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_tokens.cpp' object='liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.lo `test -f 'ooxml_tokens.cpp' || echo '$(srcdir)/'`ooxml_tokens.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-ooxml_types.lo: ooxml_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-ooxml_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_types.lo `test -f 'ooxml_types.cpp' || echo '$(srcdir)/'`ooxml_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-ooxml_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-ooxml_types.lo `test -f 'ooxml_types.cpp' || echo '$(srcdir)/'`ooxml_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-opc_context.lo: opc_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-opc_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-opc_context.lo `test -f 'opc_context.cpp' || echo '$(srcdir)/'`opc_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='opc_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-opc_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-opc_context.lo `test -f 'opc_context.cpp' || echo '$(srcdir)/'`opc_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-opc_reader.lo: opc_reader.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-opc_reader.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_reader.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-opc_reader.lo `test -f 'opc_reader.cpp' || echo '$(srcdir)/'`opc_reader.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_reader.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_reader.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='opc_reader.cpp' object='liborcus_@ORCUS_API_VERSION@_la-opc_reader.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-opc_reader.lo `test -f 'opc_reader.cpp' || echo '$(srcdir)/'`opc_reader.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.lo: orcus_xlsx.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.lo `test -f 'orcus_xlsx.cpp' || echo '$(srcdir)/'`orcus_xlsx.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xlsx.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.lo `test -f 'orcus_xlsx.cpp' || echo '$(srcdir)/'`orcus_xlsx.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.lo: orcus_import_xlsx.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.lo `test -f 'orcus_import_xlsx.cpp' || echo '$(srcdir)/'`orcus_import_xlsx.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_import_xlsx.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.lo `test -f 'orcus_import_xlsx.cpp' || echo '$(srcdir)/'`orcus_import_xlsx.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.lo: xlsx_shared_strings_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.lo `test -f 'xlsx_shared_strings_context.cpp' || echo '$(srcdir)/'`xlsx_shared_strings_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_shared_strings_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.lo `test -f 'xlsx_shared_strings_context.cpp' || echo '$(srcdir)/'`xlsx_shared_strings_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.lo: xlsx_drawing_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.lo `test -f 'xlsx_drawing_context.cpp' || echo '$(srcdir)/'`xlsx_drawing_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_drawing_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.lo `test -f 'xlsx_drawing_context.cpp' || echo '$(srcdir)/'`xlsx_drawing_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.lo: xlsx_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.lo `test -f 'xlsx_handler.cpp' || echo '$(srcdir)/'`xlsx_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_handler.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.lo `test -f 'xlsx_handler.cpp' || echo '$(srcdir)/'`xlsx_handler.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.lo: xlsx_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.lo `test -f 'xlsx_helper.cpp' || echo '$(srcdir)/'`xlsx_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_helper.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.lo `test -f 'xlsx_helper.cpp' || echo '$(srcdir)/'`xlsx_helper.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.lo: xlsx_session_data.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.lo `test -f 'xlsx_session_data.cpp' || echo '$(srcdir)/'`xlsx_session_data.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_session_data.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.lo `test -f 'xlsx_session_data.cpp' || echo '$(srcdir)/'`xlsx_session_data.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.lo: xlsx_revision_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.lo `test -f 'xlsx_revision_context.cpp' || echo '$(srcdir)/'`xlsx_revision_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_revision_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.lo `test -f 'xlsx_revision_context.cpp' || echo '$(srcdir)/'`xlsx_revision_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.lo: xlsx_pivot_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.lo `test -f 'xlsx_pivot_context.cpp' || echo '$(srcdir)/'`xlsx_pivot_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_pivot_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.lo `test -f 'xlsx_pivot_context.cpp' || echo '$(srcdir)/'`xlsx_pivot_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.lo: xlsx_sheet_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.lo `test -f 'xlsx_sheet_context.cpp' || echo '$(srcdir)/'`xlsx_sheet_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_sheet_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.lo `test -f 'xlsx_sheet_context.cpp' || echo '$(srcdir)/'`xlsx_sheet_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.lo: xlsx_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.lo `test -f 'xlsx_styles_context.cpp' || echo '$(srcdir)/'`xlsx_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_styles_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.lo `test -f 'xlsx_styles_context.cpp' || echo '$(srcdir)/'`xlsx_styles_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.lo: xlsx_conditional_format_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.lo `test -f 'xlsx_conditional_format_context.cpp' || echo '$(srcdir)/'`xlsx_conditional_format_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_conditional_format_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.lo `test -f 'xlsx_conditional_format_context.cpp' || echo '$(srcdir)/'`xlsx_conditional_format_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.lo: xlsx_table_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.lo `test -f 'xlsx_table_context.cpp' || echo '$(srcdir)/'`xlsx_table_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_table_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.lo `test -f 'xlsx_table_context.cpp' || echo '$(srcdir)/'`xlsx_table_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.lo: xlsx_autofilter_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.lo `test -f 'xlsx_autofilter_context.cpp' || echo '$(srcdir)/'`xlsx_autofilter_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_autofilter_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.lo `test -f 'xlsx_autofilter_context.cpp' || echo '$(srcdir)/'`xlsx_autofilter_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_types.lo: xlsx_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_types.lo `test -f 'xlsx_types.cpp' || echo '$(srcdir)/'`xlsx_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_types.lo `test -f 'xlsx_types.cpp' || echo '$(srcdir)/'`xlsx_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.lo: xlsx_workbook_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.lo `test -f 'xlsx_workbook_context.cpp' || echo '$(srcdir)/'`xlsx_workbook_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_workbook_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.lo `test -f 'xlsx_workbook_context.cpp' || echo '$(srcdir)/'`xlsx_workbook_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.lo: xls_xml_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.lo `test -f 'xls_xml_tokens.cpp' || echo '$(srcdir)/'`xls_xml_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xls_xml_tokens.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.lo `test -f 'xls_xml_tokens.cpp' || echo '$(srcdir)/'`xls_xml_tokens.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.lo: orcus_xls_xml.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.lo `test -f 'orcus_xls_xml.cpp' || echo '$(srcdir)/'`orcus_xls_xml.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_xls_xml.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.lo `test -f 'orcus_xls_xml.cpp' || echo '$(srcdir)/'`orcus_xls_xml.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.lo: xls_xml_detection_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.lo `test -f 'xls_xml_detection_handler.cpp' || echo '$(srcdir)/'`xls_xml_detection_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xls_xml_detection_handler.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.lo `test -f 'xls_xml_detection_handler.cpp' || echo '$(srcdir)/'`xls_xml_detection_handler.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.lo: xls_xml_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.lo `test -f 'xls_xml_handler.cpp' || echo '$(srcdir)/'`xls_xml_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xls_xml_handler.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.lo `test -f 'xls_xml_handler.cpp' || echo '$(srcdir)/'`xls_xml_handler.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.lo: xls_xml_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.lo `test -f 'xls_xml_context.cpp' || echo '$(srcdir)/'`xls_xml_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xls_xml_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.lo `test -f 'xls_xml_context.cpp' || echo '$(srcdir)/'`xls_xml_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.lo: odf_document_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.lo `test -f 'odf_document_styles_context.cpp' || echo '$(srcdir)/'`odf_document_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_document_styles_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.lo `test -f 'odf_document_styles_context.cpp' || echo '$(srcdir)/'`odf_document_styles_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-odf_para_context.lo: odf_para_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-odf_para_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_para_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-odf_para_context.lo `test -f 'odf_para_context.cpp' || echo '$(srcdir)/'`odf_para_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_para_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_para_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_para_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-odf_para_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-odf_para_context.lo `test -f 'odf_para_context.cpp' || echo '$(srcdir)/'`odf_para_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-odf_styles.lo: odf_styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-odf_styles.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-odf_styles.lo `test -f 'odf_styles.cpp' || echo '$(srcdir)/'`odf_styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_styles.cpp' object='liborcus_@ORCUS_API_VERSION@_la-odf_styles.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-odf_styles.lo `test -f 'odf_styles.cpp' || echo '$(srcdir)/'`odf_styles.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.lo: odf_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.lo `test -f 'odf_styles_context.cpp' || echo '$(srcdir)/'`odf_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_styles_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.lo `test -f 'odf_styles_context.cpp' || echo '$(srcdir)/'`odf_styles_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-odf_style_context.lo: odf_style_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-odf_style_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_style_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-odf_style_context.lo `test -f 'odf_style_context.cpp' || echo '$(srcdir)/'`odf_style_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_style_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_style_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_style_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-odf_style_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-odf_style_context.lo `test -f 'odf_style_context.cpp' || echo '$(srcdir)/'`odf_style_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.lo: odf_number_format_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.lo `test -f 'odf_number_format_context.cpp' || echo '$(srcdir)/'`odf_number_format_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_number_format_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.lo `test -f 'odf_number_format_context.cpp' || echo '$(srcdir)/'`odf_number_format_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-odf_tokens.lo: odf_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-odf_tokens.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_tokens.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-odf_tokens.lo `test -f 'odf_tokens.cpp' || echo '$(srcdir)/'`odf_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_tokens.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_tokens.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_tokens.cpp' object='liborcus_@ORCUS_API_VERSION@_la-odf_tokens.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-odf_tokens.lo `test -f 'odf_tokens.cpp' || echo '$(srcdir)/'`odf_tokens.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.lo: ods_content_xml_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.lo `test -f 'ods_content_xml_context.cpp' || echo '$(srcdir)/'`ods_content_xml_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ods_content_xml_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.lo `test -f 'ods_content_xml_context.cpp' || echo '$(srcdir)/'`ods_content_xml_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.lo: ods_dde_links_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.lo `test -f 'ods_dde_links_context.cpp' || echo '$(srcdir)/'`ods_dde_links_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ods_dde_links_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.lo `test -f 'ods_dde_links_context.cpp' || echo '$(srcdir)/'`ods_dde_links_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-ods_session_data.lo: ods_session_data.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-ods_session_data.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_session_data.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-ods_session_data.lo `test -f 'ods_session_data.cpp' || echo '$(srcdir)/'`ods_session_data.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_session_data.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_session_data.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ods_session_data.cpp' object='liborcus_@ORCUS_API_VERSION@_la-ods_session_data.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-ods_session_data.lo `test -f 'ods_session_data.cpp' || echo '$(srcdir)/'`ods_session_data.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-odf_helper.lo: odf_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-odf_helper.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_helper.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-odf_helper.lo `test -f 'odf_helper.cpp' || echo '$(srcdir)/'`odf_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_helper.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_helper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_helper.cpp' object='liborcus_@ORCUS_API_VERSION@_la-odf_helper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-odf_helper.lo `test -f 'odf_helper.cpp' || echo '$(srcdir)/'`odf_helper.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_ods.lo: orcus_ods.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_ods.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_ods.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_ods.lo `test -f 'orcus_ods.cpp' || echo '$(srcdir)/'`orcus_ods.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_ods.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_ods.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_ods.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_ods.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_ods.lo `test -f 'orcus_ods.cpp' || echo '$(srcdir)/'`orcus_ods.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.lo: orcus_import_ods.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.lo `test -f 'orcus_import_ods.cpp' || echo '$(srcdir)/'`orcus_import_ods.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_import_ods.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.lo `test -f 'orcus_import_ods.cpp' || echo '$(srcdir)/'`orcus_import_ods.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.lo: gnumeric_cell_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.lo `test -f 'gnumeric_cell_context.cpp' || echo '$(srcdir)/'`gnumeric_cell_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_cell_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.lo `test -f 'gnumeric_cell_context.cpp' || echo '$(srcdir)/'`gnumeric_cell_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.lo: gnumeric_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.lo `test -f 'gnumeric_context.cpp' || echo '$(srcdir)/'`gnumeric_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.lo `test -f 'gnumeric_context.cpp' || echo '$(srcdir)/'`gnumeric_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.lo: gnumeric_detection_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.lo `test -f 'gnumeric_detection_handler.cpp' || echo '$(srcdir)/'`gnumeric_detection_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_detection_handler.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.lo `test -f 'gnumeric_detection_handler.cpp' || echo '$(srcdir)/'`gnumeric_detection_handler.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.lo: gnumeric_filter_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.lo `test -f 'gnumeric_filter_context.cpp' || echo '$(srcdir)/'`gnumeric_filter_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_filter_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.lo `test -f 'gnumeric_filter_context.cpp' || echo '$(srcdir)/'`gnumeric_filter_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.lo: gnumeric_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.lo `test -f 'gnumeric_handler.cpp' || echo '$(srcdir)/'`gnumeric_handler.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_handler.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.lo `test -f 'gnumeric_handler.cpp' || echo '$(srcdir)/'`gnumeric_handler.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.lo: gnumeric_names_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.lo `test -f 'gnumeric_names_context.cpp' || echo '$(srcdir)/'`gnumeric_names_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_names_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.lo `test -f 'gnumeric_names_context.cpp' || echo '$(srcdir)/'`gnumeric_names_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.lo: gnumeric_sheet_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.lo `test -f 'gnumeric_sheet_context.cpp' || echo '$(srcdir)/'`gnumeric_sheet_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_sheet_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.lo `test -f 'gnumeric_sheet_context.cpp' || echo '$(srcdir)/'`gnumeric_sheet_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.lo: gnumeric_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.lo `test -f 'gnumeric_styles_context.cpp' || echo '$(srcdir)/'`gnumeric_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_styles_context.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.lo `test -f 'gnumeric_styles_context.cpp' || echo '$(srcdir)/'`gnumeric_styles_context.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.lo: gnumeric_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.lo `test -f 'gnumeric_tokens.cpp' || echo '$(srcdir)/'`gnumeric_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_tokens.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.lo `test -f 'gnumeric_tokens.cpp' || echo '$(srcdir)/'`gnumeric_tokens.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.lo: gnumeric_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.lo `test -f 'gnumeric_types.cpp' || echo '$(srcdir)/'`gnumeric_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_types.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.lo `test -f 'gnumeric_types.cpp' || echo '$(srcdir)/'`gnumeric_types.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.lo: gnumeric_value_format_parser.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.lo `test -f 'gnumeric_value_format_parser.cpp' || echo '$(srcdir)/'`gnumeric_value_format_parser.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_value_format_parser.cpp' object='liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.lo `test -f 'gnumeric_value_format_parser.cpp' || echo '$(srcdir)/'`gnumeric_value_format_parser.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.lo: orcus_gnumeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.lo `test -f 'orcus_gnumeric.cpp' || echo '$(srcdir)/'`orcus_gnumeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_gnumeric.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.lo `test -f 'orcus_gnumeric.cpp' || echo '$(srcdir)/'`orcus_gnumeric.cpp
+
+liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.lo: orcus_parquet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -MT liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.lo -MD -MP -MF $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.Tpo -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.lo `test -f 'orcus_parquet.cpp' || echo '$(srcdir)/'`orcus_parquet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.Tpo $(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='orcus_parquet.cpp' object='liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liborcus_@ORCUS_API_VERSION@_la_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.lo `test -f 'orcus_parquet.cpp' || echo '$(srcdir)/'`orcus_parquet.cpp
+
+gnumeric_sheet_context_test-session_context.o: session_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-session_context.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-session_context.Tpo -c -o gnumeric_sheet_context_test-session_context.o `test -f 'session_context.cpp' || echo '$(srcdir)/'`session_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-session_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-session_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='session_context.cpp' object='gnumeric_sheet_context_test-session_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-session_context.o `test -f 'session_context.cpp' || echo '$(srcdir)/'`session_context.cpp
+
+gnumeric_sheet_context_test-session_context.obj: session_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-session_context.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-session_context.Tpo -c -o gnumeric_sheet_context_test-session_context.obj `if test -f 'session_context.cpp'; then $(CYGPATH_W) 'session_context.cpp'; else $(CYGPATH_W) '$(srcdir)/session_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-session_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-session_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='session_context.cpp' object='gnumeric_sheet_context_test-session_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-session_context.obj `if test -f 'session_context.cpp'; then $(CYGPATH_W) 'session_context.cpp'; else $(CYGPATH_W) '$(srcdir)/session_context.cpp'; fi`
+
+gnumeric_sheet_context_test-gnumeric_sheet_context_test.o: gnumeric_sheet_context_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_sheet_context_test.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context_test.Tpo -c -o gnumeric_sheet_context_test-gnumeric_sheet_context_test.o `test -f 'gnumeric_sheet_context_test.cpp' || echo '$(srcdir)/'`gnumeric_sheet_context_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context_test.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_sheet_context_test.cpp' object='gnumeric_sheet_context_test-gnumeric_sheet_context_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_sheet_context_test.o `test -f 'gnumeric_sheet_context_test.cpp' || echo '$(srcdir)/'`gnumeric_sheet_context_test.cpp
+
+gnumeric_sheet_context_test-gnumeric_sheet_context_test.obj: gnumeric_sheet_context_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_sheet_context_test.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context_test.Tpo -c -o gnumeric_sheet_context_test-gnumeric_sheet_context_test.obj `if test -f 'gnumeric_sheet_context_test.cpp'; then $(CYGPATH_W) 'gnumeric_sheet_context_test.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_sheet_context_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context_test.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_sheet_context_test.cpp' object='gnumeric_sheet_context_test-gnumeric_sheet_context_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_sheet_context_test.obj `if test -f 'gnumeric_sheet_context_test.cpp'; then $(CYGPATH_W) 'gnumeric_sheet_context_test.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_sheet_context_test.cpp'; fi`
+
+gnumeric_sheet_context_test-gnumeric_sheet_context.o: gnumeric_sheet_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_sheet_context.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context.Tpo -c -o gnumeric_sheet_context_test-gnumeric_sheet_context.o `test -f 'gnumeric_sheet_context.cpp' || echo '$(srcdir)/'`gnumeric_sheet_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_sheet_context.cpp' object='gnumeric_sheet_context_test-gnumeric_sheet_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_sheet_context.o `test -f 'gnumeric_sheet_context.cpp' || echo '$(srcdir)/'`gnumeric_sheet_context.cpp
+
+gnumeric_sheet_context_test-gnumeric_sheet_context.obj: gnumeric_sheet_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_sheet_context.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context.Tpo -c -o gnumeric_sheet_context_test-gnumeric_sheet_context.obj `if test -f 'gnumeric_sheet_context.cpp'; then $(CYGPATH_W) 'gnumeric_sheet_context.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_sheet_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_sheet_context.cpp' object='gnumeric_sheet_context_test-gnumeric_sheet_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_sheet_context.obj `if test -f 'gnumeric_sheet_context.cpp'; then $(CYGPATH_W) 'gnumeric_sheet_context.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_sheet_context.cpp'; fi`
+
+gnumeric_sheet_context_test-gnumeric_names_context.o: gnumeric_names_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_names_context.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_names_context.Tpo -c -o gnumeric_sheet_context_test-gnumeric_names_context.o `test -f 'gnumeric_names_context.cpp' || echo '$(srcdir)/'`gnumeric_names_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_names_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_names_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_names_context.cpp' object='gnumeric_sheet_context_test-gnumeric_names_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_names_context.o `test -f 'gnumeric_names_context.cpp' || echo '$(srcdir)/'`gnumeric_names_context.cpp
+
+gnumeric_sheet_context_test-gnumeric_names_context.obj: gnumeric_names_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_names_context.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_names_context.Tpo -c -o gnumeric_sheet_context_test-gnumeric_names_context.obj `if test -f 'gnumeric_names_context.cpp'; then $(CYGPATH_W) 'gnumeric_names_context.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_names_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_names_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_names_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_names_context.cpp' object='gnumeric_sheet_context_test-gnumeric_names_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_names_context.obj `if test -f 'gnumeric_names_context.cpp'; then $(CYGPATH_W) 'gnumeric_names_context.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_names_context.cpp'; fi`
+
+gnumeric_sheet_context_test-gnumeric_cell_context.o: gnumeric_cell_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_cell_context.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_cell_context.Tpo -c -o gnumeric_sheet_context_test-gnumeric_cell_context.o `test -f 'gnumeric_cell_context.cpp' || echo '$(srcdir)/'`gnumeric_cell_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_cell_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_cell_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_cell_context.cpp' object='gnumeric_sheet_context_test-gnumeric_cell_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_cell_context.o `test -f 'gnumeric_cell_context.cpp' || echo '$(srcdir)/'`gnumeric_cell_context.cpp
+
+gnumeric_sheet_context_test-gnumeric_cell_context.obj: gnumeric_cell_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_cell_context.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_cell_context.Tpo -c -o gnumeric_sheet_context_test-gnumeric_cell_context.obj `if test -f 'gnumeric_cell_context.cpp'; then $(CYGPATH_W) 'gnumeric_cell_context.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_cell_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_cell_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_cell_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_cell_context.cpp' object='gnumeric_sheet_context_test-gnumeric_cell_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_cell_context.obj `if test -f 'gnumeric_cell_context.cpp'; then $(CYGPATH_W) 'gnumeric_cell_context.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_cell_context.cpp'; fi`
+
+gnumeric_sheet_context_test-gnumeric_filter_context.o: gnumeric_filter_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_filter_context.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_filter_context.Tpo -c -o gnumeric_sheet_context_test-gnumeric_filter_context.o `test -f 'gnumeric_filter_context.cpp' || echo '$(srcdir)/'`gnumeric_filter_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_filter_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_filter_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_filter_context.cpp' object='gnumeric_sheet_context_test-gnumeric_filter_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_filter_context.o `test -f 'gnumeric_filter_context.cpp' || echo '$(srcdir)/'`gnumeric_filter_context.cpp
+
+gnumeric_sheet_context_test-gnumeric_filter_context.obj: gnumeric_filter_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_filter_context.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_filter_context.Tpo -c -o gnumeric_sheet_context_test-gnumeric_filter_context.obj `if test -f 'gnumeric_filter_context.cpp'; then $(CYGPATH_W) 'gnumeric_filter_context.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_filter_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_filter_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_filter_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_filter_context.cpp' object='gnumeric_sheet_context_test-gnumeric_filter_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_filter_context.obj `if test -f 'gnumeric_filter_context.cpp'; then $(CYGPATH_W) 'gnumeric_filter_context.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_filter_context.cpp'; fi`
+
+gnumeric_sheet_context_test-gnumeric_styles_context.o: gnumeric_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_styles_context.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_styles_context.Tpo -c -o gnumeric_sheet_context_test-gnumeric_styles_context.o `test -f 'gnumeric_styles_context.cpp' || echo '$(srcdir)/'`gnumeric_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_styles_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_styles_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_styles_context.cpp' object='gnumeric_sheet_context_test-gnumeric_styles_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_styles_context.o `test -f 'gnumeric_styles_context.cpp' || echo '$(srcdir)/'`gnumeric_styles_context.cpp
+
+gnumeric_sheet_context_test-gnumeric_styles_context.obj: gnumeric_styles_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_styles_context.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_styles_context.Tpo -c -o gnumeric_sheet_context_test-gnumeric_styles_context.obj `if test -f 'gnumeric_styles_context.cpp'; then $(CYGPATH_W) 'gnumeric_styles_context.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_styles_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_styles_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_styles_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_styles_context.cpp' object='gnumeric_sheet_context_test-gnumeric_styles_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_styles_context.obj `if test -f 'gnumeric_styles_context.cpp'; then $(CYGPATH_W) 'gnumeric_styles_context.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_styles_context.cpp'; fi`
+
+gnumeric_sheet_context_test-gnumeric_value_format_parser.o: gnumeric_value_format_parser.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_value_format_parser.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_value_format_parser.Tpo -c -o gnumeric_sheet_context_test-gnumeric_value_format_parser.o `test -f 'gnumeric_value_format_parser.cpp' || echo '$(srcdir)/'`gnumeric_value_format_parser.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_value_format_parser.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_value_format_parser.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_value_format_parser.cpp' object='gnumeric_sheet_context_test-gnumeric_value_format_parser.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_value_format_parser.o `test -f 'gnumeric_value_format_parser.cpp' || echo '$(srcdir)/'`gnumeric_value_format_parser.cpp
+
+gnumeric_sheet_context_test-gnumeric_value_format_parser.obj: gnumeric_value_format_parser.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_value_format_parser.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_value_format_parser.Tpo -c -o gnumeric_sheet_context_test-gnumeric_value_format_parser.obj `if test -f 'gnumeric_value_format_parser.cpp'; then $(CYGPATH_W) 'gnumeric_value_format_parser.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_value_format_parser.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_value_format_parser.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_value_format_parser.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_value_format_parser.cpp' object='gnumeric_sheet_context_test-gnumeric_value_format_parser.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_value_format_parser.obj `if test -f 'gnumeric_value_format_parser.cpp'; then $(CYGPATH_W) 'gnumeric_value_format_parser.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_value_format_parser.cpp'; fi`
+
+gnumeric_sheet_context_test-gnumeric_types.o: gnumeric_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_types.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_types.Tpo -c -o gnumeric_sheet_context_test-gnumeric_types.o `test -f 'gnumeric_types.cpp' || echo '$(srcdir)/'`gnumeric_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_types.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_types.cpp' object='gnumeric_sheet_context_test-gnumeric_types.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_types.o `test -f 'gnumeric_types.cpp' || echo '$(srcdir)/'`gnumeric_types.cpp
+
+gnumeric_sheet_context_test-gnumeric_types.obj: gnumeric_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_types.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_types.Tpo -c -o gnumeric_sheet_context_test-gnumeric_types.obj `if test -f 'gnumeric_types.cpp'; then $(CYGPATH_W) 'gnumeric_types.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_types.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_types.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_types.cpp' object='gnumeric_sheet_context_test-gnumeric_types.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_types.obj `if test -f 'gnumeric_types.cpp'; then $(CYGPATH_W) 'gnumeric_types.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_types.cpp'; fi`
+
+gnumeric_sheet_context_test-number_utils.o: number_utils.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-number_utils.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-number_utils.Tpo -c -o gnumeric_sheet_context_test-number_utils.o `test -f 'number_utils.cpp' || echo '$(srcdir)/'`number_utils.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-number_utils.Tpo $(DEPDIR)/gnumeric_sheet_context_test-number_utils.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='number_utils.cpp' object='gnumeric_sheet_context_test-number_utils.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-number_utils.o `test -f 'number_utils.cpp' || echo '$(srcdir)/'`number_utils.cpp
+
+gnumeric_sheet_context_test-number_utils.obj: number_utils.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-number_utils.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-number_utils.Tpo -c -o gnumeric_sheet_context_test-number_utils.obj `if test -f 'number_utils.cpp'; then $(CYGPATH_W) 'number_utils.cpp'; else $(CYGPATH_W) '$(srcdir)/number_utils.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-number_utils.Tpo $(DEPDIR)/gnumeric_sheet_context_test-number_utils.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='number_utils.cpp' object='gnumeric_sheet_context_test-number_utils.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-number_utils.obj `if test -f 'number_utils.cpp'; then $(CYGPATH_W) 'number_utils.cpp'; else $(CYGPATH_W) '$(srcdir)/number_utils.cpp'; fi`
+
+gnumeric_sheet_context_test-xml_context_base.o: xml_context_base.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-xml_context_base.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-xml_context_base.Tpo -c -o gnumeric_sheet_context_test-xml_context_base.o `test -f 'xml_context_base.cpp' || echo '$(srcdir)/'`xml_context_base.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-xml_context_base.Tpo $(DEPDIR)/gnumeric_sheet_context_test-xml_context_base.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_context_base.cpp' object='gnumeric_sheet_context_test-xml_context_base.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-xml_context_base.o `test -f 'xml_context_base.cpp' || echo '$(srcdir)/'`xml_context_base.cpp
+
+gnumeric_sheet_context_test-xml_context_base.obj: xml_context_base.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-xml_context_base.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-xml_context_base.Tpo -c -o gnumeric_sheet_context_test-xml_context_base.obj `if test -f 'xml_context_base.cpp'; then $(CYGPATH_W) 'xml_context_base.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_context_base.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-xml_context_base.Tpo $(DEPDIR)/gnumeric_sheet_context_test-xml_context_base.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_context_base.cpp' object='gnumeric_sheet_context_test-xml_context_base.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-xml_context_base.obj `if test -f 'xml_context_base.cpp'; then $(CYGPATH_W) 'xml_context_base.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_context_base.cpp'; fi`
+
+gnumeric_sheet_context_test-xml_element_types.o: xml_element_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-xml_element_types.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-xml_element_types.Tpo -c -o gnumeric_sheet_context_test-xml_element_types.o `test -f 'xml_element_types.cpp' || echo '$(srcdir)/'`xml_element_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-xml_element_types.Tpo $(DEPDIR)/gnumeric_sheet_context_test-xml_element_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_element_types.cpp' object='gnumeric_sheet_context_test-xml_element_types.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-xml_element_types.o `test -f 'xml_element_types.cpp' || echo '$(srcdir)/'`xml_element_types.cpp
+
+gnumeric_sheet_context_test-xml_element_types.obj: xml_element_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-xml_element_types.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-xml_element_types.Tpo -c -o gnumeric_sheet_context_test-xml_element_types.obj `if test -f 'xml_element_types.cpp'; then $(CYGPATH_W) 'xml_element_types.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_element_types.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-xml_element_types.Tpo $(DEPDIR)/gnumeric_sheet_context_test-xml_element_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_element_types.cpp' object='gnumeric_sheet_context_test-xml_element_types.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-xml_element_types.obj `if test -f 'xml_element_types.cpp'; then $(CYGPATH_W) 'xml_element_types.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_element_types.cpp'; fi`
+
+gnumeric_sheet_context_test-xml_element_validator.o: xml_element_validator.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-xml_element_validator.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-xml_element_validator.Tpo -c -o gnumeric_sheet_context_test-xml_element_validator.o `test -f 'xml_element_validator.cpp' || echo '$(srcdir)/'`xml_element_validator.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-xml_element_validator.Tpo $(DEPDIR)/gnumeric_sheet_context_test-xml_element_validator.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_element_validator.cpp' object='gnumeric_sheet_context_test-xml_element_validator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-xml_element_validator.o `test -f 'xml_element_validator.cpp' || echo '$(srcdir)/'`xml_element_validator.cpp
+
+gnumeric_sheet_context_test-xml_element_validator.obj: xml_element_validator.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-xml_element_validator.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-xml_element_validator.Tpo -c -o gnumeric_sheet_context_test-xml_element_validator.obj `if test -f 'xml_element_validator.cpp'; then $(CYGPATH_W) 'xml_element_validator.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_element_validator.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-xml_element_validator.Tpo $(DEPDIR)/gnumeric_sheet_context_test-xml_element_validator.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_element_validator.cpp' object='gnumeric_sheet_context_test-xml_element_validator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-xml_element_validator.obj `if test -f 'xml_element_validator.cpp'; then $(CYGPATH_W) 'xml_element_validator.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_element_validator.cpp'; fi`
+
+gnumeric_sheet_context_test-xml_empty_context.o: xml_empty_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-xml_empty_context.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-xml_empty_context.Tpo -c -o gnumeric_sheet_context_test-xml_empty_context.o `test -f 'xml_empty_context.cpp' || echo '$(srcdir)/'`xml_empty_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-xml_empty_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-xml_empty_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_empty_context.cpp' object='gnumeric_sheet_context_test-xml_empty_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-xml_empty_context.o `test -f 'xml_empty_context.cpp' || echo '$(srcdir)/'`xml_empty_context.cpp
+
+gnumeric_sheet_context_test-xml_empty_context.obj: xml_empty_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-xml_empty_context.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-xml_empty_context.Tpo -c -o gnumeric_sheet_context_test-xml_empty_context.obj `if test -f 'xml_empty_context.cpp'; then $(CYGPATH_W) 'xml_empty_context.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_empty_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-xml_empty_context.Tpo $(DEPDIR)/gnumeric_sheet_context_test-xml_empty_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_empty_context.cpp' object='gnumeric_sheet_context_test-xml_empty_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-xml_empty_context.obj `if test -f 'xml_empty_context.cpp'; then $(CYGPATH_W) 'xml_empty_context.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_empty_context.cpp'; fi`
+
+gnumeric_sheet_context_test-xml_util.o: xml_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-xml_util.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-xml_util.Tpo -c -o gnumeric_sheet_context_test-xml_util.o `test -f 'xml_util.cpp' || echo '$(srcdir)/'`xml_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-xml_util.Tpo $(DEPDIR)/gnumeric_sheet_context_test-xml_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_util.cpp' object='gnumeric_sheet_context_test-xml_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-xml_util.o `test -f 'xml_util.cpp' || echo '$(srcdir)/'`xml_util.cpp
+
+gnumeric_sheet_context_test-xml_util.obj: xml_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-xml_util.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-xml_util.Tpo -c -o gnumeric_sheet_context_test-xml_util.obj `if test -f 'xml_util.cpp'; then $(CYGPATH_W) 'xml_util.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_util.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-xml_util.Tpo $(DEPDIR)/gnumeric_sheet_context_test-xml_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_util.cpp' object='gnumeric_sheet_context_test-xml_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-xml_util.obj `if test -f 'xml_util.cpp'; then $(CYGPATH_W) 'xml_util.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_util.cpp'; fi`
+
+gnumeric_sheet_context_test-gnumeric_namespace_types.o: gnumeric_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_namespace_types.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_namespace_types.Tpo -c -o gnumeric_sheet_context_test-gnumeric_namespace_types.o `test -f 'gnumeric_namespace_types.cpp' || echo '$(srcdir)/'`gnumeric_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_namespace_types.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_namespace_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_namespace_types.cpp' object='gnumeric_sheet_context_test-gnumeric_namespace_types.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_namespace_types.o `test -f 'gnumeric_namespace_types.cpp' || echo '$(srcdir)/'`gnumeric_namespace_types.cpp
+
+gnumeric_sheet_context_test-gnumeric_namespace_types.obj: gnumeric_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_namespace_types.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_namespace_types.Tpo -c -o gnumeric_sheet_context_test-gnumeric_namespace_types.obj `if test -f 'gnumeric_namespace_types.cpp'; then $(CYGPATH_W) 'gnumeric_namespace_types.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_namespace_types.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_namespace_types.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_namespace_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_namespace_types.cpp' object='gnumeric_sheet_context_test-gnumeric_namespace_types.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_namespace_types.obj `if test -f 'gnumeric_namespace_types.cpp'; then $(CYGPATH_W) 'gnumeric_namespace_types.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_namespace_types.cpp'; fi`
+
+gnumeric_sheet_context_test-gnumeric_tokens.o: gnumeric_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_tokens.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_tokens.Tpo -c -o gnumeric_sheet_context_test-gnumeric_tokens.o `test -f 'gnumeric_tokens.cpp' || echo '$(srcdir)/'`gnumeric_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_tokens.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_tokens.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_tokens.cpp' object='gnumeric_sheet_context_test-gnumeric_tokens.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_tokens.o `test -f 'gnumeric_tokens.cpp' || echo '$(srcdir)/'`gnumeric_tokens.cpp
+
+gnumeric_sheet_context_test-gnumeric_tokens.obj: gnumeric_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-gnumeric_tokens.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_tokens.Tpo -c -o gnumeric_sheet_context_test-gnumeric_tokens.obj `if test -f 'gnumeric_tokens.cpp'; then $(CYGPATH_W) 'gnumeric_tokens.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_tokens.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_tokens.Tpo $(DEPDIR)/gnumeric_sheet_context_test-gnumeric_tokens.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gnumeric_tokens.cpp' object='gnumeric_sheet_context_test-gnumeric_tokens.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-gnumeric_tokens.obj `if test -f 'gnumeric_tokens.cpp'; then $(CYGPATH_W) 'gnumeric_tokens.cpp'; else $(CYGPATH_W) '$(srcdir)/gnumeric_tokens.cpp'; fi`
+
+gnumeric_sheet_context_test-odf_namespace_types.o: odf_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-odf_namespace_types.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-odf_namespace_types.Tpo -c -o gnumeric_sheet_context_test-odf_namespace_types.o `test -f 'odf_namespace_types.cpp' || echo '$(srcdir)/'`odf_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-odf_namespace_types.Tpo $(DEPDIR)/gnumeric_sheet_context_test-odf_namespace_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_namespace_types.cpp' object='gnumeric_sheet_context_test-odf_namespace_types.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-odf_namespace_types.o `test -f 'odf_namespace_types.cpp' || echo '$(srcdir)/'`odf_namespace_types.cpp
+
+gnumeric_sheet_context_test-odf_namespace_types.obj: odf_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-odf_namespace_types.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-odf_namespace_types.Tpo -c -o gnumeric_sheet_context_test-odf_namespace_types.obj `if test -f 'odf_namespace_types.cpp'; then $(CYGPATH_W) 'odf_namespace_types.cpp'; else $(CYGPATH_W) '$(srcdir)/odf_namespace_types.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-odf_namespace_types.Tpo $(DEPDIR)/gnumeric_sheet_context_test-odf_namespace_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_namespace_types.cpp' object='gnumeric_sheet_context_test-odf_namespace_types.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-odf_namespace_types.obj `if test -f 'odf_namespace_types.cpp'; then $(CYGPATH_W) 'odf_namespace_types.cpp'; else $(CYGPATH_W) '$(srcdir)/odf_namespace_types.cpp'; fi`
+
+gnumeric_sheet_context_test-spreadsheet_interface.o: spreadsheet_interface.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-spreadsheet_interface.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-spreadsheet_interface.Tpo -c -o gnumeric_sheet_context_test-spreadsheet_interface.o `test -f 'spreadsheet_interface.cpp' || echo '$(srcdir)/'`spreadsheet_interface.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-spreadsheet_interface.Tpo $(DEPDIR)/gnumeric_sheet_context_test-spreadsheet_interface.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='spreadsheet_interface.cpp' object='gnumeric_sheet_context_test-spreadsheet_interface.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-spreadsheet_interface.o `test -f 'spreadsheet_interface.cpp' || echo '$(srcdir)/'`spreadsheet_interface.cpp
+
+gnumeric_sheet_context_test-spreadsheet_interface.obj: spreadsheet_interface.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-spreadsheet_interface.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-spreadsheet_interface.Tpo -c -o gnumeric_sheet_context_test-spreadsheet_interface.obj `if test -f 'spreadsheet_interface.cpp'; then $(CYGPATH_W) 'spreadsheet_interface.cpp'; else $(CYGPATH_W) '$(srcdir)/spreadsheet_interface.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-spreadsheet_interface.Tpo $(DEPDIR)/gnumeric_sheet_context_test-spreadsheet_interface.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='spreadsheet_interface.cpp' object='gnumeric_sheet_context_test-spreadsheet_interface.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-spreadsheet_interface.obj `if test -f 'spreadsheet_interface.cpp'; then $(CYGPATH_W) 'spreadsheet_interface.cpp'; else $(CYGPATH_W) '$(srcdir)/spreadsheet_interface.cpp'; fi`
+
+gnumeric_sheet_context_test-string_helper.o: string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-string_helper.o -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-string_helper.Tpo -c -o gnumeric_sheet_context_test-string_helper.o `test -f 'string_helper.cpp' || echo '$(srcdir)/'`string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-string_helper.Tpo $(DEPDIR)/gnumeric_sheet_context_test-string_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_helper.cpp' object='gnumeric_sheet_context_test-string_helper.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-string_helper.o `test -f 'string_helper.cpp' || echo '$(srcdir)/'`string_helper.cpp
+
+gnumeric_sheet_context_test-string_helper.obj: string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gnumeric_sheet_context_test-string_helper.obj -MD -MP -MF $(DEPDIR)/gnumeric_sheet_context_test-string_helper.Tpo -c -o gnumeric_sheet_context_test-string_helper.obj `if test -f 'string_helper.cpp'; then $(CYGPATH_W) 'string_helper.cpp'; else $(CYGPATH_W) '$(srcdir)/string_helper.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnumeric_sheet_context_test-string_helper.Tpo $(DEPDIR)/gnumeric_sheet_context_test-string_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_helper.cpp' object='gnumeric_sheet_context_test-string_helper.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnumeric_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gnumeric_sheet_context_test-string_helper.obj `if test -f 'string_helper.cpp'; then $(CYGPATH_W) 'string_helper.cpp'; else $(CYGPATH_W) '$(srcdir)/string_helper.cpp'; fi`
+
+json_document_tree_test-json_document_tree.o: json_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT json_document_tree_test-json_document_tree.o -MD -MP -MF $(DEPDIR)/json_document_tree_test-json_document_tree.Tpo -c -o json_document_tree_test-json_document_tree.o `test -f 'json_document_tree.cpp' || echo '$(srcdir)/'`json_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/json_document_tree_test-json_document_tree.Tpo $(DEPDIR)/json_document_tree_test-json_document_tree.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_document_tree.cpp' object='json_document_tree_test-json_document_tree.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o json_document_tree_test-json_document_tree.o `test -f 'json_document_tree.cpp' || echo '$(srcdir)/'`json_document_tree.cpp
+
+json_document_tree_test-json_document_tree.obj: json_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT json_document_tree_test-json_document_tree.obj -MD -MP -MF $(DEPDIR)/json_document_tree_test-json_document_tree.Tpo -c -o json_document_tree_test-json_document_tree.obj `if test -f 'json_document_tree.cpp'; then $(CYGPATH_W) 'json_document_tree.cpp'; else $(CYGPATH_W) '$(srcdir)/json_document_tree.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/json_document_tree_test-json_document_tree.Tpo $(DEPDIR)/json_document_tree_test-json_document_tree.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_document_tree.cpp' object='json_document_tree_test-json_document_tree.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o json_document_tree_test-json_document_tree.obj `if test -f 'json_document_tree.cpp'; then $(CYGPATH_W) 'json_document_tree.cpp'; else $(CYGPATH_W) '$(srcdir)/json_document_tree.cpp'; fi`
+
+json_document_tree_test-json_util.o: json_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT json_document_tree_test-json_util.o -MD -MP -MF $(DEPDIR)/json_document_tree_test-json_util.Tpo -c -o json_document_tree_test-json_util.o `test -f 'json_util.cpp' || echo '$(srcdir)/'`json_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/json_document_tree_test-json_util.Tpo $(DEPDIR)/json_document_tree_test-json_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_util.cpp' object='json_document_tree_test-json_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o json_document_tree_test-json_util.o `test -f 'json_util.cpp' || echo '$(srcdir)/'`json_util.cpp
+
+json_document_tree_test-json_util.obj: json_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT json_document_tree_test-json_util.obj -MD -MP -MF $(DEPDIR)/json_document_tree_test-json_util.Tpo -c -o json_document_tree_test-json_util.obj `if test -f 'json_util.cpp'; then $(CYGPATH_W) 'json_util.cpp'; else $(CYGPATH_W) '$(srcdir)/json_util.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/json_document_tree_test-json_util.Tpo $(DEPDIR)/json_document_tree_test-json_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_util.cpp' object='json_document_tree_test-json_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o json_document_tree_test-json_util.obj `if test -f 'json_util.cpp'; then $(CYGPATH_W) 'json_util.cpp'; else $(CYGPATH_W) '$(srcdir)/json_util.cpp'; fi`
+
+json_document_tree_test-json_document_tree_test.o: json_document_tree_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT json_document_tree_test-json_document_tree_test.o -MD -MP -MF $(DEPDIR)/json_document_tree_test-json_document_tree_test.Tpo -c -o json_document_tree_test-json_document_tree_test.o `test -f 'json_document_tree_test.cpp' || echo '$(srcdir)/'`json_document_tree_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/json_document_tree_test-json_document_tree_test.Tpo $(DEPDIR)/json_document_tree_test-json_document_tree_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_document_tree_test.cpp' object='json_document_tree_test-json_document_tree_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o json_document_tree_test-json_document_tree_test.o `test -f 'json_document_tree_test.cpp' || echo '$(srcdir)/'`json_document_tree_test.cpp
+
+json_document_tree_test-json_document_tree_test.obj: json_document_tree_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT json_document_tree_test-json_document_tree_test.obj -MD -MP -MF $(DEPDIR)/json_document_tree_test-json_document_tree_test.Tpo -c -o json_document_tree_test-json_document_tree_test.obj `if test -f 'json_document_tree_test.cpp'; then $(CYGPATH_W) 'json_document_tree_test.cpp'; else $(CYGPATH_W) '$(srcdir)/json_document_tree_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/json_document_tree_test-json_document_tree_test.Tpo $(DEPDIR)/json_document_tree_test-json_document_tree_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_document_tree_test.cpp' object='json_document_tree_test-json_document_tree_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o json_document_tree_test-json_document_tree_test.obj `if test -f 'json_document_tree_test.cpp'; then $(CYGPATH_W) 'json_document_tree_test.cpp'; else $(CYGPATH_W) '$(srcdir)/json_document_tree_test.cpp'; fi`
+
+odf_helper_test-odf_helper.o: odf_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT odf_helper_test-odf_helper.o -MD -MP -MF $(DEPDIR)/odf_helper_test-odf_helper.Tpo -c -o odf_helper_test-odf_helper.o `test -f 'odf_helper.cpp' || echo '$(srcdir)/'`odf_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/odf_helper_test-odf_helper.Tpo $(DEPDIR)/odf_helper_test-odf_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_helper.cpp' object='odf_helper_test-odf_helper.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o odf_helper_test-odf_helper.o `test -f 'odf_helper.cpp' || echo '$(srcdir)/'`odf_helper.cpp
+
+odf_helper_test-odf_helper.obj: odf_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT odf_helper_test-odf_helper.obj -MD -MP -MF $(DEPDIR)/odf_helper_test-odf_helper.Tpo -c -o odf_helper_test-odf_helper.obj `if test -f 'odf_helper.cpp'; then $(CYGPATH_W) 'odf_helper.cpp'; else $(CYGPATH_W) '$(srcdir)/odf_helper.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/odf_helper_test-odf_helper.Tpo $(DEPDIR)/odf_helper_test-odf_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_helper.cpp' object='odf_helper_test-odf_helper.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o odf_helper_test-odf_helper.obj `if test -f 'odf_helper.cpp'; then $(CYGPATH_W) 'odf_helper.cpp'; else $(CYGPATH_W) '$(srcdir)/odf_helper.cpp'; fi`
+
+odf_helper_test-string_helper.o: string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT odf_helper_test-string_helper.o -MD -MP -MF $(DEPDIR)/odf_helper_test-string_helper.Tpo -c -o odf_helper_test-string_helper.o `test -f 'string_helper.cpp' || echo '$(srcdir)/'`string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/odf_helper_test-string_helper.Tpo $(DEPDIR)/odf_helper_test-string_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_helper.cpp' object='odf_helper_test-string_helper.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o odf_helper_test-string_helper.o `test -f 'string_helper.cpp' || echo '$(srcdir)/'`string_helper.cpp
+
+odf_helper_test-string_helper.obj: string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT odf_helper_test-string_helper.obj -MD -MP -MF $(DEPDIR)/odf_helper_test-string_helper.Tpo -c -o odf_helper_test-string_helper.obj `if test -f 'string_helper.cpp'; then $(CYGPATH_W) 'string_helper.cpp'; else $(CYGPATH_W) '$(srcdir)/string_helper.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/odf_helper_test-string_helper.Tpo $(DEPDIR)/odf_helper_test-string_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_helper.cpp' object='odf_helper_test-string_helper.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o odf_helper_test-string_helper.obj `if test -f 'string_helper.cpp'; then $(CYGPATH_W) 'string_helper.cpp'; else $(CYGPATH_W) '$(srcdir)/string_helper.cpp'; fi`
+
+odf_helper_test-odf_helper_test.o: odf_helper_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT odf_helper_test-odf_helper_test.o -MD -MP -MF $(DEPDIR)/odf_helper_test-odf_helper_test.Tpo -c -o odf_helper_test-odf_helper_test.o `test -f 'odf_helper_test.cpp' || echo '$(srcdir)/'`odf_helper_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/odf_helper_test-odf_helper_test.Tpo $(DEPDIR)/odf_helper_test-odf_helper_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_helper_test.cpp' object='odf_helper_test-odf_helper_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o odf_helper_test-odf_helper_test.o `test -f 'odf_helper_test.cpp' || echo '$(srcdir)/'`odf_helper_test.cpp
+
+odf_helper_test-odf_helper_test.obj: odf_helper_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT odf_helper_test-odf_helper_test.obj -MD -MP -MF $(DEPDIR)/odf_helper_test-odf_helper_test.Tpo -c -o odf_helper_test-odf_helper_test.obj `if test -f 'odf_helper_test.cpp'; then $(CYGPATH_W) 'odf_helper_test.cpp'; else $(CYGPATH_W) '$(srcdir)/odf_helper_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/odf_helper_test-odf_helper_test.Tpo $(DEPDIR)/odf_helper_test-odf_helper_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='odf_helper_test.cpp' object='odf_helper_test-odf_helper_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(odf_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o odf_helper_test-odf_helper_test.obj `if test -f 'odf_helper_test.cpp'; then $(CYGPATH_W) 'odf_helper_test.cpp'; else $(CYGPATH_W) '$(srcdir)/odf_helper_test.cpp'; fi`
+
+xlsx_sheet_context_test-formula_result.o: formula_result.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-formula_result.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-formula_result.Tpo -c -o xlsx_sheet_context_test-formula_result.o `test -f 'formula_result.cpp' || echo '$(srcdir)/'`formula_result.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-formula_result.Tpo $(DEPDIR)/xlsx_sheet_context_test-formula_result.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='formula_result.cpp' object='xlsx_sheet_context_test-formula_result.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-formula_result.o `test -f 'formula_result.cpp' || echo '$(srcdir)/'`formula_result.cpp
+
+xlsx_sheet_context_test-formula_result.obj: formula_result.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-formula_result.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-formula_result.Tpo -c -o xlsx_sheet_context_test-formula_result.obj `if test -f 'formula_result.cpp'; then $(CYGPATH_W) 'formula_result.cpp'; else $(CYGPATH_W) '$(srcdir)/formula_result.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-formula_result.Tpo $(DEPDIR)/xlsx_sheet_context_test-formula_result.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='formula_result.cpp' object='xlsx_sheet_context_test-formula_result.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-formula_result.obj `if test -f 'formula_result.cpp'; then $(CYGPATH_W) 'formula_result.cpp'; else $(CYGPATH_W) '$(srcdir)/formula_result.cpp'; fi`
+
+xlsx_sheet_context_test-ooxml_global.o: ooxml_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-ooxml_global.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-ooxml_global.Tpo -c -o xlsx_sheet_context_test-ooxml_global.o `test -f 'ooxml_global.cpp' || echo '$(srcdir)/'`ooxml_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-ooxml_global.Tpo $(DEPDIR)/xlsx_sheet_context_test-ooxml_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_global.cpp' object='xlsx_sheet_context_test-ooxml_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-ooxml_global.o `test -f 'ooxml_global.cpp' || echo '$(srcdir)/'`ooxml_global.cpp
+
+xlsx_sheet_context_test-ooxml_global.obj: ooxml_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-ooxml_global.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-ooxml_global.Tpo -c -o xlsx_sheet_context_test-ooxml_global.obj `if test -f 'ooxml_global.cpp'; then $(CYGPATH_W) 'ooxml_global.cpp'; else $(CYGPATH_W) '$(srcdir)/ooxml_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-ooxml_global.Tpo $(DEPDIR)/xlsx_sheet_context_test-ooxml_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_global.cpp' object='xlsx_sheet_context_test-ooxml_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-ooxml_global.obj `if test -f 'ooxml_global.cpp'; then $(CYGPATH_W) 'ooxml_global.cpp'; else $(CYGPATH_W) '$(srcdir)/ooxml_global.cpp'; fi`
+
+xlsx_sheet_context_test-ooxml_namespace_types.o: ooxml_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-ooxml_namespace_types.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-ooxml_namespace_types.Tpo -c -o xlsx_sheet_context_test-ooxml_namespace_types.o `test -f 'ooxml_namespace_types.cpp' || echo '$(srcdir)/'`ooxml_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-ooxml_namespace_types.Tpo $(DEPDIR)/xlsx_sheet_context_test-ooxml_namespace_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_namespace_types.cpp' object='xlsx_sheet_context_test-ooxml_namespace_types.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-ooxml_namespace_types.o `test -f 'ooxml_namespace_types.cpp' || echo '$(srcdir)/'`ooxml_namespace_types.cpp
+
+xlsx_sheet_context_test-ooxml_namespace_types.obj: ooxml_namespace_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-ooxml_namespace_types.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-ooxml_namespace_types.Tpo -c -o xlsx_sheet_context_test-ooxml_namespace_types.obj `if test -f 'ooxml_namespace_types.cpp'; then $(CYGPATH_W) 'ooxml_namespace_types.cpp'; else $(CYGPATH_W) '$(srcdir)/ooxml_namespace_types.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-ooxml_namespace_types.Tpo $(DEPDIR)/xlsx_sheet_context_test-ooxml_namespace_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_namespace_types.cpp' object='xlsx_sheet_context_test-ooxml_namespace_types.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-ooxml_namespace_types.obj `if test -f 'ooxml_namespace_types.cpp'; then $(CYGPATH_W) 'ooxml_namespace_types.cpp'; else $(CYGPATH_W) '$(srcdir)/ooxml_namespace_types.cpp'; fi`
+
+xlsx_sheet_context_test-ooxml_schemas.o: ooxml_schemas.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-ooxml_schemas.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-ooxml_schemas.Tpo -c -o xlsx_sheet_context_test-ooxml_schemas.o `test -f 'ooxml_schemas.cpp' || echo '$(srcdir)/'`ooxml_schemas.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-ooxml_schemas.Tpo $(DEPDIR)/xlsx_sheet_context_test-ooxml_schemas.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_schemas.cpp' object='xlsx_sheet_context_test-ooxml_schemas.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-ooxml_schemas.o `test -f 'ooxml_schemas.cpp' || echo '$(srcdir)/'`ooxml_schemas.cpp
+
+xlsx_sheet_context_test-ooxml_schemas.obj: ooxml_schemas.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-ooxml_schemas.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-ooxml_schemas.Tpo -c -o xlsx_sheet_context_test-ooxml_schemas.obj `if test -f 'ooxml_schemas.cpp'; then $(CYGPATH_W) 'ooxml_schemas.cpp'; else $(CYGPATH_W) '$(srcdir)/ooxml_schemas.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-ooxml_schemas.Tpo $(DEPDIR)/xlsx_sheet_context_test-ooxml_schemas.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_schemas.cpp' object='xlsx_sheet_context_test-ooxml_schemas.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-ooxml_schemas.obj `if test -f 'ooxml_schemas.cpp'; then $(CYGPATH_W) 'ooxml_schemas.cpp'; else $(CYGPATH_W) '$(srcdir)/ooxml_schemas.cpp'; fi`
+
+xlsx_sheet_context_test-ooxml_tokens.o: ooxml_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-ooxml_tokens.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-ooxml_tokens.Tpo -c -o xlsx_sheet_context_test-ooxml_tokens.o `test -f 'ooxml_tokens.cpp' || echo '$(srcdir)/'`ooxml_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-ooxml_tokens.Tpo $(DEPDIR)/xlsx_sheet_context_test-ooxml_tokens.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_tokens.cpp' object='xlsx_sheet_context_test-ooxml_tokens.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-ooxml_tokens.o `test -f 'ooxml_tokens.cpp' || echo '$(srcdir)/'`ooxml_tokens.cpp
+
+xlsx_sheet_context_test-ooxml_tokens.obj: ooxml_tokens.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-ooxml_tokens.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-ooxml_tokens.Tpo -c -o xlsx_sheet_context_test-ooxml_tokens.obj `if test -f 'ooxml_tokens.cpp'; then $(CYGPATH_W) 'ooxml_tokens.cpp'; else $(CYGPATH_W) '$(srcdir)/ooxml_tokens.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-ooxml_tokens.Tpo $(DEPDIR)/xlsx_sheet_context_test-ooxml_tokens.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_tokens.cpp' object='xlsx_sheet_context_test-ooxml_tokens.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-ooxml_tokens.obj `if test -f 'ooxml_tokens.cpp'; then $(CYGPATH_W) 'ooxml_tokens.cpp'; else $(CYGPATH_W) '$(srcdir)/ooxml_tokens.cpp'; fi`
+
+xlsx_sheet_context_test-ooxml_types.o: ooxml_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-ooxml_types.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-ooxml_types.Tpo -c -o xlsx_sheet_context_test-ooxml_types.o `test -f 'ooxml_types.cpp' || echo '$(srcdir)/'`ooxml_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-ooxml_types.Tpo $(DEPDIR)/xlsx_sheet_context_test-ooxml_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_types.cpp' object='xlsx_sheet_context_test-ooxml_types.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-ooxml_types.o `test -f 'ooxml_types.cpp' || echo '$(srcdir)/'`ooxml_types.cpp
+
+xlsx_sheet_context_test-ooxml_types.obj: ooxml_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-ooxml_types.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-ooxml_types.Tpo -c -o xlsx_sheet_context_test-ooxml_types.obj `if test -f 'ooxml_types.cpp'; then $(CYGPATH_W) 'ooxml_types.cpp'; else $(CYGPATH_W) '$(srcdir)/ooxml_types.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-ooxml_types.Tpo $(DEPDIR)/xlsx_sheet_context_test-ooxml_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ooxml_types.cpp' object='xlsx_sheet_context_test-ooxml_types.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-ooxml_types.obj `if test -f 'ooxml_types.cpp'; then $(CYGPATH_W) 'ooxml_types.cpp'; else $(CYGPATH_W) '$(srcdir)/ooxml_types.cpp'; fi`
+
+xlsx_sheet_context_test-session_context.o: session_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-session_context.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-session_context.Tpo -c -o xlsx_sheet_context_test-session_context.o `test -f 'session_context.cpp' || echo '$(srcdir)/'`session_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-session_context.Tpo $(DEPDIR)/xlsx_sheet_context_test-session_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='session_context.cpp' object='xlsx_sheet_context_test-session_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-session_context.o `test -f 'session_context.cpp' || echo '$(srcdir)/'`session_context.cpp
+
+xlsx_sheet_context_test-session_context.obj: session_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-session_context.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-session_context.Tpo -c -o xlsx_sheet_context_test-session_context.obj `if test -f 'session_context.cpp'; then $(CYGPATH_W) 'session_context.cpp'; else $(CYGPATH_W) '$(srcdir)/session_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-session_context.Tpo $(DEPDIR)/xlsx_sheet_context_test-session_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='session_context.cpp' object='xlsx_sheet_context_test-session_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-session_context.obj `if test -f 'session_context.cpp'; then $(CYGPATH_W) 'session_context.cpp'; else $(CYGPATH_W) '$(srcdir)/session_context.cpp'; fi`
+
+xlsx_sheet_context_test-spreadsheet_interface.o: spreadsheet_interface.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-spreadsheet_interface.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-spreadsheet_interface.Tpo -c -o xlsx_sheet_context_test-spreadsheet_interface.o `test -f 'spreadsheet_interface.cpp' || echo '$(srcdir)/'`spreadsheet_interface.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-spreadsheet_interface.Tpo $(DEPDIR)/xlsx_sheet_context_test-spreadsheet_interface.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='spreadsheet_interface.cpp' object='xlsx_sheet_context_test-spreadsheet_interface.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-spreadsheet_interface.o `test -f 'spreadsheet_interface.cpp' || echo '$(srcdir)/'`spreadsheet_interface.cpp
+
+xlsx_sheet_context_test-spreadsheet_interface.obj: spreadsheet_interface.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-spreadsheet_interface.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-spreadsheet_interface.Tpo -c -o xlsx_sheet_context_test-spreadsheet_interface.obj `if test -f 'spreadsheet_interface.cpp'; then $(CYGPATH_W) 'spreadsheet_interface.cpp'; else $(CYGPATH_W) '$(srcdir)/spreadsheet_interface.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-spreadsheet_interface.Tpo $(DEPDIR)/xlsx_sheet_context_test-spreadsheet_interface.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='spreadsheet_interface.cpp' object='xlsx_sheet_context_test-spreadsheet_interface.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-spreadsheet_interface.obj `if test -f 'spreadsheet_interface.cpp'; then $(CYGPATH_W) 'spreadsheet_interface.cpp'; else $(CYGPATH_W) '$(srcdir)/spreadsheet_interface.cpp'; fi`
+
+xlsx_sheet_context_test-xlsx_autofilter_context.o: xlsx_autofilter_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_autofilter_context.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_autofilter_context.Tpo -c -o xlsx_sheet_context_test-xlsx_autofilter_context.o `test -f 'xlsx_autofilter_context.cpp' || echo '$(srcdir)/'`xlsx_autofilter_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_autofilter_context.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_autofilter_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_autofilter_context.cpp' object='xlsx_sheet_context_test-xlsx_autofilter_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_autofilter_context.o `test -f 'xlsx_autofilter_context.cpp' || echo '$(srcdir)/'`xlsx_autofilter_context.cpp
+
+xlsx_sheet_context_test-xlsx_autofilter_context.obj: xlsx_autofilter_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_autofilter_context.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_autofilter_context.Tpo -c -o xlsx_sheet_context_test-xlsx_autofilter_context.obj `if test -f 'xlsx_autofilter_context.cpp'; then $(CYGPATH_W) 'xlsx_autofilter_context.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_autofilter_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_autofilter_context.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_autofilter_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_autofilter_context.cpp' object='xlsx_sheet_context_test-xlsx_autofilter_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_autofilter_context.obj `if test -f 'xlsx_autofilter_context.cpp'; then $(CYGPATH_W) 'xlsx_autofilter_context.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_autofilter_context.cpp'; fi`
+
+xlsx_sheet_context_test-xlsx_conditional_format_context.o: xlsx_conditional_format_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_conditional_format_context.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_conditional_format_context.Tpo -c -o xlsx_sheet_context_test-xlsx_conditional_format_context.o `test -f 'xlsx_conditional_format_context.cpp' || echo '$(srcdir)/'`xlsx_conditional_format_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_conditional_format_context.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_conditional_format_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_conditional_format_context.cpp' object='xlsx_sheet_context_test-xlsx_conditional_format_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_conditional_format_context.o `test -f 'xlsx_conditional_format_context.cpp' || echo '$(srcdir)/'`xlsx_conditional_format_context.cpp
+
+xlsx_sheet_context_test-xlsx_conditional_format_context.obj: xlsx_conditional_format_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_conditional_format_context.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_conditional_format_context.Tpo -c -o xlsx_sheet_context_test-xlsx_conditional_format_context.obj `if test -f 'xlsx_conditional_format_context.cpp'; then $(CYGPATH_W) 'xlsx_conditional_format_context.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_conditional_format_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_conditional_format_context.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_conditional_format_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_conditional_format_context.cpp' object='xlsx_sheet_context_test-xlsx_conditional_format_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_conditional_format_context.obj `if test -f 'xlsx_conditional_format_context.cpp'; then $(CYGPATH_W) 'xlsx_conditional_format_context.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_conditional_format_context.cpp'; fi`
+
+xlsx_sheet_context_test-xlsx_helper.o: xlsx_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_helper.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_helper.Tpo -c -o xlsx_sheet_context_test-xlsx_helper.o `test -f 'xlsx_helper.cpp' || echo '$(srcdir)/'`xlsx_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_helper.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_helper.cpp' object='xlsx_sheet_context_test-xlsx_helper.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_helper.o `test -f 'xlsx_helper.cpp' || echo '$(srcdir)/'`xlsx_helper.cpp
+
+xlsx_sheet_context_test-xlsx_helper.obj: xlsx_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_helper.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_helper.Tpo -c -o xlsx_sheet_context_test-xlsx_helper.obj `if test -f 'xlsx_helper.cpp'; then $(CYGPATH_W) 'xlsx_helper.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_helper.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_helper.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_helper.cpp' object='xlsx_sheet_context_test-xlsx_helper.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_helper.obj `if test -f 'xlsx_helper.cpp'; then $(CYGPATH_W) 'xlsx_helper.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_helper.cpp'; fi`
+
+xlsx_sheet_context_test-xlsx_session_data.o: xlsx_session_data.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_session_data.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_session_data.Tpo -c -o xlsx_sheet_context_test-xlsx_session_data.o `test -f 'xlsx_session_data.cpp' || echo '$(srcdir)/'`xlsx_session_data.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_session_data.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_session_data.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_session_data.cpp' object='xlsx_sheet_context_test-xlsx_session_data.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_session_data.o `test -f 'xlsx_session_data.cpp' || echo '$(srcdir)/'`xlsx_session_data.cpp
+
+xlsx_sheet_context_test-xlsx_session_data.obj: xlsx_session_data.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_session_data.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_session_data.Tpo -c -o xlsx_sheet_context_test-xlsx_session_data.obj `if test -f 'xlsx_session_data.cpp'; then $(CYGPATH_W) 'xlsx_session_data.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_session_data.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_session_data.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_session_data.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_session_data.cpp' object='xlsx_sheet_context_test-xlsx_session_data.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_session_data.obj `if test -f 'xlsx_session_data.cpp'; then $(CYGPATH_W) 'xlsx_session_data.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_session_data.cpp'; fi`
+
+xlsx_sheet_context_test-xlsx_sheet_context.o: xlsx_sheet_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_sheet_context.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context.Tpo -c -o xlsx_sheet_context_test-xlsx_sheet_context.o `test -f 'xlsx_sheet_context.cpp' || echo '$(srcdir)/'`xlsx_sheet_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_sheet_context.cpp' object='xlsx_sheet_context_test-xlsx_sheet_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_sheet_context.o `test -f 'xlsx_sheet_context.cpp' || echo '$(srcdir)/'`xlsx_sheet_context.cpp
+
+xlsx_sheet_context_test-xlsx_sheet_context.obj: xlsx_sheet_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_sheet_context.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context.Tpo -c -o xlsx_sheet_context_test-xlsx_sheet_context.obj `if test -f 'xlsx_sheet_context.cpp'; then $(CYGPATH_W) 'xlsx_sheet_context.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_sheet_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_sheet_context.cpp' object='xlsx_sheet_context_test-xlsx_sheet_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_sheet_context.obj `if test -f 'xlsx_sheet_context.cpp'; then $(CYGPATH_W) 'xlsx_sheet_context.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_sheet_context.cpp'; fi`
+
+xlsx_sheet_context_test-xlsx_sheet_context_test.o: xlsx_sheet_context_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_sheet_context_test.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context_test.Tpo -c -o xlsx_sheet_context_test-xlsx_sheet_context_test.o `test -f 'xlsx_sheet_context_test.cpp' || echo '$(srcdir)/'`xlsx_sheet_context_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context_test.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_sheet_context_test.cpp' object='xlsx_sheet_context_test-xlsx_sheet_context_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_sheet_context_test.o `test -f 'xlsx_sheet_context_test.cpp' || echo '$(srcdir)/'`xlsx_sheet_context_test.cpp
+
+xlsx_sheet_context_test-xlsx_sheet_context_test.obj: xlsx_sheet_context_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_sheet_context_test.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context_test.Tpo -c -o xlsx_sheet_context_test-xlsx_sheet_context_test.obj `if test -f 'xlsx_sheet_context_test.cpp'; then $(CYGPATH_W) 'xlsx_sheet_context_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_sheet_context_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context_test.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_sheet_context_test.cpp' object='xlsx_sheet_context_test-xlsx_sheet_context_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_sheet_context_test.obj `if test -f 'xlsx_sheet_context_test.cpp'; then $(CYGPATH_W) 'xlsx_sheet_context_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_sheet_context_test.cpp'; fi`
+
+xlsx_sheet_context_test-xlsx_types.o: xlsx_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_types.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_types.Tpo -c -o xlsx_sheet_context_test-xlsx_types.o `test -f 'xlsx_types.cpp' || echo '$(srcdir)/'`xlsx_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_types.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_types.cpp' object='xlsx_sheet_context_test-xlsx_types.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_types.o `test -f 'xlsx_types.cpp' || echo '$(srcdir)/'`xlsx_types.cpp
+
+xlsx_sheet_context_test-xlsx_types.obj: xlsx_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xlsx_types.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xlsx_types.Tpo -c -o xlsx_sheet_context_test-xlsx_types.obj `if test -f 'xlsx_types.cpp'; then $(CYGPATH_W) 'xlsx_types.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_types.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xlsx_types.Tpo $(DEPDIR)/xlsx_sheet_context_test-xlsx_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xlsx_types.cpp' object='xlsx_sheet_context_test-xlsx_types.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xlsx_types.obj `if test -f 'xlsx_types.cpp'; then $(CYGPATH_W) 'xlsx_types.cpp'; else $(CYGPATH_W) '$(srcdir)/xlsx_types.cpp'; fi`
+
+xlsx_sheet_context_test-xml_context_base.o: xml_context_base.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_context_base.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_context_base.Tpo -c -o xlsx_sheet_context_test-xml_context_base.o `test -f 'xml_context_base.cpp' || echo '$(srcdir)/'`xml_context_base.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_context_base.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_context_base.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_context_base.cpp' object='xlsx_sheet_context_test-xml_context_base.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_context_base.o `test -f 'xml_context_base.cpp' || echo '$(srcdir)/'`xml_context_base.cpp
+
+xlsx_sheet_context_test-xml_context_base.obj: xml_context_base.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_context_base.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_context_base.Tpo -c -o xlsx_sheet_context_test-xml_context_base.obj `if test -f 'xml_context_base.cpp'; then $(CYGPATH_W) 'xml_context_base.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_context_base.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_context_base.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_context_base.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_context_base.cpp' object='xlsx_sheet_context_test-xml_context_base.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_context_base.obj `if test -f 'xml_context_base.cpp'; then $(CYGPATH_W) 'xml_context_base.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_context_base.cpp'; fi`
+
+xlsx_sheet_context_test-xml_context_global.o: xml_context_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_context_global.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_context_global.Tpo -c -o xlsx_sheet_context_test-xml_context_global.o `test -f 'xml_context_global.cpp' || echo '$(srcdir)/'`xml_context_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_context_global.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_context_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_context_global.cpp' object='xlsx_sheet_context_test-xml_context_global.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_context_global.o `test -f 'xml_context_global.cpp' || echo '$(srcdir)/'`xml_context_global.cpp
+
+xlsx_sheet_context_test-xml_context_global.obj: xml_context_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_context_global.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_context_global.Tpo -c -o xlsx_sheet_context_test-xml_context_global.obj `if test -f 'xml_context_global.cpp'; then $(CYGPATH_W) 'xml_context_global.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_context_global.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_context_global.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_context_global.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_context_global.cpp' object='xlsx_sheet_context_test-xml_context_global.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_context_global.obj `if test -f 'xml_context_global.cpp'; then $(CYGPATH_W) 'xml_context_global.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_context_global.cpp'; fi`
+
+xlsx_sheet_context_test-xml_element_types.o: xml_element_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_element_types.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_element_types.Tpo -c -o xlsx_sheet_context_test-xml_element_types.o `test -f 'xml_element_types.cpp' || echo '$(srcdir)/'`xml_element_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_element_types.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_element_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_element_types.cpp' object='xlsx_sheet_context_test-xml_element_types.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_element_types.o `test -f 'xml_element_types.cpp' || echo '$(srcdir)/'`xml_element_types.cpp
+
+xlsx_sheet_context_test-xml_element_types.obj: xml_element_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_element_types.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_element_types.Tpo -c -o xlsx_sheet_context_test-xml_element_types.obj `if test -f 'xml_element_types.cpp'; then $(CYGPATH_W) 'xml_element_types.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_element_types.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_element_types.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_element_types.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_element_types.cpp' object='xlsx_sheet_context_test-xml_element_types.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_element_types.obj `if test -f 'xml_element_types.cpp'; then $(CYGPATH_W) 'xml_element_types.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_element_types.cpp'; fi`
+
+xlsx_sheet_context_test-xml_element_validator.o: xml_element_validator.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_element_validator.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_element_validator.Tpo -c -o xlsx_sheet_context_test-xml_element_validator.o `test -f 'xml_element_validator.cpp' || echo '$(srcdir)/'`xml_element_validator.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_element_validator.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_element_validator.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_element_validator.cpp' object='xlsx_sheet_context_test-xml_element_validator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_element_validator.o `test -f 'xml_element_validator.cpp' || echo '$(srcdir)/'`xml_element_validator.cpp
+
+xlsx_sheet_context_test-xml_element_validator.obj: xml_element_validator.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_element_validator.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_element_validator.Tpo -c -o xlsx_sheet_context_test-xml_element_validator.obj `if test -f 'xml_element_validator.cpp'; then $(CYGPATH_W) 'xml_element_validator.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_element_validator.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_element_validator.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_element_validator.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_element_validator.cpp' object='xlsx_sheet_context_test-xml_element_validator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_element_validator.obj `if test -f 'xml_element_validator.cpp'; then $(CYGPATH_W) 'xml_element_validator.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_element_validator.cpp'; fi`
+
+xlsx_sheet_context_test-xml_empty_context.o: xml_empty_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_empty_context.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_empty_context.Tpo -c -o xlsx_sheet_context_test-xml_empty_context.o `test -f 'xml_empty_context.cpp' || echo '$(srcdir)/'`xml_empty_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_empty_context.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_empty_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_empty_context.cpp' object='xlsx_sheet_context_test-xml_empty_context.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_empty_context.o `test -f 'xml_empty_context.cpp' || echo '$(srcdir)/'`xml_empty_context.cpp
+
+xlsx_sheet_context_test-xml_empty_context.obj: xml_empty_context.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_empty_context.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_empty_context.Tpo -c -o xlsx_sheet_context_test-xml_empty_context.obj `if test -f 'xml_empty_context.cpp'; then $(CYGPATH_W) 'xml_empty_context.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_empty_context.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_empty_context.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_empty_context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_empty_context.cpp' object='xlsx_sheet_context_test-xml_empty_context.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_empty_context.obj `if test -f 'xml_empty_context.cpp'; then $(CYGPATH_W) 'xml_empty_context.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_empty_context.cpp'; fi`
+
+xlsx_sheet_context_test-xml_util.o: xml_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_util.o -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_util.Tpo -c -o xlsx_sheet_context_test-xml_util.o `test -f 'xml_util.cpp' || echo '$(srcdir)/'`xml_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_util.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_util.cpp' object='xlsx_sheet_context_test-xml_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_util.o `test -f 'xml_util.cpp' || echo '$(srcdir)/'`xml_util.cpp
+
+xlsx_sheet_context_test-xml_util.obj: xml_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xlsx_sheet_context_test-xml_util.obj -MD -MP -MF $(DEPDIR)/xlsx_sheet_context_test-xml_util.Tpo -c -o xlsx_sheet_context_test-xml_util.obj `if test -f 'xml_util.cpp'; then $(CYGPATH_W) 'xml_util.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_util.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xlsx_sheet_context_test-xml_util.Tpo $(DEPDIR)/xlsx_sheet_context_test-xml_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_util.cpp' object='xlsx_sheet_context_test-xml_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xlsx_sheet_context_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xlsx_sheet_context_test-xml_util.obj `if test -f 'xml_util.cpp'; then $(CYGPATH_W) 'xml_util.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_util.cpp'; fi`
+
+xml_structure_tree_test-string_helper.o: string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_structure_tree_test-string_helper.o -MD -MP -MF $(DEPDIR)/xml_structure_tree_test-string_helper.Tpo -c -o xml_structure_tree_test-string_helper.o `test -f 'string_helper.cpp' || echo '$(srcdir)/'`string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_structure_tree_test-string_helper.Tpo $(DEPDIR)/xml_structure_tree_test-string_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_helper.cpp' object='xml_structure_tree_test-string_helper.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_structure_tree_test-string_helper.o `test -f 'string_helper.cpp' || echo '$(srcdir)/'`string_helper.cpp
+
+xml_structure_tree_test-string_helper.obj: string_helper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_structure_tree_test-string_helper.obj -MD -MP -MF $(DEPDIR)/xml_structure_tree_test-string_helper.Tpo -c -o xml_structure_tree_test-string_helper.obj `if test -f 'string_helper.cpp'; then $(CYGPATH_W) 'string_helper.cpp'; else $(CYGPATH_W) '$(srcdir)/string_helper.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_structure_tree_test-string_helper.Tpo $(DEPDIR)/xml_structure_tree_test-string_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_helper.cpp' object='xml_structure_tree_test-string_helper.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_structure_tree_test-string_helper.obj `if test -f 'string_helper.cpp'; then $(CYGPATH_W) 'string_helper.cpp'; else $(CYGPATH_W) '$(srcdir)/string_helper.cpp'; fi`
+
+xml_structure_tree_test-xml_structure_tree.o: xml_structure_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_structure_tree_test-xml_structure_tree.o -MD -MP -MF $(DEPDIR)/xml_structure_tree_test-xml_structure_tree.Tpo -c -o xml_structure_tree_test-xml_structure_tree.o `test -f 'xml_structure_tree.cpp' || echo '$(srcdir)/'`xml_structure_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_structure_tree_test-xml_structure_tree.Tpo $(DEPDIR)/xml_structure_tree_test-xml_structure_tree.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_structure_tree.cpp' object='xml_structure_tree_test-xml_structure_tree.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_structure_tree_test-xml_structure_tree.o `test -f 'xml_structure_tree.cpp' || echo '$(srcdir)/'`xml_structure_tree.cpp
+
+xml_structure_tree_test-xml_structure_tree.obj: xml_structure_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_structure_tree_test-xml_structure_tree.obj -MD -MP -MF $(DEPDIR)/xml_structure_tree_test-xml_structure_tree.Tpo -c -o xml_structure_tree_test-xml_structure_tree.obj `if test -f 'xml_structure_tree.cpp'; then $(CYGPATH_W) 'xml_structure_tree.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_structure_tree.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_structure_tree_test-xml_structure_tree.Tpo $(DEPDIR)/xml_structure_tree_test-xml_structure_tree.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_structure_tree.cpp' object='xml_structure_tree_test-xml_structure_tree.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_structure_tree_test-xml_structure_tree.obj `if test -f 'xml_structure_tree.cpp'; then $(CYGPATH_W) 'xml_structure_tree.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_structure_tree.cpp'; fi`
+
+xml_structure_tree_test-xml_structure_mapper.o: xml_structure_mapper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_structure_tree_test-xml_structure_mapper.o -MD -MP -MF $(DEPDIR)/xml_structure_tree_test-xml_structure_mapper.Tpo -c -o xml_structure_tree_test-xml_structure_mapper.o `test -f 'xml_structure_mapper.cpp' || echo '$(srcdir)/'`xml_structure_mapper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_structure_tree_test-xml_structure_mapper.Tpo $(DEPDIR)/xml_structure_tree_test-xml_structure_mapper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_structure_mapper.cpp' object='xml_structure_tree_test-xml_structure_mapper.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_structure_tree_test-xml_structure_mapper.o `test -f 'xml_structure_mapper.cpp' || echo '$(srcdir)/'`xml_structure_mapper.cpp
+
+xml_structure_tree_test-xml_structure_mapper.obj: xml_structure_mapper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_structure_tree_test-xml_structure_mapper.obj -MD -MP -MF $(DEPDIR)/xml_structure_tree_test-xml_structure_mapper.Tpo -c -o xml_structure_tree_test-xml_structure_mapper.obj `if test -f 'xml_structure_mapper.cpp'; then $(CYGPATH_W) 'xml_structure_mapper.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_structure_mapper.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_structure_tree_test-xml_structure_mapper.Tpo $(DEPDIR)/xml_structure_tree_test-xml_structure_mapper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_structure_mapper.cpp' object='xml_structure_tree_test-xml_structure_mapper.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_structure_tree_test-xml_structure_mapper.obj `if test -f 'xml_structure_mapper.cpp'; then $(CYGPATH_W) 'xml_structure_mapper.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_structure_mapper.cpp'; fi`
+
+xml_structure_tree_test-xml_structure_tree_test.o: xml_structure_tree_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_structure_tree_test-xml_structure_tree_test.o -MD -MP -MF $(DEPDIR)/xml_structure_tree_test-xml_structure_tree_test.Tpo -c -o xml_structure_tree_test-xml_structure_tree_test.o `test -f 'xml_structure_tree_test.cpp' || echo '$(srcdir)/'`xml_structure_tree_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_structure_tree_test-xml_structure_tree_test.Tpo $(DEPDIR)/xml_structure_tree_test-xml_structure_tree_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_structure_tree_test.cpp' object='xml_structure_tree_test-xml_structure_tree_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_structure_tree_test-xml_structure_tree_test.o `test -f 'xml_structure_tree_test.cpp' || echo '$(srcdir)/'`xml_structure_tree_test.cpp
+
+xml_structure_tree_test-xml_structure_tree_test.obj: xml_structure_tree_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_structure_tree_test-xml_structure_tree_test.obj -MD -MP -MF $(DEPDIR)/xml_structure_tree_test-xml_structure_tree_test.Tpo -c -o xml_structure_tree_test-xml_structure_tree_test.obj `if test -f 'xml_structure_tree_test.cpp'; then $(CYGPATH_W) 'xml_structure_tree_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_structure_tree_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_structure_tree_test-xml_structure_tree_test.Tpo $(DEPDIR)/xml_structure_tree_test-xml_structure_tree_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_structure_tree_test.cpp' object='xml_structure_tree_test-xml_structure_tree_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_structure_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_structure_tree_test-xml_structure_tree_test.obj `if test -f 'xml_structure_tree_test.cpp'; then $(CYGPATH_W) 'xml_structure_tree_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_structure_tree_test.cpp'; fi`
+
+yaml_document_tree_test-yaml_document_tree.o: yaml_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT yaml_document_tree_test-yaml_document_tree.o -MD -MP -MF $(DEPDIR)/yaml_document_tree_test-yaml_document_tree.Tpo -c -o yaml_document_tree_test-yaml_document_tree.o `test -f 'yaml_document_tree.cpp' || echo '$(srcdir)/'`yaml_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/yaml_document_tree_test-yaml_document_tree.Tpo $(DEPDIR)/yaml_document_tree_test-yaml_document_tree.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='yaml_document_tree.cpp' object='yaml_document_tree_test-yaml_document_tree.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o yaml_document_tree_test-yaml_document_tree.o `test -f 'yaml_document_tree.cpp' || echo '$(srcdir)/'`yaml_document_tree.cpp
+
+yaml_document_tree_test-yaml_document_tree.obj: yaml_document_tree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT yaml_document_tree_test-yaml_document_tree.obj -MD -MP -MF $(DEPDIR)/yaml_document_tree_test-yaml_document_tree.Tpo -c -o yaml_document_tree_test-yaml_document_tree.obj `if test -f 'yaml_document_tree.cpp'; then $(CYGPATH_W) 'yaml_document_tree.cpp'; else $(CYGPATH_W) '$(srcdir)/yaml_document_tree.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/yaml_document_tree_test-yaml_document_tree.Tpo $(DEPDIR)/yaml_document_tree_test-yaml_document_tree.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='yaml_document_tree.cpp' object='yaml_document_tree_test-yaml_document_tree.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o yaml_document_tree_test-yaml_document_tree.obj `if test -f 'yaml_document_tree.cpp'; then $(CYGPATH_W) 'yaml_document_tree.cpp'; else $(CYGPATH_W) '$(srcdir)/yaml_document_tree.cpp'; fi`
+
+yaml_document_tree_test-json_util.o: json_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT yaml_document_tree_test-json_util.o -MD -MP -MF $(DEPDIR)/yaml_document_tree_test-json_util.Tpo -c -o yaml_document_tree_test-json_util.o `test -f 'json_util.cpp' || echo '$(srcdir)/'`json_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/yaml_document_tree_test-json_util.Tpo $(DEPDIR)/yaml_document_tree_test-json_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_util.cpp' object='yaml_document_tree_test-json_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o yaml_document_tree_test-json_util.o `test -f 'json_util.cpp' || echo '$(srcdir)/'`json_util.cpp
+
+yaml_document_tree_test-json_util.obj: json_util.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT yaml_document_tree_test-json_util.obj -MD -MP -MF $(DEPDIR)/yaml_document_tree_test-json_util.Tpo -c -o yaml_document_tree_test-json_util.obj `if test -f 'json_util.cpp'; then $(CYGPATH_W) 'json_util.cpp'; else $(CYGPATH_W) '$(srcdir)/json_util.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/yaml_document_tree_test-json_util.Tpo $(DEPDIR)/yaml_document_tree_test-json_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_util.cpp' object='yaml_document_tree_test-json_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o yaml_document_tree_test-json_util.obj `if test -f 'json_util.cpp'; then $(CYGPATH_W) 'json_util.cpp'; else $(CYGPATH_W) '$(srcdir)/json_util.cpp'; fi`
+
+yaml_document_tree_test-yaml_document_tree_test.o: yaml_document_tree_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT yaml_document_tree_test-yaml_document_tree_test.o -MD -MP -MF $(DEPDIR)/yaml_document_tree_test-yaml_document_tree_test.Tpo -c -o yaml_document_tree_test-yaml_document_tree_test.o `test -f 'yaml_document_tree_test.cpp' || echo '$(srcdir)/'`yaml_document_tree_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/yaml_document_tree_test-yaml_document_tree_test.Tpo $(DEPDIR)/yaml_document_tree_test-yaml_document_tree_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='yaml_document_tree_test.cpp' object='yaml_document_tree_test-yaml_document_tree_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o yaml_document_tree_test-yaml_document_tree_test.o `test -f 'yaml_document_tree_test.cpp' || echo '$(srcdir)/'`yaml_document_tree_test.cpp
+
+yaml_document_tree_test-yaml_document_tree_test.obj: yaml_document_tree_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT yaml_document_tree_test-yaml_document_tree_test.obj -MD -MP -MF $(DEPDIR)/yaml_document_tree_test-yaml_document_tree_test.Tpo -c -o yaml_document_tree_test-yaml_document_tree_test.obj `if test -f 'yaml_document_tree_test.cpp'; then $(CYGPATH_W) 'yaml_document_tree_test.cpp'; else $(CYGPATH_W) '$(srcdir)/yaml_document_tree_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/yaml_document_tree_test-yaml_document_tree_test.Tpo $(DEPDIR)/yaml_document_tree_test-yaml_document_tree_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='yaml_document_tree_test.cpp' object='yaml_document_tree_test-yaml_document_tree_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_document_tree_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o yaml_document_tree_test-yaml_document_tree_test.obj `if test -f 'yaml_document_tree_test.cpp'; then $(CYGPATH_W) 'yaml_document_tree_test.cpp'; else $(CYGPATH_W) '$(srcdir)/yaml_document_tree_test.cpp'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+xlsx-sheet-context-test.log: xlsx-sheet-context-test$(EXEEXT)
+ @p='xlsx-sheet-context-test$(EXEEXT)'; \
+ b='xlsx-sheet-context-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+odf-helper-test.log: odf-helper-test$(EXEEXT)
+ @p='odf-helper-test$(EXEEXT)'; \
+ b='odf-helper-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+gnumeric-cell-context-test.log: gnumeric-cell-context-test$(EXEEXT)
+ @p='gnumeric-cell-context-test$(EXEEXT)'; \
+ b='gnumeric-cell-context-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+gnumeric-sheet-context-test.log: gnumeric-sheet-context-test$(EXEEXT)
+ @p='gnumeric-sheet-context-test$(EXEEXT)'; \
+ b='gnumeric-sheet-context-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+css-document-tree-test.log: css-document-tree-test$(EXEEXT)
+ @p='css-document-tree-test$(EXEEXT)'; \
+ b='css-document-tree-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+json-document-tree-test.log: json-document-tree-test$(EXEEXT)
+ @p='json-document-tree-test$(EXEEXT)'; \
+ b='json-document-tree-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+yaml-document-tree-test.log: yaml-document-tree-test$(EXEEXT)
+ @p='yaml-document-tree-test$(EXEEXT)'; \
+ b='yaml-document-tree-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+xml-map-tree-test.log: xml-map-tree-test$(EXEEXT)
+ @p='xml-map-tree-test$(EXEEXT)'; \
+ b='xml-map-tree-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+common-test.log: common-test$(EXEEXT)
+ @p='common-test$(EXEEXT)'; \
+ b='common-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+dom-tree-test.log: dom-tree-test$(EXEEXT)
+ @p='dom-tree-test$(EXEEXT)'; \
+ b='dom-tree-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+json-structure-tree-test.log: json-structure-tree-test$(EXEEXT)
+ @p='json-structure-tree-test$(EXEEXT)'; \
+ b='json-structure-tree-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+json-map-tree-test.log: json-map-tree-test$(EXEEXT)
+ @p='json-map-tree-test$(EXEEXT)'; \
+ b='json-map-tree-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+xml-structure-tree-test.log: xml-structure-tree-test$(EXEEXT)
+ @p='xml-structure-tree-test$(EXEEXT)'; \
+ b='xml-structure-tree-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+xpath-parser-test.log: xpath-parser-test$(EXEEXT)
+ @p='xpath-parser-test$(EXEEXT)'; \
+ b='xpath-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+install-EXTRAPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-am
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-am
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-am
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-am
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-am
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/common_test.Po
+ -rm -f ./$(DEPDIR)/css_document_tree.Po
+ -rm -f ./$(DEPDIR)/css_document_tree_test.Po
+ -rm -f ./$(DEPDIR)/dom_tree_test.Po
+ -rm -f ./$(DEPDIR)/gnumeric_cell_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_cell_context_test.Po
+ -rm -f ./$(DEPDIR)/gnumeric_namespace_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_cell_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_filter_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_names_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_namespace_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context_test.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_styles_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_tokens.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_value_format_parser.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-number_utils.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-odf_namespace_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-session_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-spreadsheet_interface.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-string_helper.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-xml_context_base.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-xml_element_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-xml_element_validator.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-xml_empty_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-xml_util.Po
+ -rm -f ./$(DEPDIR)/gnumeric_tokens.Po
+ -rm -f ./$(DEPDIR)/gnumeric_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_value_format_parser.Po
+ -rm -f ./$(DEPDIR)/json_document_tree_test-json_document_tree.Po
+ -rm -f ./$(DEPDIR)/json_document_tree_test-json_document_tree_test.Po
+ -rm -f ./$(DEPDIR)/json_document_tree_test-json_util.Po
+ -rm -f ./$(DEPDIR)/json_map_tree.Po
+ -rm -f ./$(DEPDIR)/json_map_tree_test.Po
+ -rm -f ./$(DEPDIR)/json_structure_tree_test.Po
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-config.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_document_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_selector.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-detection_result.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-dom_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-format_detection.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-formula_result.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-info.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-interface.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_document_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_map_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_util.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-measurement.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-number_utils.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_helper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_para_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_style_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_tokens.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_session_data.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_reader.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_csv.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_json.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_ods.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-session_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-string_helper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_base.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_util.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xpath_parser.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.Plo
+ -rm -f ./$(DEPDIR)/number_utils.Po
+ -rm -f ./$(DEPDIR)/odf_helper_test-odf_helper.Po
+ -rm -f ./$(DEPDIR)/odf_helper_test-odf_helper_test.Po
+ -rm -f ./$(DEPDIR)/odf_helper_test-string_helper.Po
+ -rm -f ./$(DEPDIR)/odf_namespace_types.Po
+ -rm -f ./$(DEPDIR)/session_context.Po
+ -rm -f ./$(DEPDIR)/spreadsheet_impl_types.Po
+ -rm -f ./$(DEPDIR)/spreadsheet_interface.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-formula_result.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_global.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_namespace_types.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_schemas.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_tokens.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_types.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-session_context.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-spreadsheet_interface.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_autofilter_context.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_conditional_format_context.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_helper.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_session_data.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context_test.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_types.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_context_base.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_context_global.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_element_types.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_element_validator.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_empty_context.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_util.Po
+ -rm -f ./$(DEPDIR)/xml_context_base.Po
+ -rm -f ./$(DEPDIR)/xml_element_types.Po
+ -rm -f ./$(DEPDIR)/xml_element_validator.Po
+ -rm -f ./$(DEPDIR)/xml_empty_context.Po
+ -rm -f ./$(DEPDIR)/xml_map_tree.Po
+ -rm -f ./$(DEPDIR)/xml_map_tree_test.Po
+ -rm -f ./$(DEPDIR)/xml_structure_tree_test-string_helper.Po
+ -rm -f ./$(DEPDIR)/xml_structure_tree_test-xml_structure_mapper.Po
+ -rm -f ./$(DEPDIR)/xml_structure_tree_test-xml_structure_tree.Po
+ -rm -f ./$(DEPDIR)/xml_structure_tree_test-xml_structure_tree_test.Po
+ -rm -f ./$(DEPDIR)/xml_util.Po
+ -rm -f ./$(DEPDIR)/xpath_parser.Po
+ -rm -f ./$(DEPDIR)/xpath_parser_test.Po
+ -rm -f ./$(DEPDIR)/yaml_document_tree_test-json_util.Po
+ -rm -f ./$(DEPDIR)/yaml_document_tree_test-yaml_document_tree.Po
+ -rm -f ./$(DEPDIR)/yaml_document_tree_test-yaml_document_tree_test.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-local distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/common_test.Po
+ -rm -f ./$(DEPDIR)/css_document_tree.Po
+ -rm -f ./$(DEPDIR)/css_document_tree_test.Po
+ -rm -f ./$(DEPDIR)/dom_tree_test.Po
+ -rm -f ./$(DEPDIR)/gnumeric_cell_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_cell_context_test.Po
+ -rm -f ./$(DEPDIR)/gnumeric_namespace_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_cell_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_filter_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_names_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_namespace_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_sheet_context_test.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_styles_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_tokens.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-gnumeric_value_format_parser.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-number_utils.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-odf_namespace_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-session_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-spreadsheet_interface.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-string_helper.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-xml_context_base.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-xml_element_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-xml_element_validator.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-xml_empty_context.Po
+ -rm -f ./$(DEPDIR)/gnumeric_sheet_context_test-xml_util.Po
+ -rm -f ./$(DEPDIR)/gnumeric_tokens.Po
+ -rm -f ./$(DEPDIR)/gnumeric_types.Po
+ -rm -f ./$(DEPDIR)/gnumeric_value_format_parser.Po
+ -rm -f ./$(DEPDIR)/json_document_tree_test-json_document_tree.Po
+ -rm -f ./$(DEPDIR)/json_document_tree_test-json_document_tree_test.Po
+ -rm -f ./$(DEPDIR)/json_document_tree_test-json_util.Po
+ -rm -f ./$(DEPDIR)/json_map_tree.Po
+ -rm -f ./$(DEPDIR)/json_map_tree_test.Po
+ -rm -f ./$(DEPDIR)/json_structure_tree_test.Po
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-config.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_document_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-css_selector.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-detection_result.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-dom_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-format_detection.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-formula_result.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_cell_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_detection_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_filter_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_names_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_namespace_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_sheet_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_styles_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_tokens.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-gnumeric_value_format_parser.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-info.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-interface.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_document_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_map_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_mapper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_structure_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-json_util.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-measurement.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-number_utils.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_document_styles_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_helper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_namespace_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_number_format_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_para_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_style_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_styles_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-odf_tokens.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_content_xml_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_dde_links_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ods_session_data.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_content_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_namespace_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_schemas.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_tokens.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-ooxml_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-opc_reader.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_csv.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_gnumeric.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_ods.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_import_xlsx.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_json.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_ods.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_parquet.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xls_xml.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xlsx.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_impl.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-orcus_xml_map_def.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-session_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_iface_util.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_impl_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_interface.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-spreadsheet_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-string_helper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_detection_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_namespace_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xls_xml_tokens.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_autofilter_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_conditional_format_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_drawing_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_helper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_pivot_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_revision_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_session_data.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_shared_strings_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_sheet_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_styles_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_table_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xlsx_workbook_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_base.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_context_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_element_validator.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_empty_context.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_map_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_simple_stream_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_handler.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_stream_parser.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_mapper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_structure_tree.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xml_util.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-xpath_parser.Plo
+ -rm -f ./$(DEPDIR)/liborcus_@ORCUS_API_VERSION@_la-yaml_document_tree.Plo
+ -rm -f ./$(DEPDIR)/number_utils.Po
+ -rm -f ./$(DEPDIR)/odf_helper_test-odf_helper.Po
+ -rm -f ./$(DEPDIR)/odf_helper_test-odf_helper_test.Po
+ -rm -f ./$(DEPDIR)/odf_helper_test-string_helper.Po
+ -rm -f ./$(DEPDIR)/odf_namespace_types.Po
+ -rm -f ./$(DEPDIR)/session_context.Po
+ -rm -f ./$(DEPDIR)/spreadsheet_impl_types.Po
+ -rm -f ./$(DEPDIR)/spreadsheet_interface.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-formula_result.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_global.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_namespace_types.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_schemas.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_tokens.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-ooxml_types.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-session_context.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-spreadsheet_interface.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_autofilter_context.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_conditional_format_context.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_helper.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_session_data.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_sheet_context_test.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xlsx_types.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_context_base.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_context_global.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_element_types.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_element_validator.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_empty_context.Po
+ -rm -f ./$(DEPDIR)/xlsx_sheet_context_test-xml_util.Po
+ -rm -f ./$(DEPDIR)/xml_context_base.Po
+ -rm -f ./$(DEPDIR)/xml_element_types.Po
+ -rm -f ./$(DEPDIR)/xml_element_validator.Po
+ -rm -f ./$(DEPDIR)/xml_empty_context.Po
+ -rm -f ./$(DEPDIR)/xml_map_tree.Po
+ -rm -f ./$(DEPDIR)/xml_map_tree_test.Po
+ -rm -f ./$(DEPDIR)/xml_structure_tree_test-string_helper.Po
+ -rm -f ./$(DEPDIR)/xml_structure_tree_test-xml_structure_mapper.Po
+ -rm -f ./$(DEPDIR)/xml_structure_tree_test-xml_structure_tree.Po
+ -rm -f ./$(DEPDIR)/xml_structure_tree_test-xml_structure_tree_test.Po
+ -rm -f ./$(DEPDIR)/xml_util.Po
+ -rm -f ./$(DEPDIR)/xpath_parser.Po
+ -rm -f ./$(DEPDIR)/xpath_parser_test.Po
+ -rm -f ./$(DEPDIR)/yaml_document_tree_test-json_util.Po
+ -rm -f ./$(DEPDIR)/yaml_document_tree_test-yaml_document_tree.Po
+ -rm -f ./$(DEPDIR)/yaml_document_tree_test-yaml_document_tree_test.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am check-valgrind-am check-valgrind-drd-am \
+ check-valgrind-drd-local check-valgrind-helgrind-am \
+ check-valgrind-helgrind-local check-valgrind-local \
+ check-valgrind-memcheck-am check-valgrind-memcheck-local \
+ check-valgrind-sgcheck-am check-valgrind-sgcheck-local clean \
+ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-local distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-libLTLIBRARIES \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \
+ uninstall uninstall-am uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+distclean-local:
+ rm -rf $(TESTS)
+
+@VALGRIND_CHECK_RULES@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/liborcus/common_test.cpp b/src/liborcus/common_test.cpp
new file mode 100644
index 0000000..8e4f4c7
--- /dev/null
+++ b/src/liborcus/common_test.cpp
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/measurement.hpp>
+#include <orcus/spreadsheet/types.hpp>
+
+#include <cstdlib>
+#include <cassert>
+#include <iostream>
+#include <sstream>
+#include <cmath>
+
+using namespace std;
+using namespace orcus;
+
+void test_date_time_conversion()
+{
+ struct {
+ const char* str;
+ int year;
+ int month;
+ int day;
+ int hour;
+ int minute;
+ double second;
+ } tests[] = {
+ { "2011-02-12", 2011, 2, 12, 0, 0, 0.0 },
+ { "1934-12-23T21:34:56.69", 1934, 12, 23, 21, 34, 56.69 },
+ };
+
+ for (size_t i = 0, n = sizeof(tests)/sizeof(tests[0]); i < n; ++i)
+ {
+ std::string_view str(tests[i].str);
+ date_time_t ret = date_time_t::from_chars(str);
+ cout << "original: " << str << endl;
+ cout << "converted: year=" << ret.year << ", month=" << ret.month << ", day="
+ << ret.day << ", hour=" << ret.hour << ", minute=" << ret.minute << ", second=" << ret.second << endl;
+ assert(ret.year == tests[i].year);
+ assert(ret.month == tests[i].month);
+ assert(ret.day == tests[i].day);
+ assert(ret.hour == tests[i].hour);
+ assert(ret.minute == tests[i].minute);
+ assert(ret.second == tests[i].second);
+ }
+}
+
+string to_string(length_unit_t unit)
+{
+ switch (unit)
+ {
+ case length_unit_t::centimeter:
+ return "centimeter";
+ case length_unit_t::inch:
+ return "inch";
+ case length_unit_t::point:
+ return "point";
+ case length_unit_t::twip:
+ return "twip";
+ case length_unit_t::unknown:
+ default:
+ ;
+ }
+ return "unknown";
+}
+
+void test_measurement_conversion()
+{
+ struct {
+ const char* str;
+ double expected;
+ size_t decimals;
+ length_unit_t unit;
+ } tests[] = {
+ { "12.34", 12.34, 2, length_unit_t::unknown },
+ { "35", 35, 0, length_unit_t::unknown },
+ { "0.69825", 0.69825, 5, length_unit_t::unknown },
+ { ".1592", 0.1592, 4, length_unit_t::unknown },
+ { "5", 5.0, 0, length_unit_t::unknown },
+ { "-3", -3.0, 0, length_unit_t::unknown },
+ { "-3.456", -3.456, 3, length_unit_t::unknown },
+ { "-.987", -0.987, 3, length_unit_t::unknown },
+ { "-100.987.", -100.987, 3, length_unit_t::unknown }, // Second decimal point should stop the parsing.
+
+ { "12.345in", 12.345, 3, length_unit_t::inch },
+ { "120.30001cm", 120.30001, 5, length_unit_t::centimeter },
+ { "3.12mm", 3.12, 2, length_unit_t::millimeter },
+ { "32.681pt", 32.681, 2, length_unit_t::point },
+ { "0.1234px", 0.1234, 4, length_unit_t::pixel },
+ };
+
+ for (size_t i = 0, n = sizeof(tests)/sizeof(tests[0]); i < n; ++i)
+ {
+ length_t ret = to_length(tests[i].str);
+ cout << "original: '" << tests[i].str << "', converted: " << ret.value
+ << " (" << to_string(ret.unit) << "), expected: "
+ << tests[i].expected << " (" << to_string(tests[i].unit) << ")" << endl;
+
+ // Check for double-precision equality without the rounding error.
+ double factor = 1.0;
+ for (size_t j = 0; j < tests[i].decimals; ++j)
+ factor *= 10.0;
+
+ double converted = round(ret.value * factor);
+ double expected = round(tests[i].expected * factor);
+ assert(converted == expected);
+
+ assert(ret.unit == tests[i].unit);
+ }
+}
+
+void test_measurement_conversion_2()
+{
+ struct check
+ {
+ length_unit_t from;
+ length_unit_t to;
+ double original;
+ double expected;
+ };
+
+ std::vector<check> checks =
+ {
+ { length_unit_t::millimeter, length_unit_t::twip, 254.0, 14400.0 },
+ };
+
+ for (const check& c : checks)
+ {
+ // without volatile, sometimes the following assert evaluates to false on 32-bit debian platforms.
+ volatile double observed = convert(c.original, c.from, c.to);
+ assert(observed == c.expected);
+ }
+}
+
+void test_string2number_conversion()
+{
+ struct {
+ const char* str;
+ double expected;
+ size_t decimals;
+ size_t end_pos;
+ } tests[] = {
+ { "1.2", 1.2, 1, 3 },
+ { "1.2a", 1.2, 1, 3 },
+ { "1.2.", 1.2, 1, 3 },
+ { "1.3456", 1.3456, 4, 6 },
+ { "-10.345", -10.345, 3, 7 },
+ { "-10.345-", -10.345, 3, 7 },
+ { "1.2E-2", 1.2E-2, 3, 6 },
+ { "1.26E+3", 1.26E+3, 1, 7 },
+ };
+
+ for (size_t i = 0, n = sizeof(tests)/sizeof(tests[0]); i < n; ++i)
+ {
+ const char* p = tests[i].str;
+ const char* p_parse_ended = nullptr;
+ double converted = to_double(p, &p_parse_ended);
+ cout << "original: '" << tests[i].str << "', converted: " << converted
+ << ", expected: " << tests[i].expected << endl;
+
+ // Check for double-precision equality without the rounding error.
+ double factor = 1.0;
+ for (size_t j = 0; j < tests[i].decimals; ++j)
+ factor *= 10.0;
+
+ converted = round(converted * factor);
+ double expected = round(tests[i].expected * factor);
+ assert(converted == expected);
+
+ // Check the end parse position.
+ const char* pos_expected = p + tests[i].end_pos;
+ assert(pos_expected == p_parse_ended);
+ }
+}
+
+void test_string2long_conversion()
+{
+ struct {
+ const char* str;
+ long expected;
+ size_t end_pos;
+ } tests[] = {
+ { "1", 1, 1 },
+ { "12", 12, 2 },
+ { "13.4", 13, 2 },
+ { "-23", -23, 3 },
+ { "678abc", 678, 3 },
+ };
+
+ for (size_t i = 0, n = sizeof(tests)/sizeof(tests[0]); i < n; ++i)
+ {
+ const char* p = tests[i].str;
+ const char* p_parse_ended = nullptr;
+ long converted = to_long(p, &p_parse_ended);
+ cout << "original: '" << tests[i].str << "', converted: " << converted
+ << ", expected: " << tests[i].expected << endl;
+
+ assert(converted == tests[i].expected);
+
+ // Check the end parse position.
+ const char* pos_expected = p + tests[i].end_pos;
+ assert(pos_expected == p_parse_ended);
+ }
+}
+
+void test_spreadsheet_types()
+{
+ std::vector<spreadsheet::error_value_t> values =
+ {
+ spreadsheet::error_value_t::div0,
+ spreadsheet::error_value_t::na,
+ spreadsheet::error_value_t::name,
+ spreadsheet::error_value_t::null,
+ spreadsheet::error_value_t::num,
+ spreadsheet::error_value_t::ref,
+ spreadsheet::error_value_t::value
+ };
+
+ for (spreadsheet::error_value_t ev : values)
+ {
+ // Round-trip each enum value.
+ std::ostringstream os;
+ os << ev;
+ std::string s = os.str();
+ auto converted = spreadsheet::to_error_value_enum(s);
+ assert(converted == ev);
+ }
+}
+
+int main()
+{
+ test_date_time_conversion();
+ test_measurement_conversion();
+ test_measurement_conversion_2();
+ test_string2number_conversion();
+ test_string2long_conversion();
+ test_spreadsheet_types();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/config.cpp b/src/liborcus/config.cpp
new file mode 100644
index 0000000..9195e02
--- /dev/null
+++ b/src/liborcus/config.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/config.hpp"
+
+namespace orcus {
+
+config::config(format_t input) :
+ input_format(input),
+ debug(false),
+ structure_check(true)
+{
+ // Initialize format-specific config settings below.
+
+ switch (input_format)
+ {
+ case format_t::csv:
+ {
+ csv_config csv;
+ csv.header_row_size = 0;
+ csv.split_to_multiple_sheets = false;
+ data = csv;
+ break;
+ }
+ case format_t::gnumeric:
+ case format_t::ods:
+ case format_t::xls_xml:
+ case format_t::xlsx:
+ case format_t::unknown:
+ default:
+ ;
+ }
+}
+
+json_config::json_config() :
+ output_format(dump_format_t::none),
+ preserve_object_order(true),
+ resolve_references(false),
+ persistent_string_values(true) {}
+
+json_config::~json_config() {}
+
+yaml_config::yaml_config() :
+ output_format(output_format_type::none) {}
+
+yaml_config::~yaml_config() {}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/constants.inl.in b/src/liborcus/constants.inl.in
new file mode 100644
index 0000000..da93f77
--- /dev/null
+++ b/src/liborcus/constants.inl.in
@@ -0,0 +1,4 @@
+
+#define ORCUS_MAJOR_VERSION @ORCUS_MAJOR_VERSION@
+#define ORCUS_MINOR_VERSION @ORCUS_MINOR_VERSION@
+#define ORCUS_MICRO_VERSION @ORCUS_MICRO_VERSION@
diff --git a/src/liborcus/css_document_tree.cpp b/src/liborcus/css_document_tree.cpp
new file mode 100644
index 0000000..6960084
--- /dev/null
+++ b/src/liborcus/css_document_tree.cpp
@@ -0,0 +1,647 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/css_document_tree.hpp>
+#include <orcus/css_parser.hpp>
+#include <orcus/string_pool.hpp>
+
+#define ORCUS_DEBUG_CSS_DOCTREE 0
+
+#include <iostream>
+#include <unordered_map>
+#include <map>
+#include <algorithm>
+#include <iterator>
+#include <string_view>
+
+namespace orcus {
+
+namespace {
+
+struct selector_type
+{
+ css_selector_t selector;
+ css::pseudo_element_t pseudo_element;
+};
+
+class parser_handler
+{
+ css_document_tree& m_doc;
+ std::vector<selector_type> m_cur_selector_group;
+ css_properties_t m_cur_properties;
+ std::string_view m_cur_prop_name;
+ std::vector<css_property_value_t> m_cur_prop_values;
+ css_selector_t m_cur_selector; /// current selector
+ css_simple_selector_t m_cur_simple_selector;
+ css::pseudo_element_t m_cur_pseudo_element;
+ css::combinator_t m_cur_combinator;
+ bool m_in_prop:1;
+public:
+ parser_handler(css_document_tree& doc) :
+ m_doc(doc),
+ m_cur_pseudo_element(0),
+ m_cur_combinator(css::combinator_t::descendant),
+ m_in_prop(false) {}
+
+ void at_rule_name(std::string_view name)
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << "@" << name;
+#else
+ (void)name;
+#endif
+ }
+
+ void simple_selector_type(std::string_view type)
+ {
+ m_cur_simple_selector.name = type;
+ }
+
+ void simple_selector_class(std::string_view cls)
+ {
+ m_cur_simple_selector.classes.insert(cls);
+ }
+
+ void simple_selector_pseudo_element(css::pseudo_element_t pe)
+ {
+ // Only the one applied to the last simple selector is valid.
+ m_cur_pseudo_element |= pe;
+ }
+
+ void simple_selector_pseudo_class(css::pseudo_class_t pc)
+ {
+ m_cur_simple_selector.pseudo_classes |= pc;
+ }
+
+ void simple_selector_id(std::string_view id)
+ {
+ m_cur_simple_selector.id = id;
+ }
+
+ void end_simple_selector()
+ {
+ if (m_cur_selector.first.empty())
+ m_cur_selector.first = m_cur_simple_selector;
+ else
+ {
+ css_chained_simple_selector_t css;
+ css.combinator = m_cur_combinator;
+ css.simple_selector = m_cur_simple_selector;
+ m_cur_selector.chained.push_back(css);
+ }
+
+ m_cur_simple_selector.clear();
+ }
+
+ void end_selector()
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << m_cur_selector << "|";
+#endif
+ selector_type sel;
+ sel.selector = m_cur_selector;
+ sel.pseudo_element = m_cur_pseudo_element;
+ m_cur_selector_group.push_back(sel);
+ m_cur_selector.clear();
+ m_cur_pseudo_element = 0;
+ }
+
+ void combinator(css::combinator_t combinator)
+ {
+ m_cur_combinator = combinator;
+ }
+
+ void property_name(std::string_view name)
+ {
+ m_cur_prop_name = name;
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << name << ":";
+#endif
+ }
+
+ void value(std::string_view s)
+ {
+ m_cur_prop_values.push_back(s);
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << " '" << s << "'";
+#endif
+ }
+
+ void rgb(uint8_t red, uint8_t green, uint8_t blue)
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << " rgb(" << (int)red << ',' << (int)green << ',' << (int)blue << ')';
+#endif
+ css_property_value_t val;
+ val.type = css::property_value_t::rgb;
+ val.value = css::rgba_color_t{red, green, blue, 0.0};
+ m_cur_prop_values.push_back(val);
+ }
+
+ void rgba(uint8_t red, uint8_t green, uint8_t blue, double alpha)
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << " rgba(" << (int)red << ',' << (int)green << ',' << (int)blue << ',' << alpha << ')';
+#endif
+ css_property_value_t val;
+ val.type = css::property_value_t::rgba;
+ val.value = css::rgba_color_t{red, green, blue, alpha};
+ m_cur_prop_values.push_back(val);
+ }
+
+ void hsl(uint8_t hue, uint8_t sat, uint8_t light)
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << "hsl(" << (int)hue << ',' << (int)sat << ',' << (int)light << ')';
+#endif
+ css_property_value_t val;
+ val.type = css::property_value_t::hsl;
+ val.value = css::hsla_color_t{hue, sat, light, 0.0};
+ m_cur_prop_values.push_back(val);
+ }
+
+ void hsla(uint8_t hue, uint8_t sat, uint8_t light, double alpha)
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << "hsla(" << (int)hue << ',' << (int)sat << ',' << (int)light << ',' << alpha << ')';
+#endif
+ css_property_value_t val;
+ val.type = css::property_value_t::hsla;
+ val.value = css::hsla_color_t{hue, sat, light, alpha};
+ m_cur_prop_values.push_back(val);
+ }
+
+ void url(std::string_view url)
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << " url(" << url << ")";
+#endif
+ css_property_value_t val;
+ val.type = orcus::css::property_value_t::url;
+ val.value = url;
+ m_cur_prop_values.push_back(val);
+ }
+
+ void begin_parse()
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << "========" << endl;
+#endif
+ }
+
+ void end_parse()
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << "========" << endl;
+#endif
+ }
+
+ void begin_block()
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << endl << "{" << endl;
+#endif
+ m_in_prop = true;
+ }
+
+ void end_block()
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << "}" << endl;
+#endif
+ m_in_prop = false;
+
+ // Push the property set and selector group to the document tree.
+
+ std::vector<selector_type>::iterator it = m_cur_selector_group.begin(), ite = m_cur_selector_group.end();
+ for (; it != ite; ++it)
+ m_doc.insert_properties(it->selector, it->pseudo_element, m_cur_properties);
+
+ m_cur_selector_group.clear();
+ m_cur_properties.clear();
+ }
+
+ void begin_property()
+ {
+#if ORCUS_DEBUG_CSS_DOCTREE
+ if (m_in_prop)
+ cout << " ";
+ cout << "* ";
+#endif
+ }
+
+ void end_property()
+ {
+ m_cur_properties.insert(
+ css_properties_t::value_type(m_cur_prop_name, m_cur_prop_values));
+ m_cur_prop_name = std::string_view{};
+ m_cur_prop_values.clear();
+#if ORCUS_DEBUG_CSS_DOCTREE
+ cout << endl;
+#endif
+ }
+};
+
+struct simple_selector_node;
+
+typedef std::unordered_map<
+ css_simple_selector_t, simple_selector_node, css_simple_selector_t::hash> simple_selectors_type;
+
+typedef std::map<css::combinator_t, simple_selectors_type> combinators_type;
+
+struct simple_selector_node
+{
+ css_pseudo_element_properties_t properties;
+ combinators_type children;
+};
+
+css_simple_selector_t intern(string_pool& sp, const css_simple_selector_t& sel)
+{
+ css_simple_selector_t interned;
+
+ if (!sel.name.empty())
+ interned.name = sp.intern(sel.name).first;
+ if (!sel.id.empty())
+ interned.id = sp.intern(sel.id).first;
+
+ css_simple_selector_t::classes_type::const_iterator it = sel.classes.begin(), ite = sel.classes.end();
+ for (; it != ite; ++it)
+ interned.classes.insert(sp.intern(*it).first);
+
+ interned.pseudo_classes = sel.pseudo_classes;
+
+ return interned;
+}
+
+css_selector_t intern(string_pool& sp, const css_selector_t& sel)
+{
+ css_selector_t interned;
+ interned.first = intern(sp, sel.first);
+
+ css_selector_t::chained_type::const_iterator it = sel.chained.begin(), ite = sel.chained.end();
+ for (; it != ite; ++it)
+ {
+ const css_chained_simple_selector_t& cs = *it;
+ css_chained_simple_selector_t cs_interned;
+ cs_interned.combinator = cs.combinator;
+ cs_interned.simple_selector = intern(sp, cs.simple_selector);
+ interned.chained.push_back(cs_interned);
+ }
+
+ return interned;
+}
+
+class intern_inserter
+{
+ string_pool& m_sp;
+ std::vector<css_property_value_t>& m_dest;
+public:
+ intern_inserter(string_pool& sp, std::vector<css_property_value_t>& dest) :
+ m_sp(sp), m_dest(dest) {}
+
+ void operator() (const css_property_value_t& v) const
+ {
+ switch (v.type)
+ {
+ case css::property_value_t::string:
+ case css::property_value_t::url:
+ {
+ // String value needs interning.
+ css_property_value_t interned = v;
+ auto s = std::get<std::string_view>(v.value);
+ interned.value = m_sp.intern(s).first;
+ m_dest.push_back(interned);
+ break;
+ }
+ default:
+ m_dest.push_back(v);
+ }
+ }
+};
+
+void store_properties(
+ string_pool& sp, css_pseudo_element_properties_t& store,
+ css::pseudo_element_t pseudo_flags, const css_properties_t& props)
+{
+ css_pseudo_element_properties_t::iterator it_store = store.find(pseudo_flags);
+ if (it_store == store.end())
+ {
+ // No storage for this pseudo flag value. Create a new one.
+ std::pair<css_pseudo_element_properties_t::iterator, bool> r =
+ store.insert(
+ css_pseudo_element_properties_t::value_type(
+ pseudo_flags, css_properties_t()));
+ if (!r.second)
+ // insertion failed.
+ return;
+
+ it_store = r.first;
+ }
+
+ css_properties_t& prop_store = it_store->second;
+
+ css_properties_t::const_iterator it = props.begin(), ite = props.end();
+ for (; it != ite; ++it)
+ {
+ std::string_view key = sp.intern(it->first).first;
+ std::vector<css_property_value_t> vals;
+ for_each(it->second.begin(), it->second.end(), intern_inserter(sp, vals));
+ prop_store[key] = vals;
+ }
+}
+
+simple_selector_node* get_or_create_simple_selector_node(
+ simple_selectors_type& store, const css_simple_selector_t& ss)
+{
+ simple_selectors_type::iterator it = store.find(ss);
+ if (it == store.end())
+ {
+ // Insert this root selector.
+ std::pair<simple_selectors_type::iterator, bool> r =
+ store.insert(
+ simple_selectors_type::value_type(
+ ss, simple_selector_node()));
+
+ if (!r.second)
+ // Insertion failed.
+ return nullptr;
+
+ it = r.first;
+ }
+
+ return &it->second;
+}
+
+const simple_selector_node* get_simple_selector_node(
+ const simple_selectors_type& store, const css_simple_selector_t& ss)
+{
+ simple_selectors_type::const_iterator it = store.find(ss);
+ return it == store.end() ? nullptr : &it->second;
+}
+
+simple_selectors_type* get_or_create_simple_selectors_type(
+ combinators_type& store, css::combinator_t combinator)
+{
+ combinators_type::iterator it = store.find(combinator);
+ if (it == store.end())
+ {
+ // Insert new combinator.
+ std::pair<combinators_type::iterator, bool> r =
+ store.insert(
+ combinators_type::value_type(
+ combinator, simple_selectors_type()));
+ if (!r.second)
+ // Insertion failed.
+ return nullptr;
+
+ it = r.first;
+ }
+
+ return &it->second;
+}
+
+const simple_selectors_type* get_simple_selectors_type(
+ const combinators_type& store, css::combinator_t combinator)
+{
+ combinators_type::const_iterator it = store.find(combinator);
+ return it == store.end() ? nullptr : &it->second;
+}
+
+void dump_pseudo_elements(css::pseudo_element_t elem)
+{
+ if (!elem)
+ return;
+
+ if (elem & css::pseudo_element_after)
+ std::cout << "::after";
+ if (elem & css::pseudo_element_before)
+ std::cout << "::before";
+ if (elem & css::pseudo_element_first_letter)
+ std::cout << "::first-letter";
+ if (elem & css::pseudo_element_first_line)
+ std::cout << "::first-line";
+ if (elem & css::pseudo_element_selection)
+ std::cout << "::selection";
+ if (elem & css::pseudo_element_backdrop)
+ std::cout << "::backdrop";
+}
+
+void dump_properties(const css_properties_t& props)
+{
+ std::cout << '{' << std::endl;
+ css_properties_t::const_iterator it = props.begin(), ite = props.end();
+ for (; it != ite; ++it)
+ {
+ std::cout << " * " << it->first << ": ";
+ const std::vector<css_property_value_t>& vals = it->second;
+ std::copy(vals.begin(), vals.end(), std::ostream_iterator<css_property_value_t>(std::cout, " "));
+ std::cout << ';' << std::endl;
+ }
+ std::cout << '}' << std::endl;
+}
+
+void dump_all_properties(const css_selector_t& selector, const css_pseudo_element_properties_t& properties)
+{
+ css_pseudo_element_properties_t::const_iterator it_prop = properties.begin(), ite_prop = properties.end();
+ for (; it_prop != ite_prop; ++it_prop)
+ {
+ const css_properties_t& prop = it_prop->second;
+ if (prop.empty())
+ continue;
+
+ std::cout << selector;
+ dump_pseudo_elements(it_prop->first);
+ std::cout << std::endl;
+ dump_properties(prop);
+ }
+}
+
+void dump_chained_recursive(
+ css_selector_t& selector, css::combinator_t op, const simple_selectors_type& ss)
+{
+ simple_selectors_type::const_iterator it_ss = ss.begin(), ite_ss = ss.end();
+ for (; it_ss != ite_ss; ++it_ss)
+ {
+ css_chained_simple_selector_t chained_ss;
+ chained_ss.combinator = op;
+ chained_ss.simple_selector = it_ss->first;
+ selector.chained.push_back(chained_ss);
+
+ const simple_selector_node& node = it_ss->second;
+ dump_all_properties(selector, node.properties);
+
+ combinators_type::const_iterator it_comb = node.children.begin(), ite_comb = node.children.end();
+ for (; it_comb != ite_comb; ++it_comb)
+ dump_chained_recursive(selector, it_comb->first, it_comb->second);
+
+ selector.chained.pop_back();
+ }
+}
+
+const css_pseudo_element_properties_t* get_properties_map(
+ const simple_selectors_type& root, const css_selector_t& selector)
+{
+ const simple_selector_node* node = get_simple_selector_node(root, selector.first);
+ if (!node)
+ return nullptr;
+
+ if (!selector.chained.empty())
+ {
+ // Follow the chain to find the right node to store new properties.
+ css_selector_t::chained_type::const_iterator it_chain = selector.chained.begin();
+ css_selector_t::chained_type::const_iterator ite_chain = selector.chained.end();
+ const combinators_type* combos = &node->children;
+ for (; it_chain != ite_chain; ++it_chain)
+ {
+ const css_chained_simple_selector_t& css = *it_chain;
+ const simple_selectors_type* ss = get_simple_selectors_type(*combos, css.combinator);
+ if (!ss)
+ return nullptr;
+
+ node = get_simple_selector_node(*ss, css.simple_selector);
+ if (!node)
+ return nullptr;
+
+ combos = &node->children;
+ }
+ }
+
+ assert(node);
+ return &node->properties;
+}
+
+}
+
+css_document_tree::insertion_error::insertion_error(const std::string& msg) :
+ general_error(msg) {}
+
+struct css_document_tree::impl
+{
+ string_pool m_string_pool;
+ simple_selectors_type m_root;
+};
+
+css_document_tree::css_document_tree() : mp_impl(std::make_unique<impl>())
+{
+}
+
+css_document_tree::css_document_tree(css_document_tree&& other) :
+ mp_impl(std::move(other.mp_impl))
+{
+ other.mp_impl = std::make_unique<impl>();
+}
+
+css_document_tree::~css_document_tree() = default;
+
+css_document_tree& css_document_tree::operator=(css_document_tree&& other)
+{
+ css_document_tree tmp(std::move(other));
+ swap(tmp);
+
+ return *this;
+}
+
+void css_document_tree::load(std::string_view stream)
+{
+ if (stream.empty())
+ return;
+
+ parser_handler handler(*this);
+ css_parser<parser_handler> parser(stream, handler);
+ parser.parse();
+}
+
+void css_document_tree::insert_properties(
+ const css_selector_t& selector,
+ css::pseudo_element_t pseudo_elem,
+ const css_properties_t& props)
+{
+ if (props.empty())
+ return;
+
+ css_selector_t selector_interned = intern(mp_impl->m_string_pool, selector);
+
+ // See if the root selector already exists.
+ simple_selector_node* node =
+ get_or_create_simple_selector_node(mp_impl->m_root, selector_interned.first);
+
+ if (!node)
+ throw insertion_error("failed to find or create the root simple selector node.");
+
+ if (!selector_interned.chained.empty())
+ {
+ // Follow the chain to find the right node to store new properties.
+ css_selector_t::chained_type::iterator it_chain = selector_interned.chained.begin();
+ css_selector_t::chained_type::iterator ite_chain = selector_interned.chained.end();
+ combinators_type* combos = &node->children;
+ for (; it_chain != ite_chain; ++it_chain)
+ {
+ css_chained_simple_selector_t& css = *it_chain;
+ simple_selectors_type* ss = get_or_create_simple_selectors_type(*combos, css.combinator);
+ if (!ss)
+ throw insertion_error("failed to find or create the simple selectors type by combinator.");
+
+ node = get_or_create_simple_selector_node(*ss, css.simple_selector);
+ if (!node)
+ throw insertion_error("failed to find or create the simple selector node.");
+
+ combos = &node->children;
+ }
+ }
+
+ // We found the right node to store the properties.
+ assert(node);
+ store_properties(mp_impl->m_string_pool, node->properties, pseudo_elem, props);
+}
+
+const css_properties_t* css_document_tree::get_properties(
+ const css_selector_t& selector, css::pseudo_element_t pseudo_elem) const
+{
+ const css_pseudo_element_properties_t* prop_map = get_properties_map(mp_impl->m_root, selector);
+ if (!prop_map)
+ return nullptr;
+
+ css_pseudo_element_properties_t::const_iterator it = prop_map->find(pseudo_elem);
+ if (it == prop_map->end())
+ return nullptr;
+
+ return &it->second;
+}
+
+const css_pseudo_element_properties_t*
+css_document_tree::get_all_properties(const css_selector_t& selector) const
+{
+ return get_properties_map(mp_impl->m_root, selector);
+}
+
+void css_document_tree::dump() const
+{
+ css_selector_t selector;
+
+ const simple_selectors_type& ss = mp_impl->m_root;
+ simple_selectors_type::const_iterator it_ss = ss.begin(), ite_ss = ss.end();
+ for (; it_ss != ite_ss; ++it_ss)
+ {
+ selector.first = it_ss->first;
+
+ const simple_selector_node& node = it_ss->second;
+ dump_all_properties(selector, node.properties);
+
+ combinators_type::const_iterator it_comb = node.children.begin(), ite_comb = node.children.end();
+ for (; it_comb != ite_comb; ++it_comb)
+ dump_chained_recursive(selector, it_comb->first, it_comb->second);
+ }
+}
+
+void css_document_tree::swap(css_document_tree& other) noexcept
+{
+ mp_impl.swap(other.mp_impl);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/css_document_tree_test.cpp b/src/liborcus/css_document_tree_test.cpp
new file mode 100644
index 0000000..085ae14
--- /dev/null
+++ b/src/liborcus/css_document_tree_test.cpp
@@ -0,0 +1,690 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/css_document_tree.hpp>
+#include <orcus/css_types.hpp>
+#include <orcus/css_parser_base.hpp>
+#include <orcus/stream.hpp>
+
+#include <cstdlib>
+#include <cassert>
+#include <iostream>
+#include <sstream>
+#include <iterator>
+
+#include "filesystem_env.hpp"
+
+using namespace orcus;
+
+bool check_prop(const css_properties_t& props, std::string_view key, std::string_view val)
+{
+ css_properties_t::const_iterator it = props.find(key);
+ if (it == props.end())
+ {
+ std::cout << "property '" << key << "' not found" << std::endl;
+ return false;
+ }
+
+ // Chain all property values into a single string delimited by a " ".
+ const std::vector<css_property_value_t>& vals = it->second;
+ std::ostringstream os;
+ if (vals.size() > 1)
+ {
+ auto it_end = vals.end();
+ std::advance(it_end, -1);
+ std::copy(vals.begin(), it_end, std::ostream_iterator<css_property_value_t>(os, " "));
+ }
+ os << vals.back();
+
+ std::string val_stored = os.str();
+ if (val != val_stored)
+ {
+ std::cout << "property '" << key << "' is expected to have value '"
+ << val << "' but '" << val_stored << "' is found." << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+using check_properties_type = std::vector<std::pair<std::string, std::string>>;
+
+bool check_props(const css_properties_t& props, check_properties_type expected)
+{
+ bool pass = true;
+
+ for (const auto& [key, value] : expected)
+ {
+ bool res = check_prop(props, key, value);
+ if (!res)
+ pass = false;
+ }
+
+ return pass;
+}
+
+css_document_tree load_document(const fs::path& path)
+{
+ std::cout << path << std::endl;
+ file_content content(path.string());
+ css_document_tree doc;
+ doc.load(content.str());
+
+ return doc;
+}
+
+void test_css_invalids()
+{
+ // Get all yaml files in this directory.
+ fs::path dirpath(SRCDIR"/test/css/invalids/");
+ fs::directory_iterator it_end;
+
+ size_t file_count = 0;
+
+ for (fs::directory_iterator it(dirpath); it != it_end; ++it)
+ {
+ fs::path path = it->path();
+ if (!fs::is_regular_file(path))
+ continue;
+
+ if (path.extension().string() != ".css")
+ continue;
+
+ std::cout << "parsing invalid file " << path.filename().string() << "..." << std::endl;
+
+ ++file_count;
+
+ file_content content(path.string().data());
+ css_document_tree doc;
+
+ try
+ {
+ doc.load(content.str());
+ assert(!"css::parse_error was not thrown, but expected to be.");
+ }
+ catch (const parse_error&)
+ {
+ // This is expected.
+ }
+ }
+
+ assert(file_count > 0);
+}
+
+void test_css_simple_selector_equality()
+{
+ css_simple_selector_t left;
+ css_simple_selector_t right;
+ assert(left == right);
+
+ left.classes.insert("one");
+ assert(left != right);
+ right.classes.insert("one");
+ assert(left == right);
+
+ left.classes.insert("two");
+ assert(left != right);
+ right.classes.insert("two");
+ assert(left == right);
+
+ left.classes.insert("three");
+ assert(left != right);
+ right.classes.insert("three");
+ assert(left == right);
+}
+
+void test_css_empty()
+{
+ fs::path path = SRCDIR"/test/css/empty.css";
+ std::cout << path << std::endl;
+
+ file_content content(path.string());
+ css_document_tree doc;
+ doc.load(content.str());
+}
+
+void test_css_parse_basic1()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic1.css");
+
+ css_selector_t selector;
+ selector.first.name = "table";
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 2);
+ assert(check_prop(*props, "width", "auto"));
+ assert(check_prop(*props, "height", "500px"));
+
+ selector.first.name = "td";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 2);
+ assert(check_prop(*props, "color", "gray"));
+ assert(check_prop(*props, "background-color", "yellow"));
+
+ // This selector doesn't exist in the document tree.
+ selector.first.name = "tr";
+ props = doc.get_properties(selector, 0);
+ assert(!props);
+}
+
+void test_css_parse_basic2()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic2.css");
+
+ css_selector_t selector;
+ selector.first.name = "div";
+ selector.first.classes.insert("foo");
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "border", "solid 1px"));
+
+ selector.clear();
+ selector.first.classes.insert("warning");
+
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 2);
+ assert(check_prop(*props, "background-color", "red"));
+ assert(check_prop(*props, "font-weight", "900"));
+}
+
+void test_css_parse_basic3()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic3.css");
+
+ css_selector_t selector;
+ selector.first.name = "html";
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "height", "100%"));
+
+ selector.first.name = "body";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "height", "100%"));
+
+ {
+ // h1, h2, h3 and h4 all have identical set of properties.
+ const char* names[] = { "h1", "h2", "h3", "h4" };
+ std::size_t n = std::size(names);
+
+ for (size_t i = 0; i < n; ++i)
+ {
+ selector.first.name = names[i];
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 2);
+ assert(check_prop(*props, "font-variant", "small-caps"));
+ assert(check_prop(*props, "padding", "2.5em"));
+ }
+ }
+}
+
+void test_css_parse_basic4()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic4.css");
+
+ css_selector_t selector;
+ selector.first.name = "h1";
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "margin", "0.5in"));
+
+ selector.first.name = "h2";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "line-height", "3cm"));
+
+ selector.first.name = "h3";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "word-spacing", "4mm"));
+
+ selector.first.name = "h4";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "font-size", "1pc"));
+
+ selector.first.name = "p";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "font-size", "12px"));
+}
+
+void test_css_parse_basic5()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic5.css");
+
+ css_selector_t selector;
+ selector.first.classes.insert("info");
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "word-spacing", "normal"));
+}
+
+void test_css_parse_basic6()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic6.css");
+
+ css_selector_t selector;
+ selector.first.name = "h1";
+ selector.first.id = "chapter1";
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "text-align", "center"));
+
+ selector.first.id = "z98y";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "letter-spacing", "0.5em"));
+
+ selector.clear();
+ selector.first.id = "id_global";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "margin", "10px"));
+}
+
+void test_css_parse_basic7()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic7.css");
+
+ css_selector_t selector;
+ selector.first.classes.insert("one");
+ selector.first.classes.insert("two");
+ selector.first.classes.insert("three");
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "color", "blue"));
+
+ selector.first.classes.clear();
+ selector.first.classes.insert("one");
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "color", "aqua"));
+
+ selector.first.classes.clear();
+ selector.first.classes.insert("two");
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "color", "azure"));
+
+ selector.first.classes.insert("one"); // one two
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "color", "brown"));
+
+ selector.first.clear();
+ selector.first.name = "span";
+ selector.first.classes.insert("button");
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "border", "solid 1px gray"));
+
+ selector.first.classes.insert("selected"); // button selected
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "border", "solid 4px red"));
+}
+
+void test_css_parse_basic8()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic8.css");
+
+ css_selector_t selector;
+ selector.first.classes.insert("ribbon");
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "#5BC8F7"));
+
+ props = doc.get_properties(selector, css::pseudo_element_after);
+ assert(props);
+ assert(props->size() == 4);
+ assert(check_prop(*props, "content", "Look at this orange box."));
+ assert(check_prop(*props, "background-color", "#FFBA10"));
+ assert(check_prop(*props, "border-color", "black"));
+ assert(check_prop(*props, "border-style", "dotted"));
+
+ props = doc.get_properties(selector, css::pseudo_element_before);
+ assert(!props); // it doesn't exist for this pseudo element.
+
+ props = doc.get_properties(
+ selector,
+ css::pseudo_element_after|css::pseudo_element_selection);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "content", "Selected orange box."));
+
+ // Get all properties for all pseudo element flag combos.
+ const css_pseudo_element_properties_t* all_props = doc.get_all_properties(selector);
+ assert(all_props);
+ assert(all_props->size() == 3);
+
+ // Check the properties for no pseudo element flag.
+ css_pseudo_element_properties_t::const_iterator it = all_props->find(0);
+ assert(it != all_props->end());
+ props = &it->second;
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "#5BC8F7"));
+
+ // ::after pseudo element
+ it = all_props->find(css::pseudo_element_after);
+ assert(it != all_props->end());
+ props = &it->second;
+ assert(props->size() == 4);
+ assert(check_prop(*props, "content", "Look at this orange box."));
+ assert(check_prop(*props, "background-color", "#FFBA10"));
+ assert(check_prop(*props, "border-color", "black"));
+ assert(check_prop(*props, "border-style", "dotted"));
+
+ // ::after::selection pseudo element pair.
+ it = all_props->find(css::pseudo_element_after|css::pseudo_element_selection);
+ assert(it != all_props->end());
+ props = &it->second;
+ assert(check_prop(*props, "content", "Selected orange box."));
+}
+
+void test_css_parse_basic9()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic9.css");
+
+ css_selector_t selector;
+ selector.first.name = "a";
+ selector.first.pseudo_classes = css::pseudo_class_link;
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "color", "#FF0000"));
+
+ selector.first.pseudo_classes = css::pseudo_class_visited;
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "color", "#00FF00"));
+
+ selector.first.pseudo_classes = css::pseudo_class_hover;
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "color", "#FF00FF"));
+
+ selector.first.pseudo_classes = css::pseudo_class_active;
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "color", "#0000FF"));
+}
+
+void test_css_parse_basic10()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic10.css");
+
+ css_selector_t selector;
+ selector.first.classes.insert("foo");
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 2);
+ assert(check_prop(*props, "background-color", "rgb(12,230,222)"));
+ assert(check_prop(*props, "border", "solid 5px rgba(30,12,0,0.79)"));
+}
+
+void test_css_parse_basic11()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic11.css");
+
+ css_selector_t selector;
+ selector.first.classes.insert("callout");
+
+ const css_properties_t* props = doc.get_properties(selector, css::pseudo_element_before);
+ assert(props);
+ assert(props->size() == 5);
+ assert(check_prop(*props, "content", ""));
+ assert(check_prop(*props, "width", "0px"));
+ assert(check_prop(*props, "height", "0px"));
+ assert(check_prop(*props, "border", "0.8em solid transparent"));
+ assert(check_prop(*props, "position", "absolute"));
+}
+
+void test_css_parse_basic12()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic12.css");
+
+ css_selector_t selector;
+ selector.first.name = "div";
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-image", "url(https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png)"));
+
+ selector.first.name = "p";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-image", "none"));
+
+ selector.first.name = "div";
+ selector.first.classes.insert("img1");
+
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-image", "url(http://www.rabiakhan.com/Gallery/background.jpg)"));
+
+ selector.first.classes.clear();
+ selector.first.classes.insert("img2");
+
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-image", "url(http://www.tgraphic.com/userimages/Gallery/Backgrounds/TGraphic_com-Full-Wallpapers-Backgrounds_Colorful_C_1920_33.jpg)"));
+}
+
+void test_css_parse_basic13()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic13.css");
+
+ css_selector_t selector;
+ selector.first.id = "p1";
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "hsl(120,100,50)"));
+
+ selector.first.id = "p2";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "hsl(120,100,75)"));
+
+ selector.first.id = "p3";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "hsl(120,100,25)"));
+
+ selector.first.id = "p4";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "hsl(120,60,70)"));
+}
+
+void test_css_parse_basic14()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/basic14.css");
+
+ css_selector_t selector;
+ selector.first.id = "p1";
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "hsla(120,100,50,0.3)"));
+
+ selector.first.id = "p2";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "hsla(120,100,75,0.3)"));
+
+ selector.first.id = "p3";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "hsla(120,100,25,0.3)"));
+
+ selector.first.id = "p4";
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "hsla(120,60,70,0.3)"));
+}
+
+void test_css_parse_chained1()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/chained1.css");
+
+ css_selector_t selector;
+ selector.first.name = "div";
+ css_simple_selector_t ss;
+ ss.name = "p";
+ selector.chained.push_back(ss);
+
+ // div p
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "yellow"));
+
+ // div > p
+ selector.chained.back().combinator = css::combinator_t::direct_child;
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "blue"));
+
+ // div + p
+ selector.chained.back().combinator = css::combinator_t::next_sibling;
+ props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 1);
+ assert(check_prop(*props, "background-color", "red"));
+}
+
+void test_css_parse_chained2()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/chained2.css");
+
+ // Build selector '#id1 table.data td'.
+ css_selector_t selector;
+ selector.first.id = "id1";
+
+ css_simple_selector_t ss;
+ ss.name = "table";
+ ss.classes.insert("data");
+ selector.chained.push_back(ss);
+
+ ss.clear();
+ ss.name = "td";
+ selector.chained.push_back(ss);
+
+ const css_properties_t* props = doc.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 2);
+ assert(check_prop(*props, "background-color", "aquamarine"));
+ assert(check_prop(*props, "border", "solid 2px"));
+}
+
+void test_css_parse_utf8_1()
+{
+ css_document_tree doc = load_document(SRCDIR"/test/css/utf8-1.css");
+
+ css_document_tree doc2;
+ doc2 = std::move(doc); // test the move assignment operator.
+
+ css_selector_t selector;
+ selector.first.classes.insert("style17");
+
+ const css_properties_t* props = doc2.get_properties(selector, 0);
+ assert(props);
+ assert(props->size() == 11);
+
+ check_properties_type expected = {
+ { "mso-pattern", "auto none" },
+ { "background", "#EDEDED" },
+ { "mso-style-name", "20% - 强调文字颜色 3" },
+ { "color", "#000000" },
+ { "font-size", "11.0pt" },
+ { "font-weight", "400" },
+ { "font-style", "normal" },
+ { "font-family", "宋体" },
+ { "text-decoration", "none" },
+ { "mso-generic-font-family", "auto" },
+ { "mso-font-charset", "0" },
+ };
+
+ assert(check_props(*props, expected));
+}
+
+int main()
+{
+ test_css_invalids();
+ test_css_simple_selector_equality();
+ test_css_empty();
+ test_css_parse_basic1();
+ test_css_parse_basic2();
+ test_css_parse_basic3();
+ test_css_parse_basic4();
+ test_css_parse_basic5();
+ test_css_parse_basic6();
+ test_css_parse_basic7();
+ test_css_parse_basic8();
+ test_css_parse_basic9();
+ test_css_parse_basic10();
+ test_css_parse_basic11();
+ test_css_parse_basic12();
+ test_css_parse_basic13();
+ test_css_parse_basic14();
+ test_css_parse_chained1();
+ test_css_parse_chained2();
+ test_css_parse_utf8_1();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/css_selector.cpp b/src/liborcus/css_selector.cpp
new file mode 100644
index 0000000..b7b63f3
--- /dev/null
+++ b/src/liborcus/css_selector.cpp
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/css_selector.hpp"
+
+namespace orcus {
+
+css_simple_selector_t::css_simple_selector_t() :
+ pseudo_classes(0) {}
+
+void css_simple_selector_t::clear()
+{
+ name = std::string_view{};
+ id = std::string_view{};
+ classes.clear();
+ pseudo_classes = 0;
+}
+
+bool css_simple_selector_t::empty() const
+{
+ return name.empty() && id.empty() && classes.empty() && !pseudo_classes;
+}
+
+bool css_simple_selector_t::operator== (const css_simple_selector_t& r) const
+{
+ if (name != r.name)
+ return false;
+
+ if (id != r.id)
+ return false;
+
+ if (classes != r.classes)
+ return false;
+
+ return pseudo_classes == r.pseudo_classes;
+}
+
+bool css_simple_selector_t::operator!= (const css_simple_selector_t& r) const
+{
+ return !operator==(r);
+}
+
+size_t css_simple_selector_t::hash::operator() (const css_simple_selector_t& ss) const
+{
+ std::hash<std::string_view> h;
+
+ size_t val = h(ss.name);
+ val += h(ss.id);
+
+ for (std::string_view s : ss.classes)
+ val += h(s);
+
+ val += ss.pseudo_classes;
+
+ return val;
+}
+
+bool css_chained_simple_selector_t::operator== (const css_chained_simple_selector_t& r) const
+{
+ return combinator == r.combinator && simple_selector == r.simple_selector;
+}
+
+css_chained_simple_selector_t::css_chained_simple_selector_t() :
+ combinator(css::combinator_t::descendant) {}
+
+css_chained_simple_selector_t::css_chained_simple_selector_t(const css_simple_selector_t& ss) :
+ combinator(css::combinator_t::descendant), simple_selector(ss) {}
+
+css_chained_simple_selector_t::css_chained_simple_selector_t(
+ css::combinator_t op, const css_simple_selector_t& ss) :
+ combinator(op), simple_selector(ss) {}
+
+void css_selector_t::clear()
+{
+ first.clear();
+ chained.clear();
+}
+
+bool css_selector_t::operator== (const css_selector_t& r) const
+{
+ return first == r.first && chained == r.chained;
+}
+
+css_property_value_t::css_property_value_t() :
+ type(css::property_value_t::none), value{std::string_view{}} {}
+
+css_property_value_t::css_property_value_t(const css_property_value_t& r) :
+ type(r.type), value(r.value)
+{
+}
+
+css_property_value_t::css_property_value_t(std::string_view _str) :
+ type(css::property_value_t::string), value(_str) {}
+
+css_property_value_t& css_property_value_t::operator= (const css_property_value_t& r)
+{
+ type = r.type;
+ value = r.value;
+ return *this;
+}
+
+void css_property_value_t::swap(css_property_value_t& r)
+{
+ std::swap(type, r.type);
+ std::swap(value, r.value);
+}
+
+std::ostream& operator<< (std::ostream& os, const css_simple_selector_t& v)
+{
+ os << v.name;
+ css_simple_selector_t::classes_type::const_iterator it = v.classes.begin(), ite = v.classes.end();
+ for (; it != ite; ++it)
+ os << '.' << *it;
+ if (!v.id.empty())
+ os << '#' << v.id;
+ if (v.pseudo_classes)
+ os << css::pseudo_class_to_string(v.pseudo_classes);
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const css_selector_t& v)
+{
+ os << v.first;
+ css_selector_t::chained_type::const_iterator it = v.chained.begin(), ite = v.chained.end();
+ for (; it != ite; ++it)
+ {
+ const css_chained_simple_selector_t& css = *it;
+ os << ' ';
+ switch (css.combinator)
+ {
+ case css::combinator_t::direct_child:
+ os << "> ";
+ break;
+ case css::combinator_t::next_sibling:
+ os << "+ ";
+ break;
+ case css::combinator_t::descendant:
+ default:
+ ;
+ }
+ os << css.simple_selector;
+ }
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const css_property_value_t& v)
+{
+ const char* sep = ",";
+
+ switch (v.type)
+ {
+ case css::property_value_t::hsl:
+ {
+ auto c = std::get<css::hsla_color_t>(v.value);
+ os << "hsl("
+ << (int)c.hue << sep
+ << (int)c.saturation << sep
+ << (int)c.lightness
+ << ")";
+ break;
+ }
+ case css::property_value_t::hsla:
+ {
+ auto c = std::get<css::hsla_color_t>(v.value);
+ os << "hsla("
+ << (int)c.hue << sep
+ << (int)c.saturation << sep
+ << (int)c.lightness << sep
+ << c.alpha
+ << ")";
+ break;
+ }
+ case css::property_value_t::rgb:
+ {
+ auto c = std::get<css::rgba_color_t>(v.value);
+ os << "rgb("
+ << (int)c.red << sep
+ << (int)c.green << sep
+ << (int)c.blue
+ << ")";
+ break;
+ }
+ case css::property_value_t::rgba:
+ {
+ auto c = std::get<css::rgba_color_t>(v.value);
+ os << "rgba("
+ << (int)c.red << sep
+ << (int)c.green << sep
+ << (int)c.blue << sep
+ << c.alpha
+ << ")";
+ break;
+ }
+ case css::property_value_t::string:
+ os << std::get<std::string_view>(v.value);
+ break;
+ case css::property_value_t::url:
+ os << "url(" << std::get<std::string_view>(v.value) << ")";
+ break;
+ case css::property_value_t::none:
+ default:
+ ;
+ }
+
+ return os;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/detection_result.cpp b/src/liborcus/detection_result.cpp
new file mode 100644
index 0000000..b49f645
--- /dev/null
+++ b/src/liborcus/detection_result.cpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "detection_result.hpp"
+
+namespace orcus {
+
+detection_result::detection_result(bool result) : m_result(result) {}
+
+bool detection_result::get_result() const
+{
+ return m_result;
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/detection_result.hpp b/src/liborcus/detection_result.hpp
new file mode 100644
index 0000000..bb87941
--- /dev/null
+++ b/src/liborcus/detection_result.hpp
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_DETECTION_RESULT_HPP
+#define ORCUS_DETECTION_RESULT_HPP
+
+namespace orcus {
+
+class detection_result
+{
+ bool m_result;
+
+public:
+ detection_result(bool result);
+
+ bool get_result() const;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/dom_tree.cpp b/src/liborcus/dom_tree.cpp
new file mode 100644
index 0000000..9e7a764
--- /dev/null
+++ b/src/liborcus/dom_tree.cpp
@@ -0,0 +1,741 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/dom_tree.hpp>
+#include <orcus/exception.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <orcus/sax_ns_parser.hpp>
+#include <orcus/string_pool.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <cassert>
+#include <unordered_map>
+#include <vector>
+#include <algorithm>
+#include <deque>
+
+namespace orcus {
+
+namespace dom {
+
+namespace {
+
+/**
+ * Escape certain characters with backslash (\).
+ */
+void escape(std::ostream& os, std::string_view val)
+{
+ if (val.empty())
+ return;
+
+ const char* p = val.data();
+ const char* p_end = p + val.size();
+ for (; p != p_end; ++p)
+ {
+ if (*p == '"')
+ os << "\\\"";
+ else if (*p == '\\')
+ os << "\\\\";
+ else
+ os << *p;
+ }
+}
+
+struct attr
+{
+ dom::entity_name name;
+ std::string_view value;
+
+ attr(xmlns_id_t _ns, std::string_view _name, std::string_view _value);
+};
+
+struct entity_name_hash
+{
+ std::size_t operator()(const entity_name& v) const
+ {
+ return std::hash<std::string_view>{}(v.name) ^ reinterpret_cast<std::size_t>(v.ns);
+ }
+};
+
+using attrs_type = std::vector<attr>;
+using attr_map_type = std::unordered_map<entity_name, size_t, entity_name_hash>;
+
+struct declaration
+{
+ attrs_type attrs;
+ attr_map_type attr_map;
+};
+
+enum class node_type { element, content };
+
+struct element;
+
+struct node
+{
+ const element* parent;
+ node_type type;
+
+ node(node_type _type) : parent(nullptr), type(_type) {}
+
+ virtual ~node() = 0;
+ virtual void print(std::ostream& os, const xmlns_context& cxt) const = 0;
+};
+
+typedef std::vector<std::unique_ptr<node>> nodes_type;
+
+struct element : public node
+{
+ entity_name name;
+ attrs_type attrs;
+ attr_map_type attr_map;
+ nodes_type child_nodes;
+ std::vector<size_t> child_elem_positions;
+
+ element() = delete;
+ element(xmlns_id_t _ns, std::string_view _name);
+ virtual void print(std::ostream& os, const xmlns_context& cxt) const;
+ virtual ~element();
+};
+
+struct content : public node
+{
+ std::string_view value;
+
+ content(std::string_view _value);
+ virtual void print(std::ostream& os, const xmlns_context& cxt) const;
+ virtual ~content();
+};
+
+void print(std::ostream& os, const entity_name& name, const xmlns_context& cxt)
+{
+ if (name.ns)
+ {
+ size_t index = cxt.get_index(name.ns);
+ if (index != INDEX_NOT_FOUND)
+ os << "ns" << index << ':';
+ }
+ os << name.name;
+}
+
+void print(std::ostream& os, const attr& at, const xmlns_context& cxt)
+{
+ dom::print(os, at.name, cxt);
+ os << "=\"";
+ escape(os, at.value);
+ os << '"';
+}
+
+attr::attr(xmlns_id_t _ns, std::string_view _name, std::string_view _value) :
+ name(_ns, _name), value(_value) {}
+
+node::~node() {}
+
+element::element(xmlns_id_t _ns, std::string_view _name) :
+ node(node_type::element), name(_ns, _name) {}
+
+void element::print(std::ostream& os, const xmlns_context& cxt) const
+{
+ dom::print(os, name, cxt);
+}
+
+element::~element() = default;
+
+content::content(std::string_view _value) : node(node_type::content), value(_value) {}
+
+void content::print(std::ostream& os, const xmlns_context& /*cxt*/) const
+{
+ os << '"';
+ escape(os, value);
+ os << '"';
+}
+
+content::~content() = default;
+
+} // anonymous namespace
+
+entity_name::entity_name() : ns(XMLNS_UNKNOWN_ID) {}
+
+entity_name::entity_name(std::string_view _name) :
+ ns(XMLNS_UNKNOWN_ID), name(_name) {}
+
+entity_name::entity_name(xmlns_id_t _ns, std::string_view _name) :
+ ns(_ns), name(_name) {}
+
+bool entity_name::operator== (const entity_name& other) const
+{
+ return ns == other.ns && name == other.name;
+}
+
+bool entity_name::operator!= (const entity_name& other) const
+{
+ return !operator==(other);
+}
+
+struct const_node::impl
+{
+ node_t type;
+
+ union
+ {
+ const dom::declaration* decl;
+ const dom::element* elem;
+
+ struct
+ {
+ const char* p;
+ size_t n;
+
+ } str;
+
+ } value;
+
+ impl() : type(node_t::unset) {}
+
+ impl(const impl& other) : type(other.type)
+ {
+ switch (type)
+ {
+ case node_t::declaration:
+ value.decl = other.value.decl;
+ break;
+ case node_t::element:
+ value.elem = other.value.elem;
+ break;
+ case node_t::unset:
+ default:
+ ;
+ }
+ }
+
+ impl(const dom::element* _elem) : type(node_t::element)
+ {
+ value.elem = _elem;
+ }
+
+ impl(const dom::declaration* _decl) : type(node_t::declaration)
+ {
+ value.decl = _decl;
+ }
+};
+
+const_node::const_node(std::unique_ptr<impl>&& _impl) : mp_impl(std::move(_impl)) {}
+const_node::const_node() : mp_impl(std::make_unique<impl>()) {}
+const_node::const_node(const const_node& other) : mp_impl(std::make_unique<impl>(*other.mp_impl)) {}
+const_node::const_node(const_node&& other) : mp_impl(std::move(other.mp_impl)) {}
+const_node::~const_node() {}
+
+node_t const_node::type() const
+{
+ return mp_impl->type;
+}
+
+size_t const_node::child_count() const
+{
+ switch (mp_impl->type)
+ {
+ case node_t::element:
+ {
+ const dom::element* p = mp_impl->value.elem;
+ return p->child_elem_positions.size();
+ }
+ default:
+ ;
+ }
+
+ return 0;
+}
+
+const_node const_node::child(size_t index) const
+{
+ switch (mp_impl->type)
+ {
+ case node_t::element:
+ {
+ const dom::element* p = mp_impl->value.elem;
+
+ size_t elem_pos = p->child_elem_positions.at(index);
+ assert(elem_pos < p->child_nodes.size());
+
+ const dom::node* child_node = p->child_nodes[elem_pos].get();
+ assert(child_node->type == node_type::element);
+
+ auto v = std::make_unique<impl>(static_cast<const dom::element*>(child_node));
+ return const_node(std::move(v));
+ }
+ default:
+ ;
+ }
+ return const_node();
+}
+
+entity_name const_node::name() const
+{
+ switch (mp_impl->type)
+ {
+ case node_t::element:
+ {
+ const dom::element* p = mp_impl->value.elem;
+ return p->name;
+ }
+ default:
+ ;
+ }
+
+ return entity_name();
+}
+
+std::string_view const_node::attribute(const entity_name& name) const
+{
+ switch (mp_impl->type)
+ {
+ case node_t::element:
+ {
+ const dom::element* p = mp_impl->value.elem;
+ auto it = p->attr_map.find(name);
+ if (it == p->attr_map.end())
+ break;
+
+ size_t pos = it->second;
+ assert(pos < p->attrs.size());
+ return p->attrs[pos].value;
+ }
+ default:
+ ;
+ }
+
+ return std::string_view();
+}
+
+std::string_view const_node::attribute(std::string_view name) const
+{
+ switch (mp_impl->type)
+ {
+ case node_t::declaration:
+ {
+ const dom::declaration* p = mp_impl->value.decl;
+ auto it = p->attr_map.find(name);
+ if (it == p->attr_map.end())
+ return std::string_view();
+
+ size_t pos = it->second;
+ assert(pos < p->attrs.size());
+ return p->attrs[pos].value;
+ }
+ default:
+ ;
+ }
+
+ return attribute(entity_name(name));
+}
+
+size_t const_node::attribute_count() const
+{
+ switch (mp_impl->type)
+ {
+ case node_t::declaration:
+ {
+ const dom::declaration* p = mp_impl->value.decl;
+ return p->attrs.size();
+ }
+ case node_t::element:
+ {
+ const dom::element* p = mp_impl->value.elem;
+ return p->attrs.size();
+ }
+ default:
+ ;
+ }
+ return 0;
+}
+
+const_node const_node::parent() const
+{
+ if (mp_impl->type != node_t::element)
+ return const_node();
+
+ const dom::element* p = mp_impl->value.elem->parent;
+ if (!p)
+ return const_node();
+
+ auto v = std::make_unique<impl>(p);
+ return const_node(std::move(v));
+}
+
+void const_node::swap(const_node& other)
+{
+ mp_impl.swap(other.mp_impl);
+}
+
+const_node& const_node::operator= (const const_node& other)
+{
+ const_node tmp(other);
+ swap(tmp);
+ return *this;
+}
+
+bool const_node::operator== (const const_node& other) const
+{
+ if (mp_impl->type != other.mp_impl->type)
+ return false;
+
+ switch (mp_impl->type)
+ {
+ case node_t::unset:
+ return true;
+ case node_t::declaration:
+ return mp_impl->value.decl == other.mp_impl->value.decl;
+ case node_t::element:
+ return mp_impl->value.elem == other.mp_impl->value.elem;
+ default:
+ ;
+ }
+
+ return false;
+}
+
+bool const_node::operator!= (const const_node& other) const
+{
+ return !operator==(other);
+}
+
+/**
+ * This impl class also serves as the handler for the sax_ns_parser.
+ */
+struct document_tree::impl
+{
+ typedef std::vector<dom::element*> element_stack_type;
+ typedef std::unordered_map<std::string_view, dom::declaration> declarations_type;
+
+ xmlns_context& m_ns_cxt;
+ string_pool m_pool;
+
+ std::unique_ptr<sax::doctype_declaration> m_doctype;
+
+ std::string_view m_cur_decl_name;
+ declarations_type m_decls;
+ dom::attrs_type m_doc_attrs;
+ dom::attrs_type m_cur_attrs;
+ dom::attr_map_type m_cur_attr_map;
+ element_stack_type m_elem_stack;
+ std::unique_ptr<dom::element> m_root;
+
+ impl(xmlns_context& cxt) : m_ns_cxt(cxt) {}
+
+ void start_declaration(std::string_view name)
+ {
+ m_cur_decl_name = name;
+ }
+
+ void end_declaration(std::string_view name);
+ void start_element(const sax_ns_parser_element& elem);
+ void end_element(const sax_ns_parser_element& elem);
+ void characters(std::string_view val, bool transient);
+ void doctype(const sax::doctype_declaration& dtd);
+
+ void attribute(std::string_view name, std::string_view val)
+ {
+ set_attribute(XMLNS_UNKNOWN_ID, name, val);
+ }
+
+ void attribute(const sax_ns_parser_attribute& attr)
+ {
+ set_attribute(attr.ns, attr.name, attr.value);
+ }
+
+ void set_attribute(xmlns_id_t ns, std::string_view name, std::string_view val);
+};
+
+void document_tree::impl::end_declaration(std::string_view name)
+{
+ assert(m_cur_decl_name == name);
+
+ dom::declaration decl;
+ decl.attrs.swap(m_cur_attrs);
+ decl.attr_map.swap(m_cur_attr_map);
+
+ declarations_type::iterator it = m_decls.find(name);
+ if (it == m_decls.end())
+ {
+ // Insert a new entry for this name.
+ std::pair<declarations_type::iterator,bool> r =
+ m_decls.insert(
+ declarations_type::value_type(
+ m_pool.intern(name).first, std::move(decl)));
+
+ if (!r.second)
+ // Insertion failed.
+ throw general_error("dom_tree::end_declaration: failed to insert a new declaration entry.");
+ }
+ else
+ it->second = std::move(decl);
+}
+
+void document_tree::impl::start_element(const sax_ns_parser_element& elem)
+{
+ xmlns_id_t ns = elem.ns;
+ std::string_view name = elem.name;
+
+ // These strings must be persistent.
+ std::string_view name_safe = m_pool.intern(name).first;
+
+ dom::element* p = nullptr;
+ if (!m_root)
+ {
+ // This must be the root element!
+ m_root = std::make_unique<dom::element>(ns, name_safe);
+ m_elem_stack.push_back(m_root.get());
+ p = m_elem_stack.back();
+ p->attrs.swap(m_cur_attrs);
+ p->attr_map.swap(m_cur_attr_map);
+ return;
+ }
+
+ // Append new element as a child element of the current element.
+ p = m_elem_stack.back();
+
+ size_t elem_pos = p->child_nodes.size();
+ p->child_elem_positions.push_back(elem_pos);
+
+ p->child_nodes.push_back(std::make_unique<dom::element>(ns, name_safe));
+ const dom::element* parent = p;
+ p = static_cast<dom::element*>(p->child_nodes.back().get());
+ p->parent = parent;
+ p->attrs.swap(m_cur_attrs);
+ p->attr_map.swap(m_cur_attr_map);
+
+ m_elem_stack.push_back(p);
+}
+
+void document_tree::impl::end_element(const sax_ns_parser_element& elem)
+{
+ xmlns_id_t ns = elem.ns;
+ std::string_view name = elem.name;
+
+ const dom::element* p = m_elem_stack.back();
+ if (p->name.ns != ns || p->name.name != name)
+ throw general_error("non-matching end element.");
+
+ m_elem_stack.pop_back();
+}
+
+void document_tree::impl::characters(std::string_view val, bool /*transient*/)
+{
+ if (m_elem_stack.empty())
+ // No root element has been encountered. Ignore this.
+ return;
+
+ std::string_view val2 = trim(val);
+ if (val2.empty())
+ return;
+
+ dom::element* p = m_elem_stack.back();
+ val2 = m_pool.intern(val2).first; // Make sure the string is persistent.
+ auto child = std::make_unique<dom::content>(val2);
+ child->parent = p;
+ p->child_nodes.push_back(std::move(child));
+}
+
+void document_tree::impl::set_attribute(xmlns_id_t ns, std::string_view name, std::string_view val)
+{
+ // These strings must be persistent.
+ std::string_view name2 = m_pool.intern(name).first;
+ std::string_view val2 = m_pool.intern(val).first;
+
+ size_t pos = m_cur_attrs.size();
+ m_cur_attrs.push_back(dom::attr(ns, name2, val2));
+ m_cur_attr_map.insert({dom::entity_name(ns, name2), pos});
+}
+
+void document_tree::impl::doctype(const sax::doctype_declaration& dtd)
+{
+ m_doctype = std::make_unique<sax::doctype_declaration>(dtd); // make a copy.
+
+ sax::doctype_declaration& this_dtd = *m_doctype;
+ string_pool& pool = m_pool;
+
+ // Intern the strings.
+ this_dtd.root_element = pool.intern(dtd.root_element).first;
+ this_dtd.fpi = pool.intern(dtd.fpi).first;
+ this_dtd.uri = pool.intern(dtd.uri).first;
+}
+
+document_tree::document_tree(xmlns_context& cxt) :
+ mp_impl(std::make_unique<impl>(cxt)) {}
+
+document_tree::document_tree(document_tree&& other) :
+ mp_impl(std::move(other.mp_impl))
+{
+ other.mp_impl = std::make_unique<impl>(mp_impl->m_ns_cxt);
+}
+
+document_tree::~document_tree() {}
+
+void document_tree::load(std::string_view strm)
+{
+ sax_ns_parser<impl> parser(strm, mp_impl->m_ns_cxt, *mp_impl);
+ parser.parse();
+}
+
+dom::const_node document_tree::root() const
+{
+ const dom::element* p = mp_impl->m_root.get();
+ auto v = std::make_unique<const_node::impl>(p);
+ return dom::const_node(std::move(v));
+}
+
+dom::const_node document_tree::declaration(std::string_view name) const
+{
+ impl::declarations_type::const_iterator it = mp_impl->m_decls.find(name);
+ if (it == mp_impl->m_decls.end())
+ return dom::const_node();
+
+ const dom::declaration* decl = &it->second;
+ auto v = std::make_unique<dom::const_node::impl>(decl);
+ return dom::const_node(std::move(v));
+}
+
+void document_tree::swap(document_tree& other)
+{
+ mp_impl.swap(other.mp_impl);
+}
+
+const sax::doctype_declaration* document_tree::get_doctype() const
+{
+ return mp_impl->m_doctype.get();
+}
+
+namespace {
+
+struct scope
+{
+ typedef std::vector<const dom::node*> nodes_type;
+ std::string name;
+ nodes_type nodes;
+ nodes_type::const_iterator current_pos;
+
+ scope(const scope&) = delete;
+ scope& operator=(const scope&) = delete;
+
+ scope(const std::string& _name, dom::node* _node) :
+ name(_name)
+ {
+ nodes.push_back(_node);
+ current_pos = nodes.begin();
+ }
+
+ scope(const std::string& _name) : name(_name) {}
+};
+
+typedef std::deque<scope> scopes_type;
+
+void print_scope(std::ostream& os, const scopes_type& scopes)
+{
+ if (scopes.empty())
+ throw general_error("scope stack shouldn't be empty while dumping tree.");
+
+ // Skip the first scope which is root.
+ scopes_type::const_iterator it = scopes.begin(), it_end = scopes.end();
+ for (++it; it != it_end; ++it)
+ os << "/" << it->name;
+}
+
+}
+
+void document_tree::dump_compact(std::ostream& os) const
+{
+ if (!mp_impl->m_root)
+ return;
+
+ // Dump namespaces first.
+ mp_impl->m_ns_cxt.dump(os);
+
+ scopes_type scopes;
+
+ scopes.emplace_back(std::string(), mp_impl->m_root.get());
+ while (!scopes.empty())
+ {
+ bool new_scope = false;
+
+ // Iterate through all elements in the current scope.
+ scope& cur_scope = scopes.back();
+ for (; cur_scope.current_pos != cur_scope.nodes.end(); ++cur_scope.current_pos)
+ {
+ const dom::node* this_node = *cur_scope.current_pos;
+ assert(this_node);
+ print_scope(os, scopes);
+ if (this_node->type == dom::node_type::content)
+ {
+ // This is a text content.
+ this_node->print(os, mp_impl->m_ns_cxt);
+ os << std::endl;
+ continue;
+ }
+
+ assert(this_node->type == dom::node_type::element);
+ const dom::element* elem = static_cast<const dom::element*>(this_node);
+ os << "/";
+ elem->print(os, mp_impl->m_ns_cxt);
+ os << std::endl;
+
+ {
+ // Dump attributes.
+ dom::attrs_type attrs = elem->attrs;
+ std::sort(attrs.begin(), attrs.end(),
+ [](const dom::attr& left, const dom::attr& right) -> bool
+ {
+ return left.name.name < right.name.name;
+ }
+ );
+
+ for (const dom::attr& a : attrs)
+ {
+ print_scope(os, scopes);
+ os << "/";
+ elem->print(os, mp_impl->m_ns_cxt);
+ os << "@";
+ dom::print(os, a, mp_impl->m_ns_cxt);
+ os << std::endl;
+ }
+ }
+
+ if (elem->child_nodes.empty())
+ continue;
+
+ // This element has child nodes. Push a new scope and populate it
+ // with all child elements, but skip content nodes.
+ scope::nodes_type nodes;
+ for (const std::unique_ptr<dom::node>& p : elem->child_nodes)
+ nodes.push_back(p.get());
+
+ assert(!nodes.empty());
+
+ // Push a new scope, and restart the loop with the new scope.
+ ++cur_scope.current_pos;
+ std::ostringstream elem_name;
+ elem->print(elem_name, mp_impl->m_ns_cxt);
+ scopes.emplace_back(elem_name.str());
+ scope& child_scope = scopes.back();
+ child_scope.nodes.swap(nodes);
+ child_scope.current_pos = child_scope.nodes.begin();
+
+ new_scope = true;
+ break;
+ }
+
+ if (new_scope)
+ continue;
+
+ scopes.pop_back();
+ }
+}
+
+} // namespace dom
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/dom_tree_test.cpp b/src/liborcus/dom_tree_test.cpp
new file mode 100644
index 0000000..5ce5418
--- /dev/null
+++ b/src/liborcus/dom_tree_test.cpp
@@ -0,0 +1,123 @@
+
+#include <orcus/dom_tree.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <cassert>
+#include <iostream>
+
+using namespace orcus::dom;
+
+struct doctree
+{
+ orcus::xmlns_repository repo;
+ orcus::xmlns_context cxt;
+ orcus::dom::document_tree tree;
+
+ doctree(std::string_view content) : repo(), cxt(repo.create_context()), tree(cxt)
+ {
+ tree.load(content);
+ }
+};
+
+std::unique_ptr<doctree> load_document_tree(std::string_view content)
+{
+ std::unique_ptr<doctree> ret = std::make_unique<doctree>(content);
+ return ret;
+}
+
+std::unique_ptr<doctree> load_document_tree_from_file(const char* filepath)
+{
+ orcus::file_content content(filepath);
+ return load_document_tree(content.str());
+}
+
+void test_encoded_attr()
+{
+ std::string content = "<?xml version=\"1.0\"?><root attr=\"&amp;;\"/>";
+ auto doctree = load_document_tree(content);
+ const_node root = doctree->tree.root();
+ doctree->tree.dump_compact(std::cout);
+ std::cout << __FILE__ << "#" << __LINE__ << " (:test_encoded_attr): " << root.attribute("attr") << std::endl;
+ assert(root.attribute("attr") == "&;");
+}
+
+void test_declaration()
+{
+ auto doctree = load_document_tree_from_file(SRCDIR"/test/xml/osm/street-in-aizu.osm");
+
+ const_node decl = doctree->tree.declaration("xml");
+ assert(decl.type() == node_t::declaration);
+ assert(decl.attribute("version") == "1.0");
+ assert(decl.attribute("encoding") == "UTF-8");
+
+ const_node copied = decl;
+ assert(copied == decl);
+}
+
+void test_attributes()
+{
+ auto doctree = load_document_tree_from_file(SRCDIR"/test/xml/osm/street-in-aizu.osm");
+
+ const_node root = doctree->tree.root();
+ assert(root.name() == entity_name("osm"));
+ assert(root.type() == node_t::element);
+ assert(root.attribute("version") == "0.6");
+ assert(root.attribute("generator") == "CGImap 0.6.1 (1984 thorn-02.openstreetmap.org)");
+ assert(root.attribute("copyright") == "OpenStreetMap and contributors");
+ assert(root.attribute("attribution") == "http://www.openstreetmap.org/copyright");
+ assert(root.attribute("license") == "http://opendatacommons.org/licenses/odbl/1-0/");
+ assert(root.attribute("no-such-attribute").empty());
+ assert(root.attribute_count() == 5);
+}
+
+void test_element_hierarchy()
+{
+ auto doctree = load_document_tree_from_file(SRCDIR"/test/xml/osm/street-in-aizu.osm");
+
+ const_node root = doctree->tree.root();
+ assert(root.name() == entity_name("osm"));
+ assert(root.child_count() > 0);
+ assert(root.parent().type() == node_t::unset);
+
+ const_node elem = root.child(0);
+ assert(elem != root);
+ assert(elem.type() == node_t::element);
+ assert(elem.name() == entity_name("bounds"));
+ assert(elem.attribute("minlat") == "37.4793300");
+ assert(elem.attribute("minlon") == "139.9158300");
+ assert(elem.attribute("maxlat") == "37.4798000");
+ assert(elem.attribute("maxlon") == "139.9162300");
+ assert(elem.attribute_count() == 4);
+ assert(elem.child_count() == 0);
+ assert(elem.parent() == root);
+
+ const_node copied_elem = elem;
+ assert(copied_elem == elem);
+
+ elem = root.child(5);
+ assert(elem.name() == entity_name("node"));
+ assert(elem.attribute("user") == "jun_meguro");
+ assert(elem.child_count() == 1);
+ elem = elem.child(0);
+ assert(elem.name() == entity_name("tag"));
+ assert(elem.attribute("k") == "highway");
+ assert(elem.attribute("v") == "crossing");
+
+ // Make sure the number of child elements are accurate.
+ size_t n_elems = root.child_count();
+ for (size_t i = 0; i < n_elems; ++i)
+ {
+ auto child = root.child(i);
+ assert(child.type() == node_t::element);
+ }
+}
+
+int main()
+{
+ test_encoded_attr();
+ test_declaration();
+ test_attributes();
+ test_element_hierarchy();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/liborcus/format_detection.cpp b/src/liborcus/format_detection.cpp
new file mode 100644
index 0000000..e685362
--- /dev/null
+++ b/src/liborcus/format_detection.cpp
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifdef __ORCUS_ODS
+#define ODS_ENABLED 1
+#else
+#define ODS_ENABLED 0
+#endif
+
+#ifdef __ORCUS_XLSX
+#define XLSX_ENABLED 1
+#else
+#define XLSX_ENABLED 0
+#endif
+
+#ifdef __ORCUS_GNUMERIC
+#define GNUMERIC_ENABLED 1
+#else
+#define GNUMERIC_ENABLED 0
+#endif
+
+#ifdef __ORCUS_XLS_XML
+#define XLS_XML_ENABLED 1
+#else
+#define XLS_XML_ENABLED 0
+#endif
+
+#ifdef __ORCUS_PARQUET
+#define PARQUET_ENABLED 1
+#else
+#define PARQUET_ENABLED 0
+#endif
+
+#include <orcus/format_detection.hpp>
+#include <orcus/orcus_csv.hpp>
+
+#if ODS_ENABLED
+#include <orcus/orcus_ods.hpp>
+#endif
+#if XLSX_ENABLED
+#include <orcus/orcus_xlsx.hpp>
+#endif
+#if GNUMERIC_ENABLED
+#include <orcus/orcus_gnumeric.hpp>
+#endif
+#if XLS_XML_ENABLED
+#include <orcus/orcus_xls_xml.hpp>
+#endif
+#if PARQUET_ENABLED
+#include <orcus/orcus_parquet.hpp>
+#endif
+
+#include <stdexcept>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+format_t detect(std::string_view strm) try
+{
+ const auto* p = reinterpret_cast<const unsigned char*>(strm.data());
+
+#if ODS_ENABLED
+ if (orcus_ods::detect(p, strm.size()))
+ return format_t::ods;
+#endif
+#if XLSX_ENABLED
+ if (orcus_xlsx::detect(p, strm.size()))
+ return format_t::xlsx;
+#endif
+#if GNUMERIC_ENABLED
+ if (orcus_gnumeric::detect(p, strm.size()))
+ return format_t::gnumeric;
+#endif
+#if XLS_XML_ENABLED
+ if (orcus_xls_xml::detect(p, strm.size()))
+ return format_t::xls_xml;
+#endif
+#if PARQUET_ENABLED
+ if (orcus_parquet::detect(p, strm.size()))
+ return format_t::parquet;
+#endif
+
+ return format_t::unknown;
+}
+catch (const std::exception&)
+{
+ return format_t::unknown;
+}
+catch (...)
+{
+ return format_t::unknown;
+}
+
+std::shared_ptr<iface::import_filter> create_filter(format_t type, ss::iface::import_factory* factory)
+{
+ if (!factory)
+ throw std::invalid_argument("pointer to import factory instance must not be null");
+ switch (type)
+ {
+#if ODS_ENABLED
+ case format_t::ods:
+ return std::allocate_shared<orcus_ods>(std::allocator<orcus_ods>{}, factory);
+#endif
+#if XLSX_ENABLED
+ case format_t::xlsx:
+ return std::allocate_shared<orcus_xlsx>(std::allocator<orcus_xlsx>{}, factory);
+#endif
+#if GNUMERIC_ENABLED
+ case format_t::gnumeric:
+ return std::allocate_shared<orcus_gnumeric>(std::allocator<orcus_gnumeric>{}, factory);
+#endif
+#if XLS_XML_ENABLED
+ case format_t::xls_xml:
+ return std::allocate_shared<orcus_xls_xml>(std::allocator<orcus_xls_xml>{}, factory);
+#endif
+#if PARQUET_ENABLED
+ case format_t::parquet:
+ return std::allocate_shared<orcus_parquet>(std::allocator<orcus_parquet>{}, factory);
+#endif
+ case format_t::csv:
+ return std::allocate_shared<orcus_csv>(std::allocator<orcus_csv>{}, factory);
+ case format_t::unknown:
+ default:;
+ }
+ return {};
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/formula_result.cpp b/src/liborcus/formula_result.cpp
new file mode 100644
index 0000000..bdde523
--- /dev/null
+++ b/src/liborcus/formula_result.cpp
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "formula_result.hpp"
+
+#include <ostream>
+
+namespace orcus {
+
+formula_result::formula_result() : type(result_type::empty) {}
+formula_result::formula_result(const formula_result& r) :
+ type(r.type)
+{
+ switch (type)
+ {
+ case result_type::numeric:
+ value_numeric = r.value_numeric;
+ break;
+ case result_type::boolean:
+ value_boolean = r.value_boolean;
+ break;
+ case result_type::string:
+ value_string.p = r.value_string.p;
+ value_string.n = r.value_string.n;
+ break;
+ case result_type::empty:
+ default:
+ ;
+ }
+}
+
+formula_result::formula_result(double v) : type(result_type::numeric), value_numeric(v) {}
+formula_result::formula_result(const char* p, size_t n) :
+ type(result_type::string)
+{
+ value_string.p = p;
+ value_string.n = n;
+}
+
+formula_result::formula_result(bool b) : type(result_type::boolean), value_boolean(b) {}
+
+size_t range_formula_results::to_array_pos(size_t row, size_t col) const
+{
+ return row * m_cols + col;
+}
+
+range_formula_results::range_formula_results(size_t rows, size_t cols) :
+ m_store(rows*cols), m_rows(rows), m_cols(cols) {}
+
+void range_formula_results::set(size_t row, size_t col, const formula_result& v)
+{
+ size_t pos = to_array_pos(row, col);
+ m_store[pos] = v;
+}
+
+const formula_result& range_formula_results::get(size_t row, size_t col) const
+{
+ size_t pos = to_array_pos(row, col);
+ return m_store[pos];
+}
+
+size_t range_formula_results::row_size() const
+{
+ return m_rows;
+}
+
+size_t range_formula_results::col_size() const
+{
+ return m_cols;
+}
+
+std::ostream& operator<< (std::ostream& os, const formula_result& v)
+{
+ switch (v.type)
+ {
+ case formula_result::result_type::numeric:
+ os << v.value_numeric;
+ break;
+ case formula_result::result_type::boolean:
+ os << v.value_boolean;
+ break;
+ case formula_result::result_type::string:
+ os << std::string_view(v.value_string.p, v.value_string.n);
+ break;
+ case formula_result::result_type::empty:
+ break;
+ }
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const orcus::range_formula_results& res)
+{
+ os << "{ ";
+ size_t col_pos = 0;
+ for (const formula_result& v : res.m_store)
+ {
+ if (col_pos == res.m_cols)
+ {
+ os << " | ";
+ col_pos = 0;
+ }
+ else if (col_pos > 0)
+ os << ", ";
+
+ os << v;
+ ++col_pos;
+ }
+
+ os << " }";
+
+ return os;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/formula_result.hpp b/src/liborcus/formula_result.hpp
new file mode 100644
index 0000000..14665b3
--- /dev/null
+++ b/src/liborcus/formula_result.hpp
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_FORMULA_RESULT_HPP
+#define INCLUDED_ORCUS_FORMULA_RESULT_HPP
+
+#include <vector>
+#include <cstdlib>
+#include <iosfwd>
+
+namespace orcus {
+
+/**
+ * Stores cached formula result. Note that when the result is of string
+ * type, it only stores a pointer to the string buffer but the instance of
+ * this class does not own the buffer.
+ */
+struct formula_result
+{
+ enum class result_type { empty, numeric, string, boolean };
+
+ result_type type;
+
+ union
+ {
+ double value_numeric;
+ bool value_boolean;
+ struct { const char* p; size_t n; } value_string;
+ };
+
+ formula_result();
+ formula_result(const formula_result& r);
+ formula_result(double v);
+ formula_result(const char* p, size_t n);
+ formula_result(bool b);
+};
+
+class range_formula_results
+{
+ friend std::ostream& operator<< (std::ostream&, const range_formula_results&);
+
+ std::vector<formula_result> m_store;
+ size_t m_rows;
+ size_t m_cols;
+
+ size_t to_array_pos(size_t row, size_t col) const;
+
+public:
+ range_formula_results() = delete;
+ range_formula_results(const range_formula_results&) = delete;
+ range_formula_results(size_t rows, size_t cols);
+
+ void set(size_t row, size_t col, const formula_result& v);
+ const formula_result& get(size_t row, size_t col) const;
+
+ size_t row_size() const;
+ size_t col_size() const;
+};
+
+std::ostream& operator<< (std::ostream& os, const formula_result& v);
+std::ostream& operator<< (std::ostream& os, const orcus::range_formula_results& res);
+
+}
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_cell_context.cpp b/src/liborcus/gnumeric_cell_context.cpp
new file mode 100644
index 0000000..07b82bc
--- /dev/null
+++ b/src/liborcus/gnumeric_cell_context.cpp
@@ -0,0 +1,377 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_token_constants.hpp"
+#include "gnumeric_namespace_types.hpp"
+#include "gnumeric_cell_context.hpp"
+#include "gnumeric_value_format_parser.hpp"
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/measurement.hpp>
+
+#include <fstream>
+#include <algorithm>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+gnumeric_cell_context::gnumeric_cell_context(
+ session_context& session_cxt, const tokens& tokens, ss::iface::import_factory* factory) :
+ xml_context_base(session_cxt, tokens),
+ mp_factory(factory),
+ mp_sheet(nullptr)
+{
+}
+
+gnumeric_cell_context::~gnumeric_cell_context() = default;
+
+void gnumeric_cell_context::start_element(
+ xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Cell:
+ start_cell(attrs);
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool gnumeric_cell_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Cell:
+ end_cell();
+ break;
+ default:
+ ;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void gnumeric_cell_context::characters(std::string_view str, bool transient)
+{
+ m_chars = str;
+ if (transient)
+ m_chars = intern(m_chars);
+}
+
+void gnumeric_cell_context::reset(ss::iface::import_sheet* sheet)
+{
+ m_cell_data.reset();
+ m_chars = std::string_view{};
+ mp_sheet = sheet;
+ m_pool.clear();
+}
+
+void gnumeric_cell_context::start_cell(const xml_token_attrs_t& attrs)
+{
+ m_cell_data = cell_data{};
+ m_cell_data->type = cell_type_formula;
+ m_format_segments.clear();
+
+ for (const auto& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_Row:
+ m_cell_data->row = to_long(attr.value);
+ break;
+ case XML_Col:
+ m_cell_data->col = to_long(attr.value);
+ break;
+ case XML_ValueType:
+ {
+ auto v = to_long(attr.value);
+ m_cell_data->type = cell_type_value;
+ m_cell_data->value_type = static_cast<gnumeric_value_type>(v);
+ break;
+ }
+ case XML_ValueFormat:
+ {
+ auto v = attr.value;
+ if (attr.transient)
+ v = m_pool.intern(v).first;
+
+ gnumeric_value_format_parser parser(v);
+
+ try
+ {
+ parser.parse();
+ }
+ catch (const parse_error& e)
+ {
+ std::ostringstream os;
+ os << "failed to parse a value format string: '" << v << "' (reason=" << e.what() << ")";
+ warn(os.str());
+ break;
+ }
+
+ m_format_segments = parser.pop_segments();
+ break;
+ }
+ case XML_ExprID:
+ m_cell_data->shared_formula_id = to_long(attr.value);
+ m_cell_data->type = cell_type_shared_formula;
+ break;
+ case XML_Rows:
+ m_cell_data->type = cell_type_value;
+ m_cell_data->value_type = vt_array;
+ m_cell_data->array_rows = to_long(attr.value);
+ break;
+ case XML_Cols:
+ m_cell_data->type = cell_type_value;
+ m_cell_data->value_type = vt_array;
+ m_cell_data->array_cols = to_long(attr.value);
+ break;
+ }
+ }
+}
+
+void gnumeric_cell_context::end_cell()
+{
+ if (!m_cell_data)
+ return;
+
+ if (!mp_sheet)
+ return;
+
+ ss::col_t col = m_cell_data->col;
+ ss::row_t row = m_cell_data->row;
+
+ switch (m_cell_data->type)
+ {
+ case cell_type_value:
+ {
+ if (!m_cell_data->value_type)
+ break;
+
+ switch (*m_cell_data->value_type)
+ {
+ case vt_boolean:
+ {
+ bool val = to_bool(m_chars);
+ mp_sheet->set_bool(row, col, val);
+ break;
+ }
+ case vt_float:
+ {
+ double val = to_double(m_chars);
+ mp_sheet->set_value(row, col, val);
+ break;
+ }
+ case vt_string:
+ {
+ push_string(row, col);
+ break;
+ }
+ case vt_array:
+ {
+ ss::range_t range;
+ range.first.column = col;
+ range.first.row = row;
+ range.last.column = col + m_cell_data->array_cols - 1;
+ range.last.row = row + m_cell_data->array_rows - 1;
+
+ ss::iface::import_array_formula* af = mp_sheet->get_array_formula();
+ if (!af)
+ break;
+
+ if (m_chars.empty() || m_chars[0] != '=')
+ // formula string should start with a '='
+ break;
+
+ af->set_range(range);
+ af->set_formula(ss::formula_grammar_t::gnumeric, m_chars.substr(1));
+ af->commit();
+ break;
+ }
+ default:
+ {
+ std::ostringstream os;
+ os << "unhandled cell value type (" << *m_cell_data->value_type << ")";
+ warn(os.str());
+ }
+ }
+ break;
+ }
+ case cell_type_formula:
+ {
+ ss::iface::import_formula* xformula = mp_sheet->get_formula();
+ if (!xformula)
+ break;
+
+ if (m_chars.empty() || m_chars[0] != '=')
+ // formula string should start with a '='
+ break;
+
+ xformula->set_position(row, col);
+ xformula->set_formula(ss::formula_grammar_t::gnumeric, m_chars.substr(1));
+ xformula->commit();
+ break;
+ }
+ case cell_type_shared_formula:
+ {
+ ss::iface::import_formula* xformula = mp_sheet->get_formula();
+ if (!xformula)
+ break;
+
+ xformula->set_position(row, col);
+
+ if (!m_chars.empty() && m_chars[0] == '=')
+ xformula->set_formula(ss::formula_grammar_t::gnumeric, m_chars.substr(1));
+
+ xformula->set_shared_formula_index(m_cell_data->shared_formula_id);
+ xformula->commit();
+ break;
+ }
+ case cell_type_unknown:
+ {
+ std::ostringstream os;
+ os << "cell type is unknown (row=" << row << "; col=" << col << ")";
+ warn(os.str());
+ break;
+ }
+ }
+
+ m_cell_data.reset();
+}
+
+void gnumeric_cell_context::push_string(ss::row_t row, ss::col_t col)
+{
+ ss::iface::import_shared_strings* shared_strings = mp_factory->get_shared_strings();
+ if (!shared_strings)
+ return;
+
+ if (m_format_segments.empty())
+ {
+ // unformatted text
+ std::size_t sid = shared_strings->add(m_chars);
+ mp_sheet->set_string(row, col, sid);
+ return;
+ }
+
+ for (const auto& [start, end] : build_format_segment_ranges())
+ {
+ assert(start < end);
+
+ auto t = m_chars.substr(start, end - start);
+
+ // TODO: use segment tree to eliminate this inner loop
+ for (const gnumeric_value_format_segment& vfs : m_format_segments)
+ {
+ if (vfs.value.empty())
+ continue;
+
+ if (start < vfs.start || vfs.end < end)
+ continue;
+
+ // we have format information
+ switch (vfs.type)
+ {
+ case gnumeric_value_format_type::bold:
+ {
+ bool v = to_bool(vfs.value);
+ shared_strings->set_segment_bold(v);
+ break;
+ }
+ case gnumeric_value_format_type::italic:
+ {
+ bool v = to_bool(vfs.value);
+ shared_strings->set_segment_italic(v);
+ break;
+ }
+ case gnumeric_value_format_type::color:
+ {
+ // [red]x[green]x[blue]
+ auto color = parse_gnumeric_rgb_8x(vfs.value);
+ if (color)
+ shared_strings->set_segment_font_color(255, color->red, color->green, color->blue);
+ break;
+ }
+ case gnumeric_value_format_type::family:
+ {
+ if (!vfs.value.empty())
+ shared_strings->set_segment_font_name(vfs.value);
+ break;
+ }
+ case gnumeric_value_format_type::size:
+ {
+ const char* p_end = nullptr;
+ double v = to_double(vfs.value, &p_end);
+ if (p_end > vfs.value.data())
+ {
+ // font size here is stored in 1024ths of a point, likely coming from Pango
+ v /= 1024.0;
+ shared_strings->set_segment_font_size(v);
+ }
+ break;
+ }
+ default:
+ {
+ std::ostringstream os;
+ os << "unsupported format segment type (" << int(vfs.type) << ")";
+ warn(os.str());
+ }
+ }
+ }
+
+ shared_strings->append_segment(t);
+ }
+
+ std::size_t sid = shared_strings->commit_segments();
+ mp_sheet->set_string(row, col, sid);
+}
+
+std::vector<std::pair<std::size_t, std::size_t>> gnumeric_cell_context::build_format_segment_ranges() const
+{
+ if (m_format_segments.empty())
+ return {};
+
+ std::vector<std::size_t> pts;
+ pts.push_back(0);
+ pts.push_back(m_chars.size());
+ for (const auto& seg : m_format_segments)
+ {
+ pts.push_back(seg.start);
+ pts.push_back(seg.end);
+ }
+
+ std::sort(pts.begin(), pts.end());
+ auto last = std::unique(pts.begin(), pts.end());
+ pts.erase(last, pts.end());
+ assert(pts.size() > 2u);
+
+ std::vector<std::pair<std::size_t, std::size_t>> ranges;
+
+ auto it = pts.begin();
+ auto start = *it;
+ for (++it; it != pts.end(); ++it)
+ {
+ auto end = *it;
+ ranges.emplace_back(start, end);
+ start = end;
+ }
+
+ return ranges;
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_cell_context.hpp b/src/liborcus/gnumeric_cell_context.hpp
new file mode 100644
index 0000000..b3c5f85
--- /dev/null
+++ b/src/liborcus/gnumeric_cell_context.hpp
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_GNUMERIC_CELL_CONTEXT_HPP
+#define INCLUDED_ORCUS_GNUMERIC_CELL_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "gnumeric_types.hpp"
+
+#include <orcus/spreadsheet/types.hpp>
+#include <orcus/string_pool.hpp>
+
+#include <mdds/flat_segment_tree.hpp>
+
+#include <optional>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_factory;
+class import_sheet;
+
+}}
+
+struct gnumeric_cell_data;
+
+class gnumeric_cell_context : public xml_context_base
+{
+ enum cell_type
+ {
+ cell_type_unknown,
+ cell_type_value,
+ cell_type_formula,
+ cell_type_shared_formula,
+ };
+
+ struct cell_data
+ {
+ cell_type type = cell_type_unknown;
+ std::optional<gnumeric_value_type> value_type;
+ spreadsheet::row_t row = 0;
+ spreadsheet::col_t col = 0;
+ spreadsheet::row_t array_rows = 0;
+ spreadsheet::col_t array_cols = 0;
+ std::size_t shared_formula_id = 0;
+ };
+
+public:
+ gnumeric_cell_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_factory* factory);
+ virtual ~gnumeric_cell_context() override;
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs) override;
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ virtual void characters(std::string_view str, bool transient) override;
+
+ void reset(spreadsheet::iface::import_sheet* sheet);
+
+private:
+ void start_cell(const xml_token_attrs_t& attrs);
+ void end_cell();
+ void push_string(spreadsheet::row_t row, spreadsheet::col_t col);
+
+ std::vector<std::pair<std::size_t, std::size_t>> build_format_segment_ranges() const;
+
+private:
+ spreadsheet::iface::import_factory* mp_factory;
+ spreadsheet::iface::import_sheet* mp_sheet;
+
+ std::vector<gnumeric_value_format_segment> m_format_segments;
+ std::optional<cell_data> m_cell_data;
+ std::string_view m_chars;
+ string_pool m_pool;
+};
+
+} // namespace orcus
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_cell_context_test.cpp b/src/liborcus/gnumeric_cell_context_test.cpp
new file mode 100644
index 0000000..80d612c
--- /dev/null
+++ b/src/liborcus/gnumeric_cell_context_test.cpp
@@ -0,0 +1,386 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_cell_context.hpp"
+#include "gnumeric_tokens.hpp"
+#include "gnumeric_namespace_types.hpp"
+#include "gnumeric_token_constants.hpp"
+#include "mock_spreadsheet.hpp"
+#include "session_context.hpp"
+#include <orcus/types.hpp>
+
+#include <iostream>
+#include <string>
+#include <cstdlib>
+
+using namespace orcus;
+using namespace std;
+using namespace orcus::spreadsheet;
+using namespace orcus::spreadsheet::mock;
+
+namespace {
+
+class mock_array_formula : public import_array_formula
+{
+public:
+ virtual void set_range(const range_t& range) override
+ {
+ assert(range.first.row == 19);
+ assert(range.first.column == 111);
+ assert(range.last.row == 20);
+ assert(range.last.column == 113);
+ }
+
+ virtual void set_formula(formula_grammar_t grammar, std::string_view formula) override
+ {
+ assert(grammar == formula_grammar_t::gnumeric);
+ assert(formula == "arrayFormula");
+ }
+
+ virtual void set_result_bool(row_t, col_t, bool) override
+ {
+ }
+
+ virtual void set_result_empty(row_t, col_t) override
+ {
+ }
+
+ virtual void set_result_string(row_t, col_t, std::string_view) override
+ {
+ }
+
+ virtual void set_result_value(row_t, col_t, double) override
+ {
+ }
+
+ virtual void commit() override
+ {
+ }
+};
+
+class mock_formula : public import_formula
+{
+public:
+ virtual void set_position(row_t row, col_t col) override
+ {
+ assert(row == 9);
+ assert(col == 11);
+ }
+
+ virtual void set_formula(formula_grammar_t grammar, std::string_view formula) override
+ {
+ assert(grammar == formula_grammar_t::gnumeric);
+ assert(formula == "formula");
+ }
+
+ virtual void set_shared_formula_index(size_t) override
+ {
+ }
+
+ virtual void set_result_bool(bool) override
+ {
+ }
+
+ virtual void set_result_empty() override
+ {
+ }
+
+ virtual void set_result_string(std::string_view) override
+ {
+ }
+
+ virtual void set_result_value(double) override
+ {
+ }
+
+ virtual void commit() override
+ {
+ }
+};
+
+class mock_sheet : public import_sheet
+{
+ mock_formula m_formula;
+ mock_array_formula m_array_formula;
+public:
+ virtual void set_value(row_t row, col_t col, double val) override
+ {
+ assert(row == 1);
+ assert(col == 2);
+ assert(val == 5.0);
+ }
+
+ virtual void set_bool(row_t row, col_t col, bool val) override
+ {
+ assert(row == 31);
+ assert(col == 32);
+ assert(val == true);
+ }
+
+ virtual void set_string(row_t row, col_t col, string_id_t id) override
+ {
+ assert(row == 10);
+ assert(col == 321);
+ assert(id == 2);
+ }
+
+ virtual iface::import_array_formula* get_array_formula() override
+ {
+ return &m_array_formula;
+ }
+
+ virtual iface::import_formula* get_formula() override
+ {
+ return &m_formula;
+ }
+};
+
+class mock_shared_strings : public import_shared_strings
+{
+public:
+ virtual size_t add(std::string_view s) override
+ {
+ assert(s.size() == 14);
+ assert(s == "14 char string");
+ return 2;
+ }
+};
+
+class mock_factory : public import_factory
+{
+public:
+ virtual iface::import_shared_strings* get_shared_strings()
+ {
+ return &m_shared_strings;
+ }
+
+private:
+ mock_shared_strings m_shared_strings;
+};
+
+void test_cell_value()
+{
+ mock_sheet sheet;
+ import_factory factory;
+ session_context cxt;
+
+ orcus::gnumeric_cell_context context(cxt, orcus::gnumeric_tokens, &factory);
+ context.reset(&sheet);
+
+ orcus::xmlns_id_t ns = NS_gnumeric_gnm;
+ orcus::xml_token_t elem = XML_Cell;
+ orcus::xml_token_attrs_t attrs;
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Row, "1", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Col, "2", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_ValueType, "40", false));
+ context.start_element(ns, elem, attrs);
+ context.characters("5", false);
+ context.end_element(ns, elem);
+}
+
+void test_cell_bool()
+{
+ mock_sheet sheet;
+ import_factory factory;
+ session_context cxt;
+
+ orcus::gnumeric_cell_context context(cxt, orcus::gnumeric_tokens, &factory);
+ context.reset(&sheet);
+
+ orcus::xmlns_id_t ns = NS_gnumeric_gnm;
+ orcus::xml_token_t elem = XML_Cell;
+ orcus::xml_token_attrs_t attrs;
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Row, "31", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Col, "32", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_ValueType, "20", false));
+ context.start_element(ns, elem, attrs);
+ context.characters("TRUE", false);
+ context.end_element(ns, elem);
+}
+
+void test_cell_string()
+{
+ mock_sheet sheet;
+ mock_factory factory;
+ session_context cxt;
+
+ orcus::gnumeric_cell_context context(cxt, orcus::gnumeric_tokens, &factory);
+ context.reset(&sheet);
+
+ orcus::xmlns_id_t ns = NS_gnumeric_gnm;
+ orcus::xml_token_t elem = XML_Cell;
+ orcus::xml_token_attrs_t attrs;
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Row, "10", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Col, "321", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_ValueType, "60", false));
+ context.start_element(ns, elem, attrs);
+ context.characters("14 char string", false);
+ context.end_element(ns, elem);
+}
+
+void test_shared_formula_with_string()
+{
+ class mock_formula_local : public import_formula
+ {
+ public:
+ void set_position(row_t row, col_t col) override
+ {
+ assert(row == 5);
+ assert(col == 15);
+ }
+
+ void set_formula(formula_grammar_t grammar, std::string_view formula) override
+ {
+ assert(grammar == formula_grammar_t::gnumeric);
+ assert(formula == "basicFormulaString");
+ }
+
+ void set_shared_formula_index(size_t index) override
+ {
+ assert(index == 2);
+ }
+
+ void commit() override
+ {
+ }
+ };
+
+ class mock_sheet_local : public import_sheet
+ {
+ mock_formula_local m_formula;
+ public:
+ virtual iface::import_formula* get_formula()
+ {
+ return &m_formula;
+ }
+ };
+
+ mock_sheet_local sheet;
+ mock_factory factory;
+ session_context cxt;
+
+ orcus::gnumeric_cell_context context(cxt, orcus::gnumeric_tokens, &factory);
+ context.reset(&sheet);
+
+ orcus::xmlns_id_t ns = NS_gnumeric_gnm;
+ orcus::xml_token_t elem = XML_Cell;
+ orcus::xml_token_attrs_t attrs;
+
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Row, "5", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Col, "15", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_ExprID, "2", false));
+
+ context.start_element(ns, elem, attrs);
+ context.characters("=basicFormulaString", false);
+ context.end_element(ns, elem);
+}
+
+void test_shared_formula_without_string()
+{
+ class mock_formula_local : public import_formula
+ {
+ public:
+ void set_position(row_t row, col_t col) override
+ {
+ assert(row == 6);
+ assert(col == 16);
+ }
+
+ void set_shared_formula_index(size_t index) override
+ {
+ assert(index == 3);
+ }
+
+ void commit() override
+ {
+ }
+ };
+
+ class mock_sheet_local : public import_sheet
+ {
+ mock_formula_local m_formula;
+ public:
+ virtual iface::import_formula* get_formula()
+ {
+ return &m_formula;
+ }
+ };
+
+ mock_sheet_local sheet;
+ mock_factory factory;
+ session_context cxt;
+
+ orcus::gnumeric_cell_context context(cxt, orcus::gnumeric_tokens, &factory);
+ context.reset(&sheet);
+
+ orcus::xmlns_id_t ns = NS_gnumeric_gnm;
+ orcus::xml_token_t elem = XML_Cell;
+ orcus::xml_token_attrs_t attrs;
+
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Row, "6", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Col, "16", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_ExprID, "3", false));
+
+ context.start_element(ns, elem, attrs);
+ context.end_element(ns, elem);
+}
+
+void test_cell_formula()
+{
+ mock_sheet sheet;
+ mock_factory factory;
+ session_context cxt;
+
+ orcus::gnumeric_cell_context context(cxt, orcus::gnumeric_tokens, &factory);
+ context.reset(&sheet);
+
+ orcus::xmlns_id_t ns = NS_gnumeric_gnm;
+ orcus::xml_token_t elem = XML_Cell;
+ orcus::xml_token_attrs_t attrs;
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Row, "9", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Col, "11", false));
+ context.start_element(ns, elem, attrs);
+ context.characters("=formula", false);
+ context.end_element(ns, elem);
+}
+
+void test_cell_array_formula()
+{
+ mock_sheet sheet;
+ mock_factory factory;
+ session_context cxt;
+
+ orcus::gnumeric_cell_context context(cxt, orcus::gnumeric_tokens, &factory);
+ context.reset(&sheet);
+
+ orcus::xmlns_id_t ns = NS_gnumeric_gnm;
+ orcus::xml_token_t elem = XML_Cell;
+ orcus::xml_token_attrs_t attrs;
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Row, "19", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Col, "111", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Rows, "2", false));
+ attrs.push_back(xml_token_attr_t(NS_gnumeric_gnm, XML_Cols, "3", false));
+ context.start_element(ns, elem, attrs);
+ context.characters("arrayFormula", false);
+ context.end_element(ns, elem);
+}
+
+}
+
+int main()
+{
+ test_cell_value();
+ test_cell_bool();
+ test_cell_string();
+ test_shared_formula_with_string();
+ test_shared_formula_without_string();
+ test_cell_formula();
+ test_cell_array_formula();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_context.cpp b/src/liborcus/gnumeric_context.cpp
new file mode 100644
index 0000000..33c8d44
--- /dev/null
+++ b/src/liborcus/gnumeric_context.cpp
@@ -0,0 +1,453 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_context.hpp"
+#include "gnumeric_token_constants.hpp"
+#include "gnumeric_namespace_types.hpp"
+#include "gnumeric_sheet_context.hpp"
+#include "impl_utils.hpp"
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+
+#include <fstream>
+#include <algorithm>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+std::size_t import_font_style(ss::iface::import_styles& istyles, const gnumeric_style& style)
+{
+ ss::iface::import_font_style* ifont = istyles.start_font_style();
+ ENSURE_INTERFACE(ifont, import_font_style);
+
+ if (style.font_name)
+ ifont->set_name(*style.font_name);
+
+ if (style.font_unit)
+ ifont->set_size(*style.font_unit);
+
+ if (style.bold)
+ ifont->set_bold(*style.bold);
+
+ if (style.italic)
+ ifont->set_italic(*style.italic);
+
+ if (style.underline)
+ {
+ if (*style.underline)
+ ifont->set_underline(ss::underline_t::single_line);
+ else
+ ifont->set_underline(ss::underline_t::none);
+ }
+
+ if (style.strikethrough)
+ {
+ if (*style.strikethrough)
+ {
+ ifont->set_strikethrough_style(ss::strikethrough_style_t::solid);
+ ifont->set_strikethrough_type(ss::strikethrough_type_t::single_type);
+ ifont->set_strikethrough_width(ss::strikethrough_width_t::width_auto);
+ }
+ else
+ {
+ ifont->set_strikethrough_style(ss::strikethrough_style_t::none);
+ ifont->set_strikethrough_type(ss::strikethrough_type_t::none);
+ }
+ }
+
+ if (style.fore)
+ ifont->set_color(255, style.fore->red, style.fore->green, style.fore->blue);
+
+ return ifont->commit();
+}
+
+std::optional<std::size_t> import_fill_style(
+ ss::iface::import_styles& istyles, const gnumeric_style& style)
+{
+ if (style.pattern == ss::fill_pattern_t::none)
+ return {};
+
+ ss::iface::import_fill_style* ifill = istyles.start_fill_style();
+ ENSURE_INTERFACE(ifill, import_fill_style);
+
+ ifill->set_pattern_type(style.pattern);
+
+ if (style.back)
+ ifill->set_fg_color(
+ 255,
+ style.back->red,
+ style.back->green,
+ style.back->blue);
+
+ if (style.pattern_color)
+ ifill->set_bg_color(
+ 255,
+ style.pattern_color->red,
+ style.pattern_color->green,
+ style.pattern_color->blue);
+
+ return ifill->commit();
+}
+
+std::optional<std::size_t> import_border_styles(
+ ss::iface::import_styles& istyles, const gnumeric_style& style)
+{
+ ss::iface::import_border_style* iborder = istyles.start_border_style();
+ ENSURE_INTERFACE(iborder, import_border_style);
+
+ auto func_import_border = [&iborder](ss::border_direction_t dir, const gnumeric_style::border_type& border)
+ {
+ bool has_style = false;
+
+ if (border.style)
+ {
+ iborder->set_style(dir, to_standard_type(*border.style));
+ has_style = true;
+ }
+
+ if (border.color)
+ {
+ iborder->set_color(
+ dir, 255, border.color->red, border.color->green, border.color->blue);
+ has_style = true;
+ }
+
+ return has_style;
+ };
+
+ bool has_style = false;
+
+ if (func_import_border(ss::border_direction_t::top, style.border_top))
+ has_style = true;
+
+ if (func_import_border(ss::border_direction_t::bottom, style.border_bottom))
+ has_style = true;
+
+ if (func_import_border(ss::border_direction_t::left, style.border_left))
+ has_style = true;
+
+ if (func_import_border(ss::border_direction_t::right, style.border_right))
+ has_style = true;
+
+ if (func_import_border(ss::border_direction_t::diagonal_bl_tr, style.border_bl_tr))
+ has_style = true;
+
+ if (func_import_border(ss::border_direction_t::diagonal_tl_br, style.border_br_tl))
+ has_style = true;
+
+ if (!has_style)
+ return {};
+
+ return iborder->commit();
+}
+
+std::optional<std::size_t> import_number_format(
+ ss::iface::import_styles& istyles, const gnumeric_style& style)
+{
+ if (!style.number_format)
+ return {};
+
+ ss::iface::import_number_format* inumfmt = istyles.start_number_format();
+ ENSURE_INTERFACE(inumfmt, import_number_format);
+
+ inumfmt->set_code(*style.number_format);
+ return inumfmt->commit();
+}
+
+} // anonymous namespace
+
+gnumeric_content_xml_context::gnumeric_content_xml_context(
+ session_context& session_cxt, const tokens& tokens, spreadsheet::iface::import_factory* factory) :
+ xml_context_base(session_cxt, tokens),
+ mp_factory(factory),
+ m_sheet_pos(0),
+ m_cxt_names(session_cxt, tokens, factory),
+ m_cxt_sheet(session_cxt, tokens, factory)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_gnumeric_gnm, XML_Workbook }, // root element
+ { NS_gnumeric_gnm, XML_SheetNameIndex, NS_gnumeric_gnm, XML_SheetName },
+ { NS_gnumeric_gnm, XML_Sheets, NS_gnumeric_gnm, XML_Sheet },
+ { NS_gnumeric_gnm, XML_Workbook, NS_gnumeric_gnm, XML_Names },
+ { NS_gnumeric_gnm, XML_Workbook, NS_gnumeric_gnm, XML_SheetNameIndex },
+ { NS_gnumeric_gnm, XML_Workbook, NS_gnumeric_gnm, XML_Sheets },
+ };
+
+ init_element_validator(rules, std::size(rules));
+
+ register_child(&m_cxt_names);
+ register_child(&m_cxt_sheet);
+}
+
+gnumeric_content_xml_context::~gnumeric_content_xml_context() = default;
+
+xml_context_base* gnumeric_content_xml_context::create_child_context(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Sheet:
+ {
+ m_cxt_sheet.reset(m_sheet_pos++);
+ return &m_cxt_sheet;
+ }
+ case XML_Names:
+ {
+ m_cxt_names.reset();
+ return &m_cxt_names;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+void gnumeric_content_xml_context::end_child_context(
+ xmlns_id_t ns, xml_token_t name, xml_context_base* child)
+{
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Sheet:
+ {
+ assert(child == &m_cxt_sheet);
+ end_sheet();
+ break;
+ }
+ case XML_Names:
+ {
+ assert(child == &m_cxt_names);
+ end_names();
+ break;
+ }
+ }
+ }
+}
+
+void gnumeric_content_xml_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& /*attrs*/)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_SheetNameIndex:
+ m_sheet_pos = 0;
+ break;
+ case XML_SheetName:
+ break;
+ case XML_Sheets:
+ m_sheet_pos = 0;
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool gnumeric_content_xml_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Sheets:
+ end_sheets();
+ break;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void gnumeric_content_xml_context::characters(std::string_view str, bool /*transient*/)
+{
+ if (str.empty())
+ return;
+
+ const auto [ns, name] = get_current_element();
+
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_SheetName:
+ {
+ auto* p = mp_factory->append_sheet(m_sheet_pos++, str);
+ if (!p)
+ {
+ std::ostringstream os;
+ os << "failed to append a new sheet named '" << str << "'";
+ warn(os.str());
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+void gnumeric_content_xml_context::end_names()
+{
+ ss::iface::import_named_expression* named_exp = mp_factory->get_named_expression();
+ if (!named_exp)
+ return;
+
+ for (const auto& name : m_cxt_names.get_names())
+ {
+ try
+ {
+ named_exp->set_base_position(name.position);
+ named_exp->set_named_expression(name.name, name.value);
+ named_exp->commit();
+ }
+ catch (const std::exception& e)
+ {
+ std::ostringstream os;
+ os << "failed to commit a named expression named '" << name.name
+ << "': (reason='" << e.what() << "'; value='" << name.value << "')";
+ warn(os.str());
+ }
+ }
+}
+
+void gnumeric_content_xml_context::end_sheet()
+{
+ m_styles.push_back(m_cxt_sheet.pop_styles());
+}
+
+void gnumeric_content_xml_context::end_sheets()
+{
+ import_styles();
+}
+
+void gnumeric_content_xml_context::import_styles()
+{
+ ss::iface::import_styles* istyles = mp_factory->get_styles();
+ if (!istyles)
+ return;
+
+ std::size_t xf_count = 1; // one for the default style
+ for (const auto& sheet_styles : m_styles)
+ xf_count += sheet_styles.size();
+
+ istyles->set_xf_count(ss::xf_category_t::cell, xf_count);
+
+ import_default_styles(istyles);
+ import_cell_styles(istyles);
+}
+
+void gnumeric_content_xml_context::import_default_styles(ss::iface::import_styles* istyles)
+{
+ assert(istyles);
+
+ ss::iface::import_font_style* ifont = istyles->start_font_style();
+ ENSURE_INTERFACE(ifont, imort_font_style);
+ std::size_t id = ifont->commit();
+ assert(id == 0);
+
+ ss::iface::import_fill_style* ifill = istyles->start_fill_style();
+ ENSURE_INTERFACE(ifill, imort_fill_style);
+ id = ifill->commit();
+ assert(id == 0);
+
+ ss::iface::import_border_style* iborder = istyles->start_border_style();
+ ENSURE_INTERFACE(iborder, imort_border_style);
+ id = iborder->commit();
+ assert(id == 0);
+
+ ss::iface::import_cell_protection* iprotection = istyles->start_cell_protection();
+ ENSURE_INTERFACE(iprotection, imort_cell_protection);
+ id = iprotection->commit();
+ assert(id == 0);
+
+ ss::iface::import_number_format* inumfmt = istyles->start_number_format();
+ ENSURE_INTERFACE(inumfmt, import_number_format);
+ id = inumfmt->commit();
+ assert(id == 0);
+
+ ss::iface::import_xf* ixf = istyles->start_xf(ss::xf_category_t::cell);
+ ENSURE_INTERFACE(ixf, import_xf);
+ id = ixf->commit();
+ assert(id == 0);
+
+ ss::iface::import_cell_style* xstyle = istyles->start_cell_style();
+ ENSURE_INTERFACE(xstyle, import_cell_style);
+ xstyle->set_xf(0);
+ xstyle->commit();
+}
+
+void gnumeric_content_xml_context::import_cell_styles(ss::iface::import_styles* istyles)
+{
+ assert(istyles);
+
+ for (const auto& sheet_styles : m_styles)
+ {
+ for (const gnumeric_style& style : sheet_styles)
+ {
+ assert(style.valid()); // should be validated before insertion
+
+ ss::iface::import_sheet* isheet = mp_factory->get_sheet(style.sheet);
+ if (!isheet)
+ continue;
+
+ std::size_t id_font = import_font_style(*istyles, style);
+ auto id_fill = import_fill_style(*istyles, style);
+ auto id_border = import_border_styles(*istyles, style);
+ auto id_numfmt = import_number_format(*istyles, style);
+
+ ss::iface::import_xf* ixf = istyles->start_xf(ss::xf_category_t::cell);
+ ENSURE_INTERFACE(ixf, import_xf);
+
+ ixf->set_font(id_font);
+
+ if (id_fill)
+ ixf->set_fill(*id_fill);
+
+ if (id_border)
+ ixf->set_border(*id_border);
+
+ if (id_numfmt)
+ ixf->set_number_format(*id_numfmt);
+
+ bool apply_alignment =
+ style.hor_align != ss::hor_alignment_t::unknown ||
+ style.ver_align != ss::ver_alignment_t::unknown ||
+ style.wrap_text;
+
+ ixf->set_apply_alignment(apply_alignment);
+
+ if (style.hor_align != ss::hor_alignment_t::unknown)
+ ixf->set_horizontal_alignment(style.hor_align);
+
+ if (style.ver_align != ss::ver_alignment_t::unknown)
+ ixf->set_vertical_alignment(style.ver_align);
+
+ if (style.wrap_text)
+ ixf->set_wrap_text(*style.wrap_text);
+
+ std::size_t xfid = ixf->commit();
+ isheet->set_format(
+ style.region.first.row, style.region.first.column,
+ style.region.last.row, style.region.last.column,
+ xfid);
+ }
+ }
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_context.hpp b/src/liborcus/gnumeric_context.hpp
new file mode 100644
index 0000000..f6d066c
--- /dev/null
+++ b/src/liborcus/gnumeric_context.hpp
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_GNUMERICCONTEXT_HPP
+#define INCLUDED_ORCUS_GNUMERICCONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "gnumeric_sheet_context.hpp"
+#include "gnumeric_names_context.hpp"
+#include "gnumeric_types.hpp"
+
+#include <orcus/spreadsheet/types.hpp>
+
+#include <vector>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_factory;
+class import_sheet;
+class import_styles;
+
+}}
+
+class gnumeric_content_xml_context : public xml_context_base
+{
+public:
+ gnumeric_content_xml_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_factory* factory);
+
+ virtual ~gnumeric_content_xml_context() override;
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name) override;
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child) override;
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs) override;
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ virtual void characters(std::string_view str, bool transient) override;
+
+private:
+ void end_names();
+ void end_sheet();
+ void end_sheets();
+
+ void import_styles();
+ void import_default_styles(spreadsheet::iface::import_styles* istyles);
+ void import_cell_styles(spreadsheet::iface::import_styles* istyles);
+
+private:
+ spreadsheet::iface::import_factory* mp_factory;
+ spreadsheet::sheet_t m_sheet_pos;
+
+ gnumeric_names_context m_cxt_names;
+ gnumeric_sheet_context m_cxt_sheet;
+
+ std::vector<std::vector<gnumeric_style>> m_styles;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_detection_handler.cpp b/src/liborcus/gnumeric_detection_handler.cpp
new file mode 100644
index 0000000..1f0606e
--- /dev/null
+++ b/src/liborcus/gnumeric_detection_handler.cpp
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_detection_handler.hpp"
+#include "gnumeric_namespace_types.hpp"
+#include "gnumeric_token_constants.hpp"
+#include "xml_context_base.hpp"
+#include "detection_result.hpp"
+
+namespace orcus {
+
+namespace {
+
+/**
+ * Check the xml structure up to the first <gnm:Sheet> element. If all the
+ * structure check passes up to that point, we call it "detected".
+ */
+class gnumeric_detection_context : public xml_context_base
+{
+public:
+ gnumeric_detection_context(session_context& session_cxt, const tokens& tokens) :
+ xml_context_base(session_cxt, tokens) {}
+
+ virtual xml_context_base* create_child_context(xmlns_id_t, xml_token_t) { return nullptr; }
+ virtual void characters(std::string_view, bool) {}
+ virtual void end_child_context(xmlns_id_t, xml_token_t, xml_context_base*) {}
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& /*attrs*/)
+ {
+ xml_token_pair_t parent = push_stack(ns, name);
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Workbook:
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ break;
+ case XML_Version:
+ case XML_Attributes:
+ case XML_Calculation:
+ case XML_SheetNameIndex:
+ case XML_Geometry:
+ case XML_Sheets:
+ xml_element_expected(parent, NS_gnumeric_gnm, XML_Workbook);
+ break;
+ case XML_Attribute:
+ xml_element_expected(parent, NS_gnumeric_gnm, XML_Attributes);
+ break;
+ case XML_SheetName:
+ xml_element_expected(parent, NS_gnumeric_gnm, XML_SheetNameIndex);
+ break;
+ case XML_Sheet:
+ xml_element_expected(parent, NS_gnumeric_gnm, XML_Sheets);
+ throw detection_result(true);
+ break;
+ default:
+ ;
+ }
+ }
+ }
+
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name)
+ {
+ return pop_stack(ns, name);
+ }
+};
+
+}
+
+gnumeric_detection_handler::gnumeric_detection_handler(session_context& session_cxt, const tokens& t) :
+ xml_stream_handler(session_cxt, t, std::make_unique<gnumeric_detection_context>(session_cxt, t)) {}
+
+gnumeric_detection_handler::~gnumeric_detection_handler() {}
+
+void gnumeric_detection_handler::start_document() {}
+void gnumeric_detection_handler::end_document() {}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_detection_handler.hpp b/src/liborcus/gnumeric_detection_handler.hpp
new file mode 100644
index 0000000..e7644a3
--- /dev/null
+++ b/src/liborcus/gnumeric_detection_handler.hpp
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_GNUMERIC_DETECTION_HANDLER_HPP
+#define ORCUS_GNUMERIC_DETECTION_HANDLER_HPP
+
+#include "xml_stream_handler.hpp"
+
+namespace orcus {
+
+struct session_context;
+class tokens;
+
+class gnumeric_detection_handler : public xml_stream_handler
+{
+public:
+ gnumeric_detection_handler(session_context& session_cxt, const tokens& t);
+ virtual ~gnumeric_detection_handler();
+
+ virtual void start_document();
+ virtual void end_document();
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_filter_context.cpp b/src/liborcus/gnumeric_filter_context.cpp
new file mode 100644
index 0000000..f15d2a0
--- /dev/null
+++ b/src/liborcus/gnumeric_filter_context.cpp
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_filter_context.hpp"
+#include "gnumeric_token_constants.hpp"
+#include "gnumeric_namespace_types.hpp"
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/measurement.hpp>
+
+#include <iostream>
+#include <optional>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+enum gnumeric_filter_field_op_t
+{
+ filter_equal,
+ filter_greaterThan,
+ filter_lessThan,
+ filter_greaterThanEqual,
+ filter_lessThanEqual,
+ filter_notEqual,
+ filter_op_invalid
+};
+
+enum gnumeric_filter_field_type_t
+{
+ filter_expr,
+ filter_blanks,
+ filter_nonblanks,
+ filter_type_invalid
+};
+
+} // anonymous namespace
+
+gnumeric_filter_context::gnumeric_filter_context(
+ session_context& session_cxt, const tokens& tokens,
+ ss::iface::import_factory* factory) :
+ xml_context_base(session_cxt, tokens),
+ mp_factory(factory)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_gnumeric_gnm, XML_Filter }, // root element
+ { NS_gnumeric_gnm, XML_Filter, NS_gnumeric_gnm, XML_Field },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+gnumeric_filter_context::~gnumeric_filter_context() = default;
+
+void gnumeric_filter_context::start_element(
+ xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Filter:
+ {
+ start_filter(attrs);
+ break;
+ }
+ case XML_Field:
+ {
+ start_field(attrs);
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool gnumeric_filter_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Filter:
+ end_filter();
+ break;
+ case XML_Field:
+ end_field();
+ break;
+ }
+ }
+
+ return pop_stack(ns, name);
+}
+
+void gnumeric_filter_context::reset(spreadsheet::iface::import_sheet* sheet)
+{
+ mp_sheet = sheet;
+ mp_auto_filter = nullptr;
+}
+
+void gnumeric_filter_context::start_filter(const xml_token_attrs_t& attrs)
+{
+ if (!mp_sheet)
+ return;
+
+ ss::iface::import_reference_resolver* resolver =
+ mp_factory->get_reference_resolver(ss::formula_ref_context_t::global);
+
+ if (!resolver)
+ return;
+
+ mp_auto_filter = mp_sheet->get_auto_filter();
+ if (!mp_auto_filter)
+ return;
+
+ std::optional<spreadsheet::range_t> area;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_Area:
+ area = to_rc_range(resolver->resolve_range(attr.value));
+ break;
+ default:
+ ;
+ }
+ }
+
+ if (!area)
+ {
+ mp_auto_filter = nullptr;
+ return;
+ }
+
+ mp_auto_filter->set_range(*area);
+}
+
+void gnumeric_filter_context::start_field(const xml_token_attrs_t& attrs)
+{
+ if (!mp_auto_filter)
+ return;
+
+ gnumeric_filter_field_type_t filter_field_type = filter_type_invalid;
+ gnumeric_filter_field_op_t filter_op = filter_op_invalid;
+
+ ss::col_t col = -1;
+ std::string_view filter_value_type;
+ std::string_view filter_value;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_Index:
+ {
+ col = to_long(attr.value.data());
+ break;
+ }
+ case XML_Type:
+ {
+ if (attr.value == "expr")
+ filter_field_type = filter_expr;
+ else if (attr.value == "blanks")
+ filter_field_type = filter_blanks;
+ else if (attr.value == "nonblanks")
+ filter_field_type = filter_nonblanks;
+ break;
+ }
+ case XML_Op0:
+ {
+ if (attr.value == "eq")
+ filter_op = filter_equal;
+ else if (attr.value == "gt")
+ filter_op = filter_greaterThan;
+ else if (attr.value == "lt")
+ filter_op = filter_lessThan;
+ else if (attr.value == "gte")
+ filter_op = filter_greaterThanEqual;
+ else if (attr.value == "lte")
+ filter_op = filter_lessThanEqual;
+ else if (attr.value == "ne")
+ filter_op = filter_notEqual;
+ break;
+ }
+ case XML_Value0:
+ {
+ filter_value_type = attr.value;
+ break;
+ }
+ case XML_ValueType0:
+ {
+ filter_value = attr.value;
+ break;
+ }
+ }
+ }
+
+ if (col < 0)
+ return;
+
+ mp_auto_filter->set_column(col);
+
+ switch (filter_field_type)
+ {
+ case filter_expr:
+ {
+ // only equal supported in API yet
+ if (filter_op != filter_equal)
+ return;
+
+ // import condition for integer (30), double(40) and string (60)
+ if (filter_value_type == "30" ||
+ filter_value_type == "40" ||
+ filter_value_type == "60" )
+ {
+ mp_auto_filter->append_column_match_value(filter_value);
+ }
+ break;
+ }
+ case filter_blanks:
+ break;
+ case filter_nonblanks:
+ break;
+ case filter_type_invalid:
+ break;
+ }
+}
+
+void gnumeric_filter_context::end_filter()
+{
+ if (mp_auto_filter)
+ mp_auto_filter->commit();
+}
+
+void gnumeric_filter_context::end_field()
+{
+ if (mp_auto_filter)
+ mp_auto_filter->commit_column();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_filter_context.hpp b/src/liborcus/gnumeric_filter_context.hpp
new file mode 100644
index 0000000..b8c794b
--- /dev/null
+++ b/src/liborcus/gnumeric_filter_context.hpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "xml_context_base.hpp"
+
+#include <orcus/spreadsheet/types.hpp>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_factory;
+class import_sheet;
+class import_auto_filter;
+
+}}
+
+class gnumeric_filter_context : public xml_context_base
+{
+public:
+ gnumeric_filter_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_factory* factory);
+ virtual ~gnumeric_filter_context() override;
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+
+ void reset(spreadsheet::iface::import_sheet* sheet);
+
+private:
+ void start_filter(const xml_token_attrs_t& attrs);
+ void start_field(const xml_token_attrs_t& attrs);
+
+ void end_filter();
+ void end_field();
+
+
+private:
+ spreadsheet::iface::import_factory* mp_factory = nullptr;
+ spreadsheet::iface::import_sheet* mp_sheet = nullptr;
+ spreadsheet::iface::import_auto_filter* mp_auto_filter = nullptr;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_handler.cpp b/src/liborcus/gnumeric_handler.cpp
new file mode 100644
index 0000000..67e428f
--- /dev/null
+++ b/src/liborcus/gnumeric_handler.cpp
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_handler.hpp"
+#include "gnumeric_context.hpp"
+
+namespace orcus {
+
+gnumeric_content_xml_handler::gnumeric_content_xml_handler(
+ session_context& session_cxt, const tokens& t, spreadsheet::iface::import_factory* factory) :
+ xml_stream_handler(session_cxt, t, std::make_unique<gnumeric_content_xml_context>(session_cxt, t, factory))
+{
+}
+
+gnumeric_content_xml_handler::~gnumeric_content_xml_handler()
+{
+}
+
+void gnumeric_content_xml_handler::start_document()
+{
+}
+
+void gnumeric_content_xml_handler::end_document()
+{
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_handler.hpp b/src/liborcus/gnumeric_handler.hpp
new file mode 100644
index 0000000..1c389c3
--- /dev/null
+++ b/src/liborcus/gnumeric_handler.hpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_GNUMERICHANDLER_HPP__
+#define __ORCUS_GNUMERICHANDLER_HPP__
+
+#include "xml_stream_handler.hpp"
+
+namespace orcus {
+
+struct session_context;
+class tokens;
+
+namespace spreadsheet { namespace iface { class import_factory; }}
+
+/**
+ * Handler for parsing the content.xml part.
+ */
+class gnumeric_content_xml_handler : public xml_stream_handler
+{
+public:
+ gnumeric_content_xml_handler(session_context& session_cxt, const tokens& t, spreadsheet::iface::import_factory* factory);
+ virtual ~gnumeric_content_xml_handler();
+
+ virtual void start_document();
+ virtual void end_document();
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_names_context.cpp b/src/liborcus/gnumeric_names_context.cpp
new file mode 100644
index 0000000..9c008af
--- /dev/null
+++ b/src/liborcus/gnumeric_names_context.cpp
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_names_context.hpp"
+#include "gnumeric_token_constants.hpp"
+#include "gnumeric_namespace_types.hpp"
+
+#include <orcus/spreadsheet/import_interface.hpp>
+
+#include <iostream>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+gnumeric_names_context::gnumeric_names_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_factory* factory) :
+ xml_context_base(session_cxt, tokens),
+ mp_factory(factory)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_gnumeric_gnm, XML_Names }, // root element
+ { NS_gnumeric_gnm, XML_Names, NS_gnumeric_gnm, XML_Name },
+ { NS_gnumeric_gnm, XML_Name, NS_gnumeric_gnm, XML_name },
+ { NS_gnumeric_gnm, XML_Name, NS_gnumeric_gnm, XML_value },
+ { NS_gnumeric_gnm, XML_Name, NS_gnumeric_gnm, XML_position },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+gnumeric_names_context::~gnumeric_names_context() = default;
+
+void gnumeric_names_context::start_element(
+ xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& /*attrs*/)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Name:
+ m_current_name.reset();
+ break;
+ }
+ }
+}
+
+bool gnumeric_names_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Name:
+ m_named_exps.push_back(m_current_name);
+ break;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void gnumeric_names_context::characters(std::string_view str, bool transient)
+{
+ const auto [ns, name] = get_current_element();
+
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_name:
+ m_current_name.name = transient ? intern(str) : str;
+ break;
+ case XML_value:
+ m_current_name.value = transient ? intern(str) : str;
+ break;
+ case XML_position:
+ {
+ ss::iface::import_reference_resolver* resolver =
+ mp_factory->get_reference_resolver(ss::formula_ref_context_t::global);
+
+ if (resolver)
+ m_current_name.position = resolver->resolve_address(str);
+
+ break;
+ }
+ }
+ }
+}
+
+void gnumeric_names_context::reset()
+{
+ m_named_exps.clear();
+}
+
+const std::vector<gnumeric_named_exp>& gnumeric_names_context::get_names() const
+{
+ return m_named_exps;
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_names_context.hpp b/src/liborcus/gnumeric_names_context.hpp
new file mode 100644
index 0000000..1fb0416
--- /dev/null
+++ b/src/liborcus/gnumeric_names_context.hpp
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "xml_context_base.hpp"
+#include "gnumeric_types.hpp"
+
+#include <vector>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_factory;
+
+}}
+
+class gnumeric_names_context : public xml_context_base
+{
+public:
+ gnumeric_names_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_factory* factory);
+
+ virtual ~gnumeric_names_context() override;
+
+ virtual void start_element(
+ xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ virtual void characters(std::string_view str, bool transient) override;
+
+ void reset();
+
+ const std::vector<gnumeric_named_exp>& get_names() const;
+
+private:
+ spreadsheet::iface::import_factory* mp_factory = nullptr;
+ std::vector<gnumeric_named_exp> m_named_exps;
+ gnumeric_named_exp m_current_name;
+};
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_namespace_types.cpp b/src/liborcus/gnumeric_namespace_types.cpp
new file mode 100644
index 0000000..1ff0ec9
--- /dev/null
+++ b/src/liborcus/gnumeric_namespace_types.cpp
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_namespace_types.hpp"
+#include "odf_namespace_types.hpp"
+
+namespace orcus {
+
+const xmlns_id_t NS_gnumeric_dc = "http://purl.org/dc/elements/1.1/";
+const xmlns_id_t NS_gnumeric_gnm = "http://www.gnumeric.org/v10.dtd";
+const xmlns_id_t NS_gnumeric_ooo = "http://openoffice.org/2004/office";
+const xmlns_id_t NS_gnumeric_xlink = "http://www.w3.org/1999/xlink";
+const xmlns_id_t NS_gnumeric_xsi = "http://www.w3.org/2001/XMLSchema-instance";
+
+namespace {
+
+xmlns_id_t gnumeric_ns[] = {
+ NS_gnumeric_dc,
+ NS_gnumeric_gnm,
+ NS_gnumeric_ooo,
+ NS_gnumeric_xlink,
+ NS_gnumeric_xsi,
+
+ NS_odf_meta,
+ NS_odf_office,
+ nullptr
+};
+
+}
+
+const xmlns_id_t* NS_gnumeric_all = gnumeric_ns;
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_namespace_types.hpp b/src/liborcus/gnumeric_namespace_types.hpp
new file mode 100644
index 0000000..2d6b7ab
--- /dev/null
+++ b/src/liborcus/gnumeric_namespace_types.hpp
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_GNUMERIC_NAMESPACE_TYPES_HPP__
+#define __ORCUS_GNUMERIC_NAMESPACE_TYPES_HPP__
+
+#include "orcus/types.hpp"
+
+namespace orcus {
+
+extern const xmlns_id_t NS_gnumeric_dc;
+extern const xmlns_id_t NS_gnumeric_gnm;
+extern const xmlns_id_t NS_gnumeric_ooo;
+extern const xmlns_id_t NS_gnumeric_xlink;
+extern const xmlns_id_t NS_gnumeric_xsi;
+
+extern const xmlns_id_t* NS_gnumeric_all;
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_sheet_context.cpp b/src/liborcus/gnumeric_sheet_context.cpp
new file mode 100644
index 0000000..aecca4c
--- /dev/null
+++ b/src/liborcus/gnumeric_sheet_context.cpp
@@ -0,0 +1,819 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_sheet_context.hpp"
+#include "gnumeric_cell_context.hpp"
+#include "gnumeric_token_constants.hpp"
+#include "gnumeric_namespace_types.hpp"
+#include "impl_utils.hpp"
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+#include <orcus/measurement.hpp>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+ss::condition_operator_t get_condition_operator(int val)
+{
+ switch (val)
+ {
+ case 0:
+ return ss::condition_operator_t::between;
+ case 1:
+ return ss::condition_operator_t::not_between;
+ case 2:
+ return ss::condition_operator_t::equal;
+ case 3:
+ return ss::condition_operator_t::not_equal;
+ case 4:
+ return ss::condition_operator_t::greater;
+ case 5:
+ return ss::condition_operator_t::less;
+ case 6:
+ return ss::condition_operator_t::greater_equal;
+ case 7:
+ return ss::condition_operator_t::less_equal;
+ case 8:
+ return ss::condition_operator_t::expression;
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ break;
+ case 16:
+ return ss::condition_operator_t::contains;
+ case 17:
+ return ss::condition_operator_t::not_contains;
+ case 18:
+ return ss::condition_operator_t::begins_with;
+ case 19:
+ break;
+ case 20:
+ return ss::condition_operator_t::ends_with;
+ case 21:
+ break;
+ case 22:
+ return ss::condition_operator_t::contains_error;
+ case 23:
+ return ss::condition_operator_t::contains_no_error;
+ default:
+ break;
+ }
+ return ss::condition_operator_t::unknown;
+}
+
+} // anonymous namespace
+
+gnumeric_sheet_context::gnumeric_sheet_context(
+ session_context& session_cxt, const tokens& tokens, ss::iface::import_factory* factory) :
+ xml_context_base(session_cxt, tokens),
+ mp_factory(factory),
+ m_cxt_cell(session_cxt, tokens, factory),
+ m_cxt_filter(session_cxt, tokens, factory),
+ m_cxt_names(session_cxt, tokens, factory),
+ m_cxt_styles(session_cxt, tokens, factory)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_gnumeric_gnm, XML_Sheet }, // root element
+ { NS_gnumeric_gnm, XML_Cells, NS_gnumeric_gnm, XML_Cell },
+ { NS_gnumeric_gnm, XML_Cols, NS_gnumeric_gnm, XML_ColInfo },
+ { NS_gnumeric_gnm, XML_MergedRegions, NS_gnumeric_gnm, XML_Merge },
+ { NS_gnumeric_gnm, XML_Rows, NS_gnumeric_gnm, XML_RowInfo },
+ { NS_gnumeric_gnm, XML_Sheet, NS_gnumeric_gnm, XML_Cells },
+ { NS_gnumeric_gnm, XML_Sheet, NS_gnumeric_gnm, XML_Cols },
+ { NS_gnumeric_gnm, XML_Sheet, NS_gnumeric_gnm, XML_Filters },
+ { NS_gnumeric_gnm, XML_Sheet, NS_gnumeric_gnm, XML_MergedRegions },
+ { NS_gnumeric_gnm, XML_Sheet, NS_gnumeric_gnm, XML_Name },
+ { NS_gnumeric_gnm, XML_Sheet, NS_gnumeric_gnm, XML_Names },
+ { NS_gnumeric_gnm, XML_Sheet, NS_gnumeric_gnm, XML_Rows },
+ { NS_gnumeric_gnm, XML_Sheet, NS_gnumeric_gnm, XML_Selections },
+ { NS_gnumeric_gnm, XML_Sheet, NS_gnumeric_gnm, XML_SheetLayout },
+ { NS_gnumeric_gnm, XML_Sheet, NS_gnumeric_gnm, XML_Styles },
+ };
+
+ init_element_validator(rules, std::size(rules));
+
+ register_child(&m_cxt_cell);
+ register_child(&m_cxt_filter);
+ register_child(&m_cxt_names);
+ register_child(&m_cxt_styles);
+}
+
+gnumeric_sheet_context::~gnumeric_sheet_context() = default;
+
+xml_context_base* gnumeric_sheet_context::create_child_context(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Cells:
+ {
+ m_cxt_cell.reset(mp_sheet);
+ return &m_cxt_cell;
+ }
+ case XML_Filter:
+ {
+ m_cxt_filter.reset(mp_sheet);
+ return &m_cxt_filter;
+ }
+ case XML_Names:
+ {
+ m_cxt_names.reset();
+ return &m_cxt_names;
+ }
+ case XML_Styles:
+ {
+ m_cxt_styles.reset(m_sheet);
+ return &m_cxt_styles;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+void gnumeric_sheet_context::end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child)
+{
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Names:
+ {
+ assert(child == &m_cxt_names);
+ end_names();
+ break;
+ }
+ case XML_Styles:
+ {
+ assert(child == &m_cxt_styles);
+ end_styles();
+ break;
+ }
+ }
+ }
+}
+
+void gnumeric_sheet_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Font:
+ start_font(attrs);
+ break;
+ case XML_Merge:
+ m_merge_area = std::string_view{};
+ break;
+ case XML_Name:
+ start_name(attrs);
+ break;
+ case XML_Style:
+ start_style(attrs);
+ break;
+ case XML_StyleRegion:
+ start_style_region(attrs);
+ break;
+ case XML_ColInfo:
+ start_col(attrs);
+ break;
+ case XML_RowInfo:
+ start_row(attrs);
+ break;
+ case XML_Condition:
+ {
+ if (!m_region_data->contains_conditional_format)
+ {
+ m_region_data->contains_conditional_format = true;
+ end_style(false);
+ }
+ start_condition(attrs);
+ break;
+ }
+ case XML_Expression0:
+ case XML_Expression1:
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool gnumeric_sheet_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch(name)
+ {
+ case XML_Font:
+ end_font();
+ break;
+ case XML_Merge:
+ end_merge();
+ break;
+ case XML_Name:
+ end_name();
+ break;
+ case XML_Style:
+ {
+ xml_token_pair_t parent = get_parent_element();
+ if (parent.second == XML_Condition)
+ {
+ end_style(true);
+ }
+ else
+ {
+ // The conditional format entry contains a mandatory style element
+ // Therefore when we have a conditional format the end_style method
+ // is already called in start_element of the XML_Condition case.
+ if (!m_region_data->contains_conditional_format)
+ {
+ end_style(false);
+ }
+ }
+ break;
+ }
+ case XML_StyleRegion:
+ end_style_region();
+ break;
+ case XML_Condition:
+ end_condition();
+ break;
+ case XML_Expression0:
+ case XML_Expression1:
+ end_expression();
+ break;
+ }
+ }
+
+ return pop_stack(ns, name);
+}
+
+void gnumeric_sheet_context::characters(std::string_view str, bool transient)
+{
+ const auto [ns, name] = get_current_element();
+
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Merge:
+ {
+ m_merge_area = transient ? intern(str) : str;
+ break;
+ }
+ case XML_Name:
+ {
+ m_name = transient ? intern(str) : str;
+ break;
+ }
+ default:
+ m_chars = transient ? intern(str) : str;
+ }
+ }
+ else
+ {
+ m_chars = transient ? intern(str) : str;
+ }
+}
+
+void gnumeric_sheet_context::reset(ss::sheet_t sheet)
+{
+ mp_sheet = nullptr;
+ mp_xf = nullptr;
+ m_sheet = sheet;
+
+ m_region_data.reset();
+
+ m_front_color.red = 0;
+ m_front_color.green = 0;
+ m_front_color.blue = 0;
+
+ m_chars = std::string_view{};
+ m_name = std::string_view{};
+ m_merge_area = std::string_view{};
+}
+
+std::vector<gnumeric_style> gnumeric_sheet_context::pop_styles()
+{
+ return std::move(m_styles);
+}
+
+void gnumeric_sheet_context::start_font(const xml_token_attrs_t& attrs)
+{
+ auto* styles = mp_factory->get_styles();
+ if (!styles)
+ return;
+
+ auto* font_style = styles->start_font_style();
+ ENSURE_INTERFACE(font_style, import_font_style);
+
+ for (const auto& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_Unit:
+ {
+ double n = atoi(attr.value.data());
+ font_style->set_size(n);
+ break;
+ }
+ case XML_Bold:
+ {
+ bool b = atoi(attr.value.data()) != 0;
+ font_style->set_bold(b);
+ break;
+ }
+ case XML_Italic:
+ {
+ bool b = atoi(attr.value.data()) != 0;
+ font_style->set_italic(b);
+ break;
+ }
+ case XML_Underline:
+ {
+ int n = atoi(attr.value.data());
+ switch (n)
+ {
+ case 0:
+ font_style->set_underline(ss::underline_t::none);
+ break;
+ case 1:
+ font_style->set_underline(ss::underline_t::single_line);
+ break;
+ case 2:
+ font_style->set_underline(ss::underline_t::double_line);
+ break;
+ }
+ break;
+ }
+ }
+ }
+}
+
+void gnumeric_sheet_context::start_col(const xml_token_attrs_t& attrs)
+{
+ if (!mp_sheet)
+ return;
+
+ ss::iface::import_sheet_properties* sheet_props = mp_sheet->get_sheet_properties();
+ if (!sheet_props)
+ return;
+
+ long col = 0;
+ long col_span = 1;
+ double col_width = 0.0;
+ bool col_hidden = false;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_No:
+ {
+ col = to_long(attr.value);
+ break;
+ }
+ case XML_Unit:
+ {
+ col_width = to_double(attr.value);
+ break;
+ }
+ case XML_Count:
+ {
+ col_span = to_long(attr.value);
+ break;
+ }
+ case XML_Hidden:
+ {
+ col_hidden = to_bool(attr.value);
+ break;
+ }
+ }
+ }
+
+ sheet_props->set_column_width(col, col_span, col_width, length_unit_t::point);
+ sheet_props->set_column_hidden(col, col_span, col_hidden);
+}
+
+void gnumeric_sheet_context::start_row(const xml_token_attrs_t& attrs)
+{
+ if (!mp_sheet)
+ return;
+
+ ss::iface::import_sheet_properties* sheet_props = mp_sheet->get_sheet_properties();
+ if (!sheet_props)
+ return;
+
+ long row = 0;
+ long row_span = 1;
+ double row_height = 0.0;
+ bool row_hidden = false;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_No:
+ {
+ row = to_long(attr.value);
+ break;
+ }
+ case XML_Unit:
+ {
+ row_height = to_double(attr.value);
+ break;
+ }
+ case XML_Count:
+ {
+ row_span = to_long(attr.value);
+ break;
+ }
+ case XML_Hidden:
+ {
+ row_hidden = to_bool(attr.value);
+ break;
+ }
+ }
+ }
+
+ for (long i = 0; i < row_span; ++i)
+ {
+ sheet_props->set_row_height(row + i, row_height, length_unit_t::point);
+ sheet_props->set_row_hidden(row + i, row_hidden);
+ }
+}
+
+void gnumeric_sheet_context::start_style(const xml_token_attrs_t& attrs)
+{
+ auto* styles = mp_factory->get_styles();
+ if (!styles)
+ return;
+
+ auto* fill_style = styles->start_fill_style();
+ ENSURE_INTERFACE(fill_style, import_fill_style);
+
+ auto* cell_protection = styles->start_cell_protection();
+ ENSURE_INTERFACE(cell_protection, import_cell_protection);
+
+ auto* number_format = styles->start_number_format();
+ ENSURE_INTERFACE(number_format, import_number_format);
+
+ mp_xf = styles->start_xf(ss::xf_category_t::cell);
+ ENSURE_INTERFACE(mp_xf, import_xf);
+
+ bool fill_set = false;
+ bool protection_set = false;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_Fore:
+ {
+ auto color = parse_gnumeric_rgb(attr.value);
+ if (!color)
+ break;
+
+ fill_style->set_fg_color(255, color->red, color->green, color->blue);
+ fill_set = true;
+ m_front_color = *color;
+ break;
+ }
+ case XML_Back:
+ {
+ auto color = parse_gnumeric_rgb(attr.value);
+ if (!color)
+ break;
+
+ fill_style->set_bg_color(255, color->red, color->green, color->blue);
+ fill_set = true;
+ break;
+ }
+ case XML_Hidden:
+ {
+ bool b = atoi(attr.value.data());
+ cell_protection->set_hidden(b);
+
+ protection_set = true;
+ break;
+ }
+ case XML_Locked:
+ {
+ bool b = atoi(attr.value.data());
+ cell_protection->set_locked(b);
+
+ protection_set = true;
+ break;
+ }
+ case XML_Format:
+ {
+ if (attr.value != "General")
+ {
+ number_format->set_code(attr.value);
+ std::size_t index = number_format->commit();
+ mp_xf->set_number_format(index);
+ }
+ break;
+ }
+ case XML_HAlign:
+ {
+ ss::hor_alignment_t hor_alignment = ss::hor_alignment_t::unknown;
+ if (attr.value == "GNM_HALIGN_CENTER")
+ hor_alignment = ss::hor_alignment_t::center;
+ else if (attr.value == "GNM_HALIGN_RIGHT")
+ hor_alignment = ss::hor_alignment_t::right;
+ else if (attr.value == "GNM_HALIGN_LEFT")
+ hor_alignment = ss::hor_alignment_t::left;
+ else if (attr.value == "GNM_HALIGN_JUSTIFY")
+ hor_alignment = ss::hor_alignment_t::justified;
+ else if (attr.value == "GNM_HALIGN_DISTRIBUTED")
+ hor_alignment = ss::hor_alignment_t::distributed;
+ else if (attr.value == "GNM_HALIGN_FILL")
+ hor_alignment = ss::hor_alignment_t::filled;
+
+ if (hor_alignment != ss::hor_alignment_t::unknown)
+ mp_xf->set_apply_alignment(true);
+ mp_xf->set_horizontal_alignment(hor_alignment);
+ break;
+ }
+ case XML_VAlign:
+ {
+ ss::ver_alignment_t ver_alignment = ss::ver_alignment_t::unknown;
+ if (attr.value == "GNM_VALIGN_BOTTOM")
+ ver_alignment = ss::ver_alignment_t::bottom;
+ else if (attr.value == "GNM_VALIGN_TOP")
+ ver_alignment = ss::ver_alignment_t::top;
+ else if (attr.value == "GNM_VALIGN_CENTER")
+ ver_alignment = ss::ver_alignment_t::middle;
+ else if (attr.value == "GNM_VALIGN_JUSTIFY")
+ ver_alignment = ss::ver_alignment_t::justified;
+ else if (attr.value == "GNM_VALIGN_DISTRIBUTED")
+ ver_alignment = ss::ver_alignment_t::distributed;
+
+ if (ver_alignment != ss::ver_alignment_t::unknown)
+ mp_xf->set_apply_alignment(true);
+ mp_xf->set_vertical_alignment(ver_alignment);
+ break;
+ }
+ }
+ }
+
+ if (fill_set)
+ {
+ size_t fill_id = fill_style->commit();
+ mp_xf->set_fill(fill_id);
+ }
+ if (protection_set)
+ {
+ size_t protection_id = cell_protection->commit();
+ mp_xf->set_protection(protection_id);
+ }
+}
+
+void gnumeric_sheet_context::start_style_region(const xml_token_attrs_t& attrs)
+{
+ m_region_data = style_region{};
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_startCol:
+ {
+ size_t n = atoi(attr.value.data());
+ m_region_data->start_col = n;
+ break;
+ }
+ case XML_startRow:
+ {
+ size_t n = atoi(attr.value.data());
+ m_region_data->start_row = n;
+ break;
+ }
+ case XML_endCol:
+ {
+ size_t n = atoi(attr.value.data());
+ m_region_data->end_col = n;
+ break;
+ }
+ case XML_endRow:
+ {
+ size_t n = atoi(attr.value.data());
+ m_region_data->end_row = n;
+ break;
+ }
+ default:
+ ;
+ }
+ }
+}
+
+void gnumeric_sheet_context::start_condition(const xml_token_attrs_t& attrs)
+{
+ if (!mp_sheet)
+ return;
+
+ ss::iface::import_conditional_format* cond_format =
+ mp_sheet->get_conditional_format();
+
+ if (!cond_format)
+ return;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_Operator:
+ {
+ int val = atoi(attr.value.data());
+ ss::condition_operator_t op = get_condition_operator(val);
+ cond_format->set_operator(op);
+ break;
+ }
+ }
+ }
+}
+
+void gnumeric_sheet_context::start_name(const xml_token_attrs_t& /*attrs*/)
+{
+ m_name = std::string_view{};
+}
+
+void gnumeric_sheet_context::end_font()
+{
+ ss::iface::import_styles* styles = mp_factory->get_styles();
+ if (!styles)
+ return;
+
+ auto* font_style = styles->start_font_style();
+ ENSURE_INTERFACE(font_style, import_font_style);
+
+ font_style->set_color(0, m_front_color.red, m_front_color.green, m_front_color.blue);
+ font_style->set_name(m_chars);
+ size_t font_id = font_style->commit();
+
+ assert(mp_xf);
+ mp_xf->set_font(font_id);
+}
+
+void gnumeric_sheet_context::end_style(bool conditional_format)
+{
+ ss::iface::import_styles* styles = mp_factory->get_styles();
+ if (!styles)
+ return;
+
+ assert(mp_xf);
+ size_t xf_id = mp_xf->commit();
+ if (!conditional_format)
+ {
+ m_region_data->xf_id = xf_id;
+ }
+ else if (mp_sheet)
+ {
+ ss::iface::import_conditional_format* cond_format =
+ mp_sheet->get_conditional_format();
+ if (cond_format)
+ {
+ cond_format->set_xf_id(xf_id);
+ }
+ }
+}
+
+void gnumeric_sheet_context::end_style_region()
+{
+ if (!mp_sheet)
+ return;
+
+ mp_sheet->set_format(m_region_data->start_row, m_region_data->start_col,
+ m_region_data->end_row, m_region_data->end_col, m_region_data->xf_id);
+
+ if (m_region_data->contains_conditional_format)
+ {
+ ss::iface::import_conditional_format* cond_format =
+ mp_sheet->get_conditional_format();
+ if (cond_format)
+ {
+ cond_format->set_range(m_region_data->start_row, m_region_data->start_col,
+ m_region_data->end_row, m_region_data->end_col);
+ cond_format->commit_format();
+ }
+ }
+ m_region_data.reset();
+}
+
+void gnumeric_sheet_context::end_condition()
+{
+ if (!mp_sheet)
+ return;
+
+ ss::iface::import_conditional_format* cond_format =
+ mp_sheet->get_conditional_format();
+ if (cond_format)
+ {
+ cond_format->commit_entry();
+ }
+}
+
+void gnumeric_sheet_context::end_expression()
+{
+ if (!mp_sheet)
+ return;
+
+ ss::iface::import_conditional_format* cond_format =
+ mp_sheet->get_conditional_format();
+ if (cond_format)
+ {
+ cond_format->set_formula(m_chars);
+ cond_format->commit_condition();
+ }
+}
+
+void gnumeric_sheet_context::end_merge()
+{
+ if (!mp_sheet || m_merge_area.empty())
+ return;
+
+ auto* sp = mp_sheet->get_sheet_properties();
+ if (!sp)
+ return;
+
+ auto* resolver = mp_factory->get_reference_resolver(ss::formula_ref_context_t::global);
+ if (!resolver)
+ return;
+
+ try
+ {
+ ss::range_t range = to_rc_range(resolver->resolve_range(m_merge_area));
+ sp->set_merge_cell_range(range);
+ }
+ catch (const invalid_arg_error& e)
+ {
+ std::ostringstream os;
+ os << "failed to parse a merged area '" << m_merge_area << "': " << e.what();
+ warn(os.str());
+ }
+}
+
+void gnumeric_sheet_context::end_name()
+{
+ if (m_name.empty())
+ return;
+
+ mp_sheet = mp_factory->get_sheet(m_name);
+ m_name = std::string_view{};
+}
+
+void gnumeric_sheet_context::end_names()
+{
+ if (!mp_sheet)
+ return;
+
+ ss::iface::import_named_expression* named_exp = mp_sheet->get_named_expression();
+ if (!named_exp)
+ return;
+
+ for (const auto& name : m_cxt_names.get_names())
+ {
+ try
+ {
+ named_exp->set_base_position(name.position);
+ named_exp->set_named_expression(name.name, name.value);
+ named_exp->commit();
+ }
+ catch (const std::exception& e)
+ {
+ std::ostringstream os;
+ os << "failed to commit a named expression named '" << name.name
+ << "': (reason='" << e.what() << "'; value='" << name.value << "')";
+ warn(os.str());
+ }
+ }
+}
+
+void gnumeric_sheet_context::end_styles()
+{
+ m_styles = m_cxt_styles.pop_styles();
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_sheet_context.hpp b/src/liborcus/gnumeric_sheet_context.hpp
new file mode 100644
index 0000000..70b8f89
--- /dev/null
+++ b/src/liborcus/gnumeric_sheet_context.hpp
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_GNUMERIC_SHEET_CONTEXT_HPP
+#define INCLUDED_ORCUS_GNUMERIC_SHEET_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "gnumeric_cell_context.hpp"
+#include "gnumeric_filter_context.hpp"
+#include "gnumeric_names_context.hpp"
+#include "gnumeric_styles_context.hpp"
+#include "gnumeric_types.hpp"
+
+#include <orcus/spreadsheet/types.hpp>
+
+#include <memory>
+#include <optional>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_factory;
+class import_sheet;
+class import_auto_filter;
+class import_xf;
+
+}}
+
+class gnumeric_sheet_context : public xml_context_base
+{
+ struct style_region
+ {
+ spreadsheet::row_t start_row = 0;
+ spreadsheet::row_t end_row = 0;
+ spreadsheet::col_t start_col = 0;
+ spreadsheet::col_t end_col = 0;
+
+ std::size_t xf_id = 0;
+ bool contains_conditional_format = false;
+ };
+
+public:
+ gnumeric_sheet_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_factory* factory);
+
+ virtual ~gnumeric_sheet_context() override;
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name) override;
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child) override;
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs) override;
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ virtual void characters(std::string_view str, bool transient) override;
+
+ void reset(spreadsheet::sheet_t sheet);
+
+ std::vector<gnumeric_style> pop_styles();
+
+private:
+ void start_style_region(const xml_token_attrs_t& attrs);
+ void start_style(const xml_token_attrs_t& attrs);
+ void start_font(const xml_token_attrs_t& attrs);
+ void start_col(const xml_token_attrs_t& attrs);
+ void start_row(const xml_token_attrs_t& attrs);
+ void start_condition(const xml_token_attrs_t& attrs);
+ void start_name(const xml_token_attrs_t& attrs);
+
+ void end_style(bool conditional_format);
+ void end_font();
+ void end_style_region();
+ void end_condition();
+ void end_expression();
+ void end_merge();
+ void end_name();
+ void end_names();
+ void end_styles();
+
+private:
+ spreadsheet::iface::import_factory* mp_factory = nullptr;
+ spreadsheet::iface::import_sheet* mp_sheet = nullptr;
+ spreadsheet::iface::import_xf* mp_xf = nullptr;
+ spreadsheet::sheet_t m_sheet = -1;
+
+ std::optional<style_region> m_region_data;
+
+ spreadsheet::color_rgb_t m_front_color;
+
+ /**
+ * Used for temporary storage of characters
+ */
+ std::string_view m_chars;
+ std::string_view m_name;
+ std::string_view m_merge_area;
+
+ gnumeric_cell_context m_cxt_cell;
+ gnumeric_filter_context m_cxt_filter;
+ gnumeric_names_context m_cxt_names;
+ gnumeric_styles_context m_cxt_styles;
+
+ std::vector<gnumeric_style> m_styles;
+};
+
+} // namespace orcus
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_sheet_context_test.cpp b/src/liborcus/gnumeric_sheet_context_test.cpp
new file mode 100644
index 0000000..685357d
--- /dev/null
+++ b/src/liborcus/gnumeric_sheet_context_test.cpp
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_sheet_context.hpp"
+#include "gnumeric_tokens.hpp"
+#include "gnumeric_namespace_types.hpp"
+#include "gnumeric_token_constants.hpp"
+#include "mock_spreadsheet.hpp"
+#include "session_context.hpp"
+#include "orcus/types.hpp"
+
+#include <iostream>
+#include <string>
+#include <cstdlib>
+
+using namespace orcus;
+using namespace std;
+using namespace orcus::spreadsheet;
+using namespace orcus::spreadsheet::mock;
+
+class mock_sheet_properties : public import_sheet_properties
+{
+public:
+ virtual void set_column_width(col_t col, col_t col_span, double size, length_unit_t unit)
+ {
+ assert(col == 2);
+ assert(col_span == 1);
+ assert(size == 37.3);
+ assert(unit == length_unit_t::point);
+ }
+
+ virtual void set_column_hidden(col_t, col_t, bool)
+ {
+ }
+
+ virtual void set_row_height(row_t row, double size, length_unit_t unit)
+ {
+ assert(row == 4);
+ assert(size == 7.3);
+ assert(unit == length_unit_t::point);
+ }
+
+ virtual void set_row_hidden(row_t, bool)
+ {
+ }
+};
+
+class mock_sheet : public import_sheet
+{
+public:
+ virtual iface::import_sheet_properties* get_sheet_properties()
+ {
+ return &m_mock_properties;
+ }
+
+ virtual range_size_t get_sheet_size() const
+ {
+ range_size_t ret;
+ ret.rows = ret.columns = 0;
+ return ret;
+ }
+
+private:
+ mock_sheet_properties m_mock_properties;
+};
+
+class mock_factory : public import_factory
+{
+public:
+ virtual iface::import_sheet* get_sheet(std::string_view) override
+ {
+ return &m_mock_sheet;
+ }
+
+private:
+ mock_sheet m_mock_sheet;
+};
+
+void test_column_width()
+{
+ mock_factory factory;
+ session_context cxt;
+
+ orcus::gnumeric_sheet_context context(cxt, orcus::gnumeric_tokens, &factory);
+ context.reset(0);
+ orcus::xmlns_id_t ns = NS_gnumeric_gnm;
+ orcus::xml_token_t parent = XML_Sheet;
+ orcus::xml_token_attrs_t parent_attr;
+ context.start_element(ns, parent, parent_attr);
+ {
+ orcus::xml_token_t elem = XML_Name;
+ orcus::xml_token_attrs_t attrs;
+ context.start_element(ns, elem, attrs);
+ context.characters("test", false);
+ context.end_element(ns, elem);
+ }
+ {
+ orcus::xml_token_t elem = XML_ColInfo;
+ orcus::xml_token_attrs_t attrs;
+ attrs.push_back(xml_token_attr_t(ns, XML_No, "2", false));
+ attrs.push_back(xml_token_attr_t(ns, XML_Unit, "37.3", false));
+ attrs.push_back(xml_token_attr_t(ns, XML_Unit, "37.3", false));
+ context.start_element(ns, elem, attrs);
+ context.end_element(ns, elem);
+ }
+ context.end_element(ns, parent);
+}
+
+int main()
+{
+ test_column_width();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_styles_context.cpp b/src/liborcus/gnumeric_styles_context.cpp
new file mode 100644
index 0000000..b2c6058
--- /dev/null
+++ b/src/liborcus/gnumeric_styles_context.cpp
@@ -0,0 +1,342 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_styles_context.hpp"
+#include "gnumeric_token_constants.hpp"
+#include "gnumeric_namespace_types.hpp"
+
+#include <orcus/measurement.hpp>
+#include <mdds/sorted_string_map.hpp>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+namespace hor_align {
+
+using map_type = mdds::sorted_string_map<ss::hor_alignment_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "GNM_HALIGN_CENTER", ss::hor_alignment_t::center },
+ { "GNM_HALIGN_DISTRIBUTED", ss::hor_alignment_t::distributed },
+ { "GNM_HALIGN_GENERAL", ss::hor_alignment_t::unknown },
+ { "GNM_HALIGN_JUSTIFY", ss::hor_alignment_t::justified },
+ { "GNM_HALIGN_LEFT", ss::hor_alignment_t::left },
+ { "GNM_HALIGN_RIGHT", ss::hor_alignment_t::right },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::hor_alignment_t::unknown);
+ return mt;
+}
+
+} // namespace hor_align
+
+namespace ver_align {
+
+using map_type = mdds::sorted_string_map<ss::ver_alignment_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "GNM_VALIGN_BOTTOM", ss::ver_alignment_t::bottom },
+ { "GNM_VALIGN_CENTER", ss::ver_alignment_t::middle },
+ { "GNM_VALIGN_DISTRIBUTED", ss::ver_alignment_t::distributed },
+ { "GNM_VALIGN_JUSTIFY", ss::ver_alignment_t::justified },
+ { "GNM_VALIGN_TOP", ss::ver_alignment_t::top },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::ver_alignment_t::unknown);
+ return mt;
+}
+
+} // namespace ver_align
+
+ss::fill_pattern_t to_fill_pattern(std::size_t v)
+{
+ constexpr ss::fill_pattern_t patterns[] = {
+ ss::fill_pattern_t::none,
+ ss::fill_pattern_t::solid,
+ // TODO: add more as we establish more mapping rules
+ };
+
+ return (v < std::size(patterns)) ? patterns[v] : ss::fill_pattern_t::none;
+}
+
+gnumeric_style::border_type parse_border_attributes(const xml_token_attrs_t& attrs)
+{
+ gnumeric_style::border_type ret;
+
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == XMLNS_UNKNOWN_ID)
+ {
+ switch (attr.name)
+ {
+ case XML_Style:
+ {
+ const char* p_end = nullptr;
+ long v = to_long(attr.value, &p_end);
+ if (attr.value.data() < p_end)
+ ret.style = static_cast<gnumeric_border_type>(v);
+ break;
+ }
+ case XML_Color:
+ {
+ ret.color = parse_gnumeric_rgb(attr.value);
+ break;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+} // anonymous namespace
+
+gnumeric_styles_context::gnumeric_styles_context(
+ session_context& session_cxt, const tokens& tokens,
+ ss::iface::import_factory* factory) :
+ xml_context_base(session_cxt, tokens),
+ mp_factory(factory)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_gnumeric_gnm, XML_Styles }, // root element
+ { NS_gnumeric_gnm, XML_Style, NS_gnumeric_gnm, XML_Font },
+ { NS_gnumeric_gnm, XML_Style, NS_gnumeric_gnm, XML_StyleBorder },
+ { NS_gnumeric_gnm, XML_StyleBorder, NS_gnumeric_gnm, XML_Bottom },
+ { NS_gnumeric_gnm, XML_StyleBorder, NS_gnumeric_gnm, XML_Diagonal },
+ { NS_gnumeric_gnm, XML_StyleBorder, NS_gnumeric_gnm, XML_Left },
+ { NS_gnumeric_gnm, XML_StyleBorder, NS_gnumeric_gnm, XML_Rev_Diagonal },
+ { NS_gnumeric_gnm, XML_StyleBorder, NS_gnumeric_gnm, XML_Right },
+ { NS_gnumeric_gnm, XML_StyleBorder, NS_gnumeric_gnm, XML_Top },
+ { NS_gnumeric_gnm, XML_StyleRegion, NS_gnumeric_gnm, XML_Style },
+ { NS_gnumeric_gnm, XML_Styles, NS_gnumeric_gnm, XML_StyleRegion },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+gnumeric_styles_context::~gnumeric_styles_context() = default;
+
+void gnumeric_styles_context::start_element(
+ xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_StyleRegion:
+ start_style_region(attrs);
+ break;
+ case XML_StyleBorder:
+ break;
+ case XML_Style:
+ start_style(attrs);
+ break;
+ case XML_Top:
+ {
+ m_current_style.border_top = parse_border_attributes(attrs);
+ break;
+ }
+ case XML_Bottom:
+ {
+ m_current_style.border_bottom = parse_border_attributes(attrs);
+ break;
+ }
+ case XML_Left:
+ {
+ m_current_style.border_left = parse_border_attributes(attrs);
+ break;
+ }
+ case XML_Right:
+ {
+ m_current_style.border_right = parse_border_attributes(attrs);
+ break;
+ }
+ case XML_Diagonal:
+ {
+ m_current_style.border_bl_tr = parse_border_attributes(attrs);
+ break;
+ }
+ case XML_Rev_Diagonal:
+ {
+ m_current_style.border_br_tl = parse_border_attributes(attrs);
+ break;
+ }
+ case XML_Font:
+ start_font(attrs);
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool gnumeric_styles_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_StyleRegion:
+ end_style_region();
+ break;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void gnumeric_styles_context::characters(std::string_view str, bool transient)
+{
+ const auto [ns, name] = get_current_element();
+
+ if (ns == NS_gnumeric_gnm)
+ {
+ switch (name)
+ {
+ case XML_Font:
+ {
+ if (transient)
+ str = intern(str);
+ m_current_style.font_name = str;
+ break;
+ }
+ }
+ }
+}
+
+void gnumeric_styles_context::reset(ss::sheet_t sheet)
+{
+ m_sheet = sheet;
+ m_styles.clear();
+ m_current_style = gnumeric_style{};
+}
+
+std::vector<gnumeric_style> gnumeric_styles_context::pop_styles()
+{
+ return std::move(m_styles);
+}
+
+void gnumeric_styles_context::start_style_region(const std::vector<xml_token_attr_t>& attrs)
+{
+ m_current_style = gnumeric_style{};
+ m_current_style.sheet = m_sheet;
+
+ for (const auto& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_startCol:
+ m_current_style.region.first.column = to_long(attr.value);
+ break;
+ case XML_startRow:
+ m_current_style.region.first.row = to_long(attr.value);
+ break;
+ case XML_endCol:
+ m_current_style.region.last.column = to_long(attr.value);
+ break;
+ case XML_endRow:
+ m_current_style.region.last.row = to_long(attr.value);
+ break;
+ }
+ }
+}
+
+void gnumeric_styles_context::start_style(const std::vector<xml_token_attr_t>& attrs)
+{
+ for (const auto& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_HAlign:
+ m_current_style.hor_align = hor_align::get().find(attr.value);
+ break;
+ case XML_VAlign:
+ m_current_style.ver_align = ver_align::get().find(attr.value);
+ break;
+ case XML_WrapText:
+ m_current_style.wrap_text = to_bool(attr.value);
+ break;
+ case XML_Fore:
+ m_current_style.fore = parse_gnumeric_rgb(attr.value);
+ break;
+ case XML_Back:
+ m_current_style.back = parse_gnumeric_rgb(attr.value);
+ break;
+ case XML_PatternColor:
+ m_current_style.pattern_color = parse_gnumeric_rgb(attr.value);
+ break;
+ case XML_Shade:
+ m_current_style.pattern = to_fill_pattern(to_long(attr.value));
+ break;
+ case XML_Format:
+ {
+ auto v = attr.transient ? intern(attr.value) : attr.value;
+ m_current_style.number_format = v;
+ break;
+ }
+ }
+ }
+}
+
+void gnumeric_styles_context::start_font(const std::vector<xml_token_attr_t>& attrs)
+{
+ for (const auto& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_Unit:
+ {
+ const char* p_end = nullptr;
+ double v = to_double(attr.value, &p_end);
+ if (attr.value.data() < p_end)
+ m_current_style.font_unit = v;
+ break;
+ }
+ case XML_Bold:
+ m_current_style.bold = to_bool(attr.value);
+ break;
+ case XML_Italic:
+ m_current_style.italic = to_bool(attr.value);
+ break;
+ case XML_Underline:
+ m_current_style.underline = to_bool(attr.value);
+ break;
+ case XML_StrikeThrough:
+ m_current_style.strikethrough = to_bool(attr.value);
+ break;
+ case XML_Script:
+ {
+ auto v = to_long(attr.value);
+ m_current_style.script = static_cast<gnumeric_script_type>(v);
+ break;
+ }
+ }
+ }
+}
+
+void gnumeric_styles_context::end_style_region()
+{
+ if (m_current_style.valid())
+ m_styles.push_back(m_current_style);
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_styles_context.hpp b/src/liborcus/gnumeric_styles_context.hpp
new file mode 100644
index 0000000..1675b48
--- /dev/null
+++ b/src/liborcus/gnumeric_styles_context.hpp
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "xml_context_base.hpp"
+#include "gnumeric_types.hpp"
+
+#include <orcus/spreadsheet/types.hpp>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_factory;
+
+}}
+
+class gnumeric_styles_context : public xml_context_base
+{
+public:
+ gnumeric_styles_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_factory* factory);
+ virtual ~gnumeric_styles_context() override;
+
+ virtual void start_element(
+ xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+
+ virtual void characters(std::string_view str, bool transient) override;
+
+ void reset(spreadsheet::sheet_t sheet);
+
+ std::vector<gnumeric_style> pop_styles();
+
+private:
+ void start_style_region(const std::vector<xml_token_attr_t>& attrs);
+ void start_style(const std::vector<xml_token_attr_t>& attrs);
+ void start_font(const std::vector<xml_token_attr_t>& attrs);
+
+ void end_style_region();
+
+private:
+ spreadsheet::iface::import_factory* mp_factory = nullptr;
+ spreadsheet::sheet_t m_sheet = -1;
+
+ std::vector<gnumeric_style> m_styles;
+ gnumeric_style m_current_style;
+};
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_token_constants.hpp b/src/liborcus/gnumeric_token_constants.hpp
new file mode 100644
index 0000000..7e94fb5
--- /dev/null
+++ b/src/liborcus/gnumeric_token_constants.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_GNUMERIC_TOKEN_CONSTANTS_HPP__
+#define __ORCUS_GNUMERIC_TOKEN_CONSTANTS_HPP__
+
+#include "orcus/types.hpp"
+
+namespace orcus {
+
+#include "gnumeric_token_constants.inl"
+
+}
+
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_token_constants.inl b/src/liborcus/gnumeric_token_constants.inl
new file mode 100644
index 0000000..4043f22
--- /dev/null
+++ b/src/liborcus/gnumeric_token_constants.inl
@@ -0,0 +1,258 @@
+// This file has been auto-generated. Do not hand-edit this.
+
+const xml_token_t XML_AllowBlank = 1;
+const xml_token_t XML_AnswerR = 2;
+const xml_token_t XML_Area = 3;
+const xml_token_t XML_ArrowShapeA = 4;
+const xml_token_t XML_ArrowShapeB = 5;
+const xml_token_t XML_ArrowShapeC = 6;
+const xml_token_t XML_Attribute = 7;
+const xml_token_t XML_Attributes = 8;
+const xml_token_t XML_Author = 9;
+const xml_token_t XML_AutoScale = 10;
+const xml_token_t XML_Back = 11;
+const xml_token_t XML_Bold = 12;
+const xml_token_t XML_Bottom = 13;
+const xml_token_t XML_Calculation = 14;
+const xml_token_t XML_Cell = 15;
+const xml_token_t XML_CellComment = 16;
+const xml_token_t XML_Cells = 17;
+const xml_token_t XML_CellsStr = 18;
+const xml_token_t XML_Col = 19;
+const xml_token_t XML_ColInfo = 20;
+const xml_token_t XML_Collapsed = 21;
+const xml_token_t XML_Color = 22;
+const xml_token_t XML_Cols = 23;
+const xml_token_t XML_Comment = 24;
+const xml_token_t XML_Condition = 25;
+const xml_token_t XML_Constr = 26;
+const xml_token_t XML_Content = 27;
+const xml_token_t XML_Count = 28;
+const xml_token_t XML_CursorCol = 29;
+const xml_token_t XML_CursorRow = 30;
+const xml_token_t XML_DateConvention = 31;
+const xml_token_t XML_DefaultSizePts = 32;
+const xml_token_t XML_Diagonal = 33;
+const xml_token_t XML_Direction = 34;
+const xml_token_t XML_Discr = 35;
+const xml_token_t XML_DisplayFormulas = 36;
+const xml_token_t XML_DisplayOutlines = 37;
+const xml_token_t XML_EnableIteration = 38;
+const xml_token_t XML_Epoch = 39;
+const xml_token_t XML_ExprConvention = 40;
+const xml_token_t XML_ExprID = 41;
+const xml_token_t XML_Expression0 = 42;
+const xml_token_t XML_Expression1 = 43;
+const xml_token_t XML_Field = 44;
+const xml_token_t XML_FillColor = 45;
+const xml_token_t XML_Filter = 46;
+const xml_token_t XML_Filters = 47;
+const xml_token_t XML_FloatDigits = 48;
+const xml_token_t XML_FloatRadix = 49;
+const xml_token_t XML_Font = 50;
+const xml_token_t XML_Footer = 51;
+const xml_token_t XML_Fore = 52;
+const xml_token_t XML_Format = 53;
+const xml_token_t XML_FreezePanes = 54;
+const xml_token_t XML_FrozenTopLeft = 55;
+const xml_token_t XML_Full = 56;
+const xml_token_t XML_Geometry = 57;
+const xml_token_t XML_GogObject = 58;
+const xml_token_t XML_GridColor = 59;
+const xml_token_t XML_HAlign = 60;
+const xml_token_t XML_HardSize = 61;
+const xml_token_t XML_Header = 62;
+const xml_token_t XML_Height = 63;
+const xml_token_t XML_Hidden = 64;
+const xml_token_t XML_HideColHeader = 65;
+const xml_token_t XML_HideGrid = 66;
+const xml_token_t XML_HideRowHeader = 67;
+const xml_token_t XML_HideZero = 68;
+const xml_token_t XML_HyperLink = 69;
+const xml_token_t XML_Inc = 70;
+const xml_token_t XML_Indent = 71;
+const xml_token_t XML_Index = 72;
+const xml_token_t XML_Input = 73;
+const xml_token_t XML_InputMessage = 74;
+const xml_token_t XML_Inputs = 75;
+const xml_token_t XML_Italic = 76;
+const xml_token_t XML_IterationTolerance = 77;
+const xml_token_t XML_Label = 78;
+const xml_token_t XML_LabelFormat = 79;
+const xml_token_t XML_Lcol = 80;
+const xml_token_t XML_Left = 81;
+const xml_token_t XML_LimitsR = 82;
+const xml_token_t XML_Locked = 83;
+const xml_token_t XML_Lrow = 84;
+const xml_token_t XML_Major = 85;
+const xml_token_t XML_ManualRecalc = 86;
+const xml_token_t XML_MarginA = 87;
+const xml_token_t XML_MarginB = 88;
+const xml_token_t XML_Margins = 89;
+const xml_token_t XML_Max = 90;
+const xml_token_t XML_MaxCol = 91;
+const xml_token_t XML_MaxIter = 92;
+const xml_token_t XML_MaxIterations = 93;
+const xml_token_t XML_MaxRow = 94;
+const xml_token_t XML_MaxTime = 95;
+const xml_token_t XML_Merge = 96;
+const xml_token_t XML_MergedRegions = 97;
+const xml_token_t XML_Message = 98;
+const xml_token_t XML_Middle = 99;
+const xml_token_t XML_Min = 100;
+const xml_token_t XML_Minor = 101;
+const xml_token_t XML_ModelType = 102;
+const xml_token_t XML_Name = 103;
+const xml_token_t XML_Names = 104;
+const xml_token_t XML_No = 105;
+const xml_token_t XML_NonNeg = 106;
+const xml_token_t XML_ObjectAnchorType = 107;
+const xml_token_t XML_ObjectBound = 108;
+const xml_token_t XML_ObjectOffset = 109;
+const xml_token_t XML_Objects = 110;
+const xml_token_t XML_Op0 = 111;
+const xml_token_t XML_Op1 = 112;
+const xml_token_t XML_Operator = 113;
+const xml_token_t XML_Orient = 114;
+const xml_token_t XML_OutlineColor = 115;
+const xml_token_t XML_OutlineLevel = 116;
+const xml_token_t XML_OutlineSymbolsBelow = 117;
+const xml_token_t XML_OutlineSymbolsRight = 118;
+const xml_token_t XML_Output = 119;
+const xml_token_t XML_Page = 120;
+const xml_token_t XML_PatternColor = 121;
+const xml_token_t XML_PerformR = 122;
+const xml_token_t XML_Points = 123;
+const xml_token_t XML_PrefUnit = 124;
+const xml_token_t XML_Print = 125;
+const xml_token_t XML_PrintInformation = 126;
+const xml_token_t XML_ProblemType = 127;
+const xml_token_t XML_ProgramR = 128;
+const xml_token_t XML_Protected = 129;
+const xml_token_t XML_RTL_Layout = 130;
+const xml_token_t XML_Rcol = 131;
+const xml_token_t XML_Rev_Diagonal = 132;
+const xml_token_t XML_Right = 133;
+const xml_token_t XML_Rotation = 134;
+const xml_token_t XML_Row = 135;
+const xml_token_t XML_RowInfo = 136;
+const xml_token_t XML_Rows = 137;
+const xml_token_t XML_Rrow = 138;
+const xml_token_t XML_Scale = 139;
+const xml_token_t XML_Scenario = 140;
+const xml_token_t XML_Scenarios = 141;
+const xml_token_t XML_Script = 142;
+const xml_token_t XML_SelectedTab = 143;
+const xml_token_t XML_Selection = 144;
+const xml_token_t XML_Selections = 145;
+const xml_token_t XML_SensitivityR = 146;
+const xml_token_t XML_Shade = 147;
+const xml_token_t XML_Sheet = 148;
+const xml_token_t XML_SheetLayout = 149;
+const xml_token_t XML_SheetName = 150;
+const xml_token_t XML_SheetNameIndex = 151;
+const xml_token_t XML_SheetObjectBonobo = 152;
+const xml_token_t XML_SheetObjectFilled = 153;
+const xml_token_t XML_SheetObjectGraph = 154;
+const xml_token_t XML_SheetObjectImage = 155;
+const xml_token_t XML_SheetWidgetButton = 156;
+const xml_token_t XML_SheetWidgetCheckbox = 157;
+const xml_token_t XML_SheetWidgetCombo = 158;
+const xml_token_t XML_SheetWidgetFrame = 159;
+const xml_token_t XML_SheetWidgetLabel = 160;
+const xml_token_t XML_SheetWidgetList = 161;
+const xml_token_t XML_SheetWidgetScrollbar = 162;
+const xml_token_t XML_SheetWidgetSlider = 163;
+const xml_token_t XML_SheetWidgetSpinbutton = 164;
+const xml_token_t XML_SheetWidgetToggleButton = 165;
+const xml_token_t XML_Sheets = 166;
+const xml_token_t XML_ShowIter = 167;
+const xml_token_t XML_ShrinkToFit = 168;
+const xml_token_t XML_Solver = 169;
+const xml_token_t XML_StrikeThrough = 170;
+const xml_token_t XML_Style = 171;
+const xml_token_t XML_StyleBorder = 172;
+const xml_token_t XML_StyleRegion = 173;
+const xml_token_t XML_Styles = 174;
+const xml_token_t XML_TabColor = 175;
+const xml_token_t XML_TabTextColor = 176;
+const xml_token_t XML_TargetCol = 177;
+const xml_token_t XML_TargetRow = 178;
+const xml_token_t XML_Text = 179;
+const xml_token_t XML_TextFormat = 180;
+const xml_token_t XML_Title = 181;
+const xml_token_t XML_Top = 182;
+const xml_token_t XML_TopLeft = 183;
+const xml_token_t XML_Type = 184;
+const xml_token_t XML_UIData = 185;
+const xml_token_t XML_Underline = 186;
+const xml_token_t XML_UnfrozenTopLeft = 187;
+const xml_token_t XML_Unit = 188;
+const xml_token_t XML_UseDropdown = 189;
+const xml_token_t XML_VAlign = 190;
+const xml_token_t XML_Validation = 191;
+const xml_token_t XML_Value = 192;
+const xml_token_t XML_Value0 = 193;
+const xml_token_t XML_Value1 = 194;
+const xml_token_t XML_ValueFormat = 195;
+const xml_token_t XML_ValueType = 196;
+const xml_token_t XML_ValueType0 = 197;
+const xml_token_t XML_ValueType1 = 198;
+const xml_token_t XML_Version = 199;
+const xml_token_t XML_Visibility = 200;
+const xml_token_t XML_Width = 201;
+const xml_token_t XML_Workbook = 202;
+const xml_token_t XML_WrapText = 203;
+const xml_token_t XML_Zoom = 204;
+const xml_token_t XML_bottom = 205;
+const xml_token_t XML_break = 206;
+const xml_token_t XML_cols = 207;
+const xml_token_t XML_count = 208;
+const xml_token_t XML_crop_bottom = 209;
+const xml_token_t XML_crop_left = 210;
+const xml_token_t XML_crop_right = 211;
+const xml_token_t XML_crop_top = 212;
+const xml_token_t XML_data = 213;
+const xml_token_t XML_dimension = 214;
+const xml_token_t XML_do_not_print = 215;
+const xml_token_t XML_draft = 216;
+const xml_token_t XML_endCol = 217;
+const xml_token_t XML_endRow = 218;
+const xml_token_t XML_even_if_only_styles = 219;
+const xml_token_t XML_footer = 220;
+const xml_token_t XML_grid = 221;
+const xml_token_t XML_hPageBreaks = 222;
+const xml_token_t XML_hcenter = 223;
+const xml_token_t XML_header = 224;
+const xml_token_t XML_id = 225;
+const xml_token_t XML_image_type = 226;
+const xml_token_t XML_items = 227;
+const xml_token_t XML_left = 228;
+const xml_token_t XML_monochrome = 229;
+const xml_token_t XML_name = 230;
+const xml_token_t XML_order = 231;
+const xml_token_t XML_orientation = 232;
+const xml_token_t XML_paper = 233;
+const xml_token_t XML_percentage = 234;
+const xml_token_t XML_pos = 235;
+const xml_token_t XML_position = 236;
+const xml_token_t XML_print_to_uri = 237;
+const xml_token_t XML_print_range = 238;
+const xml_token_t XML_property = 239;
+const xml_token_t XML_repeat_left = 240;
+const xml_token_t XML_repeat_top = 241;
+const xml_token_t XML_right = 242;
+const xml_token_t XML_role = 243;
+const xml_token_t XML_rows = 244;
+const xml_token_t XML_size_bytes = 245;
+const xml_token_t XML_startCol = 246;
+const xml_token_t XML_startRow = 247;
+const xml_token_t XML_target = 248;
+const xml_token_t XML_tip = 249;
+const xml_token_t XML_titles = 250;
+const xml_token_t XML_top = 251;
+const xml_token_t XML_type = 252;
+const xml_token_t XML_vPageBreaks = 253;
+const xml_token_t XML_value = 254;
+const xml_token_t XML_vcenter = 255;
+
diff --git a/src/liborcus/gnumeric_tokens.cpp b/src/liborcus/gnumeric_tokens.cpp
new file mode 100644
index 0000000..99eaa1d
--- /dev/null
+++ b/src/liborcus/gnumeric_tokens.cpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_tokens.hpp"
+
+namespace orcus {
+
+namespace {
+
+#include "gnumeric_tokens.inl"
+
+}
+
+tokens gnumeric_tokens = tokens(token_names, token_name_count);
+
+}/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_tokens.hpp b/src/liborcus/gnumeric_tokens.hpp
new file mode 100644
index 0000000..2ce6016
--- /dev/null
+++ b/src/liborcus/gnumeric_tokens.hpp
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_GNUMERIC_TOKENS_HPP__
+#define __ORCUS_GNUMERIC_TOKENS_HPP__
+
+#include "orcus/tokens.hpp"
+
+namespace orcus {
+
+/**
+ * Singleton instance containing all GNUMERIC tokens.
+ */
+extern tokens gnumeric_tokens;
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_tokens.inl b/src/liborcus/gnumeric_tokens.inl
new file mode 100644
index 0000000..297065b
--- /dev/null
+++ b/src/liborcus/gnumeric_tokens.inl
@@ -0,0 +1,263 @@
+// This file has been auto-generated. Do not hand-edit this.
+
+const char* token_names[] = {
+ "??", // 0
+ "AllowBlank", // 1
+ "AnswerR", // 2
+ "Area", // 3
+ "ArrowShapeA", // 4
+ "ArrowShapeB", // 5
+ "ArrowShapeC", // 6
+ "Attribute", // 7
+ "Attributes", // 8
+ "Author", // 9
+ "AutoScale", // 10
+ "Back", // 11
+ "Bold", // 12
+ "Bottom", // 13
+ "Calculation", // 14
+ "Cell", // 15
+ "CellComment", // 16
+ "Cells", // 17
+ "CellsStr", // 18
+ "Col", // 19
+ "ColInfo", // 20
+ "Collapsed", // 21
+ "Color", // 22
+ "Cols", // 23
+ "Comment", // 24
+ "Condition", // 25
+ "Constr", // 26
+ "Content", // 27
+ "Count", // 28
+ "CursorCol", // 29
+ "CursorRow", // 30
+ "DateConvention", // 31
+ "DefaultSizePts", // 32
+ "Diagonal", // 33
+ "Direction", // 34
+ "Discr", // 35
+ "DisplayFormulas", // 36
+ "DisplayOutlines", // 37
+ "EnableIteration", // 38
+ "Epoch", // 39
+ "ExprConvention", // 40
+ "ExprID", // 41
+ "Expression0", // 42
+ "Expression1", // 43
+ "Field", // 44
+ "FillColor", // 45
+ "Filter", // 46
+ "Filters", // 47
+ "FloatDigits", // 48
+ "FloatRadix", // 49
+ "Font", // 50
+ "Footer", // 51
+ "Fore", // 52
+ "Format", // 53
+ "FreezePanes", // 54
+ "FrozenTopLeft", // 55
+ "Full", // 56
+ "Geometry", // 57
+ "GogObject", // 58
+ "GridColor", // 59
+ "HAlign", // 60
+ "HardSize", // 61
+ "Header", // 62
+ "Height", // 63
+ "Hidden", // 64
+ "HideColHeader", // 65
+ "HideGrid", // 66
+ "HideRowHeader", // 67
+ "HideZero", // 68
+ "HyperLink", // 69
+ "Inc", // 70
+ "Indent", // 71
+ "Index", // 72
+ "Input", // 73
+ "InputMessage", // 74
+ "Inputs", // 75
+ "Italic", // 76
+ "IterationTolerance", // 77
+ "Label", // 78
+ "LabelFormat", // 79
+ "Lcol", // 80
+ "Left", // 81
+ "LimitsR", // 82
+ "Locked", // 83
+ "Lrow", // 84
+ "Major", // 85
+ "ManualRecalc", // 86
+ "MarginA", // 87
+ "MarginB", // 88
+ "Margins", // 89
+ "Max", // 90
+ "MaxCol", // 91
+ "MaxIter", // 92
+ "MaxIterations", // 93
+ "MaxRow", // 94
+ "MaxTime", // 95
+ "Merge", // 96
+ "MergedRegions", // 97
+ "Message", // 98
+ "Middle", // 99
+ "Min", // 100
+ "Minor", // 101
+ "ModelType", // 102
+ "Name", // 103
+ "Names", // 104
+ "No", // 105
+ "NonNeg", // 106
+ "ObjectAnchorType", // 107
+ "ObjectBound", // 108
+ "ObjectOffset", // 109
+ "Objects", // 110
+ "Op0", // 111
+ "Op1", // 112
+ "Operator", // 113
+ "Orient", // 114
+ "OutlineColor", // 115
+ "OutlineLevel", // 116
+ "OutlineSymbolsBelow", // 117
+ "OutlineSymbolsRight", // 118
+ "Output", // 119
+ "Page", // 120
+ "PatternColor", // 121
+ "PerformR", // 122
+ "Points", // 123
+ "PrefUnit", // 124
+ "Print", // 125
+ "PrintInformation", // 126
+ "ProblemType", // 127
+ "ProgramR", // 128
+ "Protected", // 129
+ "RTL_Layout", // 130
+ "Rcol", // 131
+ "Rev-Diagonal", // 132
+ "Right", // 133
+ "Rotation", // 134
+ "Row", // 135
+ "RowInfo", // 136
+ "Rows", // 137
+ "Rrow", // 138
+ "Scale", // 139
+ "Scenario", // 140
+ "Scenarios", // 141
+ "Script", // 142
+ "SelectedTab", // 143
+ "Selection", // 144
+ "Selections", // 145
+ "SensitivityR", // 146
+ "Shade", // 147
+ "Sheet", // 148
+ "SheetLayout", // 149
+ "SheetName", // 150
+ "SheetNameIndex", // 151
+ "SheetObjectBonobo", // 152
+ "SheetObjectFilled", // 153
+ "SheetObjectGraph", // 154
+ "SheetObjectImage", // 155
+ "SheetWidgetButton", // 156
+ "SheetWidgetCheckbox", // 157
+ "SheetWidgetCombo", // 158
+ "SheetWidgetFrame", // 159
+ "SheetWidgetLabel", // 160
+ "SheetWidgetList", // 161
+ "SheetWidgetScrollbar", // 162
+ "SheetWidgetSlider", // 163
+ "SheetWidgetSpinbutton", // 164
+ "SheetWidgetToggleButton", // 165
+ "Sheets", // 166
+ "ShowIter", // 167
+ "ShrinkToFit", // 168
+ "Solver", // 169
+ "StrikeThrough", // 170
+ "Style", // 171
+ "StyleBorder", // 172
+ "StyleRegion", // 173
+ "Styles", // 174
+ "TabColor", // 175
+ "TabTextColor", // 176
+ "TargetCol", // 177
+ "TargetRow", // 178
+ "Text", // 179
+ "TextFormat", // 180
+ "Title", // 181
+ "Top", // 182
+ "TopLeft", // 183
+ "Type", // 184
+ "UIData", // 185
+ "Underline", // 186
+ "UnfrozenTopLeft", // 187
+ "Unit", // 188
+ "UseDropdown", // 189
+ "VAlign", // 190
+ "Validation", // 191
+ "Value", // 192
+ "Value0", // 193
+ "Value1", // 194
+ "ValueFormat", // 195
+ "ValueType", // 196
+ "ValueType0", // 197
+ "ValueType1", // 198
+ "Version", // 199
+ "Visibility", // 200
+ "Width", // 201
+ "Workbook", // 202
+ "WrapText", // 203
+ "Zoom", // 204
+ "bottom", // 205
+ "break", // 206
+ "cols", // 207
+ "count", // 208
+ "crop-bottom", // 209
+ "crop-left", // 210
+ "crop-right", // 211
+ "crop-top", // 212
+ "data", // 213
+ "dimension", // 214
+ "do_not_print", // 215
+ "draft", // 216
+ "endCol", // 217
+ "endRow", // 218
+ "even_if_only_styles", // 219
+ "footer", // 220
+ "grid", // 221
+ "hPageBreaks", // 222
+ "hcenter", // 223
+ "header", // 224
+ "id", // 225
+ "image-type", // 226
+ "items", // 227
+ "left", // 228
+ "monochrome", // 229
+ "name", // 230
+ "order", // 231
+ "orientation", // 232
+ "paper", // 233
+ "percentage", // 234
+ "pos", // 235
+ "position", // 236
+ "print-to-uri", // 237
+ "print_range", // 238
+ "property", // 239
+ "repeat_left", // 240
+ "repeat_top", // 241
+ "right", // 242
+ "role", // 243
+ "rows", // 244
+ "size-bytes", // 245
+ "startCol", // 246
+ "startRow", // 247
+ "target", // 248
+ "tip", // 249
+ "titles", // 250
+ "top", // 251
+ "type", // 252
+ "vPageBreaks", // 253
+ "value", // 254
+ "vcenter" // 255
+};
+
+size_t token_name_count = 256;
+
diff --git a/src/liborcus/gnumeric_types.cpp b/src/liborcus/gnumeric_types.cpp
new file mode 100644
index 0000000..c02627a
--- /dev/null
+++ b/src/liborcus/gnumeric_types.cpp
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_types.hpp"
+#include "number_utils.hpp"
+
+#include <mdds/sorted_string_map.hpp>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace value_format_type {
+
+using map_type = mdds::sorted_string_map<gnumeric_value_format_type, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "bold", gnumeric_value_format_type::bold },
+ { "color", gnumeric_value_format_type::color },
+ { "family", gnumeric_value_format_type::family },
+ { "italic", gnumeric_value_format_type::italic },
+ { "size", gnumeric_value_format_type::size },
+ { "strikethrough", gnumeric_value_format_type::strikethrough },
+ { "subscript", gnumeric_value_format_type::subscript },
+ { "superscript", gnumeric_value_format_type::superscript },
+ { "underline", gnumeric_value_format_type::underline },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), gnumeric_value_format_type::unknown);
+ return mt;
+}
+
+} // namespace value_format_type
+
+ss::border_style_t to_standard_type(gnumeric_border_type v)
+{
+ switch (v)
+ {
+ case gnumeric_border_type::border_none:
+ return ss::border_style_t::none;
+ case gnumeric_border_type::border_thin:
+ return ss::border_style_t::thin;
+ case gnumeric_border_type::border_medium:
+ return ss::border_style_t::medium;
+ case gnumeric_border_type::border_dashed:
+ return ss::border_style_t::dashed;
+ case gnumeric_border_type::border_dotted:
+ return ss::border_style_t::dotted;
+ case gnumeric_border_type::border_thick:
+ return ss::border_style_t::thick;
+ case gnumeric_border_type::border_double:
+ return ss::border_style_t::double_border;
+ case gnumeric_border_type::border_hair:
+ return ss::border_style_t::hair;
+ case gnumeric_border_type::border_medium_dash:
+ return ss::border_style_t::medium_dashed;
+ case gnumeric_border_type::border_dash_dot:
+ return ss::border_style_t::dash_dot;
+ case gnumeric_border_type::border_medium_dash_dot:
+ return ss::border_style_t::medium_dash_dot;
+ case gnumeric_border_type::border_dash_dot_dot:
+ return ss::border_style_t::dash_dot_dot;
+ case gnumeric_border_type::border_medium_dash_dot_dot:
+ return ss::border_style_t::medium_dash_dot_dot;
+ case gnumeric_border_type::border_slanted_dash_dot:
+ return ss::border_style_t::slant_dash_dot;
+ }
+
+ return ss::border_style_t::unknown;
+}
+
+gnumeric_value_format_type to_gnumeric_value_format_type(std::string_view s)
+{
+ return value_format_type::get().find(s);
+}
+
+void gnumeric_named_exp::reset()
+{
+ name = std::string_view{};
+ value = std::string_view{};
+ position = {0, 0, 0};
+}
+
+bool gnumeric_style::valid() const
+{
+ if (sheet < 0)
+ return false;
+
+ if (region.first.column < 0 || region.first.row < 0 || region.last.column < 0 || region.last.row < 0)
+ return false;
+
+ return true;
+}
+
+std::optional<spreadsheet::color_rgb_t> parse_gnumeric_rgb(std::string_view v)
+{
+ ss::color_rgb_t color;
+
+ auto pos = v.find(':');
+ if (pos == v.npos)
+ return {};
+
+ std::string_view seg = v.substr(0, pos);
+
+ std::optional<std::uint16_t> elem = hex_to_uint16(seg);
+ if (!elem)
+ return {};
+
+ color.red = *elem >> 8; // 16-bit to 8-bit
+ v = v.substr(pos + 1);
+ pos = v.find(':');
+ if (pos == v.npos)
+ return {};
+
+ seg = v.substr(0, pos);
+ elem = hex_to_uint16(seg);
+ if (!elem)
+ return {};
+
+ color.green = *elem >> 8;
+ v = v.substr(pos + 1);
+ elem = hex_to_uint16(v);
+ if (!elem)
+ return {};
+
+ color.blue = *elem >> 8;
+ return color;
+}
+
+std::optional<spreadsheet::color_rgb_t> parse_gnumeric_rgb_8x(std::string_view v)
+{
+ ss::color_rgb_t color;
+
+ auto pos = v.find('x');
+ if (pos == v.npos)
+ return {};
+
+ std::string_view seg = v.substr(0, pos);
+
+ std::optional<std::uint16_t> elem = hex_to_uint8(seg);
+ if (!elem)
+ return {};
+
+ color.red = *elem;
+ v = v.substr(pos + 1);
+ pos = v.find('x');
+ if (pos == v.npos)
+ return {};
+
+ seg = v.substr(0, pos);
+ elem = hex_to_uint8(seg);
+ if (!elem)
+ return {};
+
+ color.green = *elem;
+ v = v.substr(pos + 1);
+ elem = hex_to_uint8(v);
+ if (!elem)
+ return {};
+
+ color.blue = *elem;
+ return color;
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_types.hpp b/src/liborcus/gnumeric_types.hpp
new file mode 100644
index 0000000..1d8b928
--- /dev/null
+++ b/src/liborcus/gnumeric_types.hpp
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <orcus/spreadsheet/types.hpp>
+
+#include <string_view>
+#include <optional>
+
+namespace orcus {
+
+/**
+ * Values are as specified in the Gnumeric source code.
+ */
+enum gnumeric_value_type
+{
+ vt_empty = 10,
+ vt_boolean = 20,
+ vt_float = 40,
+ vt_error = 50,
+ vt_string = 60,
+ vt_cellrange = 70,
+ vt_array = 80
+};
+
+/**
+ * Values are as specified in the Gnumeric source code (see
+ * GnmStyleBorderType).
+ */
+enum class gnumeric_border_type
+{
+ border_none = 0x0,
+ border_thin = 0x1,
+ border_medium = 0x2,
+ border_dashed = 0x3,
+ border_dotted = 0x4,
+ border_thick = 0x5,
+ border_double = 0x6,
+ border_hair = 0x7,
+ border_medium_dash = 0x8,
+ border_dash_dot = 0x9,
+ border_medium_dash_dot = 0xA,
+ border_dash_dot_dot = 0xB,
+ border_medium_dash_dot_dot = 0xC,
+ border_slanted_dash_dot = 0xD,
+};
+
+spreadsheet::border_style_t to_standard_type(gnumeric_border_type v);
+
+enum class gnumeric_value_format_type
+{
+ unknown,
+ bold,
+ color,
+ family,
+ italic,
+ size,
+ strikethrough,
+ subscript,
+ superscript,
+ underline,
+};
+
+gnumeric_value_format_type to_gnumeric_value_format_type(std::string_view s);
+
+struct gnumeric_value_format_segment
+{
+ gnumeric_value_format_type type = gnumeric_value_format_type::unknown;
+ std::string_view value;
+ std::size_t start = 0;
+ std::size_t end = 0;
+};
+
+enum gnumeric_script_type
+{
+ gnm_script_none = 0,
+ gnm_script_super = 1,
+ gnm_script_sub = -1
+};
+
+struct gnumeric_named_exp
+{
+ std::string_view name;
+ std::string_view value;
+ spreadsheet::src_address_t position = {0, 0, 0};
+
+ void reset();
+};
+
+struct gnumeric_style
+{
+ struct border_type
+ {
+ std::optional<gnumeric_border_type> style;
+ std::optional<spreadsheet::color_rgb_t> color;
+ };
+
+ spreadsheet::sheet_t sheet = -1;
+ spreadsheet::range_t region = {{-1, -1}, {-1, -1}};
+ spreadsheet::hor_alignment_t hor_align = spreadsheet::hor_alignment_t::unknown;
+ spreadsheet::ver_alignment_t ver_align = spreadsheet::ver_alignment_t::unknown;
+
+ std::optional<std::string_view> font_name;
+ std::optional<double> font_unit;
+
+ std::optional<bool> wrap_text;
+ std::optional<bool> bold;
+ std::optional<bool> italic;
+ std::optional<bool> underline;
+ std::optional<bool> strikethrough;
+ std::optional<gnumeric_script_type> script; // TODO : not supported yet
+
+ std::optional<spreadsheet::color_rgb_t> fore;
+ std::optional<spreadsheet::color_rgb_t> back;
+ std::optional<spreadsheet::color_rgb_t> pattern_color;
+ spreadsheet::fill_pattern_t pattern = spreadsheet::fill_pattern_t::none;
+
+ std::optional<std::string_view> number_format;
+
+ border_type border_top;
+ border_type border_bottom;
+ border_type border_left;
+ border_type border_right;
+ border_type border_bl_tr; // bottom-left to top-right (diagonal)
+ border_type border_br_tl; // top-left to bottom-right (rev-diagonal)
+
+ bool valid() const;
+};
+
+/**
+ * Parse an RGB color encoded as 'RRRR:GGGG:BBBB', each element being a 16-bit
+ * hex value.
+ */
+std::optional<spreadsheet::color_rgb_t> parse_gnumeric_rgb(std::string_view v);
+
+/**
+ * Parse an RGB color encoded as 'RRxGGxBB', each element being an 8-bit hex
+ * value.
+ */
+std::optional<spreadsheet::color_rgb_t> parse_gnumeric_rgb_8x(std::string_view v);
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_value_format_parser.cpp b/src/liborcus/gnumeric_value_format_parser.cpp
new file mode 100644
index 0000000..014068e
--- /dev/null
+++ b/src/liborcus/gnumeric_value_format_parser.cpp
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric_value_format_parser.hpp"
+#include <orcus/exception.hpp>
+#include <orcus/measurement.hpp>
+
+#include <cassert>
+#include <sstream>
+
+#include <boost/numeric/conversion/cast.hpp>
+
+using boost::numeric_cast;
+
+namespace orcus {
+
+std::size_t gnumeric_value_format_parser::get_pos() const
+{
+ return std::distance(m_head, m_cur);
+}
+
+void gnumeric_value_format_parser::segment()
+{
+ // segment: [type=value:start:end]
+
+ assert(*m_cur == '[');
+ const char* p0 = nullptr;
+ std::size_t pos = 0;
+
+ gnumeric_value_format_segment seg;
+
+ for (++m_cur; m_cur != m_end; ++m_cur)
+ {
+ if (!p0)
+ p0 = m_cur;
+
+ switch (*m_cur)
+ {
+ case ']':
+ {
+ if (pos != 2)
+ throw parse_error("value format segment is not formatted properly", get_pos());
+
+ auto n = std::distance(p0, m_cur);
+ std::string_view s{p0, numeric_cast<std::size_t>(n)};
+ if (s.empty())
+ throw parse_error("segment value is empty", get_pos());
+
+ seg.end = to_long(s);
+ m_segments.push_back(std::move(seg));
+ return;
+ }
+ case '=':
+ {
+ auto n = std::distance(p0, m_cur);
+ std::string_view s{p0, numeric_cast<std::size_t>(n)};
+ seg.type = to_gnumeric_value_format_type(s);
+ if (seg.type == gnumeric_value_format_type::unknown)
+ {
+ std::ostringstream os;
+ os << "invalid value format type '" << s << "'";
+ throw parse_error(os.str(), get_pos());
+ }
+
+ p0 = nullptr;
+ break;
+ }
+ case ':':
+ {
+ auto n = std::distance(p0, m_cur);
+ std::string_view s{p0, numeric_cast<std::size_t>(n)};
+
+ switch (pos)
+ {
+ case 0:
+ seg.value = s;
+ break;
+ case 1:
+ seg.start = to_long(s);
+ break;
+ default:
+ throw parse_error("too many value partitions", get_pos());
+ }
+
+ p0 = nullptr;
+ ++pos;
+ break;
+ }
+ }
+ }
+
+ throw parse_error("']' was never reached", get_pos());
+}
+
+gnumeric_value_format_parser::gnumeric_value_format_parser(std::string_view format) :
+ m_head(format.data()), m_cur(m_head), m_end(m_head + format.size())
+{
+}
+
+void gnumeric_value_format_parser::parse()
+{
+ if (m_cur == m_end)
+ return;
+
+ // @[segment][segment][segment]...
+
+ if (*m_cur++ != '@')
+ throw parse_error("first character must be '@'", get_pos());
+
+ for (; m_cur != m_end; ++m_cur)
+ {
+ if (*m_cur != '[')
+ throw parse_error("'[' was expected", get_pos());
+
+ segment();
+ assert(*m_cur == ']');
+ }
+}
+
+std::vector<gnumeric_value_format_segment> gnumeric_value_format_parser::pop_segments()
+{
+ return std::move(m_segments);
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/gnumeric_value_format_parser.hpp b/src/liborcus/gnumeric_value_format_parser.hpp
new file mode 100644
index 0000000..83cc6dd
--- /dev/null
+++ b/src/liborcus/gnumeric_value_format_parser.hpp
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <string_view>
+#include <vector>
+
+#include "gnumeric_types.hpp"
+
+namespace orcus {
+
+class gnumeric_value_format_parser
+{
+ const char* m_head = nullptr;
+ const char* m_cur = nullptr;
+ const char* m_end = nullptr;
+
+ std::vector<gnumeric_value_format_segment> m_segments;
+
+private:
+ std::size_t get_pos() const;
+
+ void segment();
+
+public:
+ /**
+ * Constructor.
+ *
+ * @param format Format string containing one or more format segments. Make
+ * sure the source of this string is persisent!
+ */
+ gnumeric_value_format_parser(std::string_view format);
+
+ void parse();
+
+ std::vector<gnumeric_value_format_segment> pop_segments();
+};
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/impl_utils.hpp b/src/liborcus/impl_utils.hpp
new file mode 100644
index 0000000..9b8cd2e
--- /dev/null
+++ b/src/liborcus/impl_utils.hpp
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#define ENSURE_INTERFACE(PTR, NAME) \
+ do \
+ { \
+ if (!PTR) \
+ throw orcus::interface_error( \
+ "implementer must provide a concrete instance of " #NAME "."); \
+ } while (false)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/info.cpp b/src/liborcus/info.cpp
new file mode 100644
index 0000000..ae571f5
--- /dev/null
+++ b/src/liborcus/info.cpp
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/info.hpp"
+
+#include "constants.inl"
+
+namespace orcus {
+
+int get_version_major()
+{
+ return ORCUS_MAJOR_VERSION;
+}
+
+int get_version_minor()
+{
+ return ORCUS_MINOR_VERSION;
+}
+
+int get_version_micro()
+{
+ return ORCUS_MICRO_VERSION;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/interface.cpp b/src/liborcus/interface.cpp
new file mode 100644
index 0000000..2b743a2
--- /dev/null
+++ b/src/liborcus/interface.cpp
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/interface.hpp"
+#include "orcus/config.hpp"
+
+namespace orcus { namespace iface {
+
+struct import_filter::impl
+{
+ orcus::config m_config;
+
+ impl(format_t input) : m_config(input) {}
+};
+
+import_filter::import_filter(format_t input) : mp_impl(std::make_unique<impl>(input)) {}
+
+import_filter::~import_filter() = default;
+
+void import_filter::set_config(const config& v)
+{
+ mp_impl->m_config = v;
+}
+
+const config& import_filter::get_config() const
+{
+ return mp_impl->m_config;
+}
+
+document_dumper::~document_dumper() = default;
+
+}}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_document_tree.cpp b/src/liborcus/json_document_tree.cpp
new file mode 100644
index 0000000..009aa08
--- /dev/null
+++ b/src/liborcus/json_document_tree.cpp
@@ -0,0 +1,1777 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/json_document_tree.hpp>
+#include <orcus/json_parser.hpp>
+#include <orcus/config.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/string_pool.hpp>
+
+#include "json_util.hpp"
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <sstream>
+#include <string_view>
+#include <limits>
+#include <iostream>
+#include <deque>
+
+#include <boost/current_function.hpp>
+#include <boost/pool/object_pool.hpp>
+
+#include "filesystem_env.hpp"
+
+namespace orcus { namespace json {
+
+namespace {
+
+struct json_value_object;
+struct json_value_array;
+
+}
+
+struct document_resource
+{
+ string_pool str_pool;
+ boost::object_pool<json_value> obj_pool;
+ boost::object_pool<json_value_object> obj_pool_jvo;
+ boost::object_pool<json_value_array> obj_pool_jva;
+};
+
+namespace detail {
+
+enum class node_t : int
+{
+ // These must have the same values as their public counterparts.
+ unset = static_cast<int>(json::node_t::unset),
+ string = static_cast<int>(json::node_t::string),
+ number = static_cast<int>(json::node_t::number),
+ object = static_cast<int>(json::node_t::object),
+ array = static_cast<int>(json::node_t::array),
+ boolean_true = static_cast<int>(json::node_t::boolean_true),
+ boolean_false = static_cast<int>(json::node_t::boolean_false),
+ null = static_cast<int>(json::node_t::null),
+
+ /**
+ * Value that represents a single key-value pair. This is an internal
+ * only type, and only to be used in the initializer.
+ */
+ key_value = 10,
+
+ /**
+ * Implicit array initialized with a {} instead of explicit array().
+ */
+ array_implicit = 11,
+};
+
+std::ostream& operator<< (std::ostream& os, node_t nt)
+{
+ static const char* unknown = "???";
+
+ static std::vector<const char*> values =
+ {
+ "unset", // 0
+ "string", // 1
+ "number", // 2
+ "object", // 3
+ "array", // 4
+ "boolean_true", // 5
+ "boolean_false", // 6
+ "null", // 7
+ unknown, // 8
+ unknown, // 9
+ "key_value", // 10
+ "array_implicit", // 11
+ };
+
+ size_t nt_value = size_t(nt);
+
+ if (nt_value < values.size())
+ os << values[nt_value];
+ else
+ os << unknown;
+
+ return os;
+}
+
+}
+
+document_error::document_error(const std::string& msg) :
+ general_error("json::document_error", msg) {}
+
+document_error::~document_error() = default;
+
+key_value_error::key_value_error(const std::string& msg) :
+ document_error(msg) {}
+
+key_value_error::~key_value_error() = default;
+
+struct json_value final
+{
+ detail::node_t type;
+ json_value* parent;
+
+ union
+ {
+ double numeric;
+
+ struct
+ {
+ const char* p;
+ size_t n;
+
+ } str;
+
+ struct
+ {
+ const char* key;
+ size_t n_key;
+ json_value* value;
+
+ } kvp; // key-value pair
+
+ json_value_object* object;
+ json_value_array* array;
+
+ } value;
+
+ json_value(const json_value&) = delete;
+ json_value& operator= (const json_value&) = delete;
+
+ json_value() : type(detail::node_t::unset), parent(nullptr) {}
+ json_value(detail::node_t _type) : type(_type), parent(nullptr) {}
+ ~json_value() {}
+};
+
+namespace {
+
+const char* tab = " ";
+const char quote = '"';
+
+const xmlns_id_t NS_orcus_json_xml = "http://schemas.kohei.us/orcus/2015/json";
+
+struct json_value_array
+{
+ std::vector<json_value*> value_array;
+};
+
+struct json_value_object
+{
+ using object_type = std::unordered_map<std::string_view, json_value*>;
+
+ std::vector<std::string_view> key_order;
+ object_type value_object;
+
+ bool has_ref;
+
+ json_value_object() : has_ref(false) {}
+
+ void swap(json_value_object& src)
+ {
+ key_order.swap(src.key_order);
+ value_object.swap(src.value_object);
+ }
+};
+
+void dump_repeat(std::ostringstream& os, const char* s, int repeat)
+{
+ for (int i = 0; i < repeat; ++i)
+ os << s;
+}
+
+void dump_item(
+ std::ostringstream& os, const std::string_view* key, const json_value* val,
+ int level, bool sep);
+
+void dump_value(std::ostringstream& os, const json_value* v, int level, const std::string_view* key = nullptr)
+{
+ dump_repeat(os, tab, level);
+
+ if (key)
+ os << quote << *key << quote << ": ";
+
+ switch (v->type)
+ {
+ case detail::node_t::array:
+ {
+ auto& vals = v->value.array->value_array;
+ os << "[" << std::endl;
+ size_t n = vals.size();
+ size_t pos = 0;
+ for (auto it = vals.begin(), ite = vals.end(); it != ite; ++it, ++pos)
+ dump_item(os, nullptr, *it, level, pos < (n-1));
+
+ dump_repeat(os, tab, level);
+ os << "]";
+ }
+ break;
+ case detail::node_t::boolean_false:
+ os << "false";
+ break;
+ case detail::node_t::boolean_true:
+ os << "true";
+ break;
+ case detail::node_t::null:
+ os << "null";
+ break;
+ case detail::node_t::number:
+ os << v->value.numeric;
+ break;
+ case detail::node_t::object:
+ {
+ const std::vector<std::string_view>& key_order = v->value.object->key_order;
+ auto& vals = v->value.object->value_object;
+ os << "{" << std::endl;
+ size_t n = vals.size();
+
+ if (key_order.empty())
+ {
+ // Dump object's children unordered.
+ size_t pos = 0;
+ for (auto it = vals.begin(), ite = vals.end(); it != ite; ++it, ++pos)
+ {
+ std::string_view this_key = it->first;
+ auto& this_val = it->second;
+
+ dump_item(os, &this_key, this_val, level, pos < (n-1));
+ }
+ }
+ else
+ {
+ // Dump them based on key's original ordering.
+ size_t pos = 0;
+ for (auto it = key_order.begin(), ite = key_order.end(); it != ite; ++it, ++pos)
+ {
+ std::string_view this_key = *it;
+ auto val_pos = vals.find(this_key);
+ assert(val_pos != vals.end());
+
+ dump_item(os, &this_key, val_pos->second, level, pos < (n-1));
+ }
+ }
+
+ dump_repeat(os, tab, level);
+ os << "}";
+ }
+ break;
+ case detail::node_t::string:
+ json::dump_string(
+ os,
+ std::string(v->value.str.p, v->value.str.n));
+ break;
+ case detail::node_t::unset:
+ default:
+ ;
+ }
+}
+
+void dump_item(
+ std::ostringstream& os, const std::string_view* key, const json_value* val,
+ int level, bool sep)
+{
+ dump_value(os, val, level+1, key);
+ if (sep)
+ os << ",";
+ os << std::endl;
+}
+
+std::string dump_json_tree(const json_value* root)
+{
+ if (root->type == detail::node_t::unset)
+ return std::string();
+
+ std::ostringstream os;
+ dump_value(os, root, 0);
+ return os.str();
+}
+
+void dump_string_xml(std::ostringstream& os, std::string_view s)
+{
+ const char* p = s.data();
+ const char* p_end = p + s.size();
+ for (; p != p_end; ++p)
+ {
+ char c = *p;
+ switch (c)
+ {
+ case '"':
+ os << "&quot;";
+ break;
+ case '<':
+ os << "&lt;";
+ break;
+ case '>':
+ os << "&gt;";
+ break;
+ case '&':
+ os << "&amp;";
+ break;
+ case '\'':
+ os << "&apos;";
+ break;
+ default:
+ os << c;
+ }
+ }
+}
+
+void dump_object_item_xml(
+ std::ostringstream& os, std::string_view key, const json_value* val, int level);
+
+void dump_value_xml(std::ostringstream& os, const json_value* v, int level)
+{
+ switch (v->type)
+ {
+ case detail::node_t::array:
+ {
+ os << "<array";
+ if (level == 0)
+ os << " xmlns=\"" << NS_orcus_json_xml << "\"";
+ os << ">";
+
+ auto& vals = v->value.array->value_array;
+
+ for (auto it = vals.begin(), ite = vals.end(); it != ite; ++it)
+ {
+ os << "<item>";
+ dump_value_xml(os, *it, level+1);
+ os << "</item>";
+ }
+
+ os << "</array>";
+ }
+ break;
+ case detail::node_t::boolean_false:
+ os << "<false/>";
+ break;
+ case detail::node_t::boolean_true:
+ os << "<true/>";
+ break;
+ case detail::node_t::null:
+ os << "<null/>";
+ break;
+ case detail::node_t::number:
+ os << "<number value=\"";
+ os << v->value.numeric;
+ os << "\"/>";
+ break;
+ case detail::node_t::object:
+ {
+ os << "<object";
+ if (level == 0)
+ os << " xmlns=\"" << NS_orcus_json_xml << "\"";
+ os << ">";
+
+ const json_value_object& jvo = *v->value.object;
+ auto& key_order = jvo.key_order;
+ auto& vals = jvo.value_object;
+
+ if (key_order.empty())
+ {
+ // Dump object's children unordered.
+ for (auto it = vals.begin(), ite = vals.end(); it != ite; ++it)
+ {
+ auto& key = it->first;
+ auto& val = it->second;
+ dump_object_item_xml(os, key, val, level);
+ }
+ }
+ else
+ {
+ // Dump them based on key's original ordering.
+ for (auto it = key_order.begin(), ite = key_order.end(); it != ite; ++it)
+ {
+ auto& key = *it;
+ auto val_pos = vals.find(key);
+ assert(val_pos != vals.end());
+
+ dump_object_item_xml(os, key, val_pos->second, level);
+ }
+ }
+
+ os << "</object>";
+ }
+ break;
+ case detail::node_t::string:
+ os << "<string value=\"";
+ dump_string_xml(os, std::string_view(v->value.str.p, v->value.str.n));
+ os << "\"/>";
+ break;
+ case detail::node_t::unset:
+ default:
+ ;
+ }
+}
+
+class yaml_dumper
+{
+ enum class write_type { unspecified, indent, linebreak, value };
+
+ std::size_t m_indent_length = 0;
+ write_type m_last_write = write_type::unspecified;
+
+ void reset()
+ {
+ m_indent_length = 0;
+ m_last_write = write_type::unspecified;
+ }
+
+ static bool needs_quote(std::string_view s)
+ {
+ char c_prev = 0;
+
+ for (char c : s)
+ {
+ switch (c)
+ {
+ case '#':
+ return true;
+ case ' ':
+ if (c_prev == ':')
+ return true;
+ }
+
+ c_prev = c;
+ }
+
+ return false;
+ }
+
+public:
+ std::string dump(const json_value* root)
+ {
+ if (!root || root->type == detail::node_t::unset)
+ return std::string();
+
+ reset();
+
+ std::ostringstream os;
+ os << "---" << std::endl;
+ write_value(os, root);
+ return os.str();
+ }
+
+private:
+ void write_indent(std::ostringstream& os)
+ {
+ m_last_write = write_type::indent;
+
+ for (std::size_t i = 0; i < m_indent_length; ++i)
+ os << ' ';
+ }
+
+ void write_linebreak(std::ostringstream& os)
+ {
+ if (m_last_write == write_type::linebreak)
+ return;
+
+ m_last_write = write_type::linebreak;
+ os << std::endl;
+ }
+
+ void write_string(std::ostringstream& os, std::string_view s)
+ {
+ bool quote_value = needs_quote(s);
+
+ if (quote_value)
+ os << '"';
+
+ os << s;
+
+ if (quote_value)
+ os << '"';
+ }
+
+ void write_value(std::ostringstream& os, const json_value* v)
+ {
+ m_last_write = write_type::value;
+ detail::node_t parent_type = v->parent ? v->parent->type : detail::node_t::unset;
+
+ switch (v->type)
+ {
+ case detail::node_t::array:
+ {
+ if (parent_type != detail::node_t::unset)
+ write_linebreak(os);
+
+ for (const json_value* cv : v->value.array->value_array)
+ {
+ write_indent(os);
+ os << "- ";
+ m_indent_length += 2;
+ write_value(os, cv);
+ m_indent_length -= 2;
+ write_linebreak(os);
+ }
+ break;
+ }
+ case detail::node_t::boolean_false:
+ os << "false";
+ break;
+ case detail::node_t::boolean_true:
+ os << "true";
+ break;
+ case detail::node_t::null:
+ os << "null";
+ break;
+ case detail::node_t::number:
+ {
+ os << v->value.numeric;
+ break;
+ }
+ case detail::node_t::object:
+ {
+ const json_value_object& jvo = *v->value.object;
+ const std::vector<std::string_view>& key_order = jvo.key_order;
+ const json_value_object::object_type& vals = jvo.value_object;
+
+ std::deque<std::tuple<std::string_view, const json_value*>> key_values;
+
+ if (key_order.empty())
+ {
+ // Dump object's children unordered.
+ for (const auto& val : vals)
+ key_values.emplace_back(val.first, val.second);
+ }
+ else
+ {
+ // Dump them based on key's original ordering.
+ for (std::string_view key : key_order)
+ {
+ auto val_pos = vals.find(key);
+ assert(val_pos != vals.end());
+ key_values.emplace_back(key, val_pos->second);
+ }
+ }
+
+ if (key_values.empty())
+ break;
+
+ auto write_key_value = [this, &os](std::string_view key, const json_value* value)
+ {
+ std::size_t indent_add = 2;
+ write_string(os, key);
+ os << ": ";
+ m_indent_length += indent_add;
+ write_value(os, value);
+ m_indent_length -= indent_add;
+ write_linebreak(os);
+ };
+
+ if (parent_type == detail::node_t::array)
+ {
+ // Parent is an array. Continue on the "bullet" line.
+ write_key_value(std::get<0>(key_values[0]), std::get<1>(key_values[0]));
+ key_values.pop_front();
+ }
+ else if (parent_type != detail::node_t::unset)
+ write_linebreak(os);
+
+ for (auto& [key, value] : key_values)
+ {
+ write_indent(os);
+ write_key_value(key, value);
+ }
+
+ break;
+ }
+ case detail::node_t::string:
+ {
+ write_string(os, {v->value.str.p, v->value.str.n});
+ break;
+ }
+ case detail::node_t::unset:
+ default:
+ ;
+ }
+ }
+};
+
+void dump_object_item_xml(
+ std::ostringstream& os, std::string_view key, const json_value* val, int level)
+{
+ os << "<item name=\"";
+ dump_string_xml(os, key);
+ os << "\">";
+ dump_value_xml(os, val, level+1);
+ os << "</item>";
+}
+
+std::string dump_xml_tree(const json_value* root)
+{
+ if (root->type == detail::node_t::unset)
+ return std::string();
+
+ std::ostringstream os;
+ os << "<?xml version=\"1.0\"?>" << std::endl;
+ dump_value_xml(os, root, 0);
+ os << std::endl;
+ return os.str();
+}
+
+struct parser_stack
+{
+ std::string_view key;
+ json_value* node;
+
+ parser_stack(json_value* _node) : node(_node) {}
+};
+
+struct external_ref
+{
+ std::string_view path;
+ json_value_object* dest;
+
+ external_ref(std::string_view _path, json_value_object* _dest) :
+ path(_path), dest(_dest) {}
+};
+
+class parser_handler
+{
+ json_value* m_root;
+ const json_config& m_config;
+
+ std::vector<parser_stack> m_stack;
+ std::vector<external_ref> m_external_refs;
+
+ document_resource& m_res;
+
+ json_value* push_value(json_value* value)
+ {
+ assert(!m_stack.empty());
+ parser_stack& cur = m_stack.back();
+
+ switch (cur.node->type)
+ {
+ case detail::node_t::array:
+ {
+ json_value_array* jva = cur.node->value.array;
+ value->parent = cur.node;
+ jva->value_array.push_back(value);
+ return jva->value_array.back();
+ }
+ case detail::node_t::object:
+ {
+ std::string_view key = cur.key;
+ json_value_object* jvo = cur.node->value.object;
+ value->parent = cur.node;
+
+ if (m_config.resolve_references &&
+ key == "$ref" && value->type == detail::node_t::string)
+ {
+ std::string_view sv(value->value.str.p, value->value.str.n);
+ if (!jvo->has_ref && !sv.empty() && sv[0] != '#')
+ {
+ // Store the external reference path and the destination
+ // object for later processing.
+ m_external_refs.emplace_back(sv, jvo);
+ jvo->has_ref = true;
+ }
+ }
+
+ if (m_config.preserve_object_order)
+ jvo->key_order.push_back(key);
+
+ auto r = jvo->value_object.insert(std::make_pair(key, value));
+
+ if (!r.second)
+ throw document_error("adding the same key twice");
+
+ return r.first->second;
+ }
+ default:
+ break;
+ }
+
+ std::ostringstream os;
+ os << BOOST_CURRENT_FUNCTION << ": unstackable JSON value type.";
+ throw document_error(os.str());
+ }
+
+public:
+ parser_handler(const json_config& config, document_resource& res) :
+ m_root(nullptr), m_config(config), m_res(res) {}
+
+ void begin_parse()
+ {
+ m_root = nullptr;
+ }
+
+ void end_parse()
+ {
+ }
+
+ void begin_array()
+ {
+ if (m_root)
+ {
+ json_value* jv = m_res.obj_pool.construct(detail::node_t::array);
+ jv->value.array = m_res.obj_pool_jva.construct();
+ jv = push_value(jv);
+ assert(jv && jv->type == detail::node_t::array);
+ m_stack.push_back(parser_stack(jv));
+ }
+ else
+ {
+ m_root = m_res.obj_pool.construct(detail::node_t::array);
+ m_root->value.array = m_res.obj_pool_jva.construct();
+ m_stack.push_back(parser_stack(m_root));
+ }
+ }
+
+ void end_array()
+ {
+ assert(!m_stack.empty());
+ m_stack.pop_back();
+ }
+
+ void begin_object()
+ {
+ if (m_root)
+ {
+ json_value* jv = m_res.obj_pool.construct(detail::node_t::object);
+ jv->value.object = m_res.obj_pool_jvo.construct();
+ jv = push_value(jv);
+ assert(jv && jv->type == detail::node_t::object);
+ m_stack.push_back(parser_stack(jv));
+ }
+ else
+ {
+ m_root = m_res.obj_pool.construct(detail::node_t::object);
+ m_root->value.object = m_res.obj_pool_jvo.construct();
+ m_stack.push_back(parser_stack(m_root));
+ }
+ }
+
+ void object_key(std::string_view key, bool transient)
+ {
+ parser_stack& cur = m_stack.back();
+ cur.key = key;
+ if (m_config.persistent_string_values || transient)
+ // The tree manages the life cycle of this string value.
+ cur.key = m_res.str_pool.intern(cur.key).first;
+ }
+
+ void end_object()
+ {
+ assert(!m_stack.empty());
+ m_stack.pop_back();
+ }
+
+ void boolean_true()
+ {
+ push_value(m_res.obj_pool.construct(detail::node_t::boolean_true));
+ }
+
+ void boolean_false()
+ {
+ push_value(m_res.obj_pool.construct(detail::node_t::boolean_false));
+ }
+
+ void null()
+ {
+ push_value(m_res.obj_pool.construct(detail::node_t::null));
+ }
+
+ void string(std::string_view s, bool transient)
+ {
+ if (m_config.persistent_string_values || transient)
+ // The tree manages the life cycle of this string value.
+ s = m_res.str_pool.intern(s).first;
+
+ json_value* jv = m_res.obj_pool.construct(detail::node_t::string);
+ jv->value.str.p = s.data();
+ jv->value.str.n = s.size();
+ push_value(jv);
+ }
+
+ void number(double val)
+ {
+ json_value* jv = m_res.obj_pool.construct(detail::node_t::number);
+ jv->value.numeric = val;
+ push_value(jv);
+ }
+
+ json_value* get_root()
+ {
+ return m_root;
+ }
+
+ const std::vector<external_ref>& get_external_refs() const
+ {
+ return m_external_refs;
+ }
+};
+
+} // anonymous namespace
+
+struct const_node::impl
+{
+ const document_tree* m_doc;
+ json_value* m_node;
+
+ impl(const document_tree* doc, json_value* jv) : m_doc(doc), m_node(jv) {}
+ impl(const impl& other) : m_doc(other.m_doc), m_node(other.m_node) {}
+};
+
+const_node::const_node(const document_tree* doc, json_value* jv) : mp_impl(std::make_unique<impl>(doc, jv)) {}
+const_node::const_node(std::unique_ptr<impl>&& p) : mp_impl(std::move(p)) {}
+const_node::const_node(const const_node& other) : mp_impl(std::make_unique<impl>(*other.mp_impl)) {}
+const_node::const_node(const_node&& rhs) : mp_impl(std::move(rhs.mp_impl)) {}
+const_node::~const_node() {}
+
+const_node& const_node::operator=(const const_node& other)
+{
+ if (this == &other)
+ return *this;
+
+ const_node tmp(other);
+ mp_impl.swap(tmp.mp_impl);
+ return *this;
+}
+
+const_node& const_node::operator=(const_node&& other)
+{
+ if (this == &other)
+ return *this;
+
+ mp_impl = std::move(other.mp_impl);
+ return *this;
+}
+
+uintptr_t const_node::identity() const
+{
+ return reinterpret_cast<uintptr_t>(mp_impl->m_node);
+}
+
+const_node_iterator const_node::begin() const
+{
+ if (mp_impl->m_node->type != detail::node_t::array)
+ throw document_error("const_node::begin: this method only supports array nodes.");
+
+ return const_node_iterator(mp_impl->m_doc, *this, true);
+}
+
+const_node_iterator const_node::end() const
+{
+ if (mp_impl->m_node->type != detail::node_t::array)
+ throw document_error("const_node::end: this method only supports array nodes.");
+
+ return const_node_iterator(mp_impl->m_doc, *this, false);
+}
+
+node_t const_node::type() const
+{
+ // Convert it back to the public enum type.
+ return static_cast<node_t>(mp_impl->m_node->type);
+}
+
+size_t const_node::child_count() const
+{
+ switch (mp_impl->m_node->type)
+ {
+ case detail::node_t::object:
+ return mp_impl->m_node->value.object->value_object.size();
+ case detail::node_t::array:
+ return mp_impl->m_node->value.array->value_array.size();
+ case detail::node_t::string:
+ case detail::node_t::number:
+ case detail::node_t::boolean_true:
+ case detail::node_t::boolean_false:
+ case detail::node_t::null:
+ case detail::node_t::unset:
+ default:
+ ;
+ }
+ return 0;
+}
+
+std::vector<std::string_view> const_node::keys() const
+{
+ if (mp_impl->m_node->type != detail::node_t::object)
+ throw document_error("node::keys: this node is not of object type.");
+
+ const json_value_object* jvo = mp_impl->m_node->value.object;
+ if (!jvo->key_order.empty())
+ // Prefer to use key_order when it's populated.
+ return jvo->key_order;
+
+ std::vector<std::string_view> keys;
+
+ for (const auto& n : jvo->value_object)
+ keys.push_back(n.first);
+
+ return keys;
+}
+
+std::string_view const_node::key(size_t index) const
+{
+ if (mp_impl->m_node->type != detail::node_t::object)
+ throw document_error("node::key: this node is not of object type.");
+
+ const json_value_object* jvo = mp_impl->m_node->value.object;
+ if (index >= jvo->key_order.size())
+ throw std::out_of_range("node::key: index is out-of-range.");
+
+ return jvo->key_order[index];
+}
+
+bool const_node::has_key(std::string_view key) const
+{
+ if (mp_impl->m_node->type != detail::node_t::object)
+ return false;
+
+ const json_value_object* jvo = mp_impl->m_node->value.object;
+ const json_value_object::object_type& children = jvo->value_object;
+
+ return children.count(key) != 0;
+}
+
+const_node const_node::child(size_t index) const
+{
+ switch (mp_impl->m_node->type)
+ {
+ case detail::node_t::object:
+ {
+ // This works only when the key order is preserved.
+ const json_value_object* jvo = mp_impl->m_node->value.object;
+ if (index >= jvo->key_order.size())
+ throw std::out_of_range("node::child: index is out-of-range");
+
+ std::string_view key = jvo->key_order[index];
+ auto it = jvo->value_object.find(key);
+ assert(it != jvo->value_object.end());
+ return const_node(mp_impl->m_doc, it->second);
+ }
+ break;
+ case detail::node_t::array:
+ {
+ const json_value_array* jva = mp_impl->m_node->value.array;
+ if (index >= jva->value_array.size())
+ throw std::out_of_range("node::child: index is out-of-range");
+
+ return const_node(mp_impl->m_doc, jva->value_array[index]);
+ }
+ break;
+ case detail::node_t::string:
+ case detail::node_t::number:
+ case detail::node_t::boolean_true:
+ case detail::node_t::boolean_false:
+ case detail::node_t::null:
+ case detail::node_t::unset:
+ default:
+ throw document_error("node::child: this node cannot have child nodes.");
+ }
+}
+
+const_node const_node::child(std::string_view key) const
+{
+ if (mp_impl->m_node->type != detail::node_t::object)
+ throw document_error("node::child: this node is not of object type.");
+
+ const json_value_object* jvo = mp_impl->m_node->value.object;
+ auto it = jvo->value_object.find(key);
+ if (it == jvo->value_object.end())
+ {
+ std::ostringstream os;
+ os << "node::child: this object does not have a key labeled '" << key << "'";
+ throw document_error(os.str());
+ }
+
+ return const_node(mp_impl->m_doc, it->second);
+}
+
+const_node const_node::parent() const
+{
+ if (!mp_impl->m_node->parent)
+ throw document_error("node::parent: this node has no parent.");
+
+ return const_node(mp_impl->m_doc, mp_impl->m_node->parent);
+}
+
+const_node const_node::back() const
+{
+ if (mp_impl->m_node->type != detail::node_t::array)
+ throw document_error("const_node::child: this node is not of array type.");
+
+ const json_value_array* jva = mp_impl->m_node->value.array;
+ if (jva->value_array.empty())
+ throw document_error("const_node::child: this node has no children.");
+
+ return const_node(mp_impl->m_doc, jva->value_array.back());
+}
+
+std::string_view const_node::string_value() const
+{
+ if (mp_impl->m_node->type != detail::node_t::string)
+ throw document_error("node::key: current node is not of string type.");
+
+ return std::string_view(mp_impl->m_node->value.str.p, mp_impl->m_node->value.str.n);
+}
+
+double const_node::numeric_value() const
+{
+ if (mp_impl->m_node->type != detail::node_t::number)
+ throw document_error("node::key: current node is not of numeric type.");
+
+ return mp_impl->m_node->value.numeric;
+}
+
+node::node(const document_tree* doc, json_value* jv) : const_node(doc, jv) {}
+node::node(const_node&& rhs) : const_node(std::move(rhs)) {}
+node::node(const node& other) : const_node(other) {}
+node::node(node&& rhs) : const_node(rhs) {}
+node::~node() {}
+
+node& node::operator=(const node& other)
+{
+ if (this == &other)
+ return *this;
+
+ node tmp(other);
+ mp_impl.swap(tmp.mp_impl);
+ return *this;
+}
+
+node& node::operator=(const detail::init::node& v)
+{
+ document_resource& res =
+ const_cast<document_resource&>(mp_impl->m_doc->get_resource());
+
+ v.store_to_node(res, mp_impl->m_node);
+
+ return *this;
+}
+
+node node::operator[](std::string_view key)
+{
+ if (mp_impl->m_node->type != detail::node_t::object)
+ throw document_error("node::operator[]: the node must be of object type.");
+
+ json_value_object* jvo = const_cast<json_value_object*>(mp_impl->m_node->value.object);
+ auto it = jvo->value_object.find(key);
+ if (it == jvo->value_object.end())
+ {
+ // This object doesn't have the specified key. Create a new empty node
+ // on the fly.
+ document_resource& res =
+ const_cast<document_resource&>(mp_impl->m_doc->get_resource());
+ json_value* jv = res.obj_pool.construct(detail::node_t::unset);
+ jv->parent = mp_impl->m_node;
+ auto r = jvo->value_object.insert(std::make_pair(key, jv));
+ it = r.first;
+ }
+
+ return node(mp_impl->m_doc, it->second);
+}
+
+node node::child(size_t index)
+{
+ const_node cn = const_node::child(index);
+ return node(std::move(cn));
+}
+
+node node::child(std::string_view key)
+{
+ const_node cn = const_node::child(key);
+ return node(std::move(cn));
+}
+
+node node::parent()
+{
+ const_node cn = const_node::parent();
+ return node(std::move(cn));
+}
+
+node node::back()
+{
+ const_node cn = const_node::back();
+ return node(std::move(cn));
+}
+
+void node::push_back(const detail::init::node& v)
+{
+ if (mp_impl->m_node->type != detail::node_t::array)
+ {
+ std::ostringstream os;
+ os << "node::push_back: the node must be of array type, but the value of this node type is '" << mp_impl->m_node->type << "'.";
+ throw document_error(os.str());
+ }
+
+ json_value_array* jva = mp_impl->m_node->value.array;
+ const document_resource& res = mp_impl->m_doc->get_resource();
+ jva->value_array.push_back(v.to_json_value(const_cast<document_resource&>(res)));
+}
+
+struct const_node_iterator::impl
+{
+ const document_tree* m_doc;
+ std::vector<json_value*>::const_iterator m_pos;
+ std::vector<json_value*>::const_iterator m_end;
+ const_node m_current_node;
+
+ impl() : m_doc(nullptr), m_current_node(nullptr, nullptr) {}
+
+ impl(const impl& other) :
+ m_doc(other.m_doc),
+ m_pos(other.m_pos),
+ m_end(other.m_end),
+ m_current_node(other.m_current_node) {}
+
+ impl(const document_tree* doc, const const_node& v, bool begin) :
+ m_doc(doc), m_current_node(nullptr, nullptr)
+ {
+ const json_value_array* jva = v.mp_impl->m_node->value.array;
+ m_pos = begin ? jva->value_array.cbegin() : jva->value_array.cend();
+ m_end = jva->value_array.cend();
+
+ if (m_pos != m_end)
+ m_current_node = const_node(m_doc, *m_pos);
+ }
+
+ void update_current()
+ {
+ m_current_node = const_node(m_doc, m_pos == m_end ? nullptr : *m_pos);
+ }
+};
+
+const_node_iterator::const_node_iterator() :
+ mp_impl(std::make_unique<impl>()) {}
+
+const_node_iterator::const_node_iterator(const const_node_iterator& other) :
+ mp_impl(std::make_unique<impl>(*other.mp_impl)) {}
+
+const_node_iterator::const_node_iterator(const document_tree* doc, const const_node& v, bool begin) :
+ mp_impl(std::make_unique<impl>(doc, v, begin)) {}
+
+const_node_iterator::~const_node_iterator() {}
+
+const const_node& const_node_iterator::operator*() const
+{
+ return mp_impl->m_current_node;
+}
+
+const const_node* const_node_iterator::operator->() const
+{
+ return &mp_impl->m_current_node;
+}
+
+const_node_iterator& const_node_iterator::operator++()
+{
+ ++mp_impl->m_pos;
+ mp_impl->update_current();
+ return *this;
+}
+
+const_node_iterator const_node_iterator::operator++(int)
+{
+ const_node_iterator tmp(*this);
+ ++mp_impl->m_pos;
+ mp_impl->update_current();
+ return tmp;
+}
+
+const_node_iterator& const_node_iterator::operator--()
+{
+ --mp_impl->m_pos;
+ mp_impl->update_current();
+ return *this;
+}
+
+const_node_iterator const_node_iterator::operator--(int)
+{
+ const_node_iterator tmp(*this);
+ --mp_impl->m_pos;
+ mp_impl->update_current();
+ return tmp;
+}
+
+bool const_node_iterator::operator== (const const_node_iterator& other) const
+{
+ return mp_impl->m_pos == other.mp_impl->m_pos && mp_impl->m_end == other.mp_impl->m_end;
+}
+
+bool const_node_iterator::operator!= (const const_node_iterator& other) const
+{
+ return !operator==(other);
+}
+
+const_node_iterator& const_node_iterator::operator= (const const_node_iterator& other)
+{
+ mp_impl->m_doc = other.mp_impl->m_doc;
+ mp_impl->m_pos = other.mp_impl->m_pos;
+ mp_impl->m_end = other.mp_impl->m_end;
+ mp_impl->update_current();
+
+ return *this;
+}
+
+array::array() {}
+array::array(array&& other) : m_vs(std::move(other.m_vs)) {}
+array::array(std::initializer_list<detail::init::node> vs)
+{
+ for (const detail::init::node& v : vs)
+ m_vs.push_back(std::move(const_cast<detail::init::node&>(v)));
+}
+
+array::~array() {}
+
+object::object() {}
+object::object(object&& /*other*/) {}
+object::~object() {}
+
+namespace {
+
+json_value* aggregate_nodes(document_resource& res, std::vector<json_value*> nodes, bool object)
+{
+ bool preserve_object_order = true;
+
+ if (object)
+ {
+ json_value* jv = res.obj_pool.construct(detail::node_t::object);
+ jv->value.object = res.obj_pool_jvo.construct();
+ json_value_object* jvo = jv->value.object;
+
+ for (json_value* const_node : nodes)
+ {
+ if (const_node->type != detail::node_t::key_value)
+ throw document_error("key-value pair was expected.");
+
+ auto& kvp = const_node->value.kvp;
+
+ if (preserve_object_order)
+ jvo->key_order.emplace_back(kvp.key, kvp.n_key);
+
+ kvp.value->parent = jv;
+ auto r = jvo->value_object.insert(
+ std::make_pair(std::string_view(kvp.key, kvp.n_key), kvp.value));
+
+ if (!r.second)
+ throw document_error("adding the same key twice");
+ }
+
+ return jv;
+ }
+
+ json_value* jv = res.obj_pool.construct(detail::node_t::array);
+ jv->value.array = res.obj_pool_jva.construct();
+ json_value_array* jva = jv->value.array;
+
+ for (json_value* const_node : nodes)
+ {
+ if (const_node->type == detail::node_t::key_value)
+ throw document_error("key-value pair was not expected.");
+
+ const_node->parent = jv;
+ jva->value_array.push_back(const_node);
+ }
+
+ return jv;
+}
+
+void aggregate_nodes_to_object(
+ document_resource& res, std::vector<json_value*> nodes, json_value* parent)
+{
+ bool preserve_object_order = true;
+
+ json_value_object* jvo = res.obj_pool_jvo.construct();
+ parent->value.object = jvo;
+
+ for (json_value* const_node : nodes)
+ {
+ if (const_node->type != detail::node_t::key_value)
+ throw document_error("key-value pair was expected.");
+
+ auto& kvp = const_node->value.kvp;
+
+ if (preserve_object_order)
+ jvo->key_order.emplace_back(kvp.key, kvp.n_key);
+
+ kvp.value->parent = parent;
+ auto r = jvo->value_object.insert(
+ std::make_pair(std::string_view(kvp.key, kvp.n_key), kvp.value));
+
+ if (!r.second)
+ throw document_error("adding the same key twice");
+ }
+}
+
+void aggregate_nodes_to_array(
+ document_resource& res, std::vector<json_value*> nodes, json_value* parent)
+{
+ json_value_array* jva = res.obj_pool_jva.construct();
+ parent->value.array = jva;
+
+ for (json_value* const_node : nodes)
+ {
+ if (const_node->type == detail::node_t::key_value)
+ throw document_error("key-value pair was not expected.");
+
+ const_node->parent = parent;
+ jva->value_array.push_back(const_node);
+ }
+}
+
+#ifndef NDEBUG
+
+/**
+ * Verify that the parent pointers stored in the child objects point to
+ * their real parent object.
+ */
+void verify_parent_pointers(const json_value* jv, bool object)
+{
+ if (object)
+ {
+ json_value_object* jvo = jv->value.object;
+ for (const auto& child : jvo->value_object)
+ {
+ const json_value& cv = *child.second;
+ assert(cv.parent == jv);
+ }
+ }
+ else
+ {
+ json_value_array* jva = jv->value.array;
+ for (const auto& child : jva->value_array)
+ {
+ const json_value& cv = *child;
+ assert(cv.parent == jv);
+ }
+ }
+}
+
+#endif
+
+} // anonymous namespace
+
+namespace detail { namespace init {
+
+struct node::impl
+{
+ detail::node_t m_type;
+
+ union
+ {
+ double m_value_number;
+ const char* m_value_string;
+ };
+
+ std::vector<detail::init::node> m_value_array;
+
+ impl() : m_type(detail::node_t::unset) {}
+ impl(double v) : m_type(detail::node_t::number), m_value_number(v) {}
+ impl(int v) : m_type(detail::node_t::number), m_value_number(v) {}
+ impl(bool b) : m_type(b ? detail::node_t::boolean_true : detail::node_t::boolean_false) {}
+ impl(decltype(nullptr)) : m_type(detail::node_t::null) {}
+ impl(const char* p) : m_type(detail::node_t::string), m_value_string(p) {}
+ impl(const std::string& s) : m_type(detail::node_t::string), m_value_string(s.data()) {}
+
+ impl(std::initializer_list<detail::init::node> vs) :
+ m_type(detail::node_t::array_implicit)
+ {
+ for (const detail::init::node& v : vs)
+ m_value_array.push_back(std::move(const_cast<detail::init::node&>(v)));
+
+ // If the list has two elements, and the first element is of type string,
+ // we treat this as object's key-value pair.
+
+ if (m_value_array.size() != 2)
+ return;
+
+ const detail::init::node& v0 = *m_value_array.begin();
+ if (v0.mp_impl->m_type == detail::node_t::string)
+ m_type = detail::node_t::key_value;
+ }
+
+ impl(json::array array) :
+ m_type(detail::node_t::array),
+ m_value_array(std::move(array.m_vs))
+ {}
+
+ impl(json::object /*obj*/) :
+ m_type(detail::node_t::object) {}
+};
+
+node::node(double v) : mp_impl(std::make_unique<impl>(v)) {}
+node::node(int v) : mp_impl(std::make_unique<impl>(v)) {}
+node::node(bool b) : mp_impl(std::make_unique<impl>(b)) {}
+node::node(std::nullptr_t) : mp_impl(std::make_unique<impl>(nullptr)) {}
+node::node(const char* p) : mp_impl(std::make_unique<impl>(p)) {}
+node::node(const std::string& s) : mp_impl(std::make_unique<impl>(s)) {}
+node::node(std::initializer_list<detail::init::node> vs) : mp_impl(std::make_unique<impl>(std::move(vs))) {}
+node::node(json::array array) : mp_impl(std::make_unique<impl>(std::move(array))) {}
+node::node(json::object obj) : mp_impl(std::make_unique<impl>(std::move(obj))) {}
+
+node::node(node&& other) : mp_impl(std::move(other.mp_impl)) {}
+node::~node() {}
+
+json::node_t node::type() const
+{
+ return static_cast<json::node_t>(mp_impl->m_type);
+}
+
+json_value* node::to_json_value(document_resource& res) const
+{
+ json_value* jv = nullptr;
+
+ switch (mp_impl->m_type)
+ {
+ case detail::node_t::key_value:
+ {
+ assert(mp_impl->m_value_array.size() == 2);
+ auto it = mp_impl->m_value_array.begin();
+ const detail::init::node& key_node = *it;
+ assert(key_node.mp_impl->m_type == detail::node_t::string);
+ std::string_view key = res.str_pool.intern(key_node.mp_impl->m_value_string).first;
+ ++it;
+ json_value* value = it->to_json_value(res);
+ if (value->type == detail::node_t::key_value)
+ throw key_value_error("nested key-value pairs are not allowed.");
+
+ ++it;
+ assert(it == mp_impl->m_value_array.end());
+
+ jv = res.obj_pool.construct(mp_impl->m_type);
+ jv->value.kvp.key = key.data();
+ jv->value.kvp.n_key = key.size();
+ jv->value.kvp.value = value;
+ break;
+ }
+ case detail::node_t::array:
+ {
+ std::vector<json_value*> nodes;
+ for (const detail::init::node& v2 : mp_impl->m_value_array)
+ {
+ json_value* r = v2.to_json_value(res);
+ nodes.push_back(r);
+ }
+
+ jv = aggregate_nodes(res, std::move(nodes), false);
+#ifndef NDEBUG
+ verify_parent_pointers(jv, false);
+#endif
+ break;
+ }
+ case detail::node_t::array_implicit:
+ {
+ std::vector<json_value*> nodes;
+ bool object = !mp_impl->m_value_array.empty();
+ for (const detail::init::node& v2 : mp_impl->m_value_array)
+ {
+ json_value* r = v2.to_json_value(res);
+ if (r->type != detail::node_t::key_value)
+ object = false;
+ nodes.push_back(r);
+ }
+
+ jv = aggregate_nodes(res, std::move(nodes), object);
+#ifndef NDEBUG
+ verify_parent_pointers(jv, object);
+#endif
+ break;
+ }
+ case detail::node_t::object:
+ {
+ // Currently only empty object instance is allowed.
+ assert(mp_impl->m_value_array.size() == 0);
+ jv = res.obj_pool.construct(mp_impl->m_type);
+ jv->value.object = res.obj_pool_jvo.construct();
+ break;
+ }
+ case detail::node_t::string:
+ {
+ std::string_view s = res.str_pool.intern(mp_impl->m_value_string).first;
+ jv = res.obj_pool.construct(mp_impl->m_type);
+ jv->value.str.p = s.data();
+ jv->value.str.n = s.size();
+ break;
+ }
+ case detail::node_t::number:
+ jv = res.obj_pool.construct(mp_impl->m_type);
+ jv->value.numeric = mp_impl->m_value_number;
+ break;
+ case detail::node_t::boolean_true:
+ case detail::node_t::boolean_false:
+ case detail::node_t::null:
+ jv = res.obj_pool.construct(mp_impl->m_type);
+ break;
+ case detail::node_t::unset:
+ default:
+ {
+ std::ostringstream os;
+ os << "unknown node type (type=" << int(mp_impl->m_type) << ")";
+ throw document_error(os.str());
+ }
+ }
+
+ return jv;
+}
+
+void node::store_to_node(document_resource& res, json_value* parent) const
+{
+ parent->type = mp_impl->m_type;
+
+ switch (mp_impl->m_type)
+ {
+ case detail::node_t::unset:
+ throw document_error("node type is unset.");
+ case detail::node_t::string:
+ {
+ std::string_view s = res.str_pool.intern(mp_impl->m_value_string).first;
+ parent->value.str.p = s.data();
+ parent->value.str.n = s.size();
+ break;
+ }
+ case detail::node_t::number:
+ parent->value.numeric = mp_impl->m_value_number;
+ break;
+ case detail::node_t::object:
+ {
+ // Currently only empty object instance is allowed.
+ assert(mp_impl->m_value_array.size() == 0);
+ parent->value.object = res.obj_pool_jvo.construct();
+ break;
+ }
+ case detail::node_t::array_implicit:
+ {
+ std::vector<json_value*> nodes;
+ bool object = true;
+ for (const detail::init::node& v2 : mp_impl->m_value_array)
+ {
+ json_value* r = v2.to_json_value(res);
+ if (r->type != detail::node_t::key_value)
+ object = false;
+ nodes.push_back(r);
+ }
+
+ if (object)
+ {
+ parent->type = detail::node_t::object;
+ aggregate_nodes_to_object(res, std::move(nodes), parent);
+ }
+ else
+ {
+ parent->type = detail::node_t::array;
+ aggregate_nodes_to_array(res, std::move(nodes), parent);
+ }
+
+ break;
+ }
+ case detail::node_t::array:
+ {
+ std::vector<json_value*> nodes;
+ for (const detail::init::node& v2 : mp_impl->m_value_array)
+ {
+ json_value* r = v2.to_json_value(res);
+ nodes.push_back(r);
+ }
+
+ aggregate_nodes_to_array(res, std::move(nodes), parent);
+ break;
+ }
+ case detail::node_t::boolean_true:
+ case detail::node_t::boolean_false:
+ case detail::node_t::null:
+ break;
+ case detail::node_t::key_value:
+ // fall-through
+ default:
+ {
+ std::ostringstream os;
+ os << "unknown node type (" << (int)mp_impl->m_type << ")";
+ throw document_error(os.str());
+ }
+ }
+}
+
+}} // namespace detail::init
+
+struct document_tree::impl
+{
+ json::json_value* m_root;
+ std::unique_ptr<document_resource> m_own_res;
+ document_resource& m_res;
+
+ impl() : m_root(nullptr), m_own_res(std::make_unique<document_resource>()), m_res(*m_own_res) {}
+ impl(document_resource& res) : m_root(nullptr), m_res(res) {}
+};
+
+const document_resource& document_tree::get_resource() const
+{
+ return mp_impl->m_res;
+}
+
+document_tree::document_tree() : mp_impl(std::make_unique<impl>()) {}
+document_tree::document_tree(document_tree&& other) : mp_impl(std::move(other.mp_impl)) {}
+document_tree::document_tree(document_resource& res) : mp_impl(std::make_unique<impl>(res)) {}
+
+document_tree::document_tree(std::initializer_list<detail::init::node> vs) :
+ mp_impl(std::make_unique<impl>())
+{
+ std::vector<json_value*> nodes;
+ bool object = true;
+ for (const detail::init::node& v : vs)
+ {
+ json_value* r = v.to_json_value(mp_impl->m_res);
+ if (r->type != detail::node_t::key_value)
+ object = false;
+ nodes.push_back(r);
+ }
+
+ mp_impl->m_root = aggregate_nodes(mp_impl->m_res, std::move(nodes), object);
+}
+
+document_tree::document_tree(array vs) : mp_impl(std::make_unique<impl>())
+{
+ json_value_array* jva = mp_impl->m_res.obj_pool_jva.construct();
+ mp_impl->m_root = mp_impl->m_res.obj_pool.construct(detail::node_t::array);
+ mp_impl->m_root->value.array = jva;
+
+ for (const detail::init::node& v : vs.m_vs)
+ {
+ json_value* r = v.to_json_value(mp_impl->m_res);
+ jva->value_array.push_back(r);
+ }
+}
+
+document_tree::document_tree(object /*obj*/) : mp_impl(std::make_unique<impl>())
+{
+ mp_impl->m_root = mp_impl->m_res.obj_pool.construct(detail::node_t::object);
+ mp_impl->m_root->value.object = mp_impl->m_res.obj_pool_jvo.construct();
+}
+
+document_tree::~document_tree() {}
+
+document_tree& document_tree::operator= (std::initializer_list<detail::init::node> vs)
+{
+ document_tree tmp(std::move(vs));
+ swap(tmp);
+ return *this;
+}
+
+document_tree& document_tree::operator= (array vs)
+{
+ document_tree tmp(std::move(vs));
+ swap(tmp);
+ return *this;
+}
+
+document_tree& document_tree::operator= (object obj)
+{
+ document_tree tmp(std::move(obj));
+ swap(tmp);
+ return *this;
+}
+
+void document_tree::load(std::string_view stream, const json_config& config)
+{
+ json::parser_handler hdl(config, mp_impl->m_res);
+ json_parser<json::parser_handler> parser(stream, hdl);
+ parser.parse();
+ mp_impl->m_root = hdl.get_root();
+
+ auto& external_refs = hdl.get_external_refs();
+
+ json_config ext_config = config;
+ // The stream will get destroyed after each parsing of an external json file.
+ ext_config.persistent_string_values = true;
+
+ fs::path parent_dir = config.input_path;
+ parent_dir = parent_dir.parent_path();
+ for (auto it = external_refs.begin(), ite = external_refs.end(); it != ite; ++it)
+ {
+ fs::path extfile = std::string{it->path};
+ fs::path extpath = parent_dir;
+ extpath /= extfile;
+
+ // Get the stream content from the path.
+ file_content ext_content(extpath.string().data());
+
+ ext_config.input_path = extpath.string();
+ document_tree doc(mp_impl->m_res);
+ try
+ {
+ doc.load(ext_content.str(), ext_config);
+ }
+ catch (const parse_error& e)
+ {
+ std::ostringstream os;
+ os << "Error while parsing " << extpath.string() << std::endl;
+ os << create_parse_error_output(ext_content.str(), e.offset()) << std::endl;
+ os << e.what();
+
+ // Re-throw as general_error to avoid getting caught as parse
+ // error by the parent caller.
+ throw general_error(os.str());
+ }
+
+ json::json_value* root = doc.mp_impl->m_root;
+ if (root->type == detail::node_t::object)
+ {
+ json::json_value_object* jvo_src = root->value.object;
+ json::json_value_object* jvo_dest = it->dest;
+ if (jvo_dest->value_object.size() == 1)
+ {
+ // Swap with the referenced object only when the destination
+ // has one child value i.e. it only has '$ref'.
+ jvo_dest->swap(*jvo_src);
+ jvo_dest->has_ref = false;
+ }
+ }
+ }
+}
+
+json::const_node document_tree::get_document_root() const
+{
+ json::json_value* p = mp_impl->m_root;
+ if (!p)
+ throw document_error("document tree is empty");
+
+ return json::const_node(this, p);
+}
+
+json::node document_tree::get_document_root()
+{
+ json::json_value* p = mp_impl->m_root;
+ if (!p)
+ throw document_error("document tree is empty");
+
+ return json::node(this, p);
+}
+
+std::string document_tree::dump() const
+{
+ if (!mp_impl->m_root)
+ return std::string();
+
+ return json::dump_json_tree(mp_impl->m_root);
+}
+
+std::string document_tree::dump_xml() const
+{
+ if (!mp_impl->m_root)
+ return std::string();
+
+ return json::dump_xml_tree(mp_impl->m_root);
+}
+
+std::string document_tree::dump_yaml() const
+{
+ json::yaml_dumper dumper;
+ return dumper.dump(mp_impl->m_root);
+}
+
+void document_tree::swap(document_tree& other)
+{
+ std::swap(mp_impl, other.mp_impl);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_document_tree_test.cpp b/src/liborcus/json_document_tree_test.cpp
new file mode 100644
index 0000000..3ab6876
--- /dev/null
+++ b/src/liborcus/json_document_tree_test.cpp
@@ -0,0 +1,862 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+
+#include <orcus/stream.hpp>
+#include <orcus/json_document_tree.hpp>
+#include <orcus/json_parser_base.hpp>
+#include <orcus/config.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <orcus/dom_tree.hpp>
+
+#include "filesystem_env.hpp"
+
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+#include <cmath>
+#include <cstring>
+
+using namespace orcus;
+
+fs::path json_test_dirs[] = {
+ SRCDIR"/test/json/basic1",
+ SRCDIR"/test/json/basic2",
+ SRCDIR"/test/json/basic3",
+ SRCDIR"/test/json/basic4",
+ SRCDIR"/test/json/empty-array-1",
+ SRCDIR"/test/json/empty-array-2",
+ SRCDIR"/test/json/empty-array-3",
+ SRCDIR"/test/json/nested1",
+ SRCDIR"/test/json/nested2",
+ SRCDIR"/test/json/swagger",
+ SRCDIR"/test/json/to-yaml-1",
+};
+
+fs::path json_test_refs_dirs[] = {
+ SRCDIR"/test/json/refs1",
+};
+
+bool string_expected(const json::const_node& node, const char* expected)
+{
+ if (node.type() != json::node_t::string)
+ return false;
+
+ if (node.string_value() == expected)
+ return true;
+
+ std::cerr << "expected='" << expected << "', actual='" << node.string_value() << "'" << std::endl;
+ return false;
+}
+
+bool number_expected(
+ const json::const_node& node, double expected,
+ double decimal = 0.0, double exponent = 0.0)
+{
+ if (node.type() != json::node_t::number)
+ return false;
+
+ double actual = node.numeric_value();
+ if (!decimal || !exponent)
+ return actual == expected;
+
+ // Remove the exponent component.
+ actual /= std::pow(10.0, exponent);
+ expected /= std::pow(10.0, exponent);
+
+ // Only compare down to the specified decimal place.
+ actual *= std::pow(10.0, decimal);
+ expected *= std::pow(10.0, decimal);
+
+ actual = std::round(actual);
+ expected = std::round(expected);
+
+ if (actual == expected)
+ return true;
+
+ std::cerr << "expected=" << expected << ", actual=" << actual << std::endl;
+ return false;
+}
+
+std::string dump_check_content(const json::document_tree& doc)
+{
+ std::string xml_strm = doc.dump_xml();
+ assert(!xml_strm.empty());
+
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+ dom::document_tree dom(cxt);
+ dom.load(xml_strm);
+
+ std::ostringstream os;
+ dom.dump_compact(os);
+ return os.str();
+}
+
+bool compare_check_contents(const file_content& expected, const std::string& actual)
+{
+ std::string_view _expected(expected.data(), expected.size());
+ std::string_view _actual(actual.data(), actual.size());
+ _expected = trim(_expected);
+ _actual = trim(_actual);
+
+ if (_expected != _actual)
+ {
+ std::size_t pos = locate_first_different_char(_expected, _actual);
+ std::cout << create_parse_error_output(_expected, pos) << std::endl;
+ std::cout << create_parse_error_output(_actual, pos) << std::endl;
+ }
+
+ return _expected == _actual;
+}
+
+void verify_input(json_config& test_config, const fs::path& basedir)
+{
+ fs::path json_file = basedir / "input.json";
+ test_config.input_path = json_file.string();
+
+ std::cout << "* verify input: " << json_file << std::endl;
+
+ file_content content(json_file.string());
+ json::document_tree doc;
+ doc.load(content.str(), test_config);
+
+ fs::path check_file = basedir / "check.txt";
+ file_content check_master(check_file.string());
+ std::string check_doc = dump_check_content(doc);
+
+ bool result = compare_check_contents(check_master, check_doc);
+ assert(result);
+
+ if (fs::path outpath = basedir / "output.yaml"; fs::is_regular_file(outpath))
+ {
+ // Test the yaml output.
+ std::cout << " * yaml output: " << outpath << std::endl;
+
+ file_content expected(outpath.string());
+ std::string actual = doc.dump_yaml();
+
+ test::verify_content(__FILE__, __LINE__, expected.str(), actual);
+ }
+}
+
+void test_json_parse()
+{
+ json_config test_config;
+
+ for (std::size_t i = 0; i < std::size(json_test_dirs); ++i)
+ {
+ fs::path basedir = json_test_dirs[i];
+ verify_input(test_config, basedir);
+ }
+}
+
+void test_json_resolve_refs()
+{
+ json_config test_config;
+ test_config.resolve_references = true;
+
+ for (size_t i = 0; i < std::size(json_test_refs_dirs); ++i)
+ {
+ fs::path basedir = json_test_refs_dirs[i];
+ verify_input(test_config, basedir);
+ }
+}
+
+void test_json_parse_empty()
+{
+ json_config test_config;
+
+ const char* tests[] = {
+ "{}",
+ "[]",
+ "{\"key1\": {}, \"key2\": {}}"
+ };
+
+ for (size_t i = 0; i < std::size(tests); ++i)
+ {
+ const char* test = tests[i];
+ std::cout << "JSON stream: '" << test << "' (" << std::strlen(test) << ")" << std::endl;
+ json::document_tree doc;
+ try
+ {
+ doc.load(test, test_config);
+ }
+ catch (const parse_error& e)
+ {
+ std::cout << create_parse_error_output(test, e.offset()) << std::endl;
+ std::cout << e.what() << std::endl;
+ assert(false);
+ }
+ }
+}
+
+void test_json_parse_invalid()
+{
+ json_config test_config;
+
+ const char* invalids[] = {
+ "[foo]",
+ "[qwerty]",
+ "[1,2] null",
+ "{\"key\" 1: 12}",
+ "[1,,2]",
+ "\"key\": {\"inner\": 12}"
+ };
+
+ for (std::size_t i = 0; i < std::size(invalids); ++i)
+ {
+ const char* invalid_json = invalids[i];
+ json::document_tree doc;
+ try
+ {
+ doc.load(invalid_json, test_config);
+ std::cerr << "Invalid JSON expression is parsed as valid: '" << invalid_json << "'" << std::endl;
+ assert(false);
+ }
+ catch (const parse_error& e)
+ {
+ // works as expected.
+ std::cout << "invalid expression tested: " << invalid_json << std::endl;
+ std::cout << "error message received: " << e.what() << std::endl;
+ }
+ }
+}
+
+std::unique_ptr<json::document_tree> get_doc_tree(const char* filepath)
+{
+ json_config test_config;
+
+ std::cout << filepath << std::endl;
+ file_content content(filepath);
+ std::cout << "--- original" << std::endl;
+ std::cout << content.str() << std::endl;
+
+ auto doc = std::make_unique<json::document_tree>();
+ doc->load(content.str(), test_config);
+
+ return doc;
+}
+
+void dump_and_load(
+ const json::document_tree& doc, const std::function<void(json::const_node)>& test_func)
+{
+ json::document_tree doc2;
+ std::string dumped = doc.dump();
+ std::cout << "--- dumped" << std::endl;
+ std::cout << dumped << std::endl;
+ doc2.load(dumped, json_config());
+ json::const_node node = doc2.get_document_root();
+ test_func(node);
+}
+
+void test_json_traverse_basic1()
+{
+ auto test_func = [](json::const_node node)
+ {
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 3);
+ assert(node.child(0).type() == json::node_t::boolean_true);
+ assert(node.child(1).type() == json::node_t::boolean_false);
+ assert(node.child(2).type() == json::node_t::null);
+
+ // Move to child node and move back.
+ json::const_node node2 = node.child(0).parent();
+ assert(node.identity() == node2.identity());
+ };
+
+ const char* filepath = SRCDIR"/test/json/basic1/input.json";
+ std::unique_ptr<json::document_tree> doc = get_doc_tree(filepath);
+ json::const_node node = doc->get_document_root();
+ test_func(node);
+ dump_and_load(*doc, test_func);
+}
+
+void test_json_traverse_basic2()
+{
+ auto test_func = [](json::const_node node)
+ {
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 14);
+
+ assert(string_expected(node.child(0), "I am string"));
+ assert(string_expected(node.child(1), "me too"));
+ assert(string_expected(node.child(2), ""));
+ assert(string_expected(node.child(3), "\\"));
+ assert(string_expected(node.child(4), "/"));
+ assert(string_expected(node.child(5), "\\b"));
+ assert(string_expected(node.child(6), "\\f"));
+ assert(string_expected(node.child(7), "\\n"));
+ assert(string_expected(node.child(8), "\\r"));
+ assert(string_expected(node.child(9), "\\t"));
+ assert(string_expected(node.child(10), "\"quoted\""));
+ assert(string_expected(node.child(11), "http://www.google.com"));
+ assert(string_expected(node.child(12), "one \\n two \\n three"));
+ assert(string_expected(node.child(13), "front segment 'single quote' and \"double quote\" end segment"));
+ };
+
+ const char* filepath = SRCDIR"/test/json/basic2/input.json";
+ std::unique_ptr<json::document_tree> doc = get_doc_tree(filepath);
+ json::const_node node = doc->get_document_root();
+ test_func(node);
+ dump_and_load(*doc, test_func);
+}
+
+void test_json_traverse_basic3()
+{
+ auto test_func = [](json::const_node node)
+ {
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 9);
+
+ assert(number_expected(node.child(0), 0.0));
+ assert(number_expected(node.child(1), 1.0));
+ assert(number_expected(node.child(2), 2.0));
+ assert(number_expected(node.child(3), 15.0));
+ assert(number_expected(node.child(4), 12.34));
+ assert(number_expected(node.child(5), -0.12));
+ assert(number_expected(node.child(6), 1.2e+22, 1.0, 22.0));
+ assert(number_expected(node.child(7), 1.11e-7, 2.0, -7.0));
+ assert(number_expected(node.child(8), 11E2));
+ };
+
+ const char* filepath = SRCDIR"/test/json/basic3/input.json";
+ std::unique_ptr<json::document_tree> doc = get_doc_tree(filepath);
+ json::const_node node = doc->get_document_root();
+ test_func(node);
+ dump_and_load(*doc, test_func);
+}
+
+void test_json_traverse_basic4()
+{
+ auto test_func = [](json::const_node node)
+ {
+ assert(node.type() == json::node_t::object);
+ auto keys = node.keys();
+ assert(keys.size() == 3);
+ for (auto it = keys.begin(), ite = keys.end(); it != ite; ++it)
+ {
+ std::string_view key = *it;
+ json::const_node child = node.child(key);
+ if (key == "int")
+ assert(number_expected(child, 12.0));
+ else if (key == "float")
+ assert(number_expected(child, 0.125));
+ else if (key == "string")
+ assert(string_expected(child, "blah..."));
+ else
+ assert(!"unexpected key");
+ }
+ };
+
+ const char* filepath = SRCDIR"/test/json/basic4/input.json";
+ std::unique_ptr<json::document_tree> doc = get_doc_tree(filepath);
+ json::const_node node = doc->get_document_root();
+ test_func(node);
+ dump_and_load(*doc, test_func);
+}
+
+void test_json_traverse_nested1()
+{
+ auto test_func = [](json::const_node node)
+ {
+ uintptr_t root_id = node.identity();
+
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 1);
+
+ node = node.child(0);
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 3);
+
+ assert(number_expected(node.child(0), 1.0));
+ assert(number_expected(node.child(1), 2.0));
+ assert(number_expected(node.child(2), 3.0));
+
+ node = node.parent();
+ assert(node.identity() == root_id);
+ };
+
+ const char* filepath = SRCDIR"/test/json/nested1/input.json";
+ std::unique_ptr<json::document_tree> doc = get_doc_tree(filepath);
+ json::const_node node = doc->get_document_root();
+ test_func(node);
+ dump_and_load(*doc, test_func);
+}
+
+void test_json_traverse_nested2()
+{
+ auto test_func = [](json::const_node node)
+ {
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 3);
+
+ node = node.child(0);
+ assert(node.type() == json::node_t::object);
+ assert(number_expected(node.child("value"), 1.0));
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == json::node_t::object);
+ assert(number_expected(node.child("value"), 2.0));
+ node = node.parent();
+
+ node = node.child(2);
+ assert(node.type() == json::node_t::object);
+ assert(number_expected(node.child("value"), 3.0));
+ node = node.parent();
+ };
+
+ const char* filepath = SRCDIR"/test/json/nested2/input.json";
+ std::unique_ptr<json::document_tree> doc = get_doc_tree(filepath);
+ json::const_node node = doc->get_document_root();
+ test_func(node);
+ dump_and_load(*doc, test_func);
+}
+
+void test_json_init_list_flat1()
+{
+ json::document_tree doc = { 1.0, 2.0, 3.0, 4.0 };
+ json::const_node node = doc.get_document_root();
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 4);
+
+ node = node.child(0);
+ assert(node.type() == json::node_t::number);
+ assert(node.numeric_value() == 1.0);
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == json::node_t::number);
+ assert(node.numeric_value() == 2.0);
+ node = node.parent();
+
+ node = node.child(2);
+ assert(node.type() == json::node_t::number);
+ assert(node.numeric_value() == 3.0);
+ node = node.parent();
+
+ node = node.child(3);
+ assert(node.type() == json::node_t::number);
+ assert(node.numeric_value() == 4.0);
+ node = node.parent();
+
+ // Use iterators.
+ auto it = node.begin();
+ assert(it->type() == json::node_t::number);
+ assert(it->numeric_value() == 1.0);
+ ++it;
+ assert(it->type() == json::node_t::number);
+ assert(it->numeric_value() == 2.0);
+ auto test = it++; // post increment
+ assert(test->numeric_value() == 2.0);
+ assert(it->type() == json::node_t::number);
+ assert(it->numeric_value() == 3.0);
+ test = ++it; // pre increment
+ assert(test->numeric_value() == 4.0);
+ ++it;
+ assert(it == node.end());
+ --it;
+ assert(it->numeric_value() == 4.0);
+ test = it--;
+ assert(test->numeric_value() == 4.0);
+ assert(it->numeric_value() == 3.0);
+
+ doc = { nullptr };
+ node = doc.get_document_root();
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 1);
+
+ node = node.child(0);
+ assert(node.type() == json::node_t::null);
+
+ doc = { true, false };
+ node = doc.get_document_root();
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 2);
+
+ node = node.child(0);
+ assert(node.type() == json::node_t::boolean_true);
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == json::node_t::boolean_false);
+ node = node.parent();
+
+ doc = { "A", "B", "C" };
+ node = doc.get_document_root();
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 3);
+
+ node = node.child(0);
+ assert(node.type() == json::node_t::string);
+ assert(node.string_value() == "A");
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == json::node_t::string);
+ assert(node.string_value() == "B");
+ node = node.parent();
+
+ node = node.child(2);
+ assert(node.type() == json::node_t::string);
+ assert(node.string_value() == "C");
+}
+
+void test_json_init_list_nested1()
+{
+ json::document_tree doc = {
+ { true, false, nullptr },
+ { 1.1, 2.2, "text" }
+ };
+
+ json::const_node node = doc.get_document_root();
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 2);
+
+ node = node.child(0);
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 3);
+ assert(node.child(0).type() == json::node_t::boolean_true);
+ assert(node.child(1).type() == json::node_t::boolean_false);
+ assert(node.child(2).type() == json::node_t::null);
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 3);
+ assert(node.child(0).type() == json::node_t::number);
+ assert(node.child(0).numeric_value() == 1.1);
+ assert(node.child(1).type() == json::node_t::number);
+ assert(node.child(1).numeric_value() == 2.2);
+ assert(node.child(2).type() == json::node_t::string);
+ assert(node.child(2).string_value() == "text");
+}
+
+void test_json_init_list_object1()
+{
+ json::document_tree doc = {
+ { "key1", 1.2 },
+ { "key2", "some text" },
+ };
+
+ json::const_node node = doc.get_document_root();
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 2);
+ assert(node.key(0) == "key1");
+ assert(node.key(1) == "key2");
+
+ node = node.child("key1");
+ assert(node.type() == json::node_t::number);
+ assert(node.numeric_value() == 1.2);
+ node = node.parent();
+
+ node = node.child("key2");
+ assert(node.type() == json::node_t::string);
+ assert(node.string_value() == "some text");
+}
+
+void test_json_init_list_object2()
+{
+ // nested objects.
+ json::document_tree doc = {
+ { "parent1",
+ {
+ { "child1", true },
+ { "child2", false },
+ { "child3", 123.4 },
+ }
+ },
+ { "parent2", "not-nested" },
+ };
+
+ json::const_node node = doc.get_document_root();
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 2);
+ assert(node.key(0) == "parent1");
+ assert(node.key(1) == "parent2");
+
+ node = node.child("parent1");
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 3);
+ assert(node.key(0) == "child1");
+ assert(node.key(1) == "child2");
+ assert(node.key(2) == "child3");
+
+ assert(node.child("child1").type() == json::node_t::boolean_true);
+ assert(node.child("child2").type() == json::node_t::boolean_false);
+ assert(node.child("child3").type() == json::node_t::number);
+ assert(node.child("child3").numeric_value() == 123.4);
+
+ node = node.parent();
+
+ node = node.child("parent2");
+ assert(node.type() == json::node_t::string);
+ assert(node.string_value() == "not-nested");
+}
+
+void test_json_init_list_explicit_array()
+{
+ try
+ {
+ // This structure is too ambiguous and cannot be implicitly
+ // determined.
+ json::document_tree doc = {
+ { "array", { "one", 987.0 } }
+ };
+ assert(!"key_value_error was not thrown");
+ }
+ catch (const json::key_value_error&)
+ {
+ // expected.
+ }
+
+ // Explicitly define an array instead.
+ json::document_tree doc = {
+ { "array", json::array({ "one", 987.0 }) }
+ };
+
+ json::node node = doc.get_document_root();
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 1);
+ assert(node.key(0) == "array");
+
+ node = node.child(0);
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 2);
+ assert(node.child(0).string_value() == "one");
+ assert(node.child(1).numeric_value() == 987.0);
+
+ doc = json::array({1, 2, 3});
+ node = doc.get_document_root();
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 3);
+ assert(node.child(0).numeric_value() == 1.0);
+ assert(node.child(1).numeric_value() == 2.0);
+ assert(node.child(2).numeric_value() == 3.0);
+
+ node.push_back(4);
+ node.push_back(5);
+ assert(node.child_count() == 5);
+ assert(node.child(3).numeric_value() == 4.0);
+ assert(node.child(4).numeric_value() == 5.0);
+
+ // empty JSON with array root.
+ json::document_tree doc2 = json::array();
+ node = doc2.get_document_root();
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 0);
+
+ // Assigning a non-const node to a const one should work.
+ json::const_node cnode = node;
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 0);
+}
+
+void test_json_init_list_explicit_object()
+{
+ json::document_tree doc = json::object();
+ json::node node = doc.get_document_root();
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 0);
+
+ // Initialize with an array of 3 empty objects.
+ doc = {
+ json::object(),
+ json::object(),
+ json::object()
+ };
+
+ node = doc.get_document_root();
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 3);
+
+ for (size_t i = 0; i < 3; ++i)
+ {
+ node = node.child(i);
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 0);
+ node = node.parent();
+ }
+}
+
+void test_json_init_root_object_add_child()
+{
+ json::document_tree doc = json::object();
+ json::node node = doc.get_document_root();
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 0);
+
+ node["child1"] = 1.0;
+
+ assert(node.child_count() == 1);
+
+ node = node.child("child1");
+ assert(node.type() == json::node_t::number);
+ assert(node.numeric_value() == 1.0);
+
+ node = node.parent();
+ node["child2"] = "foo";
+
+ assert(node.child_count() == 2);
+
+ node = node.child("child2");
+ assert(node.type() == json::node_t::string);
+ assert(node.string_value() == "foo");
+
+ node = node.parent();
+
+ // Access to child via [] operator.
+ node = node["child1"];
+ assert(node.type() == json::node_t::number);
+ assert(node.numeric_value() == 1.0);
+
+ node = node.parent();
+ node["child3"] = { true, false };
+
+ node = node.child("child3");
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 2);
+
+ node = node.child(0);
+ assert(node.type() == json::node_t::boolean_true);
+
+ // Move up to the parent array.
+ node = node.parent();
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 2);
+
+ // Move down to the other child node.
+ node = node.child(1);
+ assert(node.type() == json::node_t::boolean_false);
+
+ // Move up to the root node.
+ node = node.parent().parent();
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 3);
+
+ node["child1"] = true; // overwrite an existing node.
+ node = node.child("child1");
+ assert(node.type() == json::node_t::boolean_true);
+
+ // direct assignment.
+ node = false;
+ assert(node.type() == json::node_t::boolean_false);
+
+ node = node.parent().child("child1"); // make sure the link is still intact.
+ assert(node.type() == json::node_t::boolean_false);
+
+ node = node.parent();
+ node["null-child"] = nullptr;
+
+ node = node.child("null-child");
+ assert(node.type() == json::node_t::null);
+
+ node = node.parent();
+ node["object-child"] = json::object();
+
+ node = node.child("object-child");
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 0);
+
+ node["array"] = json::array({true, false, nullptr});
+
+ node = node.child("array");
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 3);
+
+ node = node.parent();
+ node["nested-object"] =
+ {
+ { "key1", "foo" },
+ { "key2", 12.34 }
+ };
+
+ node = node.child("nested-object");
+ assert(node.type() == json::node_t::object);
+ assert(node.child_count() == 2);
+ assert(node.child("key1").string_value() == "foo");
+ assert(node.child("key2").numeric_value() == 12.34);
+}
+
+void test_json_init_empty_array()
+{
+ json::document_tree doc = json::array();
+ json::node node = doc.get_document_root();
+ assert(node.type() == json::node_t::array);
+
+ doc = {
+ { "key1", json::array({true, false}) },
+ { "key2", json::array() } // empty array
+ };
+
+ node = doc.get_document_root();
+ assert(node.type() == json::node_t::object);
+ node = node["key1"];
+ assert(node.type() == json::node_t::array);
+ node = node.parent()["key2"];
+ assert(node.type() == json::node_t::array);
+}
+
+void test_json_dynamic_object_keys()
+{
+ json::document_tree doc = json::object();
+ json::node root = doc.get_document_root();
+
+ /* {"test": [1.2, 1.3]} */
+ auto node = root["test"];
+ node = json::array();
+ node.push_back(1.2);
+ node.push_back(1.3);
+
+ // Dump the doc as a string and reload it.
+ doc.load(doc.dump(), json_config());
+ root = doc.get_document_root();
+ assert(root.type() == json::node_t::object);
+ node = root["test"];
+ assert(node.type() == json::node_t::array);
+ assert(node.child_count() == 2u);
+ assert(node.child(0).numeric_value() == 1.2);
+ assert(node.child(1).numeric_value() == 1.3);
+}
+
+int main()
+{
+ try
+ {
+ test_json_parse();
+ test_json_resolve_refs();
+ test_json_parse_empty();
+ test_json_parse_invalid();
+ test_json_traverse_basic1();
+ test_json_traverse_basic2();
+ test_json_traverse_basic3();
+ test_json_traverse_basic4();
+ test_json_traverse_nested1();
+ test_json_traverse_nested2();
+
+ test_json_init_list_flat1();
+ test_json_init_list_nested1();
+ test_json_init_list_object1();
+ test_json_init_list_object2();
+ test_json_init_list_explicit_array();
+ test_json_init_list_explicit_object();
+ test_json_init_root_object_add_child();
+ test_json_init_empty_array();
+ test_json_dynamic_object_keys();
+ }
+ catch (const orcus::general_error& e)
+ {
+ std::cerr << e.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_map_tree.cpp b/src/liborcus/json_map_tree.cpp
new file mode 100644
index 0000000..294e782
--- /dev/null
+++ b/src/liborcus/json_map_tree.cpp
@@ -0,0 +1,786 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "json_map_tree.hpp"
+#include "orcus/measurement.hpp"
+
+#include <iostream>
+#include <sstream>
+
+namespace orcus {
+
+constexpr json_map_tree::child_position_type json_map_tree::node_child_default_position;
+
+namespace {
+
+void throw_path_error(const char* file, int line, std::string_view path)
+{
+ std::ostringstream os;
+ os << file << "#" << line << ": failed to link this path '" << path << "'";
+ throw json_map_tree::path_error(os.str());
+}
+
+enum class json_path_token_t { unknown, array_pos, object_key, end };
+
+struct json_path_token_value_t
+{
+ json_path_token_t type = json_path_token_t::unknown;
+
+ union
+ {
+ json_map_tree::child_position_type array_pos = json_map_tree::node_child_default_position;
+
+ struct
+ {
+ const char* p;
+ size_t n;
+
+ } str;
+
+ } value;
+
+ json_path_token_value_t(json_path_token_t _type) : type(_type) {}
+
+ json_path_token_value_t(json_map_tree::child_position_type array_pos): type(json_path_token_t::array_pos)
+ {
+ value.array_pos = array_pos;
+ }
+
+ json_path_token_value_t(const char* p, size_t n) : type(json_path_token_t::object_key)
+ {
+ value.str.p = p;
+ value.str.n = n;
+ }
+};
+
+std::string_view get_last_object_key(const std::vector<json_path_token_value_t>& stack)
+{
+ if (stack.size() < 2)
+ return std::string_view{};
+
+ auto it = stack.rbegin();
+ ++it;
+ const json_path_token_value_t& t2 = *it;
+ if (t2.type != json_path_token_t::object_key)
+ return std::string_view{};
+
+ return std::string_view{t2.value.str.p, t2.value.str.n};
+}
+
+class json_path_parser
+{
+ const char* mp_cur;
+ const char* mp_end;
+
+public:
+
+ json_path_parser(std::string_view path) :
+ mp_cur(path.data()),
+ mp_end(mp_cur + path.size())
+ {
+ assert(!path.empty());
+ assert(path[0] == '$');
+ ++mp_cur; // skip the first '$'.
+ }
+
+ json_path_token_value_t next()
+ {
+ if (mp_cur == mp_end)
+ return json_path_token_t::end;
+
+ if (*mp_cur == '[')
+ return next_pos();
+
+ return json_path_token_t::unknown;
+ }
+
+ json_path_token_value_t next_object_key()
+ {
+ assert(*mp_cur == '\'');
+ ++mp_cur;
+ const char* p_head = mp_cur;
+
+ for (; mp_cur != mp_end && *mp_cur != '\''; ++mp_cur)
+ {
+ // Skip until we reach the closing quote.
+ }
+
+ if (*mp_cur != '\'')
+ return json_path_token_t::unknown;
+
+ size_t n = std::distance(p_head, mp_cur);
+
+ ++mp_cur; // Skip the quote.
+ if (*mp_cur != ']')
+ return json_path_token_t::unknown;
+
+ ++mp_cur; // Skip the ']'.
+
+ return json_path_token_value_t(p_head, n);
+ }
+
+ json_path_token_value_t next_pos()
+ {
+ assert(*mp_cur == '[');
+ ++mp_cur; // Skip the '['.
+
+ if (mp_cur == mp_end)
+ return json_path_token_t::unknown;
+
+ if (*mp_cur == '\'')
+ return next_object_key();
+
+ const char* p_head = mp_cur;
+
+ for (; mp_cur != mp_end; ++mp_cur)
+ {
+ if (*mp_cur != ']')
+ continue;
+
+ if (p_head == mp_cur)
+ {
+ // empty brackets.
+ ++mp_cur;
+ return json_map_tree::node_child_default_position;
+ }
+
+ const char* p_parse_ended = nullptr;
+ std::size_t n = mp_cur - p_head;
+ long pos = to_long({p_head, n}, &p_parse_ended);
+
+ if (p_parse_ended != mp_cur)
+ // Parsing failed.
+ break;
+
+ if (pos < 0)
+ // array position cannot be negative.
+ break;
+
+ ++mp_cur; // skip the ']'.
+ return pos;
+ }
+
+ return json_path_token_t::unknown;
+ }
+};
+
+} // anonymous namespace
+
+json_map_tree::path_error::path_error(const std::string& msg) :
+ general_error(msg) {}
+
+json_map_tree::cell_reference_type::cell_reference_type(const cell_position_t& _pos) :
+ pos(_pos) {}
+
+json_map_tree::range_reference_type::range_reference_type(const cell_position_t& _pos) :
+ pos(_pos), row_position(0), row_header(false) {}
+
+json_map_tree::node::node() {}
+json_map_tree::node::node(node&& other) :
+ type(other.type)
+{
+ value.children = nullptr;
+
+ switch (type)
+ {
+ case map_node_type::array:
+ value.children = other.value.children;
+ other.value.children = nullptr;
+ break;
+ case map_node_type::cell_ref:
+ value.cell_ref = other.value.cell_ref;
+ other.value.cell_ref = nullptr;
+ break;
+ case map_node_type::range_field_ref:
+ value.range_field_ref = other.value.range_field_ref;
+ other.value.range_field_ref = nullptr;
+ default:
+ ;
+ }
+
+ other.type = map_node_type::unknown;
+
+ row_group = other.row_group;
+ other.row_group = nullptr;
+
+ anchored_fields = std::move(other.anchored_fields);
+}
+
+json_map_tree::node& json_map_tree::node::get_or_create_child_node(child_position_type pos)
+{
+ node_children_type& children = *value.children;
+
+ auto it = children.lower_bound(pos); // get the first position where pos <= k is true.
+
+ if (it == children.end() || children.key_comp()(pos, it->first))
+ {
+ // Insert a new array child node of unspecified type at the specified position.
+ it = children.insert(
+ it, node_children_type::value_type(pos, node()));
+ }
+
+ assert(it->first == pos);
+ return it->second;
+}
+
+json_map_tree::walker::scope::scope(node* _p) : p(_p), array_position(0) {}
+
+json_map_tree::walker::walker(const json_map_tree& parent) : m_parent(parent) {}
+
+json_map_tree::node* json_map_tree::walker::push_node(input_node_type nt)
+{
+ if (!m_unlinked_stack.empty())
+ {
+ // We're still in the unlinked region.
+ m_unlinked_stack.push_back(nt);
+ return nullptr;
+ }
+
+ if (m_stack.empty())
+ {
+ if (!m_parent.m_root)
+ {
+ // Tree is empty.
+ m_unlinked_stack.push_back(nt);
+ return nullptr;
+ }
+
+ node* p = m_parent.m_root.get();
+
+ if (!is_equivalent(nt, p->type))
+ {
+ // Different node type.
+ m_unlinked_stack.push_back(nt);
+ return nullptr;
+ }
+
+ m_stack.push_back(p);
+ return m_stack.back().p;
+ }
+
+ scope& cur_scope = m_stack.back();
+
+ switch (cur_scope.p->type)
+ {
+ case json_map_tree::map_node_type::array:
+ {
+ node_children_type& node_children = *cur_scope.p->value.children;
+
+ auto it = node_children.find(cur_scope.array_position++);
+ if (it == node_children.end())
+ it = node_children.find(json_map_tree::node_child_default_position);
+
+ if (it == node_children.end())
+ {
+ // This array node has no children.
+ m_unlinked_stack.push_back(nt);
+ return nullptr;
+ }
+
+ node* p = &it->second;
+
+ if (!is_equivalent(nt, p->type))
+ {
+ // Different node type.
+ m_unlinked_stack.push_back(nt);
+ return nullptr;
+ }
+
+ m_stack.push_back(p);
+ return m_stack.back().p;
+ }
+ case json_map_tree::map_node_type::object:
+ {
+ node_children_type& node_children = *cur_scope.p->value.children;
+ auto it = node_children.find(cur_scope.array_position);
+ if (it == node_children.end())
+ {
+ // The currently specified key does not exist in this object.
+ m_unlinked_stack.push_back(nt);
+ return nullptr;
+ }
+
+ node* p = &it->second;
+
+ if (!is_equivalent(nt, p->type))
+ {
+ // Different node type.
+ m_unlinked_stack.push_back(nt);
+ return nullptr;
+ }
+
+ m_stack.push_back(p);
+ return m_stack.back().p;
+ }
+ default:
+ ;
+ }
+
+ m_unlinked_stack.push_back(nt);
+ return nullptr;
+}
+
+json_map_tree::node* json_map_tree::walker::pop_node(input_node_type nt)
+{
+ if (!m_unlinked_stack.empty())
+ {
+ // We're in the unlinked region. Pop a node from the unlinked stack.
+ if (m_unlinked_stack.back() != nt)
+ throw general_error("Closing node is of different type than the opening node in the unlinked node stack.");
+
+ m_unlinked_stack.pop_back();
+
+ if (!m_unlinked_stack.empty())
+ // We are still in the unlinked region.
+ return nullptr;
+
+ return m_stack.empty() ? nullptr : m_stack.back().p;
+ }
+
+ if (m_stack.empty())
+ throw general_error("A node was popped while the stack was empty.");
+
+ if (!is_equivalent(nt, m_stack.back().p->type))
+ throw general_error("Closing node is of different type than the opening node in the linked node stack.");
+
+ m_stack.pop_back();
+ return m_stack.empty() ? nullptr : m_stack.back().p;
+}
+
+void json_map_tree::walker::set_object_key(const char* p, size_t n)
+{
+ if (!m_unlinked_stack.empty())
+ return;
+
+ if (m_stack.empty())
+ return;
+
+ scope& cur_scope = m_stack.back();
+ if (cur_scope.p->type != map_node_type::object)
+ return;
+
+ std::string_view pooled = m_parent.m_str_pool.intern({p, n}).first;
+ cur_scope.array_position = reinterpret_cast<child_position_type>(pooled.data());
+}
+
+json_map_tree::json_map_tree() {}
+json_map_tree::~json_map_tree() {}
+
+json_map_tree::walker json_map_tree::get_tree_walker() const
+{
+ return walker(*this);
+}
+
+void json_map_tree::set_cell_link(std::string_view path, const cell_position_t& pos)
+{
+ path_stack_type stack = get_or_create_destination_node(path);
+ if (stack.node_stack.empty())
+ return;
+
+ node* p = stack.node_stack.back();
+ if (p->type != map_node_type::unknown)
+ {
+ std::ostringstream os;
+ os << "this path is not linkable: '" << path << '\'';
+ throw path_error(os.str());
+ }
+
+ p->type = map_node_type::cell_ref;
+ p->value.cell_ref = m_cell_ref_pool.construct(pos);
+
+ // Ensure that this tree owns the instance of the string.
+ p->value.cell_ref->pos.sheet = m_str_pool.intern(p->value.cell_ref->pos.sheet).first;
+}
+
+const json_map_tree::node* json_map_tree::get_link(std::string_view path) const
+{
+ return get_destination_node(path);
+}
+
+void json_map_tree::start_range(const cell_position_t& pos, bool row_header)
+{
+ m_current_range.pos = pos;
+ m_current_range.fields.clear();
+ m_current_range.row_groups.clear();
+ m_current_range.row_header = row_header;
+}
+
+void json_map_tree::append_field_link(std::string_view path, std::string_view label)
+{
+ m_current_range.fields.emplace_back(path, label);
+}
+
+void json_map_tree::set_range_row_group(std::string_view path)
+{
+ m_current_range.row_groups.push_back(path);
+}
+
+void json_map_tree::commit_range()
+{
+ range_reference_type* ref = &get_range_reference(m_current_range.pos);
+ ref->row_header = m_current_range.row_header;
+ spreadsheet::col_t column_pos = 0;
+
+ for (std::string_view path : m_current_range.row_groups)
+ {
+ path_stack_type stack = get_or_create_destination_node(path);
+ if (stack.node_stack.empty())
+ throw_path_error(__FILE__, __LINE__, path);
+
+ stack.node_stack.back()->row_group = ref;
+ }
+
+ long unlabeled_field_count = 0;
+
+ for (const auto& field : m_current_range.fields)
+ {
+ std::string_view path = field.first;
+ std::string_view label = field.second;
+
+ path_stack_type stack = get_or_create_destination_node(path);
+ if (stack.node_stack.empty() || stack.node_stack.back()->type != map_node_type::unknown)
+ throw_path_error(__FILE__, __LINE__, path);
+
+ node* p = stack.node_stack.back();
+ p->type = map_node_type::range_field_ref;
+ p->value.range_field_ref = m_range_field_ref_pool.construct();
+ p->value.range_field_ref->column_pos = column_pos++;
+ p->value.range_field_ref->ref = ref;
+
+ if (!label.empty())
+ {
+ // A custom label is specified. This one takes precedence.
+ p->value.range_field_ref->label = m_str_pool.intern(label).first;
+ }
+ else if (stack.dest_key.empty())
+ {
+ // This field is probably associated with an array.
+ std::ostringstream os;
+ os << "field " << unlabeled_field_count++;
+ p->value.range_field_ref->label = m_str_pool.intern(os.str()).first;
+ }
+ else
+ // This field is associated with an object key. Use its key as the label.
+ p->value.range_field_ref->label = m_str_pool.intern(stack.dest_key).first;
+
+ ref->fields.push_back(p->value.range_field_ref);
+
+ // Find the first row group node ancountered going up from the field
+ // node, and anchor itself to it.
+ for (auto it = stack.node_stack.rbegin(); it != stack.node_stack.rend(); ++it)
+ {
+ node* anchor_node = *it;
+ if (anchor_node->row_group)
+ {
+ anchor_node->anchored_fields.push_back(p);
+ break;
+ }
+ }
+ }
+}
+
+json_map_tree::range_ref_store_type& json_map_tree::get_range_references()
+{
+ return m_range_refs;
+}
+
+json_map_tree::range_reference_type& json_map_tree::get_range_reference(const cell_position_t& pos)
+{
+ auto it = m_range_refs.lower_bound(pos);
+ if (it == m_range_refs.end() || m_range_refs.key_comp()(m_current_range.pos, it->first))
+ {
+ // Ensure that we own the sheet name instance before storing it.
+ m_current_range.pos.sheet = m_str_pool.intern(m_current_range.pos.sheet).first;
+
+ it = m_range_refs.insert(
+ it, range_ref_store_type::value_type(
+ m_current_range.pos, range_reference_type(m_current_range.pos)));
+ }
+
+ return it->second;
+}
+
+const json_map_tree::node* json_map_tree::get_destination_node(std::string_view path) const
+{
+ if (!m_root)
+ // The tree is empty.
+ return nullptr;
+
+ if (path.empty() || path[0] != '$')
+ // A valid path must begin with a '$'.
+ return nullptr;
+
+ json_path_parser parser(path);
+ const node* cur_node = m_root.get();
+
+ for (json_path_token_value_t t = parser.next(); t.type != json_path_token_t::unknown; t = parser.next())
+ {
+ switch (t.type)
+ {
+ case json_path_token_t::array_pos:
+ {
+ if (cur_node->type != map_node_type::array)
+ return nullptr;
+
+ auto it = cur_node->value.children->find(t.value.array_pos);
+ if (it == cur_node->value.children->end())
+ return nullptr;
+
+ cur_node = &it->second;
+ break;
+ }
+ case json_path_token_t::object_key:
+ {
+ if (cur_node->type != map_node_type::object)
+ return nullptr;
+
+ child_position_type pos = to_key_position(t.value.str.p, t.value.str.n);
+
+ auto it = cur_node->value.children->find(pos);
+ if (it == cur_node->value.children->end())
+ return nullptr;
+
+ cur_node = &it->second;
+ break;
+ }
+ case json_path_token_t::end:
+ return cur_node;
+ case json_path_token_t::unknown:
+ default:
+ // Something has gone wrong. Bail out.
+ break;
+ }
+ }
+
+ // If this code path reaches here, something has gone wrong.
+ return nullptr;
+}
+
+json_map_tree::path_stack_type json_map_tree::get_or_create_destination_node(std::string_view path)
+{
+ path_stack_type stack;
+
+ if (path.empty() || path[0] != '$')
+ // A valid path must begin with a '$'.
+ return stack;
+
+ json_path_parser parser(path);
+ json_path_token_value_t t = parser.next();
+
+ std::vector<json_path_token_value_t> token_stack;
+ token_stack.push_back(t);
+
+ switch (t.type)
+ {
+ case json_path_token_t::array_pos:
+ {
+ // Insert or re-use an array node and its child at specified position.
+
+ if (m_root)
+ {
+ if (m_root->type == map_node_type::unknown)
+ {
+ m_root->type = map_node_type::array;
+ m_root->value.children = m_node_children_pool.construct();
+ }
+
+ if (m_root->type != map_node_type::array)
+ throw path_error("root node was expected to be of type array, but is not.");
+ }
+ else
+ {
+ m_root = std::make_unique<node>();
+ m_root->type = map_node_type::array;
+ m_root->value.children = m_node_children_pool.construct();
+ }
+
+ stack.node_stack.push_back(m_root.get());
+ node* p = &stack.node_stack.back()->get_or_create_child_node(t.value.array_pos);
+ stack.node_stack.push_back(p);
+ break;
+ }
+ case json_path_token_t::object_key:
+ {
+ if (m_root)
+ {
+ if (m_root->type == map_node_type::unknown)
+ {
+ m_root->type = map_node_type::object;
+ m_root->value.children = m_node_children_pool.construct();
+ }
+
+ if (m_root->type != map_node_type::object)
+ throw path_error("root node was expected to be of type array, but is not.");
+ }
+ else
+ {
+ m_root = std::make_unique<node>();
+ m_root->type = map_node_type::object;
+ m_root->value.children = m_node_children_pool.construct();
+ }
+
+ stack.node_stack.push_back(m_root.get());
+ child_position_type pos = to_key_position(t.value.str.p, t.value.str.n);
+ node* p = &stack.node_stack.back()->get_or_create_child_node(pos);
+ stack.node_stack.push_back(p);
+ break;
+ }
+ case json_path_token_t::end:
+ {
+ if (!m_root)
+ {
+ m_root = std::make_unique<node>();
+ m_root->type = map_node_type::unknown;
+ }
+
+ stack.node_stack.push_back(m_root.get());
+ return stack;
+ }
+ default:
+ // Something has gone wrong. Bail out.
+ stack.node_stack.clear();
+ return stack;
+ }
+
+ for (t = parser.next(); t.type != json_path_token_t::unknown; t = parser.next())
+ {
+ token_stack.push_back(t);
+ node* cur_node = stack.node_stack.back();
+
+ switch (t.type)
+ {
+ case json_path_token_t::array_pos:
+ {
+ switch (cur_node->type)
+ {
+ case map_node_type::array:
+ // Do nothing.
+ break;
+ case map_node_type::unknown:
+ // Turn this node into an array node.
+ cur_node->type = map_node_type::array;
+ cur_node->value.children = m_node_children_pool.construct();
+ break;
+ default:
+ throw_path_error(__FILE__, __LINE__, path);
+ }
+ node* p = &stack.node_stack.back()->get_or_create_child_node(t.value.array_pos);
+ stack.node_stack.push_back(p);
+ break;
+ }
+ case json_path_token_t::object_key:
+ {
+ switch (cur_node->type)
+ {
+ case map_node_type::object:
+ // Do nothing.
+ break;
+ case map_node_type::unknown:
+ // Turn this node into an object node.
+ cur_node->type = map_node_type::object;
+ cur_node->value.children = m_node_children_pool.construct();
+ break;
+ default:
+ throw_path_error(__FILE__, __LINE__, path);
+ }
+
+ // For an object children, we use the memory address of a
+ // pooled key string as its position.
+ child_position_type pos = to_key_position(t.value.str.p, t.value.str.n);
+ node* p = &stack.node_stack.back()->get_or_create_child_node(pos);
+ stack.node_stack.push_back(p);
+ break;
+ }
+ case json_path_token_t::end:
+ {
+ assert(token_stack.size() >= 2);
+ stack.dest_key = get_last_object_key(token_stack);
+
+ return stack;
+ }
+ case json_path_token_t::unknown:
+ default:
+ // Something has gone wrong. Bail out.
+ break;
+ }
+ }
+
+ // If this code path reaches here, something has gone wrong.
+ stack.node_stack.clear();
+ return stack;
+}
+
+json_map_tree::child_position_type json_map_tree::to_key_position(const char* p, size_t n) const
+{
+ std::string_view pooled_key = m_str_pool.intern({p, n}).first;
+ child_position_type pos = reinterpret_cast<child_position_type>(pooled_key.data());
+ return pos;
+}
+
+bool json_map_tree::is_equivalent(input_node_type input_node, map_node_type map_node)
+{
+ uint8_t left = (0x0F & uint8_t(input_node));
+ uint8_t right = (0x0F & uint8_t(map_node));
+ return left == right;
+}
+
+std::ostream& operator<< (std::ostream& os, json_map_tree::input_node_type nt)
+{
+ os << "(input-node-type: ";
+
+ switch (nt)
+ {
+ case json_map_tree::input_node_type::array:
+ os << "array";
+ break;
+ case json_map_tree::input_node_type::object:
+ os << "object";
+ break;
+ case json_map_tree::input_node_type::value:
+ os << "value";
+ break;
+ case json_map_tree::input_node_type::unknown:
+ os << "unknown";
+ break;
+ }
+
+ os << ')';
+
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, json_map_tree::map_node_type nt)
+{
+ os << "(map-node-type: ";
+
+ switch (nt)
+ {
+ case json_map_tree::map_node_type::array:
+ os << "array";
+ break;
+ case json_map_tree::map_node_type::cell_ref:
+ os << "cell-ref";
+ break;
+ case json_map_tree::map_node_type::object:
+ os << "object";
+ break;
+ case json_map_tree::map_node_type::range_field_ref:
+ os << "range-field-ref";
+ break;
+ case json_map_tree::map_node_type::unknown:
+ os << "unknown";
+ break;
+ }
+
+ os << ')';
+
+ return os;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_map_tree.hpp b/src/liborcus/json_map_tree.hpp
new file mode 100644
index 0000000..9470af0
--- /dev/null
+++ b/src/liborcus/json_map_tree.hpp
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "spreadsheet_impl_types.hpp"
+#include "orcus/string_pool.hpp"
+#include "orcus/exception.hpp"
+
+#include <boost/pool/object_pool.hpp>
+#include <memory>
+#include <map>
+#include <vector>
+#include <iosfwd>
+
+namespace orcus {
+
+using spreadsheet::detail::cell_position_t;
+
+class json_map_tree
+{
+public:
+ using child_position_type = std::uintptr_t;
+
+ static constexpr child_position_type node_child_default_position = -1;
+
+ /**
+ * Error indicating improper path.
+ */
+ class path_error : public general_error
+ {
+ public:
+ path_error(const std::string& msg);
+ };
+
+ struct node;
+ struct range_reference_type;
+ using node_children_type = std::map<child_position_type, node>;
+ using range_ref_store_type = std::map<cell_position_t, range_reference_type>;
+
+ /** Types of nodes in the json input tree. */
+ enum class input_node_type { unknown = 0x00, array = 0x01, object = 0x02, value = 0x04 };
+
+ /**
+ * Types of nodes in the map tree. The lower 4-bits specify the input
+ * node type which are kept in sync with the input_node_type values. The
+ * next 4-bits specify the link type.
+ */
+ enum class map_node_type { unknown = 0x00, array = 0x01, object = 0x02, cell_ref = 0x14, range_field_ref = 0x24 };
+
+ struct cell_reference_type
+ {
+ cell_position_t pos;
+
+ cell_reference_type(const cell_position_t& _pos);
+ };
+
+ struct range_field_reference_type;
+
+ struct range_reference_type
+ {
+ cell_position_t pos;
+ std::vector<const range_field_reference_type*> fields;
+ spreadsheet::row_t row_position;
+ bool row_header;
+
+ range_reference_type(const cell_position_t& _pos);
+ };
+
+ /** Represents a field within a range reference. */
+ struct range_field_reference_type
+ {
+ range_reference_type* ref;
+ spreadsheet::col_t column_pos;
+ std::string_view label;
+ };
+
+ struct node
+ {
+ map_node_type type = map_node_type::unknown;
+
+ union
+ {
+ node_children_type* children = nullptr;
+ cell_reference_type* cell_ref;
+ range_field_reference_type* range_field_ref;
+
+ } value;
+
+ /**
+ * The node is a row-group node (node that defines a row boundary)
+ * if this value is set to a non-null value. If this is not null, it
+ * points to the range_reference instance it belongs to.
+ */
+ range_reference_type* row_group = nullptr;
+
+ std::vector<node*> anchored_fields;
+
+ node(const node&) = delete;
+ node& operator=(const node&) = delete;
+
+ node();
+ node(node&& other);
+
+ node& get_or_create_child_node(child_position_type pos);
+ };
+
+ class walker
+ {
+ friend class json_map_tree;
+
+ struct scope
+ {
+ node* p;
+ child_position_type array_position;
+
+ scope(node* _p);
+ };
+
+ using stack_type = std::vector<scope>;
+ using unlinked_stack_type = std::vector<input_node_type>;
+
+ const json_map_tree& m_parent;
+ stack_type m_stack;
+ unlinked_stack_type m_unlinked_stack;
+
+ walker(const json_map_tree& parent);
+ public:
+
+ node* push_node(input_node_type nt);
+ node* pop_node(input_node_type nt);
+
+ void set_object_key(const char* p, size_t n);
+ };
+
+ json_map_tree();
+ ~json_map_tree();
+
+ walker get_tree_walker() const;
+
+ void set_cell_link(std::string_view path, const cell_position_t& pos);
+
+ const node* get_link(std::string_view path) const;
+
+ void start_range(const cell_position_t& pos, bool row_header);
+ void append_field_link(std::string_view path, std::string_view label);
+ void set_range_row_group(std::string_view path);
+ void commit_range();
+
+ range_ref_store_type& get_range_references();
+
+private:
+ range_reference_type& get_range_reference(const cell_position_t& pos);
+
+ const node* get_destination_node(std::string_view path) const;
+
+ struct path_stack_type
+ {
+ std::vector<node*> node_stack;
+ std::string_view dest_key; //< object key associated with the destination value (if applicable)
+ };
+
+ path_stack_type get_or_create_destination_node(std::string_view path);
+
+ child_position_type to_key_position(const char* p, size_t n) const;
+
+ static bool is_equivalent(input_node_type input_node, map_node_type map_node);
+
+private:
+ boost::object_pool<node_children_type> m_node_children_pool;
+ boost::object_pool<cell_reference_type> m_cell_ref_pool;
+ boost::object_pool<range_field_reference_type> m_range_field_ref_pool;
+
+ mutable string_pool m_str_pool;
+
+ std::unique_ptr<node> m_root;
+
+ range_ref_store_type m_range_refs;
+
+ struct
+ {
+ cell_position_t pos;
+ std::vector<std::pair<std::string_view, std::string_view>> fields; // path, label
+ std::vector<std::string_view> row_groups;
+ bool row_header;
+
+ } m_current_range;
+};
+
+std::ostream& operator<< (std::ostream& os, json_map_tree::input_node_type nt);
+std::ostream& operator<< (std::ostream& os, json_map_tree::map_node_type nt);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_map_tree_test.cpp b/src/liborcus/json_map_tree_test.cpp
new file mode 100644
index 0000000..6100bd9
--- /dev/null
+++ b/src/liborcus/json_map_tree_test.cpp
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "json_map_tree.hpp"
+
+#include <cassert>
+#include <iostream>
+
+using namespace orcus;
+using namespace std;
+
+void test_link_array_values()
+{
+ json_map_tree tree;
+
+ cell_position_t pos("sheet", 0, 0);
+
+ tree.set_cell_link("$[0]", pos);
+ pos.row = 1;
+ tree.set_cell_link("$[][0]", pos);
+
+ const json_map_tree::node* p = tree.get_link("$[0]");
+ assert(p);
+ assert(p->type == json_map_tree::map_node_type::cell_ref);
+ assert(p->value.cell_ref->pos == cell_position_t("sheet", 0, 0));
+
+ p = tree.get_link("$[][0]");
+ assert(p);
+ assert(p->type == json_map_tree::map_node_type::cell_ref);
+ assert(p->value.cell_ref->pos == cell_position_t("sheet", 1, 0));
+}
+
+void test_link_object_values()
+{
+ struct entry
+ {
+ const char* path;
+ cell_position_t pos;
+ };
+
+ std::vector<entry> entries =
+ {
+ { "$[]['id']", cell_position_t("sheet", 2, 3) },
+ { "$[]['name']", cell_position_t("sheet", 2, 4) },
+ { "$[]['address']", cell_position_t("sheet", 2, 5) },
+ };
+
+ json_map_tree tree;
+
+ for (const entry& e : entries)
+ tree.set_cell_link(e.path, e.pos);
+
+ for (const entry& e : entries)
+ {
+ const json_map_tree::node* p = tree.get_link(e.path);
+ assert(p);
+ assert(p->type == json_map_tree::map_node_type::cell_ref);
+ assert(e.pos == p->value.cell_ref->pos);
+ }
+}
+
+void test_link_object_root()
+{
+ json_map_tree tree;
+
+ const char* path = "$['root'][2]";
+ cell_position_t pos("sheet", 3, 4);
+ tree.set_cell_link(path, pos);
+
+ const json_map_tree::node* p = tree.get_link(path);
+ assert(p);
+ assert(p->type == json_map_tree::map_node_type::cell_ref);
+ assert(p->value.cell_ref->pos == pos);
+}
+
+void test_link_range_fields()
+{
+ json_map_tree tree;
+
+ cell_position_t pos("sheet", 1, 2);
+
+ tree.start_range(pos, false);
+ tree.append_field_link("$[][0]", std::string_view{});
+ tree.append_field_link("$[][1]", std::string_view{});
+ tree.append_field_link("$[][2]", std::string_view{});
+ tree.set_range_row_group("$[]");
+ tree.commit_range();
+
+ const json_map_tree::node* p = tree.get_link("$[][0]");
+ assert(p);
+ assert(p->type == json_map_tree::map_node_type::range_field_ref);
+ assert(p->value.range_field_ref->column_pos == 0);
+
+ p = tree.get_link("$[][1]");
+ assert(p);
+ assert(p->type == json_map_tree::map_node_type::range_field_ref);
+ assert(p->value.range_field_ref->column_pos == 1);
+
+ p = tree.get_link("$[][2]");
+ assert(p);
+ assert(p->type == json_map_tree::map_node_type::range_field_ref);
+ assert(p->value.range_field_ref->column_pos == 2);
+
+ // Check the range reference data itself.
+ const json_map_tree::range_reference_type* ref = p->value.range_field_ref->ref;
+ assert(ref->fields.size() == 3);
+ assert(ref->pos == pos);
+
+ // Make sure the row group is set.
+ p = tree.get_link("$[]");
+ assert(p);
+ assert(p->type == json_map_tree::map_node_type::array);
+ assert(p->row_group == ref);
+}
+
+int main()
+{
+ test_link_array_values();
+ test_link_object_values();
+ test_link_object_root();
+ test_link_range_fields();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_structure_mapper.cpp b/src/liborcus/json_structure_mapper.cpp
new file mode 100644
index 0000000..09a9e97
--- /dev/null
+++ b/src/liborcus/json_structure_mapper.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "json_structure_mapper.hpp"
+
+#include <algorithm>
+#include <sstream>
+#include <cassert>
+
+namespace orcus { namespace json { namespace detail {
+
+structure_mapper::structure_mapper(structure_tree::range_handler_type rh, const json::structure_tree::walker& walker) :
+ m_walker(walker),
+ m_range_handler(std::move(rh)),
+ m_repeat_count(0) {}
+
+void structure_mapper::run()
+{
+ reset();
+ traverse(0);
+}
+
+void structure_mapper::reset()
+{
+ m_walker.root();
+ m_current_range.paths.clear();
+ m_current_range.row_groups.clear();
+ m_repeat_count = 0;
+}
+
+void structure_mapper::push_range()
+{
+ m_range_handler(std::move(m_current_range));
+
+ m_current_range.paths.clear();
+ m_current_range.row_groups.clear();
+}
+
+void structure_mapper::traverse(size_t /*pos*/)
+{
+ json::structure_tree::node_properties node = m_walker.get_node();
+
+ if (node.repeat)
+ {
+ ++m_repeat_count;
+ m_current_range.row_groups.push_back(m_walker.build_row_group_path());
+ }
+
+ if (m_repeat_count && node.type == json::structure_tree::node_type::value)
+ {
+ for (std::string path : m_walker.build_field_paths())
+ m_current_range.paths.push_back(std::move(path));
+ }
+
+ for (size_t i = 0, n = m_walker.child_count(); i < n; ++i)
+ {
+ m_walker.descend(i);
+ traverse(i);
+ m_walker.ascend();
+ }
+
+ if (node.repeat)
+ {
+ --m_repeat_count;
+
+ if (!m_repeat_count)
+ push_range();
+ }
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_structure_mapper.hpp b/src/liborcus/json_structure_mapper.hpp
new file mode 100644
index 0000000..6dfdd08
--- /dev/null
+++ b/src/liborcus/json_structure_mapper.hpp
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/json_structure_tree.hpp"
+
+#include <vector>
+#include <functional>
+
+namespace orcus { namespace json { namespace detail {
+
+class structure_mapper
+{
+public:
+ structure_mapper(json::structure_tree::range_handler_type rh, const json::structure_tree::walker& walker);
+
+ void run();
+
+private:
+ void reset();
+ void push_range();
+ void traverse(size_t pos);
+
+private:
+ json::structure_tree::walker m_walker;
+ json::structure_tree::range_handler_type m_range_handler;
+ size_t m_repeat_count;
+ json::table_range_t m_current_range;
+
+};
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_structure_tree.cpp b/src/liborcus/json_structure_tree.cpp
new file mode 100644
index 0000000..862b4de
--- /dev/null
+++ b/src/liborcus/json_structure_tree.cpp
@@ -0,0 +1,720 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/json_structure_tree.hpp>
+#include <orcus/json_parser.hpp>
+#include <orcus/string_pool.hpp>
+
+#include "json_structure_mapper.hpp"
+
+#include <vector>
+#include <memory>
+#include <algorithm>
+#include <map>
+#include <functional>
+
+#include <boost/pool/object_pool.hpp>
+
+namespace orcus { namespace json {
+
+namespace {
+
+struct structure_node;
+
+using node_children_type = std::vector<structure_node*>;
+using node_type = structure_tree::node_type;
+using array_positions_type = std::map<int32_t, bool>;
+
+/**
+ * Only pick those array positions that are marked "valid" - the associated
+ * boolean value is true.
+ */
+std::vector<int32_t> to_valid_array_positions(const array_positions_type& array_positions)
+{
+ std::vector<int32_t> aps;
+
+ for (const auto& e : array_positions)
+ {
+ if (e.second)
+ aps.push_back(e.first);
+ }
+
+ return aps;
+}
+
+/**
+ * Represents a node inside a JSON structure tree.
+ */
+struct structure_node
+{
+ bool repeat = false;
+
+ node_type type = node_type::unknown;
+
+ node_children_type children;
+
+ /**
+ * The number of child nodes in the source data tree, not to be confused
+ * with the number of child nodes in the structure tree.
+ */
+ int32_t child_count = 0;
+
+ std::string_view name; //< value of a key for a object key node.
+
+ /**
+ * For a value node that is an immediate child of an array node, these
+ * positions are the positions of the parent array that values always
+ * occur in the source data tree.
+ */
+ array_positions_type array_positions;
+
+ structure_node(node_type _type) : type(_type) {}
+
+ bool operator== (const structure_node& other) const
+ {
+ if (type != other.type)
+ return false;
+
+ if (type != node_type::object_key)
+ return true;
+
+ return name == other.name;
+ }
+
+ bool operator< (const structure_node& other) const
+ {
+ if (type != other.type)
+ return type < other.type;
+
+ if (name != other.name)
+ return name < other.name;
+
+ return true;
+ }
+};
+
+struct parse_scope
+{
+ structure_node& node;
+
+ int32_t child_count = 0;
+
+ parse_scope(structure_node& _node) : node(_node) {}
+};
+
+using parse_scopes_type = std::vector<parse_scope>;
+
+/**
+ * Represents a scope during structure tree traversal.
+ */
+struct scope
+{
+ const structure_node& node;
+ node_children_type::const_iterator current_pos;
+
+ scope(const structure_node& _node) :
+ node(_node),
+ current_pos(node.children.begin()) {}
+};
+
+using scope_stack_type = std::vector<scope>;
+
+void print_scope(std::ostream& os, const scope& s)
+{
+ switch (s.node.type)
+ {
+ case node_type::array:
+ os << "array";
+ break;
+ case node_type::object:
+ os << "object";
+ break;
+ case node_type::object_key:
+ os << "['" << s.node.name << "']";
+ break;
+ default:
+ os << "???";
+ }
+
+ if (s.node.repeat)
+ os << "(*)";
+
+ if (s.node.type == node_type::array && s.node.child_count)
+ os << '[' << s.node.child_count << ']';
+}
+
+void print_scopes(std::ostream& os, const scope_stack_type& scopes)
+{
+ auto it = scopes.cbegin();
+ auto ite = scopes.cend();
+
+ os << '$';
+ print_scope(os, *it);
+
+ for (++it; it != ite; ++it)
+ {
+ if (it->node.type != node_type::object_key)
+ os << '.';
+ print_scope(os, *it);
+ }
+}
+
+structure_tree::node_properties to_node_properties(const structure_node& sn)
+{
+ structure_tree::node_properties np;
+ np.type = sn.type;
+ np.repeat = sn.repeat;
+ return np;
+}
+
+} // anonymous namespace
+
+struct structure_tree::impl
+{
+ boost::object_pool<structure_node> m_node_store;
+ structure_node* m_root;
+ parse_scopes_type m_stack;
+ string_pool m_pool;
+
+ impl() : m_root(nullptr) {}
+ ~impl() {}
+
+ void begin_parse() {}
+
+ void end_parse() {}
+
+ void begin_array()
+ {
+ push_stack(node_type::array);
+ }
+
+ void end_array()
+ {
+ pop_stack();
+ }
+
+ void begin_object()
+ {
+ push_stack(node_type::object);
+ }
+
+ void object_key(std::string_view key, bool transient)
+ {
+ structure_node node(node_type::object_key);
+ node.name = key;
+
+ if (transient)
+ node.name = m_pool.intern(node.name).first;
+
+ push_stack(node);
+ }
+
+ void end_object()
+ {
+ pop_stack();
+ }
+
+ void boolean_true()
+ {
+ push_value();
+ }
+
+ void boolean_false()
+ {
+ push_value();
+ }
+
+ void null()
+ {
+ push_value();
+ }
+
+ void string(std::string_view /*val*/, bool /*transient*/)
+ {
+ push_value();
+ }
+
+ void number(double /*val*/)
+ {
+ push_value();
+ }
+
+ void normalize_tree()
+ {
+ if (!m_root)
+ return;
+
+ std::function<void(structure_node&)> descend = [&descend](structure_node& node)
+ {
+ if (node.children.empty())
+ return;
+
+ // Sort all children.
+ std::sort(node.children.begin(), node.children.end(),
+ [](const structure_node* left, const structure_node* right) -> bool
+ {
+ return *left < *right;
+ }
+ );
+
+ for (structure_node* child : node.children)
+ descend(*child);
+ };
+
+ descend(*m_root);
+ }
+
+ void dump_compact(std::ostream& os) const
+ {
+ if (!m_root)
+ return;
+
+ scope_stack_type scopes;
+ scopes.emplace_back(*m_root);
+
+ while (!scopes.empty())
+ {
+ scope& cur_scope = scopes.back();
+
+ bool new_scope = false;
+
+ for (; cur_scope.current_pos != cur_scope.node.children.end(); ++cur_scope.current_pos)
+ {
+ const structure_node& cur_node = **cur_scope.current_pos;
+
+ if (cur_node.type == node_type::value)
+ {
+ assert(cur_node.children.empty());
+
+ // Print all its parent scopes.
+ print_scopes(os, scopes);
+
+ // Print the value node at the end.
+ os << ".value";
+
+ // Print array positions if applicable.
+ std::vector<int32_t> aps = to_valid_array_positions(cur_node.array_positions);
+
+ if (!aps.empty())
+ {
+ os << '[';
+ auto it = aps.cbegin();
+ os << *it;
+ for (++it; it != aps.cend(); ++it)
+ os << ',' << *it;
+ os << ']';
+ }
+
+ os << std::endl;
+ continue;
+ }
+
+ if (cur_node.children.empty())
+ continue;
+
+ // This node has child nodes. Push a new scope and trigger a new inner loop.
+
+ ++cur_scope.current_pos; // Don't forget to move to the next sibling for when we return to this scope.
+ scopes.emplace_back(cur_node);
+ new_scope = true;
+ break;
+ }
+
+ if (new_scope)
+ continue;
+
+ scopes.pop_back();
+ }
+ }
+
+private:
+
+ parse_scope& get_current_scope()
+ {
+ assert(!m_stack.empty());
+ return m_stack.back();
+ }
+
+ bool is_node_repeatable(const structure_node& node) const
+ {
+ const structure_node& cur = m_stack.back().node;
+
+ if (cur.type != node_type::array)
+ return false;
+
+ return node.type == node_type::array || node.type == node_type::object;
+ }
+
+ void push_stack(const structure_node& node)
+ {
+ if (!m_root)
+ {
+ // This is the very first node.
+ assert(node.type != node_type::object_key);
+ m_root = m_node_store.construct(node.type);
+ m_stack.emplace_back(*m_root);
+ return;
+ }
+
+ parse_scope& cur_scope = get_current_scope();
+ structure_node& cur_node = cur_scope.node;
+
+ // Record the position of this new child in case the parent is an
+ // array and the new node is a value node.
+
+ int32_t array_pos = -1;
+
+ if (cur_node.type == node_type::array)
+ {
+ array_pos = cur_scope.child_count;
+
+ if (node.type != node_type::value)
+ {
+ // See if this array has a child value node.
+ auto it = std::find_if(
+ cur_node.children.begin(), cur_node.children.end(),
+ [](const structure_node* p) -> bool { return p->type == node_type::value; }
+ );
+
+ if (it != cur_node.children.end())
+ {
+ // It has a child value node. See if this value node has
+ // this array position recorded. If yes, turn it off
+ // since this position is not always a value.
+ array_positions_type& aps = (*it)->array_positions;
+ auto it_array_pos = aps.find(array_pos);
+ if (it_array_pos != aps.end())
+ it_array_pos->second = false;
+ }
+
+ array_pos = -1;
+ }
+ }
+
+ ++cur_scope.child_count;
+
+ {
+ // See if the current node has a child node of the specified type.
+ auto it = std::find_if(cur_node.children.begin(), cur_node.children.end(),
+ [&node](const structure_node* p) -> bool
+ {
+ return *p == node;
+ }
+ );
+
+ if (it == cur_node.children.end())
+ {
+ // current node doesn't have a child of specified type. Add one.
+ cur_node.children.push_back(m_node_store.construct(node));
+ m_stack.emplace_back(*cur_node.children.back());
+ }
+ else
+ {
+ // current node does have a child of specified type.
+ bool repeat = is_node_repeatable(node);
+ structure_node& child = **it;
+ child.repeat = repeat;
+ m_stack.emplace_back(child);
+ }
+ }
+
+ if (array_pos >= 0)
+ {
+ array_positions_type& aps = m_stack.back().node.array_positions;
+ int32_t min_pos = aps.empty() ? 0 : aps.begin()->first;
+ if (array_pos >= min_pos)
+ {
+ auto it = aps.lower_bound(array_pos);
+
+ if (it == aps.end() || aps.key_comp()(array_pos, it->first))
+ {
+ // Insert a new array child node of unspecified type at the specified position.
+ aps.insert(
+ it, array_positions_type::value_type(array_pos, true));
+ }
+ }
+ }
+ }
+
+ void push_value()
+ {
+ push_stack(node_type::value);
+ pop_stack();
+ }
+
+ void pop_stack()
+ {
+ parse_scope& cur_scope = get_current_scope();
+ structure_node& cur_node = cur_scope.node;
+ if (cur_scope.child_count > cur_node.child_count)
+ cur_node.child_count = cur_scope.child_count;
+
+ m_stack.pop_back();
+
+ if (!m_stack.empty() && get_current_scope().node.type == node_type::object_key)
+ // Object key is a special non-leaf node that can only have one child.
+ m_stack.pop_back();
+ }
+};
+
+struct structure_tree::walker::impl
+{
+ using stack_type = std::vector<const structure_node*>;
+
+ const structure_tree::impl* parent_impl;
+
+ stack_type stack;
+
+ impl() : parent_impl(nullptr) {}
+
+ impl(const structure_tree::impl* _parent_impl) : parent_impl(_parent_impl) {}
+
+ impl(const structure_tree::walker::impl& other) :
+ parent_impl(other.parent_impl) {}
+
+ void check_tree()
+ {
+ if (!parent_impl)
+ throw json_structure_error(
+ "This walker is not associated with any json_structure_tree instance.");
+
+ if (!parent_impl->m_root)
+ throw json_structure_error("Empty tree.");
+ }
+
+ void check_stack()
+ {
+ check_tree();
+
+ if (stack.empty())
+ throw json_structure_error(
+ "Walker stack is empty. Most likely caused by not calling root() to start the traversal.");
+ }
+};
+
+structure_tree::walker::walker() : mp_impl(std::make_unique<impl>()) {}
+structure_tree::walker::walker(const walker& other) : mp_impl(std::make_unique<impl>(*other.mp_impl)) {}
+structure_tree::walker::walker(const structure_tree::impl* parent_impl) : mp_impl(std::make_unique<impl>(parent_impl)) {}
+structure_tree::walker::~walker() {}
+
+void structure_tree::walker::root()
+{
+ mp_impl->check_tree();
+
+ mp_impl->stack.clear();
+ mp_impl->stack.push_back(mp_impl->parent_impl->m_root);
+}
+
+void structure_tree::walker::descend(size_t child_pos)
+{
+ mp_impl->check_stack();
+ assert(!mp_impl->stack.empty());
+
+ const structure_node* p = mp_impl->stack.back();
+ assert(p);
+
+ if (child_pos >= p->children.size())
+ {
+ std::ostringstream os;
+ os << "Specified child position of " << child_pos << " exceeds the child count of " << p->children.size() << '.';
+ throw json_structure_error(os.str());
+ }
+
+ p = p->children[child_pos];
+ assert(p);
+ mp_impl->stack.push_back(p);
+}
+
+void structure_tree::walker::ascend()
+{
+ mp_impl->check_stack();
+ assert(!mp_impl->stack.empty());
+
+ if (mp_impl->stack.size() == 1u)
+ throw json_structure_error("You cannot ascend from the root node.");
+
+ mp_impl->stack.pop_back();
+}
+
+size_t structure_tree::walker::child_count() const
+{
+ mp_impl->check_stack();
+ assert(!mp_impl->stack.empty());
+
+ const structure_node* p = mp_impl->stack.back();
+ return p->children.size();
+}
+
+structure_tree::node_properties structure_tree::walker::get_node() const
+{
+ mp_impl->check_stack();
+ assert(!mp_impl->stack.empty());
+
+ const structure_node* p = mp_impl->stack.back();
+ assert(p);
+ return to_node_properties(*p);
+}
+
+std::vector<std::string> structure_tree::walker::build_field_paths() const
+{
+ mp_impl->check_stack();
+ assert(!mp_impl->stack.empty());
+
+ if (mp_impl->stack.empty() || mp_impl->stack.back()->type != node_type::value)
+ throw json_structure_error("You can only build field paths to value node.");
+
+ std::ostringstream os;
+ os << '$';
+
+ auto it = mp_impl->stack.cbegin(), ite = mp_impl->stack.cend();
+
+ const structure_node* p = nullptr;
+ const structure_node* p_prev = *it;
+
+ for (++it; it != ite; ++it, p_prev = p)
+ {
+ p = *it;
+
+ switch (p_prev->type)
+ {
+ case structure_tree::node_type::array:
+ if (p->type != structure_tree::node_type::value)
+ os << "[]";
+ break;
+ case structure_tree::node_type::object_key:
+ os << "['" << p_prev->name << "']";
+ break;
+ default:
+ ;
+ }
+ }
+
+ if (p_prev->type == structure_tree::node_type::value && !p->array_positions.empty())
+ {
+ // non-empty array positions implies that the parent is an array.
+ std::vector<int32_t> aps = to_valid_array_positions(p->array_positions);
+ if (!aps.empty())
+ {
+ std::vector<std::string> ret;
+ std::string base = os.str();
+ for (int32_t ap : aps)
+ {
+ std::ostringstream path;
+ path << base << '[' << ap << ']';
+ ret.push_back(path.str());
+ }
+
+ return ret;
+ }
+ }
+
+ return std::vector<std::string>(1u, os.str());
+}
+
+std::string structure_tree::walker::build_row_group_path() const
+{
+ mp_impl->check_stack();
+
+ if (mp_impl->stack.size() < 2u)
+ throw json_structure_error("Current node is root - it doesn't have a parent.");
+
+ if (!mp_impl->stack.back()->repeat)
+ throw json_structure_error(
+ "Current node is not a repeating node. Only the parent node of a repeating node can be a row group.");
+
+ {
+ auto it = mp_impl->stack.crbegin();
+ ++it;
+ if ((*it)->type != structure_tree::node_type::array)
+ throw json_structure_error(
+ "Parent node of the current node is not of array type, but it should be.");
+ }
+
+ std::ostringstream os;
+ os << '$';
+
+ auto it = mp_impl->stack.cbegin(), ite = mp_impl->stack.cend();
+ ite -= 2; // jump to the parent node, and we don't include the last node in the path output.
+
+ for (; it != ite; ++it)
+ {
+ const structure_node* p = *it;
+
+ switch (p->type)
+ {
+ case structure_tree::node_type::array:
+ os << "[]";
+ break;
+ case structure_tree::node_type::object_key:
+ os << "['" << p->name << "']";
+ break;
+ default:
+ ;
+ }
+ }
+
+ return os.str();
+}
+
+structure_tree::structure_tree() : mp_impl(std::make_unique<impl>()) {}
+structure_tree::~structure_tree() {}
+
+void structure_tree::parse(std::string_view stream)
+{
+ json_parser<impl> parser(stream, *mp_impl);
+ parser.parse();
+}
+
+void structure_tree::normalize_tree()
+{
+ mp_impl->normalize_tree();
+}
+
+void structure_tree::dump_compact(std::ostream& os) const
+{
+ mp_impl->dump_compact(os);
+}
+
+structure_tree::walker structure_tree::get_walker() const
+{
+ return walker(mp_impl.get());
+}
+
+void structure_tree::process_ranges(range_handler_type rh) const
+{
+ detail::structure_mapper mapper(rh, get_walker());
+ mapper.run();
+}
+
+std::ostream& operator<< (std::ostream& os, structure_tree::node_type nt)
+{
+
+ switch (nt)
+ {
+ case structure_tree::node_type::array:
+ os << "structure_tree::node_type::array";
+ break;
+ case structure_tree::node_type::object:
+ os << "structure_tree::node_type::object";
+ break;
+ case structure_tree::node_type::object_key:
+ os << "structure_tree::node_type::object_key";
+ break;
+ case structure_tree::node_type::unknown:
+ os << "structure_tree::node_type::unknown";
+ break;
+ case structure_tree::node_type::value:
+ os << "structure_tree::node_type::value";
+ break;
+ }
+
+ return os;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_structure_tree_test.cpp b/src/liborcus/json_structure_tree_test.cpp
new file mode 100644
index 0000000..60a0598
--- /dev/null
+++ b/src/liborcus/json_structure_tree_test.cpp
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/json_structure_tree.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/parser_global.hpp>
+#include "filesystem_env.hpp"
+
+#include <vector>
+#include <sstream>
+#include <cassert>
+#include <unordered_set>
+
+using namespace orcus;
+
+std::vector<const char*> base_dirs = {
+ SRCDIR"/test/json-structure/arrays-in-object/",
+ SRCDIR"/test/json-structure/nested-arrays/",
+ SRCDIR"/test/json-structure/nested-arrays-mixed/",
+ SRCDIR"/test/json-structure/nested-arrays-mixed-2/",
+ SRCDIR"/test/json-structure/repeat-objects/",
+ SRCDIR"/test/json-structure/repeat-objects-2/",
+ SRCDIR"/test/json-structure/multiple-ranges/",
+};
+
+/**
+ * All json contents under this directory have no value nodes. Since the
+ * structure output of a JSON content only dumps value nodes, the output
+ * string should be empty when the source content does not have any value
+ * nodes.
+ */
+void test_no_value_nodes()
+{
+ fs::path base_dir(SRCDIR"/test/json-structure/no-value-nodes");
+
+ for (const fs::path& p : fs::directory_iterator(base_dir))
+ {
+ if (!fs::is_regular_file(p))
+ continue;
+
+ if (p.extension().string() != ".json")
+ continue;
+
+ file_content strm(p.string().data());
+ json::structure_tree tree;
+ tree.parse(strm.str());
+ tree.normalize_tree();
+ std::ostringstream os;
+ tree.dump_compact(os);
+
+ assert(os.str().empty());
+ }
+}
+
+void test_basic()
+{
+ for (const char* base_dir : base_dirs)
+ {
+ std::string filepath(base_dir);
+ filepath.append("input.json");
+
+ file_content strm(filepath.data());
+ assert(!strm.empty());
+ json::structure_tree tree;
+ tree.parse(strm.str());
+ tree.normalize_tree();
+ std::ostringstream os;
+ tree.dump_compact(os);
+ std::string data_content = os.str();
+
+ // Check the dump content against known datum.
+ filepath = base_dir;
+ filepath.append("check.txt");
+ file_content strm_check(filepath.data());
+ assert(!strm_check.empty());
+
+ // They should be identical, plus or minus leading/trailing whitespaces.
+ std::string_view s1(data_content.data(), data_content.size());
+ std::string_view s2 = strm_check.str();
+ assert(trim(s1) == trim(s2));
+ }
+}
+
+void test_automatic_range_detection()
+{
+ using detected_group_type = std::unordered_set<std::string>;
+ using detected_groups_type = std::vector<detected_group_type>;
+
+ struct check
+ {
+ fs::path filepath;
+ detected_groups_type expected_groups;
+ };
+
+ std::vector<check> checks =
+ {
+ {
+ SRCDIR"/test/json-structure/arrays-in-object/input.json",
+ {
+ {
+ "row-group:$['rows']",
+ "path:$['rows'][]['name']",
+ "path:$['rows'][]['age']",
+ "path:$['rows'][]['error']",
+ }
+ }
+ },
+ {
+ SRCDIR"/test/json-structure/repeat-objects/input.json",
+ {
+ {
+ "path:$[]['name']",
+ "path:$[]['age']",
+ "row-group:$",
+ }
+ }
+ },
+ {
+ SRCDIR"/test/json-structure/repeat-objects-2/input.json",
+ {
+ {
+ "path:$[]['name']",
+ "path:$[]['age']",
+ "path:$[]['props']['alpha']",
+ "path:$[]['props']['beta']",
+ "path:$[]['props']['gamma']",
+ "path:$[]['props']['theta']",
+ "row-group:$",
+ }
+ }
+ },
+ {
+ SRCDIR"/test/json-structure/multiple-ranges/input.json",
+ {
+ {
+ "path:$['data'][]['category']",
+ "path:$['data'][]['region']",
+ "path:$['data'][]['records'][]['id']",
+ "path:$['data'][]['records'][]['ref']",
+ "row-group:$['data']",
+ "row-group:$['data'][]['records']",
+ },
+ {
+ "path:$['misc'][][0]",
+ "path:$['misc'][][1]",
+ "path:$['misc'][][2]",
+ "row-group:$['misc']",
+ }
+ }
+ },
+ };
+
+ for (const check& c : checks)
+ {
+ file_content strm(c.filepath.string().data());
+ assert(!strm.empty());
+ json::structure_tree tree;
+ tree.parse(strm.str());
+
+ detected_groups_type observed_groups;
+
+ json::structure_tree::range_handler_type rh = [&observed_groups](json::table_range_t&& range)
+ {
+ detected_group_type observed;
+ for (const std::string& s : range.row_groups)
+ {
+ std::ostringstream os;
+ os << "row-group:" << s;
+ observed.insert(os.str());
+ }
+
+ for (const std::string& s : range.paths)
+ {
+ std::ostringstream os;
+ os << "path:" << s;
+ observed.insert(os.str());
+ }
+
+ observed_groups.push_back(std::move(observed));
+ };
+
+ tree.process_ranges(rh);
+
+ assert(observed_groups == c.expected_groups);
+ }
+}
+
+int main()
+{
+ test_no_value_nodes();
+ test_basic();
+ test_automatic_range_detection();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_util.cpp b/src/liborcus/json_util.cpp
new file mode 100644
index 0000000..b031cbe
--- /dev/null
+++ b/src/liborcus/json_util.cpp
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/json_global.hpp"
+
+#include <sstream>
+
+namespace orcus { namespace json {
+
+namespace {
+
+const char quote = '"';
+
+}
+
+void dump_string(std::ostringstream& os, const std::string& s)
+{
+ os << quote << escape_string(s) << quote;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/json_util.hpp b/src/liborcus/json_util.hpp
new file mode 100644
index 0000000..00917a2
--- /dev/null
+++ b/src/liborcus/json_util.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_JSON_UTIL_HPP
+#define INCLUDED_ORCUS_JSON_UTIL_HPP
+
+#include <sstream>
+
+namespace orcus { namespace json {
+
+void dump_string(std::ostringstream& os, const std::string& s);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/measurement.cpp b/src/liborcus/measurement.cpp
new file mode 100644
index 0000000..f034595
--- /dev/null
+++ b/src/liborcus/measurement.cpp
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/measurement.hpp>
+#include <orcus/exception.hpp>
+#include <orcus/parser_global.hpp>
+
+#include <mdds/sorted_string_map.hpp>
+#include <mdds/global.hpp>
+
+#include <sstream>
+
+namespace orcus {
+
+double to_double(std::string_view s, const char** p_parse_ended)
+{
+ const char* p = s.data();
+ double value;
+ const char* p_last = parse_numeric(p, p + s.size(), value);
+ if (p_parse_ended)
+ *p_parse_ended = p_last;
+
+ return value;
+}
+
+long to_long(std::string_view s, const char** p_parse_ended)
+{
+ long value;
+ const char* p_last = parse_integer(s.data(), s.data() + s.size(), value);
+ if (p_parse_ended)
+ *p_parse_ended = p_last;
+
+ return value;
+}
+
+bool to_bool(std::string_view s)
+{
+ size_t n = s.size();
+ if (n == 1)
+ // Any single char other than '0' is true.
+ return s[0] != '0';
+
+ return s == "true" || s == "TRUE";
+}
+
+namespace {
+
+namespace length {
+
+using map_type = mdds::sorted_string_map<length_unit_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] =
+{
+ { "cm", length_unit_t::centimeter },
+ { "in", length_unit_t::inch },
+ { "mm", length_unit_t::millimeter },
+ { "pt", length_unit_t::point },
+ { "px", length_unit_t::pixel }
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), length_unit_t::unknown);
+ return mt;
+}
+
+} // namespace length
+
+} // anonymous namespace
+
+length_t to_length(std::string_view str)
+{
+ length_t ret;
+ if (str.empty())
+ return ret;
+
+ const char* p = str.data();
+ const char* p_start = p;
+ const char* p_end = p_start + str.size();
+ p = parse_numeric(p, p_end, ret.value);
+
+ std::string_view tail(p, p_end-p);
+ ret.unit = length::get().find(tail);
+
+ return ret;
+}
+
+namespace {
+
+double convert_inch(double value, length_unit_t unit_to)
+{
+ switch (unit_to)
+ {
+ case length_unit_t::twip:
+ // inches to twips : 1 twip = 1/1440 inches
+ return value * 1440.0;
+ default:
+ ;
+ }
+
+ throw general_error("convert_inch: unsupported unit of measurement.");
+}
+
+double convert_point(double value, length_unit_t unit_to)
+{
+ switch (unit_to)
+ {
+ case length_unit_t::twip:
+ // 20 twips = 1 point
+ return value * 20.0;
+ default:
+ ;
+ }
+
+ throw general_error("convert_point: unsupported unit of measurement.");
+}
+
+double convert_centimeter(double value, length_unit_t unit_to)
+{
+ switch (unit_to)
+ {
+ case length_unit_t::twip:
+ // centimeters to twips : 2.54 cm = 1 inch = 1440 twips
+ return value / 2.54 * 1440.0;
+ default:
+ ;
+ }
+
+ throw general_error("convert_centimeter: unsupported unit of measurement.");
+}
+
+double convert_millimeter(double value, length_unit_t unit_to)
+{
+ switch (unit_to)
+ {
+ case length_unit_t::twip:
+ // millimeters to twips : 25.4 mm = 1 inch = 1440 twips
+ return value / 25.4 * 1440.0;
+ default:
+ ;
+ }
+
+ throw general_error("convert_millimeter: unsupported unit of measurement.");
+}
+
+double convert_twip(double value, length_unit_t unit_to)
+{
+ switch (unit_to)
+ {
+ case length_unit_t::inch:
+ // twips to inches : 1 twip = 1/1440 inches
+ return value / 1440.0;
+ case length_unit_t::point:
+ // 1 twip = 1/1440 inches = 72/1440 points = 1/20 points
+ return value / 20.0;
+ default:
+ ;
+ }
+ throw general_error("convert_twip: unsupported unit of measurement.");
+}
+
+/**
+ * Since Excel's column width is based on the maximum digit width of font
+ * used as the "Normal" style font, it's impossible to convert it accurately
+ * without the font information.
+ */
+double convert_xlsx_column_digit(double value, length_unit_t unit_to)
+{
+ // Convert to centimeters first. Here, we'll just assume that a single
+ // digit always equals 1.9 millimeters. TODO: find a better way to convert
+ // this.
+ value *= 0.19;
+ return convert_centimeter(value, unit_to);
+}
+
+}
+
+double convert(double value, length_unit_t unit_from, length_unit_t unit_to)
+{
+ if (value == 0.0)
+ return value;
+
+ switch (unit_from)
+ {
+ case length_unit_t::point:
+ return convert_point(value, unit_to);
+ case length_unit_t::inch:
+ return convert_inch(value, unit_to);
+ case length_unit_t::centimeter:
+ return convert_centimeter(value, unit_to);
+ case length_unit_t::millimeter:
+ return convert_millimeter(value, unit_to);
+ case length_unit_t::twip:
+ return convert_twip(value, unit_to);
+ case length_unit_t::xlsx_column_digit:
+ return convert_xlsx_column_digit(value, unit_to);
+ default:
+ ;
+ }
+
+ std::ostringstream os;
+ os << "convert: unsupported unit of measurement (from "
+ << static_cast<int>(unit_from) << " to "
+ << static_cast<int>(unit_to) << ") (value=" << value << ")";
+ throw general_error(os.str());
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/number_utils.cpp b/src/liborcus/number_utils.cpp
new file mode 100644
index 0000000..8e669ae
--- /dev/null
+++ b/src/liborcus/number_utils.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "number_utils.hpp"
+
+namespace orcus {
+
+namespace {
+
+std::optional<std::uint8_t> char_to_uint8(char c)
+{
+ std::uint8_t v;
+ if ('0' <= c && c <= '9')
+ {
+ v = c - '0';
+ return v;
+ }
+
+ if ('A' <= c && c <= 'F')
+ {
+ v = c - 'A' + 10;
+ return v;
+ }
+
+ if ('a' <= c && c <= 'f')
+ {
+ v = c - 'a' + 10;
+ return v;
+ }
+
+ return {};
+}
+
+template<typename IntT>
+std::optional<IntT> hex_to_uint(std::string_view s)
+{
+ static_assert(std::is_integral_v<IntT>);
+
+ constexpr std::size_t expected_len = sizeof(IntT) * 2u;
+ if (s.size() > expected_len)
+ return {};
+
+ IntT value = 0;
+ for (char c : s)
+ {
+ value = value << 4;
+ auto v = char_to_uint8(c);
+ if (!v)
+ return {};
+ value += *v;
+ }
+
+ return value;
+}
+
+} // anonymous namespace
+
+std::optional<std::uint8_t> hex_to_uint8(std::string_view s)
+{
+ return hex_to_uint<std::uint8_t>(s);
+}
+
+std::optional<std::uint16_t> hex_to_uint16(std::string_view s)
+{
+ return hex_to_uint<std::uint16_t>(s);
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/number_utils.hpp b/src/liborcus/number_utils.hpp
new file mode 100644
index 0000000..acb4c3a
--- /dev/null
+++ b/src/liborcus/number_utils.hpp
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <string_view>
+#include <optional>
+#include <cstdint>
+
+namespace orcus {
+
+std::optional<std::uint8_t> hex_to_uint8(std::string_view s);
+
+std::optional<std::uint16_t> hex_to_uint16(std::string_view s);
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_document_styles_context.cpp b/src/liborcus/odf_document_styles_context.cpp
new file mode 100644
index 0000000..957e55f
--- /dev/null
+++ b/src/liborcus/odf_document_styles_context.cpp
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "odf_document_styles_context.hpp"
+#include "odf_token_constants.hpp"
+#include "odf_namespace_types.hpp"
+
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+
+#include <iostream>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+document_styles_context::document_styles_context(session_context& session_cxt, const tokens& tk, odf_styles_map_type& styles_map, ss::iface::import_styles* xstyles) :
+ xml_context_base(session_cxt, tk),
+ m_styles_map(styles_map),
+ mp_styles(xstyles),
+ m_cxt_styles(session_cxt, tk, xstyles)
+{
+ register_child(&m_cxt_styles);
+}
+
+xml_context_base* document_styles_context::create_child_context(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_office && name == XML_styles)
+ {
+ m_cxt_styles.reset();
+ return &m_cxt_styles;
+ }
+
+ return nullptr;
+}
+
+void document_styles_context::end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child)
+{
+ if (ns == NS_odf_office && name == XML_styles)
+ {
+ assert(child == &m_cxt_styles);
+ auto new_styles = m_cxt_styles.pop_styles();
+ merge(m_styles_map, new_styles);
+ assert(new_styles.empty());
+ }
+}
+
+void document_styles_context::start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ auto parent = push_stack(ns, name);
+ (void)parent;
+
+ (void)attrs;
+
+ warn_unhandled();
+}
+
+bool document_styles_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ return pop_stack(ns, name);
+}
+
+void document_styles_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_document_styles_context.hpp b/src/liborcus/odf_document_styles_context.hpp
new file mode 100644
index 0000000..4deecb5
--- /dev/null
+++ b/src/liborcus/odf_document_styles_context.hpp
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "xml_context_base.hpp"
+#include "odf_styles.hpp"
+#include "odf_styles_context.hpp"
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_styles;
+
+}}
+
+/**
+ * Context that handles the <office:document-styles> element scope.
+ *
+ * <office:document-styles> is the root element of styles.xml stream inside an
+ * ODF document.
+ */
+class document_styles_context : public xml_context_base
+{
+public:
+ document_styles_context(
+ session_context& session_cxt, const tokens& tk,
+ odf_styles_map_type& styles_map, spreadsheet::iface::import_styles* xstyles);
+
+ xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name) override;
+ void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child) override;
+ void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+ bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ void characters(std::string_view str, bool transient) override;
+
+private:
+ odf_styles_map_type& m_styles_map;
+ spreadsheet::iface::import_styles* mp_styles = nullptr;
+
+ styles_context m_cxt_styles;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_helper.cpp b/src/liborcus/odf_helper.cpp
new file mode 100644
index 0000000..7198b74
--- /dev/null
+++ b/src/liborcus/odf_helper.cpp
@@ -0,0 +1,260 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "odf_helper.hpp"
+#include "string_helper.hpp"
+#include <orcus/spreadsheet/types.hpp>
+#include <orcus/measurement.hpp>
+#include <mdds/sorted_string_map.hpp>
+#include <mdds/global.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+namespace border_style {
+
+using map_type = mdds::sorted_string_map<spreadsheet::border_style_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] =
+{
+ { "dash-dot", spreadsheet::border_style_t::dash_dot },
+ { "dash-dot-dot", spreadsheet::border_style_t::dash_dot_dot },
+ { "dashed", spreadsheet::border_style_t::dashed },
+ { "dotted", spreadsheet::border_style_t::dotted },
+ { "double-thin", spreadsheet::border_style_t::double_thin },
+ { "fine-dashed", spreadsheet::border_style_t::fine_dashed },
+ { "none", spreadsheet::border_style_t::none },
+ { "solid", spreadsheet::border_style_t::solid },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::border_style_t::unknown);
+ return mt;
+}
+
+} // namespace border_style
+
+namespace underline_width {
+
+using map_type = mdds::sorted_string_map<spreadsheet::underline_width_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] =
+{
+ { "auto", ss::underline_width_t::automatic },
+ { "bold", ss::underline_width_t::bold },
+ { "dash", ss::underline_width_t::dash },
+ { "medium", ss::underline_width_t::medium },
+ { "thick", ss::underline_width_t::thick },
+ { "thin", ss::underline_width_t::thin },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::underline_width_t::none);
+ return mt;
+}
+
+} // namespace underline_width
+
+namespace underline_style {
+
+using map_type = mdds::sorted_string_map<ss::underline_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] =
+{
+ { "dash", ss::underline_t::dash },
+ { "dot-dash", ss::underline_t::dot_dash },
+ { "dot-dot-dash", ss::underline_t::dot_dot_dash },
+ { "dotted", ss::underline_t::dotted },
+ { "long-dash", ss::underline_t::long_dash },
+ { "none", ss::underline_t::none },
+ { "solid", ss::underline_t::single_line },
+ { "wave", ss::underline_t::wave }
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), ss::underline_t::none);
+ return mt;
+}
+
+} // namespace underline_style
+
+namespace hor_align {
+
+using map_type = mdds::sorted_string_map<spreadsheet::hor_alignment_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] =
+{
+ { "center", spreadsheet::hor_alignment_t::center },
+ { "end", spreadsheet::hor_alignment_t::right },
+ { "justified", spreadsheet::hor_alignment_t::justified },
+ { "start", spreadsheet::hor_alignment_t::left }
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), ss::hor_alignment_t::unknown);
+ return mt;
+}
+
+} // namespace hor_align
+
+namespace ver_align {
+
+using map_type = mdds::sorted_string_map<spreadsheet::ver_alignment_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] =
+{
+ { "bottom", spreadsheet::ver_alignment_t::bottom },
+ { "justified", spreadsheet::ver_alignment_t::justified },
+ { "middle", spreadsheet::ver_alignment_t::middle },
+ { "top", spreadsheet::ver_alignment_t::top }
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), ss::ver_alignment_t::unknown);
+ return mt;
+}
+
+} // namespace ver_align
+
+bool is_valid_hex_digit(const char& character, orcus::spreadsheet::color_elem_t& val)
+{
+ if ('0' <= character && character <= '9')
+ {
+ val += character - '0';
+ return true;
+ }
+
+ if ('A' <= character && character <= 'F')
+ {
+ val += character - 'A' + 10;
+ return true;
+ }
+
+ if ('a' <= character && character <= 'f')
+ {
+ val += character - 'a' + 10;
+ return true;
+ }
+
+ return false;
+}
+
+// converts two characters starting at index to a color value
+bool convert_color_digits(std::string_view value, orcus::spreadsheet::color_elem_t& color_val, size_t index)
+{
+ const char& high_val = value[index];
+ color_val = 0;
+ if (!is_valid_hex_digit(high_val, color_val))
+ return false;
+ color_val *= 16;
+ const char& low_val = value[++index];
+ return is_valid_hex_digit(low_val, color_val);
+}
+
+} // anonymous namespace
+
+bool odf::convert_fo_color(
+ std::string_view value,
+ spreadsheet::color_elem_t& red,
+ spreadsheet::color_elem_t& green,
+ spreadsheet::color_elem_t& blue)
+{
+ auto color = convert_fo_color(value);
+ if (!color)
+ return false;
+
+ red = color->red;
+ green = color->green;
+ blue = color->blue;
+ return true;
+}
+
+std::optional<spreadsheet::color_rgb_t> odf::convert_fo_color(std::string_view value)
+{
+ std::optional<spreadsheet::color_rgb_t> ret;
+
+ // first character needs to be '#'
+ if (value.size() != 7)
+ return ret;
+
+ if (value[0] != '#')
+ return ret;
+
+ spreadsheet::color_rgb_t color;
+ if (!convert_color_digits(value, color.red, 1))
+ return ret;
+
+ if (!convert_color_digits(value, color.green, 3))
+ return ret;
+
+ if (!convert_color_digits(value, color.blue, 5))
+ return ret;
+
+ return color;
+}
+
+orcus::odf::border_details_t odf::extract_border_details(std::string_view value)
+{
+ border_details_t border_details;
+
+ auto detail = orcus::string_helper::split_string(value,' ');
+
+ for (const auto& sub_detail : detail)
+ {
+ if (sub_detail[0] == '#')
+ convert_fo_color(sub_detail, border_details.red, border_details.green, border_details.blue);
+ else if (sub_detail[0] >= '0' && sub_detail[0] <='9')
+ border_details.border_width = orcus::to_length(sub_detail);
+ else // This has to be a style
+ border_details.border_style = border_style::get().find(sub_detail);
+ }
+ return border_details;
+}
+
+ss::underline_width_t odf::extract_underline_width(std::string_view value)
+{
+ // TODO: style:text-underline-width also allows:
+ // * percent value
+ // * positive integer
+ // * positive length
+ // As we encounter real-life examples of these values, we should add code to
+ // handle them here. For now, we only handle enumerated values.
+ return underline_width::get().find(value);
+}
+
+orcus::spreadsheet::underline_t odf::extract_underline_style(std::string_view value)
+{
+ return underline_style::get().find(value);
+}
+
+ss::hor_alignment_t odf::extract_hor_alignment_style(std::string_view value)
+{
+ return hor_align::get().find(value);
+}
+
+spreadsheet::ver_alignment_t odf::extract_ver_alignment_style(std::string_view value)
+{
+ return ver_align::get().find(value);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_helper.hpp b/src/liborcus/odf_helper.hpp
new file mode 100644
index 0000000..eb95692
--- /dev/null
+++ b/src/liborcus/odf_helper.hpp
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_ODF_HELPER_HPP
+#define INCLUDED_ORCUS_ODF_HELPER_HPP
+
+#include <orcus/spreadsheet/types.hpp>
+#include <orcus/measurement.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+
+#include <optional>
+
+namespace orcus { namespace odf {
+
+struct border_details_t
+{
+ spreadsheet::border_style_t border_style = spreadsheet::border_style_t::unknown;
+
+ spreadsheet::color_elem_t red = 0;
+ spreadsheet::color_elem_t green = 0;
+ spreadsheet::color_elem_t blue = 0;
+
+ length_t border_width;
+};
+
+bool convert_fo_color(
+ std::string_view value,
+ spreadsheet::color_elem_t& red,
+ spreadsheet::color_elem_t& green,
+ spreadsheet::color_elem_t& blue);
+
+std::optional<spreadsheet::color_rgb_t> convert_fo_color(std::string_view value);
+
+/**
+ * extracts border style, width and colors from a string value.
+ */
+border_details_t extract_border_details(std::string_view value);
+
+spreadsheet::underline_width_t extract_underline_width(std::string_view value);
+
+spreadsheet::underline_t extract_underline_style(std::string_view value);
+
+spreadsheet::hor_alignment_t extract_hor_alignment_style(std::string_view value);
+
+spreadsheet::ver_alignment_t extract_ver_alignment_style(std::string_view value);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_helper_test.cpp b/src/liborcus/odf_helper_test.cpp
new file mode 100644
index 0000000..803644c
--- /dev/null
+++ b/src/liborcus/odf_helper_test.cpp
@@ -0,0 +1,51 @@
+#include "odf_helper.hpp"
+
+#include <orcus/spreadsheet/types.hpp>
+
+#include <cassert>
+
+using namespace orcus::spreadsheet;
+
+namespace {
+
+void test_color_conversion(const char* input, bool valid,
+ color_elem_t red_expected, color_elem_t green_expected, color_elem_t blue_expected)
+{
+ color_elem_t red, green, blue;
+ bool valid_result = orcus::odf::convert_fo_color(input, red, green, blue);
+
+ assert(valid == valid_result);
+ if (valid)
+ {
+ assert(red_expected == red);
+ assert(green_expected == green);
+ assert(blue_expected == blue);
+ }
+}
+
+}
+
+int main()
+{
+ struct
+ {
+ const char* input;
+ bool valid;
+ orcus::spreadsheet::color_elem_t red;
+ orcus::spreadsheet::color_elem_t green;
+ orcus::spreadsheet::color_elem_t blue;
+ } data[] = {
+ { "not valid", false, 0, 0, 0},
+ { "#000000", true, 0, 0, 0},
+ { "#0000", false, 0, 0, 0},
+ { "#abcdef", true, 0xab, 0xcd, 0xef},
+ { "#ABCDEF", true, 0xab, 0xcd, 0xef},
+ { "#123456", true, 0x12, 0x34, 0x56}
+ };
+
+ for (size_t i = 0; i < sizeof(data)/sizeof(data[0]); ++i)
+ {
+ test_color_conversion(data[i].input, data[i].valid, data[i].red, data[i].green, data[i].blue);
+ }
+ return 0;
+}
diff --git a/src/liborcus/odf_namespace_types.cpp b/src/liborcus/odf_namespace_types.cpp
new file mode 100644
index 0000000..ae768db
--- /dev/null
+++ b/src/liborcus/odf_namespace_types.cpp
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "odf_namespace_types.hpp"
+
+#include "odf_namespace_types_cpp.inl"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_namespace_types.hpp b/src/liborcus/odf_namespace_types.hpp
new file mode 100644
index 0000000..5dce680
--- /dev/null
+++ b/src/liborcus/odf_namespace_types.hpp
@@ -0,0 +1,16 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_ODF_NAMESPACE_TYPES_HPP__
+#define __ORCUS_ODF_NAMESPACE_TYPES_HPP__
+
+#include "orcus/types.hpp"
+
+#include "odf_namespace_types_hpp.inl"
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_namespace_types_cpp.inl b/src/liborcus/odf_namespace_types_cpp.inl
new file mode 100644
index 0000000..8b0dc1f
--- /dev/null
+++ b/src/liborcus/odf_namespace_types_cpp.inl
@@ -0,0 +1,63 @@
+namespace orcus {
+
+const xmlns_id_t NS_odf_anim = "urn:oasis:names:tc:opendocument:xmlns:animation:1.0";
+const xmlns_id_t NS_odf_chart = "urn:oasis:names:tc:opendocument:xmlns:chart:1.0";
+const xmlns_id_t NS_odf_config = "urn:oasis:names:tc:opendocument:xmlns:config:1.0";
+const xmlns_id_t NS_odf_db = "urn:oasis:names:tc:opendocument:xmlns:database:1.0";
+const xmlns_id_t NS_odf_dc = "http://purl.org/dc/elements/1.1/";
+const xmlns_id_t NS_odf_dr3d = "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0";
+const xmlns_id_t NS_odf_draw = "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0";
+const xmlns_id_t NS_odf_fo = "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0";
+const xmlns_id_t NS_odf_form = "urn:oasis:names:tc:opendocument:xmlns:form:1.0";
+const xmlns_id_t NS_odf_grddl = "http://www.w3.org/2003/g/data-view#";
+const xmlns_id_t NS_odf_math = "http://www.w3.org/1998/Math/MathML";
+const xmlns_id_t NS_odf_meta = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0";
+const xmlns_id_t NS_odf_number = "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0";
+const xmlns_id_t NS_odf_office = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
+const xmlns_id_t NS_odf_presentation = "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0";
+const xmlns_id_t NS_odf_script = "urn:oasis:names:tc:opendocument:xmlns:script:1.0";
+const xmlns_id_t NS_odf_smil = "urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0";
+const xmlns_id_t NS_odf_style = "urn:oasis:names:tc:opendocument:xmlns:style:1.0";
+const xmlns_id_t NS_odf_svg = "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0";
+const xmlns_id_t NS_odf_table = "urn:oasis:names:tc:opendocument:xmlns:table:1.0";
+const xmlns_id_t NS_odf_text = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
+const xmlns_id_t NS_odf_xforms = "http://www.w3.org/2002/xforms";
+const xmlns_id_t NS_odf_xhtml = "http://www.w3.org/1999/xhtml";
+const xmlns_id_t NS_odf_xlink = "http://www.w3.org/1999/xlink";
+
+namespace {
+
+const xmlns_id_t odf_ns[] = {
+ NS_odf_anim,
+ NS_odf_chart,
+ NS_odf_config,
+ NS_odf_db,
+ NS_odf_dc,
+ NS_odf_dr3d,
+ NS_odf_draw,
+ NS_odf_fo,
+ NS_odf_form,
+ NS_odf_grddl,
+ NS_odf_math,
+ NS_odf_meta,
+ NS_odf_number,
+ NS_odf_office,
+ NS_odf_presentation,
+ NS_odf_script,
+ NS_odf_smil,
+ NS_odf_style,
+ NS_odf_svg,
+ NS_odf_table,
+ NS_odf_text,
+ NS_odf_xforms,
+ NS_odf_xhtml,
+ NS_odf_xlink,
+ nullptr
+};
+
+} // anonymous
+
+const xmlns_id_t* NS_odf_all = odf_ns;
+
+}
+
diff --git a/src/liborcus/odf_namespace_types_hpp.inl b/src/liborcus/odf_namespace_types_hpp.inl
new file mode 100644
index 0000000..a80c917
--- /dev/null
+++ b/src/liborcus/odf_namespace_types_hpp.inl
@@ -0,0 +1,31 @@
+namespace orcus {
+
+extern const xmlns_id_t NS_odf_anim;
+extern const xmlns_id_t NS_odf_chart;
+extern const xmlns_id_t NS_odf_config;
+extern const xmlns_id_t NS_odf_db;
+extern const xmlns_id_t NS_odf_dc;
+extern const xmlns_id_t NS_odf_dr3d;
+extern const xmlns_id_t NS_odf_draw;
+extern const xmlns_id_t NS_odf_fo;
+extern const xmlns_id_t NS_odf_form;
+extern const xmlns_id_t NS_odf_grddl;
+extern const xmlns_id_t NS_odf_math;
+extern const xmlns_id_t NS_odf_meta;
+extern const xmlns_id_t NS_odf_number;
+extern const xmlns_id_t NS_odf_office;
+extern const xmlns_id_t NS_odf_presentation;
+extern const xmlns_id_t NS_odf_script;
+extern const xmlns_id_t NS_odf_smil;
+extern const xmlns_id_t NS_odf_style;
+extern const xmlns_id_t NS_odf_svg;
+extern const xmlns_id_t NS_odf_table;
+extern const xmlns_id_t NS_odf_text;
+extern const xmlns_id_t NS_odf_xforms;
+extern const xmlns_id_t NS_odf_xhtml;
+extern const xmlns_id_t NS_odf_xlink;
+
+extern const xmlns_id_t* NS_odf_all;
+
+}
+
diff --git a/src/liborcus/odf_number_format_context.cpp b/src/liborcus/odf_number_format_context.cpp
new file mode 100644
index 0000000..d224a64
--- /dev/null
+++ b/src/liborcus/odf_number_format_context.cpp
@@ -0,0 +1,1126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "odf_number_format_context.hpp"
+#include "odf_namespace_types.hpp"
+#include "odf_token_constants.hpp"
+#include "odf_helper.hpp"
+#include "ods_session_data.hpp"
+#include "impl_utils.hpp"
+
+#include <orcus/measurement.hpp>
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+
+#include <iostream>
+#include <algorithm>
+#include <string>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+enum class date_style_type
+{
+ unknown = 0,
+ short_symbol,
+ long_symbol
+};
+
+date_style_type to_date_style(std::string_view s)
+{
+ constexpr std::pair<std::string_view, date_style_type> entries[] = {
+ { "short", date_style_type::short_symbol },
+ { "long", date_style_type::long_symbol },
+ };
+
+ for (const auto& entry : entries)
+ {
+ if (s == entry.first)
+ return entry.second;
+ }
+
+ return date_style_type::unknown;
+}
+
+struct parse_result
+{
+ bool success = true;
+ std::string error_message;
+};
+
+date_style_type parse_attrs_for_date_style(const std::vector<xml_token_attr_t>& attrs)
+{
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_number)
+ {
+ switch (attr.name)
+ {
+ case XML_style:
+ return to_date_style(attr.value);
+ }
+ }
+ }
+
+ return date_style_type::unknown;
+}
+
+void parse_element_time_short_long(const std::vector<xml_token_attr_t>& attrs, char c, odf_number_format& style)
+{
+ style.code += c;
+
+ if (parse_attrs_for_date_style(attrs) == date_style_type::long_symbol)
+ style.code += c;
+}
+
+void parse_element_number(const std::vector<xml_token_attr_t>& attrs, odf_number_format& style)
+{
+ bool grouping = false;
+ long decimal_places = 0;
+ long min_integer_digits = 0;
+
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_number)
+ {
+ switch (attr.name)
+ {
+ case XML_decimal_places:
+ {
+ decimal_places = to_long(attr.value);
+ break;
+ }
+ case XML_grouping:
+ grouping = to_bool(attr.value);
+ break;
+ case XML_min_integer_digits:
+ min_integer_digits = to_long(attr.value);
+ break;
+ default:;
+ }
+ }
+ }
+
+ if (grouping)
+ {
+ if (min_integer_digits < 4)
+ {
+ style.code += "#,";
+
+ for (long i = 0; i < 3 - min_integer_digits; ++i)
+ style.code += "#";
+
+ for (long i = 0; i < min_integer_digits; ++i)
+ style.code += "0";
+ }
+ else
+ {
+ std::string temporary_code;
+
+ for (long i = 0; i < min_integer_digits; ++i)
+ {
+ if (i % 3 == 0 && i != 0)
+ temporary_code += ",";
+
+ temporary_code += "0";
+ }
+
+ std::reverse(temporary_code.begin(), temporary_code.end());
+ style.code += temporary_code;
+ }
+ }
+ else
+ {
+ if (min_integer_digits == 0)
+ style.code += "#";
+
+ for (long i = 0; i < min_integer_digits; ++i)
+ style.code += "0";
+ }
+
+ if (decimal_places > 0)
+ {
+ style.code += ".";
+ for (long i = 0; i < decimal_places; ++i)
+ style.code += "0";
+ }
+}
+
+void parse_element_text_properties(const std::vector<xml_token_attr_t>& attrs, odf_number_format& style)
+{
+ std::string_view color;
+
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_fo)
+ {
+ switch (attr.name)
+ {
+ case XML_color:
+ {
+ if (attr.value == "#000000")
+ color = "BLACK";
+ if (attr.value == "#ff0000")
+ color = "RED";
+ if (attr.value == "#00ff00")
+ color = "GREEN";
+ if (attr.value == "#0000ff")
+ color = "BLUE";
+ if (attr.value == "#ffff00")
+ color = "YELLOW";
+ if (attr.value == "#00ffff")
+ color = "CYAN";
+ if (attr.value == "#ff00ff")
+ color = "MAGENTA";
+ if (attr.value == "#ffffff")
+ color = "WHITE";
+ }
+ }
+ }
+ }
+
+ if (!color.empty())
+ {
+ std::ostringstream os;
+ os << '[' << color << ']';
+ style.code += os.str();
+ }
+}
+
+parse_result parse_element_map(session_context& cxt, const std::vector<xml_token_attr_t>& attrs, odf_number_format& style)
+{
+ parse_result res;
+
+ std::string_view comp; // comparison operator e.g. <, >, >=, ...
+ std::string_view value; // right-hand value
+ std::string_view style_name; // style name associated with the mapped rule
+
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_style)
+ {
+ switch (attr.name)
+ {
+ case XML_apply_style_name:
+ {
+ style_name = attr.value;
+ break;
+ }
+ case XML_condition:
+ {
+ // value()[comp][rvalue] e.g. 'value()>=0'
+ constexpr std::string_view prefix = "value()";
+
+ // check if the attribute value starts with 'value()'
+ if (attr.value.compare(0, prefix.size(), prefix) == 0)
+ {
+ auto pos_value = attr.value.find_first_not_of("<>=", prefix.size());
+
+ comp = attr.value.substr(prefix.size(), pos_value - prefix.size());
+ value = attr.value.substr(pos_value);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ if (comp.empty() || value.empty() || style_name.empty())
+ {
+ res.success = false;
+ return res;
+ }
+
+ // fetch the code associated with the mapped rule
+ auto& numfmts = cxt.get_data<ods_session_data>().number_formats;
+ std::string_view code = numfmts.get_code(style_name);
+
+ if (code.empty())
+ {
+ res.success = false;
+ std::ostringstream os;
+ os << "code stored for the number format style named '" << style_name << "' exists, but is empty.";
+ res.error_message = os.str();
+ return res;
+ }
+
+ // prepend the mapped rule to the current code
+ std::ostringstream os;
+ os << '[' << comp << value << ']' << code << ';' << style.code;
+ style.code = os.str();
+
+ return res;
+}
+
+} // anonymous namespace
+
+date_style_context::date_style_context(session_context& session_cxt, const tokens& tk) :
+ xml_context_base(session_cxt, tk)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_odf_number, XML_date_style }, // root element
+ { NS_odf_number, XML_date_style, NS_odf_number, XML_day },
+ { NS_odf_number, XML_date_style, NS_odf_number, XML_month },
+ { NS_odf_number, XML_date_style, NS_odf_number, XML_text },
+ { NS_odf_number, XML_date_style, NS_odf_number, XML_year },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+void date_style_context::start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_date_style:
+ start_element_date_style(attrs);
+ break;
+ case XML_month:
+ start_element_month(attrs);
+ break;
+ case XML_day:
+ start_element_day(attrs);
+ break;
+ case XML_year:
+ start_element_year(attrs);
+ break;
+ case XML_text:
+ m_text_stream = std::ostringstream{};
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool date_style_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_text:
+ m_current_style->code += m_text_stream.str();
+ break;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void date_style_context::characters(std::string_view str, bool /*transient*/)
+{
+ m_text_stream << str;
+}
+
+void date_style_context::reset()
+{
+ m_current_style = std::make_unique<odf_number_format>();
+}
+
+std::unique_ptr<odf_number_format> date_style_context::pop_style()
+{
+ return std::move(m_current_style);
+}
+
+void date_style_context::start_element_date_style(const std::vector<xml_token_attr_t>& attrs)
+{
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_style)
+ {
+ switch (attr.name)
+ {
+ case XML_name:
+ m_current_style->name = intern(attr);
+ break;
+ }
+ }
+ }
+}
+
+void date_style_context::start_element_month(const std::vector<xml_token_attr_t>& attrs)
+{
+ auto style = date_style_type::unknown;
+ bool textual = false;
+
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_number)
+ {
+ switch (attr.name)
+ {
+ case XML_style:
+ style = to_date_style(attr.value);
+ break;
+ case XML_textual:
+ textual = to_bool(attr.value);
+ break;
+ }
+ }
+ }
+
+ m_current_style->code += 'M';
+
+ if (style == date_style_type::long_symbol)
+ m_current_style->code += 'M';
+
+ if (textual)
+ m_current_style->code += 'M';
+
+ if (style == date_style_type::long_symbol && textual)
+ m_current_style->code += 'M';
+}
+
+void date_style_context::start_element_day(const std::vector<xml_token_attr_t>& attrs)
+{
+ m_current_style->code += 'D';
+
+ if (parse_attrs_for_date_style(attrs) == date_style_type::long_symbol)
+ m_current_style->code += 'D';
+}
+
+void date_style_context::start_element_year(const std::vector<xml_token_attr_t>& attrs)
+{
+ m_current_style->code += "YY";
+
+ if (parse_attrs_for_date_style(attrs) == date_style_type::long_symbol)
+ m_current_style->code += "YY";
+}
+
+time_style_context::time_style_context(session_context& session_cxt, const tokens& tk) :
+ xml_context_base(session_cxt, tk)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_odf_number, XML_time_style }, // root element
+ { NS_odf_number, XML_time_style, NS_odf_number, XML_hours },
+ { NS_odf_number, XML_time_style, NS_odf_number, XML_minutes },
+ { NS_odf_number, XML_time_style, NS_odf_number, XML_seconds },
+ { NS_odf_number, XML_time_style, NS_odf_number, XML_text },
+ { NS_odf_number, XML_time_style, NS_odf_number, XML_am_pm },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+void time_style_context::start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_time_style:
+ start_element_time_style(attrs);
+ break;
+ case XML_hours:
+ parse_element_time_short_long(attrs, 'H', *m_current_style);
+ break;
+ case XML_minutes:
+ parse_element_time_short_long(attrs, 'M', *m_current_style);
+ break;
+ case XML_seconds:
+ start_element_seconds(attrs);
+ break;
+ case XML_text:
+ m_text_stream = std::ostringstream{};
+ break;
+ case XML_am_pm:
+ m_current_style->code += "AM/PM";
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool time_style_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_text:
+ m_current_style->code += m_text_stream.str();
+ break;
+ }
+ }
+
+ return pop_stack(ns, name);
+}
+
+void time_style_context::characters(std::string_view str, bool /*transient*/)
+{
+ m_text_stream << str;
+}
+
+void time_style_context::reset()
+{
+ m_current_style = std::make_unique<odf_number_format>();
+}
+
+std::unique_ptr<odf_number_format> time_style_context::pop_style()
+{
+ return std::move(m_current_style);
+}
+
+void time_style_context::start_element_time_style(const std::vector<xml_token_attr_t>& attrs)
+{
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_style && attr.name == XML_name)
+ m_current_style->name = intern(attr);
+ }
+}
+
+void time_style_context::start_element_seconds(const std::vector<xml_token_attr_t>& attrs)
+{
+ auto style = date_style_type::unknown;
+ std::optional<std::size_t> decimal_places;
+
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_number)
+ {
+ switch (attr.name)
+ {
+ case XML_style:
+ style = to_date_style(attr.value);
+ break;
+ case XML_decimal_places:
+ decimal_places = to_long(attr.value);
+ break;
+ }
+ }
+ }
+
+ m_current_style->code += 'S';
+
+ if (style == date_style_type::long_symbol)
+ m_current_style->code += 'S';
+
+ if (decimal_places && *decimal_places > 0)
+ m_current_style->code += std::string{"S", *decimal_places};
+}
+
+percentage_style_context::percentage_style_context(session_context& session_cxt, const tokens& tk) :
+ xml_context_base(session_cxt, tk)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_odf_number, XML_percentage_style }, // root element
+ { NS_odf_number, XML_percentage_style, NS_odf_number, XML_number },
+ { NS_odf_number, XML_percentage_style, NS_odf_number, XML_text },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+void percentage_style_context::start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_percentage_style:
+ {
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_style && attr.name == XML_name)
+ m_current_style->name = intern(attr);
+ }
+ break;
+ }
+ case XML_number:
+ {
+ parse_element_number(attrs, *m_current_style);
+ break;
+ }
+ case XML_text:
+ m_text_stream = std::ostringstream{};
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool percentage_style_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_text:
+ m_current_style->code += m_text_stream.str();
+ break;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void percentage_style_context::characters(std::string_view str, bool /*transient*/)
+{
+ m_text_stream << str;
+}
+
+void percentage_style_context::reset()
+{
+ m_current_style = std::make_unique<odf_number_format>();
+}
+
+std::unique_ptr<odf_number_format> percentage_style_context::pop_style()
+{
+ return std::move(m_current_style);
+}
+
+boolean_style_context::boolean_style_context(session_context& session_cxt, const tokens& tk) :
+ xml_context_base(session_cxt, tk)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_odf_number, XML_boolean_style }, // root element
+ { NS_odf_number, XML_boolean_style, NS_odf_number, XML_boolean },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+void boolean_style_context::start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_boolean_style:
+ {
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_style && attr.name == XML_name)
+ m_current_style->name = intern(attr);
+ }
+ break;
+ }
+ case XML_boolean:
+ {
+ m_current_style->code += "BOOLEAN";
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool boolean_style_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ return pop_stack(ns, name);
+}
+
+void boolean_style_context::reset()
+{
+ m_current_style = std::make_unique<odf_number_format>();
+}
+
+std::unique_ptr<odf_number_format> boolean_style_context::pop_style()
+{
+ return std::move(m_current_style);
+}
+
+text_style_context::text_style_context(session_context& session_cxt, const tokens& tk) :
+ xml_context_base(session_cxt, tk)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_odf_number, XML_text_style }, // root element
+ { NS_odf_number, XML_text_style, NS_odf_number, XML_text },
+ { NS_odf_number, XML_text_style, NS_odf_number, XML_text_content },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+void text_style_context::start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_text_style:
+ {
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_style && attr.name == XML_name)
+ m_current_style->name = intern(attr);
+ }
+ break;
+ }
+ case XML_text_content:
+ {
+ m_current_style->code += '@';
+ break;
+ }
+ case XML_text:
+ m_text_stream = std::ostringstream{};
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool text_style_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_text:
+ m_current_style->code += m_text_stream.str();
+ break;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void text_style_context::characters(std::string_view str, bool /*transient*/)
+{
+ m_text_stream << str;
+}
+
+void text_style_context::reset()
+{
+ m_current_style = std::make_unique<odf_number_format>();
+}
+
+std::unique_ptr<odf_number_format> text_style_context::pop_style()
+{
+ return std::move(m_current_style);
+}
+
+number_style_context::number_style_context(session_context& session_cxt, const tokens& tk) :
+ xml_context_base(session_cxt, tk)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_odf_number, XML_number_style }, // root element
+ { NS_odf_number, XML_number_style, NS_odf_number, XML_fraction },
+ { NS_odf_number, XML_number_style, NS_odf_number, XML_number },
+ { NS_odf_number, XML_number_style, NS_odf_number, XML_scientific_number },
+ { NS_odf_number, XML_number_style, NS_odf_number, XML_text },
+ { NS_odf_number, XML_number_style, NS_odf_style, XML_map },
+ { NS_odf_number, XML_number_style, NS_odf_style, XML_text_properties },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+void number_style_context::start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_fraction:
+ start_element_fraction(attrs);
+ break;
+ case XML_number_style:
+ start_element_number_style(attrs);
+ break;
+ case XML_number:
+ parse_element_number(attrs, *m_current_style);
+ break;
+ case XML_scientific_number:
+ start_element_scientific_number(attrs);
+ break;
+ case XML_text:
+ m_text_stream = std::ostringstream{};
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else if (ns == NS_odf_style)
+ {
+ switch (name)
+ {
+ case XML_text_properties:
+ parse_element_text_properties(attrs, *m_current_style);
+ break;
+ case XML_map:
+ {
+ auto res = parse_element_map(get_session_context(), attrs, *m_current_style);
+ if (!res.success && get_config().debug)
+ warn(res.error_message);
+
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool number_style_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_text:
+ m_current_style->code += m_text_stream.str();
+ break;
+ default:;
+ }
+ }
+
+ return pop_stack(ns, name);
+}
+
+void number_style_context::characters(std::string_view str, bool /*transient*/)
+{
+ m_text_stream << str;
+}
+
+void number_style_context::reset()
+{
+ m_current_style = std::make_unique<odf_number_format>();
+ m_text_stream = std::ostringstream{};
+ m_country_code = std::string_view{};
+ m_language = std::string_view{};
+}
+
+std::unique_ptr<odf_number_format> number_style_context::pop_style()
+{
+ return std::move(m_current_style);
+}
+
+void number_style_context::start_element_fraction(const std::vector<xml_token_attr_t>& attrs)
+{
+ std::size_t min_integer_digits = 0;
+ std::size_t min_numerator_digits = 0;
+ std::size_t min_denominator_digits = 0;
+
+ std::optional<std::string_view> denominator_value;
+
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_number)
+ {
+ switch (attr.name)
+ {
+ case XML_min_integer_digits:
+ min_integer_digits = to_long(attr.value);
+ break;
+ case XML_min_numerator_digits:
+ min_numerator_digits = to_long(attr.value);
+ break;
+ case XML_min_denominator_digits:
+ min_denominator_digits = to_long(attr.value);
+ break;
+ case XML_denominator_value:
+ {
+ denominator_value = attr.value;
+ break;
+ }
+ }
+ }
+ }
+
+ if (min_integer_digits > 0)
+ {
+ m_current_style->code += std::string{"#", min_integer_digits};
+ m_current_style->code += ' ';
+ }
+
+ if (min_numerator_digits > 0)
+ m_current_style->code += std::string{"?", min_numerator_digits};
+
+ m_current_style->code += '/';
+
+ if (denominator_value)
+ m_current_style->code += *denominator_value;
+ else if (min_denominator_digits > 0)
+ m_current_style->code += std::string{"?", min_denominator_digits};
+}
+
+void number_style_context::start_element_number_style(const std::vector<xml_token_attr_t>& attrs)
+{
+ for (const xml_token_attr_t& attr: attrs)
+ {
+ if (attr.ns == NS_odf_number)
+ {
+ switch (attr.name)
+ {
+ case XML_country:
+ m_country_code = attr.value;
+ break;
+ case XML_language:
+ m_language = attr.value;
+ break;
+ default:
+ ;
+ }
+ }
+ else if (attr.ns == NS_odf_style)
+ {
+ switch (attr.name)
+ {
+ case XML_name:
+ m_current_style->name = attr.value;
+ break;
+ default:
+ ;
+ }
+ }
+ }
+}
+
+void number_style_context::start_element_scientific_number(const std::vector<xml_token_attr_t>& attrs)
+{
+ long decimal_places = 0;
+ long min_exponent_digits = 0;
+ long min_integer_digits = 0;
+ bool grouping = false;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_odf_number)
+ {
+ switch (attr.name)
+ {
+ case XML_decimal_places:
+ decimal_places = to_long(attr.value);
+ break;
+ case XML_grouping:
+ grouping = to_bool(attr.value);
+ break;
+ case XML_min_exponent_digits:
+ min_exponent_digits = to_long(attr.value);
+ break;
+ case XML_min_integer_digits:
+ min_integer_digits = to_long(attr.value);
+ break;
+ }
+ }
+ }
+
+ if (grouping)
+ {
+ if (min_integer_digits < 4)
+ {
+ m_current_style->code += "#,";
+
+ for (long i = 0; i < 3 - min_integer_digits; ++i)
+ {
+ m_current_style->code += "#";
+ }
+
+ for (long i = 0; i < min_integer_digits; ++i)
+ {
+ m_current_style->code += "0";
+ }
+ }
+ else
+ {
+ std::string temporary_code;
+ for (long i = 0; i < min_integer_digits; ++i)
+ {
+ if (i % 3 == 0 && i != 0)
+ temporary_code += ",";
+
+ temporary_code += "0";
+ }
+
+ std::reverse(temporary_code.begin(), temporary_code.end());
+ m_current_style->code += temporary_code;
+ }
+ }
+ else
+ {
+ if (min_integer_digits == 0)
+ m_current_style->code += "#";
+
+ for (long i = 0; i < min_integer_digits; ++i)
+ m_current_style->code += "0";
+ }
+
+ m_current_style->code += ".";
+
+ for (long i = 0; i < decimal_places; ++i)
+ m_current_style->code += "0";
+
+ m_current_style->code += "E+";
+
+ for (long i = 0; i < min_exponent_digits; ++i)
+ m_current_style->code += "0";
+}
+
+currency_style_context::currency_style_context(session_context& session_cxt, const tokens& tk) :
+ xml_context_base(session_cxt, tk)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_odf_number, XML_currency_style }, // root element
+ { NS_odf_number, XML_currency_style, NS_odf_number, XML_currency_symbol },
+ { NS_odf_number, XML_currency_style, NS_odf_number, XML_number },
+ { NS_odf_number, XML_currency_style, NS_odf_number, XML_text },
+ { NS_odf_number, XML_currency_style, NS_odf_style, XML_map },
+ { NS_odf_number, XML_currency_style, NS_odf_style, XML_text_properties },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+void currency_style_context::start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_currency_style:
+ start_element_currency_style(attrs);
+ break;
+ case XML_currency_symbol:
+ m_text_stream = std::ostringstream{};
+ break;
+ case XML_number:
+ parse_element_number(attrs, *m_current_style);
+ break;
+ case XML_text:
+ m_text_stream = std::ostringstream{};
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else if (ns == NS_odf_style)
+ {
+ switch (name)
+ {
+ case XML_map:
+ {
+ auto res = parse_element_map(get_session_context(), attrs, *m_current_style);
+ if (!res.success && get_config().debug)
+ warn(res.error_message);
+
+ break;
+ }
+ case XML_text_properties:
+ parse_element_text_properties(attrs, *m_current_style);
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool currency_style_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_currency_symbol:
+ {
+ std::ostringstream os;
+ os << m_current_style->code << "[$" << m_text_stream.str() << ']';
+ m_current_style->code = os.str();
+ break;
+ }
+ case XML_text:
+ m_current_style->code += m_text_stream.str();
+ break;
+ }
+ }
+
+ return pop_stack(ns, name);
+}
+
+void currency_style_context::characters(std::string_view str, bool /*transient*/)
+{
+ m_text_stream << str;
+}
+
+void currency_style_context::reset()
+{
+ m_current_style = std::make_unique<odf_number_format>();
+}
+
+std::unique_ptr<odf_number_format> currency_style_context::pop_style()
+{
+ return std::move(m_current_style);
+}
+
+void currency_style_context::start_element_currency_style(const std::vector<xml_token_attr_t>& attrs)
+{
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns == NS_odf_style)
+ {
+ switch (attr.name)
+ {
+ case XML_name:
+ m_current_style->name = intern(attr);
+ break;
+ case XML_volatile:
+ m_current_style->is_volatile = to_bool(attr.value);
+ break;
+ }
+ }
+ else if (attr.ns == NS_odf_number)
+ {
+ switch (attr.name)
+ {
+ case XML_language:
+ m_language = intern(attr);
+ break;
+ case XML_country:
+ m_country_code = intern(attr);
+ break;
+ }
+ }
+ }
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_number_format_context.hpp b/src/liborcus/odf_number_format_context.hpp
new file mode 100644
index 0000000..c91c817
--- /dev/null
+++ b/src/liborcus/odf_number_format_context.hpp
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ODF_NUMBER_FORMATTING_CONTEXT_HPP
+#define ODF_NUMBER_FORMATTING_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "odf_styles.hpp"
+
+#include "orcus/string_pool.hpp"
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+ class import_styles;
+}}
+
+class date_style_context : public xml_context_base
+{
+public:
+ date_style_context(session_context& session_cxt, const tokens& tk);
+
+ void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+ bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ void characters(std::string_view str, bool transient) override;
+
+ void reset();
+
+ std::unique_ptr<odf_number_format> pop_style();
+
+private:
+ void start_element_date_style(const std::vector<xml_token_attr_t>& attrs);
+ void start_element_month(const std::vector<xml_token_attr_t>& attrs);
+ void start_element_day(const std::vector<xml_token_attr_t>& attrs);
+ void start_element_year(const std::vector<xml_token_attr_t>& attrs);
+
+private:
+ std::unique_ptr<odf_number_format> m_current_style;
+ std::ostringstream m_text_stream;
+};
+
+class time_style_context : public xml_context_base
+{
+public:
+ time_style_context(session_context& session_cxt, const tokens& tk);
+
+ void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+ bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ void characters(std::string_view str, bool transient) override;
+
+ void reset();
+
+ std::unique_ptr<odf_number_format> pop_style();
+
+private:
+ void start_element_time_style(const std::vector<xml_token_attr_t>& attrs);
+ void start_element_seconds(const std::vector<xml_token_attr_t>& attrs);
+
+private:
+ std::unique_ptr<odf_number_format> m_current_style;
+ std::ostringstream m_text_stream;
+};
+
+class percentage_style_context : public xml_context_base
+{
+public:
+ percentage_style_context(session_context& session_cxt, const tokens& tk);
+
+ void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+ bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ void characters(std::string_view str, bool transient) override;
+
+ void reset();
+
+ std::unique_ptr<odf_number_format> pop_style();
+
+private:
+ std::unique_ptr<odf_number_format> m_current_style;
+ std::ostringstream m_text_stream;
+};
+
+class boolean_style_context : public xml_context_base
+{
+public:
+ boolean_style_context(session_context& session_cxt, const tokens& tk);
+
+ void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+ bool end_element(xmlns_id_t ns, xml_token_t name) override;
+
+ void reset();
+
+ std::unique_ptr<odf_number_format> pop_style();
+
+private:
+ std::unique_ptr<odf_number_format> m_current_style;
+};
+
+class text_style_context : public xml_context_base
+{
+public:
+ text_style_context(session_context& session_cxt, const tokens& tk);
+
+ void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+ bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ void characters(std::string_view str, bool transient) override;
+
+ void reset();
+
+ std::unique_ptr<odf_number_format> pop_style();
+
+private:
+ std::unique_ptr<odf_number_format> m_current_style;
+ std::ostringstream m_text_stream;
+};
+
+/**
+ * Context for <number:number-style> scope.
+ */
+class number_style_context : public xml_context_base
+{
+public:
+ number_style_context(session_context& session_cxt, const tokens& tk);
+
+ void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+ bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ void characters(std::string_view str, bool transient) override;
+
+ void reset();
+
+ std::unique_ptr<odf_number_format> pop_style();
+
+private:
+ void start_element_fraction(const std::vector<xml_token_attr_t>& attrs);
+ void start_element_number_style(const std::vector<xml_token_attr_t>& attrs);
+ void start_element_scientific_number(const std::vector<xml_token_attr_t>& attrs);
+
+private:
+ std::unique_ptr<odf_number_format> m_current_style;
+ std::ostringstream m_text_stream;
+
+ std::string_view m_country_code; // TODO: handle this
+ std::string_view m_language; // TODO: handle this
+};
+
+/**
+ * Context for <number:currency-style> element scope.
+ */
+class currency_style_context : public xml_context_base
+{
+public:
+ currency_style_context(session_context& session_cxt, const tokens& tk);
+
+ void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+ bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ void characters(std::string_view str, bool transient) override;
+
+ void reset();
+
+ std::unique_ptr<odf_number_format> pop_style();
+
+private:
+ void start_element_currency_style(const std::vector<xml_token_attr_t>& attrs);
+
+private:
+ std::unique_ptr<odf_number_format> m_current_style;
+ std::ostringstream m_text_stream;
+
+ std::string_view m_country_code; // TODO: handle this
+ std::string_view m_language; // TODO: handle this
+};
+
+} // namespace orcus
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_para_context.cpp b/src/liborcus/odf_para_context.cpp
new file mode 100644
index 0000000..ad4b193
--- /dev/null
+++ b/src/liborcus/odf_para_context.cpp
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "odf_para_context.hpp"
+#include "odf_token_constants.hpp"
+#include "odf_namespace_types.hpp"
+#include "xml_context_global.hpp"
+
+#include "orcus/spreadsheet/import_interface.hpp"
+#include "orcus/exception.hpp"
+
+#include <iostream>
+#include <cassert>
+
+namespace orcus {
+
+text_para_context::text_para_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_shared_strings* ssb, odf_styles_map_type& styles) :
+ xml_context_base(session_cxt, tokens),
+ mp_sstrings(ssb), m_styles(styles),
+ m_string_index(0), m_has_content(false)
+{
+}
+
+text_para_context::~text_para_context() = default;
+
+xml_context_base* text_para_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void text_para_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+ // not implemented yet.
+}
+
+void text_para_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ if (ns == NS_odf_text)
+ {
+ switch (name)
+ {
+ case XML_p:
+ // paragraph
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ break;
+ case XML_span:
+ {
+ // text span.
+ xml_element_expected(parent, NS_odf_text, XML_p);
+ flush_segment();
+ std::string_view style_name =
+ for_each(attrs.begin(), attrs.end(), single_attr_getter(m_pool, NS_odf_text, XML_style_name)).get_value();
+ m_span_stack.push_back(style_name);
+
+ }
+ break;
+ case XML_s:
+ // control character. ignored for now.
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool text_para_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_text)
+ {
+ switch (name)
+ {
+ case XML_p:
+ {
+ // paragraph
+ flush_segment();
+ if (mp_sstrings)
+ m_string_index = mp_sstrings->commit_segments();
+ }
+ break;
+ case XML_span:
+ {
+ // text span.
+ if (m_span_stack.empty())
+ throw xml_structure_error("</text:span> encountered without matching opening element.");
+
+ flush_segment();
+ m_span_stack.pop_back();
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void text_para_context::characters(std::string_view str, bool transient)
+{
+ if (transient)
+ m_contents.push_back(m_pool.intern(str).first);
+ else
+ m_contents.push_back(str);
+}
+
+void text_para_context::reset()
+{
+ m_string_index = 0;
+ m_has_content = false;
+ m_pool.clear();
+ m_contents.clear();
+}
+
+size_t text_para_context::get_string_index() const
+{
+ return m_string_index;
+}
+
+bool text_para_context::empty() const
+{
+ return !m_has_content;
+}
+
+void text_para_context::flush_segment()
+{
+ if (m_contents.empty())
+ // No content to flush.
+ return;
+
+ m_has_content = true;
+
+ const odf_style* style = nullptr;
+ if (!m_span_stack.empty())
+ {
+ std::string_view style_name = m_span_stack.back();
+ auto it = m_styles.find(style_name);
+ if (it != m_styles.end())
+ style = it->second.get();
+ }
+
+ if (mp_sstrings)
+ {
+ if (style && style->family == style_family_text)
+ {
+ const auto& data = std::get<odf_style::text>(style->data);
+ mp_sstrings->set_segment_font(data.font);
+ }
+
+ for (std::string_view ps : m_contents)
+ mp_sstrings->append_segment(ps);
+ }
+
+ m_contents.clear();
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_para_context.hpp b/src/liborcus/odf_para_context.hpp
new file mode 100644
index 0000000..42bdb7d
--- /dev/null
+++ b/src/liborcus/odf_para_context.hpp
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_PARACONTEXT_HPP
+#define ORCUS_PARACONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "odf_styles.hpp"
+
+#include "orcus/string_pool.hpp"
+
+#include <vector>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface { class import_shared_strings; }}
+
+/**
+ * This class handles <text:p> contexts.
+ */
+class text_para_context : public xml_context_base
+{
+public:
+ text_para_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_shared_strings* ssb, odf_styles_map_type& styles);
+ virtual ~text_para_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+
+ void reset();
+
+ size_t get_string_index() const;
+ bool empty() const;
+
+private:
+ void flush_segment();
+
+private:
+ spreadsheet::iface::import_shared_strings* mp_sstrings;
+ odf_styles_map_type& m_styles;
+
+ string_pool m_pool;
+ std::vector<std::string_view> m_span_stack; /// stack of text spans.
+ std::vector<std::string_view> m_contents;
+ size_t m_string_index;
+ bool m_has_content;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_style_context.cpp b/src/liborcus/odf_style_context.cpp
new file mode 100644
index 0000000..70953a1
--- /dev/null
+++ b/src/liborcus/odf_style_context.cpp
@@ -0,0 +1,774 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "odf_style_context.hpp"
+#include "impl_utils.hpp"
+#include "odf_namespace_types.hpp"
+#include "odf_token_constants.hpp"
+#include "odf_helper.hpp"
+#include "session_context.hpp"
+#include "ods_session_data.hpp"
+
+#include <mdds/sorted_string_map.hpp>
+
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+namespace style_family {
+
+using map_type = mdds::sorted_string_map<odf_style_family>;
+
+constexpr map_type::entry entries[] =
+{
+ { MDDS_ASCII("graphic"), style_family_graphic },
+ { MDDS_ASCII("paragraph"), style_family_paragraph },
+ { MDDS_ASCII("table"), style_family_table },
+ { MDDS_ASCII("table-cell"), style_family_table_cell },
+ { MDDS_ASCII("table-column"), style_family_table_column },
+ { MDDS_ASCII("table-row"), style_family_table_row },
+ { MDDS_ASCII("text"), style_family_text }
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), style_family_unknown);
+ return mt;
+}
+
+} // namespace style_family
+
+odf_style_family to_style_family(std::string_view val)
+{
+ return style_family::get().find(val.data(), val.size());
+}
+
+std::string_view to_string(odf_style_family family)
+{
+ static constexpr std::string_view unknown_str = "unknown";
+
+ for (const auto& entry : style_family::entries)
+ {
+ if (entry.value == family)
+ return {entry.key, entry.key_length};
+ }
+
+ return unknown_str;
+}
+
+namespace st_style {
+
+typedef mdds::sorted_string_map<ss::strikethrough_style_t> map_type;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] =
+{
+ { MDDS_ASCII("dash"), ss::strikethrough_style_t::dash },
+ { MDDS_ASCII("dot-dash"), ss::strikethrough_style_t::dot_dash },
+ { MDDS_ASCII("dot-dot-dash"), ss::strikethrough_style_t::dot_dot_dash },
+ { MDDS_ASCII("dotted"), ss::strikethrough_style_t::dotted },
+ { MDDS_ASCII("long-dash"), ss::strikethrough_style_t::long_dash },
+ { MDDS_ASCII("none"), ss::strikethrough_style_t::none },
+ { MDDS_ASCII("solid"), ss::strikethrough_style_t::solid },
+ { MDDS_ASCII("wave"), ss::strikethrough_style_t::wave },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::strikethrough_style_t::none);
+ return mt;
+}
+
+} // namespace st_style
+
+} // anonymous namespace
+
+style_context::style_context(session_context& session_cxt, const tokens& tk, ss::iface::import_styles* iface_styles) :
+ xml_context_base(session_cxt, tk),
+ mp_styles(iface_styles)
+{
+}
+
+void style_context::start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+
+ if (ns == NS_odf_style)
+ {
+ switch (name)
+ {
+ case XML_style:
+ {
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+
+ std::string_view style_name;
+ std::string_view display_style_name;
+ std::string_view parent_style_name;
+ std::optional<std::string_view> data_style_name;
+ odf_style_family family = style_family_unknown;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_odf_style)
+ {
+ switch (attr.name)
+ {
+ case XML_name:
+ style_name = intern(attr.value);
+ break;
+ case XML_display_name:
+ display_style_name = intern(attr.value);
+ break;
+ case XML_family:
+ family = to_style_family(attr.value);
+ break;
+ case XML_parent_style_name:
+ parent_style_name = intern(attr.value);
+ break;
+ case XML_data_style_name:
+ data_style_name = attr.value; // no need to intern
+ break;
+ }
+ }
+ }
+
+ m_current_style = std::make_unique<odf_style>(
+ style_name, display_style_name, family, parent_style_name);
+
+ if (data_style_name && family == style_family_table_cell)
+ {
+ const auto& ods_data = get_session_context().get_data<ods_session_data>();
+ const auto& numfmt_name2id = ods_data.number_formats.name2id_map;
+
+ if (auto it = numfmt_name2id.find(*data_style_name); it != numfmt_name2id.end())
+ {
+ // record the number format id associated with the name.
+ auto& data = std::get<odf_style::cell>(m_current_style->data);
+ data.number_format = it->second;
+ }
+ else
+ {
+ if (get_config().debug)
+ {
+ std::ostringstream os;
+ os << "no number style found for the data style name of '" << *data_style_name << "'";
+ warn(os.str());
+ }
+ }
+ }
+ break;
+ }
+ case XML_table_column_properties:
+ {
+ xml_element_expected(parent, NS_odf_style, XML_style);
+ assert(m_current_style->family == style_family_table_column);
+
+ for (const xml_token_attr_t& attr: attrs)
+ {
+ if (attr.ns == NS_odf_style)
+ {
+ switch (attr.name)
+ {
+ case XML_column_width:
+ {
+ std::get<odf_style::column>(m_current_style->data).width = to_length(attr.value);
+ break;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ case XML_table_row_properties:
+ {
+ xml_element_expected(parent, NS_odf_style, XML_style);
+ assert(m_current_style->family == style_family_table_row);
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_odf_style)
+ {
+ switch (attr.name)
+ {
+ case XML_row_height:
+ {
+ auto& data = std::get<odf_style::row>(m_current_style->data);
+ data.height = to_length(attr.value);
+ data.height_set = true;
+ break;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ case XML_table_properties:
+ xml_element_expected(parent, NS_odf_style, XML_style);
+ break;
+ case XML_paragraph_properties:
+ start_paragraph_properties(parent, attrs);
+ break;
+ case XML_text_properties:
+ start_text_properties(parent, attrs);
+ break;
+ case XML_table_cell_properties:
+ start_table_cell_properties(parent, attrs);
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool style_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ return pop_stack(ns, name);
+}
+
+void style_context::reset()
+{
+ m_current_style.reset();
+}
+
+std::unique_ptr<odf_style> style_context::pop_style()
+{
+ return std::move(m_current_style);
+}
+
+void style_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+void style_context::start_paragraph_properties(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ xml_element_expected(parent, NS_odf_style, XML_style);
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_odf_fo)
+ {
+ switch (attr.name)
+ {
+ case XML_text_align:
+ {
+ auto v = odf::extract_hor_alignment_style(attr.value);
+
+ switch (m_current_style->family)
+ {
+ case style_family_table_cell:
+ {
+ auto& data = std::get<odf_style::cell>(m_current_style->data);
+ data.hor_align = v;
+ break;
+ }
+ case style_family_paragraph:
+ {
+ auto& data = std::get<odf_style::paragraph>(m_current_style->data);
+ data.hor_align = v;
+ break;
+ }
+ default:
+ {
+ if (get_config().debug)
+ {
+ std::ostringstream os;
+ os << "unhandled fo:text-align attribute (family=" << to_string(m_current_style->family) << ")";
+ warn(os.str());
+ }
+ }
+ }
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ }
+}
+
+void style_context::start_text_properties(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ static const xml_elem_set_t expected = {
+ { NS_odf_style, XML_style },
+ { NS_odf_text, XML_list_level_style_number },
+ { NS_odf_text, XML_list_level_style_bullet },
+ };
+ xml_element_expected(parent, expected);
+
+ if (parent != xml_token_pair_t(NS_odf_style, XML_style))
+ // TODO : handle this properly in the future.
+ return;
+
+ // NB: no need to intern the font names since they are consumed at the end
+ // of this function.
+ std::optional<std::string_view> font_name;
+ std::optional<std::string_view> font_name_asian;
+ std::optional<std::string_view> font_name_complex;
+ std::optional<length_t> font_size;
+ std::optional<length_t> font_size_asian;
+ std::optional<length_t> font_size_complex;
+ std::optional<bool> bold;
+ std::optional<bool> bold_asian;
+ std::optional<bool> bold_complex;
+ std::optional<bool> italic;
+ std::optional<bool> italic_asian;
+ std::optional<bool> italic_complex;
+ std::optional<ss::color_rgb_t> color;
+
+ std::optional<ss::color_rgb_t> underline_color;
+ std::optional<ss::underline_t> underline_style;
+ std::optional<ss::underline_type_t> underline_type;
+ std::optional<ss::underline_width_t> underline_width;
+ std::optional<ss::underline_mode_t> underline_mode;
+
+ std::optional<ss::strikethrough_style_t> strikethrough_style;
+ std::optional<ss::strikethrough_type_t> strikethrough_type;
+ std::optional<ss::strikethrough_width_t> strikethrough_width;
+ std::optional<ss::strikethrough_text_t> strikethrough_text;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_odf_style)
+ {
+ switch (attr.name)
+ {
+ case XML_font_name:
+ font_name = attr.value;
+ break;
+ case XML_font_name_asian:
+ font_name_asian = attr.value;
+ break;
+ case XML_font_name_complex:
+ font_name_complex = attr.value;
+ break;
+ case XML_font_size_asian:
+ font_size_asian = to_length(attr.value);
+ break;
+ case XML_font_size_complex:
+ font_size_complex = to_length(attr.value);
+ break;
+ case XML_font_style_asian:
+ italic_asian = attr.value == "italic";
+ break;
+ case XML_font_style_complex:
+ italic_complex = attr.value == "italic";
+ break;
+ case XML_font_weight_asian:
+ bold_asian = attr.value == "bold";
+ break;
+ case XML_font_weight_complex:
+ bold_complex = attr.value == "bold";
+ break;
+ case XML_text_underline_color:
+ if (attr.value != "font-color")
+ underline_color = odf::convert_fo_color(attr.value);
+ break;
+ case XML_text_underline_mode:
+ if (attr.value == "skip-white-space")
+ underline_mode = ss::underline_mode_t::skip_white_space;
+ else
+ underline_mode = ss::underline_mode_t::continuous;
+ break;
+ case XML_text_underline_width:
+ {
+ underline_width = odf::extract_underline_width(attr.value);
+ break;
+ }
+ case XML_text_underline_style:
+ {
+ underline_style = odf::extract_underline_style(attr.value);
+ break;
+ }
+ case XML_text_underline_type:
+ {
+ if (attr.value == "none")
+ underline_type = ss::underline_type_t::none;
+ else if (attr.value == "single")
+ underline_type = ss::underline_type_t::single_type;
+ else if (attr.value == "double")
+ underline_type = ss::underline_type_t::double_type;
+ break;
+ }
+ case XML_text_line_through_style:
+ {
+ strikethrough_style = st_style::get().find(attr.value.data(), attr.value.size());
+ break;
+ }
+ case XML_text_line_through_type:
+ {
+ if (attr.value == "single")
+ strikethrough_type = ss::strikethrough_type_t::single_type;
+ else if (attr.value == "double")
+ strikethrough_type = ss::strikethrough_type_t::double_type;
+ else
+ strikethrough_type = ss::strikethrough_type_t::unknown;
+ break;
+ }
+ case XML_text_line_through_width:
+ {
+ if (attr.value == "bold")
+ strikethrough_width = ss::strikethrough_width_t::bold;
+ else
+ strikethrough_width = ss::strikethrough_width_t::unknown;
+ break;
+ }
+ case XML_text_line_through_text:
+ {
+ if (attr.value == "/")
+ strikethrough_text = ss::strikethrough_text_t::slash;
+ else if (attr.value == "X")
+ strikethrough_text = ss::strikethrough_text_t::cross;
+ else
+ strikethrough_text = ss::strikethrough_text_t::unknown;
+ break;
+ }
+ }
+ }
+ else if (attr.ns == NS_odf_fo)
+ {
+ switch (attr.name)
+ {
+ case XML_font_size:
+ font_size = to_length(attr.value);
+ break;
+ case XML_font_style:
+ italic = attr.value == "italic";
+ break;
+ case XML_font_weight:
+ bold = attr.value == "bold";
+ break;
+ case XML_color:
+ color = odf::convert_fo_color(attr.value);
+ break;
+ }
+ }
+ }
+
+ // Commit the font data.
+ auto* font_style = mp_styles->start_font_style();
+ ENSURE_INTERFACE(font_style, import_font_style);
+
+ if (font_name)
+ font_style->set_name(*font_name);
+
+ if (font_name_asian)
+ font_style->set_name_asian(*font_name_asian);
+
+ if (font_name_complex)
+ font_style->set_name_complex(*font_name_complex);
+
+ if (font_size && font_size->unit == length_unit_t::point)
+ font_style->set_size(font_size->value);
+
+ if (font_size_asian && font_size_asian->unit == length_unit_t::point)
+ font_style->set_size_asian(font_size_asian->value);
+
+ if (font_size_complex && font_size_complex->unit == length_unit_t::point)
+ font_style->set_size_complex(font_size_complex->value);
+
+ if (bold)
+ font_style->set_bold(*bold);
+
+ if (bold_asian)
+ font_style->set_bold_asian(*bold_asian);
+
+ if (bold_complex)
+ font_style->set_bold_complex(*bold_complex);
+
+ if (italic)
+ font_style->set_italic(*italic);
+
+ if (italic_asian)
+ font_style->set_italic_asian(*italic_asian);
+
+ if (italic_complex)
+ font_style->set_italic_complex(*italic_complex);
+
+ if (color)
+ font_style->set_color(255, color->red, color->green, color->blue);
+
+ if (underline_color)
+ // Separate underline color is specified.
+ font_style->set_underline_color(255, underline_color->red, underline_color->green, underline_color->blue);
+
+ if (underline_width)
+ font_style->set_underline_width(*underline_width);
+
+ if (underline_style)
+ font_style->set_underline(*underline_style);
+
+ if (underline_type)
+ font_style->set_underline_type(*underline_type);
+
+ if (underline_mode)
+ font_style->set_underline_mode(*underline_mode);
+
+ if (strikethrough_style)
+ font_style->set_strikethrough_style(*strikethrough_style);
+
+ if (strikethrough_type)
+ font_style->set_strikethrough_type(*strikethrough_type);
+
+ if (strikethrough_width)
+ font_style->set_strikethrough_width(*strikethrough_width);
+
+ if (strikethrough_text)
+ font_style->set_strikethrough_text(*strikethrough_text);
+
+ size_t font_id = font_style->commit();
+
+ switch (m_current_style->family)
+ {
+ case style_family_table_cell:
+ {
+ auto& data = std::get<odf_style::cell>(m_current_style->data);
+ data.font = font_id;
+ break;
+ }
+ case style_family_text:
+ {
+ auto& data = std::get<odf_style::text>(m_current_style->data);
+ data.font = font_id;
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+void style_context::start_table_cell_properties(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ xml_element_expected(parent, NS_odf_style, XML_style);
+
+ if (m_current_style->family != style_family_table_cell)
+ throw xml_structure_error("expected table_cell family style in cell_properties element");
+
+ if (!mp_styles)
+ return;
+
+ auto& data = std::get<odf_style::cell>(m_current_style->data);
+
+ std::optional<spreadsheet::color_rgb_t> bg_color;
+
+ std::optional<bool> locked;
+ std::optional<bool> hidden;
+ std::optional<bool> formula_hidden;
+ std::optional<bool> print_content;
+
+ bool cell_protection_set = false;
+
+ using border_map_type = std::map<ss::border_direction_t, odf::border_details_t>;
+ border_map_type border_styles;
+
+ ss::ver_alignment_t ver_alignment = ss::ver_alignment_t::unknown;
+ std::optional<bool> wrap_text;
+ std::optional<bool> shrink_to_fit;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_odf_fo)
+ {
+ switch (attr.name)
+ {
+ case XML_background_color:
+ bg_color = odf::convert_fo_color(attr.value);
+ break;
+ case XML_border:
+ {
+ odf::border_details_t border_details = odf::extract_border_details(attr.value);
+
+ const ss::border_direction_t dirs[] =
+ {
+ ss::border_direction_t::top,
+ ss::border_direction_t::bottom,
+ ss::border_direction_t::left,
+ ss::border_direction_t::right
+ };
+
+ for (const auto dir : dirs)
+ border_styles.insert_or_assign(dir, border_details);
+
+ break;
+ }
+ case XML_border_top:
+ {
+ odf::border_details_t border_details = odf::extract_border_details(attr.value);
+ border_styles.insert_or_assign(ss::border_direction_t::top, border_details);
+ break;
+ }
+ case XML_border_bottom:
+ {
+ odf::border_details_t border_details = odf::extract_border_details(attr.value);
+ border_styles.insert_or_assign(ss::border_direction_t::bottom, border_details);
+ break;
+ }
+ case XML_border_left:
+ {
+ odf::border_details_t border_details = odf::extract_border_details(attr.value);
+ border_styles.insert_or_assign(ss::border_direction_t::left, border_details);
+ break;
+ }
+ case XML_border_right:
+ {
+ odf::border_details_t border_details = odf::extract_border_details(attr.value);
+ border_styles.insert_or_assign(ss::border_direction_t::right, border_details);
+ break;
+ }
+ case XML_diagonal_bl_tr:
+ {
+ odf::border_details_t border_details = odf::extract_border_details(attr.value);
+ border_styles.insert_or_assign(ss::border_direction_t::diagonal_bl_tr, border_details);
+ break;
+ }
+ case XML_diagonal_tl_br:
+ {
+ odf::border_details_t border_details = odf::extract_border_details(attr.value);
+ border_styles.insert_or_assign(ss::border_direction_t::diagonal_tl_br, border_details);
+ break;
+ }
+ case XML_wrap_option:
+ {
+ wrap_text = (attr.value == "wrap");
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ else if (attr.ns == NS_odf_style)
+ {
+ switch (attr.name)
+ {
+ case XML_print_content:
+ {
+ cell_protection_set = true;
+ print_content = to_bool(attr.value);
+ break;
+ }
+ case XML_cell_protect:
+ {
+ if (attr.value == "protected")
+ {
+ cell_protection_set = true;
+ locked = true;
+ }
+ else if (attr.value == "hidden-and-protected")
+ {
+ cell_protection_set = true;
+ locked = true;
+ hidden = true;
+ }
+ else if (attr.value == "formula-hidden")
+ {
+ cell_protection_set = true;
+ formula_hidden = true;
+ }
+ else if (attr.value == "protected formula-hidden" || attr.value == "formula-hidden protected")
+ {
+ cell_protection_set = true;
+ formula_hidden = true;
+ locked = true;
+ }
+ else if (attr.value == "none")
+ {
+ cell_protection_set = true;
+ locked = false;
+ hidden = false;
+ formula_hidden = false;
+ }
+ break;
+ }
+ case XML_vertical_align:
+ ver_alignment = odf::extract_ver_alignment_style(attr.value);
+ break;
+ case XML_shrink_to_fit:
+ shrink_to_fit = to_bool(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ }
+
+ std::size_t fill_id = 0;
+ std::size_t border_id = 0;
+ std::size_t cell_protection_id = 0;
+
+ if (bg_color)
+ {
+ auto* fill_style = mp_styles->start_fill_style();
+ ENSURE_INTERFACE(fill_style, import_fill_style);
+
+ fill_style->set_pattern_type(ss::fill_pattern_t::solid);
+ fill_style->set_fg_color(255, bg_color->red, bg_color->green, bg_color->blue);
+ fill_id = fill_style->commit();
+ }
+
+ if (!border_styles.empty())
+ {
+ auto* border_style = mp_styles->start_border_style();
+ ENSURE_INTERFACE(border_style, import_border_style);
+
+ for (const auto& [dir, details] : border_styles)
+ {
+ border_style->set_color(dir, 255, details.red, details.green, details.blue);
+ border_style->set_style(dir, details.border_style);
+ border_style->set_width(dir, details.border_width.value, details.border_width.unit);
+ }
+
+ border_id = border_style->commit();
+ }
+
+ if (cell_protection_set)
+ {
+ auto* cell_protection = mp_styles->start_cell_protection();
+ ENSURE_INTERFACE(cell_protection, import_cell_protection);
+
+ if (hidden)
+ cell_protection->set_hidden(*hidden);
+
+ if (locked)
+ cell_protection->set_locked(*locked);
+
+ if (print_content)
+ cell_protection->set_print_content(*print_content);
+
+ if (formula_hidden)
+ cell_protection->set_formula_hidden(*formula_hidden);
+
+ cell_protection_id = cell_protection->commit();
+ }
+
+ switch (m_current_style->family)
+ {
+ case style_family_table_cell:
+ {
+ data.fill = fill_id;
+ data.border = border_id;
+ data.protection = cell_protection_id;
+ data.ver_align = ver_alignment;
+ data.wrap_text = wrap_text;
+ data.shrink_to_fit = shrink_to_fit;
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_style_context.hpp b/src/liborcus/odf_style_context.hpp
new file mode 100644
index 0000000..4a33948
--- /dev/null
+++ b/src/liborcus/odf_style_context.hpp
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "xml_context_base.hpp"
+#include "odf_styles.hpp"
+
+#include <memory>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+ class import_styles;
+}}
+
+/**
+ * Context for <style:style> element scope.
+ *
+ * This context populates one odf_style instance that represents a single set
+ * of style properties.
+ */
+class style_context : public xml_context_base
+{
+public:
+ style_context(session_context& session_cxt, const tokens& tk, spreadsheet::iface::import_styles* iface_styles);
+
+ void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+ void characters(std::string_view str, bool transient) override;
+ bool end_element(xmlns_id_t ns, xml_token_t name) override;
+
+ void reset();
+ std::unique_ptr<odf_style> pop_style();
+
+private:
+ void start_paragraph_properties(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void start_text_properties(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void start_table_cell_properties(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+
+private:
+ spreadsheet::iface::import_styles* mp_styles = nullptr;
+ std::unique_ptr<odf_style> m_current_style;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_styles.cpp b/src/liborcus/odf_styles.cpp
new file mode 100644
index 0000000..814d468
--- /dev/null
+++ b/src/liborcus/odf_styles.cpp
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "odf_styles.hpp"
+
+#include <stdexcept>
+
+namespace orcus {
+
+odf_style::odf_style() : family(style_family_unknown) {}
+odf_style::odf_style(std::string_view _name, std::string_view _display_name, odf_style_family _family, std::string_view parent) :
+ name(_name),
+ display_name(_display_name),
+ family(_family),
+ parent_name(parent)
+{
+ switch (family)
+ {
+ case style_family_table_column:
+ data = column{};
+ break;
+ case style_family_table_row:
+ data = row{};
+ break;
+ case style_family_table_cell:
+ data = cell{};
+ break;
+ case style_family_table:
+ data = table{};
+ break;
+ case style_family_graphic:
+ data = graphic{};
+ break;
+ case style_family_paragraph:
+ data = paragraph{};
+ break;
+ case style_family_text:
+ data = text{};
+ break;
+ case style_family_unknown:
+ throw std::invalid_argument("unkown style family is not allowed");
+ }
+}
+
+odf_style::~odf_style() {}
+
+odf_number_format::odf_number_format(std::string_view _name, bool _is_volatile):
+ name(_name),
+ is_volatile(_is_volatile)
+{
+}
+
+void merge(odf_styles_map_type& dst, odf_styles_map_type& src)
+{
+ for (auto& [name, style] : src)
+ dst.insert_or_assign(name, std::move(style));
+
+ src.clear();
+}
+
+void dump_state(const odf_styles_map_type& styles_map, std::ostream& os)
+{
+ os << "styles picked up:\n";
+
+ auto it = styles_map.begin(), it_end = styles_map.end();
+ for (; it != it_end; ++it)
+ {
+ os << " style: " << it->first << " [ ";
+
+ switch (it->second->family)
+ {
+ case style_family_table_column:
+ {
+ const auto& data = std::get<odf_style::column>(it->second->data);
+ os << "column width: " << data.width.to_string();
+ break;
+ }
+ case style_family_table_row:
+ {
+ const auto& data = std::get<odf_style::row>(it->second->data);
+ os << "row height: " << data.height.to_string();
+ break;
+ }
+ case style_family_table_cell:
+ {
+ const auto& cell = std::get<odf_style::cell>(it->second->data);
+ os << "xf ID: " << cell.xf;
+ break;
+ }
+ case style_family_text:
+ {
+ const auto& data = std::get<odf_style::text>(it->second->data);
+ os << "font ID: " << data.font;
+ break;
+ }
+ default:
+ ;
+ }
+
+ os << " ]\n";
+ }
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_styles.hpp b/src/liborcus/odf_styles.hpp
new file mode 100644
index 0000000..c4e5eaf
--- /dev/null
+++ b/src/liborcus/odf_styles.hpp
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_ODF_STYLES_HPP
+#define INCLUDED_ORCUS_ODF_STYLES_HPP
+
+#include <orcus/measurement.hpp>
+#include <orcus/spreadsheet/types.hpp>
+
+#include <map>
+#include <memory>
+#include <variant>
+#include <ostream>
+#include <optional>
+
+namespace orcus {
+
+enum odf_style_family
+{
+ style_family_unknown = 0,
+ style_family_table_column,
+ style_family_table_row,
+ style_family_table_cell,
+ style_family_table,
+ style_family_graphic,
+ style_family_paragraph,
+ style_family_text
+};
+
+/**
+ * Each instance of this class represents a single <style:style> entry.
+ */
+struct odf_style
+{
+ struct column
+ {
+ length_t width;
+ };
+
+ struct row
+ {
+ length_t height;
+ bool height_set = false;
+ };
+
+ struct cell
+ {
+ std::size_t font = 0;
+ std::size_t fill = 0;
+ std::size_t border = 0;
+ std::size_t protection = 0;
+ std::size_t xf = 0;
+ std::size_t number_format = 0;
+ spreadsheet::hor_alignment_t hor_align = spreadsheet::hor_alignment_t::unknown;
+ spreadsheet::ver_alignment_t ver_align = spreadsheet::ver_alignment_t::unknown;
+ std::optional<bool> wrap_text;
+ std::optional<bool> shrink_to_fit;
+ };
+
+ struct table
+ {
+ };
+
+ struct graphic
+ {
+ };
+
+ struct paragraph
+ {
+ spreadsheet::hor_alignment_t hor_align = spreadsheet::hor_alignment_t::unknown;
+ };
+
+ struct text
+ {
+ size_t font;
+ };
+
+ using data_type = std::variant<column, row, cell, table, graphic, paragraph, text>;
+
+ std::string_view name;
+ std::string_view display_name;
+ odf_style_family family;
+ std::string_view parent_name;
+
+ data_type data;
+
+ odf_style(const odf_style&) = delete;
+ odf_style& operator=(const odf_style&) = delete;
+
+ odf_style();
+ odf_style(std::string_view _name, std::string_view _display_name, odf_style_family _family, std::string_view parent);
+
+ ~odf_style();
+};
+
+struct odf_number_format
+{
+ std::string_view name;
+ std::string code;
+ bool is_volatile = false;
+
+ odf_number_format() = default;
+ odf_number_format(std::string_view _name, bool _is_volatile);
+};
+
+using odf_styles_map_type = std::map<std::string_view, std::unique_ptr<odf_style>>;
+
+/**
+ * Merge two styles collections into one.
+ *
+ * @param dst destination where all the styles will be stored when the call
+ * returns.
+ * @param src source collection to move all the styles from. After the call
+ * returns this one will be empty.
+ */
+void merge(odf_styles_map_type& dst, odf_styles_map_type& src);
+
+void dump_state(const odf_styles_map_type& styles_map, std::ostream& os);
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_styles_context.cpp b/src/liborcus/odf_styles_context.cpp
new file mode 100644
index 0000000..cf2589d
--- /dev/null
+++ b/src/liborcus/odf_styles_context.cpp
@@ -0,0 +1,403 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "odf_styles_context.hpp"
+#include "odf_namespace_types.hpp"
+#include "odf_token_constants.hpp"
+#include "ods_session_data.hpp"
+#include "impl_utils.hpp"
+
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+#include <iostream>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+styles_context::styles_context(
+ session_context& session_cxt, const tokens& tk,
+ spreadsheet::iface::import_styles* iface_styles) :
+ xml_context_base(session_cxt, tk),
+ mp_styles(iface_styles),
+ m_automatic_styles(false),
+ m_cxt_style(session_cxt, tk, mp_styles),
+ m_cxt_number_style(session_cxt, tk),
+ m_cxt_currency_style(session_cxt, tk),
+ m_cxt_boolean_style(session_cxt, tk),
+ m_cxt_text_style(session_cxt, tk),
+ m_cxt_percentage_style(session_cxt, tk),
+ m_cxt_date_style(session_cxt, tk),
+ m_cxt_time_style(session_cxt, tk)
+{
+ register_child(&m_cxt_style);
+ register_child(&m_cxt_number_style);
+ register_child(&m_cxt_currency_style);
+ register_child(&m_cxt_boolean_style);
+ register_child(&m_cxt_text_style);
+ register_child(&m_cxt_percentage_style);
+ register_child(&m_cxt_date_style);
+ register_child(&m_cxt_time_style);
+
+ commit_default_styles();
+}
+
+xml_context_base* styles_context::create_child_context(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_number_style:
+ {
+ m_cxt_number_style.reset();
+ return &m_cxt_number_style;
+ }
+ case XML_currency_style:
+ {
+ m_cxt_currency_style.reset();
+ return &m_cxt_currency_style;
+ }
+ case XML_boolean_style:
+ {
+ m_cxt_boolean_style.reset();
+ return &m_cxt_boolean_style;
+ }
+ case XML_text_style:
+ {
+ m_cxt_text_style.reset();
+ return &m_cxt_text_style;
+ }
+ case XML_percentage_style:
+ {
+ m_cxt_percentage_style.reset();
+ return &m_cxt_percentage_style;
+ }
+ case XML_date_style:
+ {
+ m_cxt_date_style.reset();
+ return &m_cxt_date_style;
+ }
+ case XML_time_style:
+ {
+ m_cxt_time_style.reset();
+ return &m_cxt_time_style;
+ }
+ }
+ }
+
+ if (ns == NS_odf_style && name == XML_style)
+ {
+ m_cxt_style.reset();
+ return &m_cxt_style;
+ }
+
+ return nullptr;
+}
+
+void styles_context::end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child)
+{
+ if (ns == NS_odf_number)
+ {
+ switch (name)
+ {
+ case XML_number_style:
+ {
+ assert(child == &m_cxt_number_style);
+ push_number_style(m_cxt_number_style.pop_style());
+ break;
+ }
+ case XML_currency_style:
+ {
+ assert(child == &m_cxt_currency_style);
+ push_number_style(m_cxt_currency_style.pop_style());
+ break;
+ }
+ case XML_boolean_style:
+ {
+ assert(child == &m_cxt_boolean_style);
+ push_number_style(m_cxt_boolean_style.pop_style());
+ break;
+ }
+ case XML_text_style:
+ {
+ assert(child == &m_cxt_text_style);
+ push_number_style(m_cxt_text_style.pop_style());
+ break;
+ }
+ case XML_percentage_style:
+ {
+ assert(child == &m_cxt_percentage_style);
+ push_number_style(m_cxt_percentage_style.pop_style());
+ break;
+ }
+ case XML_date_style:
+ {
+ assert(child == &m_cxt_date_style);
+ push_number_style(m_cxt_date_style.pop_style());
+ break;
+ }
+ case XML_time_style:
+ {
+ assert(child == &m_cxt_time_style);
+ push_number_style(m_cxt_time_style.pop_style());
+ break;
+ }
+ default:;
+ }
+ }
+ else if (ns == NS_odf_style && name == XML_style)
+ {
+ assert(child == &m_cxt_style);
+ std::unique_ptr<odf_style> current_style = m_cxt_style.pop_style();
+
+ std::optional<std::size_t> parent_xfid = query_parent_style_xfid(current_style->parent_name);
+
+ if (mp_styles && current_style->family == style_family_table_cell)
+ {
+ auto& cell = std::get<odf_style::cell>(current_style->data);
+
+ if (m_automatic_styles)
+ {
+ // Import it into the direct cell style store
+ auto* xf = mp_styles->start_xf(ss::xf_category_t::cell);
+ ENSURE_INTERFACE(xf, import_xf);
+ xf->set_font(cell.font);
+ xf->set_fill(cell.fill);
+ xf->set_border(cell.border);
+ xf->set_protection(cell.protection);
+ xf->set_number_format(cell.number_format);
+
+ if (cell.hor_align != ss::hor_alignment_t::unknown)
+ xf->set_horizontal_alignment(cell.hor_align);
+ if (cell.ver_align != ss::ver_alignment_t::unknown)
+ xf->set_vertical_alignment(cell.ver_align);
+ if (cell.wrap_text)
+ xf->set_wrap_text(*cell.wrap_text);
+ if (cell.shrink_to_fit)
+ xf->set_shrink_to_fit(*cell.shrink_to_fit);
+
+ if (parent_xfid)
+ xf->set_style_xf(*parent_xfid);
+
+ cell.xf = xf->commit();
+ }
+ else
+ {
+ // Import it into the cell style xf store, and reference
+ // its index in the cell style name store.
+ auto* xf = mp_styles->start_xf(ss::xf_category_t::cell_style);
+ ENSURE_INTERFACE(xf, import_xf);
+ xf->set_font(cell.font);
+ xf->set_fill(cell.fill);
+ xf->set_border(cell.border);
+ xf->set_protection(cell.protection);
+ xf->set_number_format(cell.number_format);
+
+ if (cell.hor_align != ss::hor_alignment_t::unknown)
+ xf->set_horizontal_alignment(cell.hor_align);
+ if (cell.ver_align != ss::ver_alignment_t::unknown)
+ xf->set_vertical_alignment(cell.ver_align);
+ if (cell.wrap_text)
+ xf->set_wrap_text(*cell.wrap_text);
+ if (cell.shrink_to_fit)
+ xf->set_shrink_to_fit(*cell.shrink_to_fit);
+
+ if (parent_xfid)
+ xf->set_style_xf(*parent_xfid);
+
+ size_t style_xf_id = xf->commit();
+ cell.xf = style_xf_id;
+
+ auto* cell_style = mp_styles->start_cell_style();
+ ENSURE_INTERFACE(cell_style, import_cell_style);
+
+ if (!current_style->display_name.empty())
+ cell_style->set_display_name(current_style->display_name);
+
+ cell_style->set_name(current_style->name);
+ cell_style->set_xf(style_xf_id);
+ cell_style->set_parent_name(current_style->parent_name);
+ cell_style->commit();
+ }
+ }
+
+ std::string_view style_name = get_session_context().intern(current_style->name);
+ m_styles.emplace(style_name, std::move(current_style));
+ }
+}
+
+void styles_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& /*attrs*/)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ if (ns == NS_odf_office)
+ {
+ switch (name)
+ {
+ case XML_automatic_styles:
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ m_automatic_styles = true;
+ break;
+ case XML_styles:
+ m_automatic_styles = false;
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool styles_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ return pop_stack(ns, name);
+}
+
+void styles_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+void styles_context::reset()
+{
+ m_styles.clear();
+}
+
+odf_styles_map_type styles_context::pop_styles()
+{
+ return std::move(m_styles);
+}
+
+void styles_context::commit_default_styles()
+{
+ if (!mp_styles)
+ return;
+
+ auto* font_style = mp_styles->start_font_style();
+ ENSURE_INTERFACE(font_style, import_font_style);
+
+ auto* fill_style = mp_styles->start_fill_style();
+ ENSURE_INTERFACE(fill_style, import_fill_style);
+
+ auto* border_style = mp_styles->start_border_style();
+ ENSURE_INTERFACE(border_style, import_border_style);
+
+ auto* cell_protection = mp_styles->start_cell_protection();
+ ENSURE_INTERFACE(cell_protection, import_cell_protection);
+
+ auto* number_format = mp_styles->start_number_format();
+ ENSURE_INTERFACE(number_format, import_number_format);
+
+ // Set default styles. Default styles must be associated with an index of 0.
+ // Set empty styles for all style types before importing real styles.
+ font_style->commit();
+ fill_style->commit();
+ border_style->commit();
+ cell_protection->commit();
+ number_format->commit();
+
+ auto* xf = mp_styles->start_xf(ss::xf_category_t::cell);
+ ENSURE_INTERFACE(xf, import_xf);
+ xf->commit();
+
+ xf = mp_styles->start_xf(ss::xf_category_t::cell_style);
+ ENSURE_INTERFACE(xf, import_xf);
+ xf->commit();
+
+ auto* cell_style = mp_styles->start_cell_style();
+ ENSURE_INTERFACE(cell_style, import_cell_style);
+ cell_style->commit();
+}
+
+void styles_context::push_number_style(std::unique_ptr<odf_number_format> num_style)
+{
+ if (!mp_styles)
+ return;
+
+ if (num_style->name.empty())
+ {
+ warn("ignoring a number style with empty name.");
+ return;
+ }
+
+ if (num_style->code.empty())
+ {
+ std::ostringstream os;
+ os << "number style named '" << num_style->name << "' has empty code.";
+ warn(os.str());
+ return;
+ }
+
+ auto* number_format = mp_styles->start_number_format();
+ ENSURE_INTERFACE(number_format, import_number_format);
+
+ number_format->set_code(num_style->code);
+ std::size_t id = number_format->commit();
+
+ if (get_config().debug)
+ {
+ std::cerr << "number-style: name='" << num_style->name
+ << "'; code='" << num_style->code
+ << "'; id=" << id << std::endl;
+ }
+
+ auto& sess_cxt = get_session_context();
+ auto& numfmts_store = sess_cxt.get_data<ods_session_data>().number_formats;
+
+ if (auto res = numfmts_store.name2id_map.insert_or_assign(sess_cxt.intern(num_style->name), id); !res.second)
+ {
+ std::ostringstream os;
+ os << "number style named '" << num_style->name << "' has been overwritten.";
+ warn(os.str());
+ }
+
+ if (auto res = numfmts_store.id2code_map.insert_or_assign(id, std::move(num_style->code)); !res.second)
+ {
+ std::ostringstream os;
+ os << "number style associated with the id of " << id << " has been overwritten.";
+ warn(os.str());
+ }
+}
+
+std::optional<std::size_t> styles_context::query_parent_style_xfid(std::string_view parent_name) const
+{
+ std::optional<std::size_t> parent_xfid;
+
+ if (parent_name.empty())
+ return parent_xfid;
+
+ const ods_session_data& ods_data = get_session_context().get_data<ods_session_data>();
+
+ auto it = ods_data.styles_map.find(parent_name);
+ if (it == ods_data.styles_map.end())
+ {
+ // Not found in the session store. Check the current styles map too.
+ auto it2 = m_styles.find(parent_name);
+ if (it2 != m_styles.end())
+ {
+ const odf_style& s = *it2->second;
+ if (s.family == style_family_table_cell)
+ {
+ const odf_style::cell& c = std::get<odf_style::cell>(s.data);
+ parent_xfid = c.xf;
+ }
+ }
+ return parent_xfid;
+ }
+
+ const odf_style& s = *it->second;
+ if (s.family != style_family_table_cell)
+ return parent_xfid;
+
+ const odf_style::cell& c = std::get<odf_style::cell>(s.data);
+ parent_xfid = c.xf;
+
+ return parent_xfid;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_styles_context.hpp b/src/liborcus/odf_styles_context.hpp
new file mode 100644
index 0000000..01b2ac4
--- /dev/null
+++ b/src/liborcus/odf_styles_context.hpp
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_ODF_STYLES_CONTEXT_HPP
+#define ORCUS_ODF_STYLES_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "odf_styles.hpp"
+#include "odf_style_context.hpp"
+#include "odf_number_format_context.hpp"
+
+#include <unordered_map>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+ class import_styles;
+}}
+
+/**
+ * Context that handles <office:automatic-styles> or <office:styles> scope.
+ */
+class styles_context : public xml_context_base
+{
+public:
+ styles_context(
+ session_context& session_cxt, const tokens& tk, spreadsheet::iface::import_styles* iface_styles);
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name) override;
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child) override;
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs) override;
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ virtual void characters(std::string_view str, bool transient) override;
+
+ void reset();
+ odf_styles_map_type pop_styles();
+
+private:
+ void commit_default_styles();
+
+ void push_number_style(std::unique_ptr<odf_number_format> num_style);
+
+ std::optional<std::size_t> query_parent_style_xfid(std::string_view parent_name) const;
+
+private:
+ spreadsheet::iface::import_styles* mp_styles;
+ odf_styles_map_type m_styles;
+
+ // an automatic style corresponds to a cell format and not a real style
+ bool m_automatic_styles;
+
+ style_context m_cxt_style;
+ number_style_context m_cxt_number_style;
+ currency_style_context m_cxt_currency_style;
+ boolean_style_context m_cxt_boolean_style;
+ text_style_context m_cxt_text_style;
+ percentage_style_context m_cxt_percentage_style;
+ date_style_context m_cxt_date_style;
+ time_style_context m_cxt_time_style;
+};
+
+} // namespace orcus
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_token_constants.hpp b/src/liborcus/odf_token_constants.hpp
new file mode 100644
index 0000000..71cf64b
--- /dev/null
+++ b/src/liborcus/odf_token_constants.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_ODF_TOKEN_CONSTANTS_HPP__
+#define __ORCUS_ODF_TOKEN_CONSTANTS_HPP__
+
+#include "orcus/types.hpp"
+
+namespace orcus {
+
+#include "odf_token_constants.inl"
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_token_constants.inl b/src/liborcus/odf_token_constants.inl
new file mode 100644
index 0000000..868e465
--- /dev/null
+++ b/src/liborcus/odf_token_constants.inl
@@ -0,0 +1,2280 @@
+// This file has been auto-generated. Do not hand-edit this.
+
+const xml_token_t XML_0 = 1;
+const xml_token_t XML_0deg = 2;
+const xml_token_t XML_0grad = 3;
+const xml_token_t XML_0rad = 4;
+const xml_token_t XML_1 = 5;
+const xml_token_t XML_1_3 = 6;
+const xml_token_t XML_100 = 7;
+const xml_token_t XML_2 = 8;
+const xml_token_t XML_200 = 9;
+const xml_token_t XML_3 = 10;
+const xml_token_t XML_300 = 11;
+const xml_token_t XML_3d = 12;
+const xml_token_t XML_400 = 13;
+const xml_token_t XML_500 = 14;
+const xml_token_t XML_600 = 15;
+const xml_token_t XML_700 = 16;
+const xml_token_t XML_800 = 17;
+const xml_token_t XML_900 = 18;
+const xml_token_t XML_A = 19;
+const xml_token_t XML_I = 20;
+const xml_token_t XML_ROC = 21;
+const xml_token_t XML__blank = 22;
+const xml_token_t XML__parent = 23;
+const xml_token_t XML__self = 24;
+const xml_token_t XML__top = 25;
+const xml_token_t XML_a = 26;
+const xml_token_t XML_about = 27;
+const xml_token_t XML_above = 28;
+const xml_token_t XML_accelerate = 29;
+const xml_token_t XML_accent = 30;
+const xml_token_t XML_accent_height = 31;
+const xml_token_t XML_acceptance_state = 32;
+const xml_token_t XML_accepted = 33;
+const xml_token_t XML_accumulate = 34;
+const xml_token_t XML_action = 35;
+const xml_token_t XML_active = 36;
+const xml_token_t XML_actuate = 37;
+const xml_token_t XML_add_empty_lines = 38;
+const xml_token_t XML_additional_column_statement = 39;
+const xml_token_t XML_additive = 40;
+const xml_token_t XML_address = 41;
+const xml_token_t XML_adjustment = 42;
+const xml_token_t XML_after_previous = 43;
+const xml_token_t XML_algorithm = 44;
+const xml_token_t XML_align = 45;
+const xml_token_t XML_all = 46;
+const xml_token_t XML_allow_deletes = 47;
+const xml_token_t XML_allow_empty_cell = 48;
+const xml_token_t XML_allow_inserts = 49;
+const xml_token_t XML_allow_updates = 50;
+const xml_token_t XML_alpha_numeric = 51;
+const xml_token_t XML_alphabetic = 52;
+const xml_token_t XML_alphabetical_index = 53;
+const xml_token_t XML_alphabetical_index_auto_mark_file = 54;
+const xml_token_t XML_alphabetical_index_entry_template = 55;
+const xml_token_t XML_alphabetical_index_mark = 56;
+const xml_token_t XML_alphabetical_index_mark_end = 57;
+const xml_token_t XML_alphabetical_index_mark_start = 58;
+const xml_token_t XML_alphabetical_index_source = 59;
+const xml_token_t XML_alphabetical_separators = 60;
+const xml_token_t XML_alternate = 61;
+const xml_token_t XML_always = 62;
+const xml_token_t XML_am_pm = 63;
+const xml_token_t XML_ambient_color = 64;
+const xml_token_t XML_anchor_page_number = 65;
+const xml_token_t XML_anchor_type = 66;
+const xml_token_t XML_angle = 67;
+const xml_token_t XML_angle_offset = 68;
+const xml_token_t XML_angled_connector_line = 69;
+const xml_token_t XML_angled_line = 70;
+const xml_token_t XML_anim = 71;
+const xml_token_t XML_animate = 72;
+const xml_token_t XML_animateColor = 73;
+const xml_token_t XML_animateMotion = 74;
+const xml_token_t XML_animateTransform = 75;
+const xml_token_t XML_animation = 76;
+const xml_token_t XML_animation_delay = 77;
+const xml_token_t XML_animation_direction = 78;
+const xml_token_t XML_animation_group = 79;
+const xml_token_t XML_animation_repeat = 80;
+const xml_token_t XML_animation_start_inside = 81;
+const xml_token_t XML_animation_steps = 82;
+const xml_token_t XML_animation_stop_inside = 83;
+const xml_token_t XML_animations = 84;
+const xml_token_t XML_annotation = 85;
+const xml_token_t XML_annotation_end = 86;
+const xml_token_t XML_annotations = 87;
+const xml_token_t XML_annote = 88;
+const xml_token_t XML_appear = 89;
+const xml_token_t XML_append_table_alias_name = 90;
+const xml_token_t XML_applet = 91;
+const xml_token_t XML_application_connection_settings = 92;
+const xml_token_t XML_application_data = 93;
+const xml_token_t XML_apply_command = 94;
+const xml_token_t XML_apply_design_mode = 95;
+const xml_token_t XML_apply_filter = 96;
+const xml_token_t XML_apply_style_name = 97;
+const xml_token_t XML_arc = 98;
+const xml_token_t XML_archive = 99;
+const xml_token_t XML_area = 100;
+const xml_token_t XML_area_circle = 101;
+const xml_token_t XML_area_polygon = 102;
+const xml_token_t XML_area_rectangle = 103;
+const xml_token_t XML_array = 104;
+const xml_token_t XML_arrow_down = 105;
+const xml_token_t XML_arrow_left = 106;
+const xml_token_t XML_arrow_right = 107;
+const xml_token_t XML_arrow_up = 108;
+const xml_token_t XML_article = 109;
+const xml_token_t XML_as_char = 110;
+const xml_token_t XML_as_template = 111;
+const xml_token_t XML_ascending = 112;
+const xml_token_t XML_ascent = 113;
+const xml_token_t XML_asian = 114;
+const xml_token_t XML_asterisk = 115;
+const xml_token_t XML_at_axis = 116;
+const xml_token_t XML_at_labels = 117;
+const xml_token_t XML_at_labels_and_axis = 118;
+const xml_token_t XML_attached_axis = 119;
+const xml_token_t XML_attractive = 120;
+const xml_token_t XML_attributeName = 121;
+const xml_token_t XML_audio = 122;
+const xml_token_t XML_audio_level = 123;
+const xml_token_t XML_author = 124;
+const xml_token_t XML_author_initials = 125;
+const xml_token_t XML_author_name = 126;
+const xml_token_t XML_auto = 127;
+const xml_token_t XML_auto_complete = 128;
+const xml_token_t XML_auto_create_new_frame = 129;
+const xml_token_t XML_auto_grow_height = 130;
+const xml_token_t XML_auto_grow_width = 131;
+const xml_token_t XML_auto_increment = 132;
+const xml_token_t XML_auto_position = 133;
+const xml_token_t XML_auto_reload = 134;
+const xml_token_t XML_auto_size = 135;
+const xml_token_t XML_auto_text_indent = 136;
+const xml_token_t XML_auto_update = 137;
+const xml_token_t XML_autoReverse = 138;
+const xml_token_t XML_automatic = 139;
+const xml_token_t XML_automatic_content = 140;
+const xml_token_t XML_automatic_find_labels = 141;
+const xml_token_t XML_automatic_focus = 142;
+const xml_token_t XML_automatic_order = 143;
+const xml_token_t XML_automatic_styles = 144;
+const xml_token_t XML_automatic_update = 145;
+const xml_token_t XML_average = 146;
+const xml_token_t XML_averaged_abscissa = 147;
+const xml_token_t XML_avoid_overlap = 148;
+const xml_token_t XML_axial = 149;
+const xml_token_t XML_axis = 150;
+const xml_token_t XML_axis_label_position = 151;
+const xml_token_t XML_axis_position = 152;
+const xml_token_t XML_b_spline = 153;
+const xml_token_t XML_back_scale = 154;
+const xml_token_t XML_backface_culling = 155;
+const xml_token_t XML_background = 156;
+const xml_token_t XML_background_color = 157;
+const xml_token_t XML_background_image = 158;
+const xml_token_t XML_background_objects_visible = 159;
+const xml_token_t XML_background_size = 160;
+const xml_token_t XML_background_transparency = 161;
+const xml_token_t XML_background_visible = 162;
+const xml_token_t XML_balanced = 163;
+const xml_token_t XML_base_cell_address = 164;
+const xml_token_t XML_base_dn = 165;
+const xml_token_t XML_base64Binary = 166;
+const xml_token_t XML_baseline = 167;
+const xml_token_t XML_bbox = 168;
+const xml_token_t XML_begin = 169;
+const xml_token_t XML_below = 170;
+const xml_token_t XML_bevel = 171;
+const xml_token_t XML_bibliography = 172;
+const xml_token_t XML_bibliography_configuration = 173;
+const xml_token_t XML_bibliography_data_field = 174;
+const xml_token_t XML_bibliography_entry_template = 175;
+const xml_token_t XML_bibliography_mark = 176;
+const xml_token_t XML_bibliography_source = 177;
+const xml_token_t XML_bibliography_type = 178;
+const xml_token_t XML_biggest = 179;
+const xml_token_t XML_bigint = 180;
+const xml_token_t XML_binary = 181;
+const xml_token_t XML_binary_data = 182;
+const xml_token_t XML_bind = 183;
+const xml_token_t XML_bind_styles_to_content = 184;
+const xml_token_t XML_bit = 185;
+const xml_token_t XML_bitmap = 186;
+const xml_token_t XML_blend = 187;
+const xml_token_t XML_blob = 188;
+const xml_token_t XML_blue = 189;
+const xml_token_t XML_body = 190;
+const xml_token_t XML_bold = 191;
+const xml_token_t XML_book = 192;
+const xml_token_t XML_booklet = 193;
+const xml_token_t XML_bookmark = 194;
+const xml_token_t XML_bookmark_end = 195;
+const xml_token_t XML_bookmark_start = 196;
+const xml_token_t XML_booktitle = 197;
+const xml_token_t XML_boolean = 198;
+const xml_token_t XML_boolean_comparison_mode = 199;
+const xml_token_t XML_boolean_style = 200;
+const xml_token_t XML_boolean_value = 201;
+const xml_token_t XML_border = 202;
+const xml_token_t XML_border_bottom = 203;
+const xml_token_t XML_border_color = 204;
+const xml_token_t XML_border_left = 205;
+const xml_token_t XML_border_line_width = 206;
+const xml_token_t XML_border_line_width_bottom = 207;
+const xml_token_t XML_border_line_width_left = 208;
+const xml_token_t XML_border_line_width_right = 209;
+const xml_token_t XML_border_line_width_top = 210;
+const xml_token_t XML_border_model = 211;
+const xml_token_t XML_border_right = 212;
+const xml_token_t XML_border_top = 213;
+const xml_token_t XML_both = 214;
+const xml_token_t XML_bottom = 215;
+const xml_token_t XML_bottom_end = 216;
+const xml_token_t XML_bottom_left = 217;
+const xml_token_t XML_bottom_right = 218;
+const xml_token_t XML_bottom_start = 219;
+const xml_token_t XML_bound_column = 220;
+const xml_token_t XML_bow_tie = 221;
+const xml_token_t XML_break_after = 222;
+const xml_token_t XML_break_before = 223;
+const xml_token_t XML_buddhist = 224;
+const xml_token_t XML_bullet_char = 225;
+const xml_token_t XML_bullet_relative_size = 226;
+const xml_token_t XML_butt = 227;
+const xml_token_t XML_button = 228;
+const xml_token_t XML_button_type = 229;
+const xml_token_t XML_buttons = 230;
+const xml_token_t XML_by = 231;
+const xml_token_t XML_c = 232;
+const xml_token_t XML_calcMode = 233;
+const xml_token_t XML_calculation_settings = 234;
+const xml_token_t XML_calendar = 235;
+const xml_token_t XML_cap_height = 236;
+const xml_token_t XML_capitalize = 237;
+const xml_token_t XML_capitalize_entries = 238;
+const xml_token_t XML_caption = 239;
+const xml_token_t XML_caption_angle = 240;
+const xml_token_t XML_caption_angle_type = 241;
+const xml_token_t XML_caption_escape = 242;
+const xml_token_t XML_caption_escape_direction = 243;
+const xml_token_t XML_caption_fit_line_length = 244;
+const xml_token_t XML_caption_gap = 245;
+const xml_token_t XML_caption_id = 246;
+const xml_token_t XML_caption_line_length = 247;
+const xml_token_t XML_caption_point_x = 248;
+const xml_token_t XML_caption_point_y = 249;
+const xml_token_t XML_caption_sequence_format = 250;
+const xml_token_t XML_caption_sequence_name = 251;
+const xml_token_t XML_caption_type = 252;
+const xml_token_t XML_cascade = 253;
+const xml_token_t XML_case_sensitive = 254;
+const xml_token_t XML_catalog_name = 255;
+const xml_token_t XML_categories = 256;
+const xml_token_t XML_category_and_value = 257;
+const xml_token_t XML_cell_address = 258;
+const xml_token_t XML_cell_content_change = 259;
+const xml_token_t XML_cell_content_deletion = 260;
+const xml_token_t XML_cell_count = 261;
+const xml_token_t XML_cell_protect = 262;
+const xml_token_t XML_cell_range = 263;
+const xml_token_t XML_cell_range_address = 264;
+const xml_token_t XML_cell_range_source = 265;
+const xml_token_t XML_center = 266;
+const xml_token_t XML_central = 267;
+const xml_token_t XML_chain_next_name = 268;
+const xml_token_t XML_change = 269;
+const xml_token_t XML_change_deletion = 270;
+const xml_token_t XML_change_end = 271;
+const xml_token_t XML_change_id = 272;
+const xml_token_t XML_change_info = 273;
+const xml_token_t XML_change_start = 274;
+const xml_token_t XML_change_track_table_cell = 275;
+const xml_token_t XML_changed_region = 276;
+const xml_token_t XML_chapter = 277;
+const xml_token_t XML_char = 278;
+const xml_token_t XML_character_count = 279;
+const xml_token_t XML_character_set = 280;
+const xml_token_t XML_chart = 281;
+const xml_token_t XML_chart_properties = 282;
+const xml_token_t XML_charts = 283;
+const xml_token_t XML_checkbox = 284;
+const xml_token_t XML_checked = 285;
+const xml_token_t XML_checkerboard = 286;
+const xml_token_t XML_circle = 287;
+const xml_token_t XML_citation_body_style_name = 288;
+const xml_token_t XML_citation_style_name = 289;
+const xml_token_t XML_class = 290;
+const xml_token_t XML_class_id = 291;
+const xml_token_t XML_class_names = 292;
+const xml_token_t XML_clip = 293;
+const xml_token_t XML_clob = 294;
+const xml_token_t XML_clockwise = 295;
+const xml_token_t XML_close = 296;
+const xml_token_t XML_close_back = 297;
+const xml_token_t XML_close_front = 298;
+const xml_token_t XML_close_horizontal = 299;
+const xml_token_t XML_close_vertical = 300;
+const xml_token_t XML_cm = 301;
+const xml_token_t XML_code = 302;
+const xml_token_t XML_collapse = 303;
+const xml_token_t XML_collapsing = 304;
+const xml_token_t XML_color = 305;
+const xml_token_t XML_color_interpolation = 306;
+const xml_token_t XML_color_interpolation_direction = 307;
+const xml_token_t XML_color_inversion = 308;
+const xml_token_t XML_color_mode = 309;
+const xml_token_t XML_column = 310;
+const xml_token_t XML_column_count = 311;
+const xml_token_t XML_column_definition = 312;
+const xml_token_t XML_column_definitions = 313;
+const xml_token_t XML_column_gap = 314;
+const xml_token_t XML_column_mapping = 315;
+const xml_token_t XML_column_name = 316;
+const xml_token_t XML_column_percentage = 317;
+const xml_token_t XML_column_sep = 318;
+const xml_token_t XML_column_width = 319;
+const xml_token_t XML_columns = 320;
+const xml_token_t XML_combine_entries = 321;
+const xml_token_t XML_combine_entries_with_dash = 322;
+const xml_token_t XML_combine_entries_with_pp = 323;
+const xml_token_t XML_combobox = 324;
+const xml_token_t XML_comma_separated = 325;
+const xml_token_t XML_command = 326;
+const xml_token_t XML_command_type = 327;
+const xml_token_t XML_comment = 328;
+const xml_token_t XML_complex = 329;
+const xml_token_t XML_component = 330;
+const xml_token_t XML_component_collection = 331;
+const xml_token_t XML_concave = 332;
+const xml_token_t XML_concentric_gradient_fill_allowed = 333;
+const xml_token_t XML_cond_style_name = 334;
+const xml_token_t XML_condensed = 335;
+const xml_token_t XML_condition = 336;
+const xml_token_t XML_condition_source = 337;
+const xml_token_t XML_condition_source_range_address = 338;
+const xml_token_t XML_conditional_text = 339;
+const xml_token_t XML_cone = 340;
+const xml_token_t XML_conference = 341;
+const xml_token_t XML_config = 342;
+const xml_token_t XML_config_item = 343;
+const xml_token_t XML_config_item_map_entry = 344;
+const xml_token_t XML_config_item_map_indexed = 345;
+const xml_token_t XML_config_item_map_named = 346;
+const xml_token_t XML_config_item_set = 347;
+const xml_token_t XML_connect_bars = 348;
+const xml_token_t XML_connection_data = 349;
+const xml_token_t XML_connection_name = 350;
+const xml_token_t XML_connection_resource = 351;
+const xml_token_t XML_connector = 352;
+const xml_token_t XML_consecutive_numbering = 353;
+const xml_token_t XML_consolidation = 354;
+const xml_token_t XML_constant = 355;
+const xml_token_t XML_contains_error = 356;
+const xml_token_t XML_contains_header = 357;
+const xml_token_t XML_content = 358;
+const xml_token_t XML_content_validation = 359;
+const xml_token_t XML_content_validation_name = 360;
+const xml_token_t XML_content_validations = 361;
+const xml_token_t XML_contextual_spacing = 362;
+const xml_token_t XML_continue = 363;
+const xml_token_t XML_continue_list = 364;
+const xml_token_t XML_continue_numbering = 365;
+const xml_token_t XML_continuous = 366;
+const xml_token_t XML_contour_path = 367;
+const xml_token_t XML_contour_polygon = 368;
+const xml_token_t XML_contrast = 369;
+const xml_token_t XML_control = 370;
+const xml_token_t XML_control_implementation = 371;
+const xml_token_t XML_conversion_mode = 372;
+const xml_token_t XML_convert_empty_to_null = 373;
+const xml_token_t XML_coordinate_region = 374;
+const xml_token_t XML_copy_all = 375;
+const xml_token_t XML_copy_back = 376;
+const xml_token_t XML_copy_formulas = 377;
+const xml_token_t XML_copy_of = 378;
+const xml_token_t XML_copy_outline_levels = 379;
+const xml_token_t XML_copy_results_only = 380;
+const xml_token_t XML_copy_styles = 381;
+const xml_token_t XML_corner_radius = 382;
+const xml_token_t XML_corners = 383;
+const xml_token_t XML_correct = 384;
+const xml_token_t XML_count = 385;
+const xml_token_t XML_count_empty_lines = 386;
+const xml_token_t XML_count_in_text_boxes = 387;
+const xml_token_t XML_counter_clockwise = 388;
+const xml_token_t XML_counterclockwise = 389;
+const xml_token_t XML_countnums = 390;
+const xml_token_t XML_country = 391;
+const xml_token_t XML_country_asian = 392;
+const xml_token_t XML_country_complex = 393;
+const xml_token_t XML_covered_table_cell = 394;
+const xml_token_t XML_creation_date = 395;
+const xml_token_t XML_creation_time = 396;
+const xml_token_t XML_creator = 397;
+const xml_token_t XML_creator_initials = 398;
+const xml_token_t XML_cube = 399;
+const xml_token_t XML_cubic_spline = 400;
+const xml_token_t XML_cuboid = 401;
+const xml_token_t XML_currency = 402;
+const xml_token_t XML_currency_style = 403;
+const xml_token_t XML_currency_symbol = 404;
+const xml_token_t XML_current = 405;
+const xml_token_t XML_current_date = 406;
+const xml_token_t XML_current_selected = 407;
+const xml_token_t XML_current_state = 408;
+const xml_token_t XML_current_value = 409;
+const xml_token_t XML_curve = 410;
+const xml_token_t XML_custom = 411;
+const xml_token_t XML_custom_shape = 412;
+const xml_token_t XML_custom1 = 413;
+const xml_token_t XML_custom2 = 414;
+const xml_token_t XML_custom3 = 415;
+const xml_token_t XML_custom4 = 416;
+const xml_token_t XML_custom5 = 417;
+const xml_token_t XML_cut = 418;
+const xml_token_t XML_cut_offs = 419;
+const xml_token_t XML_cx = 420;
+const xml_token_t XML_cy = 421;
+const xml_token_t XML_cylinder = 422;
+const xml_token_t XML_d = 423;
+const xml_token_t XML_dash = 424;
+const xml_token_t XML_dashed = 425;
+const xml_token_t XML_data = 426;
+const xml_token_t XML_data_cell_range_address = 427;
+const xml_token_t XML_data_field = 428;
+const xml_token_t XML_data_label = 429;
+const xml_token_t XML_data_label_number = 430;
+const xml_token_t XML_data_label_series = 431;
+const xml_token_t XML_data_label_symbol = 432;
+const xml_token_t XML_data_label_text = 433;
+const xml_token_t XML_data_pilot_display_info = 434;
+const xml_token_t XML_data_pilot_field = 435;
+const xml_token_t XML_data_pilot_field_reference = 436;
+const xml_token_t XML_data_pilot_group = 437;
+const xml_token_t XML_data_pilot_group_member = 438;
+const xml_token_t XML_data_pilot_groups = 439;
+const xml_token_t XML_data_pilot_layout_info = 440;
+const xml_token_t XML_data_pilot_level = 441;
+const xml_token_t XML_data_pilot_member = 442;
+const xml_token_t XML_data_pilot_members = 443;
+const xml_token_t XML_data_pilot_sort_info = 444;
+const xml_token_t XML_data_pilot_subtotal = 445;
+const xml_token_t XML_data_pilot_subtotals = 446;
+const xml_token_t XML_data_pilot_table = 447;
+const xml_token_t XML_data_pilot_tables = 448;
+const xml_token_t XML_data_point = 449;
+const xml_token_t XML_data_source = 450;
+const xml_token_t XML_data_source_has_labels = 451;
+const xml_token_t XML_data_source_setting = 452;
+const xml_token_t XML_data_source_setting_is_list = 453;
+const xml_token_t XML_data_source_setting_name = 454;
+const xml_token_t XML_data_source_setting_type = 455;
+const xml_token_t XML_data_source_setting_value = 456;
+const xml_token_t XML_data_source_settings = 457;
+const xml_token_t XML_data_style_name = 458;
+const xml_token_t XML_data_type = 459;
+const xml_token_t XML_database = 460;
+const xml_token_t XML_database_description = 461;
+const xml_token_t XML_database_display = 462;
+const xml_token_t XML_database_name = 463;
+const xml_token_t XML_database_next = 464;
+const xml_token_t XML_database_range = 465;
+const xml_token_t XML_database_ranges = 466;
+const xml_token_t XML_database_row_number = 467;
+const xml_token_t XML_database_row_select = 468;
+const xml_token_t XML_database_source_query = 469;
+const xml_token_t XML_database_source_sql = 470;
+const xml_token_t XML_database_source_table = 471;
+const xml_token_t XML_database_table_name = 472;
+const xml_token_t XML_datasource = 473;
+const xml_token_t XML_datatype = 474;
+const xml_token_t XML_date = 475;
+const xml_token_t XML_date_adjust = 476;
+const xml_token_t XML_date_end = 477;
+const xml_token_t XML_date_start = 478;
+const xml_token_t XML_date_string = 479;
+const xml_token_t XML_date_style = 480;
+const xml_token_t XML_date_time = 481;
+const xml_token_t XML_date_time_decl = 482;
+const xml_token_t XML_date_value = 483;
+const xml_token_t XML_datetime = 484;
+const xml_token_t XML_day = 485;
+const xml_token_t XML_day_of_week = 486;
+const xml_token_t XML_days = 487;
+const xml_token_t XML_db = 488;
+const xml_token_t XML_dc = 489;
+const xml_token_t XML_dde_application = 490;
+const xml_token_t XML_dde_connection = 491;
+const xml_token_t XML_dde_connection_decl = 492;
+const xml_token_t XML_dde_connection_decls = 493;
+const xml_token_t XML_dde_item = 494;
+const xml_token_t XML_dde_link = 495;
+const xml_token_t XML_dde_links = 496;
+const xml_token_t XML_dde_source = 497;
+const xml_token_t XML_dde_topic = 498;
+const xml_token_t XML_decelerate = 499;
+const xml_token_t XML_decimal = 500;
+const xml_token_t XML_decimal_places = 501;
+const xml_token_t XML_decimal_replacement = 502;
+const xml_token_t XML_decorative = 503;
+const xml_token_t XML_deep = 504;
+const xml_token_t XML_default = 505;
+const xml_token_t XML_default_button = 506;
+const xml_token_t XML_default_cell_style_name = 507;
+const xml_token_t XML_default_outline_level = 508;
+const xml_token_t XML_default_page_layout = 509;
+const xml_token_t XML_default_row_style_name = 510;
+const xml_token_t XML_default_style = 511;
+const xml_token_t XML_default_style_name = 512;
+const xml_token_t XML_definition_src = 513;
+const xml_token_t XML_delay = 514;
+const xml_token_t XML_delay_for_repeat = 515;
+const xml_token_t XML_delete_rule = 516;
+const xml_token_t XML_deletion = 517;
+const xml_token_t XML_deletions = 518;
+const xml_token_t XML_delimiter = 519;
+const xml_token_t XML_denominator_value = 520;
+const xml_token_t XML_dependencies = 521;
+const xml_token_t XML_dependency = 522;
+const xml_token_t XML_depth = 523;
+const xml_token_t XML_desc = 524;
+const xml_token_t XML_descending = 525;
+const xml_token_t XML_descent = 526;
+const xml_token_t XML_description = 527;
+const xml_token_t XML_detail_fields = 528;
+const xml_token_t XML_detective = 529;
+const xml_token_t XML_diagonal_bl_tr = 530;
+const xml_token_t XML_diagonal_bl_tr_widths = 531;
+const xml_token_t XML_diagonal_tl_br = 532;
+const xml_token_t XML_diagonal_tl_br_widths = 533;
+const xml_token_t XML_diamond = 534;
+const xml_token_t XML_diffuse_color = 535;
+const xml_token_t XML_dim = 536;
+const xml_token_t XML_dimension = 537;
+const xml_token_t XML_direction = 538;
+const xml_token_t XML_disable = 539;
+const xml_token_t XML_disabled = 540;
+const xml_token_t XML_disc = 541;
+const xml_token_t XML_discrete = 542;
+const xml_token_t XML_display = 543;
+const xml_token_t XML_display_border = 544;
+const xml_token_t XML_display_date_time = 545;
+const xml_token_t XML_display_duplicates = 546;
+const xml_token_t XML_display_equation = 547;
+const xml_token_t XML_display_factor = 548;
+const xml_token_t XML_display_filter_buttons = 549;
+const xml_token_t XML_display_footer = 550;
+const xml_token_t XML_display_header = 551;
+const xml_token_t XML_display_label = 552;
+const xml_token_t XML_display_levels = 553;
+const xml_token_t XML_display_list = 554;
+const xml_token_t XML_display_member_mode = 555;
+const xml_token_t XML_display_name = 556;
+const xml_token_t XML_display_outline_level = 557;
+const xml_token_t XML_display_page_number = 558;
+const xml_token_t XML_display_r_square = 559;
+const xml_token_t XML_dissolve = 560;
+const xml_token_t XML_distance = 561;
+const xml_token_t XML_distance_after_sep = 562;
+const xml_token_t XML_distance_before_sep = 563;
+const xml_token_t XML_distinct = 564;
+const xml_token_t XML_distribute_letter = 565;
+const xml_token_t XML_distribute_space = 566;
+const xml_token_t XML_document = 567;
+const xml_token_t XML_document_content = 568;
+const xml_token_t XML_document_meta = 569;
+const xml_token_t XML_document_settings = 570;
+const xml_token_t XML_document_statistic = 571;
+const xml_token_t XML_document_styles = 572;
+const xml_token_t XML_domain = 573;
+const xml_token_t XML_dont_balance_text_columns = 574;
+const xml_token_t XML_dot = 575;
+const xml_token_t XML_dot_dash = 576;
+const xml_token_t XML_dot_dashed = 577;
+const xml_token_t XML_dot_dot_dash = 578;
+const xml_token_t XML_dots1 = 579;
+const xml_token_t XML_dots1_length = 580;
+const xml_token_t XML_dots2 = 581;
+const xml_token_t XML_dots2_length = 582;
+const xml_token_t XML_dotted = 583;
+const xml_token_t XML_double = 584;
+const xml_token_t XML_double_sided = 585;
+const xml_token_t XML_down = 586;
+const xml_token_t XML_dr3d = 587;
+const xml_token_t XML_draft = 588;
+const xml_token_t XML_draw = 589;
+const xml_token_t XML_draw_aspect = 590;
+const xml_token_t XML_draw_count = 591;
+const xml_token_t XML_drawing = 592;
+const xml_token_t XML_drawing_page = 593;
+const xml_token_t XML_drawing_page_properties = 594;
+const xml_token_t XML_drawings = 595;
+const xml_token_t XML_drill_down_on_double_click = 596;
+const xml_token_t XML_driver_settings = 597;
+const xml_token_t XML_drop_cap = 598;
+const xml_token_t XML_drop_down = 599;
+const xml_token_t XML_dropdown = 600;
+const xml_token_t XML_dur = 601;
+const xml_token_t XML_duration = 602;
+const xml_token_t XML_dynamic = 603;
+const xml_token_t XML_dynamic_spacing = 604;
+const xml_token_t XML_echo_char = 605;
+const xml_token_t XML_edge_rounding = 606;
+const xml_token_t XML_edge_rounding_mode = 607;
+const xml_token_t XML_editable = 608;
+const xml_token_t XML_editing_cycles = 609;
+const xml_token_t XML_editing_duration = 610;
+const xml_token_t XML_edition = 611;
+const xml_token_t XML_editor = 612;
+const xml_token_t XML_effect = 613;
+const xml_token_t XML_ellipse = 614;
+const xml_token_t XML_ellipsoid = 615;
+const xml_token_t XML_email = 616;
+const xml_token_t XML_embed = 617;
+const xml_token_t XML_embedded_number_behavior = 618;
+const xml_token_t XML_embedded_text = 619;
+const xml_token_t XML_embossed = 620;
+const xml_token_t XML_emissive_color = 621;
+const xml_token_t XML_emphasis = 622;
+const xml_token_t XML_enable = 623;
+const xml_token_t XML_enable_sql92_check = 624;
+const xml_token_t XML_enabled = 625;
+const xml_token_t XML_encoding = 626;
+const xml_token_t XML_enctype = 627;
+const xml_token_t XML_end = 628;
+const xml_token_t XML_end_angle = 629;
+const xml_token_t XML_end_cell_address = 630;
+const xml_token_t XML_end_color = 631;
+const xml_token_t XML_end_column = 632;
+const xml_token_t XML_end_glue_point = 633;
+const xml_token_t XML_end_guide = 634;
+const xml_token_t XML_end_indent = 635;
+const xml_token_t XML_end_intensity = 636;
+const xml_token_t XML_end_line_spacing_horizontal = 637;
+const xml_token_t XML_end_line_spacing_vertical = 638;
+const xml_token_t XML_end_position = 639;
+const xml_token_t XML_end_row = 640;
+const xml_token_t XML_end_shape = 641;
+const xml_token_t XML_end_table = 642;
+const xml_token_t XML_end_x = 643;
+const xml_token_t XML_end_y = 644;
+const xml_token_t XML_endless = 645;
+const xml_token_t XML_endnote = 646;
+const xml_token_t XML_endsync = 647;
+const xml_token_t XML_engine = 648;
+const xml_token_t XML_engraved = 649;
+const xml_token_t XML_enhanced_geometry = 650;
+const xml_token_t XML_enhanced_path = 651;
+const xml_token_t XML_entrance = 652;
+const xml_token_t XML_equal_boolean = 653;
+const xml_token_t XML_equal_integer = 654;
+const xml_token_t XML_equal_use_only_zero = 655;
+const xml_token_t XML_equation = 656;
+const xml_token_t XML_era = 657;
+const xml_token_t XML_error_category = 658;
+const xml_token_t XML_error_indicator = 659;
+const xml_token_t XML_error_lower_indicator = 660;
+const xml_token_t XML_error_lower_limit = 661;
+const xml_token_t XML_error_lower_range = 662;
+const xml_token_t XML_error_macro = 663;
+const xml_token_t XML_error_margin = 664;
+const xml_token_t XML_error_message = 665;
+const xml_token_t XML_error_percentage = 666;
+const xml_token_t XML_error_upper_indicator = 667;
+const xml_token_t XML_error_upper_limit = 668;
+const xml_token_t XML_error_upper_range = 669;
+const xml_token_t XML_escape_direction = 670;
+const xml_token_t XML_escape_processing = 671;
+const xml_token_t XML_even_columns = 672;
+const xml_token_t XML_even_rows = 673;
+const xml_token_t XML_evenodd = 674;
+const xml_token_t XML_event_listener = 675;
+const xml_token_t XML_event_listeners = 676;
+const xml_token_t XML_event_name = 677;
+const xml_token_t XML_execute = 678;
+const xml_token_t XML_execute_macro = 679;
+const xml_token_t XML_exit = 680;
+const xml_token_t XML_expanded = 681;
+const xml_token_t XML_exponent_interval = 682;
+const xml_token_t XML_exponential = 683;
+const xml_token_t XML_expression = 684;
+const xml_token_t XML_extension = 685;
+const xml_token_t XML_extra_condensed = 686;
+const xml_token_t XML_extra_expanded = 687;
+const xml_token_t XML_extrude = 688;
+const xml_token_t XML_extrusion = 689;
+const xml_token_t XML_extrusion_allowed = 690;
+const xml_token_t XML_extrusion_brightness = 691;
+const xml_token_t XML_extrusion_color = 692;
+const xml_token_t XML_extrusion_depth = 693;
+const xml_token_t XML_extrusion_diffusion = 694;
+const xml_token_t XML_extrusion_first_light_direction = 695;
+const xml_token_t XML_extrusion_first_light_harsh = 696;
+const xml_token_t XML_extrusion_first_light_level = 697;
+const xml_token_t XML_extrusion_light_face = 698;
+const xml_token_t XML_extrusion_metal = 699;
+const xml_token_t XML_extrusion_number_of_line_segments = 700;
+const xml_token_t XML_extrusion_origin = 701;
+const xml_token_t XML_extrusion_rotation_angle = 702;
+const xml_token_t XML_extrusion_rotation_center = 703;
+const xml_token_t XML_extrusion_second_light_direction = 704;
+const xml_token_t XML_extrusion_second_light_harsh = 705;
+const xml_token_t XML_extrusion_second_light_level = 706;
+const xml_token_t XML_extrusion_shininess = 707;
+const xml_token_t XML_extrusion_skew = 708;
+const xml_token_t XML_extrusion_specularity = 709;
+const xml_token_t XML_extrusion_viewpoint = 710;
+const xml_token_t XML_fade = 711;
+const xml_token_t XML_fade_from_bottom = 712;
+const xml_token_t XML_fade_from_center = 713;
+const xml_token_t XML_fade_from_left = 714;
+const xml_token_t XML_fade_from_lowerleft = 715;
+const xml_token_t XML_fade_from_lowerright = 716;
+const xml_token_t XML_fade_from_right = 717;
+const xml_token_t XML_fade_from_top = 718;
+const xml_token_t XML_fade_from_upperleft = 719;
+const xml_token_t XML_fade_from_upperright = 720;
+const xml_token_t XML_fade_out = 721;
+const xml_token_t XML_fade_to_center = 722;
+const xml_token_t XML_fadeColor = 723;
+const xml_token_t XML_false = 724;
+const xml_token_t XML_family = 725;
+const xml_token_t XML_fast = 726;
+const xml_token_t XML_field = 727;
+const xml_token_t XML_field_name = 728;
+const xml_token_t XML_field_number = 729;
+const xml_token_t XML_file = 730;
+const xml_token_t XML_file_based_database = 731;
+const xml_token_t XML_file_name = 732;
+const xml_token_t XML_fill = 733;
+const xml_token_t XML_fill_character = 734;
+const xml_token_t XML_fill_color = 735;
+const xml_token_t XML_fill_gradient_name = 736;
+const xml_token_t XML_fill_hatch_name = 737;
+const xml_token_t XML_fill_hatch_solid = 738;
+const xml_token_t XML_fill_image = 739;
+const xml_token_t XML_fill_image_height = 740;
+const xml_token_t XML_fill_image_name = 741;
+const xml_token_t XML_fill_image_ref_point = 742;
+const xml_token_t XML_fill_image_ref_point_x = 743;
+const xml_token_t XML_fill_image_ref_point_y = 744;
+const xml_token_t XML_fill_image_width = 745;
+const xml_token_t XML_fill_rule = 746;
+const xml_token_t XML_fillDefault = 747;
+const xml_token_t XML_filter = 748;
+const xml_token_t XML_filter_and = 749;
+const xml_token_t XML_filter_condition = 750;
+const xml_token_t XML_filter_name = 751;
+const xml_token_t XML_filter_options = 752;
+const xml_token_t XML_filter_or = 753;
+const xml_token_t XML_filter_set_item = 754;
+const xml_token_t XML_filter_statement = 755;
+const xml_token_t XML_first = 756;
+const xml_token_t XML_first_column = 757;
+const xml_token_t XML_first_page = 758;
+const xml_token_t XML_first_page_number = 759;
+const xml_token_t XML_first_row = 760;
+const xml_token_t XML_first_row_end_column = 761;
+const xml_token_t XML_first_row_start_column = 762;
+const xml_token_t XML_fit_to_contour = 763;
+const xml_token_t XML_fit_to_size = 764;
+const xml_token_t XML_fix = 765;
+const xml_token_t XML_fixed = 766;
+const xml_token_t XML_fixed_text = 767;
+const xml_token_t XML_flat = 768;
+const xml_token_t XML_float = 769;
+const xml_token_t XML_floating_frame = 770;
+const xml_token_t XML_floor = 771;
+const xml_token_t XML_flow_with_text = 772;
+const xml_token_t XML_fly_away = 773;
+const xml_token_t XML_fo = 774;
+const xml_token_t XML_focal_length = 775;
+const xml_token_t XML_focus_on_click = 776;
+const xml_token_t XML_font_adornments = 777;
+const xml_token_t XML_font_charset = 778;
+const xml_token_t XML_font_charset_asian = 779;
+const xml_token_t XML_font_charset_complex = 780;
+const xml_token_t XML_font_color = 781;
+const xml_token_t XML_font_face = 782;
+const xml_token_t XML_font_face_decls = 783;
+const xml_token_t XML_font_face_format = 784;
+const xml_token_t XML_font_face_name = 785;
+const xml_token_t XML_font_face_src = 786;
+const xml_token_t XML_font_face_uri = 787;
+const xml_token_t XML_font_family = 788;
+const xml_token_t XML_font_family_asian = 789;
+const xml_token_t XML_font_family_complex = 790;
+const xml_token_t XML_font_family_generic = 791;
+const xml_token_t XML_font_family_generic_asian = 792;
+const xml_token_t XML_font_family_generic_complex = 793;
+const xml_token_t XML_font_independent_line_spacing = 794;
+const xml_token_t XML_font_name = 795;
+const xml_token_t XML_font_name_asian = 796;
+const xml_token_t XML_font_name_complex = 797;
+const xml_token_t XML_font_pitch = 798;
+const xml_token_t XML_font_pitch_asian = 799;
+const xml_token_t XML_font_pitch_complex = 800;
+const xml_token_t XML_font_relief = 801;
+const xml_token_t XML_font_size = 802;
+const xml_token_t XML_font_size_asian = 803;
+const xml_token_t XML_font_size_complex = 804;
+const xml_token_t XML_font_size_rel = 805;
+const xml_token_t XML_font_size_rel_asian = 806;
+const xml_token_t XML_font_size_rel_complex = 807;
+const xml_token_t XML_font_stretch = 808;
+const xml_token_t XML_font_style = 809;
+const xml_token_t XML_font_style_asian = 810;
+const xml_token_t XML_font_style_complex = 811;
+const xml_token_t XML_font_style_name = 812;
+const xml_token_t XML_font_style_name_asian = 813;
+const xml_token_t XML_font_style_name_complex = 814;
+const xml_token_t XML_font_variant = 815;
+const xml_token_t XML_font_weight = 816;
+const xml_token_t XML_font_weight_asian = 817;
+const xml_token_t XML_font_weight_complex = 818;
+const xml_token_t XML_footer = 819;
+const xml_token_t XML_footer_decl = 820;
+const xml_token_t XML_footer_first = 821;
+const xml_token_t XML_footer_left = 822;
+const xml_token_t XML_footer_style = 823;
+const xml_token_t XML_footnote = 824;
+const xml_token_t XML_footnote_max_height = 825;
+const xml_token_t XML_footnote_sep = 826;
+const xml_token_t XML_footnotes_position = 827;
+const xml_token_t XML_for = 828;
+const xml_token_t XML_force_manual = 829;
+const xml_token_t XML_forced_exponent_sign = 830;
+const xml_token_t XML_foreground = 831;
+const xml_token_t XML_foreign = 832;
+const xml_token_t XML_form = 833;
+const xml_token_t XML_format_change = 834;
+const xml_token_t XML_format_source = 835;
+const xml_token_t XML_formatted_text = 836;
+const xml_token_t XML_forms = 837;
+const xml_token_t XML_formula = 838;
+const xml_token_t XML_formula_hidden = 839;
+const xml_token_t XML_formulas = 840;
+const xml_token_t XML_forward = 841;
+const xml_token_t XML_fraction = 842;
+const xml_token_t XML_frame = 843;
+const xml_token_t XML_frame_content = 844;
+const xml_token_t XML_frame_count = 845;
+const xml_token_t XML_frame_display_border = 846;
+const xml_token_t XML_frame_display_scrollbar = 847;
+const xml_token_t XML_frame_end_margin = 848;
+const xml_token_t XML_frame_margin_horizontal = 849;
+const xml_token_t XML_frame_margin_vertical = 850;
+const xml_token_t XML_frame_name = 851;
+const xml_token_t XML_frame_start_margin = 852;
+const xml_token_t XML_free = 853;
+const xml_token_t XML_freeze = 854;
+const xml_token_t XML_from = 855;
+const xml_token_t XML_from_another_table = 856;
+const xml_token_t XML_from_bottom = 857;
+const xml_token_t XML_from_center = 858;
+const xml_token_t XML_from_inside = 859;
+const xml_token_t XML_from_left = 860;
+const xml_token_t XML_from_lower_left = 861;
+const xml_token_t XML_from_lower_right = 862;
+const xml_token_t XML_from_right = 863;
+const xml_token_t XML_from_same_table = 864;
+const xml_token_t XML_from_top = 865;
+const xml_token_t XML_from_upper_left = 866;
+const xml_token_t XML_from_upper_right = 867;
+const xml_token_t XML_ft = 868;
+const xml_token_t XML_full = 869;
+const xml_token_t XML_full_screen = 870;
+const xml_token_t XML_function = 871;
+const xml_token_t XML_fx = 872;
+const xml_token_t XML_fy = 873;
+const xml_token_t XML_g = 874;
+const xml_token_t XML_gamma = 875;
+const xml_token_t XML_gap = 876;
+const xml_token_t XML_gap_width = 877;
+const xml_token_t XML_generator = 878;
+const xml_token_t XML_generic_control = 879;
+const xml_token_t XML_gengou = 880;
+const xml_token_t XML_get = 881;
+const xml_token_t XML_global = 882;
+const xml_token_t XML_glue_point = 883;
+const xml_token_t XML_glue_point_leaving_directions = 884;
+const xml_token_t XML_glue_point_type = 885;
+const xml_token_t XML_glue_points = 886;
+const xml_token_t XML_glyph_orientation_vertical = 887;
+const xml_token_t XML_gouraud = 888;
+const xml_token_t XML_gradient = 889;
+const xml_token_t XML_gradient_step_count = 890;
+const xml_token_t XML_gradientTransform = 891;
+const xml_token_t XML_gradientUnits = 892;
+const xml_token_t XML_grand_total = 893;
+const xml_token_t XML_graphic = 894;
+const xml_token_t XML_graphic_properties = 895;
+const xml_token_t XML_grddl = 896;
+const xml_token_t XML_green = 897;
+const xml_token_t XML_gregorian = 898;
+const xml_token_t XML_greyscale = 899;
+const xml_token_t XML_grid = 900;
+const xml_token_t XML_group_bars_per_axis = 901;
+const xml_token_t XML_group_by_field_number = 902;
+const xml_token_t XML_group_id = 903;
+const xml_token_t XML_grouped_by = 904;
+const xml_token_t XML_grouping = 905;
+const xml_token_t XML_guide_distance = 906;
+const xml_token_t XML_guide_overhang = 907;
+const xml_token_t XML_h = 908;
+const xml_token_t XML_handle = 909;
+const xml_token_t XML_handle_mirror_horizontal = 910;
+const xml_token_t XML_handle_mirror_vertical = 911;
+const xml_token_t XML_handle_polar = 912;
+const xml_token_t XML_handle_position = 913;
+const xml_token_t XML_handle_radius_range_maximum = 914;
+const xml_token_t XML_handle_radius_range_minimum = 915;
+const xml_token_t XML_handle_range_x_maximum = 916;
+const xml_token_t XML_handle_range_x_minimum = 917;
+const xml_token_t XML_handle_range_y_maximum = 918;
+const xml_token_t XML_handle_range_y_minimum = 919;
+const xml_token_t XML_handle_switched = 920;
+const xml_token_t XML_handout = 921;
+const xml_token_t XML_handout_master = 922;
+const xml_token_t XML_hanging = 923;
+const xml_token_t XML_hanja = 924;
+const xml_token_t XML_hanja_yoil = 925;
+const xml_token_t XML_has_persistent_data = 926;
+const xml_token_t XML_hatch = 927;
+const xml_token_t XML_header = 928;
+const xml_token_t XML_header_decl = 929;
+const xml_token_t XML_header_first = 930;
+const xml_token_t XML_header_footer_properties = 931;
+const xml_token_t XML_header_left = 932;
+const xml_token_t XML_header_style = 933;
+const xml_token_t XML_headers = 934;
+const xml_token_t XML_height = 935;
+const xml_token_t XML_help_message = 936;
+const xml_token_t XML_hidden = 937;
+const xml_token_t XML_hidden_and_protected = 938;
+const xml_token_t XML_hidden_paragraph = 939;
+const xml_token_t XML_hidden_text = 940;
+const xml_token_t XML_hide = 941;
+const xml_token_t XML_hide_shape = 942;
+const xml_token_t XML_hide_text = 943;
+const xml_token_t XML_high = 944;
+const xml_token_t XML_highlighted_range = 945;
+const xml_token_t XML_hijri = 946;
+const xml_token_t XML_hold = 947;
+const xml_token_t XML_hole_size = 948;
+const xml_token_t XML_horizontal = 949;
+const xml_token_t XML_horizontal_bar = 950;
+const xml_token_t XML_horizontal_checkerboard = 951;
+const xml_token_t XML_horizontal_lines = 952;
+const xml_token_t XML_horizontal_on_even = 953;
+const xml_token_t XML_horizontal_on_odd = 954;
+const xml_token_t XML_horizontal_pos = 955;
+const xml_token_t XML_horizontal_rel = 956;
+const xml_token_t XML_horizontal_segments = 957;
+const xml_token_t XML_horizontal_stripes = 958;
+const xml_token_t XML_hostname = 959;
+const xml_token_t XML_hourglass = 960;
+const xml_token_t XML_hours = 961;
+const xml_token_t XML_howpublished = 962;
+const xml_token_t XML_href = 963;
+const xml_token_t XML_hsl = 964;
+const xml_token_t XML_hyperlink_behaviour = 965;
+const xml_token_t XML_hyphenate = 966;
+const xml_token_t XML_hyphenation_keep = 967;
+const xml_token_t XML_hyphenation_ladder_count = 968;
+const xml_token_t XML_hyphenation_push_char_count = 969;
+const xml_token_t XML_hyphenation_remain_char_count = 970;
+const xml_token_t XML_i = 971;
+const xml_token_t XML_icon = 972;
+const xml_token_t XML_id = 973;
+const xml_token_t XML_identifier = 974;
+const xml_token_t XML_identify_categories = 975;
+const xml_token_t XML_ideograph_alpha = 976;
+const xml_token_t XML_ideographic = 977;
+const xml_token_t XML_ignore = 978;
+const xml_token_t XML_ignore_case = 979;
+const xml_token_t XML_ignore_driver_privileges = 980;
+const xml_token_t XML_ignore_empty_rows = 981;
+const xml_token_t XML_ignore_result = 982;
+const xml_token_t XML_illustration_index = 983;
+const xml_token_t XML_illustration_index_entry_template = 984;
+const xml_token_t XML_illustration_index_source = 985;
+const xml_token_t XML_image = 986;
+const xml_token_t XML_image_align = 987;
+const xml_token_t XML_image_count = 988;
+const xml_token_t XML_image_data = 989;
+const xml_token_t XML_image_frame = 990;
+const xml_token_t XML_image_map = 991;
+const xml_token_t XML_image_opacity = 992;
+const xml_token_t XML_image_position = 993;
+const xml_token_t XML_in = 994;
+const xml_token_t XML_inbook = 995;
+const xml_token_t XML_inch = 996;
+const xml_token_t XML_include_hidden_cells = 997;
+const xml_token_t XML_incollection = 998;
+const xml_token_t XML_increment = 999;
+const xml_token_t XML_indefinite = 1000;
+const xml_token_t XML_index = 1001;
+const xml_token_t XML_index_body = 1002;
+const xml_token_t XML_index_column = 1003;
+const xml_token_t XML_index_columns = 1004;
+const xml_token_t XML_index_entry_bibliography = 1005;
+const xml_token_t XML_index_entry_chapter = 1006;
+const xml_token_t XML_index_entry_link_end = 1007;
+const xml_token_t XML_index_entry_link_start = 1008;
+const xml_token_t XML_index_entry_page_number = 1009;
+const xml_token_t XML_index_entry_span = 1010;
+const xml_token_t XML_index_entry_tab_stop = 1011;
+const xml_token_t XML_index_entry_text = 1012;
+const xml_token_t XML_index_name = 1013;
+const xml_token_t XML_index_scope = 1014;
+const xml_token_t XML_index_source_style = 1015;
+const xml_token_t XML_index_source_styles = 1016;
+const xml_token_t XML_index_title = 1017;
+const xml_token_t XML_index_title_template = 1018;
+const xml_token_t XML_indices = 1019;
+const xml_token_t XML_information = 1020;
+const xml_token_t XML_inherit = 1021;
+const xml_token_t XML_initial_creator = 1022;
+const xml_token_t XML_inner = 1023;
+const xml_token_t XML_inproceedings = 1024;
+const xml_token_t XML_insertion = 1025;
+const xml_token_t XML_insertion_cut_off = 1026;
+const xml_token_t XML_inside = 1027;
+const xml_token_t XML_institution = 1028;
+const xml_token_t XML_int = 1029;
+const xml_token_t XML_integer = 1030;
+const xml_token_t XML_intensity = 1031;
+const xml_token_t XML_interactive_sequence = 1032;
+const xml_token_t XML_interlocking_horizontal_left = 1033;
+const xml_token_t XML_interlocking_horizontal_right = 1034;
+const xml_token_t XML_interlocking_vertical_bottom = 1035;
+const xml_token_t XML_interlocking_vertical_top = 1036;
+const xml_token_t XML_interpolation = 1037;
+const xml_token_t XML_interval_major = 1038;
+const xml_token_t XML_interval_minor_divisor = 1039;
+const xml_token_t XML_into_default_style_data_style = 1040;
+const xml_token_t XML_into_english_number = 1041;
+const xml_token_t XML_inverse = 1042;
+const xml_token_t XML_is_active = 1043;
+const xml_token_t XML_is_ascending = 1044;
+const xml_token_t XML_is_autoincrement = 1045;
+const xml_token_t XML_is_boolean = 1046;
+const xml_token_t XML_is_clustered = 1047;
+const xml_token_t XML_is_data_layout_field = 1048;
+const xml_token_t XML_is_empty_allowed = 1049;
+const xml_token_t XML_is_first_row_header_line = 1050;
+const xml_token_t XML_is_hidden = 1051;
+const xml_token_t XML_is_list_header = 1052;
+const xml_token_t XML_is_nullable = 1053;
+const xml_token_t XML_is_password_required = 1054;
+const xml_token_t XML_is_selection = 1055;
+const xml_token_t XML_is_sub_table = 1056;
+const xml_token_t XML_is_table_name_length_limited = 1057;
+const xml_token_t XML_is_tristate = 1058;
+const xml_token_t XML_is_unique = 1059;
+const xml_token_t XML_isbn = 1060;
+const xml_token_t XML_issn = 1061;
+const xml_token_t XML_italic = 1062;
+const xml_token_t XML_item = 1063;
+const xml_token_t XML_iterate = 1064;
+const xml_token_t XML_iterate_interval = 1065;
+const xml_token_t XML_iterate_type = 1066;
+const xml_token_t XML_iteration = 1067;
+const xml_token_t XML_iterative = 1068;
+const xml_token_t XML_japanese_candle_stick = 1069;
+const xml_token_t XML_jewish = 1070;
+const xml_token_t XML_join_border = 1071;
+const xml_token_t XML_journal = 1072;
+const xml_token_t XML_justify = 1073;
+const xml_token_t XML_justify_single_word = 1074;
+const xml_token_t XML_keep_text = 1075;
+const xml_token_t XML_keep_together = 1076;
+const xml_token_t XML_keep_with_next = 1077;
+const xml_token_t XML_key = 1078;
+const xml_token_t XML_key_column = 1079;
+const xml_token_t XML_key_columns = 1080;
+const xml_token_t XML_key1 = 1081;
+const xml_token_t XML_key1_phonetic = 1082;
+const xml_token_t XML_key2 = 1083;
+const xml_token_t XML_key2_phonetic = 1084;
+const xml_token_t XML_keySplines = 1085;
+const xml_token_t XML_keyTimes = 1086;
+const xml_token_t XML_keys = 1087;
+const xml_token_t XML_keyword = 1088;
+const xml_token_t XML_keywords = 1089;
+const xml_token_t XML_kind = 1090;
+const xml_token_t XML_km = 1091;
+const xml_token_t XML_label = 1092;
+const xml_token_t XML_label_alignment = 1093;
+const xml_token_t XML_label_arrangement = 1094;
+const xml_token_t XML_label_cell_address = 1095;
+const xml_token_t XML_label_cell_range_address = 1096;
+const xml_token_t XML_label_followed_by = 1097;
+const xml_token_t XML_label_position = 1098;
+const xml_token_t XML_label_position_negative = 1099;
+const xml_token_t XML_label_range = 1100;
+const xml_token_t XML_label_ranges = 1101;
+const xml_token_t XML_label_separator = 1102;
+const xml_token_t XML_label_width_and_position = 1103;
+const xml_token_t XML_landscape = 1104;
+const xml_token_t XML_language = 1105;
+const xml_token_t XML_language_asian = 1106;
+const xml_token_t XML_language_complex = 1107;
+const xml_token_t XML_laser = 1108;
+const xml_token_t XML_last = 1109;
+const xml_token_t XML_last_column = 1110;
+const xml_token_t XML_last_column_spanned = 1111;
+const xml_token_t XML_last_page = 1112;
+const xml_token_t XML_last_row = 1113;
+const xml_token_t XML_last_row_end_column = 1114;
+const xml_token_t XML_last_row_spanned = 1115;
+const xml_token_t XML_last_row_start_column = 1116;
+const xml_token_t XML_last_visited_page = 1117;
+const xml_token_t XML_latin = 1118;
+const xml_token_t XML_layer = 1119;
+const xml_token_t XML_layer_set = 1120;
+const xml_token_t XML_layout_grid_base_height = 1121;
+const xml_token_t XML_layout_grid_base_width = 1122;
+const xml_token_t XML_layout_grid_color = 1123;
+const xml_token_t XML_layout_grid_display = 1124;
+const xml_token_t XML_layout_grid_lines = 1125;
+const xml_token_t XML_layout_grid_mode = 1126;
+const xml_token_t XML_layout_grid_print = 1127;
+const xml_token_t XML_layout_grid_ruby_below = 1128;
+const xml_token_t XML_layout_grid_ruby_height = 1129;
+const xml_token_t XML_layout_grid_snap_to = 1130;
+const xml_token_t XML_layout_grid_standard_mode = 1131;
+const xml_token_t XML_layout_mode = 1132;
+const xml_token_t XML_leader_char = 1133;
+const xml_token_t XML_leader_color = 1134;
+const xml_token_t XML_leader_style = 1135;
+const xml_token_t XML_leader_text = 1136;
+const xml_token_t XML_leader_text_style = 1137;
+const xml_token_t XML_leader_type = 1138;
+const xml_token_t XML_leader_width = 1139;
+const xml_token_t XML_leave_gap = 1140;
+const xml_token_t XML_left = 1141;
+const xml_token_t XML_left_outside = 1142;
+const xml_token_t XML_legend = 1143;
+const xml_token_t XML_legend_align = 1144;
+const xml_token_t XML_legend_expansion = 1145;
+const xml_token_t XML_legend_expansion_aspect_ratio = 1146;
+const xml_token_t XML_legend_position = 1147;
+const xml_token_t XML_length = 1148;
+const xml_token_t XML_letter_kerning = 1149;
+const xml_token_t XML_letter_spacing = 1150;
+const xml_token_t XML_letters = 1151;
+const xml_token_t XML_level = 1152;
+const xml_token_t XML_light = 1153;
+const xml_token_t XML_lighting_mode = 1154;
+const xml_token_t XML_line = 1155;
+const xml_token_t XML_line_break = 1156;
+const xml_token_t XML_line_distance = 1157;
+const xml_token_t XML_line_height = 1158;
+const xml_token_t XML_line_height_at_least = 1159;
+const xml_token_t XML_line_number = 1160;
+const xml_token_t XML_line_skew = 1161;
+const xml_token_t XML_line_spacing = 1162;
+const xml_token_t XML_line_style = 1163;
+const xml_token_t XML_linear = 1164;
+const xml_token_t XML_linearGradient = 1165;
+const xml_token_t XML_linenumbering_configuration = 1166;
+const xml_token_t XML_linenumbering_separator = 1167;
+const xml_token_t XML_lines = 1168;
+const xml_token_t XML_link_data_style_to_source = 1169;
+const xml_token_t XML_link_to_source_data = 1170;
+const xml_token_t XML_linked_cell = 1171;
+const xml_token_t XML_list = 1172;
+const xml_token_t XML_list_header = 1173;
+const xml_token_t XML_list_id = 1174;
+const xml_token_t XML_list_item = 1175;
+const xml_token_t XML_list_level = 1176;
+const xml_token_t XML_list_level_label_alignment = 1177;
+const xml_token_t XML_list_level_position_and_space_mode = 1178;
+const xml_token_t XML_list_level_properties = 1179;
+const xml_token_t XML_list_level_style_bullet = 1180;
+const xml_token_t XML_list_level_style_image = 1181;
+const xml_token_t XML_list_level_style_number = 1182;
+const xml_token_t XML_list_linkage_type = 1183;
+const xml_token_t XML_list_property = 1184;
+const xml_token_t XML_list_source = 1185;
+const xml_token_t XML_list_source_type = 1186;
+const xml_token_t XML_list_style = 1187;
+const xml_token_t XML_list_style_name = 1188;
+const xml_token_t XML_list_tab_stop_position = 1189;
+const xml_token_t XML_list_value = 1190;
+const xml_token_t XML_listbox = 1191;
+const xml_token_t XML_listtab = 1192;
+const xml_token_t XML_local_socket = 1193;
+const xml_token_t XML_logarithmic = 1194;
+const xml_token_t XML_login = 1195;
+const xml_token_t XML_login_timeout = 1196;
+const xml_token_t XML_long = 1197;
+const xml_token_t XML_long_dash = 1198;
+const xml_token_t XML_longvarbinary = 1199;
+const xml_token_t XML_longvarchar = 1200;
+const xml_token_t XML_lowercase = 1201;
+const xml_token_t XML_lr = 1202;
+const xml_token_t XML_lr_tb = 1203;
+const xml_token_t XML_ltr = 1204;
+const xml_token_t XML_luminance = 1205;
+const xml_token_t XML_m = 1206;
+const xml_token_t XML_macro_name = 1207;
+const xml_token_t XML_main_entry = 1208;
+const xml_token_t XML_main_entry_style_name = 1209;
+const xml_token_t XML_main_sequence = 1210;
+const xml_token_t XML_major = 1211;
+const xml_token_t XML_manual = 1212;
+const xml_token_t XML_map = 1213;
+const xml_token_t XML_margin = 1214;
+const xml_token_t XML_margin_bottom = 1215;
+const xml_token_t XML_margin_left = 1216;
+const xml_token_t XML_margin_right = 1217;
+const xml_token_t XML_margin_top = 1218;
+const xml_token_t XML_margins = 1219;
+const xml_token_t XML_marked_invalid = 1220;
+const xml_token_t XML_marker = 1221;
+const xml_token_t XML_marker_end = 1222;
+const xml_token_t XML_marker_end_center = 1223;
+const xml_token_t XML_marker_end_width = 1224;
+const xml_token_t XML_marker_start = 1225;
+const xml_token_t XML_marker_start_center = 1226;
+const xml_token_t XML_marker_start_width = 1227;
+const xml_token_t XML_master_element = 1228;
+const xml_token_t XML_master_fields = 1229;
+const xml_token_t XML_master_page = 1230;
+const xml_token_t XML_master_page_name = 1231;
+const xml_token_t XML_master_styles = 1232;
+const xml_token_t XML_mastersthesis = 1233;
+const xml_token_t XML_math = 1234;
+const xml_token_t XML_mathematical = 1235;
+const xml_token_t XML_matrix_covered = 1236;
+const xml_token_t XML_max = 1237;
+const xml_token_t XML_max_denominator_value = 1238;
+const xml_token_t XML_max_edge = 1239;
+const xml_token_t XML_max_height = 1240;
+const xml_token_t XML_max_length = 1241;
+const xml_token_t XML_max_row_count = 1242;
+const xml_token_t XML_max_value = 1243;
+const xml_token_t XML_max_width = 1244;
+const xml_token_t XML_maximum = 1245;
+const xml_token_t XML_maximum_difference = 1246;
+const xml_token_t XML_may_break_between_rows = 1247;
+const xml_token_t XML_may_script = 1248;
+const xml_token_t XML_mean_value = 1249;
+const xml_token_t XML_measure = 1250;
+const xml_token_t XML_measure_align = 1251;
+const xml_token_t XML_measure_vertical_align = 1252;
+const xml_token_t XML_media = 1253;
+const xml_token_t XML_media_call = 1254;
+const xml_token_t XML_media_type = 1255;
+const xml_token_t XML_medium = 1256;
+const xml_token_t XML_melt = 1257;
+const xml_token_t XML_member_count = 1258;
+const xml_token_t XML_member_difference = 1259;
+const xml_token_t XML_member_name = 1260;
+const xml_token_t XML_member_percentage = 1261;
+const xml_token_t XML_member_percentage_difference = 1262;
+const xml_token_t XML_member_type = 1263;
+const xml_token_t XML_message_type = 1264;
+const xml_token_t XML_meta = 1265;
+const xml_token_t XML_meta_field = 1266;
+const xml_token_t XML_method = 1267;
+const xml_token_t XML_mi = 1268;
+const xml_token_t XML_middle = 1269;
+const xml_token_t XML_mime_type = 1270;
+const xml_token_t XML_mimetype = 1271;
+const xml_token_t XML_min = 1272;
+const xml_token_t XML_min_decimal_places = 1273;
+const xml_token_t XML_min_denominator_digits = 1274;
+const xml_token_t XML_min_edge = 1275;
+const xml_token_t XML_min_exponent_digits = 1276;
+const xml_token_t XML_min_height = 1277;
+const xml_token_t XML_min_integer_digits = 1278;
+const xml_token_t XML_min_label_distance = 1279;
+const xml_token_t XML_min_label_width = 1280;
+const xml_token_t XML_min_numerator_digits = 1281;
+const xml_token_t XML_min_row_height = 1282;
+const xml_token_t XML_min_value = 1283;
+const xml_token_t XML_min_width = 1284;
+const xml_token_t XML_minimum = 1285;
+const xml_token_t XML_minor = 1286;
+const xml_token_t XML_minutes = 1287;
+const xml_token_t XML_mirror = 1288;
+const xml_token_t XML_mirror_horizontal = 1289;
+const xml_token_t XML_mirror_vertical = 1290;
+const xml_token_t XML_mirrored = 1291;
+const xml_token_t XML_misc = 1292;
+const xml_token_t XML_miter = 1293;
+const xml_token_t XML_mm = 1294;
+const xml_token_t XML_mode = 1295;
+const xml_token_t XML_model = 1296;
+const xml_token_t XML_modern = 1297;
+const xml_token_t XML_modification_date = 1298;
+const xml_token_t XML_modification_time = 1299;
+const xml_token_t XML_modifiers = 1300;
+const xml_token_t XML_modulate = 1301;
+const xml_token_t XML_mono = 1302;
+const xml_token_t XML_month = 1303;
+const xml_token_t XML_months = 1304;
+const xml_token_t XML_motion_path = 1305;
+const xml_token_t XML_mouse_as_pen = 1306;
+const xml_token_t XML_mouse_visible = 1307;
+const xml_token_t XML_move = 1308;
+const xml_token_t XML_move_from_bottom = 1309;
+const xml_token_t XML_move_from_left = 1310;
+const xml_token_t XML_move_from_lowerleft = 1311;
+const xml_token_t XML_move_from_lowerright = 1312;
+const xml_token_t XML_move_from_right = 1313;
+const xml_token_t XML_move_from_top = 1314;
+const xml_token_t XML_move_from_upperleft = 1315;
+const xml_token_t XML_move_from_upperright = 1316;
+const xml_token_t XML_move_short = 1317;
+const xml_token_t XML_movement = 1318;
+const xml_token_t XML_movement_cut_off = 1319;
+const xml_token_t XML_moving_average = 1320;
+const xml_token_t XML_multi_deletion_spanned = 1321;
+const xml_token_t XML_multi_line = 1322;
+const xml_token_t XML_multiple = 1323;
+const xml_token_t XML_name = 1324;
+const xml_token_t XML_name_and_extension = 1325;
+const xml_token_t XML_named = 1326;
+const xml_token_t XML_named_expression = 1327;
+const xml_token_t XML_named_expressions = 1328;
+const xml_token_t XML_named_range = 1329;
+const xml_token_t XML_named_symbol = 1330;
+const xml_token_t XML_nav_order = 1331;
+const xml_token_t XML_navigation_mode = 1332;
+const xml_token_t XML_near_axis = 1333;
+const xml_token_t XML_near_axis_other_side = 1334;
+const xml_token_t XML_near_origin = 1335;
+const xml_token_t XML_never = 1336;
+const xml_token_t XML_new = 1337;
+const xml_token_t XML_next = 1338;
+const xml_token_t XML_next_page = 1339;
+const xml_token_t XML_next_style_name = 1340;
+const xml_token_t XML_no_action = 1341;
+const xml_token_t XML_no_limit = 1342;
+const xml_token_t XML_no_nulls = 1343;
+const xml_token_t XML_no_repeat = 1344;
+const xml_token_t XML_no_wrap = 1345;
+const xml_token_t XML_node_type = 1346;
+const xml_token_t XML_nohref = 1347;
+const xml_token_t XML_non_primitive = 1348;
+const xml_token_t XML_non_whitespace_character_count = 1349;
+const xml_token_t XML_none = 1350;
+const xml_token_t XML_nonzero = 1351;
+const xml_token_t XML_normal = 1352;
+const xml_token_t XML_normals_direction = 1353;
+const xml_token_t XML_normals_kind = 1354;
+const xml_token_t XML_note = 1355;
+const xml_token_t XML_note_body = 1356;
+const xml_token_t XML_note_citation = 1357;
+const xml_token_t XML_note_class = 1358;
+const xml_token_t XML_note_continuation_notice_backward = 1359;
+const xml_token_t XML_note_continuation_notice_forward = 1360;
+const xml_token_t XML_note_ref = 1361;
+const xml_token_t XML_notes = 1362;
+const xml_token_t XML_notes_configuration = 1363;
+const xml_token_t XML_nothing = 1364;
+const xml_token_t XML_notify_on_update_of_ranges = 1365;
+const xml_token_t XML_null_date = 1366;
+const xml_token_t XML_null_year = 1367;
+const xml_token_t XML_nullable = 1368;
+const xml_token_t XML_num_format = 1369;
+const xml_token_t XML_num_letter_sync = 1370;
+const xml_token_t XML_num_prefix = 1371;
+const xml_token_t XML_num_suffix = 1372;
+const xml_token_t XML_number = 1373;
+const xml_token_t XML_number_all_superior = 1374;
+const xml_token_t XML_number_and_name = 1375;
+const xml_token_t XML_number_columns_repeated = 1376;
+const xml_token_t XML_number_columns_spanned = 1377;
+const xml_token_t XML_number_lines = 1378;
+const xml_token_t XML_number_matrix_columns_spanned = 1379;
+const xml_token_t XML_number_matrix_rows_spanned = 1380;
+const xml_token_t XML_number_no_superior = 1381;
+const xml_token_t XML_number_position = 1382;
+const xml_token_t XML_number_rows_repeated = 1383;
+const xml_token_t XML_number_rows_spanned = 1384;
+const xml_token_t XML_number_style = 1385;
+const xml_token_t XML_number_wrapped_paragraphs = 1386;
+const xml_token_t XML_numbered_entries = 1387;
+const xml_token_t XML_numbered_paragraph = 1388;
+const xml_token_t XML_numeric = 1389;
+const xml_token_t XML_object = 1390;
+const xml_token_t XML_object_count = 1391;
+const xml_token_t XML_object_index = 1392;
+const xml_token_t XML_object_index_entry_template = 1393;
+const xml_token_t XML_object_index_source = 1394;
+const xml_token_t XML_object_name = 1395;
+const xml_token_t XML_object_ole = 1396;
+const xml_token_t XML_objectBoundingBox = 1397;
+const xml_token_t XML_objects = 1398;
+const xml_token_t XML_oblique = 1399;
+const xml_token_t XML_odd_columns = 1400;
+const xml_token_t XML_odd_rows = 1401;
+const xml_token_t XML_office = 1402;
+const xml_token_t XML_offset = 1403;
+const xml_token_t XML_ole_action = 1404;
+const xml_token_t XML_ole_draw_aspect = 1405;
+const xml_token_t XML_ole_object_count = 1406;
+const xml_token_t XML_on_click = 1407;
+const xml_token_t XML_on_update_keep_size = 1408;
+const xml_token_t XML_on_update_keep_styles = 1409;
+const xml_token_t XML_onLoad = 1410;
+const xml_token_t XML_onRequest = 1411;
+const xml_token_t XML_once_concurrent = 1412;
+const xml_token_t XML_once_successive = 1413;
+const xml_token_t XML_opacity = 1414;
+const xml_token_t XML_opacity_name = 1415;
+const xml_token_t XML_open = 1416;
+const xml_token_t XML_open_horizontal = 1417;
+const xml_token_t XML_open_vertical = 1418;
+const xml_token_t XML_operation = 1419;
+const xml_token_t XML_operator = 1420;
+const xml_token_t XML_option = 1421;
+const xml_token_t XML_order = 1422;
+const xml_token_t XML_order_statement = 1423;
+const xml_token_t XML_organizations = 1424;
+const xml_token_t XML_orgchart = 1425;
+const xml_token_t XML_orientation = 1426;
+const xml_token_t XML_origin = 1427;
+const xml_token_t XML_orphans = 1428;
+const xml_token_t XML_other = 1429;
+const xml_token_t XML_out = 1430;
+const xml_token_t XML_outer = 1431;
+const xml_token_t XML_outline = 1432;
+const xml_token_t XML_outline_level = 1433;
+const xml_token_t XML_outline_level_style = 1434;
+const xml_token_t XML_outline_style = 1435;
+const xml_token_t XML_outline_subtotals_bottom = 1436;
+const xml_token_t XML_outline_subtotals_top = 1437;
+const xml_token_t XML_outside = 1438;
+const xml_token_t XML_outside_end = 1439;
+const xml_token_t XML_outside_start = 1440;
+const xml_token_t XML_overflow_behavior = 1441;
+const xml_token_t XML_overlap = 1442;
+const xml_token_t XML_overline_position = 1443;
+const xml_token_t XML_overline_thickness = 1444;
+const xml_token_t XML_p = 1445;
+const xml_token_t XML_paced = 1446;
+const xml_token_t XML_pad = 1447;
+const xml_token_t XML_padding = 1448;
+const xml_token_t XML_padding_bottom = 1449;
+const xml_token_t XML_padding_left = 1450;
+const xml_token_t XML_padding_right = 1451;
+const xml_token_t XML_padding_top = 1452;
+const xml_token_t XML_page = 1453;
+const xml_token_t XML_page_adjust = 1454;
+const xml_token_t XML_page_breaks_on_group_change = 1455;
+const xml_token_t XML_page_content = 1456;
+const xml_token_t XML_page_continuation = 1457;
+const xml_token_t XML_page_count = 1458;
+const xml_token_t XML_page_end_margin = 1459;
+const xml_token_t XML_page_height = 1460;
+const xml_token_t XML_page_layout = 1461;
+const xml_token_t XML_page_layout_name = 1462;
+const xml_token_t XML_page_layout_properties = 1463;
+const xml_token_t XML_page_number = 1464;
+const xml_token_t XML_page_sequence = 1465;
+const xml_token_t XML_page_start_margin = 1466;
+const xml_token_t XML_page_step_size = 1467;
+const xml_token_t XML_page_thumbnail = 1468;
+const xml_token_t XML_page_usage = 1469;
+const xml_token_t XML_page_variable_get = 1470;
+const xml_token_t XML_page_variable_set = 1471;
+const xml_token_t XML_page_width = 1472;
+const xml_token_t XML_pages = 1473;
+const xml_token_t XML_panose_1 = 1474;
+const xml_token_t XML_paper_tray_name = 1475;
+const xml_token_t XML_par = 1476;
+const xml_token_t XML_paragraph = 1477;
+const xml_token_t XML_paragraph_content = 1478;
+const xml_token_t XML_paragraph_count = 1479;
+const xml_token_t XML_paragraph_end_margin = 1480;
+const xml_token_t XML_paragraph_properties = 1481;
+const xml_token_t XML_paragraph_start_margin = 1482;
+const xml_token_t XML_paragraph_style_name = 1483;
+const xml_token_t XML_parallel = 1484;
+const xml_token_t XML_param = 1485;
+const xml_token_t XML_parameter_name_substitution = 1486;
+const xml_token_t XML_parent = 1487;
+const xml_token_t XML_parent_style_name = 1488;
+const xml_token_t XML_parse_sql_statement = 1489;
+const xml_token_t XML_password = 1490;
+const xml_token_t XML_path = 1491;
+const xml_token_t XML_path_id = 1492;
+const xml_token_t XML_path_stretchpoint_x = 1493;
+const xml_token_t XML_path_stretchpoint_y = 1494;
+const xml_token_t XML_pause = 1495;
+const xml_token_t XML_pc = 1496;
+const xml_token_t XML_pending = 1497;
+const xml_token_t XML_percentage = 1498;
+const xml_token_t XML_percentage_data_style_name = 1499;
+const xml_token_t XML_percentage_style = 1500;
+const xml_token_t XML_perspective = 1501;
+const xml_token_t XML_phdthesis = 1502;
+const xml_token_t XML_phong = 1503;
+const xml_token_t XML_pie_offset = 1504;
+const xml_token_t XML_placeholder = 1505;
+const xml_token_t XML_placeholder_type = 1506;
+const xml_token_t XML_placing = 1507;
+const xml_token_t XML_plain_number = 1508;
+const xml_token_t XML_plain_number_and_name = 1509;
+const xml_token_t XML_play = 1510;
+const xml_token_t XML_play_full = 1511;
+const xml_token_t XML_plot_area = 1512;
+const xml_token_t XML_plugin = 1513;
+const xml_token_t XML_plus = 1514;
+const xml_token_t XML_points = 1515;
+const xml_token_t XML_polygon = 1516;
+const xml_token_t XML_polyline = 1517;
+const xml_token_t XML_polynomial = 1518;
+const xml_token_t XML_port = 1519;
+const xml_token_t XML_portrait = 1520;
+const xml_token_t XML_position = 1521;
+const xml_token_t XML_possessive_form = 1522;
+const xml_token_t XML_post = 1523;
+const xml_token_t XML_power = 1524;
+const xml_token_t XML_precision = 1525;
+const xml_token_t XML_precision_as_shown = 1526;
+const xml_token_t XML_prefix = 1527;
+const xml_token_t XML_presentation = 1528;
+const xml_token_t XML_presentation_page_layout = 1529;
+const xml_token_t XML_presentation_page_layout_name = 1530;
+const xml_token_t XML_preset_class = 1531;
+const xml_token_t XML_preset_id = 1532;
+const xml_token_t XML_preset_sub_type = 1533;
+const xml_token_t XML_previous = 1534;
+const xml_token_t XML_previous_page = 1535;
+const xml_token_t XML_primary = 1536;
+const xml_token_t XML_print = 1537;
+const xml_token_t XML_print_content = 1538;
+const xml_token_t XML_print_date = 1539;
+const xml_token_t XML_print_orientation = 1540;
+const xml_token_t XML_print_page_order = 1541;
+const xml_token_t XML_print_range = 1542;
+const xml_token_t XML_print_ranges = 1543;
+const xml_token_t XML_print_time = 1544;
+const xml_token_t XML_print_view = 1545;
+const xml_token_t XML_printable = 1546;
+const xml_token_t XML_printed_by = 1547;
+const xml_token_t XML_printer = 1548;
+const xml_token_t XML_prior = 1549;
+const xml_token_t XML_proceedings = 1550;
+const xml_token_t XML_product = 1551;
+const xml_token_t XML_projection = 1552;
+const xml_token_t XML_properties = 1553;
+const xml_token_t XML_property = 1554;
+const xml_token_t XML_property_name = 1555;
+const xml_token_t XML_protect = 1556;
+const xml_token_t XML_protected = 1557;
+const xml_token_t XML_protection_key = 1558;
+const xml_token_t XML_protection_key_digest_algorithm = 1559;
+const xml_token_t XML_pt = 1560;
+const xml_token_t XML_publisher = 1561;
+const xml_token_t XML_punctuation_wrap = 1562;
+const xml_token_t XML_push = 1563;
+const xml_token_t XML_pyramid = 1564;
+const xml_token_t XML_quarter = 1565;
+const xml_token_t XML_quarters = 1566;
+const xml_token_t XML_queries = 1567;
+const xml_token_t XML_query = 1568;
+const xml_token_t XML_query_collection = 1569;
+const xml_token_t XML_query_name = 1570;
+const xml_token_t XML_r = 1571;
+const xml_token_t XML_radial = 1572;
+const xml_token_t XML_radialGradient = 1573;
+const xml_token_t XML_radio = 1574;
+const xml_token_t XML_random = 1575;
+const xml_token_t XML_range_usable_as = 1576;
+const xml_token_t XML_readonly = 1577;
+const xml_token_t XML_real = 1578;
+const xml_token_t XML_records = 1579;
+const xml_token_t XML_recreate_on_edit = 1580;
+const xml_token_t XML_rect = 1581;
+const xml_token_t XML_rectangle = 1582;
+const xml_token_t XML_rectangular = 1583;
+const xml_token_t XML_red = 1584;
+const xml_token_t XML_ref = 1585;
+const xml_token_t XML_ref_name = 1586;
+const xml_token_t XML_reference_format = 1587;
+const xml_token_t XML_reference_mark = 1588;
+const xml_token_t XML_reference_mark_end = 1589;
+const xml_token_t XML_reference_mark_start = 1590;
+const xml_token_t XML_referenced_table_name = 1591;
+const xml_token_t XML_reflect = 1592;
+const xml_token_t XML_refresh_delay = 1593;
+const xml_token_t XML_region_center = 1594;
+const xml_token_t XML_region_left = 1595;
+const xml_token_t XML_region_right = 1596;
+const xml_token_t XML_register_true = 1597;
+const xml_token_t XML_register_truth_ref_style_name = 1598;
+const xml_token_t XML_regression_curve = 1599;
+const xml_token_t XML_regression_force_intercept = 1600;
+const xml_token_t XML_regression_intercept_value = 1601;
+const xml_token_t XML_regression_max_degree = 1602;
+const xml_token_t XML_regression_moving_type = 1603;
+const xml_token_t XML_regression_name = 1604;
+const xml_token_t XML_regression_period = 1605;
+const xml_token_t XML_regression_type = 1606;
+const xml_token_t XML_regular_polygon = 1607;
+const xml_token_t XML_rejected = 1608;
+const xml_token_t XML_rejecting_change_id = 1609;
+const xml_token_t XML_rel_column_width = 1610;
+const xml_token_t XML_rel_height = 1611;
+const xml_token_t XML_rel_width = 1612;
+const xml_token_t XML_related_column_name = 1613;
+const xml_token_t XML_relative_tab_stop_position = 1614;
+const xml_token_t XML_remove = 1615;
+const xml_token_t XML_remove_dependents = 1616;
+const xml_token_t XML_remove_precedents = 1617;
+const xml_token_t XML_repeat = 1618;
+const xml_token_t XML_repeat_column = 1619;
+const xml_token_t XML_repeat_content = 1620;
+const xml_token_t XML_repeat_row = 1621;
+const xml_token_t XML_repeatCount = 1622;
+const xml_token_t XML_repeatDur = 1623;
+const xml_token_t XML_repeated = 1624;
+const xml_token_t XML_replace = 1625;
+const xml_token_t XML_report_type = 1626;
+const xml_token_t XML_reports = 1627;
+const xml_token_t XML_reset = 1628;
+const xml_token_t XML_restart = 1629;
+const xml_token_t XML_restart_numbering = 1630;
+const xml_token_t XML_restart_on_page = 1631;
+const xml_token_t XML_restartDefault = 1632;
+const xml_token_t XML_restrict = 1633;
+const xml_token_t XML_reverse = 1634;
+const xml_token_t XML_reverse_direction = 1635;
+const xml_token_t XML_rfc_language_tag = 1636;
+const xml_token_t XML_rfc_language_tag_asian = 1637;
+const xml_token_t XML_rfc_language_tag_complex = 1638;
+const xml_token_t XML_rgb = 1639;
+const xml_token_t XML_right = 1640;
+const xml_token_t XML_right_angled_axes = 1641;
+const xml_token_t XML_right_outside = 1642;
+const xml_token_t XML_rl = 1643;
+const xml_token_t XML_rl_tb = 1644;
+const xml_token_t XML_roll_from_bottom = 1645;
+const xml_token_t XML_roll_from_left = 1646;
+const xml_token_t XML_roll_from_right = 1647;
+const xml_token_t XML_roll_from_top = 1648;
+const xml_token_t XML_roman = 1649;
+const xml_token_t XML_rotate = 1650;
+const xml_token_t XML_rotation = 1651;
+const xml_token_t XML_rotation_align = 1652;
+const xml_token_t XML_rotation_angle = 1653;
+const xml_token_t XML_round = 1654;
+const xml_token_t XML_row = 1655;
+const xml_token_t XML_row_count = 1656;
+const xml_token_t XML_row_height = 1657;
+const xml_token_t XML_row_mapping = 1658;
+const xml_token_t XML_row_number = 1659;
+const xml_token_t XML_row_percentage = 1660;
+const xml_token_t XML_row_retrieving_statement = 1661;
+const xml_token_t XML_rows = 1662;
+const xml_token_t XML_ruby = 1663;
+const xml_token_t XML_ruby_align = 1664;
+const xml_token_t XML_ruby_base = 1665;
+const xml_token_t XML_ruby_position = 1666;
+const xml_token_t XML_ruby_properties = 1667;
+const xml_token_t XML_ruby_text = 1668;
+const xml_token_t XML_run_through = 1669;
+const xml_token_t XML_running_total = 1670;
+const xml_token_t XML_rx = 1671;
+const xml_token_t XML_ry = 1672;
+const xml_token_t XML_s = 1673;
+const xml_token_t XML_scale = 1674;
+const xml_token_t XML_scale_min = 1675;
+const xml_token_t XML_scale_text = 1676;
+const xml_token_t XML_scale_to = 1677;
+const xml_token_t XML_scale_to_X = 1678;
+const xml_token_t XML_scale_to_Y = 1679;
+const xml_token_t XML_scale_to_pages = 1680;
+const xml_token_t XML_scenario = 1681;
+const xml_token_t XML_scenario_ranges = 1682;
+const xml_token_t XML_scene = 1683;
+const xml_token_t XML_schema_definition = 1684;
+const xml_token_t XML_schema_name = 1685;
+const xml_token_t XML_school = 1686;
+const xml_token_t XML_scientific_number = 1687;
+const xml_token_t XML_screen = 1688;
+const xml_token_t XML_script = 1689;
+const xml_token_t XML_script_asian = 1690;
+const xml_token_t XML_script_complex = 1691;
+const xml_token_t XML_script_type = 1692;
+const xml_token_t XML_scripts = 1693;
+const xml_token_t XML_scroll = 1694;
+const xml_token_t XML_search_criteria_must_apply_to_whole_cell = 1695;
+const xml_token_t XML_secondary_fill_color = 1696;
+const xml_token_t XML_seconds = 1697;
+const xml_token_t XML_section = 1698;
+const xml_token_t XML_section_name = 1699;
+const xml_token_t XML_section_properties = 1700;
+const xml_token_t XML_section_source = 1701;
+const xml_token_t XML_segments = 1702;
+const xml_token_t XML_select_page = 1703;
+const xml_token_t XML_selected = 1704;
+const xml_token_t XML_selected_page = 1705;
+const xml_token_t XML_selection = 1706;
+const xml_token_t XML_selection_indices = 1707;
+const xml_token_t XML_self = 1708;
+const xml_token_t XML_semi_automatic = 1709;
+const xml_token_t XML_semi_condensed = 1710;
+const xml_token_t XML_semi_expanded = 1711;
+const xml_token_t XML_sender_city = 1712;
+const xml_token_t XML_sender_company = 1713;
+const xml_token_t XML_sender_country = 1714;
+const xml_token_t XML_sender_email = 1715;
+const xml_token_t XML_sender_fax = 1716;
+const xml_token_t XML_sender_firstname = 1717;
+const xml_token_t XML_sender_initials = 1718;
+const xml_token_t XML_sender_lastname = 1719;
+const xml_token_t XML_sender_phone_private = 1720;
+const xml_token_t XML_sender_phone_work = 1721;
+const xml_token_t XML_sender_position = 1722;
+const xml_token_t XML_sender_postal_code = 1723;
+const xml_token_t XML_sender_state_or_province = 1724;
+const xml_token_t XML_sender_street = 1725;
+const xml_token_t XML_sender_title = 1726;
+const xml_token_t XML_sentence_count = 1727;
+const xml_token_t XML_separating = 1728;
+const xml_token_t XML_separation_character = 1729;
+const xml_token_t XML_separator = 1730;
+const xml_token_t XML_seq = 1731;
+const xml_token_t XML_sequence = 1732;
+const xml_token_t XML_sequence_decl = 1733;
+const xml_token_t XML_sequence_decls = 1734;
+const xml_token_t XML_sequence_ref = 1735;
+const xml_token_t XML_series = 1736;
+const xml_token_t XML_series_source = 1737;
+const xml_token_t XML_server_database = 1738;
+const xml_token_t XML_server_map = 1739;
+const xml_token_t XML_set = 1740;
+const xml_token_t XML_set_default = 1741;
+const xml_token_t XML_set_null = 1742;
+const xml_token_t XML_settings = 1743;
+const xml_token_t XML_shade_mode = 1744;
+const xml_token_t XML_shadow = 1745;
+const xml_token_t XML_shadow_color = 1746;
+const xml_token_t XML_shadow_offset_x = 1747;
+const xml_token_t XML_shadow_offset_y = 1748;
+const xml_token_t XML_shadow_opacity = 1749;
+const xml_token_t XML_shadow_slant = 1750;
+const xml_token_t XML_shape = 1751;
+const xml_token_t XML_shape_id = 1752;
+const xml_token_t XML_shapes = 1753;
+const xml_token_t XML_sharpness = 1754;
+const xml_token_t XML_sheet_name = 1755;
+const xml_token_t XML_shininess = 1756;
+const xml_token_t XML_short = 1757;
+const xml_token_t XML_show = 1758;
+const xml_token_t XML_show_deleted = 1759;
+const xml_token_t XML_show_details = 1760;
+const xml_token_t XML_show_empty = 1761;
+const xml_token_t XML_show_end_of_presentation_slide = 1762;
+const xml_token_t XML_show_filter_button = 1763;
+const xml_token_t XML_show_logo = 1764;
+const xml_token_t XML_show_shape = 1765;
+const xml_token_t XML_show_text = 1766;
+const xml_token_t XML_show_unit = 1767;
+const xml_token_t XML_shrink_to_fit = 1768;
+const xml_token_t XML_side_by_side = 1769;
+const xml_token_t XML_simple = 1770;
+const xml_token_t XML_single = 1771;
+const xml_token_t XML_size = 1772;
+const xml_token_t XML_skewX = 1773;
+const xml_token_t XML_skewY = 1774;
+const xml_token_t XML_skip_white_space = 1775;
+const xml_token_t XML_slide = 1776;
+const xml_token_t XML_slope = 1777;
+const xml_token_t XML_slow = 1778;
+const xml_token_t XML_small_caps = 1779;
+const xml_token_t XML_smallint = 1780;
+const xml_token_t XML_smil = 1781;
+const xml_token_t XML_snap_to_layout_grid = 1782;
+const xml_token_t XML_soft_page_break = 1783;
+const xml_token_t XML_solid = 1784;
+const xml_token_t XML_solid_type = 1785;
+const xml_token_t XML_sort = 1786;
+const xml_token_t XML_sort_algorithm = 1787;
+const xml_token_t XML_sort_ascending = 1788;
+const xml_token_t XML_sort_by = 1789;
+const xml_token_t XML_sort_by_position = 1790;
+const xml_token_t XML_sort_by_x_values = 1791;
+const xml_token_t XML_sort_groups = 1792;
+const xml_token_t XML_sort_key = 1793;
+const xml_token_t XML_sort_mode = 1794;
+const xml_token_t XML_sound = 1795;
+const xml_token_t XML_source = 1796;
+const xml_token_t XML_source_cell_range = 1797;
+const xml_token_t XML_source_cell_range_addresses = 1798;
+const xml_token_t XML_source_field_name = 1799;
+const xml_token_t XML_source_name = 1800;
+const xml_token_t XML_source_range_address = 1801;
+const xml_token_t XML_source_service = 1802;
+const xml_token_t XML_space = 1803;
+const xml_token_t XML_space_after = 1804;
+const xml_token_t XML_space_before = 1805;
+const xml_token_t XML_span = 1806;
+const xml_token_t XML_specular = 1807;
+const xml_token_t XML_specular_color = 1808;
+const xml_token_t XML_speed = 1809;
+const xml_token_t XML_sphere = 1810;
+const xml_token_t XML_spin_button = 1811;
+const xml_token_t XML_spiral_inward_left = 1812;
+const xml_token_t XML_spiral_inward_right = 1813;
+const xml_token_t XML_spiral_outward_left = 1814;
+const xml_token_t XML_spiral_outward_right = 1815;
+const xml_token_t XML_spiralin_left = 1816;
+const xml_token_t XML_spiralin_right = 1817;
+const xml_token_t XML_spiralout_left = 1818;
+const xml_token_t XML_spiralout_right = 1819;
+const xml_token_t XML_spline = 1820;
+const xml_token_t XML_spline_order = 1821;
+const xml_token_t XML_spline_resolution = 1822;
+const xml_token_t XML_spreadMethod = 1823;
+const xml_token_t XML_spreadsheet = 1824;
+const xml_token_t XML_sql = 1825;
+const xml_token_t XML_sql_pass_through = 1826;
+const xml_token_t XML_sql_statement = 1827;
+const xml_token_t XML_sqlnull = 1828;
+const xml_token_t XML_square = 1829;
+const xml_token_t XML_stacked = 1830;
+const xml_token_t XML_stagger_even = 1831;
+const xml_token_t XML_stagger_odd = 1832;
+const xml_token_t XML_standard = 1833;
+const xml_token_t XML_standard_deviation = 1834;
+const xml_token_t XML_standard_error = 1835;
+const xml_token_t XML_star = 1836;
+const xml_token_t XML_start = 1837;
+const xml_token_t XML_start_angle = 1838;
+const xml_token_t XML_start_color = 1839;
+const xml_token_t XML_start_column = 1840;
+const xml_token_t XML_start_glue_point = 1841;
+const xml_token_t XML_start_guide = 1842;
+const xml_token_t XML_start_indent = 1843;
+const xml_token_t XML_start_intensity = 1844;
+const xml_token_t XML_start_line_spacing_horizontal = 1845;
+const xml_token_t XML_start_line_spacing_vertical = 1846;
+const xml_token_t XML_start_numbering_at = 1847;
+const xml_token_t XML_start_page = 1848;
+const xml_token_t XML_start_position = 1849;
+const xml_token_t XML_start_row = 1850;
+const xml_token_t XML_start_scale = 1851;
+const xml_token_t XML_start_shape = 1852;
+const xml_token_t XML_start_table = 1853;
+const xml_token_t XML_start_value = 1854;
+const xml_token_t XML_start_with_navigator = 1855;
+const xml_token_t XML_state = 1856;
+const xml_token_t XML_status = 1857;
+const xml_token_t XML_stay_on_top = 1858;
+const xml_token_t XML_stdev = 1859;
+const xml_token_t XML_stdevp = 1860;
+const xml_token_t XML_stemh = 1861;
+const xml_token_t XML_stemv = 1862;
+const xml_token_t XML_step = 1863;
+const xml_token_t XML_step_center_x = 1864;
+const xml_token_t XML_step_center_y = 1865;
+const xml_token_t XML_step_end = 1866;
+const xml_token_t XML_step_size = 1867;
+const xml_token_t XML_step_start = 1868;
+const xml_token_t XML_steps = 1869;
+const xml_token_t XML_stock_gain_marker = 1870;
+const xml_token_t XML_stock_loss_marker = 1871;
+const xml_token_t XML_stock_range_line = 1872;
+const xml_token_t XML_stop = 1873;
+const xml_token_t XML_stop_color = 1874;
+const xml_token_t XML_stop_opacity = 1875;
+const xml_token_t XML_straight_line = 1876;
+const xml_token_t XML_stretch = 1877;
+const xml_token_t XML_stretch_from_bottom = 1878;
+const xml_token_t XML_stretch_from_left = 1879;
+const xml_token_t XML_stretch_from_right = 1880;
+const xml_token_t XML_stretch_from_top = 1881;
+const xml_token_t XML_strict = 1882;
+const xml_token_t XML_strikethrough_position = 1883;
+const xml_token_t XML_strikethrough_thickness = 1884;
+const xml_token_t XML_string = 1885;
+const xml_token_t XML_string_value = 1886;
+const xml_token_t XML_string_value_if_false = 1887;
+const xml_token_t XML_string_value_if_true = 1888;
+const xml_token_t XML_string_value_phonetic = 1889;
+const xml_token_t XML_stripes = 1890;
+const xml_token_t XML_stroke = 1891;
+const xml_token_t XML_stroke_color = 1892;
+const xml_token_t XML_stroke_dash = 1893;
+const xml_token_t XML_stroke_dash_names = 1894;
+const xml_token_t XML_stroke_linecap = 1895;
+const xml_token_t XML_stroke_linejoin = 1896;
+const xml_token_t XML_stroke_opacity = 1897;
+const xml_token_t XML_stroke_width = 1898;
+const xml_token_t XML_struct = 1899;
+const xml_token_t XML_structure_protected = 1900;
+const xml_token_t XML_style = 1901;
+const xml_token_t XML_style_name = 1902;
+const xml_token_t XML_style_override = 1903;
+const xml_token_t XML_styles = 1904;
+const xml_token_t XML_sub = 1905;
+const xml_token_t XML_sub_item = 1906;
+const xml_token_t XML_subject = 1907;
+const xml_token_t XML_submit = 1908;
+const xml_token_t XML_subtitle = 1909;
+const xml_token_t XML_subtotal_field = 1910;
+const xml_token_t XML_subtotal_rule = 1911;
+const xml_token_t XML_subtotal_rules = 1912;
+const xml_token_t XML_subtype = 1913;
+const xml_token_t XML_suffix = 1914;
+const xml_token_t XML_sum = 1915;
+const xml_token_t XML_super = 1916;
+const xml_token_t XML_suppress_version_columns = 1917;
+const xml_token_t XML_svg = 1918;
+const xml_token_t XML_swiss = 1919;
+const xml_token_t XML_syllable_count = 1920;
+const xml_token_t XML_symbol_color = 1921;
+const xml_token_t XML_symbol_height = 1922;
+const xml_token_t XML_symbol_image = 1923;
+const xml_token_t XML_symbol_name = 1924;
+const xml_token_t XML_symbol_type = 1925;
+const xml_token_t XML_symbol_width = 1926;
+const xml_token_t XML_system = 1927;
+const xml_token_t XML_system_driver_settings = 1928;
+const xml_token_t XML_tab = 1929;
+const xml_token_t XML_tab_color = 1930;
+const xml_token_t XML_tab_cycle = 1931;
+const xml_token_t XML_tab_index = 1932;
+const xml_token_t XML_tab_ref = 1933;
+const xml_token_t XML_tab_stop = 1934;
+const xml_token_t XML_tab_stop_distance = 1935;
+const xml_token_t XML_tab_stops = 1936;
+const xml_token_t XML_table = 1937;
+const xml_token_t XML_table_background = 1938;
+const xml_token_t XML_table_cell = 1939;
+const xml_token_t XML_table_cell_properties = 1940;
+const xml_token_t XML_table_centering = 1941;
+const xml_token_t XML_table_column = 1942;
+const xml_token_t XML_table_column_group = 1943;
+const xml_token_t XML_table_column_properties = 1944;
+const xml_token_t XML_table_columns = 1945;
+const xml_token_t XML_table_count = 1946;
+const xml_token_t XML_table_definition = 1947;
+const xml_token_t XML_table_definitions = 1948;
+const xml_token_t XML_table_exclude_filter = 1949;
+const xml_token_t XML_table_fields = 1950;
+const xml_token_t XML_table_filter = 1951;
+const xml_token_t XML_table_filter_pattern = 1952;
+const xml_token_t XML_table_formula = 1953;
+const xml_token_t XML_table_header_columns = 1954;
+const xml_token_t XML_table_header_rows = 1955;
+const xml_token_t XML_table_include_filter = 1956;
+const xml_token_t XML_table_index = 1957;
+const xml_token_t XML_table_index_entry_template = 1958;
+const xml_token_t XML_table_index_source = 1959;
+const xml_token_t XML_table_name = 1960;
+const xml_token_t XML_table_of_content = 1961;
+const xml_token_t XML_table_of_content_entry_template = 1962;
+const xml_token_t XML_table_of_content_source = 1963;
+const xml_token_t XML_table_properties = 1964;
+const xml_token_t XML_table_representation = 1965;
+const xml_token_t XML_table_representations = 1966;
+const xml_token_t XML_table_row = 1967;
+const xml_token_t XML_table_row_group = 1968;
+const xml_token_t XML_table_row_properties = 1969;
+const xml_token_t XML_table_rows = 1970;
+const xml_token_t XML_table_setting = 1971;
+const xml_token_t XML_table_settings = 1972;
+const xml_token_t XML_table_source = 1973;
+const xml_token_t XML_table_template = 1974;
+const xml_token_t XML_table_type = 1975;
+const xml_token_t XML_table_type_filter = 1976;
+const xml_token_t XML_tabular_layout = 1977;
+const xml_token_t XML_target_cell_address = 1978;
+const xml_token_t XML_target_frame = 1979;
+const xml_token_t XML_target_frame_name = 1980;
+const xml_token_t XML_target_range_address = 1981;
+const xml_token_t XML_targetElement = 1982;
+const xml_token_t XML_tb = 1983;
+const xml_token_t XML_tb_lr = 1984;
+const xml_token_t XML_tb_rl = 1985;
+const xml_token_t XML_techreport = 1986;
+const xml_token_t XML_template = 1987;
+const xml_token_t XML_template_name = 1988;
+const xml_token_t XML_text = 1989;
+const xml_token_t XML_text_align = 1990;
+const xml_token_t XML_text_align_last = 1991;
+const xml_token_t XML_text_align_source = 1992;
+const xml_token_t XML_text_areas = 1993;
+const xml_token_t XML_text_autospace = 1994;
+const xml_token_t XML_text_blinking = 1995;
+const xml_token_t XML_text_box = 1996;
+const xml_token_t XML_text_combine = 1997;
+const xml_token_t XML_text_combine_end_char = 1998;
+const xml_token_t XML_text_combine_start_char = 1999;
+const xml_token_t XML_text_content = 2000;
+const xml_token_t XML_text_emphasize = 2001;
+const xml_token_t XML_text_indent = 2002;
+const xml_token_t XML_text_input = 2003;
+const xml_token_t XML_text_line_through_color = 2004;
+const xml_token_t XML_text_line_through_mode = 2005;
+const xml_token_t XML_text_line_through_style = 2006;
+const xml_token_t XML_text_line_through_text = 2007;
+const xml_token_t XML_text_line_through_text_style = 2008;
+const xml_token_t XML_text_line_through_type = 2009;
+const xml_token_t XML_text_line_through_width = 2010;
+const xml_token_t XML_text_outline = 2011;
+const xml_token_t XML_text_overlap = 2012;
+const xml_token_t XML_text_overline_color = 2013;
+const xml_token_t XML_text_overline_mode = 2014;
+const xml_token_t XML_text_overline_style = 2015;
+const xml_token_t XML_text_overline_type = 2016;
+const xml_token_t XML_text_overline_width = 2017;
+const xml_token_t XML_text_path = 2018;
+const xml_token_t XML_text_path_allowed = 2019;
+const xml_token_t XML_text_path_mode = 2020;
+const xml_token_t XML_text_path_same_letter_heights = 2021;
+const xml_token_t XML_text_path_scale = 2022;
+const xml_token_t XML_text_position = 2023;
+const xml_token_t XML_text_properties = 2024;
+const xml_token_t XML_text_rotate_angle = 2025;
+const xml_token_t XML_text_rotation_angle = 2026;
+const xml_token_t XML_text_rotation_scale = 2027;
+const xml_token_t XML_text_scale = 2028;
+const xml_token_t XML_text_shadow = 2029;
+const xml_token_t XML_text_style = 2030;
+const xml_token_t XML_text_style_name = 2031;
+const xml_token_t XML_text_transform = 2032;
+const xml_token_t XML_text_underline_color = 2033;
+const xml_token_t XML_text_underline_mode = 2034;
+const xml_token_t XML_text_underline_style = 2035;
+const xml_token_t XML_text_underline_type = 2036;
+const xml_token_t XML_text_underline_width = 2037;
+const xml_token_t XML_textarea = 2038;
+const xml_token_t XML_textarea_horizontal_align = 2039;
+const xml_token_t XML_textarea_vertical_align = 2040;
+const xml_token_t XML_textual = 2041;
+const xml_token_t XML_texture_filter = 2042;
+const xml_token_t XML_texture_generation_mode_x = 2043;
+const xml_token_t XML_texture_generation_mode_y = 2044;
+const xml_token_t XML_texture_kind = 2045;
+const xml_token_t XML_texture_mode = 2046;
+const xml_token_t XML_thick = 2047;
+const xml_token_t XML_thin = 2048;
+const xml_token_t XML_thousand = 2049;
+const xml_token_t XML_three_dimensional = 2050;
+const xml_token_t XML_thumbnail = 2051;
+const xml_token_t XML_tick_mark_position = 2052;
+const xml_token_t XML_tick_marks_major_inner = 2053;
+const xml_token_t XML_tick_marks_major_outer = 2054;
+const xml_token_t XML_tick_marks_minor_inner = 2055;
+const xml_token_t XML_tick_marks_minor_outer = 2056;
+const xml_token_t XML_tile_repeat_offset = 2057;
+const xml_token_t XML_time = 2058;
+const xml_token_t XML_time_adjust = 2059;
+const xml_token_t XML_time_style = 2060;
+const xml_token_t XML_time_value = 2061;
+const xml_token_t XML_timestmp = 2062;
+const xml_token_t XML_timing_root = 2063;
+const xml_token_t XML_tinyint = 2064;
+const xml_token_t XML_title = 2065;
+const xml_token_t XML_to = 2066;
+const xml_token_t XML_to_another_table = 2067;
+const xml_token_t XML_to_bottom = 2068;
+const xml_token_t XML_to_center = 2069;
+const xml_token_t XML_to_left = 2070;
+const xml_token_t XML_to_lower_left = 2071;
+const xml_token_t XML_to_lower_right = 2072;
+const xml_token_t XML_to_right = 2073;
+const xml_token_t XML_to_top = 2074;
+const xml_token_t XML_to_upper_left = 2075;
+const xml_token_t XML_to_upper_right = 2076;
+const xml_token_t XML_toc_mark = 2077;
+const xml_token_t XML_toc_mark_end = 2078;
+const xml_token_t XML_toc_mark_start = 2079;
+const xml_token_t XML_toggle = 2080;
+const xml_token_t XML_top = 2081;
+const xml_token_t XML_top_end = 2082;
+const xml_token_t XML_top_left = 2083;
+const xml_token_t XML_top_right = 2084;
+const xml_token_t XML_top_start = 2085;
+const xml_token_t XML_total_percentage = 2086;
+const xml_token_t XML_trace_dependents = 2087;
+const xml_token_t XML_trace_errors = 2088;
+const xml_token_t XML_trace_precedents = 2089;
+const xml_token_t XML_track_changes = 2090;
+const xml_token_t XML_tracked_changes = 2091;
+const xml_token_t XML_transform = 2092;
+const xml_token_t XML_transformation = 2093;
+const xml_token_t XML_transition = 2094;
+const xml_token_t XML_transition_on_click = 2095;
+const xml_token_t XML_transition_speed = 2096;
+const xml_token_t XML_transition_style = 2097;
+const xml_token_t XML_transition_type = 2098;
+const xml_token_t XML_transitionFilter = 2099;
+const xml_token_t XML_translate = 2100;
+const xml_token_t XML_transliteration_country = 2101;
+const xml_token_t XML_transliteration_format = 2102;
+const xml_token_t XML_transliteration_language = 2103;
+const xml_token_t XML_transliteration_style = 2104;
+const xml_token_t XML_transparent = 2105;
+const xml_token_t XML_treat_empty_cells = 2106;
+const xml_token_t XML_triple = 2107;
+const xml_token_t XML_true = 2108;
+const xml_token_t XML_truncate_on_overflow = 2109;
+const xml_token_t XML_ttb = 2110;
+const xml_token_t XML_type = 2111;
+const xml_token_t XML_type_name = 2112;
+const xml_token_t XML_ultra_condensed = 2113;
+const xml_token_t XML_ultra_expanded = 2114;
+const xml_token_t XML_unchecked = 2115;
+const xml_token_t XML_uncover_to_bottom = 2116;
+const xml_token_t XML_uncover_to_left = 2117;
+const xml_token_t XML_uncover_to_lowerleft = 2118;
+const xml_token_t XML_uncover_to_lowerright = 2119;
+const xml_token_t XML_uncover_to_right = 2120;
+const xml_token_t XML_uncover_to_top = 2121;
+const xml_token_t XML_uncover_to_upperleft = 2122;
+const xml_token_t XML_uncover_to_upperright = 2123;
+const xml_token_t XML_underline_position = 2124;
+const xml_token_t XML_underline_thickness = 2125;
+const xml_token_t XML_unicode_range = 2126;
+const xml_token_t XML_unique = 2127;
+const xml_token_t XML_unit = 2128;
+const xml_token_t XML_units_per_em = 2129;
+const xml_token_t XML_unknown = 2130;
+const xml_token_t XML_unpublished = 2131;
+const xml_token_t XML_unsorted = 2132;
+const xml_token_t XML_up = 2133;
+const xml_token_t XML_update_rule = 2134;
+const xml_token_t XML_update_table = 2135;
+const xml_token_t XML_uppercase = 2136;
+const xml_token_t XML_url = 2137;
+const xml_token_t XML_use_banding_columns_styles = 2138;
+const xml_token_t XML_use_banding_rows_styles = 2139;
+const xml_token_t XML_use_caption = 2140;
+const xml_token_t XML_use_catalog = 2141;
+const xml_token_t XML_use_chart_objects = 2142;
+const xml_token_t XML_use_date_time_name = 2143;
+const xml_token_t XML_use_draw_objects = 2144;
+const xml_token_t XML_use_first_column_styles = 2145;
+const xml_token_t XML_use_first_row_styles = 2146;
+const xml_token_t XML_use_floating_frames = 2147;
+const xml_token_t XML_use_footer_name = 2148;
+const xml_token_t XML_use_graphics = 2149;
+const xml_token_t XML_use_header_name = 2150;
+const xml_token_t XML_use_index_marks = 2151;
+const xml_token_t XML_use_index_source_styles = 2152;
+const xml_token_t XML_use_keys_as_entries = 2153;
+const xml_token_t XML_use_labels = 2154;
+const xml_token_t XML_use_last_column_styles = 2155;
+const xml_token_t XML_use_last_row_styles = 2156;
+const xml_token_t XML_use_math_objects = 2157;
+const xml_token_t XML_use_objects = 2158;
+const xml_token_t XML_use_optimal_column_width = 2159;
+const xml_token_t XML_use_optimal_row_height = 2160;
+const xml_token_t XML_use_other_objects = 2161;
+const xml_token_t XML_use_outline_level = 2162;
+const xml_token_t XML_use_regular_expressions = 2163;
+const xml_token_t XML_use_soft_page_breaks = 2164;
+const xml_token_t XML_use_spreadsheet_objects = 2165;
+const xml_token_t XML_use_system_user = 2166;
+const xml_token_t XML_use_tables = 2167;
+const xml_token_t XML_use_wildcards = 2168;
+const xml_token_t XML_use_window_font_color = 2169;
+const xml_token_t XML_use_zero = 2170;
+const xml_token_t XML_used_hierarchy = 2171;
+const xml_token_t XML_user_defined = 2172;
+const xml_token_t XML_user_field_decl = 2173;
+const xml_token_t XML_user_field_decls = 2174;
+const xml_token_t XML_user_field_get = 2175;
+const xml_token_t XML_user_field_input = 2176;
+const xml_token_t XML_user_index = 2177;
+const xml_token_t XML_user_index_entry_template = 2178;
+const xml_token_t XML_user_index_mark = 2179;
+const xml_token_t XML_user_index_mark_end = 2180;
+const xml_token_t XML_user_index_mark_start = 2181;
+const xml_token_t XML_user_index_source = 2182;
+const xml_token_t XML_user_name = 2183;
+const xml_token_t XML_user_transformed = 2184;
+const xml_token_t XML_v_alphabetic = 2185;
+const xml_token_t XML_v_hanging = 2186;
+const xml_token_t XML_v_ideographic = 2187;
+const xml_token_t XML_v_mathematical = 2188;
+const xml_token_t XML_validation = 2189;
+const xml_token_t XML_value = 2190;
+const xml_token_t XML_value_and_percentage = 2191;
+const xml_token_t XML_value_list = 2192;
+const xml_token_t XML_value_range = 2193;
+const xml_token_t XML_value_type = 2194;
+const xml_token_t XML_values = 2195;
+const xml_token_t XML_values_cell_range_address = 2196;
+const xml_token_t XML_var = 2197;
+const xml_token_t XML_varbinary = 2198;
+const xml_token_t XML_varchar = 2199;
+const xml_token_t XML_variable = 2200;
+const xml_token_t XML_variable_decl = 2201;
+const xml_token_t XML_variable_decls = 2202;
+const xml_token_t XML_variable_get = 2203;
+const xml_token_t XML_variable_input = 2204;
+const xml_token_t XML_variable_set = 2205;
+const xml_token_t XML_variance = 2206;
+const xml_token_t XML_varp = 2207;
+const xml_token_t XML_verb = 2208;
+const xml_token_t XML_version = 2209;
+const xml_token_t XML_vertical = 2210;
+const xml_token_t XML_vertical_align = 2211;
+const xml_token_t XML_vertical_bar = 2212;
+const xml_token_t XML_vertical_checkerboard = 2213;
+const xml_token_t XML_vertical_lines = 2214;
+const xml_token_t XML_vertical_pos = 2215;
+const xml_token_t XML_vertical_rel = 2216;
+const xml_token_t XML_vertical_segments = 2217;
+const xml_token_t XML_vertical_stripes = 2218;
+const xml_token_t XML_viewBox = 2219;
+const xml_token_t XML_visibility = 2220;
+const xml_token_t XML_visible = 2221;
+const xml_token_t XML_visible_area_height = 2222;
+const xml_token_t XML_visible_area_left = 2223;
+const xml_token_t XML_visible_area_top = 2224;
+const xml_token_t XML_visible_area_width = 2225;
+const xml_token_t XML_visited_style_name = 2226;
+const xml_token_t XML_visual_effect = 2227;
+const xml_token_t XML_void = 2228;
+const xml_token_t XML_volatile = 2229;
+const xml_token_t XML_volume = 2230;
+const xml_token_t XML_vpn = 2231;
+const xml_token_t XML_vrp = 2232;
+const xml_token_t XML_vup = 2233;
+const xml_token_t XML_wall = 2234;
+const xml_token_t XML_warning = 2235;
+const xml_token_t XML_watermark = 2236;
+const xml_token_t XML_wave = 2237;
+const xml_token_t XML_wavyline = 2238;
+const xml_token_t XML_wavyline_from_bottom = 2239;
+const xml_token_t XML_wavyline_from_left = 2240;
+const xml_token_t XML_wavyline_from_right = 2241;
+const xml_token_t XML_wavyline_from_top = 2242;
+const xml_token_t XML_week_of_year = 2243;
+const xml_token_t XML_whenNotActive = 2244;
+const xml_token_t XML_wide = 2245;
+const xml_token_t XML_widows = 2246;
+const xml_token_t XML_width = 2247;
+const xml_token_t XML_widths = 2248;
+const xml_token_t XML_with_previous = 2249;
+const xml_token_t XML_word = 2250;
+const xml_token_t XML_word_count = 2251;
+const xml_token_t XML_wrap = 2252;
+const xml_token_t XML_wrap_contour = 2253;
+const xml_token_t XML_wrap_contour_mode = 2254;
+const xml_token_t XML_wrap_dynamic_threshold = 2255;
+const xml_token_t XML_wrap_influence_on_position = 2256;
+const xml_token_t XML_wrap_option = 2257;
+const xml_token_t XML_writing_mode = 2258;
+const xml_token_t XML_writing_mode_automatic = 2259;
+const xml_token_t XML_www = 2260;
+const xml_token_t XML_x = 2261;
+const xml_token_t XML_x_height = 2262;
+const xml_token_t XML_x1 = 2263;
+const xml_token_t XML_x2 = 2264;
+const xml_token_t XML_xforms = 2265;
+const xml_token_t XML_xforms_list_source = 2266;
+const xml_token_t XML_xforms_submission = 2267;
+const xml_token_t XML_xhtml = 2268;
+const xml_token_t XML_xlink = 2269;
+const xml_token_t XML_xml = 2270;
+const xml_token_t XML_y = 2271;
+const xml_token_t XML_y1 = 2272;
+const xml_token_t XML_y2 = 2273;
+const xml_token_t XML_year = 2274;
+const xml_token_t XML_years = 2275;
+const xml_token_t XML_z = 2276;
+const xml_token_t XML_z_index = 2277;
+const xml_token_t XML_zero_values = 2278;
diff --git a/src/liborcus/odf_tokens.cpp b/src/liborcus/odf_tokens.cpp
new file mode 100644
index 0000000..b20414d
--- /dev/null
+++ b/src/liborcus/odf_tokens.cpp
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "odf_tokens.hpp"
+
+namespace orcus {
+
+namespace {
+
+#include "odf_tokens.inl"
+
+}
+
+tokens odf_tokens = tokens(token_names, token_name_count);
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_tokens.hpp b/src/liborcus/odf_tokens.hpp
new file mode 100644
index 0000000..db1befa
--- /dev/null
+++ b/src/liborcus/odf_tokens.hpp
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_ODF_TOKENS_HPP__
+#define __ORCUS_ODF_TOKENS_HPP__
+
+#include "orcus/tokens.hpp"
+
+namespace orcus {
+
+/**
+ * Singleton instance containing all ODF tokens.
+ */
+extern tokens odf_tokens;
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/odf_tokens.inl b/src/liborcus/odf_tokens.inl
new file mode 100644
index 0000000..623c721
--- /dev/null
+++ b/src/liborcus/odf_tokens.inl
@@ -0,0 +1,2285 @@
+// This file has been auto-generated. Do not hand-edit this.
+
+const char* token_names[] = {
+ "??", // 0
+ "0", // 1
+ "0deg", // 2
+ "0grad", // 3
+ "0rad", // 4
+ "1", // 5
+ "1.3", // 6
+ "100", // 7
+ "2", // 8
+ "200", // 9
+ "3", // 10
+ "300", // 11
+ "3d", // 12
+ "400", // 13
+ "500", // 14
+ "600", // 15
+ "700", // 16
+ "800", // 17
+ "900", // 18
+ "A", // 19
+ "I", // 20
+ "ROC", // 21
+ "_blank", // 22
+ "_parent", // 23
+ "_self", // 24
+ "_top", // 25
+ "a", // 26
+ "about", // 27
+ "above", // 28
+ "accelerate", // 29
+ "accent", // 30
+ "accent-height", // 31
+ "acceptance-state", // 32
+ "accepted", // 33
+ "accumulate", // 34
+ "action", // 35
+ "active", // 36
+ "actuate", // 37
+ "add-empty-lines", // 38
+ "additional-column-statement", // 39
+ "additive", // 40
+ "address", // 41
+ "adjustment", // 42
+ "after-previous", // 43
+ "algorithm", // 44
+ "align", // 45
+ "all", // 46
+ "allow-deletes", // 47
+ "allow-empty-cell", // 48
+ "allow-inserts", // 49
+ "allow-updates", // 50
+ "alpha-numeric", // 51
+ "alphabetic", // 52
+ "alphabetical-index", // 53
+ "alphabetical-index-auto-mark-file", // 54
+ "alphabetical-index-entry-template", // 55
+ "alphabetical-index-mark", // 56
+ "alphabetical-index-mark-end", // 57
+ "alphabetical-index-mark-start", // 58
+ "alphabetical-index-source", // 59
+ "alphabetical-separators", // 60
+ "alternate", // 61
+ "always", // 62
+ "am-pm", // 63
+ "ambient-color", // 64
+ "anchor-page-number", // 65
+ "anchor-type", // 66
+ "angle", // 67
+ "angle-offset", // 68
+ "angled-connector-line", // 69
+ "angled-line", // 70
+ "anim", // 71
+ "animate", // 72
+ "animateColor", // 73
+ "animateMotion", // 74
+ "animateTransform", // 75
+ "animation", // 76
+ "animation-delay", // 77
+ "animation-direction", // 78
+ "animation-group", // 79
+ "animation-repeat", // 80
+ "animation-start-inside", // 81
+ "animation-steps", // 82
+ "animation-stop-inside", // 83
+ "animations", // 84
+ "annotation", // 85
+ "annotation-end", // 86
+ "annotations", // 87
+ "annote", // 88
+ "appear", // 89
+ "append-table-alias-name", // 90
+ "applet", // 91
+ "application-connection-settings", // 92
+ "application-data", // 93
+ "apply-command", // 94
+ "apply-design-mode", // 95
+ "apply-filter", // 96
+ "apply-style-name", // 97
+ "arc", // 98
+ "archive", // 99
+ "area", // 100
+ "area-circle", // 101
+ "area-polygon", // 102
+ "area-rectangle", // 103
+ "array", // 104
+ "arrow-down", // 105
+ "arrow-left", // 106
+ "arrow-right", // 107
+ "arrow-up", // 108
+ "article", // 109
+ "as-char", // 110
+ "as-template", // 111
+ "ascending", // 112
+ "ascent", // 113
+ "asian", // 114
+ "asterisk", // 115
+ "at-axis", // 116
+ "at-labels", // 117
+ "at-labels-and-axis", // 118
+ "attached-axis", // 119
+ "attractive", // 120
+ "attributeName", // 121
+ "audio", // 122
+ "audio-level", // 123
+ "author", // 124
+ "author-initials", // 125
+ "author-name", // 126
+ "auto", // 127
+ "auto-complete", // 128
+ "auto-create-new-frame", // 129
+ "auto-grow-height", // 130
+ "auto-grow-width", // 131
+ "auto-increment", // 132
+ "auto-position", // 133
+ "auto-reload", // 134
+ "auto-size", // 135
+ "auto-text-indent", // 136
+ "auto-update", // 137
+ "autoReverse", // 138
+ "automatic", // 139
+ "automatic-content", // 140
+ "automatic-find-labels", // 141
+ "automatic-focus", // 142
+ "automatic-order", // 143
+ "automatic-styles", // 144
+ "automatic-update", // 145
+ "average", // 146
+ "averaged-abscissa", // 147
+ "avoid-overlap", // 148
+ "axial", // 149
+ "axis", // 150
+ "axis-label-position", // 151
+ "axis-position", // 152
+ "b-spline", // 153
+ "back-scale", // 154
+ "backface-culling", // 155
+ "background", // 156
+ "background-color", // 157
+ "background-image", // 158
+ "background-objects-visible", // 159
+ "background-size", // 160
+ "background-transparency", // 161
+ "background-visible", // 162
+ "balanced", // 163
+ "base-cell-address", // 164
+ "base-dn", // 165
+ "base64Binary", // 166
+ "baseline", // 167
+ "bbox", // 168
+ "begin", // 169
+ "below", // 170
+ "bevel", // 171
+ "bibliography", // 172
+ "bibliography-configuration", // 173
+ "bibliography-data-field", // 174
+ "bibliography-entry-template", // 175
+ "bibliography-mark", // 176
+ "bibliography-source", // 177
+ "bibliography-type", // 178
+ "biggest", // 179
+ "bigint", // 180
+ "binary", // 181
+ "binary-data", // 182
+ "bind", // 183
+ "bind-styles-to-content", // 184
+ "bit", // 185
+ "bitmap", // 186
+ "blend", // 187
+ "blob", // 188
+ "blue", // 189
+ "body", // 190
+ "bold", // 191
+ "book", // 192
+ "booklet", // 193
+ "bookmark", // 194
+ "bookmark-end", // 195
+ "bookmark-start", // 196
+ "booktitle", // 197
+ "boolean", // 198
+ "boolean-comparison-mode", // 199
+ "boolean-style", // 200
+ "boolean-value", // 201
+ "border", // 202
+ "border-bottom", // 203
+ "border-color", // 204
+ "border-left", // 205
+ "border-line-width", // 206
+ "border-line-width-bottom", // 207
+ "border-line-width-left", // 208
+ "border-line-width-right", // 209
+ "border-line-width-top", // 210
+ "border-model", // 211
+ "border-right", // 212
+ "border-top", // 213
+ "both", // 214
+ "bottom", // 215
+ "bottom-end", // 216
+ "bottom-left", // 217
+ "bottom-right", // 218
+ "bottom-start", // 219
+ "bound-column", // 220
+ "bow-tie", // 221
+ "break-after", // 222
+ "break-before", // 223
+ "buddhist", // 224
+ "bullet-char", // 225
+ "bullet-relative-size", // 226
+ "butt", // 227
+ "button", // 228
+ "button-type", // 229
+ "buttons", // 230
+ "by", // 231
+ "c", // 232
+ "calcMode", // 233
+ "calculation-settings", // 234
+ "calendar", // 235
+ "cap-height", // 236
+ "capitalize", // 237
+ "capitalize-entries", // 238
+ "caption", // 239
+ "caption-angle", // 240
+ "caption-angle-type", // 241
+ "caption-escape", // 242
+ "caption-escape-direction", // 243
+ "caption-fit-line-length", // 244
+ "caption-gap", // 245
+ "caption-id", // 246
+ "caption-line-length", // 247
+ "caption-point-x", // 248
+ "caption-point-y", // 249
+ "caption-sequence-format", // 250
+ "caption-sequence-name", // 251
+ "caption-type", // 252
+ "cascade", // 253
+ "case-sensitive", // 254
+ "catalog-name", // 255
+ "categories", // 256
+ "category-and-value", // 257
+ "cell-address", // 258
+ "cell-content-change", // 259
+ "cell-content-deletion", // 260
+ "cell-count", // 261
+ "cell-protect", // 262
+ "cell-range", // 263
+ "cell-range-address", // 264
+ "cell-range-source", // 265
+ "center", // 266
+ "central", // 267
+ "chain-next-name", // 268
+ "change", // 269
+ "change-deletion", // 270
+ "change-end", // 271
+ "change-id", // 272
+ "change-info", // 273
+ "change-start", // 274
+ "change-track-table-cell", // 275
+ "changed-region", // 276
+ "chapter", // 277
+ "char", // 278
+ "character-count", // 279
+ "character-set", // 280
+ "chart", // 281
+ "chart-properties", // 282
+ "charts", // 283
+ "checkbox", // 284
+ "checked", // 285
+ "checkerboard", // 286
+ "circle", // 287
+ "citation-body-style-name", // 288
+ "citation-style-name", // 289
+ "class", // 290
+ "class-id", // 291
+ "class-names", // 292
+ "clip", // 293
+ "clob", // 294
+ "clockwise", // 295
+ "close", // 296
+ "close-back", // 297
+ "close-front", // 298
+ "close-horizontal", // 299
+ "close-vertical", // 300
+ "cm", // 301
+ "code", // 302
+ "collapse", // 303
+ "collapsing", // 304
+ "color", // 305
+ "color-interpolation", // 306
+ "color-interpolation-direction", // 307
+ "color-inversion", // 308
+ "color-mode", // 309
+ "column", // 310
+ "column-count", // 311
+ "column-definition", // 312
+ "column-definitions", // 313
+ "column-gap", // 314
+ "column-mapping", // 315
+ "column-name", // 316
+ "column-percentage", // 317
+ "column-sep", // 318
+ "column-width", // 319
+ "columns", // 320
+ "combine-entries", // 321
+ "combine-entries-with-dash", // 322
+ "combine-entries-with-pp", // 323
+ "combobox", // 324
+ "comma-separated", // 325
+ "command", // 326
+ "command-type", // 327
+ "comment", // 328
+ "complex", // 329
+ "component", // 330
+ "component-collection", // 331
+ "concave", // 332
+ "concentric-gradient-fill-allowed", // 333
+ "cond-style-name", // 334
+ "condensed", // 335
+ "condition", // 336
+ "condition-source", // 337
+ "condition-source-range-address", // 338
+ "conditional-text", // 339
+ "cone", // 340
+ "conference", // 341
+ "config", // 342
+ "config-item", // 343
+ "config-item-map-entry", // 344
+ "config-item-map-indexed", // 345
+ "config-item-map-named", // 346
+ "config-item-set", // 347
+ "connect-bars", // 348
+ "connection-data", // 349
+ "connection-name", // 350
+ "connection-resource", // 351
+ "connector", // 352
+ "consecutive-numbering", // 353
+ "consolidation", // 354
+ "constant", // 355
+ "contains-error", // 356
+ "contains-header", // 357
+ "content", // 358
+ "content-validation", // 359
+ "content-validation-name", // 360
+ "content-validations", // 361
+ "contextual-spacing", // 362
+ "continue", // 363
+ "continue-list", // 364
+ "continue-numbering", // 365
+ "continuous", // 366
+ "contour-path", // 367
+ "contour-polygon", // 368
+ "contrast", // 369
+ "control", // 370
+ "control-implementation", // 371
+ "conversion-mode", // 372
+ "convert-empty-to-null", // 373
+ "coordinate-region", // 374
+ "copy-all", // 375
+ "copy-back", // 376
+ "copy-formulas", // 377
+ "copy-of", // 378
+ "copy-outline-levels", // 379
+ "copy-results-only", // 380
+ "copy-styles", // 381
+ "corner-radius", // 382
+ "corners", // 383
+ "correct", // 384
+ "count", // 385
+ "count-empty-lines", // 386
+ "count-in-text-boxes", // 387
+ "counter-clockwise", // 388
+ "counterclockwise", // 389
+ "countnums", // 390
+ "country", // 391
+ "country-asian", // 392
+ "country-complex", // 393
+ "covered-table-cell", // 394
+ "creation-date", // 395
+ "creation-time", // 396
+ "creator", // 397
+ "creator-initials", // 398
+ "cube", // 399
+ "cubic-spline", // 400
+ "cuboid", // 401
+ "currency", // 402
+ "currency-style", // 403
+ "currency-symbol", // 404
+ "current", // 405
+ "current-date", // 406
+ "current-selected", // 407
+ "current-state", // 408
+ "current-value", // 409
+ "curve", // 410
+ "custom", // 411
+ "custom-shape", // 412
+ "custom1", // 413
+ "custom2", // 414
+ "custom3", // 415
+ "custom4", // 416
+ "custom5", // 417
+ "cut", // 418
+ "cut-offs", // 419
+ "cx", // 420
+ "cy", // 421
+ "cylinder", // 422
+ "d", // 423
+ "dash", // 424
+ "dashed", // 425
+ "data", // 426
+ "data-cell-range-address", // 427
+ "data-field", // 428
+ "data-label", // 429
+ "data-label-number", // 430
+ "data-label-series", // 431
+ "data-label-symbol", // 432
+ "data-label-text", // 433
+ "data-pilot-display-info", // 434
+ "data-pilot-field", // 435
+ "data-pilot-field-reference", // 436
+ "data-pilot-group", // 437
+ "data-pilot-group-member", // 438
+ "data-pilot-groups", // 439
+ "data-pilot-layout-info", // 440
+ "data-pilot-level", // 441
+ "data-pilot-member", // 442
+ "data-pilot-members", // 443
+ "data-pilot-sort-info", // 444
+ "data-pilot-subtotal", // 445
+ "data-pilot-subtotals", // 446
+ "data-pilot-table", // 447
+ "data-pilot-tables", // 448
+ "data-point", // 449
+ "data-source", // 450
+ "data-source-has-labels", // 451
+ "data-source-setting", // 452
+ "data-source-setting-is-list", // 453
+ "data-source-setting-name", // 454
+ "data-source-setting-type", // 455
+ "data-source-setting-value", // 456
+ "data-source-settings", // 457
+ "data-style-name", // 458
+ "data-type", // 459
+ "database", // 460
+ "database-description", // 461
+ "database-display", // 462
+ "database-name", // 463
+ "database-next", // 464
+ "database-range", // 465
+ "database-ranges", // 466
+ "database-row-number", // 467
+ "database-row-select", // 468
+ "database-source-query", // 469
+ "database-source-sql", // 470
+ "database-source-table", // 471
+ "database-table-name", // 472
+ "datasource", // 473
+ "datatype", // 474
+ "date", // 475
+ "date-adjust", // 476
+ "date-end", // 477
+ "date-start", // 478
+ "date-string", // 479
+ "date-style", // 480
+ "date-time", // 481
+ "date-time-decl", // 482
+ "date-value", // 483
+ "datetime", // 484
+ "day", // 485
+ "day-of-week", // 486
+ "days", // 487
+ "db", // 488
+ "dc", // 489
+ "dde-application", // 490
+ "dde-connection", // 491
+ "dde-connection-decl", // 492
+ "dde-connection-decls", // 493
+ "dde-item", // 494
+ "dde-link", // 495
+ "dde-links", // 496
+ "dde-source", // 497
+ "dde-topic", // 498
+ "decelerate", // 499
+ "decimal", // 500
+ "decimal-places", // 501
+ "decimal-replacement", // 502
+ "decorative", // 503
+ "deep", // 504
+ "default", // 505
+ "default-button", // 506
+ "default-cell-style-name", // 507
+ "default-outline-level", // 508
+ "default-page-layout", // 509
+ "default-row-style-name", // 510
+ "default-style", // 511
+ "default-style-name", // 512
+ "definition-src", // 513
+ "delay", // 514
+ "delay-for-repeat", // 515
+ "delete-rule", // 516
+ "deletion", // 517
+ "deletions", // 518
+ "delimiter", // 519
+ "denominator-value", // 520
+ "dependencies", // 521
+ "dependency", // 522
+ "depth", // 523
+ "desc", // 524
+ "descending", // 525
+ "descent", // 526
+ "description", // 527
+ "detail-fields", // 528
+ "detective", // 529
+ "diagonal-bl-tr", // 530
+ "diagonal-bl-tr-widths", // 531
+ "diagonal-tl-br", // 532
+ "diagonal-tl-br-widths", // 533
+ "diamond", // 534
+ "diffuse-color", // 535
+ "dim", // 536
+ "dimension", // 537
+ "direction", // 538
+ "disable", // 539
+ "disabled", // 540
+ "disc", // 541
+ "discrete", // 542
+ "display", // 543
+ "display-border", // 544
+ "display-date-time", // 545
+ "display-duplicates", // 546
+ "display-equation", // 547
+ "display-factor", // 548
+ "display-filter-buttons", // 549
+ "display-footer", // 550
+ "display-header", // 551
+ "display-label", // 552
+ "display-levels", // 553
+ "display-list", // 554
+ "display-member-mode", // 555
+ "display-name", // 556
+ "display-outline-level", // 557
+ "display-page-number", // 558
+ "display-r-square", // 559
+ "dissolve", // 560
+ "distance", // 561
+ "distance-after-sep", // 562
+ "distance-before-sep", // 563
+ "distinct", // 564
+ "distribute-letter", // 565
+ "distribute-space", // 566
+ "document", // 567
+ "document-content", // 568
+ "document-meta", // 569
+ "document-settings", // 570
+ "document-statistic", // 571
+ "document-styles", // 572
+ "domain", // 573
+ "dont-balance-text-columns", // 574
+ "dot", // 575
+ "dot-dash", // 576
+ "dot-dashed", // 577
+ "dot-dot-dash", // 578
+ "dots1", // 579
+ "dots1-length", // 580
+ "dots2", // 581
+ "dots2-length", // 582
+ "dotted", // 583
+ "double", // 584
+ "double-sided", // 585
+ "down", // 586
+ "dr3d", // 587
+ "draft", // 588
+ "draw", // 589
+ "draw-aspect", // 590
+ "draw-count", // 591
+ "drawing", // 592
+ "drawing-page", // 593
+ "drawing-page-properties", // 594
+ "drawings", // 595
+ "drill-down-on-double-click", // 596
+ "driver-settings", // 597
+ "drop-cap", // 598
+ "drop-down", // 599
+ "dropdown", // 600
+ "dur", // 601
+ "duration", // 602
+ "dynamic", // 603
+ "dynamic-spacing", // 604
+ "echo-char", // 605
+ "edge-rounding", // 606
+ "edge-rounding-mode", // 607
+ "editable", // 608
+ "editing-cycles", // 609
+ "editing-duration", // 610
+ "edition", // 611
+ "editor", // 612
+ "effect", // 613
+ "ellipse", // 614
+ "ellipsoid", // 615
+ "email", // 616
+ "embed", // 617
+ "embedded-number-behavior", // 618
+ "embedded-text", // 619
+ "embossed", // 620
+ "emissive-color", // 621
+ "emphasis", // 622
+ "enable", // 623
+ "enable-sql92-check", // 624
+ "enabled", // 625
+ "encoding", // 626
+ "enctype", // 627
+ "end", // 628
+ "end-angle", // 629
+ "end-cell-address", // 630
+ "end-color", // 631
+ "end-column", // 632
+ "end-glue-point", // 633
+ "end-guide", // 634
+ "end-indent", // 635
+ "end-intensity", // 636
+ "end-line-spacing-horizontal", // 637
+ "end-line-spacing-vertical", // 638
+ "end-position", // 639
+ "end-row", // 640
+ "end-shape", // 641
+ "end-table", // 642
+ "end-x", // 643
+ "end-y", // 644
+ "endless", // 645
+ "endnote", // 646
+ "endsync", // 647
+ "engine", // 648
+ "engraved", // 649
+ "enhanced-geometry", // 650
+ "enhanced-path", // 651
+ "entrance", // 652
+ "equal-boolean", // 653
+ "equal-integer", // 654
+ "equal-use-only-zero", // 655
+ "equation", // 656
+ "era", // 657
+ "error-category", // 658
+ "error-indicator", // 659
+ "error-lower-indicator", // 660
+ "error-lower-limit", // 661
+ "error-lower-range", // 662
+ "error-macro", // 663
+ "error-margin", // 664
+ "error-message", // 665
+ "error-percentage", // 666
+ "error-upper-indicator", // 667
+ "error-upper-limit", // 668
+ "error-upper-range", // 669
+ "escape-direction", // 670
+ "escape-processing", // 671
+ "even-columns", // 672
+ "even-rows", // 673
+ "evenodd", // 674
+ "event-listener", // 675
+ "event-listeners", // 676
+ "event-name", // 677
+ "execute", // 678
+ "execute-macro", // 679
+ "exit", // 680
+ "expanded", // 681
+ "exponent-interval", // 682
+ "exponential", // 683
+ "expression", // 684
+ "extension", // 685
+ "extra-condensed", // 686
+ "extra-expanded", // 687
+ "extrude", // 688
+ "extrusion", // 689
+ "extrusion-allowed", // 690
+ "extrusion-brightness", // 691
+ "extrusion-color", // 692
+ "extrusion-depth", // 693
+ "extrusion-diffusion", // 694
+ "extrusion-first-light-direction", // 695
+ "extrusion-first-light-harsh", // 696
+ "extrusion-first-light-level", // 697
+ "extrusion-light-face", // 698
+ "extrusion-metal", // 699
+ "extrusion-number-of-line-segments", // 700
+ "extrusion-origin", // 701
+ "extrusion-rotation-angle", // 702
+ "extrusion-rotation-center", // 703
+ "extrusion-second-light-direction", // 704
+ "extrusion-second-light-harsh", // 705
+ "extrusion-second-light-level", // 706
+ "extrusion-shininess", // 707
+ "extrusion-skew", // 708
+ "extrusion-specularity", // 709
+ "extrusion-viewpoint", // 710
+ "fade", // 711
+ "fade-from-bottom", // 712
+ "fade-from-center", // 713
+ "fade-from-left", // 714
+ "fade-from-lowerleft", // 715
+ "fade-from-lowerright", // 716
+ "fade-from-right", // 717
+ "fade-from-top", // 718
+ "fade-from-upperleft", // 719
+ "fade-from-upperright", // 720
+ "fade-out", // 721
+ "fade-to-center", // 722
+ "fadeColor", // 723
+ "false", // 724
+ "family", // 725
+ "fast", // 726
+ "field", // 727
+ "field-name", // 728
+ "field-number", // 729
+ "file", // 730
+ "file-based-database", // 731
+ "file-name", // 732
+ "fill", // 733
+ "fill-character", // 734
+ "fill-color", // 735
+ "fill-gradient-name", // 736
+ "fill-hatch-name", // 737
+ "fill-hatch-solid", // 738
+ "fill-image", // 739
+ "fill-image-height", // 740
+ "fill-image-name", // 741
+ "fill-image-ref-point", // 742
+ "fill-image-ref-point-x", // 743
+ "fill-image-ref-point-y", // 744
+ "fill-image-width", // 745
+ "fill-rule", // 746
+ "fillDefault", // 747
+ "filter", // 748
+ "filter-and", // 749
+ "filter-condition", // 750
+ "filter-name", // 751
+ "filter-options", // 752
+ "filter-or", // 753
+ "filter-set-item", // 754
+ "filter-statement", // 755
+ "first", // 756
+ "first-column", // 757
+ "first-page", // 758
+ "first-page-number", // 759
+ "first-row", // 760
+ "first-row-end-column", // 761
+ "first-row-start-column", // 762
+ "fit-to-contour", // 763
+ "fit-to-size", // 764
+ "fix", // 765
+ "fixed", // 766
+ "fixed-text", // 767
+ "flat", // 768
+ "float", // 769
+ "floating-frame", // 770
+ "floor", // 771
+ "flow-with-text", // 772
+ "fly-away", // 773
+ "fo", // 774
+ "focal-length", // 775
+ "focus-on-click", // 776
+ "font-adornments", // 777
+ "font-charset", // 778
+ "font-charset-asian", // 779
+ "font-charset-complex", // 780
+ "font-color", // 781
+ "font-face", // 782
+ "font-face-decls", // 783
+ "font-face-format", // 784
+ "font-face-name", // 785
+ "font-face-src", // 786
+ "font-face-uri", // 787
+ "font-family", // 788
+ "font-family-asian", // 789
+ "font-family-complex", // 790
+ "font-family-generic", // 791
+ "font-family-generic-asian", // 792
+ "font-family-generic-complex", // 793
+ "font-independent-line-spacing", // 794
+ "font-name", // 795
+ "font-name-asian", // 796
+ "font-name-complex", // 797
+ "font-pitch", // 798
+ "font-pitch-asian", // 799
+ "font-pitch-complex", // 800
+ "font-relief", // 801
+ "font-size", // 802
+ "font-size-asian", // 803
+ "font-size-complex", // 804
+ "font-size-rel", // 805
+ "font-size-rel-asian", // 806
+ "font-size-rel-complex", // 807
+ "font-stretch", // 808
+ "font-style", // 809
+ "font-style-asian", // 810
+ "font-style-complex", // 811
+ "font-style-name", // 812
+ "font-style-name-asian", // 813
+ "font-style-name-complex", // 814
+ "font-variant", // 815
+ "font-weight", // 816
+ "font-weight-asian", // 817
+ "font-weight-complex", // 818
+ "footer", // 819
+ "footer-decl", // 820
+ "footer-first", // 821
+ "footer-left", // 822
+ "footer-style", // 823
+ "footnote", // 824
+ "footnote-max-height", // 825
+ "footnote-sep", // 826
+ "footnotes-position", // 827
+ "for", // 828
+ "force-manual", // 829
+ "forced-exponent-sign", // 830
+ "foreground", // 831
+ "foreign", // 832
+ "form", // 833
+ "format-change", // 834
+ "format-source", // 835
+ "formatted-text", // 836
+ "forms", // 837
+ "formula", // 838
+ "formula-hidden", // 839
+ "formulas", // 840
+ "forward", // 841
+ "fraction", // 842
+ "frame", // 843
+ "frame-content", // 844
+ "frame-count", // 845
+ "frame-display-border", // 846
+ "frame-display-scrollbar", // 847
+ "frame-end-margin", // 848
+ "frame-margin-horizontal", // 849
+ "frame-margin-vertical", // 850
+ "frame-name", // 851
+ "frame-start-margin", // 852
+ "free", // 853
+ "freeze", // 854
+ "from", // 855
+ "from-another-table", // 856
+ "from-bottom", // 857
+ "from-center", // 858
+ "from-inside", // 859
+ "from-left", // 860
+ "from-lower-left", // 861
+ "from-lower-right", // 862
+ "from-right", // 863
+ "from-same-table", // 864
+ "from-top", // 865
+ "from-upper-left", // 866
+ "from-upper-right", // 867
+ "ft", // 868
+ "full", // 869
+ "full-screen", // 870
+ "function", // 871
+ "fx", // 872
+ "fy", // 873
+ "g", // 874
+ "gamma", // 875
+ "gap", // 876
+ "gap-width", // 877
+ "generator", // 878
+ "generic-control", // 879
+ "gengou", // 880
+ "get", // 881
+ "global", // 882
+ "glue-point", // 883
+ "glue-point-leaving-directions", // 884
+ "glue-point-type", // 885
+ "glue-points", // 886
+ "glyph-orientation-vertical", // 887
+ "gouraud", // 888
+ "gradient", // 889
+ "gradient-step-count", // 890
+ "gradientTransform", // 891
+ "gradientUnits", // 892
+ "grand-total", // 893
+ "graphic", // 894
+ "graphic-properties", // 895
+ "grddl", // 896
+ "green", // 897
+ "gregorian", // 898
+ "greyscale", // 899
+ "grid", // 900
+ "group-bars-per-axis", // 901
+ "group-by-field-number", // 902
+ "group-id", // 903
+ "grouped-by", // 904
+ "grouping", // 905
+ "guide-distance", // 906
+ "guide-overhang", // 907
+ "h", // 908
+ "handle", // 909
+ "handle-mirror-horizontal", // 910
+ "handle-mirror-vertical", // 911
+ "handle-polar", // 912
+ "handle-position", // 913
+ "handle-radius-range-maximum", // 914
+ "handle-radius-range-minimum", // 915
+ "handle-range-x-maximum", // 916
+ "handle-range-x-minimum", // 917
+ "handle-range-y-maximum", // 918
+ "handle-range-y-minimum", // 919
+ "handle-switched", // 920
+ "handout", // 921
+ "handout-master", // 922
+ "hanging", // 923
+ "hanja", // 924
+ "hanja_yoil", // 925
+ "has-persistent-data", // 926
+ "hatch", // 927
+ "header", // 928
+ "header-decl", // 929
+ "header-first", // 930
+ "header-footer-properties", // 931
+ "header-left", // 932
+ "header-style", // 933
+ "headers", // 934
+ "height", // 935
+ "help-message", // 936
+ "hidden", // 937
+ "hidden-and-protected", // 938
+ "hidden-paragraph", // 939
+ "hidden-text", // 940
+ "hide", // 941
+ "hide-shape", // 942
+ "hide-text", // 943
+ "high", // 944
+ "highlighted-range", // 945
+ "hijri", // 946
+ "hold", // 947
+ "hole-size", // 948
+ "horizontal", // 949
+ "horizontal-bar", // 950
+ "horizontal-checkerboard", // 951
+ "horizontal-lines", // 952
+ "horizontal-on-even", // 953
+ "horizontal-on-odd", // 954
+ "horizontal-pos", // 955
+ "horizontal-rel", // 956
+ "horizontal-segments", // 957
+ "horizontal-stripes", // 958
+ "hostname", // 959
+ "hourglass", // 960
+ "hours", // 961
+ "howpublished", // 962
+ "href", // 963
+ "hsl", // 964
+ "hyperlink-behaviour", // 965
+ "hyphenate", // 966
+ "hyphenation-keep", // 967
+ "hyphenation-ladder-count", // 968
+ "hyphenation-push-char-count", // 969
+ "hyphenation-remain-char-count", // 970
+ "i", // 971
+ "icon", // 972
+ "id", // 973
+ "identifier", // 974
+ "identify-categories", // 975
+ "ideograph-alpha", // 976
+ "ideographic", // 977
+ "ignore", // 978
+ "ignore-case", // 979
+ "ignore-driver-privileges", // 980
+ "ignore-empty-rows", // 981
+ "ignore-result", // 982
+ "illustration-index", // 983
+ "illustration-index-entry-template", // 984
+ "illustration-index-source", // 985
+ "image", // 986
+ "image-align", // 987
+ "image-count", // 988
+ "image-data", // 989
+ "image-frame", // 990
+ "image-map", // 991
+ "image-opacity", // 992
+ "image-position", // 993
+ "in", // 994
+ "inbook", // 995
+ "inch", // 996
+ "include-hidden-cells", // 997
+ "incollection", // 998
+ "increment", // 999
+ "indefinite", // 1000
+ "index", // 1001
+ "index-body", // 1002
+ "index-column", // 1003
+ "index-columns", // 1004
+ "index-entry-bibliography", // 1005
+ "index-entry-chapter", // 1006
+ "index-entry-link-end", // 1007
+ "index-entry-link-start", // 1008
+ "index-entry-page-number", // 1009
+ "index-entry-span", // 1010
+ "index-entry-tab-stop", // 1011
+ "index-entry-text", // 1012
+ "index-name", // 1013
+ "index-scope", // 1014
+ "index-source-style", // 1015
+ "index-source-styles", // 1016
+ "index-title", // 1017
+ "index-title-template", // 1018
+ "indices", // 1019
+ "information", // 1020
+ "inherit", // 1021
+ "initial-creator", // 1022
+ "inner", // 1023
+ "inproceedings", // 1024
+ "insertion", // 1025
+ "insertion-cut-off", // 1026
+ "inside", // 1027
+ "institution", // 1028
+ "int", // 1029
+ "integer", // 1030
+ "intensity", // 1031
+ "interactive-sequence", // 1032
+ "interlocking-horizontal-left", // 1033
+ "interlocking-horizontal-right", // 1034
+ "interlocking-vertical-bottom", // 1035
+ "interlocking-vertical-top", // 1036
+ "interpolation", // 1037
+ "interval-major", // 1038
+ "interval-minor-divisor", // 1039
+ "into-default-style-data-style", // 1040
+ "into-english-number", // 1041
+ "inverse", // 1042
+ "is-active", // 1043
+ "is-ascending", // 1044
+ "is-autoincrement", // 1045
+ "is-boolean", // 1046
+ "is-clustered", // 1047
+ "is-data-layout-field", // 1048
+ "is-empty-allowed", // 1049
+ "is-first-row-header-line", // 1050
+ "is-hidden", // 1051
+ "is-list-header", // 1052
+ "is-nullable", // 1053
+ "is-password-required", // 1054
+ "is-selection", // 1055
+ "is-sub-table", // 1056
+ "is-table-name-length-limited", // 1057
+ "is-tristate", // 1058
+ "is-unique", // 1059
+ "isbn", // 1060
+ "issn", // 1061
+ "italic", // 1062
+ "item", // 1063
+ "iterate", // 1064
+ "iterate-interval", // 1065
+ "iterate-type", // 1066
+ "iteration", // 1067
+ "iterative", // 1068
+ "japanese-candle-stick", // 1069
+ "jewish", // 1070
+ "join-border", // 1071
+ "journal", // 1072
+ "justify", // 1073
+ "justify-single-word", // 1074
+ "keep-text", // 1075
+ "keep-together", // 1076
+ "keep-with-next", // 1077
+ "key", // 1078
+ "key-column", // 1079
+ "key-columns", // 1080
+ "key1", // 1081
+ "key1-phonetic", // 1082
+ "key2", // 1083
+ "key2-phonetic", // 1084
+ "keySplines", // 1085
+ "keyTimes", // 1086
+ "keys", // 1087
+ "keyword", // 1088
+ "keywords", // 1089
+ "kind", // 1090
+ "km", // 1091
+ "label", // 1092
+ "label-alignment", // 1093
+ "label-arrangement", // 1094
+ "label-cell-address", // 1095
+ "label-cell-range-address", // 1096
+ "label-followed-by", // 1097
+ "label-position", // 1098
+ "label-position-negative", // 1099
+ "label-range", // 1100
+ "label-ranges", // 1101
+ "label-separator", // 1102
+ "label-width-and-position", // 1103
+ "landscape", // 1104
+ "language", // 1105
+ "language-asian", // 1106
+ "language-complex", // 1107
+ "laser", // 1108
+ "last", // 1109
+ "last-column", // 1110
+ "last-column-spanned", // 1111
+ "last-page", // 1112
+ "last-row", // 1113
+ "last-row-end-column", // 1114
+ "last-row-spanned", // 1115
+ "last-row-start-column", // 1116
+ "last-visited-page", // 1117
+ "latin", // 1118
+ "layer", // 1119
+ "layer-set", // 1120
+ "layout-grid-base-height", // 1121
+ "layout-grid-base-width", // 1122
+ "layout-grid-color", // 1123
+ "layout-grid-display", // 1124
+ "layout-grid-lines", // 1125
+ "layout-grid-mode", // 1126
+ "layout-grid-print", // 1127
+ "layout-grid-ruby-below", // 1128
+ "layout-grid-ruby-height", // 1129
+ "layout-grid-snap-to", // 1130
+ "layout-grid-standard-mode", // 1131
+ "layout-mode", // 1132
+ "leader-char", // 1133
+ "leader-color", // 1134
+ "leader-style", // 1135
+ "leader-text", // 1136
+ "leader-text-style", // 1137
+ "leader-type", // 1138
+ "leader-width", // 1139
+ "leave-gap", // 1140
+ "left", // 1141
+ "left-outside", // 1142
+ "legend", // 1143
+ "legend-align", // 1144
+ "legend-expansion", // 1145
+ "legend-expansion-aspect-ratio", // 1146
+ "legend-position", // 1147
+ "length", // 1148
+ "letter-kerning", // 1149
+ "letter-spacing", // 1150
+ "letters", // 1151
+ "level", // 1152
+ "light", // 1153
+ "lighting-mode", // 1154
+ "line", // 1155
+ "line-break", // 1156
+ "line-distance", // 1157
+ "line-height", // 1158
+ "line-height-at-least", // 1159
+ "line-number", // 1160
+ "line-skew", // 1161
+ "line-spacing", // 1162
+ "line-style", // 1163
+ "linear", // 1164
+ "linearGradient", // 1165
+ "linenumbering-configuration", // 1166
+ "linenumbering-separator", // 1167
+ "lines", // 1168
+ "link-data-style-to-source", // 1169
+ "link-to-source-data", // 1170
+ "linked-cell", // 1171
+ "list", // 1172
+ "list-header", // 1173
+ "list-id", // 1174
+ "list-item", // 1175
+ "list-level", // 1176
+ "list-level-label-alignment", // 1177
+ "list-level-position-and-space-mode", // 1178
+ "list-level-properties", // 1179
+ "list-level-style-bullet", // 1180
+ "list-level-style-image", // 1181
+ "list-level-style-number", // 1182
+ "list-linkage-type", // 1183
+ "list-property", // 1184
+ "list-source", // 1185
+ "list-source-type", // 1186
+ "list-style", // 1187
+ "list-style-name", // 1188
+ "list-tab-stop-position", // 1189
+ "list-value", // 1190
+ "listbox", // 1191
+ "listtab", // 1192
+ "local-socket", // 1193
+ "logarithmic", // 1194
+ "login", // 1195
+ "login-timeout", // 1196
+ "long", // 1197
+ "long-dash", // 1198
+ "longvarbinary", // 1199
+ "longvarchar", // 1200
+ "lowercase", // 1201
+ "lr", // 1202
+ "lr-tb", // 1203
+ "ltr", // 1204
+ "luminance", // 1205
+ "m", // 1206
+ "macro-name", // 1207
+ "main-entry", // 1208
+ "main-entry-style-name", // 1209
+ "main-sequence", // 1210
+ "major", // 1211
+ "manual", // 1212
+ "map", // 1213
+ "margin", // 1214
+ "margin-bottom", // 1215
+ "margin-left", // 1216
+ "margin-right", // 1217
+ "margin-top", // 1218
+ "margins", // 1219
+ "marked-invalid", // 1220
+ "marker", // 1221
+ "marker-end", // 1222
+ "marker-end-center", // 1223
+ "marker-end-width", // 1224
+ "marker-start", // 1225
+ "marker-start-center", // 1226
+ "marker-start-width", // 1227
+ "master-element", // 1228
+ "master-fields", // 1229
+ "master-page", // 1230
+ "master-page-name", // 1231
+ "master-styles", // 1232
+ "mastersthesis", // 1233
+ "math", // 1234
+ "mathematical", // 1235
+ "matrix-covered", // 1236
+ "max", // 1237
+ "max-denominator-value", // 1238
+ "max-edge", // 1239
+ "max-height", // 1240
+ "max-length", // 1241
+ "max-row-count", // 1242
+ "max-value", // 1243
+ "max-width", // 1244
+ "maximum", // 1245
+ "maximum-difference", // 1246
+ "may-break-between-rows", // 1247
+ "may-script", // 1248
+ "mean-value", // 1249
+ "measure", // 1250
+ "measure-align", // 1251
+ "measure-vertical-align", // 1252
+ "media", // 1253
+ "media-call", // 1254
+ "media-type", // 1255
+ "medium", // 1256
+ "melt", // 1257
+ "member-count", // 1258
+ "member-difference", // 1259
+ "member-name", // 1260
+ "member-percentage", // 1261
+ "member-percentage-difference", // 1262
+ "member-type", // 1263
+ "message-type", // 1264
+ "meta", // 1265
+ "meta-field", // 1266
+ "method", // 1267
+ "mi", // 1268
+ "middle", // 1269
+ "mime-type", // 1270
+ "mimetype", // 1271
+ "min", // 1272
+ "min-decimal-places", // 1273
+ "min-denominator-digits", // 1274
+ "min-edge", // 1275
+ "min-exponent-digits", // 1276
+ "min-height", // 1277
+ "min-integer-digits", // 1278
+ "min-label-distance", // 1279
+ "min-label-width", // 1280
+ "min-numerator-digits", // 1281
+ "min-row-height", // 1282
+ "min-value", // 1283
+ "min-width", // 1284
+ "minimum", // 1285
+ "minor", // 1286
+ "minutes", // 1287
+ "mirror", // 1288
+ "mirror-horizontal", // 1289
+ "mirror-vertical", // 1290
+ "mirrored", // 1291
+ "misc", // 1292
+ "miter", // 1293
+ "mm", // 1294
+ "mode", // 1295
+ "model", // 1296
+ "modern", // 1297
+ "modification-date", // 1298
+ "modification-time", // 1299
+ "modifiers", // 1300
+ "modulate", // 1301
+ "mono", // 1302
+ "month", // 1303
+ "months", // 1304
+ "motion-path", // 1305
+ "mouse-as-pen", // 1306
+ "mouse-visible", // 1307
+ "move", // 1308
+ "move-from-bottom", // 1309
+ "move-from-left", // 1310
+ "move-from-lowerleft", // 1311
+ "move-from-lowerright", // 1312
+ "move-from-right", // 1313
+ "move-from-top", // 1314
+ "move-from-upperleft", // 1315
+ "move-from-upperright", // 1316
+ "move-short", // 1317
+ "movement", // 1318
+ "movement-cut-off", // 1319
+ "moving-average", // 1320
+ "multi-deletion-spanned", // 1321
+ "multi-line", // 1322
+ "multiple", // 1323
+ "name", // 1324
+ "name-and-extension", // 1325
+ "named", // 1326
+ "named-expression", // 1327
+ "named-expressions", // 1328
+ "named-range", // 1329
+ "named-symbol", // 1330
+ "nav-order", // 1331
+ "navigation-mode", // 1332
+ "near-axis", // 1333
+ "near-axis-other-side", // 1334
+ "near-origin", // 1335
+ "never", // 1336
+ "new", // 1337
+ "next", // 1338
+ "next-page", // 1339
+ "next-style-name", // 1340
+ "no-action", // 1341
+ "no-limit", // 1342
+ "no-nulls", // 1343
+ "no-repeat", // 1344
+ "no-wrap", // 1345
+ "node-type", // 1346
+ "nohref", // 1347
+ "non-primitive", // 1348
+ "non-whitespace-character-count", // 1349
+ "none", // 1350
+ "nonzero", // 1351
+ "normal", // 1352
+ "normals-direction", // 1353
+ "normals-kind", // 1354
+ "note", // 1355
+ "note-body", // 1356
+ "note-citation", // 1357
+ "note-class", // 1358
+ "note-continuation-notice-backward", // 1359
+ "note-continuation-notice-forward", // 1360
+ "note-ref", // 1361
+ "notes", // 1362
+ "notes-configuration", // 1363
+ "nothing", // 1364
+ "notify-on-update-of-ranges", // 1365
+ "null-date", // 1366
+ "null-year", // 1367
+ "nullable", // 1368
+ "num-format", // 1369
+ "num-letter-sync", // 1370
+ "num-prefix", // 1371
+ "num-suffix", // 1372
+ "number", // 1373
+ "number-all-superior", // 1374
+ "number-and-name", // 1375
+ "number-columns-repeated", // 1376
+ "number-columns-spanned", // 1377
+ "number-lines", // 1378
+ "number-matrix-columns-spanned", // 1379
+ "number-matrix-rows-spanned", // 1380
+ "number-no-superior", // 1381
+ "number-position", // 1382
+ "number-rows-repeated", // 1383
+ "number-rows-spanned", // 1384
+ "number-style", // 1385
+ "number-wrapped-paragraphs", // 1386
+ "numbered-entries", // 1387
+ "numbered-paragraph", // 1388
+ "numeric", // 1389
+ "object", // 1390
+ "object-count", // 1391
+ "object-index", // 1392
+ "object-index-entry-template", // 1393
+ "object-index-source", // 1394
+ "object-name", // 1395
+ "object-ole", // 1396
+ "objectBoundingBox", // 1397
+ "objects", // 1398
+ "oblique", // 1399
+ "odd-columns", // 1400
+ "odd-rows", // 1401
+ "office", // 1402
+ "offset", // 1403
+ "ole-action", // 1404
+ "ole-draw-aspect", // 1405
+ "ole-object-count", // 1406
+ "on-click", // 1407
+ "on-update-keep-size", // 1408
+ "on-update-keep-styles", // 1409
+ "onLoad", // 1410
+ "onRequest", // 1411
+ "once-concurrent", // 1412
+ "once-successive", // 1413
+ "opacity", // 1414
+ "opacity-name", // 1415
+ "open", // 1416
+ "open-horizontal", // 1417
+ "open-vertical", // 1418
+ "operation", // 1419
+ "operator", // 1420
+ "option", // 1421
+ "order", // 1422
+ "order-statement", // 1423
+ "organizations", // 1424
+ "orgchart", // 1425
+ "orientation", // 1426
+ "origin", // 1427
+ "orphans", // 1428
+ "other", // 1429
+ "out", // 1430
+ "outer", // 1431
+ "outline", // 1432
+ "outline-level", // 1433
+ "outline-level-style", // 1434
+ "outline-style", // 1435
+ "outline-subtotals-bottom", // 1436
+ "outline-subtotals-top", // 1437
+ "outside", // 1438
+ "outside-end", // 1439
+ "outside-start", // 1440
+ "overflow-behavior", // 1441
+ "overlap", // 1442
+ "overline-position", // 1443
+ "overline-thickness", // 1444
+ "p", // 1445
+ "paced", // 1446
+ "pad", // 1447
+ "padding", // 1448
+ "padding-bottom", // 1449
+ "padding-left", // 1450
+ "padding-right", // 1451
+ "padding-top", // 1452
+ "page", // 1453
+ "page-adjust", // 1454
+ "page-breaks-on-group-change", // 1455
+ "page-content", // 1456
+ "page-continuation", // 1457
+ "page-count", // 1458
+ "page-end-margin", // 1459
+ "page-height", // 1460
+ "page-layout", // 1461
+ "page-layout-name", // 1462
+ "page-layout-properties", // 1463
+ "page-number", // 1464
+ "page-sequence", // 1465
+ "page-start-margin", // 1466
+ "page-step-size", // 1467
+ "page-thumbnail", // 1468
+ "page-usage", // 1469
+ "page-variable-get", // 1470
+ "page-variable-set", // 1471
+ "page-width", // 1472
+ "pages", // 1473
+ "panose-1", // 1474
+ "paper-tray-name", // 1475
+ "par", // 1476
+ "paragraph", // 1477
+ "paragraph-content", // 1478
+ "paragraph-count", // 1479
+ "paragraph-end-margin", // 1480
+ "paragraph-properties", // 1481
+ "paragraph-start-margin", // 1482
+ "paragraph-style-name", // 1483
+ "parallel", // 1484
+ "param", // 1485
+ "parameter-name-substitution", // 1486
+ "parent", // 1487
+ "parent-style-name", // 1488
+ "parse-sql-statement", // 1489
+ "password", // 1490
+ "path", // 1491
+ "path-id", // 1492
+ "path-stretchpoint-x", // 1493
+ "path-stretchpoint-y", // 1494
+ "pause", // 1495
+ "pc", // 1496
+ "pending", // 1497
+ "percentage", // 1498
+ "percentage-data-style-name", // 1499
+ "percentage-style", // 1500
+ "perspective", // 1501
+ "phdthesis", // 1502
+ "phong", // 1503
+ "pie-offset", // 1504
+ "placeholder", // 1505
+ "placeholder-type", // 1506
+ "placing", // 1507
+ "plain-number", // 1508
+ "plain-number-and-name", // 1509
+ "play", // 1510
+ "play-full", // 1511
+ "plot-area", // 1512
+ "plugin", // 1513
+ "plus", // 1514
+ "points", // 1515
+ "polygon", // 1516
+ "polyline", // 1517
+ "polynomial", // 1518
+ "port", // 1519
+ "portrait", // 1520
+ "position", // 1521
+ "possessive-form", // 1522
+ "post", // 1523
+ "power", // 1524
+ "precision", // 1525
+ "precision-as-shown", // 1526
+ "prefix", // 1527
+ "presentation", // 1528
+ "presentation-page-layout", // 1529
+ "presentation-page-layout-name", // 1530
+ "preset-class", // 1531
+ "preset-id", // 1532
+ "preset-sub-type", // 1533
+ "previous", // 1534
+ "previous-page", // 1535
+ "primary", // 1536
+ "print", // 1537
+ "print-content", // 1538
+ "print-date", // 1539
+ "print-orientation", // 1540
+ "print-page-order", // 1541
+ "print-range", // 1542
+ "print-ranges", // 1543
+ "print-time", // 1544
+ "print-view", // 1545
+ "printable", // 1546
+ "printed-by", // 1547
+ "printer", // 1548
+ "prior", // 1549
+ "proceedings", // 1550
+ "product", // 1551
+ "projection", // 1552
+ "properties", // 1553
+ "property", // 1554
+ "property-name", // 1555
+ "protect", // 1556
+ "protected", // 1557
+ "protection-key", // 1558
+ "protection-key-digest-algorithm", // 1559
+ "pt", // 1560
+ "publisher", // 1561
+ "punctuation-wrap", // 1562
+ "push", // 1563
+ "pyramid", // 1564
+ "quarter", // 1565
+ "quarters", // 1566
+ "queries", // 1567
+ "query", // 1568
+ "query-collection", // 1569
+ "query-name", // 1570
+ "r", // 1571
+ "radial", // 1572
+ "radialGradient", // 1573
+ "radio", // 1574
+ "random", // 1575
+ "range-usable-as", // 1576
+ "readonly", // 1577
+ "real", // 1578
+ "records", // 1579
+ "recreate-on-edit", // 1580
+ "rect", // 1581
+ "rectangle", // 1582
+ "rectangular", // 1583
+ "red", // 1584
+ "ref", // 1585
+ "ref-name", // 1586
+ "reference-format", // 1587
+ "reference-mark", // 1588
+ "reference-mark-end", // 1589
+ "reference-mark-start", // 1590
+ "referenced-table-name", // 1591
+ "reflect", // 1592
+ "refresh-delay", // 1593
+ "region-center", // 1594
+ "region-left", // 1595
+ "region-right", // 1596
+ "register-true", // 1597
+ "register-truth-ref-style-name", // 1598
+ "regression-curve", // 1599
+ "regression-force-intercept", // 1600
+ "regression-intercept-value", // 1601
+ "regression-max-degree", // 1602
+ "regression-moving-type", // 1603
+ "regression-name", // 1604
+ "regression-period", // 1605
+ "regression-type", // 1606
+ "regular-polygon", // 1607
+ "rejected", // 1608
+ "rejecting-change-id", // 1609
+ "rel-column-width", // 1610
+ "rel-height", // 1611
+ "rel-width", // 1612
+ "related-column-name", // 1613
+ "relative-tab-stop-position", // 1614
+ "remove", // 1615
+ "remove-dependents", // 1616
+ "remove-precedents", // 1617
+ "repeat", // 1618
+ "repeat-column", // 1619
+ "repeat-content", // 1620
+ "repeat-row", // 1621
+ "repeatCount", // 1622
+ "repeatDur", // 1623
+ "repeated", // 1624
+ "replace", // 1625
+ "report-type", // 1626
+ "reports", // 1627
+ "reset", // 1628
+ "restart", // 1629
+ "restart-numbering", // 1630
+ "restart-on-page", // 1631
+ "restartDefault", // 1632
+ "restrict", // 1633
+ "reverse", // 1634
+ "reverse-direction", // 1635
+ "rfc-language-tag", // 1636
+ "rfc-language-tag-asian", // 1637
+ "rfc-language-tag-complex", // 1638
+ "rgb", // 1639
+ "right", // 1640
+ "right-angled-axes", // 1641
+ "right-outside", // 1642
+ "rl", // 1643
+ "rl-tb", // 1644
+ "roll-from-bottom", // 1645
+ "roll-from-left", // 1646
+ "roll-from-right", // 1647
+ "roll-from-top", // 1648
+ "roman", // 1649
+ "rotate", // 1650
+ "rotation", // 1651
+ "rotation-align", // 1652
+ "rotation-angle", // 1653
+ "round", // 1654
+ "row", // 1655
+ "row-count", // 1656
+ "row-height", // 1657
+ "row-mapping", // 1658
+ "row-number", // 1659
+ "row-percentage", // 1660
+ "row-retrieving-statement", // 1661
+ "rows", // 1662
+ "ruby", // 1663
+ "ruby-align", // 1664
+ "ruby-base", // 1665
+ "ruby-position", // 1666
+ "ruby-properties", // 1667
+ "ruby-text", // 1668
+ "run-through", // 1669
+ "running-total", // 1670
+ "rx", // 1671
+ "ry", // 1672
+ "s", // 1673
+ "scale", // 1674
+ "scale-min", // 1675
+ "scale-text", // 1676
+ "scale-to", // 1677
+ "scale-to-X", // 1678
+ "scale-to-Y", // 1679
+ "scale-to-pages", // 1680
+ "scenario", // 1681
+ "scenario-ranges", // 1682
+ "scene", // 1683
+ "schema-definition", // 1684
+ "schema-name", // 1685
+ "school", // 1686
+ "scientific-number", // 1687
+ "screen", // 1688
+ "script", // 1689
+ "script-asian", // 1690
+ "script-complex", // 1691
+ "script-type", // 1692
+ "scripts", // 1693
+ "scroll", // 1694
+ "search-criteria-must-apply-to-whole-cell", // 1695
+ "secondary-fill-color", // 1696
+ "seconds", // 1697
+ "section", // 1698
+ "section-name", // 1699
+ "section-properties", // 1700
+ "section-source", // 1701
+ "segments", // 1702
+ "select-page", // 1703
+ "selected", // 1704
+ "selected-page", // 1705
+ "selection", // 1706
+ "selection-indices", // 1707
+ "self", // 1708
+ "semi-automatic", // 1709
+ "semi-condensed", // 1710
+ "semi-expanded", // 1711
+ "sender-city", // 1712
+ "sender-company", // 1713
+ "sender-country", // 1714
+ "sender-email", // 1715
+ "sender-fax", // 1716
+ "sender-firstname", // 1717
+ "sender-initials", // 1718
+ "sender-lastname", // 1719
+ "sender-phone-private", // 1720
+ "sender-phone-work", // 1721
+ "sender-position", // 1722
+ "sender-postal-code", // 1723
+ "sender-state-or-province", // 1724
+ "sender-street", // 1725
+ "sender-title", // 1726
+ "sentence-count", // 1727
+ "separating", // 1728
+ "separation-character", // 1729
+ "separator", // 1730
+ "seq", // 1731
+ "sequence", // 1732
+ "sequence-decl", // 1733
+ "sequence-decls", // 1734
+ "sequence-ref", // 1735
+ "series", // 1736
+ "series-source", // 1737
+ "server-database", // 1738
+ "server-map", // 1739
+ "set", // 1740
+ "set-default", // 1741
+ "set-null", // 1742
+ "settings", // 1743
+ "shade-mode", // 1744
+ "shadow", // 1745
+ "shadow-color", // 1746
+ "shadow-offset-x", // 1747
+ "shadow-offset-y", // 1748
+ "shadow-opacity", // 1749
+ "shadow-slant", // 1750
+ "shape", // 1751
+ "shape-id", // 1752
+ "shapes", // 1753
+ "sharpness", // 1754
+ "sheet-name", // 1755
+ "shininess", // 1756
+ "short", // 1757
+ "show", // 1758
+ "show-deleted", // 1759
+ "show-details", // 1760
+ "show-empty", // 1761
+ "show-end-of-presentation-slide", // 1762
+ "show-filter-button", // 1763
+ "show-logo", // 1764
+ "show-shape", // 1765
+ "show-text", // 1766
+ "show-unit", // 1767
+ "shrink-to-fit", // 1768
+ "side-by-side", // 1769
+ "simple", // 1770
+ "single", // 1771
+ "size", // 1772
+ "skewX", // 1773
+ "skewY", // 1774
+ "skip-white-space", // 1775
+ "slide", // 1776
+ "slope", // 1777
+ "slow", // 1778
+ "small-caps", // 1779
+ "smallint", // 1780
+ "smil", // 1781
+ "snap-to-layout-grid", // 1782
+ "soft-page-break", // 1783
+ "solid", // 1784
+ "solid-type", // 1785
+ "sort", // 1786
+ "sort-algorithm", // 1787
+ "sort-ascending", // 1788
+ "sort-by", // 1789
+ "sort-by-position", // 1790
+ "sort-by-x-values", // 1791
+ "sort-groups", // 1792
+ "sort-key", // 1793
+ "sort-mode", // 1794
+ "sound", // 1795
+ "source", // 1796
+ "source-cell-range", // 1797
+ "source-cell-range-addresses", // 1798
+ "source-field-name", // 1799
+ "source-name", // 1800
+ "source-range-address", // 1801
+ "source-service", // 1802
+ "space", // 1803
+ "space-after", // 1804
+ "space-before", // 1805
+ "span", // 1806
+ "specular", // 1807
+ "specular-color", // 1808
+ "speed", // 1809
+ "sphere", // 1810
+ "spin-button", // 1811
+ "spiral-inward-left", // 1812
+ "spiral-inward-right", // 1813
+ "spiral-outward-left", // 1814
+ "spiral-outward-right", // 1815
+ "spiralin-left", // 1816
+ "spiralin-right", // 1817
+ "spiralout-left", // 1818
+ "spiralout-right", // 1819
+ "spline", // 1820
+ "spline-order", // 1821
+ "spline-resolution", // 1822
+ "spreadMethod", // 1823
+ "spreadsheet", // 1824
+ "sql", // 1825
+ "sql-pass-through", // 1826
+ "sql-statement", // 1827
+ "sqlnull", // 1828
+ "square", // 1829
+ "stacked", // 1830
+ "stagger-even", // 1831
+ "stagger-odd", // 1832
+ "standard", // 1833
+ "standard-deviation", // 1834
+ "standard-error", // 1835
+ "star", // 1836
+ "start", // 1837
+ "start-angle", // 1838
+ "start-color", // 1839
+ "start-column", // 1840
+ "start-glue-point", // 1841
+ "start-guide", // 1842
+ "start-indent", // 1843
+ "start-intensity", // 1844
+ "start-line-spacing-horizontal", // 1845
+ "start-line-spacing-vertical", // 1846
+ "start-numbering-at", // 1847
+ "start-page", // 1848
+ "start-position", // 1849
+ "start-row", // 1850
+ "start-scale", // 1851
+ "start-shape", // 1852
+ "start-table", // 1853
+ "start-value", // 1854
+ "start-with-navigator", // 1855
+ "state", // 1856
+ "status", // 1857
+ "stay-on-top", // 1858
+ "stdev", // 1859
+ "stdevp", // 1860
+ "stemh", // 1861
+ "stemv", // 1862
+ "step", // 1863
+ "step-center-x", // 1864
+ "step-center-y", // 1865
+ "step-end", // 1866
+ "step-size", // 1867
+ "step-start", // 1868
+ "steps", // 1869
+ "stock-gain-marker", // 1870
+ "stock-loss-marker", // 1871
+ "stock-range-line", // 1872
+ "stop", // 1873
+ "stop-color", // 1874
+ "stop-opacity", // 1875
+ "straight-line", // 1876
+ "stretch", // 1877
+ "stretch-from-bottom", // 1878
+ "stretch-from-left", // 1879
+ "stretch-from-right", // 1880
+ "stretch-from-top", // 1881
+ "strict", // 1882
+ "strikethrough-position", // 1883
+ "strikethrough-thickness", // 1884
+ "string", // 1885
+ "string-value", // 1886
+ "string-value-if-false", // 1887
+ "string-value-if-true", // 1888
+ "string-value-phonetic", // 1889
+ "stripes", // 1890
+ "stroke", // 1891
+ "stroke-color", // 1892
+ "stroke-dash", // 1893
+ "stroke-dash-names", // 1894
+ "stroke-linecap", // 1895
+ "stroke-linejoin", // 1896
+ "stroke-opacity", // 1897
+ "stroke-width", // 1898
+ "struct", // 1899
+ "structure-protected", // 1900
+ "style", // 1901
+ "style-name", // 1902
+ "style-override", // 1903
+ "styles", // 1904
+ "sub", // 1905
+ "sub-item", // 1906
+ "subject", // 1907
+ "submit", // 1908
+ "subtitle", // 1909
+ "subtotal-field", // 1910
+ "subtotal-rule", // 1911
+ "subtotal-rules", // 1912
+ "subtype", // 1913
+ "suffix", // 1914
+ "sum", // 1915
+ "super", // 1916
+ "suppress-version-columns", // 1917
+ "svg", // 1918
+ "swiss", // 1919
+ "syllable-count", // 1920
+ "symbol-color", // 1921
+ "symbol-height", // 1922
+ "symbol-image", // 1923
+ "symbol-name", // 1924
+ "symbol-type", // 1925
+ "symbol-width", // 1926
+ "system", // 1927
+ "system-driver-settings", // 1928
+ "tab", // 1929
+ "tab-color", // 1930
+ "tab-cycle", // 1931
+ "tab-index", // 1932
+ "tab-ref", // 1933
+ "tab-stop", // 1934
+ "tab-stop-distance", // 1935
+ "tab-stops", // 1936
+ "table", // 1937
+ "table-background", // 1938
+ "table-cell", // 1939
+ "table-cell-properties", // 1940
+ "table-centering", // 1941
+ "table-column", // 1942
+ "table-column-group", // 1943
+ "table-column-properties", // 1944
+ "table-columns", // 1945
+ "table-count", // 1946
+ "table-definition", // 1947
+ "table-definitions", // 1948
+ "table-exclude-filter", // 1949
+ "table-fields", // 1950
+ "table-filter", // 1951
+ "table-filter-pattern", // 1952
+ "table-formula", // 1953
+ "table-header-columns", // 1954
+ "table-header-rows", // 1955
+ "table-include-filter", // 1956
+ "table-index", // 1957
+ "table-index-entry-template", // 1958
+ "table-index-source", // 1959
+ "table-name", // 1960
+ "table-of-content", // 1961
+ "table-of-content-entry-template", // 1962
+ "table-of-content-source", // 1963
+ "table-properties", // 1964
+ "table-representation", // 1965
+ "table-representations", // 1966
+ "table-row", // 1967
+ "table-row-group", // 1968
+ "table-row-properties", // 1969
+ "table-rows", // 1970
+ "table-setting", // 1971
+ "table-settings", // 1972
+ "table-source", // 1973
+ "table-template", // 1974
+ "table-type", // 1975
+ "table-type-filter", // 1976
+ "tabular-layout", // 1977
+ "target-cell-address", // 1978
+ "target-frame", // 1979
+ "target-frame-name", // 1980
+ "target-range-address", // 1981
+ "targetElement", // 1982
+ "tb", // 1983
+ "tb-lr", // 1984
+ "tb-rl", // 1985
+ "techreport", // 1986
+ "template", // 1987
+ "template-name", // 1988
+ "text", // 1989
+ "text-align", // 1990
+ "text-align-last", // 1991
+ "text-align-source", // 1992
+ "text-areas", // 1993
+ "text-autospace", // 1994
+ "text-blinking", // 1995
+ "text-box", // 1996
+ "text-combine", // 1997
+ "text-combine-end-char", // 1998
+ "text-combine-start-char", // 1999
+ "text-content", // 2000
+ "text-emphasize", // 2001
+ "text-indent", // 2002
+ "text-input", // 2003
+ "text-line-through-color", // 2004
+ "text-line-through-mode", // 2005
+ "text-line-through-style", // 2006
+ "text-line-through-text", // 2007
+ "text-line-through-text-style", // 2008
+ "text-line-through-type", // 2009
+ "text-line-through-width", // 2010
+ "text-outline", // 2011
+ "text-overlap", // 2012
+ "text-overline-color", // 2013
+ "text-overline-mode", // 2014
+ "text-overline-style", // 2015
+ "text-overline-type", // 2016
+ "text-overline-width", // 2017
+ "text-path", // 2018
+ "text-path-allowed", // 2019
+ "text-path-mode", // 2020
+ "text-path-same-letter-heights", // 2021
+ "text-path-scale", // 2022
+ "text-position", // 2023
+ "text-properties", // 2024
+ "text-rotate-angle", // 2025
+ "text-rotation-angle", // 2026
+ "text-rotation-scale", // 2027
+ "text-scale", // 2028
+ "text-shadow", // 2029
+ "text-style", // 2030
+ "text-style-name", // 2031
+ "text-transform", // 2032
+ "text-underline-color", // 2033
+ "text-underline-mode", // 2034
+ "text-underline-style", // 2035
+ "text-underline-type", // 2036
+ "text-underline-width", // 2037
+ "textarea", // 2038
+ "textarea-horizontal-align", // 2039
+ "textarea-vertical-align", // 2040
+ "textual", // 2041
+ "texture-filter", // 2042
+ "texture-generation-mode-x", // 2043
+ "texture-generation-mode-y", // 2044
+ "texture-kind", // 2045
+ "texture-mode", // 2046
+ "thick", // 2047
+ "thin", // 2048
+ "thousand", // 2049
+ "three-dimensional", // 2050
+ "thumbnail", // 2051
+ "tick-mark-position", // 2052
+ "tick-marks-major-inner", // 2053
+ "tick-marks-major-outer", // 2054
+ "tick-marks-minor-inner", // 2055
+ "tick-marks-minor-outer", // 2056
+ "tile-repeat-offset", // 2057
+ "time", // 2058
+ "time-adjust", // 2059
+ "time-style", // 2060
+ "time-value", // 2061
+ "timestmp", // 2062
+ "timing-root", // 2063
+ "tinyint", // 2064
+ "title", // 2065
+ "to", // 2066
+ "to-another-table", // 2067
+ "to-bottom", // 2068
+ "to-center", // 2069
+ "to-left", // 2070
+ "to-lower-left", // 2071
+ "to-lower-right", // 2072
+ "to-right", // 2073
+ "to-top", // 2074
+ "to-upper-left", // 2075
+ "to-upper-right", // 2076
+ "toc-mark", // 2077
+ "toc-mark-end", // 2078
+ "toc-mark-start", // 2079
+ "toggle", // 2080
+ "top", // 2081
+ "top-end", // 2082
+ "top-left", // 2083
+ "top-right", // 2084
+ "top-start", // 2085
+ "total-percentage", // 2086
+ "trace-dependents", // 2087
+ "trace-errors", // 2088
+ "trace-precedents", // 2089
+ "track-changes", // 2090
+ "tracked-changes", // 2091
+ "transform", // 2092
+ "transformation", // 2093
+ "transition", // 2094
+ "transition-on-click", // 2095
+ "transition-speed", // 2096
+ "transition-style", // 2097
+ "transition-type", // 2098
+ "transitionFilter", // 2099
+ "translate", // 2100
+ "transliteration-country", // 2101
+ "transliteration-format", // 2102
+ "transliteration-language", // 2103
+ "transliteration-style", // 2104
+ "transparent", // 2105
+ "treat-empty-cells", // 2106
+ "triple", // 2107
+ "true", // 2108
+ "truncate-on-overflow", // 2109
+ "ttb", // 2110
+ "type", // 2111
+ "type-name", // 2112
+ "ultra-condensed", // 2113
+ "ultra-expanded", // 2114
+ "unchecked", // 2115
+ "uncover-to-bottom", // 2116
+ "uncover-to-left", // 2117
+ "uncover-to-lowerleft", // 2118
+ "uncover-to-lowerright", // 2119
+ "uncover-to-right", // 2120
+ "uncover-to-top", // 2121
+ "uncover-to-upperleft", // 2122
+ "uncover-to-upperright", // 2123
+ "underline-position", // 2124
+ "underline-thickness", // 2125
+ "unicode-range", // 2126
+ "unique", // 2127
+ "unit", // 2128
+ "units-per-em", // 2129
+ "unknown", // 2130
+ "unpublished", // 2131
+ "unsorted", // 2132
+ "up", // 2133
+ "update-rule", // 2134
+ "update-table", // 2135
+ "uppercase", // 2136
+ "url", // 2137
+ "use-banding-columns-styles", // 2138
+ "use-banding-rows-styles", // 2139
+ "use-caption", // 2140
+ "use-catalog", // 2141
+ "use-chart-objects", // 2142
+ "use-date-time-name", // 2143
+ "use-draw-objects", // 2144
+ "use-first-column-styles", // 2145
+ "use-first-row-styles", // 2146
+ "use-floating-frames", // 2147
+ "use-footer-name", // 2148
+ "use-graphics", // 2149
+ "use-header-name", // 2150
+ "use-index-marks", // 2151
+ "use-index-source-styles", // 2152
+ "use-keys-as-entries", // 2153
+ "use-labels", // 2154
+ "use-last-column-styles", // 2155
+ "use-last-row-styles", // 2156
+ "use-math-objects", // 2157
+ "use-objects", // 2158
+ "use-optimal-column-width", // 2159
+ "use-optimal-row-height", // 2160
+ "use-other-objects", // 2161
+ "use-outline-level", // 2162
+ "use-regular-expressions", // 2163
+ "use-soft-page-breaks", // 2164
+ "use-spreadsheet-objects", // 2165
+ "use-system-user", // 2166
+ "use-tables", // 2167
+ "use-wildcards", // 2168
+ "use-window-font-color", // 2169
+ "use-zero", // 2170
+ "used-hierarchy", // 2171
+ "user-defined", // 2172
+ "user-field-decl", // 2173
+ "user-field-decls", // 2174
+ "user-field-get", // 2175
+ "user-field-input", // 2176
+ "user-index", // 2177
+ "user-index-entry-template", // 2178
+ "user-index-mark", // 2179
+ "user-index-mark-end", // 2180
+ "user-index-mark-start", // 2181
+ "user-index-source", // 2182
+ "user-name", // 2183
+ "user-transformed", // 2184
+ "v-alphabetic", // 2185
+ "v-hanging", // 2186
+ "v-ideographic", // 2187
+ "v-mathematical", // 2188
+ "validation", // 2189
+ "value", // 2190
+ "value-and-percentage", // 2191
+ "value-list", // 2192
+ "value-range", // 2193
+ "value-type", // 2194
+ "values", // 2195
+ "values-cell-range-address", // 2196
+ "var", // 2197
+ "varbinary", // 2198
+ "varchar", // 2199
+ "variable", // 2200
+ "variable-decl", // 2201
+ "variable-decls", // 2202
+ "variable-get", // 2203
+ "variable-input", // 2204
+ "variable-set", // 2205
+ "variance", // 2206
+ "varp", // 2207
+ "verb", // 2208
+ "version", // 2209
+ "vertical", // 2210
+ "vertical-align", // 2211
+ "vertical-bar", // 2212
+ "vertical-checkerboard", // 2213
+ "vertical-lines", // 2214
+ "vertical-pos", // 2215
+ "vertical-rel", // 2216
+ "vertical-segments", // 2217
+ "vertical-stripes", // 2218
+ "viewBox", // 2219
+ "visibility", // 2220
+ "visible", // 2221
+ "visible-area-height", // 2222
+ "visible-area-left", // 2223
+ "visible-area-top", // 2224
+ "visible-area-width", // 2225
+ "visited-style-name", // 2226
+ "visual-effect", // 2227
+ "void", // 2228
+ "volatile", // 2229
+ "volume", // 2230
+ "vpn", // 2231
+ "vrp", // 2232
+ "vup", // 2233
+ "wall", // 2234
+ "warning", // 2235
+ "watermark", // 2236
+ "wave", // 2237
+ "wavyline", // 2238
+ "wavyline-from-bottom", // 2239
+ "wavyline-from-left", // 2240
+ "wavyline-from-right", // 2241
+ "wavyline-from-top", // 2242
+ "week-of-year", // 2243
+ "whenNotActive", // 2244
+ "wide", // 2245
+ "widows", // 2246
+ "width", // 2247
+ "widths", // 2248
+ "with-previous", // 2249
+ "word", // 2250
+ "word-count", // 2251
+ "wrap", // 2252
+ "wrap-contour", // 2253
+ "wrap-contour-mode", // 2254
+ "wrap-dynamic-threshold", // 2255
+ "wrap-influence-on-position", // 2256
+ "wrap-option", // 2257
+ "writing-mode", // 2258
+ "writing-mode-automatic", // 2259
+ "www", // 2260
+ "x", // 2261
+ "x-height", // 2262
+ "x1", // 2263
+ "x2", // 2264
+ "xforms", // 2265
+ "xforms-list-source", // 2266
+ "xforms-submission", // 2267
+ "xhtml", // 2268
+ "xlink", // 2269
+ "xml", // 2270
+ "y", // 2271
+ "y1", // 2272
+ "y2", // 2273
+ "year", // 2274
+ "years", // 2275
+ "z", // 2276
+ "z-index", // 2277
+ "zero-values" // 2278
+};
+
+size_t token_name_count = 2279; \ No newline at end of file
diff --git a/src/liborcus/ods_content_xml_context.cpp b/src/liborcus/ods_content_xml_context.cpp
new file mode 100644
index 0000000..5f07594
--- /dev/null
+++ b/src/liborcus/ods_content_xml_context.cpp
@@ -0,0 +1,900 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ods_content_xml_context.hpp"
+#include "odf_token_constants.hpp"
+#include "odf_namespace_types.hpp"
+#include "session_context.hpp"
+#include "ods_session_data.hpp"
+#include "impl_utils.hpp"
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include <cstring>
+
+#include <mdds/sorted_string_map.hpp>
+
+using namespace std;
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+namespace cell_value {
+
+using map_type = mdds::sorted_string_map<ods_content_xml_context::cell_value_type, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+map_type::entry entries[] = {
+ { "date", ods_content_xml_context::vt_date },
+ { "float", ods_content_xml_context::vt_float },
+ { "string", ods_content_xml_context::vt_string }
+};
+
+const map_type& get()
+{
+ static map_type cv_map(
+ entries, std::size(entries), ods_content_xml_context::vt_unknown);
+
+ return cv_map;
+}
+
+} // namespace cell_value
+
+void pick_up_named_range_or_expression(
+ session_context& cxt, const xml_token_attrs_t& attrs, xmlns_id_t exp_attr_ns, xml_token_t exp_attr_name,
+ ods_session_data::named_exp_type name_type, ss::sheet_t scope)
+{
+ std::string_view name;
+ std::string_view expression;
+ std::string_view base;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == exp_attr_ns && attr.name == exp_attr_name)
+ {
+ expression = cxt.intern(attr);
+ continue;
+ }
+
+ switch (attr.name)
+ {
+ case XML_name:
+ name = cxt.intern(attr);
+ break;
+ case XML_base_cell_address:
+ base = cxt.intern(attr);
+ break;
+ }
+ }
+
+ auto& ods_data = cxt.get_data<ods_session_data>();
+
+ if (!name.empty() && !expression.empty() && !base.empty())
+ ods_data.named_exps.emplace_back(name, expression, base, name_type, scope);
+}
+
+} // anonymous namespace
+
+// ============================================================================
+
+ods_content_xml_context::sheet_data::sheet_data() :
+ sheet(nullptr), index(-1) {}
+
+void ods_content_xml_context::sheet_data::reset()
+{
+ sheet = nullptr;
+ index = -1;
+}
+
+ods_content_xml_context::row_attr::row_attr() :
+ number_rows_repeated(1)
+{
+}
+
+ods_content_xml_context::cell_attr::cell_attr() :
+ number_columns_repeated(1),
+ type(vt_unknown),
+ value(0.0),
+ formula_grammar(spreadsheet::formula_grammar_t::ods)
+{
+}
+
+// ============================================================================
+
+ods_content_xml_context::ods_content_xml_context(session_context& session_cxt, const tokens& tokens, spreadsheet::iface::import_factory* factory) :
+ xml_context_base(session_cxt, tokens),
+ mp_factory(factory),
+ m_row(0), m_col(0), m_col_repeated(0),
+ m_para_index(0),
+ m_has_content(false),
+ m_styles(),
+ m_child_styles(session_cxt, tokens, mp_factory->get_styles()),
+ m_child_para(session_cxt, tokens, factory->get_shared_strings(), m_styles),
+ m_child_dde_links(session_cxt, tokens)
+{
+ register_child(&m_child_styles);
+ register_child(&m_child_para);
+ register_child(&m_child_dde_links);
+
+ spreadsheet::iface::import_global_settings* gs = mp_factory->get_global_settings();
+ if (gs)
+ {
+ // Set the default null date to 1899-12-30 per specification (19.614).
+ gs->set_origin_date(1899, 12, 30);
+ }
+}
+
+ods_content_xml_context::~ods_content_xml_context() = default;
+
+xml_context_base* ods_content_xml_context::create_child_context(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_text && name == XML_p)
+ {
+ m_child_para.reset();
+ return &m_child_para;
+ }
+
+ if (ns == NS_odf_office && name == XML_automatic_styles)
+ {
+ m_child_styles.reset();
+ return &m_child_styles;
+ }
+
+ if (ns == NS_odf_table && name == XML_dde_links)
+ {
+ m_child_dde_links.reset();
+ return &m_child_dde_links;
+ }
+
+ return nullptr;
+}
+
+void ods_content_xml_context::end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child)
+{
+ if (ns == NS_odf_text && name == XML_p)
+ {
+ text_para_context* para_context = static_cast<text_para_context*>(child);
+ m_has_content = !para_context->empty();
+ m_para_index = para_context->get_string_index();
+ }
+ else if (ns == NS_odf_office && name == XML_automatic_styles)
+ {
+ auto new_styles = m_child_styles.pop_styles();
+ merge(m_styles, new_styles);
+ assert(new_styles.empty());
+
+ if (get_config().debug)
+ dump_state(m_styles, std::cout);
+
+ spreadsheet::iface::import_styles* xstyles = mp_factory->get_styles();
+ if (xstyles)
+ {
+ for (const auto& [style_name, style_value] : m_styles)
+ {
+ if (style_value->family == style_family_table_cell)
+ {
+ // TODO: Actually we need a boolean flag to see if it is an automatic style or a real style
+ // currently we have no way to set a real style to a cell anyway
+ const auto& cell = std::get<odf_style::cell>(style_value->data);
+ m_cell_format_map.insert(name2id_type::value_type(style_name, cell.xf));
+ }
+ }
+ }
+ }
+}
+
+void ods_content_xml_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+
+ if (ns == NS_odf_office)
+ {
+ switch (name)
+ {
+ case XML_body:
+ break;
+ case XML_spreadsheet:
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else if (ns == NS_odf_table)
+ {
+ switch (name)
+ {
+ case XML_calculation_settings:
+ break;
+ case XML_null_date:
+ xml_element_expected(parent, NS_odf_table, XML_calculation_settings);
+ start_null_date(attrs);
+ break;
+ case XML_table:
+ start_table(parent, attrs);
+ break;
+ case XML_table_column:
+ {
+ static const xml_elem_set_t expected = {
+ { NS_odf_table, XML_table },
+ { NS_odf_table, XML_table_column_group },
+ { NS_odf_table, XML_table_columns },
+ { NS_odf_table, XML_table_header_columns }
+ };
+ xml_element_expected(parent, expected);
+ start_column(attrs);
+ break;
+ }
+ case XML_table_row:
+ {
+ static const xml_elem_set_t expected = {
+ { NS_odf_table, XML_table },
+ { NS_odf_table, XML_table_header_rows },
+ { NS_odf_table, XML_table_row_group },
+ };
+ xml_element_expected(parent, expected);
+ start_row(attrs);
+ break;
+ }
+ case XML_table_cell:
+ xml_element_expected(parent, NS_odf_table, XML_table_row);
+ start_cell(attrs);
+ break;
+ case XML_dde_links:
+ xml_element_expected(parent, NS_odf_office, XML_spreadsheet);
+ break;
+ case XML_dde_link:
+ xml_element_expected(parent, NS_odf_table, XML_dde_links);
+ break;
+ case XML_named_expressions:
+ {
+ static const xml_elem_set_t expected = {
+ { NS_odf_office, XML_spreadsheet },
+ { NS_odf_table, XML_table },
+ };
+ xml_element_expected(parent, expected);
+ break;
+ }
+ case XML_named_range:
+ start_named_range(parent, attrs);
+ break;
+ case XML_named_expression:
+ start_named_expression(parent, attrs);
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool ods_content_xml_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_odf_office)
+ {
+ switch (name)
+ {
+ case XML_body:
+ break;
+ case XML_spreadsheet:
+ end_spreadsheet();
+ break;
+ default:
+ ;
+ }
+ }
+ else if (ns == NS_odf_table)
+ {
+ switch (name)
+ {
+ case XML_calculation_settings:
+ break;
+ case XML_null_date:
+ break;
+ case XML_table:
+ end_table();
+ break;
+ case XML_table_column:
+ end_column();
+ break;
+ case XML_table_row:
+ end_row();
+ break;
+ case XML_table_cell:
+ end_cell();
+ break;
+ case XML_named_range:
+ end_named_range();
+ break;
+ case XML_named_expression:
+ end_named_expression();
+ break;
+ default:
+ ;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void ods_content_xml_context::start_null_date(const xml_token_attrs_t& attrs)
+{
+ spreadsheet::iface::import_global_settings* gs = mp_factory->get_global_settings();
+ if (!gs)
+ // Global settings not available. No point going further.
+ return;
+
+ std::string_view null_date;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_odf_table && attr.name == XML_date_value)
+ null_date = attr.value;
+ }
+
+ date_time_t val = date_time_t::from_chars(null_date);
+
+ gs->set_origin_date(val.year, val.month, val.day);
+}
+
+void ods_content_xml_context::start_table(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ static const xml_elem_set_t expected = {
+ { NS_odf_office, XML_spreadsheet },
+ { NS_odf_table, XML_dde_link },
+ };
+ xml_element_expected(parent, expected);
+
+ if (parent == xml_token_pair_t(NS_odf_office, XML_spreadsheet))
+ {
+ std::string_view name;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_odf_table && attr.name == XML_name)
+ name = attr.value;
+ }
+
+ m_tables.push_back(mp_factory->append_sheet(m_tables.size(), name));
+ m_cur_sheet.sheet = m_tables.back();
+ m_cur_sheet.index = m_tables.size() - 1;
+
+ if (get_config().debug)
+ cout << "start table " << name << endl;
+
+ m_row = m_col = 0;
+ }
+ else if (parent == xml_token_pair_t(NS_odf_table, XML_dde_link))
+ {
+ if (get_config().debug)
+ cout << "start table (DDE link)" << endl;
+ }
+}
+
+void ods_content_xml_context::end_table()
+{
+ if (m_cur_sheet.sheet)
+ {
+ if (get_config().debug)
+ cout << "end table" << endl;
+
+ m_cur_sheet.reset();
+ }
+}
+
+void ods_content_xml_context::start_named_range(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ xml_element_expected(parent, NS_odf_table, XML_named_expressions);
+
+ pick_up_named_range_or_expression(
+ get_session_context(), attrs, NS_odf_table, XML_cell_range_address,
+ ods_session_data::ne_range, m_cur_sheet.index);
+}
+
+void ods_content_xml_context::end_named_range()
+{
+}
+
+void ods_content_xml_context::start_named_expression(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ xml_element_expected(parent, NS_odf_table, XML_named_expressions);
+
+ pick_up_named_range_or_expression(
+ get_session_context(), attrs, NS_odf_table, XML_expression,
+ ods_session_data::ne_expression, m_cur_sheet.index);
+}
+
+void ods_content_xml_context::end_named_expression()
+{
+}
+
+void ods_content_xml_context::start_column(const xml_token_attrs_t& attrs)
+{
+ if (!m_cur_sheet.sheet)
+ return;
+
+ spreadsheet::iface::import_sheet_properties* sheet_props =
+ m_cur_sheet.sheet->get_sheet_properties();
+
+ if (!sheet_props)
+ return;
+
+ std::string_view style_name;
+ std::string_view default_cell_style_name;
+ m_col_repeated = 1;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_odf_table)
+ {
+ switch (attr.name)
+ {
+ case XML_style_name:
+ style_name = attr.value;
+ break;
+ case XML_default_cell_style_name:
+ default_cell_style_name = intern(attr);
+ break;
+ case XML_number_columns_repeated:
+ m_col_repeated = to_long(attr.value);
+ break;
+ }
+ }
+ }
+
+ if (auto it = m_styles.find(style_name); it != m_styles.end())
+ {
+ const odf_style& style = *it->second;
+
+ sheet_props->set_column_width(
+ m_col, m_col_repeated,
+ std::get<odf_style::column>(style.data).width.value,
+ std::get<odf_style::column>(style.data).width.unit);
+ }
+
+ push_default_column_cell_style(default_cell_style_name, m_col_repeated);
+}
+
+void ods_content_xml_context::end_column()
+{
+ m_col += m_col_repeated;
+}
+
+void ods_content_xml_context::start_row(const xml_token_attrs_t& attrs)
+{
+ m_col = 0;
+ m_row_attr = row_attr();
+
+ std::string_view style_name;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_odf_table)
+ {
+ switch (attr.name)
+ {
+ case XML_number_rows_repeated:
+ m_row_attr.number_rows_repeated = to_long(attr.value);
+ break;
+ case XML_style_name:
+ style_name = attr.value;
+ break;
+ }
+ }
+ }
+
+ if (get_config().debug)
+ std::cout << "row: (style='" << style_name << "')" << std::endl;
+
+ if (!m_cur_sheet.sheet)
+ return;
+
+ // Pass row properties to the interface.
+ spreadsheet::iface::import_sheet_properties* sheet_props =
+ m_cur_sheet.sheet->get_sheet_properties();
+
+ if (sheet_props)
+ {
+ if (auto it = m_styles.find(style_name); it != m_styles.end())
+ {
+ const odf_style& style = *it->second;
+ if (style.family == style_family_table_row)
+ {
+ const auto& data = std::get<odf_style::row>(style.data);
+ if (data.height_set)
+ sheet_props->set_row_height(m_row, data.height.value, data.height.unit);
+ }
+ }
+ }
+}
+
+void ods_content_xml_context::end_row()
+{
+ if (m_row_attr.number_rows_repeated > 1)
+ {
+ // TODO: repeat this row.
+ if (get_config().debug)
+ cout << "TODO: repeat this row " << m_row_attr.number_rows_repeated << " times." << endl;
+ }
+ m_row += m_row_attr.number_rows_repeated;
+}
+
+void ods_content_xml_context::start_cell(const xml_token_attrs_t& attrs)
+{
+ m_cell_attr = cell_attr();
+
+ /**
+ * Process the prefixed raw formula string stored as attribute value.
+ */
+ auto process_formula = [](std::string_view str) -> std::string_view
+ {
+ if (str.empty())
+ return {};
+
+ // Formula is prefixed with formula type, followed by a ':'
+ // then the actual formula content.
+
+ // First, detect prefix if any. Only try up to the first 5 characters.
+ const char* p0 = str.data();
+ const char* end = p0 + std::min<size_t>(str.size(), 5);
+ size_t prefix_size = 0;
+ for (const char* p = p0; p != end; ++p)
+ {
+ if (*p == ':')
+ {
+ // Prefix separator found.
+ prefix_size = p - p0;
+ break;
+ }
+
+ if (!is_alpha(*p))
+ // Only alphabets are allowed in the prefix space.
+ break;
+ }
+
+ std::string_view prefix, formula;
+ if (prefix_size)
+ {
+ prefix = std::string_view(p0, prefix_size);
+ const char* p = p0;
+ p += prefix_size + 1;
+ end = p0 + str.size();
+ formula = std::string_view(p, end - p);
+ }
+ else
+ {
+ // TODO : Handle cases where a formula doesn't have a prefix.
+ }
+
+ // Formula needs to begin with '='.
+ if (formula.empty() || formula[0] != '=')
+ return {};
+
+ // Remove the '='.
+ formula = std::string_view(formula.data()+1, formula.size()-1);
+
+ if (prefix == "of")
+ {
+ // ODF formula. No action needed.
+ }
+
+ return formula;
+ };
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.value.empty())
+ continue;
+
+ if (attr.ns == NS_odf_table)
+ {
+ switch (attr.name)
+ {
+ case XML_style_name:
+ {
+ m_cell_attr.style_name = intern(attr);
+ break;
+ }
+ case XML_number_columns_repeated:
+ m_cell_attr.number_columns_repeated = to_long(attr.value);
+ break;
+ case XML_formula:
+ m_cell_attr.formula = process_formula(attr.value);
+ m_cell_attr.formula = intern(m_cell_attr.formula);
+ break;
+ default:
+ ;
+ }
+ }
+
+ if (attr.ns == NS_odf_office)
+ {
+ switch (attr.name)
+ {
+ case XML_value:
+ {
+ const char* end = attr.value.data() + attr.value.size();
+ char* endptr;
+ double val = strtod(attr.value.data(), &endptr);
+ if (endptr == end)
+ m_cell_attr.value = val;
+ break;
+ }
+ case XML_value_type:
+ m_cell_attr.type = cell_value::get().find(attr.value.data(), attr.value.size());
+ break;
+ case XML_date_value:
+ m_cell_attr.date_value = attr.value;
+ break;
+ default:
+ ;
+ }
+ }
+ }
+}
+
+void ods_content_xml_context::end_cell()
+{
+ push_cell_format();
+ push_cell_value();
+
+ ++m_col;
+ if (m_cell_attr.number_columns_repeated > 1)
+ {
+ int col_upper = m_col + m_cell_attr.number_columns_repeated - 2;
+ for (; m_col <= col_upper; ++m_col)
+ push_cell_value();
+ }
+ m_has_content = false;
+}
+
+std::optional<std::size_t> ods_content_xml_context::push_named_cell_style(std::string_view style_name)
+{
+ ss::iface::import_styles* xstyles = mp_factory->get_styles();
+ if (!xstyles)
+ return {};
+
+ const ods_session_data& ods_data = get_session_context().get_data<ods_session_data>();
+
+ auto it = ods_data.styles_map.find(style_name);
+ if (it == ods_data.styles_map.end())
+ return {};
+
+ // found in the named styles store.
+ const odf_style& style = *it->second;
+ if (style.family != style_family_table_cell)
+ // it's a named style but not a cell style
+ return {};
+
+ // It references a named style. Create a direct cell (aka automatic) style
+ // that references this named style, and set that as the cell format since
+ // we can't reference a named style directly from a cell.
+ const auto& celldata = std::get<odf_style::cell>(style.data);
+
+ ss::iface::import_xf* xf = xstyles->start_xf(ss::xf_category_t::cell);
+ ENSURE_INTERFACE(xf, import_xf);
+ xf->set_style_xf(celldata.xf);
+ std::size_t xfid = xf->commit();
+ m_cell_format_map.insert({style_name, xfid});
+ return xfid;
+}
+
+void ods_content_xml_context::push_default_column_cell_style(
+ std::string_view style_name, ss::col_t span)
+{
+ if (span < 1)
+ {
+ std::ostringstream os;
+ os << "Column " << m_col << " on sheet " << m_cur_sheet.index << " has an invalid span of " << span;
+ warn(os.str());
+ return;
+ }
+
+ if (style_name.empty())
+ return;
+
+ if (!m_cur_sheet.sheet)
+ return;
+
+ if (auto it = m_cell_format_map.find(style_name); it != m_cell_format_map.end())
+ {
+ // automatic style already present for this name.
+ m_cur_sheet.sheet->set_column_format(m_col, span, it->second);
+ return;
+ }
+
+ auto xfid = push_named_cell_style(style_name);
+ if (!xfid)
+ {
+ std::ostringstream os;
+ os << "failed to push a new cell style of name '" << style_name << "' to cache";
+ warn(os.str());
+ return;
+ }
+
+ m_cur_sheet.sheet->set_column_format(m_col, span, *xfid);
+}
+
+void ods_content_xml_context::push_cell_format()
+{
+ if (!m_cur_sheet.sheet)
+ return;
+
+ if (auto it = m_cell_format_map.find(m_cell_attr.style_name); it != m_cell_format_map.end())
+ {
+ for (ss::col_t col_offset = 0; col_offset < m_cell_attr.number_columns_repeated; ++col_offset)
+ m_cur_sheet.sheet->set_format(m_row, m_col + col_offset, it->second);
+ // style key found and direct cell format set.
+ return;
+ }
+
+ auto xfid = push_named_cell_style(m_cell_attr.style_name);
+ if (!xfid)
+ return;
+
+ for (ss::col_t col_offset = 0; col_offset < m_cell_attr.number_columns_repeated; ++col_offset)
+ m_cur_sheet.sheet->set_format(m_row, m_col + col_offset, *xfid);
+}
+
+void ods_content_xml_context::push_cell_value()
+{
+ assert(m_cur_sheet.index >= 0); // this is expected to be called only within a valid sheet scope.
+
+ bool has_formula = !m_cell_attr.formula.empty();
+ if (has_formula)
+ {
+ // Store formula cell data for later processing.
+ auto& ods_data = get_session_context().get_data<ods_session_data>();
+ ods_data.formulas.emplace_back(
+ m_cur_sheet.index, m_row, m_col, m_cell_attr.formula_grammar, m_cell_attr.formula);
+
+ ods_session_data::formula& formula_data = ods_data.formulas.back();
+
+ // Store formula result.
+ switch (m_cell_attr.type)
+ {
+ case vt_float:
+ {
+ formula_data.result.type = orcus::ods_session_data::rt_numeric;
+ formula_data.result.numeric_value = m_cell_attr.value;
+ break;
+ }
+ case vt_string:
+ // TODO : pass string result here. We need to decide whether
+ // to pass a string ID or a raw string.
+ break;
+ default:
+ ;
+ }
+ return;
+ }
+
+ if (m_cur_sheet.sheet)
+ {
+ switch (m_cell_attr.type)
+ {
+ case vt_float:
+ m_cur_sheet.sheet->set_value(m_row, m_col, m_cell_attr.value);
+ break;
+ case vt_string:
+ if (m_has_content)
+ m_cur_sheet.sheet->set_string(m_row, m_col, m_para_index);
+ break;
+ case vt_date:
+ {
+ date_time_t val = date_time_t::from_chars(m_cell_attr.date_value);
+ m_cur_sheet.sheet->set_date_time(
+ m_row, m_col, val.year, val.month, val.day, val.hour, val.minute, val.second);
+ break;
+ }
+ default:
+ ;
+ }
+ }
+}
+
+void ods_content_xml_context::end_spreadsheet()
+{
+ auto& ods_data = get_session_context().get_data<ods_session_data>();
+
+ ss::iface::import_reference_resolver* resolver =
+ mp_factory->get_reference_resolver(ss::formula_ref_context_t::named_expression_base);
+
+ if (resolver)
+ {
+ for (const ods_session_data::named_exp& data : ods_data.named_exps)
+ {
+ if (get_config().debug)
+ {
+ cout << "named expression: name='" << data.name
+ << "'; base='" << data.base
+ << "'; expression='" << data.expression
+ << "'; sheet-scope=" << data.scope
+ << endl;
+ }
+
+ ss::src_address_t base = resolver->resolve_address(data.base);
+
+ ss::iface::import_named_expression* named_exp = nullptr;
+
+ if (data.scope >= 0)
+ {
+ // sheet local scope
+ assert(data.scope < ss::sheet_t(m_tables.size()));
+ named_exp = m_tables[data.scope]->get_named_expression();
+ }
+ else
+ {
+ // global scope.
+ named_exp = mp_factory->get_named_expression();
+ }
+
+ if (named_exp)
+ {
+ named_exp->set_base_position(base);
+ switch (data.type)
+ {
+ case ods_session_data::ne_range:
+ named_exp->set_named_range(data.name, data.expression);
+ break;
+ case ods_session_data::ne_expression:
+ named_exp->set_named_expression(data.name, data.expression);
+ break;
+ default:
+ ;
+ }
+ named_exp->commit();
+ }
+ }
+ }
+
+ // Push all formula cells. Formula cells needs to be processed after all
+ // the sheet data have been imported, else 3D reference would fail to
+ // resolve.
+ for (ods_session_data::formula& data : ods_data.formulas)
+ {
+ if (data.sheet < 0 || static_cast<size_t>(data.sheet) >= m_tables.size())
+ // Invalid sheet index.
+ continue;
+
+ spreadsheet::iface::import_sheet* sheet = m_tables[data.sheet];
+ if (sheet)
+ {
+ spreadsheet::iface::import_formula* formula = sheet->get_formula();
+ if (formula)
+ {
+ formula->set_position(data.row, data.column);
+ formula->set_formula(data.grammar, data.exp);
+
+ switch (data.result.type)
+ {
+ case ods_session_data::rt_numeric:
+ formula->set_result_value(data.result.numeric_value);
+ break;
+ case ods_session_data::rt_string:
+ case ods_session_data::rt_error:
+ case ods_session_data::rt_none:
+ default:
+ ;
+ }
+
+ formula->commit();
+ }
+ }
+ }
+
+ // Clear the formula buffer.
+ ods_data.formulas.clear();
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ods_content_xml_context.hpp b/src/liborcus/ods_content_xml_context.hpp
new file mode 100644
index 0000000..bc50a67
--- /dev/null
+++ b/src/liborcus/ods_content_xml_context.hpp
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_ODSCONTEXT_XML_CONTEXT_HPP
+#define INCLUDED_ORCUS_ODSCONTEXT_XML_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "odf_para_context.hpp"
+#include "ods_dde_links_context.hpp"
+#include "odf_styles.hpp"
+#include "odf_styles_context.hpp"
+#include "orcus/spreadsheet/types.hpp"
+
+#include <vector>
+#include <unordered_map>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_factory;
+class import_sheet;
+
+}}
+
+class ods_content_xml_context : public xml_context_base
+{
+ typedef std::unordered_map<std::string_view, std::size_t> name2id_type;
+
+public:
+ struct sheet_data
+ {
+ spreadsheet::iface::import_sheet* sheet;
+ spreadsheet::sheet_t index;
+
+ sheet_data();
+
+ void reset();
+ };
+
+ struct row_attr
+ {
+ long number_rows_repeated;
+ row_attr();
+ };
+
+ enum cell_value_type { vt_unknown, vt_float, vt_string, vt_date };
+
+ struct cell_attr
+ {
+ long number_columns_repeated;
+ cell_value_type type;
+ double value;
+ std::string_view date_value;
+ std::string_view style_name;
+
+ std::string_view formula;
+ spreadsheet::formula_grammar_t formula_grammar;
+
+ cell_attr();
+ };
+
+ ods_content_xml_context(session_context& session_cxt, const tokens& tokens, spreadsheet::iface::import_factory* factory);
+ virtual ~ods_content_xml_context() override;
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name) override;
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child) override;
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs) override;
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+
+private:
+ void start_null_date(const xml_token_attrs_t& attrs);
+
+ void start_table(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void end_table();
+
+ void start_named_range(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void end_named_range();
+
+ void start_named_expression(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void end_named_expression();
+
+ void start_column(const xml_token_attrs_t& attrs);
+ void end_column();
+
+ void start_row(const xml_token_attrs_t& attrs);
+ void end_row();
+
+ void start_cell(const xml_token_attrs_t& attrs);
+ void end_cell();
+
+ /**
+ * Push a named cell style as a parent style of an automatic style, as we
+ * cannot directly reference a named cell style from a cell, column etc.
+ *
+ * @param style_name name of the named cell style to push.
+ *
+ * @return xfid of the newly-created automatic style that "wraps" the named
+ * cell as its parent if the call is successful, else it's not set.
+ */
+ std::optional<std::size_t> push_named_cell_style(std::string_view style_name);
+ void push_default_column_cell_style(std::string_view style_name, spreadsheet::col_t span);
+ void push_cell_format();
+ void push_cell_value();
+
+ void end_spreadsheet();
+
+private:
+ spreadsheet::iface::import_factory* mp_factory;
+ std::vector<spreadsheet::iface::import_sheet*> m_tables;
+ sheet_data m_cur_sheet;
+
+ row_attr m_row_attr;
+ cell_attr m_cell_attr; /// attributes of current cell.
+
+ int m_row;
+ int m_col;
+ int m_col_repeated;
+ size_t m_para_index;
+ bool m_has_content;
+
+ odf_styles_map_type m_styles; /// map storing all automatic styles by their names.
+ name2id_type m_cell_format_map; /// map of automatic style names to cell format (xf) IDs.
+
+ styles_context m_child_styles;
+ text_para_context m_child_para;
+ ods_dde_links_context m_child_dde_links;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ods_dde_links_context.cpp b/src/liborcus/ods_dde_links_context.cpp
new file mode 100644
index 0000000..4b644a2
--- /dev/null
+++ b/src/liborcus/ods_dde_links_context.cpp
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ods_dde_links_context.hpp"
+
+namespace orcus {
+
+ods_dde_links_context::ods_dde_links_context(session_context& session_cxt, const tokens& tokens) :
+ xml_context_base(session_cxt, tokens) {}
+
+ods_dde_links_context::~ods_dde_links_context() {}
+
+xml_context_base* ods_dde_links_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void ods_dde_links_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void ods_dde_links_context::start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& /*attrs*/)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ (void)parent;
+
+ warn_unhandled();
+}
+
+bool ods_dde_links_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ return pop_stack(ns, name);
+}
+
+void ods_dde_links_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+void ods_dde_links_context::reset()
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ods_dde_links_context.hpp b/src/liborcus/ods_dde_links_context.hpp
new file mode 100644
index 0000000..0abba49
--- /dev/null
+++ b/src/liborcus/ods_dde_links_context.hpp
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ODS_DDE_LINKS_CONTEXT_HPP
+#define INCLUDED_ODS_DDE_LINKS_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+
+namespace orcus {
+
+/**
+ * Handle <table:dde-links> element structure. For now, this context exists
+ * only to ignore all DDE related data.
+ */
+class ods_dde_links_context : public xml_context_base
+{
+public:
+ ods_dde_links_context(session_context& session_cxt, const tokens& tokens);
+ virtual ~ods_dde_links_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name) override;
+
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base *child) override;
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t> &attrs) override;
+
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+
+ virtual void characters(std::string_view str, bool transient) override;
+
+ void reset();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ods_session_data.cpp b/src/liborcus/ods_session_data.cpp
new file mode 100644
index 0000000..c039e05
--- /dev/null
+++ b/src/liborcus/ods_session_data.cpp
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ods_session_data.hpp"
+
+#include <limits>
+
+namespace orcus {
+
+ods_session_data::formula_result::formula_result() :
+ type(rt_none), numeric_value(std::numeric_limits<double>::quiet_NaN()) {}
+
+ods_session_data::formula::formula(
+ spreadsheet::sheet_t _sheet, spreadsheet::row_t _row, spreadsheet::col_t _col,
+ spreadsheet::formula_grammar_t _grammar, std::string_view _exp) :
+ sheet(_sheet), row(_row), column(_col), grammar(_grammar), exp(_exp) {}
+
+ods_session_data::named_exp::named_exp(
+ std::string_view _name, std::string_view _expression, std::string_view _base, named_exp_type _type, spreadsheet::sheet_t _scope) :
+ name(_name), expression(_expression), base(_base), type(_type), scope(_scope) {}
+
+std::string_view ods_session_data::number_formats_store::get_code(std::string_view name) const
+{
+ auto it_name = name2id_map.find(name);
+ if (it_name == name2id_map.end())
+ return {};
+
+ std::size_t id = it_name->second;
+ auto it_code = id2code_map.find(id);
+ if (it_code == id2code_map.end())
+ return {};
+
+ return it_code->second;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ods_session_data.hpp b/src/liborcus/ods_session_data.hpp
new file mode 100644
index 0000000..4223095
--- /dev/null
+++ b/src/liborcus/ods_session_data.hpp
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_ODS_SESSION_DATA_HPP
+#define INCLUDED_ORCUS_ODS_SESSION_DATA_HPP
+
+#include "session_context.hpp"
+#include "odf_styles.hpp"
+
+#include <orcus/spreadsheet/types.hpp>
+
+#include <deque>
+
+namespace orcus {
+
+struct ods_session_data : public session_context::custom_data
+{
+ enum formula_result_type { rt_none, rt_numeric, rt_string, rt_error };
+ enum named_exp_type { ne_unknown, ne_range, ne_expression };
+
+ struct formula_result
+ {
+ formula_result_type type;
+ double numeric_value;
+ std::string_view string_value;
+
+ formula_result();
+ };
+
+ struct formula
+ {
+ spreadsheet::sheet_t sheet;
+ spreadsheet::row_t row;
+ spreadsheet::col_t column;
+
+ spreadsheet::formula_grammar_t grammar;
+ std::string_view exp;
+
+ formula_result result;
+
+ formula(
+ spreadsheet::sheet_t _sheet, spreadsheet::row_t _row, spreadsheet::col_t _col,
+ spreadsheet::formula_grammar_t _grammar, std::string_view _exp);
+ };
+
+ struct named_exp
+ {
+ std::string_view name;
+ std::string_view expression;
+ std::string_view base;
+
+ named_exp_type type;
+ spreadsheet::sheet_t scope; // >= 0 for sheet scope, or < 0 for global scope.
+
+ named_exp(std::string_view _name, std::string_view _expression, std::string_view _base, named_exp_type _type, spreadsheet::sheet_t _scope);
+ };
+
+ std::deque<formula> formulas;
+ std::deque<named_exp> named_exps;
+
+ odf_styles_map_type styles_map;
+
+ struct number_formats_store
+ {
+ std::map<std::string_view, std::size_t> name2id_map;
+ std::map<std::size_t, std::string> id2code_map;
+
+ std::string_view get_code(std::string_view name) const;
+ };
+
+ number_formats_store number_formats;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_content_types.cpp b/src/liborcus/ooxml_content_types.cpp
new file mode 100644
index 0000000..eb614c7
--- /dev/null
+++ b/src/liborcus/ooxml_content_types.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ooxml_content_types.hpp"
+
+namespace orcus {
+
+const content_type_t CT_ooxml_extended_properties = "application/vnd.openxmlformats-officedocument.extended-properties+xml";
+const content_type_t CT_ooxml_drawing = "application/vnd.openxmlformats-officedocument.drawing+xml";
+const content_type_t CT_ooxml_vml_drawing = "application/vnd.openxmlformats-officedocument.vmlDrawing";
+const content_type_t CT_ooxml_xlsx_calc_chain = "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml";
+const content_type_t CT_ooxml_xlsx_comments = "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml";
+const content_type_t CT_ooxml_xlsx_connections = "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml";
+const content_type_t CT_ooxml_xlsx_external_link = "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml";
+const content_type_t CT_ooxml_xlsx_pivot_cache_def = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml";
+const content_type_t CT_ooxml_xlsx_pivot_cache_rec = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml";
+const content_type_t CT_ooxml_xlsx_pivot_table = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml";
+const content_type_t CT_ooxml_xlsx_printer_settings = "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings";
+const content_type_t CT_ooxml_xlsx_query_table = "application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml";
+const content_type_t CT_ooxml_xlsx_shared_strings = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
+const content_type_t CT_ooxml_xlsx_sheet_main = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
+const content_type_t CT_ooxml_xlsx_styles = "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml";
+const content_type_t CT_ooxml_xlsx_table = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml";
+const content_type_t CT_ooxml_xlsx_worksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
+const content_type_t CT_ooxml_xlsx_usernames = "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml";
+const content_type_t CT_ooxml_xlsx_rev_headers = "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml";
+const content_type_t CT_ooxml_xlsx_rev_log = "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml";
+const content_type_t CT_ooxml_theme = "application/vnd.openxmlformats-officedocument.theme+xml";
+const content_type_t CT_opc_core_properties = "application/vnd.openxmlformats-package.core-properties+xml";
+const content_type_t CT_opc_relationships = "application/vnd.openxmlformats-package.relationships+xml";
+const content_type_t CT_xml = "application/xml";
+const content_type_t CT_image_png = "image/png";
+
+namespace {
+
+content_type_t cts[] = {
+ CT_ooxml_extended_properties,
+ CT_ooxml_drawing,
+ CT_ooxml_vml_drawing,
+ CT_ooxml_xlsx_calc_chain,
+ CT_ooxml_xlsx_comments,
+ CT_ooxml_xlsx_connections,
+ CT_ooxml_xlsx_external_link,
+ CT_ooxml_xlsx_pivot_cache_def,
+ CT_ooxml_xlsx_pivot_cache_rec,
+ CT_ooxml_xlsx_pivot_table,
+ CT_ooxml_xlsx_printer_settings,
+ CT_ooxml_xlsx_query_table,
+ CT_ooxml_xlsx_shared_strings,
+ CT_ooxml_xlsx_sheet_main,
+ CT_ooxml_xlsx_styles,
+ CT_ooxml_xlsx_table,
+ CT_ooxml_xlsx_worksheet,
+ CT_ooxml_xlsx_usernames,
+ CT_ooxml_xlsx_rev_headers,
+ CT_ooxml_xlsx_rev_log,
+ CT_ooxml_theme,
+ CT_opc_core_properties,
+ CT_opc_relationships,
+ CT_xml,
+ CT_image_png,
+ nullptr
+};
+
+}
+
+const content_type_t* CT_all = cts;
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_content_types.hpp b/src/liborcus/ooxml_content_types.hpp
new file mode 100644
index 0000000..d82dd53
--- /dev/null
+++ b/src/liborcus/ooxml_content_types.hpp
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_OOXML_CONTENT_TYPES_HPP
+#define INCLUDED_ORCUS_OOXML_CONTENT_TYPES_HPP
+
+#include "ooxml_types.hpp"
+
+namespace orcus {
+
+extern const content_type_t CT_ooxml_extended_properties;
+extern const content_type_t CT_ooxml_drawing;
+extern const content_type_t CT_ooxml_vml_drawing;
+extern const content_type_t CT_ooxml_xlsx_calc_chain;
+extern const content_type_t CT_ooxml_xlsx_comments;
+extern const content_type_t CT_ooxml_xlsx_connections;
+extern const content_type_t CT_ooxml_xlsx_external_link;
+extern const content_type_t CT_ooxml_xlsx_pivot_cache_def;
+extern const content_type_t CT_ooxml_xlsx_pivot_cache_rec;
+extern const content_type_t CT_ooxml_xlsx_pivot_table;
+extern const content_type_t CT_ooxml_xlsx_printer_settings;
+extern const content_type_t CT_ooxml_xlsx_query_table;
+extern const content_type_t CT_ooxml_xlsx_shared_strings;
+extern const content_type_t CT_ooxml_xlsx_sheet_main;
+extern const content_type_t CT_ooxml_xlsx_styles;
+extern const content_type_t CT_ooxml_xlsx_table;
+extern const content_type_t CT_ooxml_xlsx_worksheet;
+extern const content_type_t CT_ooxml_xlsx_usernames;
+extern const content_type_t CT_ooxml_xlsx_rev_headers;
+extern const content_type_t CT_ooxml_xlsx_rev_log;
+extern const content_type_t CT_ooxml_theme;
+extern const content_type_t CT_opc_core_properties;
+extern const content_type_t CT_opc_relationships;
+extern const content_type_t CT_xml;
+extern const content_type_t CT_image_png;
+
+/**
+ * Null-terminated array of all content types.
+ */
+extern const content_type_t* CT_all;
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_global.cpp b/src/liborcus/ooxml_global.cpp
new file mode 100644
index 0000000..6c6d93b
--- /dev/null
+++ b/src/liborcus/ooxml_global.cpp
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ooxml_global.hpp"
+#include "ooxml_types.hpp"
+#include "ooxml_token_constants.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "xml_context_base.hpp"
+
+#include <iostream>
+#include <sstream>
+
+namespace orcus {
+
+void print_opc_rel::operator() (const opc_rel_t& v) const
+{
+ std::cout << v.rid << ": " << v.target << " (" << v.type << ")" << std::endl;
+}
+
+std::string resolve_file_path(const std::string& dir_path, const std::string& file_name)
+{
+ if (dir_path.empty())
+ return file_name;
+
+ const char* p = &dir_path[0];
+ const char* p_end = p + dir_path.size();
+
+ bool has_root = *p == '/';
+ if (has_root)
+ ++p;
+
+ std::vector<std::string_view> dir_stack;
+ const char* p_head = nullptr;
+ for (; p != p_end; ++p)
+ {
+ if (*p == '/')
+ {
+ if (!p_head)
+ // invalid directory path.
+ return file_name;
+
+ size_t len = p - p_head;
+ std::string_view dir(p_head, len);
+ if (dir == "..")
+ {
+ if (dir_stack.empty())
+ // invalid directory path.
+ return file_name;
+
+ dir_stack.pop_back();
+ }
+ else
+ dir_stack.push_back(dir);
+
+ p_head = nullptr;
+ }
+ else if (p_head)
+ {
+ // Do nothing.
+ }
+ else
+ p_head = p;
+ }
+
+ if (p_head)
+ {
+ // directory path must end with '/'. This one doesn't.
+ return file_name;
+ }
+
+ std::ostringstream full_path;
+ if (has_root)
+ full_path << '/';
+
+ for (auto dir : dir_stack)
+ full_path << dir << '/';
+
+ full_path << file_name;
+
+ return full_path.str();
+}
+
+void init_ooxml_context(xml_context_base& cxt)
+{
+ cxt.set_always_allowed_elements({
+ { NS_mc, XML_Choice },
+ { NS_mc, XML_Fallback },
+ });
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_global.hpp b/src/liborcus/ooxml_global.hpp
new file mode 100644
index 0000000..853c4e9
--- /dev/null
+++ b/src/liborcus/ooxml_global.hpp
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_OOXML_GLOBAL_HPP
+#define ORCUS_OOXML_GLOBAL_HPP
+
+#include "orcus/types.hpp"
+#include "ooxml_types.hpp"
+
+#include <string>
+#include <functional>
+
+namespace orcus {
+
+struct opc_rel_t;
+struct xml_token_attr_t;
+class xml_context_base;
+
+/**
+ * Function object to print relationship information.
+ */
+struct print_opc_rel
+{
+ void operator() (const opc_rel_t& v) const;
+};
+
+/**
+ * Given a directory path and a file name, return a full path that combines
+ * the two while resolving any parent directory path ".." markers.
+ *
+ * @param dir_path directory path. It can optionally start with a '/', but
+ * it must end with a '/'.
+ * @param file_name file name.
+ *
+ * @return full file path.
+ */
+std::string resolve_file_path(const std::string& dir_path, const std::string& file_name);
+
+void init_ooxml_context(xml_context_base& cxt);
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_namespace_types.cpp b/src/liborcus/ooxml_namespace_types.cpp
new file mode 100644
index 0000000..8c1224b
--- /dev/null
+++ b/src/liborcus/ooxml_namespace_types.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ooxml_namespace_types.hpp"
+
+namespace orcus {
+
+const xmlns_id_t NS_ooxml_a = "http://schemas.openxmlformats.org/drawingml/2006/main";
+const xmlns_id_t NS_ooxml_r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
+const xmlns_id_t NS_ooxml_xdr = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
+const xmlns_id_t NS_ooxml_xlsx = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
+
+const xmlns_id_t NS_opc_ct = "http://schemas.openxmlformats.org/package/2006/content-types";
+const xmlns_id_t NS_opc_rel = "http://schemas.openxmlformats.org/package/2006/relationships";
+
+const xmlns_id_t NS_mc = "http://schemas.openxmlformats.org/markup-compatibility/2006";
+const xmlns_id_t NS_mso_x14 = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main";
+
+namespace {
+
+xmlns_id_t ooxml_ns[] = {
+ NS_ooxml_a,
+ NS_ooxml_r,
+ NS_ooxml_xdr,
+ NS_ooxml_xlsx,
+ nullptr
+};
+
+xmlns_id_t opc_ns[] = {
+ NS_opc_ct,
+ NS_opc_rel,
+ nullptr
+};
+
+xmlns_id_t misc_ns[] = {
+ NS_mc,
+ NS_mso_x14,
+ nullptr
+};
+
+}
+
+const xmlns_id_t* NS_ooxml_all = ooxml_ns;
+const xmlns_id_t* NS_opc_all = opc_ns;
+const xmlns_id_t* NS_misc_all = misc_ns;
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_namespace_types.hpp b/src/liborcus/ooxml_namespace_types.hpp
new file mode 100644
index 0000000..8183bf8
--- /dev/null
+++ b/src/liborcus/ooxml_namespace_types.hpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_OOXML_NAMESPACE_TYPES_HPP
+#define INCLUDED_ORCUS_OOXML_NAMESPACE_TYPES_HPP
+
+#include "orcus/types.hpp"
+
+namespace orcus {
+
+extern const xmlns_id_t NS_ooxml_a;
+extern const xmlns_id_t NS_ooxml_r;
+extern const xmlns_id_t NS_ooxml_xlsx;
+extern const xmlns_id_t NS_ooxml_xdr;
+
+extern const xmlns_id_t NS_opc_ct;
+extern const xmlns_id_t NS_opc_rel;
+
+extern const xmlns_id_t NS_mc;
+extern const xmlns_id_t NS_mso_x14;
+
+/**
+ * Null-terminated array of all ooxml namespaces.
+ */
+extern const xmlns_id_t* NS_ooxml_all;
+
+/**
+ * Null-terminated array of all opc namespaces.
+ */
+extern const xmlns_id_t* NS_opc_all;
+
+/**
+ * Null-terminated array of all the other namespaces.
+ */
+extern const xmlns_id_t* NS_misc_all;
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_schemas.cpp b/src/liborcus/ooxml_schemas.cpp
new file mode 100644
index 0000000..b0e86e4
--- /dev/null
+++ b/src/liborcus/ooxml_schemas.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ooxml_schemas.hpp"
+
+namespace orcus {
+
+schema_t SCH_mc = "http://schemas.openxmlformats.org/markup-compatibility/2006";
+schema_t SCH_opc_content_types = "http://schemas.openxmlformats.org/package/2006/content-types";
+schema_t SCH_opc_rels = "http://schemas.openxmlformats.org/package/2006/relationships";
+schema_t SCH_opc_rels_metadata_core_props = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
+schema_t SCH_od_rels_calc_chain = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain";
+schema_t SCH_od_rels_connections = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/connections";
+schema_t SCH_od_rels_printer_settings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings";
+schema_t SCH_od_rels_rev_headers = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/revisionHeaders";
+schema_t SCH_od_rels_rev_log = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/revisionLog";
+schema_t SCH_od_rels_shared_strings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
+schema_t SCH_od_rels_styles = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
+schema_t SCH_od_rels_theme = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
+schema_t SCH_od_rels_usernames = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/usernames";
+schema_t SCH_od_rels_worksheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
+schema_t SCH_od_rels_extended_props = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
+schema_t SCH_od_rels_office_doc = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
+schema_t SCH_od_rels_table = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table";
+schema_t SCH_od_rels_pivot_cache_def = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition";
+schema_t SCH_od_rels_pivot_cache_rec = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheRecords";
+schema_t SCH_od_rels_pivot_table = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable";
+schema_t SCH_od_rels_drawing = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
+schema_t SCH_xlsx_main = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
+schema_t SCH_mso_x14ac = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac";
+
+namespace {
+
+schema_t schs[] = {
+ SCH_mc,
+ SCH_opc_content_types,
+ SCH_opc_rels,
+ SCH_opc_rels_metadata_core_props,
+ SCH_od_rels_calc_chain,
+ SCH_od_rels_connections,
+ SCH_od_rels_printer_settings,
+ SCH_od_rels_rev_headers,
+ SCH_od_rels_rev_log,
+ SCH_od_rels_shared_strings,
+ SCH_od_rels_styles,
+ SCH_od_rels_theme,
+ SCH_od_rels_usernames,
+ SCH_od_rels_worksheet,
+ SCH_od_rels_extended_props,
+ SCH_od_rels_office_doc,
+ SCH_od_rels_table,
+ SCH_od_rels_pivot_cache_def,
+ SCH_od_rels_pivot_cache_rec,
+ SCH_od_rels_pivot_table,
+ SCH_od_rels_drawing,
+ SCH_xlsx_main,
+ SCH_mso_x14ac,
+ nullptr
+};
+
+}
+
+schema_t* SCH_all = schs;
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_schemas.hpp b/src/liborcus/ooxml_schemas.hpp
new file mode 100644
index 0000000..85adb6f
--- /dev/null
+++ b/src/liborcus/ooxml_schemas.hpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_OOXML_SCHEMAS_HPP
+#define INCLUDED_ORCUS_OOXML_SCHEMAS_HPP
+
+#include "ooxml_types.hpp"
+
+namespace orcus {
+
+extern schema_t SCH_mc;
+extern schema_t SCH_opc_content_types;
+extern schema_t SCH_opc_rels;
+extern schema_t SCH_opc_rels_metadata_core_props;
+extern schema_t SCH_od_rels_calc_chain;
+extern schema_t SCH_od_rels_connections;
+extern schema_t SCH_od_rels_printer_settings;
+extern schema_t SCH_od_rels_rev_headers;
+extern schema_t SCH_od_rels_rev_log;
+extern schema_t SCH_od_rels_shared_strings;
+extern schema_t SCH_od_rels_styles;
+extern schema_t SCH_od_rels_theme;
+extern schema_t SCH_od_rels_usernames;
+extern schema_t SCH_od_rels_worksheet;
+extern schema_t SCH_od_rels_extended_props;
+extern schema_t SCH_od_rels_office_doc;
+extern schema_t SCH_od_rels_table;
+extern schema_t SCH_od_rels_pivot_cache_def;
+extern schema_t SCH_od_rels_pivot_cache_rec;
+extern schema_t SCH_od_rels_pivot_table;
+extern schema_t SCH_od_rels_drawing;
+extern schema_t SCH_xlsx_main;
+extern schema_t SCH_mso_x14ac;
+
+/**
+ * Null-terminated array of all schema types.
+ */
+extern schema_t* SCH_all;
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_token_constants.hpp b/src/liborcus/ooxml_token_constants.hpp
new file mode 100644
index 0000000..13f7fcf
--- /dev/null
+++ b/src/liborcus/ooxml_token_constants.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_OOXML_TOKEN_CONSTANTS_HPP__
+#define __ORCUS_OOXML_TOKEN_CONSTANTS_HPP__
+
+#include "orcus/types.hpp"
+
+namespace orcus {
+
+#include "ooxml_token_constants.inl"
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_token_constants.inl b/src/liborcus/ooxml_token_constants.inl
new file mode 100644
index 0000000..c2a047d
--- /dev/null
+++ b/src/liborcus/ooxml_token_constants.inl
@@ -0,0 +1,3519 @@
+// This file has been auto-generated. Do not hand-edit this.
+
+const xml_token_t XML_AbbreviatedCaseNumber = 1;
+const xml_token_t XML_Accel = 2;
+const xml_token_t XML_Accel2 = 3;
+const xml_token_t XML_AlbumTitle = 4;
+const xml_token_t XML_AlternateContent = 5;
+const xml_token_t XML_Anchor = 6;
+const xml_token_t XML_AppVersion = 7;
+const xml_token_t XML_Append = 8;
+const xml_token_t XML_Application = 9;
+const xml_token_t XML_Artist = 10;
+const xml_token_t XML_Author = 11;
+const xml_token_t XML_AutoFill = 12;
+const xml_token_t XML_AutoFit = 13;
+const xml_token_t XML_AutoLine = 14;
+const xml_token_t XML_AutoPict = 15;
+const xml_token_t XML_AutoScale = 16;
+const xml_token_t XML_BookAuthor = 17;
+const xml_token_t XML_BookTitle = 18;
+const xml_token_t XML_BroadcastTitle = 19;
+const xml_token_t XML_Broadcaster = 20;
+const xml_token_t XML_CF = 21;
+const xml_token_t XML_Camera = 22;
+const xml_token_t XML_Cancel = 23;
+const xml_token_t XML_CaseNumber = 24;
+const xml_token_t XML_ChapterNumber = 25;
+const xml_token_t XML_Characters = 26;
+const xml_token_t XML_CharactersWithSpaces = 27;
+const xml_token_t XML_Checked = 28;
+const xml_token_t XML_Choice = 29;
+const xml_token_t XML_City = 30;
+const xml_token_t XML_ClientData = 31;
+const xml_token_t XML_ColHidden = 32;
+const xml_token_t XML_Colored = 33;
+const xml_token_t XML_Column = 34;
+const xml_token_t XML_Comments = 35;
+const xml_token_t XML_Company = 36;
+const xml_token_t XML_Compiler = 37;
+const xml_token_t XML_Composer = 38;
+const xml_token_t XML_Conductor = 39;
+const xml_token_t XML_ConferenceName = 40;
+const xml_token_t XML_ConnectionID = 41;
+const xml_token_t XML_Corporate = 42;
+const xml_token_t XML_Counsel = 43;
+const xml_token_t XML_CountryRegion = 44;
+const xml_token_t XML_Court = 45;
+const xml_token_t XML_DDE = 46;
+const xml_token_t XML_DataBinding = 47;
+const xml_token_t XML_DataBindingLoadMode = 48;
+const xml_token_t XML_DataBindingName = 49;
+const xml_token_t XML_Day = 50;
+const xml_token_t XML_DayAccessed = 51;
+const xml_token_t XML_Default = 52;
+const xml_token_t XML_DefaultSize = 53;
+const xml_token_t XML_Department = 54;
+const xml_token_t XML_DigSig = 55;
+const xml_token_t XML_Director = 56;
+const xml_token_t XML_Disabled = 57;
+const xml_token_t XML_Dismiss = 58;
+const xml_token_t XML_Distributor = 59;
+const xml_token_t XML_DocSecurity = 60;
+const xml_token_t XML_DrawAspect = 61;
+const xml_token_t XML_DropLines = 62;
+const xml_token_t XML_DropStyle = 63;
+const xml_token_t XML_Dx = 64;
+const xml_token_t XML_Edition = 65;
+const xml_token_t XML_Editor = 66;
+const xml_token_t XML_Fallback = 67;
+const xml_token_t XML_FieldCodes = 68;
+const xml_token_t XML_FileBinding = 69;
+const xml_token_t XML_FileBindingName = 70;
+const xml_token_t XML_First = 71;
+const xml_token_t XML_FirstButton = 72;
+const xml_token_t XML_FmlaGroup = 73;
+const xml_token_t XML_FmlaLink = 74;
+const xml_token_t XML_FmlaMacro = 75;
+const xml_token_t XML_FmlaPict = 76;
+const xml_token_t XML_FmlaRange = 77;
+const xml_token_t XML_FmlaTxbx = 78;
+const xml_token_t XML_Guid = 79;
+const xml_token_t XML_HLinks = 80;
+const xml_token_t XML_HeadingPairs = 81;
+const xml_token_t XML_Help = 82;
+const xml_token_t XML_HiddenSlides = 83;
+const xml_token_t XML_Horiz = 84;
+const xml_token_t XML_HyperlinkBase = 85;
+const xml_token_t XML_HyperlinksChanged = 86;
+const xml_token_t XML_ID = 87;
+const xml_token_t XML_Inc = 88;
+const xml_token_t XML_Institution = 89;
+const xml_token_t XML_InternetSiteTitle = 90;
+const xml_token_t XML_Interviewee = 91;
+const xml_token_t XML_Interviewer = 92;
+const xml_token_t XML_Inventor = 93;
+const xml_token_t XML_Issue = 94;
+const xml_token_t XML_JournalName = 95;
+const xml_token_t XML_JustLastX = 96;
+const xml_token_t XML_LCID = 97;
+const xml_token_t XML_LCT = 98;
+const xml_token_t XML_Last = 99;
+const xml_token_t XML_Lines = 100;
+const xml_token_t XML_LinkType = 101;
+const xml_token_t XML_LinksUpToDate = 102;
+const xml_token_t XML_ListItem = 103;
+const xml_token_t XML_LockText = 104;
+const xml_token_t XML_Locked = 105;
+const xml_token_t XML_LockedField = 106;
+const xml_token_t XML_MMClips = 107;
+const xml_token_t XML_Manager = 108;
+const xml_token_t XML_Map = 109;
+const xml_token_t XML_MapInfo = 110;
+const xml_token_t XML_MapOCX = 111;
+const xml_token_t XML_Max = 112;
+const xml_token_t XML_Medium = 113;
+const xml_token_t XML_Middle = 114;
+const xml_token_t XML_Min = 115;
+const xml_token_t XML_Month = 116;
+const xml_token_t XML_MonthAccessed = 117;
+const xml_token_t XML_MoveWithCells = 118;
+const xml_token_t XML_MultiLine = 119;
+const xml_token_t XML_MultiSel = 120;
+const xml_token_t XML_Name = 121;
+const xml_token_t XML_NameList = 122;
+const xml_token_t XML_Namespace = 123;
+const xml_token_t XML_NoThreeD = 124;
+const xml_token_t XML_NoThreeD2 = 125;
+const xml_token_t XML_Notes = 126;
+const xml_token_t XML_NumberVolumes = 127;
+const xml_token_t XML_OLEObject = 128;
+const xml_token_t XML_ObjectID = 129;
+const xml_token_t XML_ObjectType = 130;
+const xml_token_t XML_Page = 131;
+const xml_token_t XML_Pages = 132;
+const xml_token_t XML_Paragraphs = 133;
+const xml_token_t XML_PatentNumber = 134;
+const xml_token_t XML_Performer = 135;
+const xml_token_t XML_PeriodicalTitle = 136;
+const xml_token_t XML_Person = 137;
+const xml_token_t XML_PresentationFormat = 138;
+const xml_token_t XML_PreserveFormat = 139;
+const xml_token_t XML_PreserveSortAFLayout = 140;
+const xml_token_t XML_PrintObject = 141;
+const xml_token_t XML_ProducerName = 142;
+const xml_token_t XML_ProductionCompany = 143;
+const xml_token_t XML_ProgID = 144;
+const xml_token_t XML_Properties = 145;
+const xml_token_t XML_PublicationTitle = 146;
+const xml_token_t XML_Publisher = 147;
+const xml_token_t XML_RecalcAlways = 148;
+const xml_token_t XML_RecordingNumber = 149;
+const xml_token_t XML_RefOrder = 150;
+const xml_token_t XML_Reporter = 151;
+const xml_token_t XML_RootElement = 152;
+const xml_token_t XML_Row = 153;
+const xml_token_t XML_RowHidden = 154;
+const xml_token_t XML_ScaleCrop = 155;
+const xml_token_t XML_Schema = 156;
+const xml_token_t XML_SchemaID = 157;
+const xml_token_t XML_SchemaRef = 158;
+const xml_token_t XML_ScriptExtended = 159;
+const xml_token_t XML_ScriptLanguage = 160;
+const xml_token_t XML_ScriptLocation = 161;
+const xml_token_t XML_ScriptText = 162;
+const xml_token_t XML_SecretEdit = 163;
+const xml_token_t XML_Sel = 164;
+const xml_token_t XML_SelType = 165;
+const xml_token_t XML_SelectedStyle = 166;
+const xml_token_t XML_SelectionNamespaces = 167;
+const xml_token_t XML_ShapeID = 168;
+const xml_token_t XML_SharedDoc = 169;
+const xml_token_t XML_ShortTitle = 170;
+const xml_token_t XML_ShowImportExportValidationErrors = 171;
+const xml_token_t XML_SizeWithCells = 172;
+const xml_token_t XML_Slides = 173;
+const xml_token_t XML_Source = 174;
+const xml_token_t XML_SourceType = 175;
+const xml_token_t XML_Sources = 176;
+const xml_token_t XML_StandardNumber = 177;
+const xml_token_t XML_StateProvince = 178;
+const xml_token_t XML_Station = 179;
+const xml_token_t XML_StyleName = 180;
+const xml_token_t XML_Tag = 181;
+const xml_token_t XML_Template = 182;
+const xml_token_t XML_TextHAlign = 183;
+const xml_token_t XML_TextVAlign = 184;
+const xml_token_t XML_Theater = 185;
+const xml_token_t XML_ThesisType = 186;
+const xml_token_t XML_Title = 187;
+const xml_token_t XML_TitlesOfParts = 188;
+const xml_token_t XML_TotalTime = 189;
+const xml_token_t XML_Translator = 190;
+const xml_token_t XML_Type = 191;
+const xml_token_t XML_UIObj = 192;
+const xml_token_t XML_URI = 193;
+const xml_token_t XML_URL = 194;
+const xml_token_t XML_UpdateMode = 195;
+const xml_token_t XML_VScroll = 196;
+const xml_token_t XML_VTEdit = 197;
+const xml_token_t XML_Val = 198;
+const xml_token_t XML_ValidIds = 199;
+const xml_token_t XML_Version = 200;
+const xml_token_t XML_Visible = 201;
+const xml_token_t XML_Volume = 202;
+const xml_token_t XML_WidthMin = 203;
+const xml_token_t XML_Words = 204;
+const xml_token_t XML_Writer = 205;
+const xml_token_t XML_Year = 206;
+const xml_token_t XML_YearAccessed = 207;
+const xml_token_t XML_a = 208;
+const xml_token_t XML_aboveAverage = 209;
+const xml_token_t XML_absSizeAnchor = 210;
+const xml_token_t XML_absoluteAnchor = 211;
+const xml_token_t XML_abstractNum = 212;
+const xml_token_t XML_abstractNumId = 213;
+const xml_token_t XML_aca = 214;
+const xml_token_t XML_acc = 215;
+const xml_token_t XML_accPr = 216;
+const xml_token_t XML_accel = 217;
+const xml_token_t XML_accent1 = 218;
+const xml_token_t XML_accent2 = 219;
+const xml_token_t XML_accent3 = 220;
+const xml_token_t XML_accent4 = 221;
+const xml_token_t XML_accent5 = 222;
+const xml_token_t XML_accent6 = 223;
+const xml_token_t XML_accentbar = 224;
+const xml_token_t XML_accumulate = 225;
+const xml_token_t XML_action = 226;
+const xml_token_t XML_active = 227;
+const xml_token_t XML_activeCell = 228;
+const xml_token_t XML_activeCellId = 229;
+const xml_token_t XML_activeCol = 230;
+const xml_token_t XML_activePane = 231;
+const xml_token_t XML_activeRecord = 232;
+const xml_token_t XML_activeRow = 233;
+const xml_token_t XML_activeSheetId = 234;
+const xml_token_t XML_activeTab = 235;
+const xml_token_t XML_activeWritingStyle = 236;
+const xml_token_t XML_actualPg = 237;
+const xml_token_t XML_additionalCharacteristics = 238;
+const xml_token_t XML_additive = 239;
+const xml_token_t XML_addlxml = 240;
+const xml_token_t XML_addressFieldName = 241;
+const xml_token_t XML_adj = 242;
+const xml_token_t XML_adjLst = 243;
+const xml_token_t XML_adjust = 244;
+const xml_token_t XML_adjustColumnWidth = 245;
+const xml_token_t XML_adjustLineHeightInTable = 246;
+const xml_token_t XML_adjustRightInd = 247;
+const xml_token_t XML_adjusthandles = 248;
+const xml_token_t XML_advAuto = 249;
+const xml_token_t XML_advClick = 250;
+const xml_token_t XML_advTm = 251;
+const xml_token_t XML_advise = 252;
+const xml_token_t XML_after = 253;
+const xml_token_t XML_afterAutospacing = 254;
+const xml_token_t XML_afterEffect = 255;
+const xml_token_t XML_afterLines = 256;
+const xml_token_t XML_ahLst = 257;
+const xml_token_t XML_ahPolar = 258;
+const xml_token_t XML_ahXY = 259;
+const xml_token_t XML_alg = 260;
+const xml_token_t XML_algIdExt = 261;
+const xml_token_t XML_algIdExtSource = 262;
+const xml_token_t XML_algn = 263;
+const xml_token_t XML_alias = 264;
+const xml_token_t XML_aliases = 265;
+const xml_token_t XML_align = 266;
+const xml_token_t XML_alignBordersAndEdges = 267;
+const xml_token_t XML_alignTablesRowByRow = 268;
+const xml_token_t XML_alignWithMargins = 269;
+const xml_token_t XML_alignment = 270;
+const xml_token_t XML_alignshape = 271;
+const xml_token_t XML_all = 272;
+const xml_token_t XML_allCaption = 273;
+const xml_token_t XML_allDrilled = 274;
+const xml_token_t XML_allUniqueName = 275;
+const xml_token_t XML_allowBlank = 276;
+const xml_token_t XML_allowOverlap = 277;
+const xml_token_t XML_allowPNG = 278;
+const xml_token_t XML_allowPng = 279;
+const xml_token_t XML_allowRefreshQuery = 280;
+const xml_token_t XML_allowSpaceOfSameStyleInTable = 281;
+const xml_token_t XML_allowcomments = 282;
+const xml_token_t XML_allowincell = 283;
+const xml_token_t XML_allowoverlap = 284;
+const xml_token_t XML_aln = 285;
+const xml_token_t XML_alnAt = 286;
+const xml_token_t XML_alnScr = 287;
+const xml_token_t XML_alpha = 288;
+const xml_token_t XML_alphaBiLevel = 289;
+const xml_token_t XML_alphaCeiling = 290;
+const xml_token_t XML_alphaFloor = 291;
+const xml_token_t XML_alphaInv = 292;
+const xml_token_t XML_alphaMod = 293;
+const xml_token_t XML_alphaModFix = 294;
+const xml_token_t XML_alphaOff = 295;
+const xml_token_t XML_alphaOutset = 296;
+const xml_token_t XML_alphaRepl = 297;
+const xml_token_t XML_alt = 298;
+const xml_token_t XML_altChunk = 299;
+const xml_token_t XML_altChunkPr = 300;
+const xml_token_t XML_altLang = 301;
+const xml_token_t XML_altName = 302;
+const xml_token_t XML_althref = 303;
+const xml_token_t XML_alwaysMergeEmptyNamespace = 304;
+const xml_token_t XML_alwaysShow = 305;
+const xml_token_t XML_alwaysShowPlaceholderText = 306;
+const xml_token_t XML_amt = 307;
+const xml_token_t XML_anchor = 308;
+const xml_token_t XML_anchorCtr = 309;
+const xml_token_t XML_anchorLock = 310;
+const xml_token_t XML_anchorlock = 311;
+const xml_token_t XML_anchorx = 312;
+const xml_token_t XML_anchory = 313;
+const xml_token_t XML_and = 314;
+const xml_token_t XML_ang = 315;
+const xml_token_t XML_angle = 316;
+const xml_token_t XML_anim = 317;
+const xml_token_t XML_animBg = 318;
+const xml_token_t XML_animClr = 319;
+const xml_token_t XML_animEffect = 320;
+const xml_token_t XML_animLvl = 321;
+const xml_token_t XML_animMotion = 322;
+const xml_token_t XML_animOne = 323;
+const xml_token_t XML_animRot = 324;
+const xml_token_t XML_animScale = 325;
+const xml_token_t XML_annotation = 326;
+const xml_token_t XML_annotationRef = 327;
+const xml_token_t XML_appName = 328;
+const xml_token_t XML_applyAlignment = 329;
+const xml_token_t XML_applyAlignmentFormats = 330;
+const xml_token_t XML_applyBorder = 331;
+const xml_token_t XML_applyBorderFormats = 332;
+const xml_token_t XML_applyBreakingRules = 333;
+const xml_token_t XML_applyFill = 334;
+const xml_token_t XML_applyFont = 335;
+const xml_token_t XML_applyFontFormats = 336;
+const xml_token_t XML_applyNumberFormat = 337;
+const xml_token_t XML_applyNumberFormats = 338;
+const xml_token_t XML_applyPatternFormats = 339;
+const xml_token_t XML_applyProtection = 340;
+const xml_token_t XML_applyStyles = 341;
+const xml_token_t XML_applyToEnd = 342;
+const xml_token_t XML_applyToFront = 343;
+const xml_token_t XML_applyToSides = 344;
+const xml_token_t XML_applyWidthHeightFormats = 345;
+const xml_token_t XML_arc = 346;
+const xml_token_t XML_arcTo = 347;
+const xml_token_t XML_arcsize = 348;
+const xml_token_t XML_area3DChart = 349;
+const xml_token_t XML_areaChart = 350;
+const xml_token_t XML_arg = 351;
+const xml_token_t XML_argPr = 352;
+const xml_token_t XML_argSz = 353;
+const xml_token_t XML_array = 354;
+const xml_token_t XML_arrowok = 355;
+const xml_token_t XML_ascii = 356;
+const xml_token_t XML_asciiTheme = 357;
+const xml_token_t XML_aspect = 358;
+const xml_token_t XML_aspectratio = 359;
+const xml_token_t XML_assign = 360;
+const xml_token_t XML_asteriskTotals = 361;
+const xml_token_t XML_attachedSchema = 362;
+const xml_token_t XML_attachedTemplate = 363;
+const xml_token_t XML_attr = 364;
+const xml_token_t XML_attrName = 365;
+const xml_token_t XML_attrNameLst = 366;
+const xml_token_t XML_attribute = 367;
+const xml_token_t XML_audio = 368;
+const xml_token_t XML_audioCd = 369;
+const xml_token_t XML_audioFile = 370;
+const xml_token_t XML_author = 371;
+const xml_token_t XML_authorId = 372;
+const xml_token_t XML_authors = 373;
+const xml_token_t XML_auto = 374;
+const xml_token_t XML_autoAdjust = 375;
+const xml_token_t XML_autoCaption = 376;
+const xml_token_t XML_autoCaptions = 377;
+const xml_token_t XML_autoCompressPictures = 378;
+const xml_token_t XML_autoEnd = 379;
+const xml_token_t XML_autoFilter = 380;
+const xml_token_t XML_autoFilterDateGrouping = 381;
+const xml_token_t XML_autoFormatId = 382;
+const xml_token_t XML_autoFormatOverride = 383;
+const xml_token_t XML_autoHyphenation = 384;
+const xml_token_t XML_autoLoad = 385;
+const xml_token_t XML_autoPage = 386;
+const xml_token_t XML_autoPageBreaks = 387;
+const xml_token_t XML_autoRecover = 388;
+const xml_token_t XML_autoRedefine = 389;
+const xml_token_t XML_autoRepublish = 390;
+const xml_token_t XML_autoRev = 391;
+const xml_token_t XML_autoShow = 392;
+const xml_token_t XML_autoSortScope = 393;
+const xml_token_t XML_autoSpaceDE = 394;
+const xml_token_t XML_autoSpaceDN = 395;
+const xml_token_t XML_autoSpaceLikeWord95 = 396;
+const xml_token_t XML_autoStart = 397;
+const xml_token_t XML_autoTitleDeleted = 398;
+const xml_token_t XML_autoUpdate = 399;
+const xml_token_t XML_autoUpdateAnimBg = 400;
+const xml_token_t XML_autofitToFirstFixedWidthCell = 401;
+const xml_token_t XML_autoformat = 402;
+const xml_token_t XML_autolayout = 403;
+const xml_token_t XML_autorotationcenter = 404;
+const xml_token_t XML_avLst = 405;
+const xml_token_t XML_avgSubtotal = 406;
+const xml_token_t XML_axId = 407;
+const xml_token_t XML_axPos = 408;
+const xml_token_t XML_axis = 409;
+const xml_token_t XML_b = 410;
+const xml_token_t XML_bCs = 411;
+const xml_token_t XML_bIns = 412;
+const xml_token_t XML_backWall = 413;
+const xml_token_t XML_backdepth = 414;
+const xml_token_t XML_backdrop = 415;
+const xml_token_t XML_background = 416;
+const xml_token_t XML_backgroundQuery = 417;
+const xml_token_t XML_backgroundRefresh = 418;
+const xml_token_t XML_backupFile = 419;
+const xml_token_t XML_backward = 420;
+const xml_token_t XML_backwards = 421;
+const xml_token_t XML_balanceSingleByteDoubleByteWidth = 422;
+const xml_token_t XML_band1H = 423;
+const xml_token_t XML_band1V = 424;
+const xml_token_t XML_band2H = 425;
+const xml_token_t XML_band2V = 426;
+const xml_token_t XML_bandCol = 427;
+const xml_token_t XML_bandFmt = 428;
+const xml_token_t XML_bandFmts = 429;
+const xml_token_t XML_bandRow = 430;
+const xml_token_t XML_bar = 431;
+const xml_token_t XML_bar3DChart = 432;
+const xml_token_t XML_barChart = 433;
+const xml_token_t XML_barDir = 434;
+const xml_token_t XML_barPr = 435;
+const xml_token_t XML_base = 436;
+const xml_token_t XML_baseColWidth = 437;
+const xml_token_t XML_baseField = 438;
+const xml_token_t XML_baseItem = 439;
+const xml_token_t XML_baseJc = 440;
+const xml_token_t XML_baseTimeUnit = 441;
+const xml_token_t XML_baseType = 442;
+const xml_token_t XML_basedOn = 443;
+const xml_token_t XML_baseline = 444;
+const xml_token_t XML_bc = 445;
+const xml_token_t XML_bdr = 446;
+const xml_token_t XML_before = 447;
+const xml_token_t XML_beforeAutospacing = 448;
+const xml_token_t XML_beforeLines = 449;
+const xml_token_t XML_begChr = 450;
+const xml_token_t XML_behavior = 451;
+const xml_token_t XML_behaviors = 452;
+const xml_token_t XML_behindDoc = 453;
+const xml_token_t XML_bestFit = 454;
+const xml_token_t XML_between = 455;
+const xml_token_t XML_bevel = 456;
+const xml_token_t XML_bevelB = 457;
+const xml_token_t XML_bevelT = 458;
+const xml_token_t XML_bg = 459;
+const xml_token_t XML_bg1 = 460;
+const xml_token_t XML_bg2 = 461;
+const xml_token_t XML_bgClr = 462;
+const xml_token_t XML_bgColor = 463;
+const xml_token_t XML_bgFillStyleLst = 464;
+const xml_token_t XML_bgPr = 465;
+const xml_token_t XML_bgRef = 466;
+const xml_token_t XML_biLevel = 467;
+const xml_token_t XML_bibliography = 468;
+const xml_token_t XML_bidi = 469;
+const xml_token_t XML_bidiVisual = 470;
+const xml_token_t XML_bilevel = 471;
+const xml_token_t XML_bk = 472;
+const xml_token_t XML_blackAndWhite = 473;
+const xml_token_t XML_blacklevel = 474;
+const xml_token_t XML_blank = 475;
+const xml_token_t XML_bld = 476;
+const xml_token_t XML_bldAsOne = 477;
+const xml_token_t XML_bldChart = 478;
+const xml_token_t XML_bldDgm = 479;
+const xml_token_t XML_bldGraphic = 480;
+const xml_token_t XML_bldLst = 481;
+const xml_token_t XML_bldLvl = 482;
+const xml_token_t XML_bldOleChart = 483;
+const xml_token_t XML_bldP = 484;
+const xml_token_t XML_bldStep = 485;
+const xml_token_t XML_bldSub = 486;
+const xml_token_t XML_blend = 487;
+const xml_token_t XML_blinds = 488;
+const xml_token_t XML_blip = 489;
+const xml_token_t XML_blipFill = 490;
+const xml_token_t XML_blipPhldr = 491;
+const xml_token_t XML_blob = 492;
+const xml_token_t XML_blockQuote = 493;
+const xml_token_t XML_blue = 494;
+const xml_token_t XML_blueMod = 495;
+const xml_token_t XML_blueOff = 496;
+const xml_token_t XML_blur = 497;
+const xml_token_t XML_blurRad = 498;
+const xml_token_t XML_bmk = 499;
+const xml_token_t XML_body = 500;
+const xml_token_t XML_bodyDiv = 501;
+const xml_token_t XML_bodyPr = 502;
+const xml_token_t XML_bodyStyle = 503;
+const xml_token_t XML_bold = 504;
+const xml_token_t XML_boldItalic = 505;
+const xml_token_t XML_bookFoldPrinting = 506;
+const xml_token_t XML_bookFoldPrintingSheets = 507;
+const xml_token_t XML_bookFoldRevPrinting = 508;
+const xml_token_t XML_bookViews = 509;
+const xml_token_t XML_bookmarkEnd = 510;
+const xml_token_t XML_bookmarkIdSeed = 511;
+const xml_token_t XML_bookmarkStart = 512;
+const xml_token_t XML_bool = 513;
+const xml_token_t XML_boolVal = 514;
+const xml_token_t XML_boolean = 515;
+const xml_token_t XML_border = 516;
+const xml_token_t XML_borderBox = 517;
+const xml_token_t XML_borderBoxPr = 518;
+const xml_token_t XML_borderId = 519;
+const xml_token_t XML_borderbottom = 520;
+const xml_token_t XML_borderbottomcolor = 521;
+const xml_token_t XML_borderleft = 522;
+const xml_token_t XML_borderleftcolor = 523;
+const xml_token_t XML_borderright = 524;
+const xml_token_t XML_borderrightcolor = 525;
+const xml_token_t XML_borders = 526;
+const xml_token_t XML_bordersDoNotSurroundFooter = 527;
+const xml_token_t XML_bordersDoNotSurroundHeader = 528;
+const xml_token_t XML_bordertop = 529;
+const xml_token_t XML_bordertopcolor = 530;
+const xml_token_t XML_bottom = 531;
+const xml_token_t XML_bottomFromText = 532;
+const xml_token_t XML_box = 533;
+const xml_token_t XML_boxPr = 534;
+const xml_token_t XML_br = 535;
+const xml_token_t XML_bright = 536;
+const xml_token_t XML_brightness = 537;
+const xml_token_t XML_brk = 538;
+const xml_token_t XML_brkBin = 539;
+const xml_token_t XML_brkBinSub = 540;
+const xml_token_t XML_browse = 541;
+const xml_token_t XML_bstr = 542;
+const xml_token_t XML_buAutoNum = 543;
+const xml_token_t XML_buBlip = 544;
+const xml_token_t XML_buChar = 545;
+const xml_token_t XML_buClr = 546;
+const xml_token_t XML_buClrTx = 547;
+const xml_token_t XML_buFont = 548;
+const xml_token_t XML_buFontTx = 549;
+const xml_token_t XML_buNone = 550;
+const xml_token_t XML_buSzPct = 551;
+const xml_token_t XML_buSzPts = 552;
+const xml_token_t XML_buSzTx = 553;
+const xml_token_t XML_bubble3D = 554;
+const xml_token_t XML_bubbleChart = 555;
+const xml_token_t XML_bubbleScale = 556;
+const xml_token_t XML_bubbleSize = 557;
+const xml_token_t XML_build = 558;
+const xml_token_t XML_builtIn = 559;
+const xml_token_t XML_builtInGroupCount = 560;
+const xml_token_t XML_builtInUnit = 561;
+const xml_token_t XML_builtinId = 562;
+const xml_token_t XML_bullet = 563;
+const xml_token_t XML_bulletEnabled = 564;
+const xml_token_t XML_button = 565;
+const xml_token_t XML_bw = 566;
+const xml_token_t XML_bwMode = 567;
+const xml_token_t XML_bwmode = 568;
+const xml_token_t XML_bwnormal = 569;
+const xml_token_t XML_bwpure = 570;
+const xml_token_t XML_bx = 571;
+const xml_token_t XML_by = 572;
+const xml_token_t XML_byPosition = 573;
+const xml_token_t XML_c = 574;
+const xml_token_t XML_cBhvr = 575;
+const xml_token_t XML_cGp = 576;
+const xml_token_t XML_cGpRule = 577;
+const xml_token_t XML_cMediaNode = 578;
+const xml_token_t XML_cNvCxnSpPr = 579;
+const xml_token_t XML_cNvGraphicFramePr = 580;
+const xml_token_t XML_cNvGrpSpPr = 581;
+const xml_token_t XML_cNvPicPr = 582;
+const xml_token_t XML_cNvPr = 583;
+const xml_token_t XML_cNvSpPr = 584;
+const xml_token_t XML_cSld = 585;
+const xml_token_t XML_cSldViewPr = 586;
+const xml_token_t XML_cSp = 587;
+const xml_token_t XML_cTn = 588;
+const xml_token_t XML_cViewPr = 589;
+const xml_token_t XML_ca = 590;
+const xml_token_t XML_cacheField = 591;
+const xml_token_t XML_cacheFields = 592;
+const xml_token_t XML_cacheHierarchies = 593;
+const xml_token_t XML_cacheHierarchy = 594;
+const xml_token_t XML_cacheId = 595;
+const xml_token_t XML_cacheIndex = 596;
+const xml_token_t XML_cacheSource = 597;
+const xml_token_t XML_cachedColBalance = 598;
+const xml_token_t XML_calcChain = 599;
+const xml_token_t XML_calcCompleted = 600;
+const xml_token_t XML_calcId = 601;
+const xml_token_t XML_calcMode = 602;
+const xml_token_t XML_calcOnExit = 603;
+const xml_token_t XML_calcOnSave = 604;
+const xml_token_t XML_calcPr = 605;
+const xml_token_t XML_calcmode = 606;
+const xml_token_t XML_calculatedColumn = 607;
+const xml_token_t XML_calculatedColumnFormula = 608;
+const xml_token_t XML_calculatedItem = 609;
+const xml_token_t XML_calculatedItems = 610;
+const xml_token_t XML_calculatedMember = 611;
+const xml_token_t XML_calculatedMembers = 612;
+const xml_token_t XML_calendar = 613;
+const xml_token_t XML_calendarType = 614;
+const xml_token_t XML_callout = 615;
+const xml_token_t XML_camera = 616;
+const xml_token_t XML_cantSplit = 617;
+const xml_token_t XML_cap = 618;
+const xml_token_t XML_caps = 619;
+const xml_token_t XML_caption = 620;
+const xml_token_t XML_captions = 621;
+const xml_token_t XML_caseSensitive = 622;
+const xml_token_t XML_cat = 623;
+const xml_token_t XML_catAx = 624;
+const xml_token_t XML_catLst = 625;
+const xml_token_t XML_category = 626;
+const xml_token_t XML_categoryIdx = 627;
+const xml_token_t XML_cell = 628;
+const xml_token_t XML_cell3D = 629;
+const xml_token_t XML_cellColor = 630;
+const xml_token_t XML_cellComments = 631;
+const xml_token_t XML_cellDel = 632;
+const xml_token_t XML_cellIns = 633;
+const xml_token_t XML_cellMerge = 634;
+const xml_token_t XML_cellMeta = 635;
+const xml_token_t XML_cellMetadata = 636;
+const xml_token_t XML_cellSmartTag = 637;
+const xml_token_t XML_cellSmartTagPr = 638;
+const xml_token_t XML_cellSmartTags = 639;
+const xml_token_t XML_cellStyle = 640;
+const xml_token_t XML_cellStyleXfs = 641;
+const xml_token_t XML_cellStyles = 642;
+const xml_token_t XML_cellWatch = 643;
+const xml_token_t XML_cellWatches = 644;
+const xml_token_t XML_cellXfs = 645;
+const xml_token_t XML_cf = 646;
+const xml_token_t XML_cfRule = 647;
+const xml_token_t XML_cfvo = 648;
+const xml_token_t XML_chExt = 649;
+const xml_token_t XML_chMax = 650;
+const xml_token_t XML_chOff = 651;
+const xml_token_t XML_chOrder = 652;
+const xml_token_t XML_chPref = 653;
+const xml_token_t XML_changesSavedWin = 654;
+const xml_token_t XML_chapNum = 655;
+const xml_token_t XML_chapSep = 656;
+const xml_token_t XML_chapStyle = 657;
+const xml_token_t XML_char = 658;
+const xml_token_t XML_charRg = 659;
+const xml_token_t XML_charSpace = 660;
+const xml_token_t XML_characterSpacingControl = 661;
+const xml_token_t XML_characteristic = 662;
+const xml_token_t XML_charset = 663;
+const xml_token_t XML_chart = 664;
+const xml_token_t XML_chartFormat = 665;
+const xml_token_t XML_chartFormats = 666;
+const xml_token_t XML_chartObject = 667;
+const xml_token_t XML_chartSpace = 668;
+const xml_token_t XML_chartsheet = 669;
+const xml_token_t XML_checkBox = 670;
+const xml_token_t XML_checkCompatibility = 671;
+const xml_token_t XML_checkErrors = 672;
+const xml_token_t XML_checkStyle = 673;
+const xml_token_t XML_checked = 674;
+const xml_token_t XML_checker = 675;
+const xml_token_t XML_childTnLst = 676;
+const xml_token_t XML_choose = 677;
+const xml_token_t XML_chr = 678;
+const xml_token_t XML_chromakey = 679;
+const xml_token_t XML_circle = 680;
+const xml_token_t XML_citation = 681;
+const xml_token_t XML_class = 682;
+const xml_token_t XML_clear = 683;
+const xml_token_t XML_clearAll = 684;
+const xml_token_t XML_clearComments = 685;
+const xml_token_t XML_clearContents = 686;
+const xml_token_t XML_clearFormats = 687;
+const xml_token_t XML_click = 688;
+const xml_token_t XML_clickAndTypeStyle = 689;
+const xml_token_t XML_clientData = 690;
+const xml_token_t XML_clientInsertedTime = 691;
+const xml_token_t XML_clip = 692;
+const xml_token_t XML_clippath = 693;
+const xml_token_t XML_clipped = 694;
+const xml_token_t XML_cliptowrap = 695;
+const xml_token_t XML_close = 696;
+const xml_token_t XML_clr = 697;
+const xml_token_t XML_clrChange = 698;
+const xml_token_t XML_clrData = 699;
+const xml_token_t XML_clrFrom = 700;
+const xml_token_t XML_clrIdx = 701;
+const xml_token_t XML_clrMap = 702;
+const xml_token_t XML_clrMapOvr = 703;
+const xml_token_t XML_clrMode = 704;
+const xml_token_t XML_clrMru = 705;
+const xml_token_t XML_clrRepl = 706;
+const xml_token_t XML_clrScheme = 707;
+const xml_token_t XML_clrSchemeMapping = 708;
+const xml_token_t XML_clrSpc = 709;
+const xml_token_t XML_clrTo = 710;
+const xml_token_t XML_clrVal = 711;
+const xml_token_t XML_clsid = 712;
+const xml_token_t XML_cm = 713;
+const xml_token_t XML_cmAuthor = 714;
+const xml_token_t XML_cmAuthorLst = 715;
+const xml_token_t XML_cmLst = 716;
+const xml_token_t XML_cmd = 717;
+const xml_token_t XML_cmpd = 718;
+const xml_token_t XML_cnfStyle = 719;
+const xml_token_t XML_cnt = 720;
+const xml_token_t XML_code = 721;
+const xml_token_t XML_codeName = 722;
+const xml_token_t XML_codePage = 723;
+const xml_token_t XML_coerce = 724;
+const xml_token_t XML_coherent3DOff = 725;
+const xml_token_t XML_col = 726;
+const xml_token_t XML_colBreaks = 727;
+const xml_token_t XML_colDelim = 728;
+const xml_token_t XML_colFields = 729;
+const xml_token_t XML_colFirst = 730;
+const xml_token_t XML_colGrandTotals = 731;
+const xml_token_t XML_colHeaderCaption = 732;
+const xml_token_t XML_colHierarchiesUsage = 733;
+const xml_token_t XML_colHierarchyUsage = 734;
+const xml_token_t XML_colId = 735;
+const xml_token_t XML_colItems = 736;
+const xml_token_t XML_colLast = 737;
+const xml_token_t XML_colOff = 738;
+const xml_token_t XML_colPageCount = 739;
+const xml_token_t XML_collapse = 740;
+const xml_token_t XML_collapsed = 741;
+const xml_token_t XML_collapsedLevelsAreSubtotals = 742;
+const xml_token_t XML_color = 743;
+const xml_token_t XML_color2 = 744;
+const xml_token_t XML_colorFilter = 745;
+const xml_token_t XML_colorId = 746;
+const xml_token_t XML_colorScale = 747;
+const xml_token_t XML_colormenu = 748;
+const xml_token_t XML_colormode = 749;
+const xml_token_t XML_colormru = 750;
+const xml_token_t XML_colors = 751;
+const xml_token_t XML_colorsDef = 752;
+const xml_token_t XML_colorsDefHdr = 753;
+const xml_token_t XML_colorsDefHdrLst = 754;
+const xml_token_t XML_cols = 755;
+const xml_token_t XML_column = 756;
+const xml_token_t XML_columnSort = 757;
+const xml_token_t XML_comb = 758;
+const xml_token_t XML_combine = 759;
+const xml_token_t XML_combineBrackets = 760;
+const xml_token_t XML_comboBox = 761;
+const xml_token_t XML_comma = 762;
+const xml_token_t XML_command = 763;
+const xml_token_t XML_commandType = 764;
+const xml_token_t XML_comment = 765;
+const xml_token_t XML_commentList = 766;
+const xml_token_t XML_commentRangeEnd = 767;
+const xml_token_t XML_commentRangeStart = 768;
+const xml_token_t XML_commentReference = 769;
+const xml_token_t XML_comments = 770;
+const xml_token_t XML_comp = 771;
+const xml_token_t XML_compact = 772;
+const xml_token_t XML_compactData = 773;
+const xml_token_t XML_compat = 774;
+const xml_token_t XML_compatLnSpc = 775;
+const xml_token_t XML_compatMode = 776;
+const xml_token_t XML_complex = 777;
+const xml_token_t XML_concurrent = 778;
+const xml_token_t XML_concurrentCalc = 779;
+const xml_token_t XML_concurrentManualCount = 780;
+const xml_token_t XML_cond = 781;
+const xml_token_t XML_condense = 782;
+const xml_token_t XML_conditionalFormat = 783;
+const xml_token_t XML_conditionalFormats = 784;
+const xml_token_t XML_conditionalFormatting = 785;
+const xml_token_t XML_connectString = 786;
+const xml_token_t XML_connectangles = 787;
+const xml_token_t XML_connection = 788;
+const xml_token_t XML_connectionId = 789;
+const xml_token_t XML_connections = 790;
+const xml_token_t XML_connectloc = 791;
+const xml_token_t XML_connectlocs = 792;
+const xml_token_t XML_connectortype = 793;
+const xml_token_t XML_connecttype = 794;
+const xml_token_t XML_consecutive = 795;
+const xml_token_t XML_consecutiveHyphenLimit = 796;
+const xml_token_t XML_consolidation = 797;
+const xml_token_t XML_constr = 798;
+const xml_token_t XML_constrLst = 799;
+const xml_token_t XML_constrainbounds = 800;
+const xml_token_t XML_cont = 801;
+const xml_token_t XML_containsBlank = 802;
+const xml_token_t XML_containsDate = 803;
+const xml_token_t XML_containsInteger = 804;
+const xml_token_t XML_containsMixedTypes = 805;
+const xml_token_t XML_containsNonDate = 806;
+const xml_token_t XML_containsNumber = 807;
+const xml_token_t XML_containsSemiMixedTypes = 808;
+const xml_token_t XML_containsString = 809;
+const xml_token_t XML_content = 810;
+const xml_token_t XML_contextualSpacing = 811;
+const xml_token_t XML_continuationSeparator = 812;
+const xml_token_t XML_contourClr = 813;
+const xml_token_t XML_contourW = 814;
+const xml_token_t XML_contrast = 815;
+const xml_token_t XML_control = 816;
+const xml_token_t XML_control1 = 817;
+const xml_token_t XML_control2 = 818;
+const xml_token_t XML_controls = 819;
+const xml_token_t XML_convMailMergeEsc = 820;
+const xml_token_t XML_coordorigin = 821;
+const xml_token_t XML_coordsize = 822;
+const xml_token_t XML_copies = 823;
+const xml_token_t XML_copy = 824;
+const xml_token_t XML_count = 825;
+const xml_token_t XML_countASubtotal = 826;
+const xml_token_t XML_countBy = 827;
+const xml_token_t XML_countSubtotal = 828;
+const xml_token_t XML_cover = 829;
+const xml_token_t XML_cp = 830;
+const xml_token_t XML_cr = 831;
+const xml_token_t XML_crashSave = 832;
+const xml_token_t XML_createdVersion = 833;
+const xml_token_t XML_credentials = 834;
+const xml_token_t XML_cropbottom = 835;
+const xml_token_t XML_cropleft = 836;
+const xml_token_t XML_cropping = 837;
+const xml_token_t XML_cropright = 838;
+const xml_token_t XML_croptop = 839;
+const xml_token_t XML_crossAx = 840;
+const xml_token_t XML_crossBetween = 841;
+const xml_token_t XML_crosses = 842;
+const xml_token_t XML_crossesAt = 843;
+const xml_token_t XML_cryptAlgorithmClass = 844;
+const xml_token_t XML_cryptAlgorithmSid = 845;
+const xml_token_t XML_cryptAlgorithmType = 846;
+const xml_token_t XML_cryptProvider = 847;
+const xml_token_t XML_cryptProviderType = 848;
+const xml_token_t XML_cryptProviderTypeExt = 849;
+const xml_token_t XML_cryptProviderTypeExtSource = 850;
+const xml_token_t XML_cryptSpinCount = 851;
+const xml_token_t XML_cs = 852;
+const xml_token_t XML_csCatId = 853;
+const xml_token_t XML_csTypeId = 854;
+const xml_token_t XML_csb0 = 855;
+const xml_token_t XML_csb1 = 856;
+const xml_token_t XML_css = 857;
+const xml_token_t XML_cstate = 858;
+const xml_token_t XML_cstheme = 859;
+const xml_token_t XML_ct = 860;
+const xml_token_t XML_ctrlPr = 861;
+const xml_token_t XML_cubicBezTo = 862;
+const xml_token_t XML_culture = 863;
+const xml_token_t XML_current = 864;
+const xml_token_t XML_curve = 865;
+const xml_token_t XML_custAng = 866;
+const xml_token_t XML_custClr = 867;
+const xml_token_t XML_custClrLst = 868;
+const xml_token_t XML_custDash = 869;
+const xml_token_t XML_custData = 870;
+const xml_token_t XML_custDataLst = 871;
+const xml_token_t XML_custFlipHor = 872;
+const xml_token_t XML_custFlipVert = 873;
+const xml_token_t XML_custGeom = 874;
+const xml_token_t XML_custLinFactNeighborX = 875;
+const xml_token_t XML_custLinFactNeighborY = 876;
+const xml_token_t XML_custLinFactX = 877;
+const xml_token_t XML_custLinFactY = 878;
+const xml_token_t XML_custRadScaleInc = 879;
+const xml_token_t XML_custRadScaleRad = 880;
+const xml_token_t XML_custScaleX = 881;
+const xml_token_t XML_custScaleY = 882;
+const xml_token_t XML_custShow = 883;
+const xml_token_t XML_custShowLst = 884;
+const xml_token_t XML_custSplit = 885;
+const xml_token_t XML_custSzX = 886;
+const xml_token_t XML_custSzY = 887;
+const xml_token_t XML_custT = 888;
+const xml_token_t XML_custUnit = 889;
+const xml_token_t XML_customBuiltin = 890;
+const xml_token_t XML_customFilter = 891;
+const xml_token_t XML_customFilters = 892;
+const xml_token_t XML_customFormat = 893;
+const xml_token_t XML_customHeight = 894;
+const xml_token_t XML_customList = 895;
+const xml_token_t XML_customListSort = 896;
+const xml_token_t XML_customMarkFollows = 897;
+const xml_token_t XML_customMenu = 898;
+const xml_token_t XML_customPr = 899;
+const xml_token_t XML_customProperties = 900;
+const xml_token_t XML_customRollUp = 901;
+const xml_token_t XML_customSheetView = 902;
+const xml_token_t XML_customSheetViews = 903;
+const xml_token_t XML_customStyle = 904;
+const xml_token_t XML_customView = 905;
+const xml_token_t XML_customWidth = 906;
+const xml_token_t XML_customWorkbookView = 907;
+const xml_token_t XML_customWorkbookViews = 908;
+const xml_token_t XML_customXml = 909;
+const xml_token_t XML_customXmlDelRangeEnd = 910;
+const xml_token_t XML_customXmlDelRangeStart = 911;
+const xml_token_t XML_customXmlInsRangeEnd = 912;
+const xml_token_t XML_customXmlInsRangeStart = 913;
+const xml_token_t XML_customXmlMoveFromRangeEnd = 914;
+const xml_token_t XML_customXmlMoveFromRangeStart = 915;
+const xml_token_t XML_customXmlMoveToRangeEnd = 916;
+const xml_token_t XML_customXmlMoveToRangeStart = 917;
+const xml_token_t XML_customXmlPr = 918;
+const xml_token_t XML_cut = 919;
+const xml_token_t XML_cx = 920;
+const xml_token_t XML_cxn = 921;
+const xml_token_t XML_cxnId = 922;
+const xml_token_t XML_cxnLst = 923;
+const xml_token_t XML_cxnSp = 924;
+const xml_token_t XML_cxnSpLocks = 925;
+const xml_token_t XML_cy = 926;
+const xml_token_t XML_d = 927;
+const xml_token_t XML_dLbl = 928;
+const xml_token_t XML_dLblPos = 929;
+const xml_token_t XML_dLbls = 930;
+const xml_token_t XML_dPr = 931;
+const xml_token_t XML_dPt = 932;
+const xml_token_t XML_dTable = 933;
+const xml_token_t XML_dashstyle = 934;
+const xml_token_t XML_data = 935;
+const xml_token_t XML_dataBar = 936;
+const xml_token_t XML_dataBinding = 937;
+const xml_token_t XML_dataBound = 938;
+const xml_token_t XML_dataCaption = 939;
+const xml_token_t XML_dataCellStyle = 940;
+const xml_token_t XML_dataConsolidate = 941;
+const xml_token_t XML_dataDxfId = 942;
+const xml_token_t XML_dataExtractLoad = 943;
+const xml_token_t XML_dataField = 944;
+const xml_token_t XML_dataFields = 945;
+const xml_token_t XML_dataModel = 946;
+const xml_token_t XML_dataOnRows = 947;
+const xml_token_t XML_dataOnly = 948;
+const xml_token_t XML_dataPosition = 949;
+const xml_token_t XML_dataRef = 950;
+const xml_token_t XML_dataRefs = 951;
+const xml_token_t XML_dataSource = 952;
+const xml_token_t XML_dataSourceSort = 953;
+const xml_token_t XML_dataType = 954;
+const xml_token_t XML_dataValidation = 955;
+const xml_token_t XML_dataValidations = 956;
+const xml_token_t XML_databaseField = 957;
+const xml_token_t XML_datastoreItem = 958;
+const xml_token_t XML_date = 959;
+const xml_token_t XML_date1904 = 960;
+const xml_token_t XML_dateAx = 961;
+const xml_token_t XML_dateFormat = 962;
+const xml_token_t XML_dateGroupItem = 963;
+const xml_token_t XML_dateTime = 964;
+const xml_token_t XML_dateTimeGrouping = 965;
+const xml_token_t XML_day = 966;
+const xml_token_t XML_dayLong = 967;
+const xml_token_t XML_dayShort = 968;
+const xml_token_t XML_dbPr = 969;
+const xml_token_t XML_ddList = 970;
+const xml_token_t XML_ddeItem = 971;
+const xml_token_t XML_ddeItems = 972;
+const xml_token_t XML_ddeLink = 973;
+const xml_token_t XML_ddeService = 974;
+const xml_token_t XML_ddeTopic = 975;
+const xml_token_t XML_decel = 976;
+const xml_token_t XML_decimal = 977;
+const xml_token_t XML_decimalSymbol = 978;
+const xml_token_t XML_decorated = 979;
+const xml_token_t XML_def = 980;
+const xml_token_t XML_defJc = 981;
+const xml_token_t XML_defLockedState = 982;
+const xml_token_t XML_defPPr = 983;
+const xml_token_t XML_defQFormat = 984;
+const xml_token_t XML_defRPr = 985;
+const xml_token_t XML_defSemiHidden = 986;
+const xml_token_t XML_defStyle = 987;
+const xml_token_t XML_defTabSz = 988;
+const xml_token_t XML_defUIPriority = 989;
+const xml_token_t XML_defUnhideWhenUsed = 990;
+const xml_token_t XML_default = 991;
+const xml_token_t XML_defaultAttributeDrillState = 992;
+const xml_token_t XML_defaultColWidth = 993;
+const xml_token_t XML_defaultGridColor = 994;
+const xml_token_t XML_defaultMemberUniqueName = 995;
+const xml_token_t XML_defaultPivotStyle = 996;
+const xml_token_t XML_defaultRowHeight = 997;
+const xml_token_t XML_defaultSubtotal = 998;
+const xml_token_t XML_defaultTabStop = 999;
+const xml_token_t XML_defaultTableStyle = 1000;
+const xml_token_t XML_defaultTextStyle = 1001;
+const xml_token_t XML_defaultThemeVersion = 1002;
+const xml_token_t XML_definedName = 1003;
+const xml_token_t XML_definedNames = 1004;
+const xml_token_t XML_deg = 1005;
+const xml_token_t XML_degHide = 1006;
+const xml_token_t XML_degree = 1007;
+const xml_token_t XML_del = 1008;
+const xml_token_t XML_del1 = 1009;
+const xml_token_t XML_del2 = 1010;
+const xml_token_t XML_delInstrText = 1011;
+const xml_token_t XML_delText = 1012;
+const xml_token_t XML_delay = 1013;
+const xml_token_t XML_delete = 1014;
+const xml_token_t XML_deleteColumns = 1015;
+const xml_token_t XML_deleteRows = 1016;
+const xml_token_t XML_deleted = 1017;
+const xml_token_t XML_deletedField = 1018;
+const xml_token_t XML_delimited = 1019;
+const xml_token_t XML_delimiter = 1020;
+const xml_token_t XML_den = 1021;
+const xml_token_t XML_denormalized = 1022;
+const xml_token_t XML_depthPercent = 1023;
+const xml_token_t XML_desc = 1024;
+const xml_token_t XML_descending = 1025;
+const xml_token_t XML_descr = 1026;
+const xml_token_t XML_description = 1027;
+const xml_token_t XML_destId = 1028;
+const xml_token_t XML_destOrd = 1029;
+const xml_token_t XML_destination = 1030;
+const xml_token_t XML_destinationFile = 1031;
+const xml_token_t XML_detectmouseclick = 1032;
+const xml_token_t XML_dgm = 1033;
+const xml_token_t XML_dgmbasetextscale = 1034;
+const xml_token_t XML_dgmfontsize = 1035;
+const xml_token_t XML_dgmlayout = 1036;
+const xml_token_t XML_dgmlayoutmru = 1037;
+const xml_token_t XML_dgmnodekind = 1038;
+const xml_token_t XML_dgmscalex = 1039;
+const xml_token_t XML_dgmscaley = 1040;
+const xml_token_t XML_dgmstyle = 1041;
+const xml_token_t XML_diagonal = 1042;
+const xml_token_t XML_diagonalDown = 1043;
+const xml_token_t XML_diagonalUp = 1044;
+const xml_token_t XML_diagram = 1045;
+const xml_token_t XML_dialogsheet = 1046;
+const xml_token_t XML_diamond = 1047;
+const xml_token_t XML_diff = 1048;
+const xml_token_t XML_differentFirst = 1049;
+const xml_token_t XML_differentOddEven = 1050;
+const xml_token_t XML_diffusity = 1051;
+const xml_token_t XML_dimension = 1052;
+const xml_token_t XML_dimensionUniqueName = 1053;
+const xml_token_t XML_dimensions = 1054;
+const xml_token_t XML_dir = 1055;
+const xml_token_t XML_dirty = 1056;
+const xml_token_t XML_disableEdit = 1057;
+const xml_token_t XML_disableFieldList = 1058;
+const xml_token_t XML_disablePrompts = 1059;
+const xml_token_t XML_disableRefresh = 1060;
+const xml_token_t XML_discretePr = 1061;
+const xml_token_t XML_diskRevisions = 1062;
+const xml_token_t XML_dispBlanksAs = 1063;
+const xml_token_t XML_dispDef = 1064;
+const xml_token_t XML_dispEq = 1065;
+const xml_token_t XML_dispRSqr = 1066;
+const xml_token_t XML_dispUnits = 1067;
+const xml_token_t XML_dispUnitsLbl = 1068;
+const xml_token_t XML_displacedByCustomXml = 1069;
+const xml_token_t XML_display = 1070;
+const xml_token_t XML_displayBackgroundShape = 1071;
+const xml_token_t XML_displayFolder = 1072;
+const xml_token_t XML_displayHangulFixedWidth = 1073;
+const xml_token_t XML_displayHorizontalDrawingGridEvery = 1074;
+const xml_token_t XML_displayName = 1075;
+const xml_token_t XML_displayText = 1076;
+const xml_token_t XML_displayVerticalDrawingGridEvery = 1077;
+const xml_token_t XML_dissolve = 1078;
+const xml_token_t XML_dist = 1079;
+const xml_token_t XML_distB = 1080;
+const xml_token_t XML_distL = 1081;
+const xml_token_t XML_distR = 1082;
+const xml_token_t XML_distT = 1083;
+const xml_token_t XML_distance = 1084;
+const xml_token_t XML_div = 1085;
+const xml_token_t XML_divBdr = 1086;
+const xml_token_t XML_divId = 1087;
+const xml_token_t XML_divs = 1088;
+const xml_token_t XML_divsChild = 1089;
+const xml_token_t XML_dk1 = 1090;
+const xml_token_t XML_dk2 = 1091;
+const xml_token_t XML_dllVersion = 1092;
+const xml_token_t XML_dm = 1093;
+const xml_token_t XML_dn = 1094;
+const xml_token_t XML_doNotAutoCompressPictures = 1095;
+const xml_token_t XML_doNotAutofitConstrainedTables = 1096;
+const xml_token_t XML_doNotBreakConstrainedForcedTable = 1097;
+const xml_token_t XML_doNotBreakWrappedTables = 1098;
+const xml_token_t XML_doNotDemarcateInvalidXml = 1099;
+const xml_token_t XML_doNotDisplayPageBoundaries = 1100;
+const xml_token_t XML_doNotEmbedSmartTags = 1101;
+const xml_token_t XML_doNotExpandShiftReturn = 1102;
+const xml_token_t XML_doNotHyphenateCaps = 1103;
+const xml_token_t XML_doNotIncludeSubdocsInStats = 1104;
+const xml_token_t XML_doNotLeaveBackslashAlone = 1105;
+const xml_token_t XML_doNotOrganizeInFolder = 1106;
+const xml_token_t XML_doNotRelyOnCSS = 1107;
+const xml_token_t XML_doNotSaveAsSingleFile = 1108;
+const xml_token_t XML_doNotShadeFormData = 1109;
+const xml_token_t XML_doNotSnapToGridInCell = 1110;
+const xml_token_t XML_doNotSuppressBlankLines = 1111;
+const xml_token_t XML_doNotSuppressIndentation = 1112;
+const xml_token_t XML_doNotSuppressParagraphBorders = 1113;
+const xml_token_t XML_doNotTrackFormatting = 1114;
+const xml_token_t XML_doNotTrackMoves = 1115;
+const xml_token_t XML_doNotUseEastAsianBreakRules = 1116;
+const xml_token_t XML_doNotUseHTMLParagraphAutoSpacing = 1117;
+const xml_token_t XML_doNotUseIndentAsNumberingTabStop = 1118;
+const xml_token_t XML_doNotUseLongFileNames = 1119;
+const xml_token_t XML_doNotUseMarginsForDrawingGridOrigin = 1120;
+const xml_token_t XML_doNotValidateAgainstSchema = 1121;
+const xml_token_t XML_doNotVertAlignCellWithSp = 1122;
+const xml_token_t XML_doNotVertAlignInTxbx = 1123;
+const xml_token_t XML_doNotWrapTextWithPunct = 1124;
+const xml_token_t XML_docDefaults = 1125;
+const xml_token_t XML_docGrid = 1126;
+const xml_token_t XML_docLocation = 1127;
+const xml_token_t XML_docPart = 1128;
+const xml_token_t XML_docPartBody = 1129;
+const xml_token_t XML_docPartCategory = 1130;
+const xml_token_t XML_docPartGallery = 1131;
+const xml_token_t XML_docPartList = 1132;
+const xml_token_t XML_docPartObj = 1133;
+const xml_token_t XML_docPartPr = 1134;
+const xml_token_t XML_docPartUnique = 1135;
+const xml_token_t XML_docParts = 1136;
+const xml_token_t XML_docPr = 1137;
+const xml_token_t XML_docVar = 1138;
+const xml_token_t XML_docVars = 1139;
+const xml_token_t XML_document = 1140;
+const xml_token_t XML_documentProtection = 1141;
+const xml_token_t XML_documentType = 1142;
+const xml_token_t XML_double = 1143;
+const xml_token_t XML_doubleclicknotify = 1144;
+const xml_token_t XML_doughnutChart = 1145;
+const xml_token_t XML_downBars = 1146;
+const xml_token_t XML_dpi = 1147;
+const xml_token_t XML_dr = 1148;
+const xml_token_t XML_draft = 1149;
+const xml_token_t XML_dragOff = 1150;
+const xml_token_t XML_dragToCol = 1151;
+const xml_token_t XML_dragToData = 1152;
+const xml_token_t XML_dragToPage = 1153;
+const xml_token_t XML_dragToRow = 1154;
+const xml_token_t XML_drawing = 1155;
+const xml_token_t XML_drawingGridHorizontalOrigin = 1156;
+const xml_token_t XML_drawingGridHorizontalSpacing = 1157;
+const xml_token_t XML_drawingGridVerticalOrigin = 1158;
+const xml_token_t XML_drawingGridVerticalSpacing = 1159;
+const xml_token_t XML_drop = 1160;
+const xml_token_t XML_dropCap = 1161;
+const xml_token_t XML_dropDownList = 1162;
+const xml_token_t XML_dropLines = 1163;
+const xml_token_t XML_dropauto = 1164;
+const xml_token_t XML_ds = 1165;
+const xml_token_t XML_dstrike = 1166;
+const xml_token_t XML_dt = 1167;
+const xml_token_t XML_dt2D = 1168;
+const xml_token_t XML_dtr = 1169;
+const xml_token_t XML_duotone = 1170;
+const xml_token_t XML_dur = 1171;
+const xml_token_t XML_dvAspect = 1172;
+const xml_token_t XML_dx = 1173;
+const xml_token_t XML_dxaOrig = 1174;
+const xml_token_t XML_dxf = 1175;
+const xml_token_t XML_dxfId = 1176;
+const xml_token_t XML_dxfs = 1177;
+const xml_token_t XML_dy = 1178;
+const xml_token_t XML_dyaOrig = 1179;
+const xml_token_t XML_dynamicAddress = 1180;
+const xml_token_t XML_dynamicFilter = 1181;
+const xml_token_t XML_dz = 1182;
+const xml_token_t XML_e = 1183;
+const xml_token_t XML_ea = 1184;
+const xml_token_t XML_eaLnBrk = 1185;
+const xml_token_t XML_eastAsia = 1186;
+const xml_token_t XML_eastAsiaTheme = 1187;
+const xml_token_t XML_eastAsianLayout = 1188;
+const xml_token_t XML_eb = 1189;
+const xml_token_t XML_ed = 1190;
+const xml_token_t XML_edGrp = 1191;
+const xml_token_t XML_edge = 1192;
+const xml_token_t XML_edit = 1193;
+const xml_token_t XML_editAs = 1194;
+const xml_token_t XML_editData = 1195;
+const xml_token_t XML_editPage = 1196;
+const xml_token_t XML_editas = 1197;
+const xml_token_t XML_edited = 1198;
+const xml_token_t XML_effect = 1199;
+const xml_token_t XML_effectClrLst = 1200;
+const xml_token_t XML_effectDag = 1201;
+const xml_token_t XML_effectExtent = 1202;
+const xml_token_t XML_effectLst = 1203;
+const xml_token_t XML_effectRef = 1204;
+const xml_token_t XML_effectStyle = 1205;
+const xml_token_t XML_effectStyleLst = 1206;
+const xml_token_t XML_element = 1207;
+const xml_token_t XML_else = 1208;
+const xml_token_t XML_em = 1209;
+const xml_token_t XML_embed = 1210;
+const xml_token_t XML_embedBold = 1211;
+const xml_token_t XML_embedBoldItalic = 1212;
+const xml_token_t XML_embedItalic = 1213;
+const xml_token_t XML_embedRegular = 1214;
+const xml_token_t XML_embedSystemFonts = 1215;
+const xml_token_t XML_embedTrueTypeFonts = 1216;
+const xml_token_t XML_embeddedFont = 1217;
+const xml_token_t XML_embeddedFontLst = 1218;
+const xml_token_t XML_emboss = 1219;
+const xml_token_t XML_embosscolor = 1220;
+const xml_token_t XML_empty = 1221;
+const xml_token_t XML_emptyCellReference = 1222;
+const xml_token_t XML_enableDrill = 1223;
+const xml_token_t XML_enableFieldProperties = 1224;
+const xml_token_t XML_enableFormatConditionsCalculation = 1225;
+const xml_token_t XML_enableRefresh = 1226;
+const xml_token_t XML_enableWizard = 1227;
+const xml_token_t XML_enabled = 1228;
+const xml_token_t XML_encoding = 1229;
+const xml_token_t XML_end = 1230;
+const xml_token_t XML_endA = 1231;
+const xml_token_t XML_endAngle = 1232;
+const xml_token_t XML_endChr = 1233;
+const xml_token_t XML_endCondLst = 1234;
+const xml_token_t XML_endCxn = 1235;
+const xml_token_t XML_endDate = 1236;
+const xml_token_t XML_endNum = 1237;
+const xml_token_t XML_endOfListFormulaUpdate = 1238;
+const xml_token_t XML_endParaRPr = 1239;
+const xml_token_t XML_endPos = 1240;
+const xml_token_t XML_endSnd = 1241;
+const xml_token_t XML_endSync = 1242;
+const xml_token_t XML_endarrow = 1243;
+const xml_token_t XML_endarrowlength = 1244;
+const xml_token_t XML_endarrowwidth = 1245;
+const xml_token_t XML_endcap = 1246;
+const xml_token_t XML_endnote = 1247;
+const xml_token_t XML_endnotePr = 1248;
+const xml_token_t XML_endnoteRef = 1249;
+const xml_token_t XML_endnoteReference = 1250;
+const xml_token_t XML_endnotes = 1251;
+const xml_token_t XML_enforcement = 1252;
+const xml_token_t XML_entries = 1253;
+const xml_token_t XML_entry = 1254;
+const xml_token_t XML_entryMacro = 1255;
+const xml_token_t XML_eol = 1256;
+const xml_token_t XML_eqArr = 1257;
+const xml_token_t XML_eqArrPr = 1258;
+const xml_token_t XML_eqn = 1259;
+const xml_token_t XML_equalAverage = 1260;
+const xml_token_t XML_equalWidth = 1261;
+const xml_token_t XML_equation = 1262;
+const xml_token_t XML_equationxml = 1263;
+const xml_token_t XML_err = 1264;
+const xml_token_t XML_errBarType = 1265;
+const xml_token_t XML_errBars = 1266;
+const xml_token_t XML_errDir = 1267;
+const xml_token_t XML_errValType = 1268;
+const xml_token_t XML_error = 1269;
+const xml_token_t XML_errorCaption = 1270;
+const xml_token_t XML_errorStyle = 1271;
+const xml_token_t XML_errorTitle = 1272;
+const xml_token_t XML_errors = 1273;
+const xml_token_t XML_evalError = 1274;
+const xml_token_t XML_evalOrder = 1275;
+const xml_token_t XML_evenAndOddHeaders = 1276;
+const xml_token_t XML_evenFooter = 1277;
+const xml_token_t XML_evenHeader = 1278;
+const xml_token_t XML_evt = 1279;
+const xml_token_t XML_evtFilter = 1280;
+const xml_token_t XML_excl = 1281;
+const xml_token_t XML_exclusive = 1282;
+const xml_token_t XML_exitMacro = 1283;
+const xml_token_t XML_exp = 1284;
+const xml_token_t XML_explosion = 1285;
+const xml_token_t XML_ext = 1286;
+const xml_token_t XML_extLst = 1287;
+const xml_token_t XML_extend = 1288;
+const xml_token_t XML_extendable = 1289;
+const xml_token_t XML_extent = 1290;
+const xml_token_t XML_externalBook = 1291;
+const xml_token_t XML_externalData = 1292;
+const xml_token_t XML_externalLink = 1293;
+const xml_token_t XML_externalReference = 1294;
+const xml_token_t XML_externalReferences = 1295;
+const xml_token_t XML_extraClrScheme = 1296;
+const xml_token_t XML_extraClrSchemeLst = 1297;
+const xml_token_t XML_extrusion = 1298;
+const xml_token_t XML_extrusionClr = 1299;
+const xml_token_t XML_extrusionH = 1300;
+const xml_token_t XML_extrusionOk = 1301;
+const xml_token_t XML_extrusioncolor = 1302;
+const xml_token_t XML_extrusionok = 1303;
+const xml_token_t XML_f = 1304;
+const xml_token_t XML_fHdr = 1305;
+const xml_token_t XML_fLocksText = 1306;
+const xml_token_t XML_fLocksWithSheet = 1307;
+const xml_token_t XML_fName = 1308;
+const xml_token_t XML_fPr = 1309;
+const xml_token_t XML_fPrintsWithSheet = 1310;
+const xml_token_t XML_fPublished = 1311;
+const xml_token_t XML_facet = 1312;
+const xml_token_t XML_fact = 1313;
+const xml_token_t XML_fade = 1314;
+const xml_token_t XML_fadeDir = 1315;
+const xml_token_t XML_family = 1316;
+const xml_token_t XML_fc = 1317;
+const xml_token_t XML_ffData = 1318;
+const xml_token_t XML_fgClr = 1319;
+const xml_token_t XML_fgColor = 1320;
+const xml_token_t XML_fi = 1321;
+const xml_token_t XML_field = 1322;
+const xml_token_t XML_fieldGroup = 1323;
+const xml_token_t XML_fieldId = 1324;
+const xml_token_t XML_fieldIdWrapped = 1325;
+const xml_token_t XML_fieldListSortAscending = 1326;
+const xml_token_t XML_fieldMapData = 1327;
+const xml_token_t XML_fieldPosition = 1328;
+const xml_token_t XML_fieldPrintTitles = 1329;
+const xml_token_t XML_fieldUsage = 1330;
+const xml_token_t XML_fieldsUsage = 1331;
+const xml_token_t XML_fileRecoveryPr = 1332;
+const xml_token_t XML_fileSharing = 1333;
+const xml_token_t XML_fileType = 1334;
+const xml_token_t XML_fileVersion = 1335;
+const xml_token_t XML_filetime = 1336;
+const xml_token_t XML_fill = 1337;
+const xml_token_t XML_fillClrLst = 1338;
+const xml_token_t XML_fillFormulas = 1339;
+const xml_token_t XML_fillId = 1340;
+const xml_token_t XML_fillOverlay = 1341;
+const xml_token_t XML_fillRect = 1342;
+const xml_token_t XML_fillRef = 1343;
+const xml_token_t XML_fillStyleLst = 1344;
+const xml_token_t XML_fillToRect = 1345;
+const xml_token_t XML_fillcolor = 1346;
+const xml_token_t XML_filled = 1347;
+const xml_token_t XML_fillok = 1348;
+const xml_token_t XML_fills = 1349;
+const xml_token_t XML_filltype = 1350;
+const xml_token_t XML_filter = 1351;
+const xml_token_t XML_filterColumn = 1352;
+const xml_token_t XML_filterMode = 1353;
+const xml_token_t XML_filterPrivacy = 1354;
+const xml_token_t XML_filterUnique = 1355;
+const xml_token_t XML_filterVal = 1356;
+const xml_token_t XML_filters = 1357;
+const xml_token_t XML_first = 1358;
+const xml_token_t XML_firstBackgroundRefresh = 1359;
+const xml_token_t XML_firstCol = 1360;
+const xml_token_t XML_firstDataCol = 1361;
+const xml_token_t XML_firstDataRow = 1362;
+const xml_token_t XML_firstFooter = 1363;
+const xml_token_t XML_firstHeader = 1364;
+const xml_token_t XML_firstHeaderRow = 1365;
+const xml_token_t XML_firstLine = 1366;
+const xml_token_t XML_firstLineChars = 1367;
+const xml_token_t XML_firstPageNumber = 1368;
+const xml_token_t XML_firstRow = 1369;
+const xml_token_t XML_firstSheet = 1370;
+const xml_token_t XML_firstSliceAng = 1371;
+const xml_token_t XML_firstSlideNum = 1372;
+const xml_token_t XML_fitText = 1373;
+const xml_token_t XML_fitToHeight = 1374;
+const xml_token_t XML_fitToPage = 1375;
+const xml_token_t XML_fitToWidth = 1376;
+const xml_token_t XML_fitpath = 1377;
+const xml_token_t XML_fitshape = 1378;
+const xml_token_t XML_flatBorders = 1379;
+const xml_token_t XML_flatTx = 1380;
+const xml_token_t XML_fld = 1381;
+const xml_token_t XML_fldChar = 1382;
+const xml_token_t XML_fldCharType = 1383;
+const xml_token_t XML_fldData = 1384;
+const xml_token_t XML_fldLock = 1385;
+const xml_token_t XML_fldSimple = 1386;
+const xml_token_t XML_flip = 1387;
+const xml_token_t XML_flipH = 1388;
+const xml_token_t XML_flipV = 1389;
+const xml_token_t XML_floor = 1390;
+const xml_token_t XML_fltVal = 1391;
+const xml_token_t XML_fmla = 1392;
+const xml_token_t XML_fmt = 1393;
+const xml_token_t XML_fmtId = 1394;
+const xml_token_t XML_fmtScheme = 1395;
+const xml_token_t XML_fmtid = 1396;
+const xml_token_t XML_focus = 1397;
+const xml_token_t XML_focusposition = 1398;
+const xml_token_t XML_focussize = 1399;
+const xml_token_t XML_folHlink = 1400;
+const xml_token_t XML_followColorScheme = 1401;
+const xml_token_t XML_followedHyperlink = 1402;
+const xml_token_t XML_font = 1403;
+const xml_token_t XML_fontAlgn = 1404;
+const xml_token_t XML_fontId = 1405;
+const xml_token_t XML_fontKey = 1406;
+const xml_token_t XML_fontRef = 1407;
+const xml_token_t XML_fontScale = 1408;
+const xml_token_t XML_fontScheme = 1409;
+const xml_token_t XML_fontSz = 1410;
+const xml_token_t XML_fonts = 1411;
+const xml_token_t XML_footer = 1412;
+const xml_token_t XML_footerReference = 1413;
+const xml_token_t XML_footnote = 1414;
+const xml_token_t XML_footnoteLayoutLikeWW8 = 1415;
+const xml_token_t XML_footnotePr = 1416;
+const xml_token_t XML_footnoteRef = 1417;
+const xml_token_t XML_footnoteReference = 1418;
+const xml_token_t XML_footnotes = 1419;
+const xml_token_t XML_for = 1420;
+const xml_token_t XML_forEach = 1421;
+const xml_token_t XML_forName = 1422;
+const xml_token_t XML_forceAA = 1423;
+const xml_token_t XML_forceFullCalc = 1424;
+const xml_token_t XML_forceUpgrade = 1425;
+const xml_token_t XML_forcedash = 1426;
+const xml_token_t XML_foredepth = 1427;
+const xml_token_t XML_forgetLastTabAlignment = 1428;
+const xml_token_t XML_formProt = 1429;
+const xml_token_t XML_format = 1430;
+const xml_token_t XML_formatCells = 1431;
+const xml_token_t XML_formatCode = 1432;
+const xml_token_t XML_formatColumns = 1433;
+const xml_token_t XML_formatRows = 1434;
+const xml_token_t XML_formats = 1435;
+const xml_token_t XML_formatting = 1436;
+const xml_token_t XML_formsDesign = 1437;
+const xml_token_t XML_formula = 1438;
+const xml_token_t XML_formula1 = 1439;
+const xml_token_t XML_formula2 = 1440;
+const xml_token_t XML_formulaRange = 1441;
+const xml_token_t XML_formulas = 1442;
+const xml_token_t XML_forward = 1443;
+const xml_token_t XML_fov = 1444;
+const xml_token_t XML_frame = 1445;
+const xml_token_t XML_frameLayout = 1446;
+const xml_token_t XML_framePr = 1447;
+const xml_token_t XML_frameSlides = 1448;
+const xml_token_t XML_frameset = 1449;
+const xml_token_t XML_framesetSplitbar = 1450;
+const xml_token_t XML_from = 1451;
+const xml_token_t XML_fromWordArt = 1452;
+const xml_token_t XML_ftr = 1453;
+const xml_token_t XML_fullCalcOnLoad = 1454;
+const xml_token_t XML_fullDate = 1455;
+const xml_token_t XML_fullPrecision = 1456;
+const xml_token_t XML_fullScrn = 1457;
+const xml_token_t XML_func = 1458;
+const xml_token_t XML_funcPr = 1459;
+const xml_token_t XML_function = 1460;
+const xml_token_t XML_functionGroup = 1461;
+const xml_token_t XML_functionGroupId = 1462;
+const xml_token_t XML_functionGroups = 1463;
+const xml_token_t XML_futureMetadata = 1464;
+const xml_token_t XML_g = 1465;
+const xml_token_t XML_gain = 1466;
+const xml_token_t XML_gallery = 1467;
+const xml_token_t XML_gamma = 1468;
+const xml_token_t XML_gap = 1469;
+const xml_token_t XML_gapDepth = 1470;
+const xml_token_t XML_gapWidth = 1471;
+const xml_token_t XML_gd = 1472;
+const xml_token_t XML_gdLst = 1473;
+const xml_token_t XML_gdRefAng = 1474;
+const xml_token_t XML_gdRefR = 1475;
+const xml_token_t XML_gdRefX = 1476;
+const xml_token_t XML_gdRefY = 1477;
+const xml_token_t XML_gfxdata = 1478;
+const xml_token_t XML_ghostCol = 1479;
+const xml_token_t XML_ghostRow = 1480;
+const xml_token_t XML_glossaryDocument = 1481;
+const xml_token_t XML_glow = 1482;
+const xml_token_t XML_goal = 1483;
+const xml_token_t XML_gradFill = 1484;
+const xml_token_t XML_gradientFill = 1485;
+const xml_token_t XML_gradientshapeok = 1486;
+const xml_token_t XML_grammar = 1487;
+const xml_token_t XML_grandCol = 1488;
+const xml_token_t XML_grandRow = 1489;
+const xml_token_t XML_grandTotalCaption = 1490;
+const xml_token_t XML_graphic = 1491;
+const xml_token_t XML_graphicData = 1492;
+const xml_token_t XML_graphicEl = 1493;
+const xml_token_t XML_graphicFrame = 1494;
+const xml_token_t XML_graphicFrameLocks = 1495;
+const xml_token_t XML_gray = 1496;
+const xml_token_t XML_grayscale = 1497;
+const xml_token_t XML_grayscl = 1498;
+const xml_token_t XML_green = 1499;
+const xml_token_t XML_greenMod = 1500;
+const xml_token_t XML_greenOff = 1501;
+const xml_token_t XML_gridAfter = 1502;
+const xml_token_t XML_gridBefore = 1503;
+const xml_token_t XML_gridCol = 1504;
+const xml_token_t XML_gridDropZones = 1505;
+const xml_token_t XML_gridLines = 1506;
+const xml_token_t XML_gridLinesSet = 1507;
+const xml_token_t XML_gridSpacing = 1508;
+const xml_token_t XML_gridSpan = 1509;
+const xml_token_t XML_group = 1510;
+const xml_token_t XML_groupBy = 1511;
+const xml_token_t XML_groupChr = 1512;
+const xml_token_t XML_groupChrPr = 1513;
+const xml_token_t XML_groupInterval = 1514;
+const xml_token_t XML_groupItems = 1515;
+const xml_token_t XML_groupLevel = 1516;
+const xml_token_t XML_groupLevels = 1517;
+const xml_token_t XML_groupMember = 1518;
+const xml_token_t XML_groupMembers = 1519;
+const xml_token_t XML_grouping = 1520;
+const xml_token_t XML_groups = 1521;
+const xml_token_t XML_grow = 1522;
+const xml_token_t XML_growAutofit = 1523;
+const xml_token_t XML_growShrinkType = 1524;
+const xml_token_t XML_grpFill = 1525;
+const xml_token_t XML_grpId = 1526;
+const xml_token_t XML_grpSp = 1527;
+const xml_token_t XML_grpSpLocks = 1528;
+const xml_token_t XML_grpSpPr = 1529;
+const xml_token_t XML_gs = 1530;
+const xml_token_t XML_gsLst = 1531;
+const xml_token_t XML_gte = 1532;
+const xml_token_t XML_guid = 1533;
+const xml_token_t XML_guide = 1534;
+const xml_token_t XML_guideLst = 1535;
+const xml_token_t XML_gutter = 1536;
+const xml_token_t XML_gutterAtTop = 1537;
+const xml_token_t XML_h = 1538;
+const xml_token_t XML_hAnchor = 1539;
+const xml_token_t XML_hAnsi = 1540;
+const xml_token_t XML_hAnsiTheme = 1541;
+const xml_token_t XML_hMerge = 1542;
+const xml_token_t XML_hMode = 1543;
+const xml_token_t XML_hPercent = 1544;
+const xml_token_t XML_hR = 1545;
+const xml_token_t XML_hRule = 1546;
+const xml_token_t XML_hSpace = 1547;
+const xml_token_t XML_handles = 1548;
+const xml_token_t XML_handoutMaster = 1549;
+const xml_token_t XML_handoutMasterId = 1550;
+const xml_token_t XML_handoutMasterIdLst = 1551;
+const xml_token_t XML_hanging = 1552;
+const xml_token_t XML_hangingChars = 1553;
+const xml_token_t XML_hangingPunct = 1554;
+const xml_token_t XML_hasCustomPrompt = 1555;
+const xml_token_t XML_hash = 1556;
+const xml_token_t XML_hashData = 1557;
+const xml_token_t XML_hdr = 1558;
+const xml_token_t XML_hdrShapeDefaults = 1559;
+const xml_token_t XML_headEnd = 1560;
+const xml_token_t XML_header = 1561;
+const xml_token_t XML_headerFooter = 1562;
+const xml_token_t XML_headerReference = 1563;
+const xml_token_t XML_headerRowBorderDxfId = 1564;
+const xml_token_t XML_headerRowCellStyle = 1565;
+const xml_token_t XML_headerRowCount = 1566;
+const xml_token_t XML_headerRowDxfId = 1567;
+const xml_token_t XML_headerSource = 1568;
+const xml_token_t XML_headers = 1569;
+const xml_token_t XML_headersInLastRefresh = 1570;
+const xml_token_t XML_heading = 1571;
+const xml_token_t XML_headings = 1572;
+const xml_token_t XML_help = 1573;
+const xml_token_t XML_helpText = 1574;
+const xml_token_t XML_hf = 1575;
+const xml_token_t XML_hiLowLines = 1576;
+const xml_token_t XML_hidden = 1577;
+const xml_token_t XML_hiddenButton = 1578;
+const xml_token_t XML_hiddenColumn = 1579;
+const xml_token_t XML_hiddenColumns = 1580;
+const xml_token_t XML_hiddenLevel = 1581;
+const xml_token_t XML_hiddenRow = 1582;
+const xml_token_t XML_hiddenRows = 1583;
+const xml_token_t XML_hiddenSlides = 1584;
+const xml_token_t XML_hideBot = 1585;
+const xml_token_t XML_hideGeom = 1586;
+const xml_token_t XML_hideGrammaticalErrors = 1587;
+const xml_token_t XML_hideLastTrans = 1588;
+const xml_token_t XML_hideLeft = 1589;
+const xml_token_t XML_hideMark = 1590;
+const xml_token_t XML_hideNewItems = 1591;
+const xml_token_t XML_hidePivotFieldList = 1592;
+const xml_token_t XML_hideRight = 1593;
+const xml_token_t XML_hideSpellingErrors = 1594;
+const xml_token_t XML_hideTop = 1595;
+const xml_token_t XML_hier = 1596;
+const xml_token_t XML_hierBranch = 1597;
+const xml_token_t XML_hierarchy = 1598;
+const xml_token_t XML_hierarchyUsage = 1599;
+const xml_token_t XML_highlight = 1600;
+const xml_token_t XML_highlightClick = 1601;
+const xml_token_t XML_hint = 1602;
+const xml_token_t XML_history = 1603;
+const xml_token_t XML_hlink = 1604;
+const xml_token_t XML_hlinkClick = 1605;
+const xml_token_t XML_hlinkHover = 1606;
+const xml_token_t XML_hlinkMouseOver = 1607;
+const xml_token_t XML_holeSize = 1608;
+const xml_token_t XML_horizontal = 1609;
+const xml_token_t XML_horizontalCentered = 1610;
+const xml_token_t XML_horizontalDpi = 1611;
+const xml_token_t XML_horzAnchor = 1612;
+const xml_token_t XML_horzBarState = 1613;
+const xml_token_t XML_horzOverflow = 1614;
+const xml_token_t XML_hour = 1615;
+const xml_token_t XML_how = 1616;
+const xml_token_t XML_hps = 1617;
+const xml_token_t XML_hpsBaseText = 1618;
+const xml_token_t XML_hpsRaise = 1619;
+const xml_token_t XML_hr = 1620;
+const xml_token_t XML_hralign = 1621;
+const xml_token_t XML_href = 1622;
+const xml_token_t XML_hrnoshade = 1623;
+const xml_token_t XML_hrpct = 1624;
+const xml_token_t XML_hrstd = 1625;
+const xml_token_t XML_hsl = 1626;
+const xml_token_t XML_hslClr = 1627;
+const xml_token_t XML_ht = 1628;
+const xml_token_t XML_htmlFormat = 1629;
+const xml_token_t XML_htmlPubPr = 1630;
+const xml_token_t XML_htmlTables = 1631;
+const xml_token_t XML_hue = 1632;
+const xml_token_t XML_hueDir = 1633;
+const xml_token_t XML_hueMod = 1634;
+const xml_token_t XML_hueOff = 1635;
+const xml_token_t XML_hyperlink = 1636;
+const xml_token_t XML_hyperlinks = 1637;
+const xml_token_t XML_hyphenationZone = 1638;
+const xml_token_t XML_i = 1639;
+const xml_token_t XML_i1 = 1640;
+const xml_token_t XML_i2 = 1641;
+const xml_token_t XML_i3 = 1642;
+const xml_token_t XML_i4 = 1643;
+const xml_token_t XML_i8 = 1644;
+const xml_token_t XML_iCs = 1645;
+const xml_token_t XML_iLevel = 1646;
+const xml_token_t XML_iMeasureFld = 1647;
+const xml_token_t XML_iMeasureHier = 1648;
+const xml_token_t XML_icon = 1649;
+const xml_token_t XML_iconFilter = 1650;
+const xml_token_t XML_iconId = 1651;
+const xml_token_t XML_iconSet = 1652;
+const xml_token_t XML_id = 1653;
+const xml_token_t XML_idcntr = 1654;
+const xml_token_t XML_iddest = 1655;
+const xml_token_t XML_idmap = 1656;
+const xml_token_t XML_idref = 1657;
+const xml_token_t XML_idsrc = 1658;
+const xml_token_t XML_idx = 1659;
+const xml_token_t XML_if = 1660;
+const xml_token_t XML_ignoreMixedContent = 1661;
+const xml_token_t XML_ignoredError = 1662;
+const xml_token_t XML_ignoredErrors = 1663;
+const xml_token_t XML_ilvl = 1664;
+const xml_token_t XML_image = 1665;
+const xml_token_t XML_imagealignshape = 1666;
+const xml_token_t XML_imageaspect = 1667;
+const xml_token_t XML_imagedata = 1668;
+const xml_token_t XML_imagesize = 1669;
+const xml_token_t XML_imeMode = 1670;
+const xml_token_t XML_imgH = 1671;
+const xml_token_t XML_imgSz = 1672;
+const xml_token_t XML_imgW = 1673;
+const xml_token_t XML_immersive = 1674;
+const xml_token_t XML_imprint = 1675;
+const xml_token_t XML_in = 1676;
+const xml_token_t XML_includeHiddenRowCol = 1677;
+const xml_token_t XML_includeNewItemsInFilter = 1678;
+const xml_token_t XML_includePrintSettings = 1679;
+const xml_token_t XML_ind = 1680;
+const xml_token_t XML_indent = 1681;
+const xml_token_t XML_index = 1682;
+const xml_token_t XML_indexed = 1683;
+const xml_token_t XML_indexedColors = 1684;
+const xml_token_t XML_initials = 1685;
+const xml_token_t XML_ink = 1686;
+const xml_token_t XML_inkAnnotations = 1687;
+const xml_token_t XML_inkTgt = 1688;
+const xml_token_t XML_inline = 1689;
+const xml_token_t XML_innerShdw = 1690;
+const xml_token_t XML_inputCells = 1691;
+const xml_token_t XML_ins = 1692;
+const xml_token_t XML_insDel = 1693;
+const xml_token_t XML_insertBlankRow = 1694;
+const xml_token_t XML_insertColumns = 1695;
+const xml_token_t XML_insertHyperlinks = 1696;
+const xml_token_t XML_insertPageBreak = 1697;
+const xml_token_t XML_insertRow = 1698;
+const xml_token_t XML_insertRowShift = 1699;
+const xml_token_t XML_insertRows = 1700;
+const xml_token_t XML_inset = 1701;
+const xml_token_t XML_insetmode = 1702;
+const xml_token_t XML_insetpen = 1703;
+const xml_token_t XML_insetpenok = 1704;
+const xml_token_t XML_insideH = 1705;
+const xml_token_t XML_insideV = 1706;
+const xml_token_t XML_instr = 1707;
+const xml_token_t XML_instrText = 1708;
+const xml_token_t XML_int = 1709;
+const xml_token_t XML_intLim = 1710;
+const xml_token_t XML_intVal = 1711;
+const xml_token_t XML_integer = 1712;
+const xml_token_t XML_interSp = 1713;
+const xml_token_t XML_intercept = 1714;
+const xml_token_t XML_intermediate = 1715;
+const xml_token_t XML_interval = 1716;
+const xml_token_t XML_intraSp = 1717;
+const xml_token_t XML_inv = 1718;
+const xml_token_t XML_invGamma = 1719;
+const xml_token_t XML_invalEndChars = 1720;
+const xml_token_t XML_invalStChars = 1721;
+const xml_token_t XML_invalid = 1722;
+const xml_token_t XML_invalidUrl = 1723;
+const xml_token_t XML_invertIfNegative = 1724;
+const xml_token_t XML_invx = 1725;
+const xml_token_t XML_invy = 1726;
+const xml_token_t XML_is = 1727;
+const xml_token_t XML_isLgl = 1728;
+const xml_token_t XML_isNarration = 1729;
+const xml_token_t XML_isPhoto = 1730;
+const xml_token_t XML_iscomment = 1731;
+const xml_token_t XML_issignatureline = 1732;
+const xml_token_t XML_italic = 1733;
+const xml_token_t XML_item = 1734;
+const xml_token_t XML_itemID = 1735;
+const xml_token_t XML_itemPageCount = 1736;
+const xml_token_t XML_itemPrintTitles = 1737;
+const xml_token_t XML_items = 1738;
+const xml_token_t XML_iterate = 1739;
+const xml_token_t XML_iterateCount = 1740;
+const xml_token_t XML_iterateDelta = 1741;
+const xml_token_t XML_jc = 1742;
+const xml_token_t XML_joinstyle = 1743;
+const xml_token_t XML_justifyLastLine = 1744;
+const xml_token_t XML_k = 1745;
+const xml_token_t XML_keepAlive = 1746;
+const xml_token_t XML_keepChangeHistory = 1747;
+const xml_token_t XML_keepLines = 1748;
+const xml_token_t XML_keepNext = 1749;
+const xml_token_t XML_kern = 1750;
+const xml_token_t XML_key = 1751;
+const xml_token_t XML_keyAttribute = 1752;
+const xml_token_t XML_kinsoku = 1753;
+const xml_token_t XML_kiosk = 1754;
+const xml_token_t XML_kpi = 1755;
+const xml_token_t XML_kpis = 1756;
+const xml_token_t XML_kumimoji = 1757;
+const xml_token_t XML_kx = 1758;
+const xml_token_t XML_ky = 1759;
+const xml_token_t XML_l = 1760;
+const xml_token_t XML_lBounds = 1761;
+const xml_token_t XML_lIns = 1762;
+const xml_token_t XML_lMargin = 1763;
+const xml_token_t XML_label = 1764;
+const xml_token_t XML_labelOnly = 1765;
+const xml_token_t XML_lang = 1766;
+const xml_token_t XML_lastClr = 1767;
+const xml_token_t XML_lastCol = 1768;
+const xml_token_t XML_lastEdited = 1769;
+const xml_token_t XML_lastGuid = 1770;
+const xml_token_t XML_lastIdx = 1771;
+const xml_token_t XML_lastRenderedPageBreak = 1772;
+const xml_token_t XML_lastRow = 1773;
+const xml_token_t XML_lastValue = 1774;
+const xml_token_t XML_lastView = 1775;
+const xml_token_t XML_lat = 1776;
+const xml_token_t XML_latentStyles = 1777;
+const xml_token_t XML_latin = 1778;
+const xml_token_t XML_latinLnBrk = 1779;
+const xml_token_t XML_layout = 1780;
+const xml_token_t XML_layoutDef = 1781;
+const xml_token_t XML_layoutDefHdr = 1782;
+const xml_token_t XML_layoutDefHdrLst = 1783;
+const xml_token_t XML_layoutInCell = 1784;
+const xml_token_t XML_layoutNode = 1785;
+const xml_token_t XML_layoutRawTableWidth = 1786;
+const xml_token_t XML_layoutTableRowsApart = 1787;
+const xml_token_t XML_layoutTarget = 1788;
+const xml_token_t XML_lblAlgn = 1789;
+const xml_token_t XML_lblOffset = 1790;
+const xml_token_t XML_leader = 1791;
+const xml_token_t XML_leaderLines = 1792;
+const xml_token_t XML_left = 1793;
+const xml_token_t XML_leftChars = 1794;
+const xml_token_t XML_leftFromText = 1795;
+const xml_token_t XML_leftLabels = 1796;
+const xml_token_t XML_legacy = 1797;
+const xml_token_t XML_legacyDrawing = 1798;
+const xml_token_t XML_legacyDrawingHF = 1799;
+const xml_token_t XML_legacyIndent = 1800;
+const xml_token_t XML_legacySpace = 1801;
+const xml_token_t XML_legend = 1802;
+const xml_token_t XML_legendEntry = 1803;
+const xml_token_t XML_legendPos = 1804;
+const xml_token_t XML_len = 1805;
+const xml_token_t XML_length = 1806;
+const xml_token_t XML_lengthspecified = 1807;
+const xml_token_t XML_level = 1808;
+const xml_token_t XML_lid = 1809;
+const xml_token_t XML_lightRig = 1810;
+const xml_token_t XML_lightface = 1811;
+const xml_token_t XML_lightharsh = 1812;
+const xml_token_t XML_lightharsh2 = 1813;
+const xml_token_t XML_lightlevel = 1814;
+const xml_token_t XML_lightlevel2 = 1815;
+const xml_token_t XML_lightposition = 1816;
+const xml_token_t XML_lightposition2 = 1817;
+const xml_token_t XML_lim = 1818;
+const xml_token_t XML_limLoc = 1819;
+const xml_token_t XML_limLow = 1820;
+const xml_token_t XML_limLowPr = 1821;
+const xml_token_t XML_limUpp = 1822;
+const xml_token_t XML_limUppPr = 1823;
+const xml_token_t XML_limo = 1824;
+const xml_token_t XML_lin = 1825;
+const xml_token_t XML_linClrLst = 1826;
+const xml_token_t XML_line = 1827;
+const xml_token_t XML_line3DChart = 1828;
+const xml_token_t XML_lineChart = 1829;
+const xml_token_t XML_linePitch = 1830;
+const xml_token_t XML_lineRule = 1831;
+const xml_token_t XML_lineTo = 1832;
+const xml_token_t XML_lineWrapLikeWord6 = 1833;
+const xml_token_t XML_lines = 1834;
+const xml_token_t XML_linestyle = 1835;
+const xml_token_t XML_link = 1836;
+const xml_token_t XML_linkStyles = 1837;
+const xml_token_t XML_linkTarget = 1838;
+const xml_token_t XML_linkToQuery = 1839;
+const xml_token_t XML_linkedToFile = 1840;
+const xml_token_t XML_listDataValidation = 1841;
+const xml_token_t XML_listEntry = 1842;
+const xml_token_t XML_listItem = 1843;
+const xml_token_t XML_listSeparator = 1844;
+const xml_token_t XML_lit = 1845;
+const xml_token_t XML_lkTxEntry = 1846;
+const xml_token_t XML_ln = 1847;
+const xml_token_t XML_lnB = 1848;
+const xml_token_t XML_lnBlToTr = 1849;
+const xml_token_t XML_lnDef = 1850;
+const xml_token_t XML_lnL = 1851;
+const xml_token_t XML_lnNumType = 1852;
+const xml_token_t XML_lnR = 1853;
+const xml_token_t XML_lnRef = 1854;
+const xml_token_t XML_lnSpc = 1855;
+const xml_token_t XML_lnSpcReduction = 1856;
+const xml_token_t XML_lnStyleLst = 1857;
+const xml_token_t XML_lnT = 1858;
+const xml_token_t XML_lnTlToBr = 1859;
+const xml_token_t XML_lnTo = 1860;
+const xml_token_t XML_lo = 1861;
+const xml_token_t XML_loCatId = 1862;
+const xml_token_t XML_loTypeId = 1863;
+const xml_token_t XML_local = 1864;
+const xml_token_t XML_localConnection = 1865;
+const xml_token_t XML_localRefresh = 1866;
+const xml_token_t XML_localSheetId = 1867;
+const xml_token_t XML_location = 1868;
+const xml_token_t XML_lock = 1869;
+const xml_token_t XML_lockRevision = 1870;
+const xml_token_t XML_lockStructure = 1871;
+const xml_token_t XML_lockWindows = 1872;
+const xml_token_t XML_locked = 1873;
+const xml_token_t XML_lockedCanvas = 1874;
+const xml_token_t XML_lockrotationcenter = 1875;
+const xml_token_t XML_logBase = 1876;
+const xml_token_t XML_lon = 1877;
+const xml_token_t XML_longFileNames = 1878;
+const xml_token_t XML_longText = 1879;
+const xml_token_t XML_loop = 1880;
+const xml_token_t XML_lowestEdited = 1881;
+const xml_token_t XML_lpstr = 1882;
+const xml_token_t XML_lpwstr = 1883;
+const xml_token_t XML_lsdException = 1884;
+const xml_token_t XML_lstStyle = 1885;
+const xml_token_t XML_lt1 = 1886;
+const xml_token_t XML_lt2 = 1887;
+const xml_token_t XML_lum = 1888;
+const xml_token_t XML_lumMod = 1889;
+const xml_token_t XML_lumOff = 1890;
+const xml_token_t XML_lvl = 1891;
+const xml_token_t XML_lvl1pPr = 1892;
+const xml_token_t XML_lvl2pPr = 1893;
+const xml_token_t XML_lvl3pPr = 1894;
+const xml_token_t XML_lvl4pPr = 1895;
+const xml_token_t XML_lvl5pPr = 1896;
+const xml_token_t XML_lvl6pPr = 1897;
+const xml_token_t XML_lvl7pPr = 1898;
+const xml_token_t XML_lvl8pPr = 1899;
+const xml_token_t XML_lvl9pPr = 1900;
+const xml_token_t XML_lvlJc = 1901;
+const xml_token_t XML_lvlOverride = 1902;
+const xml_token_t XML_lvlPicBulletId = 1903;
+const xml_token_t XML_lvlRestart = 1904;
+const xml_token_t XML_lvlText = 1905;
+const xml_token_t XML_m = 1906;
+const xml_token_t XML_mPr = 1907;
+const xml_token_t XML_macro = 1908;
+const xml_token_t XML_mailAsAttachment = 1909;
+const xml_token_t XML_mailMerge = 1910;
+const xml_token_t XML_mailSubject = 1911;
+const xml_token_t XML_main = 1912;
+const xml_token_t XML_mainDocumentType = 1913;
+const xml_token_t XML_majorFont = 1914;
+const xml_token_t XML_majorGridlines = 1915;
+const xml_token_t XML_majorTickMark = 1916;
+const xml_token_t XML_majorTimeUnit = 1917;
+const xml_token_t XML_majorUnit = 1918;
+const xml_token_t XML_man = 1919;
+const xml_token_t XML_manifestLocation = 1920;
+const xml_token_t XML_manualBreakCount = 1921;
+const xml_token_t XML_manualLayout = 1922;
+const xml_token_t XML_map = 1923;
+const xml_token_t XML_mapId = 1924;
+const xml_token_t XML_mappedName = 1925;
+const xml_token_t XML_mappingCount = 1926;
+const xml_token_t XML_maps = 1927;
+const xml_token_t XML_marB = 1928;
+const xml_token_t XML_marBottom = 1929;
+const xml_token_t XML_marH = 1930;
+const xml_token_t XML_marL = 1931;
+const xml_token_t XML_marLeft = 1932;
+const xml_token_t XML_marR = 1933;
+const xml_token_t XML_marRight = 1934;
+const xml_token_t XML_marT = 1935;
+const xml_token_t XML_marTop = 1936;
+const xml_token_t XML_marW = 1937;
+const xml_token_t XML_marker = 1938;
+const xml_token_t XML_markup = 1939;
+const xml_token_t XML_master = 1940;
+const xml_token_t XML_masterClrMapping = 1941;
+const xml_token_t XML_masterRel = 1942;
+const xml_token_t XML_matchSrc = 1943;
+const xml_token_t XML_matchingName = 1944;
+const xml_token_t XML_mathFont = 1945;
+const xml_token_t XML_mathPr = 1946;
+const xml_token_t XML_matrix = 1947;
+const xml_token_t XML_max = 1948;
+const xml_token_t XML_maxAng = 1949;
+const xml_token_t XML_maxDate = 1950;
+const xml_token_t XML_maxDist = 1951;
+const xml_token_t XML_maxLength = 1952;
+const xml_token_t XML_maxR = 1953;
+const xml_token_t XML_maxRId = 1954;
+const xml_token_t XML_maxRank = 1955;
+const xml_token_t XML_maxSheetId = 1956;
+const xml_token_t XML_maxSubtotal = 1957;
+const xml_token_t XML_maxVal = 1958;
+const xml_token_t XML_maxValue = 1959;
+const xml_token_t XML_maxX = 1960;
+const xml_token_t XML_maxY = 1961;
+const xml_token_t XML_maximized = 1962;
+const xml_token_t XML_mc = 1963;
+const xml_token_t XML_mcJc = 1964;
+const xml_token_t XML_mcPr = 1965;
+const xml_token_t XML_mcs = 1966;
+const xml_token_t XML_mdx = 1967;
+const xml_token_t XML_mdxMetadata = 1968;
+const xml_token_t XML_mdxSubqueries = 1969;
+const xml_token_t XML_measure = 1970;
+const xml_token_t XML_measureFilter = 1971;
+const xml_token_t XML_measureGroup = 1972;
+const xml_token_t XML_measureGroups = 1973;
+const xml_token_t XML_measures = 1974;
+const xml_token_t XML_member = 1975;
+const xml_token_t XML_memberName = 1976;
+const xml_token_t XML_memberPropertyField = 1977;
+const xml_token_t XML_memberValueDatatype = 1978;
+const xml_token_t XML_members = 1979;
+const xml_token_t XML_merge = 1980;
+const xml_token_t XML_mergeCell = 1981;
+const xml_token_t XML_mergeCells = 1982;
+const xml_token_t XML_mergeInterval = 1983;
+const xml_token_t XML_mergeItem = 1984;
+const xml_token_t XML_metadata = 1985;
+const xml_token_t XML_metadataStrings = 1986;
+const xml_token_t XML_metadataType = 1987;
+const xml_token_t XML_metadataTypes = 1988;
+const xml_token_t XML_metal = 1989;
+const xml_token_t XML_meth = 1990;
+const xml_token_t XML_method = 1991;
+const xml_token_t XML_min = 1992;
+const xml_token_t XML_minAng = 1993;
+const xml_token_t XML_minDate = 1994;
+const xml_token_t XML_minLength = 1995;
+const xml_token_t XML_minR = 1996;
+const xml_token_t XML_minRId = 1997;
+const xml_token_t XML_minRefreshableVersion = 1998;
+const xml_token_t XML_minSubtotal = 1999;
+const xml_token_t XML_minSupportedVersion = 2000;
+const xml_token_t XML_minValue = 2001;
+const xml_token_t XML_minVer = 2002;
+const xml_token_t XML_minX = 2003;
+const xml_token_t XML_minY = 2004;
+const xml_token_t XML_minimized = 2005;
+const xml_token_t XML_minimumVersion = 2006;
+const xml_token_t XML_minorFont = 2007;
+const xml_token_t XML_minorGridlines = 2008;
+const xml_token_t XML_minorTickMark = 2009;
+const xml_token_t XML_minorTimeUnit = 2010;
+const xml_token_t XML_minorUnit = 2011;
+const xml_token_t XML_minus = 2012;
+const xml_token_t XML_minusx = 2013;
+const xml_token_t XML_minusy = 2014;
+const xml_token_t XML_minute = 2015;
+const xml_token_t XML_mirrorIndents = 2016;
+const xml_token_t XML_mirrorMargins = 2017;
+const xml_token_t XML_missingCaption = 2018;
+const xml_token_t XML_missingItemsLimit = 2019;
+const xml_token_t XML_miter = 2020;
+const xml_token_t XML_miterlimit = 2021;
+const xml_token_t XML_mod = 2022;
+const xml_token_t XML_modelId = 2023;
+const xml_token_t XML_modifyVerifier = 2024;
+const xml_token_t XML_month = 2025;
+const xml_token_t XML_monthLong = 2026;
+const xml_token_t XML_monthShort = 2027;
+const xml_token_t XML_moveFrom = 2028;
+const xml_token_t XML_moveFromRangeEnd = 2029;
+const xml_token_t XML_moveFromRangeStart = 2030;
+const xml_token_t XML_moveTo = 2031;
+const xml_token_t XML_moveToRangeEnd = 2032;
+const xml_token_t XML_moveToRangeStart = 2033;
+const xml_token_t XML_moveWith = 2034;
+const xml_token_t XML_movie = 2035;
+const xml_token_t XML_mp = 2036;
+const xml_token_t XML_mpFld = 2037;
+const xml_token_t XML_mpMap = 2038;
+const xml_token_t XML_mps = 2039;
+const xml_token_t XML_mr = 2040;
+const xml_token_t XML_mruColors = 2041;
+const xml_token_t XML_ms = 2042;
+const xml_token_t XML_multiLevelType = 2043;
+const xml_token_t XML_multiLine = 2044;
+const xml_token_t XML_multiLvlStrCache = 2045;
+const xml_token_t XML_multiLvlStrRef = 2046;
+const xml_token_t XML_multipleFieldFilters = 2047;
+const xml_token_t XML_multipleItemSelectionAllowed = 2048;
+const xml_token_t XML_mute = 2049;
+const xml_token_t XML_mwSmallCaps = 2050;
+const xml_token_t XML_n = 2051;
+const xml_token_t XML_name = 2052;
+const xml_token_t XML_nameLen = 2053;
+const xml_token_t XML_namespaceUri = 2054;
+const xml_token_t XML_namespaceuri = 2055;
+const xml_token_t XML_nary = 2056;
+const xml_token_t XML_naryLim = 2057;
+const xml_token_t XML_naryPr = 2058;
+const xml_token_t XML_nc = 2059;
+const xml_token_t XML_ndxf = 2060;
+const xml_token_t XML_neCell = 2061;
+const xml_token_t XML_new = 2062;
+const xml_token_t XML_newLength = 2063;
+const xml_token_t XML_newName = 2064;
+const xml_token_t XML_newsflash = 2065;
+const xml_token_t XML_next = 2066;
+const xml_token_t XML_nextAc = 2067;
+const xml_token_t XML_nextCondLst = 2068;
+const xml_token_t XML_nextId = 2069;
+const xml_token_t XML_nf = 2070;
+const xml_token_t XML_nlCheck = 2071;
+const xml_token_t XML_noAdjustHandles = 2072;
+const xml_token_t XML_noAutofit = 2073;
+const xml_token_t XML_noBorder = 2074;
+const xml_token_t XML_noBreak = 2075;
+const xml_token_t XML_noBreakHyphen = 2076;
+const xml_token_t XML_noChangeArrowheads = 2077;
+const xml_token_t XML_noChangeAspect = 2078;
+const xml_token_t XML_noChangeShapeType = 2079;
+const xml_token_t XML_noColumnBalance = 2080;
+const xml_token_t XML_noCrop = 2081;
+const xml_token_t XML_noDrilldown = 2082;
+const xml_token_t XML_noEditPoints = 2083;
+const xml_token_t XML_noEndCap = 2084;
+const xml_token_t XML_noEndnote = 2085;
+const xml_token_t XML_noExtraLineSpacing = 2086;
+const xml_token_t XML_noFill = 2087;
+const xml_token_t XML_noGrp = 2088;
+const xml_token_t XML_noLabel = 2089;
+const xml_token_t XML_noLeading = 2090;
+const xml_token_t XML_noLineBreaksAfter = 2091;
+const xml_token_t XML_noLineBreaksBefore = 2092;
+const xml_token_t XML_noMove = 2093;
+const xml_token_t XML_noMultiLvlLbl = 2094;
+const xml_token_t XML_noProof = 2095;
+const xml_token_t XML_noPunctuationKerning = 2096;
+const xml_token_t XML_noResize = 2097;
+const xml_token_t XML_noResizeAllowed = 2098;
+const xml_token_t XML_noRot = 2099;
+const xml_token_t XML_noSelect = 2100;
+const xml_token_t XML_noSpaceRaiseLower = 2101;
+const xml_token_t XML_noTabHangInd = 2102;
+const xml_token_t XML_noTextEdit = 2103;
+const xml_token_t XML_noUngrp = 2104;
+const xml_token_t XML_noWrap = 2105;
+const xml_token_t XML_nodePh = 2106;
+const xml_token_t XML_nodeType = 2107;
+const xml_token_t XML_nonAutoSortDefault = 2108;
+const xml_token_t XML_nor = 2109;
+const xml_token_t XML_norm = 2110;
+const xml_token_t XML_normAutofit = 2111;
+const xml_token_t XML_normalViewPr = 2112;
+const xml_token_t XML_normalizeH = 2113;
+const xml_token_t XML_notTrueType = 2114;
+const xml_token_t XML_notes = 2115;
+const xml_token_t XML_notesMaster = 2116;
+const xml_token_t XML_notesMasterId = 2117;
+const xml_token_t XML_notesMasterIdLst = 2118;
+const xml_token_t XML_notesStyle = 2119;
+const xml_token_t XML_notesSz = 2120;
+const xml_token_t XML_notesTextViewPr = 2121;
+const xml_token_t XML_notesViewPr = 2122;
+const xml_token_t XML_np = 2123;
+const xml_token_t XML_ns = 2124;
+const xml_token_t XML_nsid = 2125;
+const xml_token_t XML_null = 2126;
+const xml_token_t XML_num = 2127;
+const xml_token_t XML_numCache = 2128;
+const xml_token_t XML_numCol = 2129;
+const xml_token_t XML_numFmt = 2130;
+const xml_token_t XML_numFmtId = 2131;
+const xml_token_t XML_numFmts = 2132;
+const xml_token_t XML_numId = 2133;
+const xml_token_t XML_numIdMacAtCleanup = 2134;
+const xml_token_t XML_numLit = 2135;
+const xml_token_t XML_numPicBullet = 2136;
+const xml_token_t XML_numPicBulletId = 2137;
+const xml_token_t XML_numPr = 2138;
+const xml_token_t XML_numRef = 2139;
+const xml_token_t XML_numRestart = 2140;
+const xml_token_t XML_numSld = 2141;
+const xml_token_t XML_numStart = 2142;
+const xml_token_t XML_numStyleLink = 2143;
+const xml_token_t XML_numberStoredAsText = 2144;
+const xml_token_t XML_numbering = 2145;
+const xml_token_t XML_numberingChange = 2146;
+const xml_token_t XML_nvCxnSpPr = 2147;
+const xml_token_t XML_nvGraphicFramePr = 2148;
+const xml_token_t XML_nvGrpSpPr = 2149;
+const xml_token_t XML_nvPicPr = 2150;
+const xml_token_t XML_nvPr = 2151;
+const xml_token_t XML_nvSpPr = 2152;
+const xml_token_t XML_nwCell = 2153;
+const xml_token_t XML_o = 2154;
+const xml_token_t XML_oMath = 2155;
+const xml_token_t XML_oMathPara = 2156;
+const xml_token_t XML_oMathParaPr = 2157;
+const xml_token_t XML_objDist = 2158;
+const xml_token_t XML_object = 2159;
+const xml_token_t XML_objectDefaults = 2160;
+const xml_token_t XML_objects = 2161;
+const xml_token_t XML_oblob = 2162;
+const xml_token_t XML_obscured = 2163;
+const xml_token_t XML_oc = 2164;
+const xml_token_t XML_odcFile = 2165;
+const xml_token_t XML_oddFooter = 2166;
+const xml_token_t XML_oddHeader = 2167;
+const xml_token_t XML_odso = 2168;
+const xml_token_t XML_odxf = 2169;
+const xml_token_t XML_ofPieChart = 2170;
+const xml_token_t XML_ofPieType = 2171;
+const xml_token_t XML_off = 2172;
+const xml_token_t XML_offset = 2173;
+const xml_token_t XML_offset2 = 2174;
+const xml_token_t XML_offsetFrom = 2175;
+const xml_token_t XML_olapPr = 2176;
+const xml_token_t XML_old = 2177;
+const xml_token_t XML_oldComment = 2178;
+const xml_token_t XML_oldCustomMenu = 2179;
+const xml_token_t XML_oldDescription = 2180;
+const xml_token_t XML_oldFormula = 2181;
+const xml_token_t XML_oldFunction = 2182;
+const xml_token_t XML_oldFunctionGroupId = 2183;
+const xml_token_t XML_oldHelp = 2184;
+const xml_token_t XML_oldHidden = 2185;
+const xml_token_t XML_oldLength = 2186;
+const xml_token_t XML_oldName = 2187;
+const xml_token_t XML_oldPh = 2188;
+const xml_token_t XML_oldQuotePrefix = 2189;
+const xml_token_t XML_oldShortcutKey = 2190;
+const xml_token_t XML_oldStatusBar = 2191;
+const xml_token_t XML_ole = 2192;
+const xml_token_t XML_oleChartEl = 2193;
+const xml_token_t XML_oleItem = 2194;
+const xml_token_t XML_oleItems = 2195;
+const xml_token_t XML_oleLink = 2196;
+const xml_token_t XML_oleObj = 2197;
+const xml_token_t XML_oleObject = 2198;
+const xml_token_t XML_oleObjects = 2199;
+const xml_token_t XML_oleSize = 2200;
+const xml_token_t XML_oleUpdate = 2201;
+const xml_token_t XML_oleicon = 2202;
+const xml_token_t XML_oleid = 2203;
+const xml_token_t XML_on = 2204;
+const xml_token_t XML_oneCellAnchor = 2205;
+const xml_token_t XML_oneField = 2206;
+const xml_token_t XML_oned = 2207;
+const xml_token_t XML_onlySync = 2208;
+const xml_token_t XML_onlyUseConnectionFile = 2209;
+const xml_token_t XML_op = 2210;
+const xml_token_t XML_opEmu = 2211;
+const xml_token_t XML_opacity = 2212;
+const xml_token_t XML_opacity2 = 2213;
+const xml_token_t XML_operator = 2214;
+const xml_token_t XML_optimizeForBrowser = 2215;
+const xml_token_t XML_optimizeMemory = 2216;
+const xml_token_t XML_order = 2217;
+const xml_token_t XML_orgChart = 2218;
+const xml_token_t XML_organizeInFolders = 2219;
+const xml_token_t XML_orient = 2220;
+const xml_token_t XML_orientation = 2221;
+const xml_token_t XML_orientationangle = 2222;
+const xml_token_t XML_origin = 2223;
+const xml_token_t XML_original = 2224;
+const xml_token_t XML_ostorage = 2225;
+const xml_token_t XML_ostream = 2226;
+const xml_token_t XML_other = 2227;
+const xml_token_t XML_otherStyle = 2228;
+const xml_token_t XML_outerShdw = 2229;
+const xml_token_t XML_outline = 2230;
+const xml_token_t XML_outlineData = 2231;
+const xml_token_t XML_outlineLevel = 2232;
+const xml_token_t XML_outlineLevelCol = 2233;
+const xml_token_t XML_outlineLevelRow = 2234;
+const xml_token_t XML_outlineLvl = 2235;
+const xml_token_t XML_outlinePr = 2236;
+const xml_token_t XML_outlineSymbols = 2237;
+const xml_token_t XML_outlineViewPr = 2238;
+const xml_token_t XML_oval = 2239;
+const xml_token_t XML_overflowPunct = 2240;
+const xml_token_t XML_overlap = 2241;
+const xml_token_t XML_overlay = 2242;
+const xml_token_t XML_override = 2243;
+const xml_token_t XML_overrideClrMapping = 2244;
+const xml_token_t XML_p = 2245;
+const xml_token_t XML_pBdr = 2246;
+const xml_token_t XML_pLen = 2247;
+const xml_token_t XML_pPos = 2248;
+const xml_token_t XML_pPr = 2249;
+const xml_token_t XML_pPrChange = 2250;
+const xml_token_t XML_pPrDefault = 2251;
+const xml_token_t XML_pRg = 2252;
+const xml_token_t XML_pStyle = 2253;
+const xml_token_t XML_page = 2254;
+const xml_token_t XML_pageBreakBefore = 2255;
+const xml_token_t XML_pageField = 2256;
+const xml_token_t XML_pageFields = 2257;
+const xml_token_t XML_pageItem = 2258;
+const xml_token_t XML_pageMargins = 2259;
+const xml_token_t XML_pageOrder = 2260;
+const xml_token_t XML_pageOverThenDown = 2261;
+const xml_token_t XML_pageSetUpPr = 2262;
+const xml_token_t XML_pageSetup = 2263;
+const xml_token_t XML_pageStyle = 2264;
+const xml_token_t XML_pageWrap = 2265;
+const xml_token_t XML_pages = 2266;
+const xml_token_t XML_pane = 2267;
+const xml_token_t XML_panose = 2268;
+const xml_token_t XML_panose1 = 2269;
+const xml_token_t XML_paperSize = 2270;
+const xml_token_t XML_paperSrc = 2271;
+const xml_token_t XML_par = 2272;
+const xml_token_t XML_parTransId = 2273;
+const xml_token_t XML_param = 2274;
+const xml_token_t XML_parameter = 2275;
+const xml_token_t XML_parameterType = 2276;
+const xml_token_t XML_parameters = 2277;
+const xml_token_t XML_parent = 2278;
+const xml_token_t XML_parentSet = 2279;
+const xml_token_t XML_parsePre = 2280;
+const xml_token_t XML_password = 2281;
+const xml_token_t XML_pasteAll = 2282;
+const xml_token_t XML_pasteBorders = 2283;
+const xml_token_t XML_pasteColWidths = 2284;
+const xml_token_t XML_pasteComments = 2285;
+const xml_token_t XML_pasteDataValidation = 2286;
+const xml_token_t XML_pasteFormats = 2287;
+const xml_token_t XML_pasteFormulas = 2288;
+const xml_token_t XML_pasteNumberFormats = 2289;
+const xml_token_t XML_pasteValues = 2290;
+const xml_token_t XML_path = 2291;
+const xml_token_t XML_pathEditMode = 2292;
+const xml_token_t XML_pathLst = 2293;
+const xml_token_t XML_pattFill = 2294;
+const xml_token_t XML_patternFill = 2295;
+const xml_token_t XML_patternType = 2296;
+const xml_token_t XML_penClr = 2297;
+const xml_token_t XML_percent = 2298;
+const xml_token_t XML_period = 2299;
+const xml_token_t XML_permEnd = 2300;
+const xml_token_t XML_permStart = 2301;
+const xml_token_t XML_personal = 2302;
+const xml_token_t XML_personalCompose = 2303;
+const xml_token_t XML_personalReply = 2304;
+const xml_token_t XML_personalView = 2305;
+const xml_token_t XML_perspective = 2306;
+const xml_token_t XML_pgBorders = 2307;
+const xml_token_t XML_pgMar = 2308;
+const xml_token_t XML_pgNum = 2309;
+const xml_token_t XML_pgNumType = 2310;
+const xml_token_t XML_pgSz = 2311;
+const xml_token_t XML_ph = 2312;
+const xml_token_t XML_phant = 2313;
+const xml_token_t XML_phantPr = 2314;
+const xml_token_t XML_phldr = 2315;
+const xml_token_t XML_phldrT = 2316;
+const xml_token_t XML_phonetic = 2317;
+const xml_token_t XML_phoneticPr = 2318;
+const xml_token_t XML_photoAlbum = 2319;
+const xml_token_t XML_pic = 2320;
+const xml_token_t XML_picLocks = 2321;
+const xml_token_t XML_pict = 2322;
+const xml_token_t XML_picture = 2323;
+const xml_token_t XML_pictureFormat = 2324;
+const xml_token_t XML_pictureOptions = 2325;
+const xml_token_t XML_pictureStackUnit = 2326;
+const xml_token_t XML_pid = 2327;
+const xml_token_t XML_pie3DChart = 2328;
+const xml_token_t XML_pieChart = 2329;
+const xml_token_t XML_pitch = 2330;
+const xml_token_t XML_pitchFamily = 2331;
+const xml_token_t XML_pivot = 2332;
+const xml_token_t XML_pivotArea = 2333;
+const xml_token_t XML_pivotAreas = 2334;
+const xml_token_t XML_pivotButton = 2335;
+const xml_token_t XML_pivotCache = 2336;
+const xml_token_t XML_pivotCacheDefinition = 2337;
+const xml_token_t XML_pivotCacheRecords = 2338;
+const xml_token_t XML_pivotCaches = 2339;
+const xml_token_t XML_pivotField = 2340;
+const xml_token_t XML_pivotFields = 2341;
+const xml_token_t XML_pivotFmt = 2342;
+const xml_token_t XML_pivotFmts = 2343;
+const xml_token_t XML_pivotHierarchies = 2344;
+const xml_token_t XML_pivotHierarchy = 2345;
+const xml_token_t XML_pivotSelection = 2346;
+const xml_token_t XML_pivotSource = 2347;
+const xml_token_t XML_pivotTableDefinition = 2348;
+const xml_token_t XML_pivotTableStyle = 2349;
+const xml_token_t XML_pivotTableStyleInfo = 2350;
+const xml_token_t XML_pivotTables = 2351;
+const xml_token_t XML_pixelsPerInch = 2352;
+const xml_token_t XML_placeholder = 2353;
+const xml_token_t XML_plane = 2354;
+const xml_token_t XML_plcHide = 2355;
+const xml_token_t XML_plotArea = 2356;
+const xml_token_t XML_plotVisOnly = 2357;
+const xml_token_t XML_plus = 2358;
+const xml_token_t XML_points = 2359;
+const xml_token_t XML_polar = 2360;
+const xml_token_t XML_polyline = 2361;
+const xml_token_t XML_pos = 2362;
+const xml_token_t XML_posOffset = 2363;
+const xml_token_t XML_position = 2364;
+const xml_token_t XML_positionH = 2365;
+const xml_token_t XML_positionV = 2366;
+const xml_token_t XML_post = 2367;
+const xml_token_t XML_postSp = 2368;
+const xml_token_t XML_prLst = 2369;
+const xml_token_t XML_prSet = 2370;
+const xml_token_t XML_preSp = 2371;
+const xml_token_t XML_preferPic = 2372;
+const xml_token_t XML_preferRelativeResize = 2373;
+const xml_token_t XML_preferSingleView = 2374;
+const xml_token_t XML_preferrelative = 2375;
+const xml_token_t XML_prefixMappings = 2376;
+const xml_token_t XML_presAssocID = 2377;
+const xml_token_t XML_presId = 2378;
+const xml_token_t XML_presLayoutVars = 2379;
+const xml_token_t XML_presName = 2380;
+const xml_token_t XML_presOf = 2381;
+const xml_token_t XML_presStyleCnt = 2382;
+const xml_token_t XML_presStyleIdx = 2383;
+const xml_token_t XML_presStyleLbl = 2384;
+const xml_token_t XML_present = 2385;
+const xml_token_t XML_presentation = 2386;
+const xml_token_t XML_presentationPr = 2387;
+const xml_token_t XML_preserve = 2388;
+const xml_token_t XML_preserveFormatting = 2389;
+const xml_token_t XML_preserveHistory = 2390;
+const xml_token_t XML_preserveSortFilterLayout = 2391;
+const xml_token_t XML_presetClass = 2392;
+const xml_token_t XML_presetID = 2393;
+const xml_token_t XML_presetSubtype = 2394;
+const xml_token_t XML_prevAc = 2395;
+const xml_token_t XML_prevCondLst = 2396;
+const xml_token_t XML_previousCol = 2397;
+const xml_token_t XML_previousRow = 2398;
+const xml_token_t XML_pri = 2399;
+const xml_token_t XML_print = 2400;
+const xml_token_t XML_printArea = 2401;
+const xml_token_t XML_printBodyTextBeforeHeader = 2402;
+const xml_token_t XML_printColBlack = 2403;
+const xml_token_t XML_printDrill = 2404;
+const xml_token_t XML_printFormsData = 2405;
+const xml_token_t XML_printFractionalCharacterWidth = 2406;
+const xml_token_t XML_printOptions = 2407;
+const xml_token_t XML_printPostScriptOverText = 2408;
+const xml_token_t XML_printSettings = 2409;
+const xml_token_t XML_printTwoOnOne = 2410;
+const xml_token_t XML_printerSettings = 2411;
+const xml_token_t XML_priority = 2412;
+const xml_token_t XML_prnPr = 2413;
+const xml_token_t XML_prnWhat = 2414;
+const xml_token_t XML_productSubtotal = 2415;
+const xml_token_t XML_progId = 2416;
+const xml_token_t XML_progress = 2417;
+const xml_token_t XML_prompt = 2418;
+const xml_token_t XML_promptTitle = 2419;
+const xml_token_t XML_promptedSolutions = 2420;
+const xml_token_t XML_proofErr = 2421;
+const xml_token_t XML_proofState = 2422;
+const xml_token_t XML_property = 2423;
+const xml_token_t XML_propertyName = 2424;
+const xml_token_t XML_protected = 2425;
+const xml_token_t XML_protectedRange = 2426;
+const xml_token_t XML_protectedRanges = 2427;
+const xml_token_t XML_protection = 2428;
+const xml_token_t XML_provid = 2429;
+const xml_token_t XML_proxy = 2430;
+const xml_token_t XML_prst = 2431;
+const xml_token_t XML_prstClr = 2432;
+const xml_token_t XML_prstDash = 2433;
+const xml_token_t XML_prstGeom = 2434;
+const xml_token_t XML_prstMaterial = 2435;
+const xml_token_t XML_prstShdw = 2436;
+const xml_token_t XML_prstTxWarp = 2437;
+const xml_token_t XML_pt = 2438;
+const xml_token_t XML_ptCount = 2439;
+const xml_token_t XML_ptLst = 2440;
+const xml_token_t XML_ptType = 2441;
+const xml_token_t XML_ptab = 2442;
+const xml_token_t XML_ptsTypes = 2443;
+const xml_token_t XML_pubBrowser = 2444;
+const xml_token_t XML_publishItems = 2445;
+const xml_token_t XML_publishToServer = 2446;
+const xml_token_t XML_published = 2447;
+const xml_token_t XML_pull = 2448;
+const xml_token_t XML_push = 2449;
+const xml_token_t XML_qFormat = 2450;
+const xml_token_t XML_qs = 2451;
+const xml_token_t XML_qsCatId = 2452;
+const xml_token_t XML_qsTypeId = 2453;
+const xml_token_t XML_quadBezTo = 2454;
+const xml_token_t XML_qualifier = 2455;
+const xml_token_t XML_query = 2456;
+const xml_token_t XML_queryCache = 2457;
+const xml_token_t XML_queryFailed = 2458;
+const xml_token_t XML_queryTable = 2459;
+const xml_token_t XML_queryTableDeletedFields = 2460;
+const xml_token_t XML_queryTableField = 2461;
+const xml_token_t XML_queryTableFieldId = 2462;
+const xml_token_t XML_queryTableFields = 2463;
+const xml_token_t XML_queryTableRefresh = 2464;
+const xml_token_t XML_quickTimeFile = 2465;
+const xml_token_t XML_quotePrefix = 2466;
+const xml_token_t XML_r = 2467;
+const xml_token_t XML_r1 = 2468;
+const xml_token_t XML_r2 = 2469;
+const xml_token_t XML_r4 = 2470;
+const xml_token_t XML_r8 = 2471;
+const xml_token_t XML_rAng = 2472;
+const xml_token_t XML_rAngAx = 2473;
+const xml_token_t XML_rCtr = 2474;
+const xml_token_t XML_rFont = 2475;
+const xml_token_t XML_rFonts = 2476;
+const xml_token_t XML_rId = 2477;
+const xml_token_t XML_rIns = 2478;
+const xml_token_t XML_rMargin = 2479;
+const xml_token_t XML_rPh = 2480;
+const xml_token_t XML_rPr = 2481;
+const xml_token_t XML_rPrChange = 2482;
+const xml_token_t XML_rPrDefault = 2483;
+const xml_token_t XML_rSp = 2484;
+const xml_token_t XML_rSpRule = 2485;
+const xml_token_t XML_rStyle = 2486;
+const xml_token_t XML_ra = 2487;
+const xml_token_t XML_rad = 2488;
+const xml_token_t XML_radPr = 2489;
+const xml_token_t XML_radarChart = 2490;
+const xml_token_t XML_radarStyle = 2491;
+const xml_token_t XML_radiusrange = 2492;
+const xml_token_t XML_raf = 2493;
+const xml_token_t XML_random = 2494;
+const xml_token_t XML_randomBar = 2495;
+const xml_token_t XML_rangePr = 2496;
+const xml_token_t XML_rangeSet = 2497;
+const xml_token_t XML_rangeSets = 2498;
+const xml_token_t XML_rank = 2499;
+const xml_token_t XML_rankBy = 2500;
+const xml_token_t XML_rc = 2501;
+const xml_token_t XML_rcc = 2502;
+const xml_token_t XML_rcft = 2503;
+const xml_token_t XML_rcmt = 2504;
+const xml_token_t XML_rctx = 2505;
+const xml_token_t XML_rcv = 2506;
+const xml_token_t XML_rdn = 2507;
+const xml_token_t XML_readModeInkLockDown = 2508;
+const xml_token_t XML_readOnlyRecommended = 2509;
+const xml_token_t XML_readingOrder = 2510;
+const xml_token_t XML_recipientData = 2511;
+const xml_token_t XML_recipients = 2512;
+const xml_token_t XML_recolor = 2513;
+const xml_token_t XML_recolortarget = 2514;
+const xml_token_t XML_recommended = 2515;
+const xml_token_t XML_reconnectionMethod = 2516;
+const xml_token_t XML_recordCount = 2517;
+const xml_token_t XML_rect = 2518;
+const xml_token_t XML_red = 2519;
+const xml_token_t XML_redMod = 2520;
+const xml_token_t XML_redOff = 2521;
+const xml_token_t XML_ref = 2522;
+const xml_token_t XML_ref3D = 2523;
+const xml_token_t XML_refFor = 2524;
+const xml_token_t XML_refForName = 2525;
+const xml_token_t XML_refMode = 2526;
+const xml_token_t XML_refPtType = 2527;
+const xml_token_t XML_refType = 2528;
+const xml_token_t XML_reference = 2529;
+const xml_token_t XML_references = 2530;
+const xml_token_t XML_refersTo = 2531;
+const xml_token_t XML_reflection = 2532;
+const xml_token_t XML_refreshAllConnections = 2533;
+const xml_token_t XML_refreshError = 2534;
+const xml_token_t XML_refreshOnChange = 2535;
+const xml_token_t XML_refreshOnLoad = 2536;
+const xml_token_t XML_refreshedBy = 2537;
+const xml_token_t XML_refreshedDate = 2538;
+const xml_token_t XML_refreshedVersion = 2539;
+const xml_token_t XML_regroupid = 2540;
+const xml_token_t XML_regrouptable = 2541;
+const xml_token_t XML_regular = 2542;
+const xml_token_t XML_rel = 2543;
+const xml_token_t XML_relIds = 2544;
+const xml_token_t XML_relOff = 2545;
+const xml_token_t XML_relSizeAnchor = 2546;
+const xml_token_t XML_relation = 2547;
+const xml_token_t XML_relationtable = 2548;
+const xml_token_t XML_relative = 2549;
+const xml_token_t XML_relativeFrom = 2550;
+const xml_token_t XML_relativeHeight = 2551;
+const xml_token_t XML_relativeIndent = 2552;
+const xml_token_t XML_relativeTo = 2553;
+const xml_token_t XML_relid = 2554;
+const xml_token_t XML_relyOnVML = 2555;
+const xml_token_t XML_relyOnVml = 2556;
+const xml_token_t XML_removeDataOnSave = 2557;
+const xml_token_t XML_removeDateAndTime = 2558;
+const xml_token_t XML_removePersonalInfoOnSave = 2559;
+const xml_token_t XML_removePersonalInformation = 2560;
+const xml_token_t XML_render = 2561;
+const xml_token_t XML_repairLoad = 2562;
+const xml_token_t XML_repeatCount = 2563;
+const xml_token_t XML_repeatDur = 2564;
+const xml_token_t XML_resId = 2565;
+const xml_token_t XML_reservationPassword = 2566;
+const xml_token_t XML_resizeGraphics = 2567;
+const xml_token_t XML_resizeHandles = 2568;
+const xml_token_t XML_restart = 2569;
+const xml_token_t XML_restoredLeft = 2570;
+const xml_token_t XML_restoredTop = 2571;
+const xml_token_t XML_result = 2572;
+const xml_token_t XML_rev = 2573;
+const xml_token_t XML_reverse = 2574;
+const xml_token_t XML_reviewed = 2575;
+const xml_token_t XML_reviewedList = 2576;
+const xml_token_t XML_revisionId = 2577;
+const xml_token_t XML_revisionView = 2578;
+const xml_token_t XML_revisions = 2579;
+const xml_token_t XML_revisionsPassword = 2580;
+const xml_token_t XML_rfmt = 2581;
+const xml_token_t XML_rgb = 2582;
+const xml_token_t XML_rgbColor = 2583;
+const xml_token_t XML_rich = 2584;
+const xml_token_t XML_richText = 2585;
+const xml_token_t XML_rig = 2586;
+const xml_token_t XML_right = 2587;
+const xml_token_t XML_rightChars = 2588;
+const xml_token_t XML_rightFromText = 2589;
+const xml_token_t XML_rightToLeft = 2590;
+const xml_token_t XML_ris = 2591;
+const xml_token_t XML_rm = 2592;
+const xml_token_t XML_rot = 2593;
+const xml_token_t XML_rotWithShape = 2594;
+const xml_token_t XML_rotX = 2595;
+const xml_token_t XML_rotY = 2596;
+const xml_token_t XML_rotate = 2597;
+const xml_token_t XML_rotation = 2598;
+const xml_token_t XML_rotationangle = 2599;
+const xml_token_t XML_rotationcenter = 2600;
+const xml_token_t XML_round = 2601;
+const xml_token_t XML_roundedCorners = 2602;
+const xml_token_t XML_roundrect = 2603;
+const xml_token_t XML_row = 2604;
+const xml_token_t XML_rowBreaks = 2605;
+const xml_token_t XML_rowColShift = 2606;
+const xml_token_t XML_rowDrillCount = 2607;
+const xml_token_t XML_rowFields = 2608;
+const xml_token_t XML_rowGrandTotals = 2609;
+const xml_token_t XML_rowHeaderCaption = 2610;
+const xml_token_t XML_rowHierarchiesUsage = 2611;
+const xml_token_t XML_rowHierarchyUsage = 2612;
+const xml_token_t XML_rowItems = 2613;
+const xml_token_t XML_rowNumbers = 2614;
+const xml_token_t XML_rowOff = 2615;
+const xml_token_t XML_rowPageCount = 2616;
+const xml_token_t XML_rowSpan = 2617;
+const xml_token_t XML_rows = 2618;
+const xml_token_t XML_rqt = 2619;
+const xml_token_t XML_rrc = 2620;
+const xml_token_t XML_rsid = 2621;
+const xml_token_t XML_rsidDel = 2622;
+const xml_token_t XML_rsidP = 2623;
+const xml_token_t XML_rsidR = 2624;
+const xml_token_t XML_rsidRDefault = 2625;
+const xml_token_t XML_rsidRPr = 2626;
+const xml_token_t XML_rsidRoot = 2627;
+const xml_token_t XML_rsidSect = 2628;
+const xml_token_t XML_rsidTr = 2629;
+const xml_token_t XML_rsids = 2630;
+const xml_token_t XML_rsnm = 2631;
+const xml_token_t XML_rt = 2632;
+const xml_token_t XML_rtl = 2633;
+const xml_token_t XML_rtlCol = 2634;
+const xml_token_t XML_rtlGutter = 2635;
+const xml_token_t XML_rtn = 2636;
+const xml_token_t XML_ruby = 2637;
+const xml_token_t XML_rubyAlign = 2638;
+const xml_token_t XML_rubyBase = 2639;
+const xml_token_t XML_rubyPr = 2640;
+const xml_token_t XML_rule = 2641;
+const xml_token_t XML_ruleLst = 2642;
+const xml_token_t XML_rules = 2643;
+const xml_token_t XML_rupBuild = 2644;
+const xml_token_t XML_s = 2645;
+const xml_token_t XML_sId = 2646;
+const xml_token_t XML_sPre = 2647;
+const xml_token_t XML_sPrePr = 2648;
+const xml_token_t XML_sSub = 2649;
+const xml_token_t XML_sSubPr = 2650;
+const xml_token_t XML_sSubSup = 2651;
+const xml_token_t XML_sSubSupPr = 2652;
+const xml_token_t XML_sSup = 2653;
+const xml_token_t XML_sSupPr = 2654;
+const xml_token_t XML_salt = 2655;
+const xml_token_t XML_saltData = 2656;
+const xml_token_t XML_sampData = 2657;
+const xml_token_t XML_sat = 2658;
+const xml_token_t XML_satMod = 2659;
+const xml_token_t XML_satOff = 2660;
+const xml_token_t XML_saveData = 2661;
+const xml_token_t XML_saveExternalLinkValues = 2662;
+const xml_token_t XML_saveFormsData = 2663;
+const xml_token_t XML_saveInvalidXml = 2664;
+const xml_token_t XML_savePassword = 2665;
+const xml_token_t XML_savePreviewPicture = 2666;
+const xml_token_t XML_saveSmartTagsAsXml = 2667;
+const xml_token_t XML_saveSubsetFonts = 2668;
+const xml_token_t XML_saveThroughXslt = 2669;
+const xml_token_t XML_saveXmlDataOnly = 2670;
+const xml_token_t XML_sb = 2671;
+const xml_token_t XML_scale = 2672;
+const xml_token_t XML_scaleToFitPaper = 2673;
+const xml_token_t XML_scaleWithDoc = 2674;
+const xml_token_t XML_scaled = 2675;
+const xml_token_t XML_scaling = 2676;
+const xml_token_t XML_scatterChart = 2677;
+const xml_token_t XML_scatterStyle = 2678;
+const xml_token_t XML_scenario = 2679;
+const xml_token_t XML_scenarios = 2680;
+const xml_token_t XML_scene3d = 2681;
+const xml_token_t XML_schema = 2682;
+const xml_token_t XML_schemaLibrary = 2683;
+const xml_token_t XML_schemaLocation = 2684;
+const xml_token_t XML_schemaRef = 2685;
+const xml_token_t XML_schemaRefs = 2686;
+const xml_token_t XML_scheme = 2687;
+const xml_token_t XML_schemeClr = 2688;
+const xml_token_t XML_scope = 2689;
+const xml_token_t XML_scr = 2690;
+const xml_token_t XML_scrgbClr = 2691;
+const xml_token_t XML_script = 2692;
+const xml_token_t XML_scrollbar = 2693;
+const xml_token_t XML_sd = 2694;
+const xml_token_t XML_sdt = 2695;
+const xml_token_t XML_sdtContent = 2696;
+const xml_token_t XML_sdtEndPr = 2697;
+const xml_token_t XML_sdtPr = 2698;
+const xml_token_t XML_seCell = 2699;
+const xml_token_t XML_second = 2700;
+const xml_token_t XML_secondPiePt = 2701;
+const xml_token_t XML_secondPieSize = 2702;
+const xml_token_t XML_sectPr = 2703;
+const xml_token_t XML_sectPrChange = 2704;
+const xml_token_t XML_securityDescriptor = 2705;
+const xml_token_t XML_selectFldWithFirstOrLastChar = 2706;
+const xml_token_t XML_selectLockedCells = 2707;
+const xml_token_t XML_selectUnlockedCells = 2708;
+const xml_token_t XML_selected = 2709;
+const xml_token_t XML_selection = 2710;
+const xml_token_t XML_semiHidden = 2711;
+const xml_token_t XML_semicolon = 2712;
+const xml_token_t XML_sendLocale = 2713;
+const xml_token_t XML_sep = 2714;
+const xml_token_t XML_sepChr = 2715;
+const xml_token_t XML_separator = 2716;
+const xml_token_t XML_seq = 2717;
+const xml_token_t XML_ser = 2718;
+const xml_token_t XML_serAx = 2719;
+const xml_token_t XML_serLines = 2720;
+const xml_token_t XML_series = 2721;
+const xml_token_t XML_seriesIdx = 2722;
+const xml_token_t XML_serverCommand = 2723;
+const xml_token_t XML_serverField = 2724;
+const xml_token_t XML_serverFill = 2725;
+const xml_token_t XML_serverFont = 2726;
+const xml_token_t XML_serverFontColor = 2727;
+const xml_token_t XML_serverFormat = 2728;
+const xml_token_t XML_serverFormats = 2729;
+const xml_token_t XML_serverNumberFormat = 2730;
+const xml_token_t XML_serverSldId = 2731;
+const xml_token_t XML_serverSldModifiedTime = 2732;
+const xml_token_t XML_serverZoom = 2733;
+const xml_token_t XML_set = 2734;
+const xml_token_t XML_setDefinition = 2735;
+const xml_token_t XML_sets = 2736;
+const xml_token_t XML_settings = 2737;
+const xml_token_t XML_shade = 2738;
+const xml_token_t XML_shadeToTitle = 2739;
+const xml_token_t XML_shadow = 2740;
+const xml_token_t XML_shadowcolor = 2741;
+const xml_token_t XML_shadowok = 2742;
+const xml_token_t XML_shape = 2743;
+const xml_token_t XML_shapeDefaults = 2744;
+const xml_token_t XML_shapeId = 2745;
+const xml_token_t XML_shapeLayoutLikeWW8 = 2746;
+const xml_token_t XML_shapedefaults = 2747;
+const xml_token_t XML_shapeid = 2748;
+const xml_token_t XML_shapelayout = 2749;
+const xml_token_t XML_shapetype = 2750;
+const xml_token_t XML_shared = 2751;
+const xml_token_t XML_sharedItems = 2752;
+const xml_token_t XML_shd = 2753;
+const xml_token_t XML_sheet = 2754;
+const xml_token_t XML_sheetCalcPr = 2755;
+const xml_token_t XML_sheetData = 2756;
+const xml_token_t XML_sheetDataSet = 2757;
+const xml_token_t XML_sheetFormatPr = 2758;
+const xml_token_t XML_sheetId = 2759;
+const xml_token_t XML_sheetIdMap = 2760;
+const xml_token_t XML_sheetName = 2761;
+const xml_token_t XML_sheetNames = 2762;
+const xml_token_t XML_sheetPosition = 2763;
+const xml_token_t XML_sheetPr = 2764;
+const xml_token_t XML_sheetProtection = 2765;
+const xml_token_t XML_sheetView = 2766;
+const xml_token_t XML_sheetViews = 2767;
+const xml_token_t XML_sheets = 2768;
+const xml_token_t XML_shininess = 2769;
+const xml_token_t XML_shortcutKey = 2770;
+const xml_token_t XML_show = 2771;
+const xml_token_t XML_showAll = 2772;
+const xml_token_t XML_showAnimation = 2773;
+const xml_token_t XML_showAsCaption = 2774;
+const xml_token_t XML_showAsIcon = 2775;
+const xml_token_t XML_showAutoFilter = 2776;
+const xml_token_t XML_showBorderUnselectedTables = 2777;
+const xml_token_t XML_showBreaksInFrames = 2778;
+const xml_token_t XML_showBubbleSize = 2779;
+const xml_token_t XML_showButton = 2780;
+const xml_token_t XML_showCalcMbrs = 2781;
+const xml_token_t XML_showCaptions = 2782;
+const xml_token_t XML_showCatName = 2783;
+const xml_token_t XML_showCell = 2784;
+const xml_token_t XML_showColHeaders = 2785;
+const xml_token_t XML_showColStripes = 2786;
+const xml_token_t XML_showColumnStripes = 2787;
+const xml_token_t XML_showComments = 2788;
+const xml_token_t XML_showDLblsOverMax = 2789;
+const xml_token_t XML_showDataAs = 2790;
+const xml_token_t XML_showDataDropDown = 2791;
+const xml_token_t XML_showDataTips = 2792;
+const xml_token_t XML_showDrill = 2793;
+const xml_token_t XML_showDropDown = 2794;
+const xml_token_t XML_showDropDowns = 2795;
+const xml_token_t XML_showDropZones = 2796;
+const xml_token_t XML_showEmptyCol = 2797;
+const xml_token_t XML_showEmptyRow = 2798;
+const xml_token_t XML_showEnvelope = 2799;
+const xml_token_t XML_showError = 2800;
+const xml_token_t XML_showErrorMessage = 2801;
+const xml_token_t XML_showFirstColumn = 2802;
+const xml_token_t XML_showFormatting = 2803;
+const xml_token_t XML_showFormulaBar = 2804;
+const xml_token_t XML_showFormulas = 2805;
+const xml_token_t XML_showGridLines = 2806;
+const xml_token_t XML_showGuides = 2807;
+const xml_token_t XML_showHeader = 2808;
+const xml_token_t XML_showHeaders = 2809;
+const xml_token_t XML_showHorizontalScroll = 2810;
+const xml_token_t XML_showHorzBorder = 2811;
+const xml_token_t XML_showInFieldList = 2812;
+const xml_token_t XML_showInkAnnotation = 2813;
+const xml_token_t XML_showInputMessage = 2814;
+const xml_token_t XML_showItems = 2815;
+const xml_token_t XML_showKeys = 2816;
+const xml_token_t XML_showLastColumn = 2817;
+const xml_token_t XML_showLeaderLines = 2818;
+const xml_token_t XML_showLegendKey = 2819;
+const xml_token_t XML_showMasterPhAnim = 2820;
+const xml_token_t XML_showMasterSp = 2821;
+const xml_token_t XML_showMemberPropertyTips = 2822;
+const xml_token_t XML_showMissing = 2823;
+const xml_token_t XML_showMultipleLabel = 2824;
+const xml_token_t XML_showNarration = 2825;
+const xml_token_t XML_showNegBubbles = 2826;
+const xml_token_t XML_showObjects = 2827;
+const xml_token_t XML_showOutline = 2828;
+const xml_token_t XML_showOutlineIcons = 2829;
+const xml_token_t XML_showOutlineSymbols = 2830;
+const xml_token_t XML_showPageBreaks = 2831;
+const xml_token_t XML_showPercent = 2832;
+const xml_token_t XML_showPivotChartFilter = 2833;
+const xml_token_t XML_showPr = 2834;
+const xml_token_t XML_showPropAsCaption = 2835;
+const xml_token_t XML_showPropCell = 2836;
+const xml_token_t XML_showPropTip = 2837;
+const xml_token_t XML_showRowCol = 2838;
+const xml_token_t XML_showRowColHeaders = 2839;
+const xml_token_t XML_showRowHeaders = 2840;
+const xml_token_t XML_showRowStripes = 2841;
+const xml_token_t XML_showRuler = 2842;
+const xml_token_t XML_showScrollbar = 2843;
+const xml_token_t XML_showSerName = 2844;
+const xml_token_t XML_showSheetTabs = 2845;
+const xml_token_t XML_showSpeakerNotes = 2846;
+const xml_token_t XML_showSpecialPlsOnTitleSld = 2847;
+const xml_token_t XML_showStatusbar = 2848;
+const xml_token_t XML_showTip = 2849;
+const xml_token_t XML_showVal = 2850;
+const xml_token_t XML_showValue = 2851;
+const xml_token_t XML_showVertBorder = 2852;
+const xml_token_t XML_showVerticalScroll = 2853;
+const xml_token_t XML_showWhenStopped = 2854;
+const xml_token_t XML_showWhiteSpace = 2855;
+const xml_token_t XML_showXMLTags = 2856;
+const xml_token_t XML_showZeros = 2857;
+const xml_token_t XML_showingPlcHdr = 2858;
+const xml_token_t XML_showsigndate = 2859;
+const xml_token_t XML_shp = 2860;
+const xml_token_t XML_shrinkToFit = 2861;
+const xml_token_t XML_si = 2862;
+const xml_token_t XML_sibTransId = 2863;
+const xml_token_t XML_side = 2864;
+const xml_token_t XML_sideWall = 2865;
+const xml_token_t XML_sig = 2866;
+const xml_token_t XML_signatureline = 2867;
+const xml_token_t XML_signinginstructions = 2868;
+const xml_token_t XML_signinginstructionsset = 2869;
+const xml_token_t XML_sigprovurl = 2870;
+const xml_token_t XML_simplePos = 2871;
+const xml_token_t XML_singleSignOnId = 2872;
+const xml_token_t XML_singleXmlCell = 2873;
+const xml_token_t XML_singleXmlCells = 2874;
+const xml_token_t XML_singleclick = 2875;
+const xml_token_t XML_size = 2876;
+const xml_token_t XML_sizeAuto = 2877;
+const xml_token_t XML_sizeRepresents = 2878;
+const xml_token_t XML_skew = 2879;
+const xml_token_t XML_skewamt = 2880;
+const xml_token_t XML_skewangle = 2881;
+const xml_token_t XML_sld = 2882;
+const xml_token_t XML_sldAll = 2883;
+const xml_token_t XML_sldId = 2884;
+const xml_token_t XML_sldIdLst = 2885;
+const xml_token_t XML_sldLayout = 2886;
+const xml_token_t XML_sldLayoutId = 2887;
+const xml_token_t XML_sldLayoutIdLst = 2888;
+const xml_token_t XML_sldLst = 2889;
+const xml_token_t XML_sldMaster = 2890;
+const xml_token_t XML_sldMasterId = 2891;
+const xml_token_t XML_sldMasterIdLst = 2892;
+const xml_token_t XML_sldNum = 2893;
+const xml_token_t XML_sldRg = 2894;
+const xml_token_t XML_sldSyncPr = 2895;
+const xml_token_t XML_sldSz = 2896;
+const xml_token_t XML_sldTgt = 2897;
+const xml_token_t XML_slideViewPr = 2898;
+const xml_token_t XML_smallCaps = 2899;
+const xml_token_t XML_smallFrac = 2900;
+const xml_token_t XML_smartTag = 2901;
+const xml_token_t XML_smartTagPr = 2902;
+const xml_token_t XML_smartTagType = 2903;
+const xml_token_t XML_smartTagTypes = 2904;
+const xml_token_t XML_smartTags = 2905;
+const xml_token_t XML_smooth = 2906;
+const xml_token_t XML_smtClean = 2907;
+const xml_token_t XML_smtId = 2908;
+const xml_token_t XML_snapToGrid = 2909;
+const xml_token_t XML_snapToObjects = 2910;
+const xml_token_t XML_snapVertSplitter = 2911;
+const xml_token_t XML_snd = 2912;
+const xml_token_t XML_sndAc = 2913;
+const xml_token_t XML_sndTgt = 2914;
+const xml_token_t XML_softEdge = 2915;
+const xml_token_t XML_softHyphen = 2916;
+const xml_token_t XML_solidFill = 2917;
+const xml_token_t XML_solutionID = 2918;
+const xml_token_t XML_solveOrder = 2919;
+const xml_token_t XML_sort = 2920;
+const xml_token_t XML_sortBy = 2921;
+const xml_token_t XML_sortByTuple = 2922;
+const xml_token_t XML_sortCondition = 2923;
+const xml_token_t XML_sortMethod = 2924;
+const xml_token_t XML_sortState = 2925;
+const xml_token_t XML_sortType = 2926;
+const xml_token_t XML_sorterViewPr = 2927;
+const xml_token_t XML_source = 2928;
+const xml_token_t XML_sourceData = 2929;
+const xml_token_t XML_sourceFile = 2930;
+const xml_token_t XML_sourceFileName = 2931;
+const xml_token_t XML_sourceLinked = 2932;
+const xml_token_t XML_sourceObject = 2933;
+const xml_token_t XML_sourceRef = 2934;
+const xml_token_t XML_sourceSheetId = 2935;
+const xml_token_t XML_sourceType = 2936;
+const xml_token_t XML_sp = 2937;
+const xml_token_t XML_sp3d = 2938;
+const xml_token_t XML_spAutoFit = 2939;
+const xml_token_t XML_spDef = 2940;
+const xml_token_t XML_spLocks = 2941;
+const xml_token_t XML_spPr = 2942;
+const xml_token_t XML_spTgt = 2943;
+const xml_token_t XML_spTree = 2944;
+const xml_token_t XML_space = 2945;
+const xml_token_t XML_spaceForUL = 2946;
+const xml_token_t XML_spacing = 2947;
+const xml_token_t XML_spacingInWholePoints = 2948;
+const xml_token_t XML_spans = 2949;
+const xml_token_t XML_spc = 2950;
+const xml_token_t XML_spcAft = 2951;
+const xml_token_t XML_spcBef = 2952;
+const xml_token_t XML_spcCol = 2953;
+const xml_token_t XML_spcFirstLastPara = 2954;
+const xml_token_t XML_spcPct = 2955;
+const xml_token_t XML_spcPts = 2956;
+const xml_token_t XML_spd = 2957;
+const xml_token_t XML_specVanish = 2958;
+const xml_token_t XML_specularity = 2959;
+const xml_token_t XML_spelling = 2960;
+const xml_token_t XML_spid = 2961;
+const xml_token_t XML_spidmax = 2962;
+const xml_token_t XML_spinCount = 2963;
+const xml_token_t XML_split = 2964;
+const xml_token_t XML_splitAll = 2965;
+const xml_token_t XML_splitFirst = 2966;
+const xml_token_t XML_splitPgBreakAndParaMark = 2967;
+const xml_token_t XML_splitPos = 2968;
+const xml_token_t XML_splitType = 2969;
+const xml_token_t XML_spokes = 2970;
+const xml_token_t XML_spt = 2971;
+const xml_token_t XML_sqlType = 2972;
+const xml_token_t XML_sqref = 2973;
+const xml_token_t XML_src = 2974;
+const xml_token_t XML_srcId = 2975;
+const xml_token_t XML_srcOrd = 2976;
+const xml_token_t XML_srcRect = 2977;
+const xml_token_t XML_srgbClr = 2978;
+const xml_token_t XML_sst = 2979;
+const xml_token_t XML_st = 2980;
+const xml_token_t XML_stA = 2981;
+const xml_token_t XML_stAng = 2982;
+const xml_token_t XML_stCondLst = 2983;
+const xml_token_t XML_stCxn = 2984;
+const xml_token_t XML_stPos = 2985;
+const xml_token_t XML_stSnd = 2986;
+const xml_token_t XML_start = 2987;
+const xml_token_t XML_startAngle = 2988;
+const xml_token_t XML_startAt = 2989;
+const xml_token_t XML_startDate = 2990;
+const xml_token_t XML_startNum = 2991;
+const xml_token_t XML_startOverride = 2992;
+const xml_token_t XML_startarrow = 2993;
+const xml_token_t XML_startarrowlength = 2994;
+const xml_token_t XML_startarrowwidth = 2995;
+const xml_token_t XML_state = 2996;
+const xml_token_t XML_status = 2997;
+const xml_token_t XML_statusBar = 2998;
+const xml_token_t XML_statusText = 2999;
+const xml_token_t XML_stdDev = 3000;
+const xml_token_t XML_stdDevPSubtotal = 3001;
+const xml_token_t XML_stdDevSubtotal = 3002;
+const xml_token_t XML_step = 3003;
+const xml_token_t XML_stockChart = 3004;
+const xml_token_t XML_stop = 3005;
+const xml_token_t XML_stopIfTrue = 3006;
+const xml_token_t XML_storage = 3007;
+const xml_token_t XML_storeItemID = 3008;
+const xml_token_t XML_storeMappedDataAs = 3009;
+const xml_token_t XML_stp = 3010;
+const xml_token_t XML_strCache = 3011;
+const xml_token_t XML_strLit = 3012;
+const xml_token_t XML_strRef = 3013;
+const xml_token_t XML_strVal = 3014;
+const xml_token_t XML_stream = 3015;
+const xml_token_t XML_stretch = 3016;
+const xml_token_t XML_strictFirstAndLastChars = 3017;
+const xml_token_t XML_strike = 3018;
+const xml_token_t XML_strikeBLTR = 3019;
+const xml_token_t XML_strikeH = 3020;
+const xml_token_t XML_strikeTLBR = 3021;
+const xml_token_t XML_strikeV = 3022;
+const xml_token_t XML_string = 3023;
+const xml_token_t XML_stringValue1 = 3024;
+const xml_token_t XML_stringValue2 = 3025;
+const xml_token_t XML_strips = 3026;
+const xml_token_t XML_stroke = 3027;
+const xml_token_t XML_strokecolor = 3028;
+const xml_token_t XML_stroked = 3029;
+const xml_token_t XML_strokeok = 3030;
+const xml_token_t XML_strokeweight = 3031;
+const xml_token_t XML_sty = 3032;
+const xml_token_t XML_style = 3033;
+const xml_token_t XML_styleData = 3034;
+const xml_token_t XML_styleDef = 3035;
+const xml_token_t XML_styleDefHdr = 3036;
+const xml_token_t XML_styleDefHdrLst = 3037;
+const xml_token_t XML_styleId = 3038;
+const xml_token_t XML_styleLbl = 3039;
+const xml_token_t XML_styleLink = 3040;
+const xml_token_t XML_styleLockQFSet = 3041;
+const xml_token_t XML_styleLockTheme = 3042;
+const xml_token_t XML_styleName = 3043;
+const xml_token_t XML_stylePaneFormatFilter = 3044;
+const xml_token_t XML_stylePaneSortMethod = 3045;
+const xml_token_t XML_styleSheet = 3046;
+const xml_token_t XML_styles = 3047;
+const xml_token_t XML_sub = 3048;
+const xml_token_t XML_subDoc = 3049;
+const xml_token_t XML_subFontBySize = 3050;
+const xml_token_t XML_subHide = 3051;
+const xml_token_t XML_subSp = 3052;
+const xml_token_t XML_subTnLst = 3053;
+const xml_token_t XML_subsetted = 3054;
+const xml_token_t XML_subtotal = 3055;
+const xml_token_t XML_subtotalCaption = 3056;
+const xml_token_t XML_subtotalHiddenItems = 3057;
+const xml_token_t XML_subtotalTop = 3058;
+const xml_token_t XML_suff = 3059;
+const xml_token_t XML_suggestedsigner = 3060;
+const xml_token_t XML_suggestedsigner2 = 3061;
+const xml_token_t XML_suggestedsigneremail = 3062;
+const xml_token_t XML_sumSubtotal = 3063;
+const xml_token_t XML_summaryBelow = 3064;
+const xml_token_t XML_summaryLength = 3065;
+const xml_token_t XML_summaryRight = 3066;
+const xml_token_t XML_sup = 3067;
+const xml_token_t XML_supHide = 3068;
+const xml_token_t XML_supportAdvancedDrill = 3069;
+const xml_token_t XML_supportSubquery = 3070;
+const xml_token_t XML_suppressAutoHyphens = 3071;
+const xml_token_t XML_suppressBottomSpacing = 3072;
+const xml_token_t XML_suppressLineNumbers = 3073;
+const xml_token_t XML_suppressOverlap = 3074;
+const xml_token_t XML_suppressSpBfAfterPgBrk = 3075;
+const xml_token_t XML_suppressSpacingAtTopOfPage = 3076;
+const xml_token_t XML_suppressTopSpacing = 3077;
+const xml_token_t XML_suppressTopSpacingWP = 3078;
+const xml_token_t XML_surface3DChart = 3079;
+const xml_token_t XML_surfaceChart = 3080;
+const xml_token_t XML_swAng = 3081;
+const xml_token_t XML_swCell = 3082;
+const xml_token_t XML_swapBordersFacingPages = 3083;
+const xml_token_t XML_switch = 3084;
+const xml_token_t XML_sx = 3085;
+const xml_token_t XML_sy = 3086;
+const xml_token_t XML_sym = 3087;
+const xml_token_t XML_symbol = 3088;
+const xml_token_t XML_syncBehavior = 3089;
+const xml_token_t XML_syncHorizontal = 3090;
+const xml_token_t XML_syncRef = 3091;
+const xml_token_t XML_syncVertical = 3092;
+const xml_token_t XML_sysClr = 3093;
+const xml_token_t XML_sz = 3094;
+const xml_token_t XML_szCs = 3095;
+const xml_token_t XML_t = 3096;
+const xml_token_t XML_t1 = 3097;
+const xml_token_t XML_t2 = 3098;
+const xml_token_t XML_tIns = 3099;
+const xml_token_t XML_tab = 3100;
+const xml_token_t XML_tabColor = 3101;
+const xml_token_t XML_tabLst = 3102;
+const xml_token_t XML_tabRatio = 3103;
+const xml_token_t XML_tabSelected = 3104;
+const xml_token_t XML_table = 3105;
+const xml_token_t XML_tableBorderDxfId = 3106;
+const xml_token_t XML_tableColumn = 3107;
+const xml_token_t XML_tableColumnId = 3108;
+const xml_token_t XML_tableColumns = 3109;
+const xml_token_t XML_tablePart = 3110;
+const xml_token_t XML_tableParts = 3111;
+const xml_token_t XML_tableStyle = 3112;
+const xml_token_t XML_tableStyleElement = 3113;
+const xml_token_t XML_tableStyleId = 3114;
+const xml_token_t XML_tableStyleInfo = 3115;
+const xml_token_t XML_tableStyles = 3116;
+const xml_token_t XML_tableType = 3117;
+const xml_token_t XML_tablelimits = 3118;
+const xml_token_t XML_tableproperties = 3119;
+const xml_token_t XML_tables = 3120;
+const xml_token_t XML_tabs = 3121;
+const xml_token_t XML_tag = 3122;
+const xml_token_t XML_tagLst = 3123;
+const xml_token_t XML_tags = 3124;
+const xml_token_t XML_tailEnd = 3125;
+const xml_token_t XML_target = 3126;
+const xml_token_t XML_targetScreenSize = 3127;
+const xml_token_t XML_targetScreenSz = 3128;
+const xml_token_t XML_targetscreensize = 3129;
+const xml_token_t XML_tav = 3130;
+const xml_token_t XML_tavLst = 3131;
+const xml_token_t XML_tbl = 3132;
+const xml_token_t XML_tblBg = 3133;
+const xml_token_t XML_tblBorders = 3134;
+const xml_token_t XML_tblCellMar = 3135;
+const xml_token_t XML_tblCellSpacing = 3136;
+const xml_token_t XML_tblGrid = 3137;
+const xml_token_t XML_tblGridChange = 3138;
+const xml_token_t XML_tblHeader = 3139;
+const xml_token_t XML_tblInd = 3140;
+const xml_token_t XML_tblLayout = 3141;
+const xml_token_t XML_tblLook = 3142;
+const xml_token_t XML_tblOverlap = 3143;
+const xml_token_t XML_tblPr = 3144;
+const xml_token_t XML_tblPrChange = 3145;
+const xml_token_t XML_tblPrEx = 3146;
+const xml_token_t XML_tblPrExChange = 3147;
+const xml_token_t XML_tblStyle = 3148;
+const xml_token_t XML_tblStyleColBandSize = 3149;
+const xml_token_t XML_tblStyleLst = 3150;
+const xml_token_t XML_tblStylePr = 3151;
+const xml_token_t XML_tblStyleRowBandSize = 3152;
+const xml_token_t XML_tblW = 3153;
+const xml_token_t XML_tblpPr = 3154;
+const xml_token_t XML_tblpX = 3155;
+const xml_token_t XML_tblpXSpec = 3156;
+const xml_token_t XML_tblpY = 3157;
+const xml_token_t XML_tblpYSpec = 3158;
+const xml_token_t XML_tc = 3159;
+const xml_token_t XML_tcBdr = 3160;
+const xml_token_t XML_tcBorders = 3161;
+const xml_token_t XML_tcFitText = 3162;
+const xml_token_t XML_tcMar = 3163;
+const xml_token_t XML_tcPr = 3164;
+const xml_token_t XML_tcPrChange = 3165;
+const xml_token_t XML_tcStyle = 3166;
+const xml_token_t XML_tcTxStyle = 3167;
+const xml_token_t XML_tcW = 3168;
+const xml_token_t XML_temporary = 3169;
+const xml_token_t XML_tentative = 3170;
+const xml_token_t XML_text = 3171;
+const xml_token_t XML_textAlignment = 3172;
+const xml_token_t XML_textDates = 3173;
+const xml_token_t XML_textDirection = 3174;
+const xml_token_t XML_textField = 3175;
+const xml_token_t XML_textFields = 3176;
+const xml_token_t XML_textInput = 3177;
+const xml_token_t XML_textPr = 3178;
+const xml_token_t XML_textRotation = 3179;
+const xml_token_t XML_textborder = 3180;
+const xml_token_t XML_textbox = 3181;
+const xml_token_t XML_textboxTightWrap = 3182;
+const xml_token_t XML_textboxrect = 3183;
+const xml_token_t XML_textdata = 3184;
+const xml_token_t XML_textlink = 3185;
+const xml_token_t XML_textpath = 3186;
+const xml_token_t XML_textpathok = 3187;
+const xml_token_t XML_tgtEl = 3188;
+const xml_token_t XML_tgtFrame = 3189;
+const xml_token_t XML_theme = 3190;
+const xml_token_t XML_themeColor = 3191;
+const xml_token_t XML_themeElements = 3192;
+const xml_token_t XML_themeFill = 3193;
+const xml_token_t XML_themeFillShade = 3194;
+const xml_token_t XML_themeFillTint = 3195;
+const xml_token_t XML_themeFontLang = 3196;
+const xml_token_t XML_themeManager = 3197;
+const xml_token_t XML_themeOverride = 3198;
+const xml_token_t XML_themeShade = 3199;
+const xml_token_t XML_themeTint = 3200;
+const xml_token_t XML_thickBot = 3201;
+const xml_token_t XML_thickBottom = 3202;
+const xml_token_t XML_thickTop = 3203;
+const xml_token_t XML_thicket = 3204;
+const xml_token_t XML_thickness = 3205;
+const xml_token_t XML_thousands = 3206;
+const xml_token_t XML_thresh = 3207;
+const xml_token_t XML_thruBlk = 3208;
+const xml_token_t XML_tickLblPos = 3209;
+const xml_token_t XML_tickLblSkip = 3210;
+const xml_token_t XML_tickMarkSkip = 3211;
+const xml_token_t XML_tile = 3212;
+const xml_token_t XML_tileRect = 3213;
+const xml_token_t XML_time = 3214;
+const xml_token_t XML_timePeriod = 3215;
+const xml_token_t XML_timing = 3216;
+const xml_token_t XML_tint = 3217;
+const xml_token_t XML_title = 3218;
+const xml_token_t XML_titlePg = 3219;
+const xml_token_t XML_titleStyle = 3220;
+const xml_token_t XML_tl2br = 3221;
+const xml_token_t XML_tm = 3222;
+const xml_token_t XML_tmAbs = 3223;
+const xml_token_t XML_tmFilter = 3224;
+const xml_token_t XML_tmPct = 3225;
+const xml_token_t XML_tmpl = 3226;
+const xml_token_t XML_tmplLst = 3227;
+const xml_token_t XML_tn = 3228;
+const xml_token_t XML_tnLst = 3229;
+const xml_token_t XML_to = 3230;
+const xml_token_t XML_tooltip = 3231;
+const xml_token_t XML_top = 3232;
+const xml_token_t XML_top10 = 3233;
+const xml_token_t XML_topAutoShow = 3234;
+const xml_token_t XML_topFromText = 3235;
+const xml_token_t XML_topLabels = 3236;
+const xml_token_t XML_topLeftCell = 3237;
+const xml_token_t XML_topLinePunct = 3238;
+const xml_token_t XML_totalsRowBorderDxfId = 3239;
+const xml_token_t XML_totalsRowCellStyle = 3240;
+const xml_token_t XML_totalsRowCount = 3241;
+const xml_token_t XML_totalsRowDxfId = 3242;
+const xml_token_t XML_totalsRowFormula = 3243;
+const xml_token_t XML_totalsRowFunction = 3244;
+const xml_token_t XML_totalsRowLabel = 3245;
+const xml_token_t XML_totalsRowShown = 3246;
+const xml_token_t XML_tp = 3247;
+const xml_token_t XML_tpl = 3248;
+const xml_token_t XML_tplc = 3249;
+const xml_token_t XML_tpls = 3250;
+const xml_token_t XML_tr = 3251;
+const xml_token_t XML_tr2bl = 3252;
+const xml_token_t XML_trHeight = 3253;
+const xml_token_t XML_trPr = 3254;
+const xml_token_t XML_trPrChange = 3255;
+const xml_token_t XML_track = 3256;
+const xml_token_t XML_trackRevisions = 3257;
+const xml_token_t XML_transition = 3258;
+const xml_token_t XML_transitionEntry = 3259;
+const xml_token_t XML_transitionEvaluation = 3260;
+const xml_token_t XML_transp = 3261;
+const xml_token_t XML_trend = 3262;
+const xml_token_t XML_trendline = 3263;
+const xml_token_t XML_trendlineLbl = 3264;
+const xml_token_t XML_trendlineType = 3265;
+const xml_token_t XML_trim = 3266;
+const xml_token_t XML_truncateFontHeightsLikeWP6 = 3267;
+const xml_token_t XML_tupleCache = 3268;
+const xml_token_t XML_twoCellAnchor = 3269;
+const xml_token_t XML_twoDigitTextYear = 3270;
+const xml_token_t XML_tx = 3271;
+const xml_token_t XML_tx1 = 3272;
+const xml_token_t XML_tx2 = 3273;
+const xml_token_t XML_txBody = 3274;
+const xml_token_t XML_txBox = 3275;
+const xml_token_t XML_txDef = 3276;
+const xml_token_t XML_txEffectClrLst = 3277;
+const xml_token_t XML_txEl = 3278;
+const xml_token_t XML_txFillClrLst = 3279;
+const xml_token_t XML_txLinClrLst = 3280;
+const xml_token_t XML_txPr = 3281;
+const xml_token_t XML_txSp = 3282;
+const xml_token_t XML_txStyles = 3283;
+const xml_token_t XML_txbxContent = 3284;
+const xml_token_t XML_ty = 3285;
+const xml_token_t XML_type = 3286;
+const xml_token_t XML_typeface = 3287;
+const xml_token_t XML_types = 3288;
+const xml_token_t XML_u = 3289;
+const xml_token_t XML_uBounds = 3290;
+const xml_token_t XML_uFill = 3291;
+const xml_token_t XML_uFillTx = 3292;
+const xml_token_t XML_uLn = 3293;
+const xml_token_t XML_uLnTx = 3294;
+const xml_token_t XML_ua = 3295;
+const xml_token_t XML_udl = 3296;
+const xml_token_t XML_ui1 = 3297;
+const xml_token_t XML_ui2 = 3298;
+const xml_token_t XML_ui4 = 3299;
+const xml_token_t XML_ui8 = 3300;
+const xml_token_t XML_uiCompat97To2003 = 3301;
+const xml_token_t XML_uiExpand = 3302;
+const xml_token_t XML_uiPriority = 3303;
+const xml_token_t XML_uint = 3304;
+const xml_token_t XML_ulTrailSpace = 3305;
+const xml_token_t XML_un = 3306;
+const xml_token_t XML_unbalanced = 3307;
+const xml_token_t XML_unbalancedGroup = 3308;
+const xml_token_t XML_unboundColumnsLeft = 3309;
+const xml_token_t XML_unboundColumnsRight = 3310;
+const xml_token_t XML_underlineTabInNumList = 3311;
+const xml_token_t XML_undo = 3312;
+const xml_token_t XML_undone = 3313;
+const xml_token_t XML_ungrouping = 3314;
+const xml_token_t XML_unhideWhenUsed = 3315;
+const xml_token_t XML_uniqueCount = 3316;
+const xml_token_t XML_uniqueId = 3317;
+const xml_token_t XML_uniqueList = 3318;
+const xml_token_t XML_uniqueMemberProperty = 3319;
+const xml_token_t XML_uniqueName = 3320;
+const xml_token_t XML_uniqueParent = 3321;
+const xml_token_t XML_uniqueTag = 3322;
+const xml_token_t XML_unlockedFormula = 3323;
+const xml_token_t XML_up = 3324;
+const xml_token_t XML_upBars = 3325;
+const xml_token_t XML_upDownBars = 3326;
+const xml_token_t XML_updateAutomatic = 3327;
+const xml_token_t XML_updateFields = 3328;
+const xml_token_t XML_updateLinks = 3329;
+const xml_token_t XML_updatedVersion = 3330;
+const xml_token_t XML_upgradeOnRefresh = 3331;
+const xml_token_t XML_upright = 3332;
+const xml_token_t XML_uri = 3333;
+const xml_token_t XML_url = 3334;
+const xml_token_t XML_usb0 = 3335;
+const xml_token_t XML_usb1 = 3336;
+const xml_token_t XML_usb2 = 3337;
+const xml_token_t XML_usb3 = 3338;
+const xml_token_t XML_useA = 3339;
+const xml_token_t XML_useAltKinsokuLineBreakRules = 3340;
+const xml_token_t XML_useAnsiKerningPairs = 3341;
+const xml_token_t XML_useAutoFormatting = 3342;
+const xml_token_t XML_useBgFill = 3343;
+const xml_token_t XML_useDef = 3344;
+const xml_token_t XML_useFELayout = 3345;
+const xml_token_t XML_useFirstPageNumber = 3346;
+const xml_token_t XML_useLongFilenames = 3347;
+const xml_token_t XML_useNormalStyleForList = 3348;
+const xml_token_t XML_usePrinterDefaults = 3349;
+const xml_token_t XML_usePrinterMetrics = 3350;
+const xml_token_t XML_useSingleBorderforContiguousCells = 3351;
+const xml_token_t XML_useSpRect = 3352;
+const xml_token_t XML_useTimings = 3353;
+const xml_token_t XML_useWord2002TableStyleRules = 3354;
+const xml_token_t XML_useWord97LineBreakRules = 3355;
+const xml_token_t XML_useXSLTWhenSaving = 3356;
+const xml_token_t XML_user = 3357;
+const xml_token_t XML_userDrawn = 3358;
+const xml_token_t XML_userInfo = 3359;
+const xml_token_t XML_userInterface = 3360;
+const xml_token_t XML_userName = 3361;
+const xml_token_t XML_userShapes = 3362;
+const xml_token_t XML_userdrawn = 3363;
+const xml_token_t XML_userhidden = 3364;
+const xml_token_t XML_users = 3365;
+const xml_token_t XML_v = 3366;
+const xml_token_t XML_vAlign = 3367;
+const xml_token_t XML_vAnchor = 3368;
+const xml_token_t XML_vMerge = 3369;
+const xml_token_t XML_vMergeOrig = 3370;
+const xml_token_t XML_vSpace = 3371;
+const xml_token_t XML_vacatedStyle = 3372;
+const xml_token_t XML_val = 3373;
+const xml_token_t XML_valAx = 3374;
+const xml_token_t XML_value = 3375;
+const xml_token_t XML_valueMetadata = 3376;
+const xml_token_t XML_valueType = 3377;
+const xml_token_t XML_values = 3378;
+const xml_token_t XML_vanish = 3379;
+const xml_token_t XML_varLst = 3380;
+const xml_token_t XML_varPSubtotal = 3381;
+const xml_token_t XML_varScale = 3382;
+const xml_token_t XML_varSubtotal = 3383;
+const xml_token_t XML_variant = 3384;
+const xml_token_t XML_varyColors = 3385;
+const xml_token_t XML_vbProcedure = 3386;
+const xml_token_t XML_vector = 3387;
+const xml_token_t XML_vendorID = 3388;
+const xml_token_t XML_version = 3389;
+const xml_token_t XML_vert = 3390;
+const xml_token_t XML_vertAlign = 3391;
+const xml_token_t XML_vertAnchor = 3392;
+const xml_token_t XML_vertBarState = 3393;
+const xml_token_t XML_vertCompress = 3394;
+const xml_token_t XML_vertJc = 3395;
+const xml_token_t XML_vertOverflow = 3396;
+const xml_token_t XML_vertical = 3397;
+const xml_token_t XML_verticalCentered = 3398;
+const xml_token_t XML_verticalDpi = 3399;
+const xml_token_t XML_verticies = 3400;
+const xml_token_t XML_video = 3401;
+const xml_token_t XML_videoFile = 3402;
+const xml_token_t XML_view = 3403;
+const xml_token_t XML_view3D = 3404;
+const xml_token_t XML_viewMergedData = 3405;
+const xml_token_t XML_viewPr = 3406;
+const xml_token_t XML_viewpoint = 3407;
+const xml_token_t XML_viewpointorigin = 3408;
+const xml_token_t XML_visibility = 3409;
+const xml_token_t XML_visualTotals = 3410;
+const xml_token_t XML_vm = 3411;
+const xml_token_t XML_vml = 3412;
+const xml_token_t XML_vocabulary = 3413;
+const xml_token_t XML_vol = 3414;
+const xml_token_t XML_volType = 3415;
+const xml_token_t XML_volTypes = 3416;
+const xml_token_t XML_vstream = 3417;
+const xml_token_t XML_w = 3418;
+const xml_token_t XML_wAfter = 3419;
+const xml_token_t XML_wBefore = 3420;
+const xml_token_t XML_wMode = 3421;
+const xml_token_t XML_wR = 3422;
+const xml_token_t XML_wavAudioFile = 3423;
+const xml_token_t XML_webHidden = 3424;
+const xml_token_t XML_webPr = 3425;
+const xml_token_t XML_webPublishItem = 3426;
+const xml_token_t XML_webPublishItems = 3427;
+const xml_token_t XML_webPublishObject = 3428;
+const xml_token_t XML_webPublishObjects = 3429;
+const xml_token_t XML_webPublishing = 3430;
+const xml_token_t XML_webSettings = 3431;
+const xml_token_t XML_wedge = 3432;
+const xml_token_t XML_weight = 3433;
+const xml_token_t XML_wheel = 3434;
+const xml_token_t XML_whole = 3435;
+const xml_token_t XML_wholeTbl = 3436;
+const xml_token_t XML_widowControl = 3437;
+const xml_token_t XML_width = 3438;
+const xml_token_t XML_windowHeight = 3439;
+const xml_token_t XML_windowProtection = 3440;
+const xml_token_t XML_windowWidth = 3441;
+const xml_token_t XML_wipe = 3442;
+const xml_token_t XML_wireframe = 3443;
+const xml_token_t XML_wordWrap = 3444;
+const xml_token_t XML_workbook = 3445;
+const xml_token_t XML_workbookParameter = 3446;
+const xml_token_t XML_workbookPassword = 3447;
+const xml_token_t XML_workbookPr = 3448;
+const xml_token_t XML_workbookProtection = 3449;
+const xml_token_t XML_workbookView = 3450;
+const xml_token_t XML_workbookViewId = 3451;
+const xml_token_t XML_worksheet = 3452;
+const xml_token_t XML_worksheetSource = 3453;
+const xml_token_t XML_wpJustification = 3454;
+const xml_token_t XML_wpSpaceWidth = 3455;
+const xml_token_t XML_wrap = 3456;
+const xml_token_t XML_wrapIndent = 3457;
+const xml_token_t XML_wrapNone = 3458;
+const xml_token_t XML_wrapPolygon = 3459;
+const xml_token_t XML_wrapRight = 3460;
+const xml_token_t XML_wrapSquare = 3461;
+const xml_token_t XML_wrapText = 3462;
+const xml_token_t XML_wrapThrough = 3463;
+const xml_token_t XML_wrapTight = 3464;
+const xml_token_t XML_wrapTopAndBottom = 3465;
+const xml_token_t XML_wrapTrailSpaces = 3466;
+const xml_token_t XML_wrapcoords = 3467;
+const xml_token_t XML_writeProtection = 3468;
+const xml_token_t XML_wsDr = 3469;
+const xml_token_t XML_x = 3470;
+const xml_token_t XML_xAlign = 3471;
+const xml_token_t XML_xMode = 3472;
+const xml_token_t XML_xSplit = 3473;
+const xml_token_t XML_xVal = 3474;
+const xml_token_t XML_xWindow = 3475;
+const xml_token_t XML_xf = 3476;
+const xml_token_t XML_xfDxf = 3477;
+const xml_token_t XML_xfId = 3478;
+const xml_token_t XML_xfrm = 3479;
+const xml_token_t XML_xfrmType = 3480;
+const xml_token_t XML_xl2000 = 3481;
+const xml_token_t XML_xl97 = 3482;
+const xml_token_t XML_xlm = 3483;
+const xml_token_t XML_xml = 3484;
+const xml_token_t XML_xmlBased = 3485;
+const xml_token_t XML_xmlCellPr = 3486;
+const xml_token_t XML_xmlColumnPr = 3487;
+const xml_token_t XML_xmlDataType = 3488;
+const xml_token_t XML_xmlPr = 3489;
+const xml_token_t XML_xpath = 3490;
+const xml_token_t XML_xrange = 3491;
+const xml_token_t XML_xscale = 3492;
+const xml_token_t XML_y = 3493;
+const xml_token_t XML_yAlign = 3494;
+const xml_token_t XML_yMode = 3495;
+const xml_token_t XML_ySplit = 3496;
+const xml_token_t XML_yVal = 3497;
+const xml_token_t XML_yWindow = 3498;
+const xml_token_t XML_year = 3499;
+const xml_token_t XML_yearLong = 3500;
+const xml_token_t XML_yearShort = 3501;
+const xml_token_t XML_yrange = 3502;
+const xml_token_t XML_z = 3503;
+const xml_token_t XML_zOrder = 3504;
+const xml_token_t XML_zOrderOff = 3505;
+const xml_token_t XML_zeroAsc = 3506;
+const xml_token_t XML_zeroDesc = 3507;
+const xml_token_t XML_zeroHeight = 3508;
+const xml_token_t XML_zeroValues = 3509;
+const xml_token_t XML_zeroWid = 3510;
+const xml_token_t XML_zoom = 3511;
+const xml_token_t XML_zoomContents = 3512;
+const xml_token_t XML_zoomScale = 3513;
+const xml_token_t XML_zoomScaleNormal = 3514;
+const xml_token_t XML_zoomScalePageLayoutView = 3515;
+const xml_token_t XML_zoomScaleSheetLayoutView = 3516;
+const xml_token_t XML_zoomToFit = 3517;
diff --git a/src/liborcus/ooxml_tokens.cpp b/src/liborcus/ooxml_tokens.cpp
new file mode 100644
index 0000000..f73a06c
--- /dev/null
+++ b/src/liborcus/ooxml_tokens.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ooxml_tokens.hpp"
+
+namespace orcus {
+
+namespace ooxml {
+
+#include "ooxml_tokens.inl"
+
+}
+
+namespace opc {
+
+#include "opc_tokens.inl"
+
+}
+
+tokens ooxml_tokens = tokens(ooxml::token_names, ooxml::token_name_count);
+
+tokens opc_tokens = tokens(opc::token_names, opc::token_name_count);
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_tokens.hpp b/src/liborcus/ooxml_tokens.hpp
new file mode 100644
index 0000000..3e8380b
--- /dev/null
+++ b/src/liborcus/ooxml_tokens.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_OOXML_TOKENS_HPP__
+#define __ORCUS_OOXML_TOKENS_HPP__
+
+#include "orcus/tokens.hpp"
+
+namespace orcus {
+
+extern tokens ooxml_tokens;
+extern tokens opc_tokens;
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_tokens.inl b/src/liborcus/ooxml_tokens.inl
new file mode 100644
index 0000000..5fa2ad0
--- /dev/null
+++ b/src/liborcus/ooxml_tokens.inl
@@ -0,0 +1,3524 @@
+// This file has been auto-generated. Do not hand-edit this.
+
+const char* token_names[] = {
+ "??", // 0
+ "AbbreviatedCaseNumber", // 1
+ "Accel", // 2
+ "Accel2", // 3
+ "AlbumTitle", // 4
+ "AlternateContent", // 5
+ "Anchor", // 6
+ "AppVersion", // 7
+ "Append", // 8
+ "Application", // 9
+ "Artist", // 10
+ "Author", // 11
+ "AutoFill", // 12
+ "AutoFit", // 13
+ "AutoLine", // 14
+ "AutoPict", // 15
+ "AutoScale", // 16
+ "BookAuthor", // 17
+ "BookTitle", // 18
+ "BroadcastTitle", // 19
+ "Broadcaster", // 20
+ "CF", // 21
+ "Camera", // 22
+ "Cancel", // 23
+ "CaseNumber", // 24
+ "ChapterNumber", // 25
+ "Characters", // 26
+ "CharactersWithSpaces", // 27
+ "Checked", // 28
+ "Choice", // 29
+ "City", // 30
+ "ClientData", // 31
+ "ColHidden", // 32
+ "Colored", // 33
+ "Column", // 34
+ "Comments", // 35
+ "Company", // 36
+ "Compiler", // 37
+ "Composer", // 38
+ "Conductor", // 39
+ "ConferenceName", // 40
+ "ConnectionID", // 41
+ "Corporate", // 42
+ "Counsel", // 43
+ "CountryRegion", // 44
+ "Court", // 45
+ "DDE", // 46
+ "DataBinding", // 47
+ "DataBindingLoadMode", // 48
+ "DataBindingName", // 49
+ "Day", // 50
+ "DayAccessed", // 51
+ "Default", // 52
+ "DefaultSize", // 53
+ "Department", // 54
+ "DigSig", // 55
+ "Director", // 56
+ "Disabled", // 57
+ "Dismiss", // 58
+ "Distributor", // 59
+ "DocSecurity", // 60
+ "DrawAspect", // 61
+ "DropLines", // 62
+ "DropStyle", // 63
+ "Dx", // 64
+ "Edition", // 65
+ "Editor", // 66
+ "Fallback", // 67
+ "FieldCodes", // 68
+ "FileBinding", // 69
+ "FileBindingName", // 70
+ "First", // 71
+ "FirstButton", // 72
+ "FmlaGroup", // 73
+ "FmlaLink", // 74
+ "FmlaMacro", // 75
+ "FmlaPict", // 76
+ "FmlaRange", // 77
+ "FmlaTxbx", // 78
+ "Guid", // 79
+ "HLinks", // 80
+ "HeadingPairs", // 81
+ "Help", // 82
+ "HiddenSlides", // 83
+ "Horiz", // 84
+ "HyperlinkBase", // 85
+ "HyperlinksChanged", // 86
+ "ID", // 87
+ "Inc", // 88
+ "Institution", // 89
+ "InternetSiteTitle", // 90
+ "Interviewee", // 91
+ "Interviewer", // 92
+ "Inventor", // 93
+ "Issue", // 94
+ "JournalName", // 95
+ "JustLastX", // 96
+ "LCID", // 97
+ "LCT", // 98
+ "Last", // 99
+ "Lines", // 100
+ "LinkType", // 101
+ "LinksUpToDate", // 102
+ "ListItem", // 103
+ "LockText", // 104
+ "Locked", // 105
+ "LockedField", // 106
+ "MMClips", // 107
+ "Manager", // 108
+ "Map", // 109
+ "MapInfo", // 110
+ "MapOCX", // 111
+ "Max", // 112
+ "Medium", // 113
+ "Middle", // 114
+ "Min", // 115
+ "Month", // 116
+ "MonthAccessed", // 117
+ "MoveWithCells", // 118
+ "MultiLine", // 119
+ "MultiSel", // 120
+ "Name", // 121
+ "NameList", // 122
+ "Namespace", // 123
+ "NoThreeD", // 124
+ "NoThreeD2", // 125
+ "Notes", // 126
+ "NumberVolumes", // 127
+ "OLEObject", // 128
+ "ObjectID", // 129
+ "ObjectType", // 130
+ "Page", // 131
+ "Pages", // 132
+ "Paragraphs", // 133
+ "PatentNumber", // 134
+ "Performer", // 135
+ "PeriodicalTitle", // 136
+ "Person", // 137
+ "PresentationFormat", // 138
+ "PreserveFormat", // 139
+ "PreserveSortAFLayout", // 140
+ "PrintObject", // 141
+ "ProducerName", // 142
+ "ProductionCompany", // 143
+ "ProgID", // 144
+ "Properties", // 145
+ "PublicationTitle", // 146
+ "Publisher", // 147
+ "RecalcAlways", // 148
+ "RecordingNumber", // 149
+ "RefOrder", // 150
+ "Reporter", // 151
+ "RootElement", // 152
+ "Row", // 153
+ "RowHidden", // 154
+ "ScaleCrop", // 155
+ "Schema", // 156
+ "SchemaID", // 157
+ "SchemaRef", // 158
+ "ScriptExtended", // 159
+ "ScriptLanguage", // 160
+ "ScriptLocation", // 161
+ "ScriptText", // 162
+ "SecretEdit", // 163
+ "Sel", // 164
+ "SelType", // 165
+ "SelectedStyle", // 166
+ "SelectionNamespaces", // 167
+ "ShapeID", // 168
+ "SharedDoc", // 169
+ "ShortTitle", // 170
+ "ShowImportExportValidationErrors", // 171
+ "SizeWithCells", // 172
+ "Slides", // 173
+ "Source", // 174
+ "SourceType", // 175
+ "Sources", // 176
+ "StandardNumber", // 177
+ "StateProvince", // 178
+ "Station", // 179
+ "StyleName", // 180
+ "Tag", // 181
+ "Template", // 182
+ "TextHAlign", // 183
+ "TextVAlign", // 184
+ "Theater", // 185
+ "ThesisType", // 186
+ "Title", // 187
+ "TitlesOfParts", // 188
+ "TotalTime", // 189
+ "Translator", // 190
+ "Type", // 191
+ "UIObj", // 192
+ "URI", // 193
+ "URL", // 194
+ "UpdateMode", // 195
+ "VScroll", // 196
+ "VTEdit", // 197
+ "Val", // 198
+ "ValidIds", // 199
+ "Version", // 200
+ "Visible", // 201
+ "Volume", // 202
+ "WidthMin", // 203
+ "Words", // 204
+ "Writer", // 205
+ "Year", // 206
+ "YearAccessed", // 207
+ "a", // 208
+ "aboveAverage", // 209
+ "absSizeAnchor", // 210
+ "absoluteAnchor", // 211
+ "abstractNum", // 212
+ "abstractNumId", // 213
+ "aca", // 214
+ "acc", // 215
+ "accPr", // 216
+ "accel", // 217
+ "accent1", // 218
+ "accent2", // 219
+ "accent3", // 220
+ "accent4", // 221
+ "accent5", // 222
+ "accent6", // 223
+ "accentbar", // 224
+ "accumulate", // 225
+ "action", // 226
+ "active", // 227
+ "activeCell", // 228
+ "activeCellId", // 229
+ "activeCol", // 230
+ "activePane", // 231
+ "activeRecord", // 232
+ "activeRow", // 233
+ "activeSheetId", // 234
+ "activeTab", // 235
+ "activeWritingStyle", // 236
+ "actualPg", // 237
+ "additionalCharacteristics", // 238
+ "additive", // 239
+ "addlxml", // 240
+ "addressFieldName", // 241
+ "adj", // 242
+ "adjLst", // 243
+ "adjust", // 244
+ "adjustColumnWidth", // 245
+ "adjustLineHeightInTable", // 246
+ "adjustRightInd", // 247
+ "adjusthandles", // 248
+ "advAuto", // 249
+ "advClick", // 250
+ "advTm", // 251
+ "advise", // 252
+ "after", // 253
+ "afterAutospacing", // 254
+ "afterEffect", // 255
+ "afterLines", // 256
+ "ahLst", // 257
+ "ahPolar", // 258
+ "ahXY", // 259
+ "alg", // 260
+ "algIdExt", // 261
+ "algIdExtSource", // 262
+ "algn", // 263
+ "alias", // 264
+ "aliases", // 265
+ "align", // 266
+ "alignBordersAndEdges", // 267
+ "alignTablesRowByRow", // 268
+ "alignWithMargins", // 269
+ "alignment", // 270
+ "alignshape", // 271
+ "all", // 272
+ "allCaption", // 273
+ "allDrilled", // 274
+ "allUniqueName", // 275
+ "allowBlank", // 276
+ "allowOverlap", // 277
+ "allowPNG", // 278
+ "allowPng", // 279
+ "allowRefreshQuery", // 280
+ "allowSpaceOfSameStyleInTable", // 281
+ "allowcomments", // 282
+ "allowincell", // 283
+ "allowoverlap", // 284
+ "aln", // 285
+ "alnAt", // 286
+ "alnScr", // 287
+ "alpha", // 288
+ "alphaBiLevel", // 289
+ "alphaCeiling", // 290
+ "alphaFloor", // 291
+ "alphaInv", // 292
+ "alphaMod", // 293
+ "alphaModFix", // 294
+ "alphaOff", // 295
+ "alphaOutset", // 296
+ "alphaRepl", // 297
+ "alt", // 298
+ "altChunk", // 299
+ "altChunkPr", // 300
+ "altLang", // 301
+ "altName", // 302
+ "althref", // 303
+ "alwaysMergeEmptyNamespace", // 304
+ "alwaysShow", // 305
+ "alwaysShowPlaceholderText", // 306
+ "amt", // 307
+ "anchor", // 308
+ "anchorCtr", // 309
+ "anchorLock", // 310
+ "anchorlock", // 311
+ "anchorx", // 312
+ "anchory", // 313
+ "and", // 314
+ "ang", // 315
+ "angle", // 316
+ "anim", // 317
+ "animBg", // 318
+ "animClr", // 319
+ "animEffect", // 320
+ "animLvl", // 321
+ "animMotion", // 322
+ "animOne", // 323
+ "animRot", // 324
+ "animScale", // 325
+ "annotation", // 326
+ "annotationRef", // 327
+ "appName", // 328
+ "applyAlignment", // 329
+ "applyAlignmentFormats", // 330
+ "applyBorder", // 331
+ "applyBorderFormats", // 332
+ "applyBreakingRules", // 333
+ "applyFill", // 334
+ "applyFont", // 335
+ "applyFontFormats", // 336
+ "applyNumberFormat", // 337
+ "applyNumberFormats", // 338
+ "applyPatternFormats", // 339
+ "applyProtection", // 340
+ "applyStyles", // 341
+ "applyToEnd", // 342
+ "applyToFront", // 343
+ "applyToSides", // 344
+ "applyWidthHeightFormats", // 345
+ "arc", // 346
+ "arcTo", // 347
+ "arcsize", // 348
+ "area3DChart", // 349
+ "areaChart", // 350
+ "arg", // 351
+ "argPr", // 352
+ "argSz", // 353
+ "array", // 354
+ "arrowok", // 355
+ "ascii", // 356
+ "asciiTheme", // 357
+ "aspect", // 358
+ "aspectratio", // 359
+ "assign", // 360
+ "asteriskTotals", // 361
+ "attachedSchema", // 362
+ "attachedTemplate", // 363
+ "attr", // 364
+ "attrName", // 365
+ "attrNameLst", // 366
+ "attribute", // 367
+ "audio", // 368
+ "audioCd", // 369
+ "audioFile", // 370
+ "author", // 371
+ "authorId", // 372
+ "authors", // 373
+ "auto", // 374
+ "autoAdjust", // 375
+ "autoCaption", // 376
+ "autoCaptions", // 377
+ "autoCompressPictures", // 378
+ "autoEnd", // 379
+ "autoFilter", // 380
+ "autoFilterDateGrouping", // 381
+ "autoFormatId", // 382
+ "autoFormatOverride", // 383
+ "autoHyphenation", // 384
+ "autoLoad", // 385
+ "autoPage", // 386
+ "autoPageBreaks", // 387
+ "autoRecover", // 388
+ "autoRedefine", // 389
+ "autoRepublish", // 390
+ "autoRev", // 391
+ "autoShow", // 392
+ "autoSortScope", // 393
+ "autoSpaceDE", // 394
+ "autoSpaceDN", // 395
+ "autoSpaceLikeWord95", // 396
+ "autoStart", // 397
+ "autoTitleDeleted", // 398
+ "autoUpdate", // 399
+ "autoUpdateAnimBg", // 400
+ "autofitToFirstFixedWidthCell", // 401
+ "autoformat", // 402
+ "autolayout", // 403
+ "autorotationcenter", // 404
+ "avLst", // 405
+ "avgSubtotal", // 406
+ "axId", // 407
+ "axPos", // 408
+ "axis", // 409
+ "b", // 410
+ "bCs", // 411
+ "bIns", // 412
+ "backWall", // 413
+ "backdepth", // 414
+ "backdrop", // 415
+ "background", // 416
+ "backgroundQuery", // 417
+ "backgroundRefresh", // 418
+ "backupFile", // 419
+ "backward", // 420
+ "backwards", // 421
+ "balanceSingleByteDoubleByteWidth", // 422
+ "band1H", // 423
+ "band1V", // 424
+ "band2H", // 425
+ "band2V", // 426
+ "bandCol", // 427
+ "bandFmt", // 428
+ "bandFmts", // 429
+ "bandRow", // 430
+ "bar", // 431
+ "bar3DChart", // 432
+ "barChart", // 433
+ "barDir", // 434
+ "barPr", // 435
+ "base", // 436
+ "baseColWidth", // 437
+ "baseField", // 438
+ "baseItem", // 439
+ "baseJc", // 440
+ "baseTimeUnit", // 441
+ "baseType", // 442
+ "basedOn", // 443
+ "baseline", // 444
+ "bc", // 445
+ "bdr", // 446
+ "before", // 447
+ "beforeAutospacing", // 448
+ "beforeLines", // 449
+ "begChr", // 450
+ "behavior", // 451
+ "behaviors", // 452
+ "behindDoc", // 453
+ "bestFit", // 454
+ "between", // 455
+ "bevel", // 456
+ "bevelB", // 457
+ "bevelT", // 458
+ "bg", // 459
+ "bg1", // 460
+ "bg2", // 461
+ "bgClr", // 462
+ "bgColor", // 463
+ "bgFillStyleLst", // 464
+ "bgPr", // 465
+ "bgRef", // 466
+ "biLevel", // 467
+ "bibliography", // 468
+ "bidi", // 469
+ "bidiVisual", // 470
+ "bilevel", // 471
+ "bk", // 472
+ "blackAndWhite", // 473
+ "blacklevel", // 474
+ "blank", // 475
+ "bld", // 476
+ "bldAsOne", // 477
+ "bldChart", // 478
+ "bldDgm", // 479
+ "bldGraphic", // 480
+ "bldLst", // 481
+ "bldLvl", // 482
+ "bldOleChart", // 483
+ "bldP", // 484
+ "bldStep", // 485
+ "bldSub", // 486
+ "blend", // 487
+ "blinds", // 488
+ "blip", // 489
+ "blipFill", // 490
+ "blipPhldr", // 491
+ "blob", // 492
+ "blockQuote", // 493
+ "blue", // 494
+ "blueMod", // 495
+ "blueOff", // 496
+ "blur", // 497
+ "blurRad", // 498
+ "bmk", // 499
+ "body", // 500
+ "bodyDiv", // 501
+ "bodyPr", // 502
+ "bodyStyle", // 503
+ "bold", // 504
+ "boldItalic", // 505
+ "bookFoldPrinting", // 506
+ "bookFoldPrintingSheets", // 507
+ "bookFoldRevPrinting", // 508
+ "bookViews", // 509
+ "bookmarkEnd", // 510
+ "bookmarkIdSeed", // 511
+ "bookmarkStart", // 512
+ "bool", // 513
+ "boolVal", // 514
+ "boolean", // 515
+ "border", // 516
+ "borderBox", // 517
+ "borderBoxPr", // 518
+ "borderId", // 519
+ "borderbottom", // 520
+ "borderbottomcolor", // 521
+ "borderleft", // 522
+ "borderleftcolor", // 523
+ "borderright", // 524
+ "borderrightcolor", // 525
+ "borders", // 526
+ "bordersDoNotSurroundFooter", // 527
+ "bordersDoNotSurroundHeader", // 528
+ "bordertop", // 529
+ "bordertopcolor", // 530
+ "bottom", // 531
+ "bottomFromText", // 532
+ "box", // 533
+ "boxPr", // 534
+ "br", // 535
+ "bright", // 536
+ "brightness", // 537
+ "brk", // 538
+ "brkBin", // 539
+ "brkBinSub", // 540
+ "browse", // 541
+ "bstr", // 542
+ "buAutoNum", // 543
+ "buBlip", // 544
+ "buChar", // 545
+ "buClr", // 546
+ "buClrTx", // 547
+ "buFont", // 548
+ "buFontTx", // 549
+ "buNone", // 550
+ "buSzPct", // 551
+ "buSzPts", // 552
+ "buSzTx", // 553
+ "bubble3D", // 554
+ "bubbleChart", // 555
+ "bubbleScale", // 556
+ "bubbleSize", // 557
+ "build", // 558
+ "builtIn", // 559
+ "builtInGroupCount", // 560
+ "builtInUnit", // 561
+ "builtinId", // 562
+ "bullet", // 563
+ "bulletEnabled", // 564
+ "button", // 565
+ "bw", // 566
+ "bwMode", // 567
+ "bwmode", // 568
+ "bwnormal", // 569
+ "bwpure", // 570
+ "bx", // 571
+ "by", // 572
+ "byPosition", // 573
+ "c", // 574
+ "cBhvr", // 575
+ "cGp", // 576
+ "cGpRule", // 577
+ "cMediaNode", // 578
+ "cNvCxnSpPr", // 579
+ "cNvGraphicFramePr", // 580
+ "cNvGrpSpPr", // 581
+ "cNvPicPr", // 582
+ "cNvPr", // 583
+ "cNvSpPr", // 584
+ "cSld", // 585
+ "cSldViewPr", // 586
+ "cSp", // 587
+ "cTn", // 588
+ "cViewPr", // 589
+ "ca", // 590
+ "cacheField", // 591
+ "cacheFields", // 592
+ "cacheHierarchies", // 593
+ "cacheHierarchy", // 594
+ "cacheId", // 595
+ "cacheIndex", // 596
+ "cacheSource", // 597
+ "cachedColBalance", // 598
+ "calcChain", // 599
+ "calcCompleted", // 600
+ "calcId", // 601
+ "calcMode", // 602
+ "calcOnExit", // 603
+ "calcOnSave", // 604
+ "calcPr", // 605
+ "calcmode", // 606
+ "calculatedColumn", // 607
+ "calculatedColumnFormula", // 608
+ "calculatedItem", // 609
+ "calculatedItems", // 610
+ "calculatedMember", // 611
+ "calculatedMembers", // 612
+ "calendar", // 613
+ "calendarType", // 614
+ "callout", // 615
+ "camera", // 616
+ "cantSplit", // 617
+ "cap", // 618
+ "caps", // 619
+ "caption", // 620
+ "captions", // 621
+ "caseSensitive", // 622
+ "cat", // 623
+ "catAx", // 624
+ "catLst", // 625
+ "category", // 626
+ "categoryIdx", // 627
+ "cell", // 628
+ "cell3D", // 629
+ "cellColor", // 630
+ "cellComments", // 631
+ "cellDel", // 632
+ "cellIns", // 633
+ "cellMerge", // 634
+ "cellMeta", // 635
+ "cellMetadata", // 636
+ "cellSmartTag", // 637
+ "cellSmartTagPr", // 638
+ "cellSmartTags", // 639
+ "cellStyle", // 640
+ "cellStyleXfs", // 641
+ "cellStyles", // 642
+ "cellWatch", // 643
+ "cellWatches", // 644
+ "cellXfs", // 645
+ "cf", // 646
+ "cfRule", // 647
+ "cfvo", // 648
+ "chExt", // 649
+ "chMax", // 650
+ "chOff", // 651
+ "chOrder", // 652
+ "chPref", // 653
+ "changesSavedWin", // 654
+ "chapNum", // 655
+ "chapSep", // 656
+ "chapStyle", // 657
+ "char", // 658
+ "charRg", // 659
+ "charSpace", // 660
+ "characterSpacingControl", // 661
+ "characteristic", // 662
+ "charset", // 663
+ "chart", // 664
+ "chartFormat", // 665
+ "chartFormats", // 666
+ "chartObject", // 667
+ "chartSpace", // 668
+ "chartsheet", // 669
+ "checkBox", // 670
+ "checkCompatibility", // 671
+ "checkErrors", // 672
+ "checkStyle", // 673
+ "checked", // 674
+ "checker", // 675
+ "childTnLst", // 676
+ "choose", // 677
+ "chr", // 678
+ "chromakey", // 679
+ "circle", // 680
+ "citation", // 681
+ "class", // 682
+ "clear", // 683
+ "clearAll", // 684
+ "clearComments", // 685
+ "clearContents", // 686
+ "clearFormats", // 687
+ "click", // 688
+ "clickAndTypeStyle", // 689
+ "clientData", // 690
+ "clientInsertedTime", // 691
+ "clip", // 692
+ "clippath", // 693
+ "clipped", // 694
+ "cliptowrap", // 695
+ "close", // 696
+ "clr", // 697
+ "clrChange", // 698
+ "clrData", // 699
+ "clrFrom", // 700
+ "clrIdx", // 701
+ "clrMap", // 702
+ "clrMapOvr", // 703
+ "clrMode", // 704
+ "clrMru", // 705
+ "clrRepl", // 706
+ "clrScheme", // 707
+ "clrSchemeMapping", // 708
+ "clrSpc", // 709
+ "clrTo", // 710
+ "clrVal", // 711
+ "clsid", // 712
+ "cm", // 713
+ "cmAuthor", // 714
+ "cmAuthorLst", // 715
+ "cmLst", // 716
+ "cmd", // 717
+ "cmpd", // 718
+ "cnfStyle", // 719
+ "cnt", // 720
+ "code", // 721
+ "codeName", // 722
+ "codePage", // 723
+ "coerce", // 724
+ "coherent3DOff", // 725
+ "col", // 726
+ "colBreaks", // 727
+ "colDelim", // 728
+ "colFields", // 729
+ "colFirst", // 730
+ "colGrandTotals", // 731
+ "colHeaderCaption", // 732
+ "colHierarchiesUsage", // 733
+ "colHierarchyUsage", // 734
+ "colId", // 735
+ "colItems", // 736
+ "colLast", // 737
+ "colOff", // 738
+ "colPageCount", // 739
+ "collapse", // 740
+ "collapsed", // 741
+ "collapsedLevelsAreSubtotals", // 742
+ "color", // 743
+ "color2", // 744
+ "colorFilter", // 745
+ "colorId", // 746
+ "colorScale", // 747
+ "colormenu", // 748
+ "colormode", // 749
+ "colormru", // 750
+ "colors", // 751
+ "colorsDef", // 752
+ "colorsDefHdr", // 753
+ "colorsDefHdrLst", // 754
+ "cols", // 755
+ "column", // 756
+ "columnSort", // 757
+ "comb", // 758
+ "combine", // 759
+ "combineBrackets", // 760
+ "comboBox", // 761
+ "comma", // 762
+ "command", // 763
+ "commandType", // 764
+ "comment", // 765
+ "commentList", // 766
+ "commentRangeEnd", // 767
+ "commentRangeStart", // 768
+ "commentReference", // 769
+ "comments", // 770
+ "comp", // 771
+ "compact", // 772
+ "compactData", // 773
+ "compat", // 774
+ "compatLnSpc", // 775
+ "compatMode", // 776
+ "complex", // 777
+ "concurrent", // 778
+ "concurrentCalc", // 779
+ "concurrentManualCount", // 780
+ "cond", // 781
+ "condense", // 782
+ "conditionalFormat", // 783
+ "conditionalFormats", // 784
+ "conditionalFormatting", // 785
+ "connectString", // 786
+ "connectangles", // 787
+ "connection", // 788
+ "connectionId", // 789
+ "connections", // 790
+ "connectloc", // 791
+ "connectlocs", // 792
+ "connectortype", // 793
+ "connecttype", // 794
+ "consecutive", // 795
+ "consecutiveHyphenLimit", // 796
+ "consolidation", // 797
+ "constr", // 798
+ "constrLst", // 799
+ "constrainbounds", // 800
+ "cont", // 801
+ "containsBlank", // 802
+ "containsDate", // 803
+ "containsInteger", // 804
+ "containsMixedTypes", // 805
+ "containsNonDate", // 806
+ "containsNumber", // 807
+ "containsSemiMixedTypes", // 808
+ "containsString", // 809
+ "content", // 810
+ "contextualSpacing", // 811
+ "continuationSeparator", // 812
+ "contourClr", // 813
+ "contourW", // 814
+ "contrast", // 815
+ "control", // 816
+ "control1", // 817
+ "control2", // 818
+ "controls", // 819
+ "convMailMergeEsc", // 820
+ "coordorigin", // 821
+ "coordsize", // 822
+ "copies", // 823
+ "copy", // 824
+ "count", // 825
+ "countASubtotal", // 826
+ "countBy", // 827
+ "countSubtotal", // 828
+ "cover", // 829
+ "cp", // 830
+ "cr", // 831
+ "crashSave", // 832
+ "createdVersion", // 833
+ "credentials", // 834
+ "cropbottom", // 835
+ "cropleft", // 836
+ "cropping", // 837
+ "cropright", // 838
+ "croptop", // 839
+ "crossAx", // 840
+ "crossBetween", // 841
+ "crosses", // 842
+ "crossesAt", // 843
+ "cryptAlgorithmClass", // 844
+ "cryptAlgorithmSid", // 845
+ "cryptAlgorithmType", // 846
+ "cryptProvider", // 847
+ "cryptProviderType", // 848
+ "cryptProviderTypeExt", // 849
+ "cryptProviderTypeExtSource", // 850
+ "cryptSpinCount", // 851
+ "cs", // 852
+ "csCatId", // 853
+ "csTypeId", // 854
+ "csb0", // 855
+ "csb1", // 856
+ "css", // 857
+ "cstate", // 858
+ "cstheme", // 859
+ "ct", // 860
+ "ctrlPr", // 861
+ "cubicBezTo", // 862
+ "culture", // 863
+ "current", // 864
+ "curve", // 865
+ "custAng", // 866
+ "custClr", // 867
+ "custClrLst", // 868
+ "custDash", // 869
+ "custData", // 870
+ "custDataLst", // 871
+ "custFlipHor", // 872
+ "custFlipVert", // 873
+ "custGeom", // 874
+ "custLinFactNeighborX", // 875
+ "custLinFactNeighborY", // 876
+ "custLinFactX", // 877
+ "custLinFactY", // 878
+ "custRadScaleInc", // 879
+ "custRadScaleRad", // 880
+ "custScaleX", // 881
+ "custScaleY", // 882
+ "custShow", // 883
+ "custShowLst", // 884
+ "custSplit", // 885
+ "custSzX", // 886
+ "custSzY", // 887
+ "custT", // 888
+ "custUnit", // 889
+ "customBuiltin", // 890
+ "customFilter", // 891
+ "customFilters", // 892
+ "customFormat", // 893
+ "customHeight", // 894
+ "customList", // 895
+ "customListSort", // 896
+ "customMarkFollows", // 897
+ "customMenu", // 898
+ "customPr", // 899
+ "customProperties", // 900
+ "customRollUp", // 901
+ "customSheetView", // 902
+ "customSheetViews", // 903
+ "customStyle", // 904
+ "customView", // 905
+ "customWidth", // 906
+ "customWorkbookView", // 907
+ "customWorkbookViews", // 908
+ "customXml", // 909
+ "customXmlDelRangeEnd", // 910
+ "customXmlDelRangeStart", // 911
+ "customXmlInsRangeEnd", // 912
+ "customXmlInsRangeStart", // 913
+ "customXmlMoveFromRangeEnd", // 914
+ "customXmlMoveFromRangeStart", // 915
+ "customXmlMoveToRangeEnd", // 916
+ "customXmlMoveToRangeStart", // 917
+ "customXmlPr", // 918
+ "cut", // 919
+ "cx", // 920
+ "cxn", // 921
+ "cxnId", // 922
+ "cxnLst", // 923
+ "cxnSp", // 924
+ "cxnSpLocks", // 925
+ "cy", // 926
+ "d", // 927
+ "dLbl", // 928
+ "dLblPos", // 929
+ "dLbls", // 930
+ "dPr", // 931
+ "dPt", // 932
+ "dTable", // 933
+ "dashstyle", // 934
+ "data", // 935
+ "dataBar", // 936
+ "dataBinding", // 937
+ "dataBound", // 938
+ "dataCaption", // 939
+ "dataCellStyle", // 940
+ "dataConsolidate", // 941
+ "dataDxfId", // 942
+ "dataExtractLoad", // 943
+ "dataField", // 944
+ "dataFields", // 945
+ "dataModel", // 946
+ "dataOnRows", // 947
+ "dataOnly", // 948
+ "dataPosition", // 949
+ "dataRef", // 950
+ "dataRefs", // 951
+ "dataSource", // 952
+ "dataSourceSort", // 953
+ "dataType", // 954
+ "dataValidation", // 955
+ "dataValidations", // 956
+ "databaseField", // 957
+ "datastoreItem", // 958
+ "date", // 959
+ "date1904", // 960
+ "dateAx", // 961
+ "dateFormat", // 962
+ "dateGroupItem", // 963
+ "dateTime", // 964
+ "dateTimeGrouping", // 965
+ "day", // 966
+ "dayLong", // 967
+ "dayShort", // 968
+ "dbPr", // 969
+ "ddList", // 970
+ "ddeItem", // 971
+ "ddeItems", // 972
+ "ddeLink", // 973
+ "ddeService", // 974
+ "ddeTopic", // 975
+ "decel", // 976
+ "decimal", // 977
+ "decimalSymbol", // 978
+ "decorated", // 979
+ "def", // 980
+ "defJc", // 981
+ "defLockedState", // 982
+ "defPPr", // 983
+ "defQFormat", // 984
+ "defRPr", // 985
+ "defSemiHidden", // 986
+ "defStyle", // 987
+ "defTabSz", // 988
+ "defUIPriority", // 989
+ "defUnhideWhenUsed", // 990
+ "default", // 991
+ "defaultAttributeDrillState", // 992
+ "defaultColWidth", // 993
+ "defaultGridColor", // 994
+ "defaultMemberUniqueName", // 995
+ "defaultPivotStyle", // 996
+ "defaultRowHeight", // 997
+ "defaultSubtotal", // 998
+ "defaultTabStop", // 999
+ "defaultTableStyle", // 1000
+ "defaultTextStyle", // 1001
+ "defaultThemeVersion", // 1002
+ "definedName", // 1003
+ "definedNames", // 1004
+ "deg", // 1005
+ "degHide", // 1006
+ "degree", // 1007
+ "del", // 1008
+ "del1", // 1009
+ "del2", // 1010
+ "delInstrText", // 1011
+ "delText", // 1012
+ "delay", // 1013
+ "delete", // 1014
+ "deleteColumns", // 1015
+ "deleteRows", // 1016
+ "deleted", // 1017
+ "deletedField", // 1018
+ "delimited", // 1019
+ "delimiter", // 1020
+ "den", // 1021
+ "denormalized", // 1022
+ "depthPercent", // 1023
+ "desc", // 1024
+ "descending", // 1025
+ "descr", // 1026
+ "description", // 1027
+ "destId", // 1028
+ "destOrd", // 1029
+ "destination", // 1030
+ "destinationFile", // 1031
+ "detectmouseclick", // 1032
+ "dgm", // 1033
+ "dgmbasetextscale", // 1034
+ "dgmfontsize", // 1035
+ "dgmlayout", // 1036
+ "dgmlayoutmru", // 1037
+ "dgmnodekind", // 1038
+ "dgmscalex", // 1039
+ "dgmscaley", // 1040
+ "dgmstyle", // 1041
+ "diagonal", // 1042
+ "diagonalDown", // 1043
+ "diagonalUp", // 1044
+ "diagram", // 1045
+ "dialogsheet", // 1046
+ "diamond", // 1047
+ "diff", // 1048
+ "differentFirst", // 1049
+ "differentOddEven", // 1050
+ "diffusity", // 1051
+ "dimension", // 1052
+ "dimensionUniqueName", // 1053
+ "dimensions", // 1054
+ "dir", // 1055
+ "dirty", // 1056
+ "disableEdit", // 1057
+ "disableFieldList", // 1058
+ "disablePrompts", // 1059
+ "disableRefresh", // 1060
+ "discretePr", // 1061
+ "diskRevisions", // 1062
+ "dispBlanksAs", // 1063
+ "dispDef", // 1064
+ "dispEq", // 1065
+ "dispRSqr", // 1066
+ "dispUnits", // 1067
+ "dispUnitsLbl", // 1068
+ "displacedByCustomXml", // 1069
+ "display", // 1070
+ "displayBackgroundShape", // 1071
+ "displayFolder", // 1072
+ "displayHangulFixedWidth", // 1073
+ "displayHorizontalDrawingGridEvery", // 1074
+ "displayName", // 1075
+ "displayText", // 1076
+ "displayVerticalDrawingGridEvery", // 1077
+ "dissolve", // 1078
+ "dist", // 1079
+ "distB", // 1080
+ "distL", // 1081
+ "distR", // 1082
+ "distT", // 1083
+ "distance", // 1084
+ "div", // 1085
+ "divBdr", // 1086
+ "divId", // 1087
+ "divs", // 1088
+ "divsChild", // 1089
+ "dk1", // 1090
+ "dk2", // 1091
+ "dllVersion", // 1092
+ "dm", // 1093
+ "dn", // 1094
+ "doNotAutoCompressPictures", // 1095
+ "doNotAutofitConstrainedTables", // 1096
+ "doNotBreakConstrainedForcedTable", // 1097
+ "doNotBreakWrappedTables", // 1098
+ "doNotDemarcateInvalidXml", // 1099
+ "doNotDisplayPageBoundaries", // 1100
+ "doNotEmbedSmartTags", // 1101
+ "doNotExpandShiftReturn", // 1102
+ "doNotHyphenateCaps", // 1103
+ "doNotIncludeSubdocsInStats", // 1104
+ "doNotLeaveBackslashAlone", // 1105
+ "doNotOrganizeInFolder", // 1106
+ "doNotRelyOnCSS", // 1107
+ "doNotSaveAsSingleFile", // 1108
+ "doNotShadeFormData", // 1109
+ "doNotSnapToGridInCell", // 1110
+ "doNotSuppressBlankLines", // 1111
+ "doNotSuppressIndentation", // 1112
+ "doNotSuppressParagraphBorders", // 1113
+ "doNotTrackFormatting", // 1114
+ "doNotTrackMoves", // 1115
+ "doNotUseEastAsianBreakRules", // 1116
+ "doNotUseHTMLParagraphAutoSpacing", // 1117
+ "doNotUseIndentAsNumberingTabStop", // 1118
+ "doNotUseLongFileNames", // 1119
+ "doNotUseMarginsForDrawingGridOrigin", // 1120
+ "doNotValidateAgainstSchema", // 1121
+ "doNotVertAlignCellWithSp", // 1122
+ "doNotVertAlignInTxbx", // 1123
+ "doNotWrapTextWithPunct", // 1124
+ "docDefaults", // 1125
+ "docGrid", // 1126
+ "docLocation", // 1127
+ "docPart", // 1128
+ "docPartBody", // 1129
+ "docPartCategory", // 1130
+ "docPartGallery", // 1131
+ "docPartList", // 1132
+ "docPartObj", // 1133
+ "docPartPr", // 1134
+ "docPartUnique", // 1135
+ "docParts", // 1136
+ "docPr", // 1137
+ "docVar", // 1138
+ "docVars", // 1139
+ "document", // 1140
+ "documentProtection", // 1141
+ "documentType", // 1142
+ "double", // 1143
+ "doubleclicknotify", // 1144
+ "doughnutChart", // 1145
+ "downBars", // 1146
+ "dpi", // 1147
+ "dr", // 1148
+ "draft", // 1149
+ "dragOff", // 1150
+ "dragToCol", // 1151
+ "dragToData", // 1152
+ "dragToPage", // 1153
+ "dragToRow", // 1154
+ "drawing", // 1155
+ "drawingGridHorizontalOrigin", // 1156
+ "drawingGridHorizontalSpacing", // 1157
+ "drawingGridVerticalOrigin", // 1158
+ "drawingGridVerticalSpacing", // 1159
+ "drop", // 1160
+ "dropCap", // 1161
+ "dropDownList", // 1162
+ "dropLines", // 1163
+ "dropauto", // 1164
+ "ds", // 1165
+ "dstrike", // 1166
+ "dt", // 1167
+ "dt2D", // 1168
+ "dtr", // 1169
+ "duotone", // 1170
+ "dur", // 1171
+ "dvAspect", // 1172
+ "dx", // 1173
+ "dxaOrig", // 1174
+ "dxf", // 1175
+ "dxfId", // 1176
+ "dxfs", // 1177
+ "dy", // 1178
+ "dyaOrig", // 1179
+ "dynamicAddress", // 1180
+ "dynamicFilter", // 1181
+ "dz", // 1182
+ "e", // 1183
+ "ea", // 1184
+ "eaLnBrk", // 1185
+ "eastAsia", // 1186
+ "eastAsiaTheme", // 1187
+ "eastAsianLayout", // 1188
+ "eb", // 1189
+ "ed", // 1190
+ "edGrp", // 1191
+ "edge", // 1192
+ "edit", // 1193
+ "editAs", // 1194
+ "editData", // 1195
+ "editPage", // 1196
+ "editas", // 1197
+ "edited", // 1198
+ "effect", // 1199
+ "effectClrLst", // 1200
+ "effectDag", // 1201
+ "effectExtent", // 1202
+ "effectLst", // 1203
+ "effectRef", // 1204
+ "effectStyle", // 1205
+ "effectStyleLst", // 1206
+ "element", // 1207
+ "else", // 1208
+ "em", // 1209
+ "embed", // 1210
+ "embedBold", // 1211
+ "embedBoldItalic", // 1212
+ "embedItalic", // 1213
+ "embedRegular", // 1214
+ "embedSystemFonts", // 1215
+ "embedTrueTypeFonts", // 1216
+ "embeddedFont", // 1217
+ "embeddedFontLst", // 1218
+ "emboss", // 1219
+ "embosscolor", // 1220
+ "empty", // 1221
+ "emptyCellReference", // 1222
+ "enableDrill", // 1223
+ "enableFieldProperties", // 1224
+ "enableFormatConditionsCalculation", // 1225
+ "enableRefresh", // 1226
+ "enableWizard", // 1227
+ "enabled", // 1228
+ "encoding", // 1229
+ "end", // 1230
+ "endA", // 1231
+ "endAngle", // 1232
+ "endChr", // 1233
+ "endCondLst", // 1234
+ "endCxn", // 1235
+ "endDate", // 1236
+ "endNum", // 1237
+ "endOfListFormulaUpdate", // 1238
+ "endParaRPr", // 1239
+ "endPos", // 1240
+ "endSnd", // 1241
+ "endSync", // 1242
+ "endarrow", // 1243
+ "endarrowlength", // 1244
+ "endarrowwidth", // 1245
+ "endcap", // 1246
+ "endnote", // 1247
+ "endnotePr", // 1248
+ "endnoteRef", // 1249
+ "endnoteReference", // 1250
+ "endnotes", // 1251
+ "enforcement", // 1252
+ "entries", // 1253
+ "entry", // 1254
+ "entryMacro", // 1255
+ "eol", // 1256
+ "eqArr", // 1257
+ "eqArrPr", // 1258
+ "eqn", // 1259
+ "equalAverage", // 1260
+ "equalWidth", // 1261
+ "equation", // 1262
+ "equationxml", // 1263
+ "err", // 1264
+ "errBarType", // 1265
+ "errBars", // 1266
+ "errDir", // 1267
+ "errValType", // 1268
+ "error", // 1269
+ "errorCaption", // 1270
+ "errorStyle", // 1271
+ "errorTitle", // 1272
+ "errors", // 1273
+ "evalError", // 1274
+ "evalOrder", // 1275
+ "evenAndOddHeaders", // 1276
+ "evenFooter", // 1277
+ "evenHeader", // 1278
+ "evt", // 1279
+ "evtFilter", // 1280
+ "excl", // 1281
+ "exclusive", // 1282
+ "exitMacro", // 1283
+ "exp", // 1284
+ "explosion", // 1285
+ "ext", // 1286
+ "extLst", // 1287
+ "extend", // 1288
+ "extendable", // 1289
+ "extent", // 1290
+ "externalBook", // 1291
+ "externalData", // 1292
+ "externalLink", // 1293
+ "externalReference", // 1294
+ "externalReferences", // 1295
+ "extraClrScheme", // 1296
+ "extraClrSchemeLst", // 1297
+ "extrusion", // 1298
+ "extrusionClr", // 1299
+ "extrusionH", // 1300
+ "extrusionOk", // 1301
+ "extrusioncolor", // 1302
+ "extrusionok", // 1303
+ "f", // 1304
+ "fHdr", // 1305
+ "fLocksText", // 1306
+ "fLocksWithSheet", // 1307
+ "fName", // 1308
+ "fPr", // 1309
+ "fPrintsWithSheet", // 1310
+ "fPublished", // 1311
+ "facet", // 1312
+ "fact", // 1313
+ "fade", // 1314
+ "fadeDir", // 1315
+ "family", // 1316
+ "fc", // 1317
+ "ffData", // 1318
+ "fgClr", // 1319
+ "fgColor", // 1320
+ "fi", // 1321
+ "field", // 1322
+ "fieldGroup", // 1323
+ "fieldId", // 1324
+ "fieldIdWrapped", // 1325
+ "fieldListSortAscending", // 1326
+ "fieldMapData", // 1327
+ "fieldPosition", // 1328
+ "fieldPrintTitles", // 1329
+ "fieldUsage", // 1330
+ "fieldsUsage", // 1331
+ "fileRecoveryPr", // 1332
+ "fileSharing", // 1333
+ "fileType", // 1334
+ "fileVersion", // 1335
+ "filetime", // 1336
+ "fill", // 1337
+ "fillClrLst", // 1338
+ "fillFormulas", // 1339
+ "fillId", // 1340
+ "fillOverlay", // 1341
+ "fillRect", // 1342
+ "fillRef", // 1343
+ "fillStyleLst", // 1344
+ "fillToRect", // 1345
+ "fillcolor", // 1346
+ "filled", // 1347
+ "fillok", // 1348
+ "fills", // 1349
+ "filltype", // 1350
+ "filter", // 1351
+ "filterColumn", // 1352
+ "filterMode", // 1353
+ "filterPrivacy", // 1354
+ "filterUnique", // 1355
+ "filterVal", // 1356
+ "filters", // 1357
+ "first", // 1358
+ "firstBackgroundRefresh", // 1359
+ "firstCol", // 1360
+ "firstDataCol", // 1361
+ "firstDataRow", // 1362
+ "firstFooter", // 1363
+ "firstHeader", // 1364
+ "firstHeaderRow", // 1365
+ "firstLine", // 1366
+ "firstLineChars", // 1367
+ "firstPageNumber", // 1368
+ "firstRow", // 1369
+ "firstSheet", // 1370
+ "firstSliceAng", // 1371
+ "firstSlideNum", // 1372
+ "fitText", // 1373
+ "fitToHeight", // 1374
+ "fitToPage", // 1375
+ "fitToWidth", // 1376
+ "fitpath", // 1377
+ "fitshape", // 1378
+ "flatBorders", // 1379
+ "flatTx", // 1380
+ "fld", // 1381
+ "fldChar", // 1382
+ "fldCharType", // 1383
+ "fldData", // 1384
+ "fldLock", // 1385
+ "fldSimple", // 1386
+ "flip", // 1387
+ "flipH", // 1388
+ "flipV", // 1389
+ "floor", // 1390
+ "fltVal", // 1391
+ "fmla", // 1392
+ "fmt", // 1393
+ "fmtId", // 1394
+ "fmtScheme", // 1395
+ "fmtid", // 1396
+ "focus", // 1397
+ "focusposition", // 1398
+ "focussize", // 1399
+ "folHlink", // 1400
+ "followColorScheme", // 1401
+ "followedHyperlink", // 1402
+ "font", // 1403
+ "fontAlgn", // 1404
+ "fontId", // 1405
+ "fontKey", // 1406
+ "fontRef", // 1407
+ "fontScale", // 1408
+ "fontScheme", // 1409
+ "fontSz", // 1410
+ "fonts", // 1411
+ "footer", // 1412
+ "footerReference", // 1413
+ "footnote", // 1414
+ "footnoteLayoutLikeWW8", // 1415
+ "footnotePr", // 1416
+ "footnoteRef", // 1417
+ "footnoteReference", // 1418
+ "footnotes", // 1419
+ "for", // 1420
+ "forEach", // 1421
+ "forName", // 1422
+ "forceAA", // 1423
+ "forceFullCalc", // 1424
+ "forceUpgrade", // 1425
+ "forcedash", // 1426
+ "foredepth", // 1427
+ "forgetLastTabAlignment", // 1428
+ "formProt", // 1429
+ "format", // 1430
+ "formatCells", // 1431
+ "formatCode", // 1432
+ "formatColumns", // 1433
+ "formatRows", // 1434
+ "formats", // 1435
+ "formatting", // 1436
+ "formsDesign", // 1437
+ "formula", // 1438
+ "formula1", // 1439
+ "formula2", // 1440
+ "formulaRange", // 1441
+ "formulas", // 1442
+ "forward", // 1443
+ "fov", // 1444
+ "frame", // 1445
+ "frameLayout", // 1446
+ "framePr", // 1447
+ "frameSlides", // 1448
+ "frameset", // 1449
+ "framesetSplitbar", // 1450
+ "from", // 1451
+ "fromWordArt", // 1452
+ "ftr", // 1453
+ "fullCalcOnLoad", // 1454
+ "fullDate", // 1455
+ "fullPrecision", // 1456
+ "fullScrn", // 1457
+ "func", // 1458
+ "funcPr", // 1459
+ "function", // 1460
+ "functionGroup", // 1461
+ "functionGroupId", // 1462
+ "functionGroups", // 1463
+ "futureMetadata", // 1464
+ "g", // 1465
+ "gain", // 1466
+ "gallery", // 1467
+ "gamma", // 1468
+ "gap", // 1469
+ "gapDepth", // 1470
+ "gapWidth", // 1471
+ "gd", // 1472
+ "gdLst", // 1473
+ "gdRefAng", // 1474
+ "gdRefR", // 1475
+ "gdRefX", // 1476
+ "gdRefY", // 1477
+ "gfxdata", // 1478
+ "ghostCol", // 1479
+ "ghostRow", // 1480
+ "glossaryDocument", // 1481
+ "glow", // 1482
+ "goal", // 1483
+ "gradFill", // 1484
+ "gradientFill", // 1485
+ "gradientshapeok", // 1486
+ "grammar", // 1487
+ "grandCol", // 1488
+ "grandRow", // 1489
+ "grandTotalCaption", // 1490
+ "graphic", // 1491
+ "graphicData", // 1492
+ "graphicEl", // 1493
+ "graphicFrame", // 1494
+ "graphicFrameLocks", // 1495
+ "gray", // 1496
+ "grayscale", // 1497
+ "grayscl", // 1498
+ "green", // 1499
+ "greenMod", // 1500
+ "greenOff", // 1501
+ "gridAfter", // 1502
+ "gridBefore", // 1503
+ "gridCol", // 1504
+ "gridDropZones", // 1505
+ "gridLines", // 1506
+ "gridLinesSet", // 1507
+ "gridSpacing", // 1508
+ "gridSpan", // 1509
+ "group", // 1510
+ "groupBy", // 1511
+ "groupChr", // 1512
+ "groupChrPr", // 1513
+ "groupInterval", // 1514
+ "groupItems", // 1515
+ "groupLevel", // 1516
+ "groupLevels", // 1517
+ "groupMember", // 1518
+ "groupMembers", // 1519
+ "grouping", // 1520
+ "groups", // 1521
+ "grow", // 1522
+ "growAutofit", // 1523
+ "growShrinkType", // 1524
+ "grpFill", // 1525
+ "grpId", // 1526
+ "grpSp", // 1527
+ "grpSpLocks", // 1528
+ "grpSpPr", // 1529
+ "gs", // 1530
+ "gsLst", // 1531
+ "gte", // 1532
+ "guid", // 1533
+ "guide", // 1534
+ "guideLst", // 1535
+ "gutter", // 1536
+ "gutterAtTop", // 1537
+ "h", // 1538
+ "hAnchor", // 1539
+ "hAnsi", // 1540
+ "hAnsiTheme", // 1541
+ "hMerge", // 1542
+ "hMode", // 1543
+ "hPercent", // 1544
+ "hR", // 1545
+ "hRule", // 1546
+ "hSpace", // 1547
+ "handles", // 1548
+ "handoutMaster", // 1549
+ "handoutMasterId", // 1550
+ "handoutMasterIdLst", // 1551
+ "hanging", // 1552
+ "hangingChars", // 1553
+ "hangingPunct", // 1554
+ "hasCustomPrompt", // 1555
+ "hash", // 1556
+ "hashData", // 1557
+ "hdr", // 1558
+ "hdrShapeDefaults", // 1559
+ "headEnd", // 1560
+ "header", // 1561
+ "headerFooter", // 1562
+ "headerReference", // 1563
+ "headerRowBorderDxfId", // 1564
+ "headerRowCellStyle", // 1565
+ "headerRowCount", // 1566
+ "headerRowDxfId", // 1567
+ "headerSource", // 1568
+ "headers", // 1569
+ "headersInLastRefresh", // 1570
+ "heading", // 1571
+ "headings", // 1572
+ "help", // 1573
+ "helpText", // 1574
+ "hf", // 1575
+ "hiLowLines", // 1576
+ "hidden", // 1577
+ "hiddenButton", // 1578
+ "hiddenColumn", // 1579
+ "hiddenColumns", // 1580
+ "hiddenLevel", // 1581
+ "hiddenRow", // 1582
+ "hiddenRows", // 1583
+ "hiddenSlides", // 1584
+ "hideBot", // 1585
+ "hideGeom", // 1586
+ "hideGrammaticalErrors", // 1587
+ "hideLastTrans", // 1588
+ "hideLeft", // 1589
+ "hideMark", // 1590
+ "hideNewItems", // 1591
+ "hidePivotFieldList", // 1592
+ "hideRight", // 1593
+ "hideSpellingErrors", // 1594
+ "hideTop", // 1595
+ "hier", // 1596
+ "hierBranch", // 1597
+ "hierarchy", // 1598
+ "hierarchyUsage", // 1599
+ "highlight", // 1600
+ "highlightClick", // 1601
+ "hint", // 1602
+ "history", // 1603
+ "hlink", // 1604
+ "hlinkClick", // 1605
+ "hlinkHover", // 1606
+ "hlinkMouseOver", // 1607
+ "holeSize", // 1608
+ "horizontal", // 1609
+ "horizontalCentered", // 1610
+ "horizontalDpi", // 1611
+ "horzAnchor", // 1612
+ "horzBarState", // 1613
+ "horzOverflow", // 1614
+ "hour", // 1615
+ "how", // 1616
+ "hps", // 1617
+ "hpsBaseText", // 1618
+ "hpsRaise", // 1619
+ "hr", // 1620
+ "hralign", // 1621
+ "href", // 1622
+ "hrnoshade", // 1623
+ "hrpct", // 1624
+ "hrstd", // 1625
+ "hsl", // 1626
+ "hslClr", // 1627
+ "ht", // 1628
+ "htmlFormat", // 1629
+ "htmlPubPr", // 1630
+ "htmlTables", // 1631
+ "hue", // 1632
+ "hueDir", // 1633
+ "hueMod", // 1634
+ "hueOff", // 1635
+ "hyperlink", // 1636
+ "hyperlinks", // 1637
+ "hyphenationZone", // 1638
+ "i", // 1639
+ "i1", // 1640
+ "i2", // 1641
+ "i3", // 1642
+ "i4", // 1643
+ "i8", // 1644
+ "iCs", // 1645
+ "iLevel", // 1646
+ "iMeasureFld", // 1647
+ "iMeasureHier", // 1648
+ "icon", // 1649
+ "iconFilter", // 1650
+ "iconId", // 1651
+ "iconSet", // 1652
+ "id", // 1653
+ "idcntr", // 1654
+ "iddest", // 1655
+ "idmap", // 1656
+ "idref", // 1657
+ "idsrc", // 1658
+ "idx", // 1659
+ "if", // 1660
+ "ignoreMixedContent", // 1661
+ "ignoredError", // 1662
+ "ignoredErrors", // 1663
+ "ilvl", // 1664
+ "image", // 1665
+ "imagealignshape", // 1666
+ "imageaspect", // 1667
+ "imagedata", // 1668
+ "imagesize", // 1669
+ "imeMode", // 1670
+ "imgH", // 1671
+ "imgSz", // 1672
+ "imgW", // 1673
+ "immersive", // 1674
+ "imprint", // 1675
+ "in", // 1676
+ "includeHiddenRowCol", // 1677
+ "includeNewItemsInFilter", // 1678
+ "includePrintSettings", // 1679
+ "ind", // 1680
+ "indent", // 1681
+ "index", // 1682
+ "indexed", // 1683
+ "indexedColors", // 1684
+ "initials", // 1685
+ "ink", // 1686
+ "inkAnnotations", // 1687
+ "inkTgt", // 1688
+ "inline", // 1689
+ "innerShdw", // 1690
+ "inputCells", // 1691
+ "ins", // 1692
+ "insDel", // 1693
+ "insertBlankRow", // 1694
+ "insertColumns", // 1695
+ "insertHyperlinks", // 1696
+ "insertPageBreak", // 1697
+ "insertRow", // 1698
+ "insertRowShift", // 1699
+ "insertRows", // 1700
+ "inset", // 1701
+ "insetmode", // 1702
+ "insetpen", // 1703
+ "insetpenok", // 1704
+ "insideH", // 1705
+ "insideV", // 1706
+ "instr", // 1707
+ "instrText", // 1708
+ "int", // 1709
+ "intLim", // 1710
+ "intVal", // 1711
+ "integer", // 1712
+ "interSp", // 1713
+ "intercept", // 1714
+ "intermediate", // 1715
+ "interval", // 1716
+ "intraSp", // 1717
+ "inv", // 1718
+ "invGamma", // 1719
+ "invalEndChars", // 1720
+ "invalStChars", // 1721
+ "invalid", // 1722
+ "invalidUrl", // 1723
+ "invertIfNegative", // 1724
+ "invx", // 1725
+ "invy", // 1726
+ "is", // 1727
+ "isLgl", // 1728
+ "isNarration", // 1729
+ "isPhoto", // 1730
+ "iscomment", // 1731
+ "issignatureline", // 1732
+ "italic", // 1733
+ "item", // 1734
+ "itemID", // 1735
+ "itemPageCount", // 1736
+ "itemPrintTitles", // 1737
+ "items", // 1738
+ "iterate", // 1739
+ "iterateCount", // 1740
+ "iterateDelta", // 1741
+ "jc", // 1742
+ "joinstyle", // 1743
+ "justifyLastLine", // 1744
+ "k", // 1745
+ "keepAlive", // 1746
+ "keepChangeHistory", // 1747
+ "keepLines", // 1748
+ "keepNext", // 1749
+ "kern", // 1750
+ "key", // 1751
+ "keyAttribute", // 1752
+ "kinsoku", // 1753
+ "kiosk", // 1754
+ "kpi", // 1755
+ "kpis", // 1756
+ "kumimoji", // 1757
+ "kx", // 1758
+ "ky", // 1759
+ "l", // 1760
+ "lBounds", // 1761
+ "lIns", // 1762
+ "lMargin", // 1763
+ "label", // 1764
+ "labelOnly", // 1765
+ "lang", // 1766
+ "lastClr", // 1767
+ "lastCol", // 1768
+ "lastEdited", // 1769
+ "lastGuid", // 1770
+ "lastIdx", // 1771
+ "lastRenderedPageBreak", // 1772
+ "lastRow", // 1773
+ "lastValue", // 1774
+ "lastView", // 1775
+ "lat", // 1776
+ "latentStyles", // 1777
+ "latin", // 1778
+ "latinLnBrk", // 1779
+ "layout", // 1780
+ "layoutDef", // 1781
+ "layoutDefHdr", // 1782
+ "layoutDefHdrLst", // 1783
+ "layoutInCell", // 1784
+ "layoutNode", // 1785
+ "layoutRawTableWidth", // 1786
+ "layoutTableRowsApart", // 1787
+ "layoutTarget", // 1788
+ "lblAlgn", // 1789
+ "lblOffset", // 1790
+ "leader", // 1791
+ "leaderLines", // 1792
+ "left", // 1793
+ "leftChars", // 1794
+ "leftFromText", // 1795
+ "leftLabels", // 1796
+ "legacy", // 1797
+ "legacyDrawing", // 1798
+ "legacyDrawingHF", // 1799
+ "legacyIndent", // 1800
+ "legacySpace", // 1801
+ "legend", // 1802
+ "legendEntry", // 1803
+ "legendPos", // 1804
+ "len", // 1805
+ "length", // 1806
+ "lengthspecified", // 1807
+ "level", // 1808
+ "lid", // 1809
+ "lightRig", // 1810
+ "lightface", // 1811
+ "lightharsh", // 1812
+ "lightharsh2", // 1813
+ "lightlevel", // 1814
+ "lightlevel2", // 1815
+ "lightposition", // 1816
+ "lightposition2", // 1817
+ "lim", // 1818
+ "limLoc", // 1819
+ "limLow", // 1820
+ "limLowPr", // 1821
+ "limUpp", // 1822
+ "limUppPr", // 1823
+ "limo", // 1824
+ "lin", // 1825
+ "linClrLst", // 1826
+ "line", // 1827
+ "line3DChart", // 1828
+ "lineChart", // 1829
+ "linePitch", // 1830
+ "lineRule", // 1831
+ "lineTo", // 1832
+ "lineWrapLikeWord6", // 1833
+ "lines", // 1834
+ "linestyle", // 1835
+ "link", // 1836
+ "linkStyles", // 1837
+ "linkTarget", // 1838
+ "linkToQuery", // 1839
+ "linkedToFile", // 1840
+ "listDataValidation", // 1841
+ "listEntry", // 1842
+ "listItem", // 1843
+ "listSeparator", // 1844
+ "lit", // 1845
+ "lkTxEntry", // 1846
+ "ln", // 1847
+ "lnB", // 1848
+ "lnBlToTr", // 1849
+ "lnDef", // 1850
+ "lnL", // 1851
+ "lnNumType", // 1852
+ "lnR", // 1853
+ "lnRef", // 1854
+ "lnSpc", // 1855
+ "lnSpcReduction", // 1856
+ "lnStyleLst", // 1857
+ "lnT", // 1858
+ "lnTlToBr", // 1859
+ "lnTo", // 1860
+ "lo", // 1861
+ "loCatId", // 1862
+ "loTypeId", // 1863
+ "local", // 1864
+ "localConnection", // 1865
+ "localRefresh", // 1866
+ "localSheetId", // 1867
+ "location", // 1868
+ "lock", // 1869
+ "lockRevision", // 1870
+ "lockStructure", // 1871
+ "lockWindows", // 1872
+ "locked", // 1873
+ "lockedCanvas", // 1874
+ "lockrotationcenter", // 1875
+ "logBase", // 1876
+ "lon", // 1877
+ "longFileNames", // 1878
+ "longText", // 1879
+ "loop", // 1880
+ "lowestEdited", // 1881
+ "lpstr", // 1882
+ "lpwstr", // 1883
+ "lsdException", // 1884
+ "lstStyle", // 1885
+ "lt1", // 1886
+ "lt2", // 1887
+ "lum", // 1888
+ "lumMod", // 1889
+ "lumOff", // 1890
+ "lvl", // 1891
+ "lvl1pPr", // 1892
+ "lvl2pPr", // 1893
+ "lvl3pPr", // 1894
+ "lvl4pPr", // 1895
+ "lvl5pPr", // 1896
+ "lvl6pPr", // 1897
+ "lvl7pPr", // 1898
+ "lvl8pPr", // 1899
+ "lvl9pPr", // 1900
+ "lvlJc", // 1901
+ "lvlOverride", // 1902
+ "lvlPicBulletId", // 1903
+ "lvlRestart", // 1904
+ "lvlText", // 1905
+ "m", // 1906
+ "mPr", // 1907
+ "macro", // 1908
+ "mailAsAttachment", // 1909
+ "mailMerge", // 1910
+ "mailSubject", // 1911
+ "main", // 1912
+ "mainDocumentType", // 1913
+ "majorFont", // 1914
+ "majorGridlines", // 1915
+ "majorTickMark", // 1916
+ "majorTimeUnit", // 1917
+ "majorUnit", // 1918
+ "man", // 1919
+ "manifestLocation", // 1920
+ "manualBreakCount", // 1921
+ "manualLayout", // 1922
+ "map", // 1923
+ "mapId", // 1924
+ "mappedName", // 1925
+ "mappingCount", // 1926
+ "maps", // 1927
+ "marB", // 1928
+ "marBottom", // 1929
+ "marH", // 1930
+ "marL", // 1931
+ "marLeft", // 1932
+ "marR", // 1933
+ "marRight", // 1934
+ "marT", // 1935
+ "marTop", // 1936
+ "marW", // 1937
+ "marker", // 1938
+ "markup", // 1939
+ "master", // 1940
+ "masterClrMapping", // 1941
+ "masterRel", // 1942
+ "matchSrc", // 1943
+ "matchingName", // 1944
+ "mathFont", // 1945
+ "mathPr", // 1946
+ "matrix", // 1947
+ "max", // 1948
+ "maxAng", // 1949
+ "maxDate", // 1950
+ "maxDist", // 1951
+ "maxLength", // 1952
+ "maxR", // 1953
+ "maxRId", // 1954
+ "maxRank", // 1955
+ "maxSheetId", // 1956
+ "maxSubtotal", // 1957
+ "maxVal", // 1958
+ "maxValue", // 1959
+ "maxX", // 1960
+ "maxY", // 1961
+ "maximized", // 1962
+ "mc", // 1963
+ "mcJc", // 1964
+ "mcPr", // 1965
+ "mcs", // 1966
+ "mdx", // 1967
+ "mdxMetadata", // 1968
+ "mdxSubqueries", // 1969
+ "measure", // 1970
+ "measureFilter", // 1971
+ "measureGroup", // 1972
+ "measureGroups", // 1973
+ "measures", // 1974
+ "member", // 1975
+ "memberName", // 1976
+ "memberPropertyField", // 1977
+ "memberValueDatatype", // 1978
+ "members", // 1979
+ "merge", // 1980
+ "mergeCell", // 1981
+ "mergeCells", // 1982
+ "mergeInterval", // 1983
+ "mergeItem", // 1984
+ "metadata", // 1985
+ "metadataStrings", // 1986
+ "metadataType", // 1987
+ "metadataTypes", // 1988
+ "metal", // 1989
+ "meth", // 1990
+ "method", // 1991
+ "min", // 1992
+ "minAng", // 1993
+ "minDate", // 1994
+ "minLength", // 1995
+ "minR", // 1996
+ "minRId", // 1997
+ "minRefreshableVersion", // 1998
+ "minSubtotal", // 1999
+ "minSupportedVersion", // 2000
+ "minValue", // 2001
+ "minVer", // 2002
+ "minX", // 2003
+ "minY", // 2004
+ "minimized", // 2005
+ "minimumVersion", // 2006
+ "minorFont", // 2007
+ "minorGridlines", // 2008
+ "minorTickMark", // 2009
+ "minorTimeUnit", // 2010
+ "minorUnit", // 2011
+ "minus", // 2012
+ "minusx", // 2013
+ "minusy", // 2014
+ "minute", // 2015
+ "mirrorIndents", // 2016
+ "mirrorMargins", // 2017
+ "missingCaption", // 2018
+ "missingItemsLimit", // 2019
+ "miter", // 2020
+ "miterlimit", // 2021
+ "mod", // 2022
+ "modelId", // 2023
+ "modifyVerifier", // 2024
+ "month", // 2025
+ "monthLong", // 2026
+ "monthShort", // 2027
+ "moveFrom", // 2028
+ "moveFromRangeEnd", // 2029
+ "moveFromRangeStart", // 2030
+ "moveTo", // 2031
+ "moveToRangeEnd", // 2032
+ "moveToRangeStart", // 2033
+ "moveWith", // 2034
+ "movie", // 2035
+ "mp", // 2036
+ "mpFld", // 2037
+ "mpMap", // 2038
+ "mps", // 2039
+ "mr", // 2040
+ "mruColors", // 2041
+ "ms", // 2042
+ "multiLevelType", // 2043
+ "multiLine", // 2044
+ "multiLvlStrCache", // 2045
+ "multiLvlStrRef", // 2046
+ "multipleFieldFilters", // 2047
+ "multipleItemSelectionAllowed", // 2048
+ "mute", // 2049
+ "mwSmallCaps", // 2050
+ "n", // 2051
+ "name", // 2052
+ "nameLen", // 2053
+ "namespaceUri", // 2054
+ "namespaceuri", // 2055
+ "nary", // 2056
+ "naryLim", // 2057
+ "naryPr", // 2058
+ "nc", // 2059
+ "ndxf", // 2060
+ "neCell", // 2061
+ "new", // 2062
+ "newLength", // 2063
+ "newName", // 2064
+ "newsflash", // 2065
+ "next", // 2066
+ "nextAc", // 2067
+ "nextCondLst", // 2068
+ "nextId", // 2069
+ "nf", // 2070
+ "nlCheck", // 2071
+ "noAdjustHandles", // 2072
+ "noAutofit", // 2073
+ "noBorder", // 2074
+ "noBreak", // 2075
+ "noBreakHyphen", // 2076
+ "noChangeArrowheads", // 2077
+ "noChangeAspect", // 2078
+ "noChangeShapeType", // 2079
+ "noColumnBalance", // 2080
+ "noCrop", // 2081
+ "noDrilldown", // 2082
+ "noEditPoints", // 2083
+ "noEndCap", // 2084
+ "noEndnote", // 2085
+ "noExtraLineSpacing", // 2086
+ "noFill", // 2087
+ "noGrp", // 2088
+ "noLabel", // 2089
+ "noLeading", // 2090
+ "noLineBreaksAfter", // 2091
+ "noLineBreaksBefore", // 2092
+ "noMove", // 2093
+ "noMultiLvlLbl", // 2094
+ "noProof", // 2095
+ "noPunctuationKerning", // 2096
+ "noResize", // 2097
+ "noResizeAllowed", // 2098
+ "noRot", // 2099
+ "noSelect", // 2100
+ "noSpaceRaiseLower", // 2101
+ "noTabHangInd", // 2102
+ "noTextEdit", // 2103
+ "noUngrp", // 2104
+ "noWrap", // 2105
+ "nodePh", // 2106
+ "nodeType", // 2107
+ "nonAutoSortDefault", // 2108
+ "nor", // 2109
+ "norm", // 2110
+ "normAutofit", // 2111
+ "normalViewPr", // 2112
+ "normalizeH", // 2113
+ "notTrueType", // 2114
+ "notes", // 2115
+ "notesMaster", // 2116
+ "notesMasterId", // 2117
+ "notesMasterIdLst", // 2118
+ "notesStyle", // 2119
+ "notesSz", // 2120
+ "notesTextViewPr", // 2121
+ "notesViewPr", // 2122
+ "np", // 2123
+ "ns", // 2124
+ "nsid", // 2125
+ "null", // 2126
+ "num", // 2127
+ "numCache", // 2128
+ "numCol", // 2129
+ "numFmt", // 2130
+ "numFmtId", // 2131
+ "numFmts", // 2132
+ "numId", // 2133
+ "numIdMacAtCleanup", // 2134
+ "numLit", // 2135
+ "numPicBullet", // 2136
+ "numPicBulletId", // 2137
+ "numPr", // 2138
+ "numRef", // 2139
+ "numRestart", // 2140
+ "numSld", // 2141
+ "numStart", // 2142
+ "numStyleLink", // 2143
+ "numberStoredAsText", // 2144
+ "numbering", // 2145
+ "numberingChange", // 2146
+ "nvCxnSpPr", // 2147
+ "nvGraphicFramePr", // 2148
+ "nvGrpSpPr", // 2149
+ "nvPicPr", // 2150
+ "nvPr", // 2151
+ "nvSpPr", // 2152
+ "nwCell", // 2153
+ "o", // 2154
+ "oMath", // 2155
+ "oMathPara", // 2156
+ "oMathParaPr", // 2157
+ "objDist", // 2158
+ "object", // 2159
+ "objectDefaults", // 2160
+ "objects", // 2161
+ "oblob", // 2162
+ "obscured", // 2163
+ "oc", // 2164
+ "odcFile", // 2165
+ "oddFooter", // 2166
+ "oddHeader", // 2167
+ "odso", // 2168
+ "odxf", // 2169
+ "ofPieChart", // 2170
+ "ofPieType", // 2171
+ "off", // 2172
+ "offset", // 2173
+ "offset2", // 2174
+ "offsetFrom", // 2175
+ "olapPr", // 2176
+ "old", // 2177
+ "oldComment", // 2178
+ "oldCustomMenu", // 2179
+ "oldDescription", // 2180
+ "oldFormula", // 2181
+ "oldFunction", // 2182
+ "oldFunctionGroupId", // 2183
+ "oldHelp", // 2184
+ "oldHidden", // 2185
+ "oldLength", // 2186
+ "oldName", // 2187
+ "oldPh", // 2188
+ "oldQuotePrefix", // 2189
+ "oldShortcutKey", // 2190
+ "oldStatusBar", // 2191
+ "ole", // 2192
+ "oleChartEl", // 2193
+ "oleItem", // 2194
+ "oleItems", // 2195
+ "oleLink", // 2196
+ "oleObj", // 2197
+ "oleObject", // 2198
+ "oleObjects", // 2199
+ "oleSize", // 2200
+ "oleUpdate", // 2201
+ "oleicon", // 2202
+ "oleid", // 2203
+ "on", // 2204
+ "oneCellAnchor", // 2205
+ "oneField", // 2206
+ "oned", // 2207
+ "onlySync", // 2208
+ "onlyUseConnectionFile", // 2209
+ "op", // 2210
+ "opEmu", // 2211
+ "opacity", // 2212
+ "opacity2", // 2213
+ "operator", // 2214
+ "optimizeForBrowser", // 2215
+ "optimizeMemory", // 2216
+ "order", // 2217
+ "orgChart", // 2218
+ "organizeInFolders", // 2219
+ "orient", // 2220
+ "orientation", // 2221
+ "orientationangle", // 2222
+ "origin", // 2223
+ "original", // 2224
+ "ostorage", // 2225
+ "ostream", // 2226
+ "other", // 2227
+ "otherStyle", // 2228
+ "outerShdw", // 2229
+ "outline", // 2230
+ "outlineData", // 2231
+ "outlineLevel", // 2232
+ "outlineLevelCol", // 2233
+ "outlineLevelRow", // 2234
+ "outlineLvl", // 2235
+ "outlinePr", // 2236
+ "outlineSymbols", // 2237
+ "outlineViewPr", // 2238
+ "oval", // 2239
+ "overflowPunct", // 2240
+ "overlap", // 2241
+ "overlay", // 2242
+ "override", // 2243
+ "overrideClrMapping", // 2244
+ "p", // 2245
+ "pBdr", // 2246
+ "pLen", // 2247
+ "pPos", // 2248
+ "pPr", // 2249
+ "pPrChange", // 2250
+ "pPrDefault", // 2251
+ "pRg", // 2252
+ "pStyle", // 2253
+ "page", // 2254
+ "pageBreakBefore", // 2255
+ "pageField", // 2256
+ "pageFields", // 2257
+ "pageItem", // 2258
+ "pageMargins", // 2259
+ "pageOrder", // 2260
+ "pageOverThenDown", // 2261
+ "pageSetUpPr", // 2262
+ "pageSetup", // 2263
+ "pageStyle", // 2264
+ "pageWrap", // 2265
+ "pages", // 2266
+ "pane", // 2267
+ "panose", // 2268
+ "panose1", // 2269
+ "paperSize", // 2270
+ "paperSrc", // 2271
+ "par", // 2272
+ "parTransId", // 2273
+ "param", // 2274
+ "parameter", // 2275
+ "parameterType", // 2276
+ "parameters", // 2277
+ "parent", // 2278
+ "parentSet", // 2279
+ "parsePre", // 2280
+ "password", // 2281
+ "pasteAll", // 2282
+ "pasteBorders", // 2283
+ "pasteColWidths", // 2284
+ "pasteComments", // 2285
+ "pasteDataValidation", // 2286
+ "pasteFormats", // 2287
+ "pasteFormulas", // 2288
+ "pasteNumberFormats", // 2289
+ "pasteValues", // 2290
+ "path", // 2291
+ "pathEditMode", // 2292
+ "pathLst", // 2293
+ "pattFill", // 2294
+ "patternFill", // 2295
+ "patternType", // 2296
+ "penClr", // 2297
+ "percent", // 2298
+ "period", // 2299
+ "permEnd", // 2300
+ "permStart", // 2301
+ "personal", // 2302
+ "personalCompose", // 2303
+ "personalReply", // 2304
+ "personalView", // 2305
+ "perspective", // 2306
+ "pgBorders", // 2307
+ "pgMar", // 2308
+ "pgNum", // 2309
+ "pgNumType", // 2310
+ "pgSz", // 2311
+ "ph", // 2312
+ "phant", // 2313
+ "phantPr", // 2314
+ "phldr", // 2315
+ "phldrT", // 2316
+ "phonetic", // 2317
+ "phoneticPr", // 2318
+ "photoAlbum", // 2319
+ "pic", // 2320
+ "picLocks", // 2321
+ "pict", // 2322
+ "picture", // 2323
+ "pictureFormat", // 2324
+ "pictureOptions", // 2325
+ "pictureStackUnit", // 2326
+ "pid", // 2327
+ "pie3DChart", // 2328
+ "pieChart", // 2329
+ "pitch", // 2330
+ "pitchFamily", // 2331
+ "pivot", // 2332
+ "pivotArea", // 2333
+ "pivotAreas", // 2334
+ "pivotButton", // 2335
+ "pivotCache", // 2336
+ "pivotCacheDefinition", // 2337
+ "pivotCacheRecords", // 2338
+ "pivotCaches", // 2339
+ "pivotField", // 2340
+ "pivotFields", // 2341
+ "pivotFmt", // 2342
+ "pivotFmts", // 2343
+ "pivotHierarchies", // 2344
+ "pivotHierarchy", // 2345
+ "pivotSelection", // 2346
+ "pivotSource", // 2347
+ "pivotTableDefinition", // 2348
+ "pivotTableStyle", // 2349
+ "pivotTableStyleInfo", // 2350
+ "pivotTables", // 2351
+ "pixelsPerInch", // 2352
+ "placeholder", // 2353
+ "plane", // 2354
+ "plcHide", // 2355
+ "plotArea", // 2356
+ "plotVisOnly", // 2357
+ "plus", // 2358
+ "points", // 2359
+ "polar", // 2360
+ "polyline", // 2361
+ "pos", // 2362
+ "posOffset", // 2363
+ "position", // 2364
+ "positionH", // 2365
+ "positionV", // 2366
+ "post", // 2367
+ "postSp", // 2368
+ "prLst", // 2369
+ "prSet", // 2370
+ "preSp", // 2371
+ "preferPic", // 2372
+ "preferRelativeResize", // 2373
+ "preferSingleView", // 2374
+ "preferrelative", // 2375
+ "prefixMappings", // 2376
+ "presAssocID", // 2377
+ "presId", // 2378
+ "presLayoutVars", // 2379
+ "presName", // 2380
+ "presOf", // 2381
+ "presStyleCnt", // 2382
+ "presStyleIdx", // 2383
+ "presStyleLbl", // 2384
+ "present", // 2385
+ "presentation", // 2386
+ "presentationPr", // 2387
+ "preserve", // 2388
+ "preserveFormatting", // 2389
+ "preserveHistory", // 2390
+ "preserveSortFilterLayout", // 2391
+ "presetClass", // 2392
+ "presetID", // 2393
+ "presetSubtype", // 2394
+ "prevAc", // 2395
+ "prevCondLst", // 2396
+ "previousCol", // 2397
+ "previousRow", // 2398
+ "pri", // 2399
+ "print", // 2400
+ "printArea", // 2401
+ "printBodyTextBeforeHeader", // 2402
+ "printColBlack", // 2403
+ "printDrill", // 2404
+ "printFormsData", // 2405
+ "printFractionalCharacterWidth", // 2406
+ "printOptions", // 2407
+ "printPostScriptOverText", // 2408
+ "printSettings", // 2409
+ "printTwoOnOne", // 2410
+ "printerSettings", // 2411
+ "priority", // 2412
+ "prnPr", // 2413
+ "prnWhat", // 2414
+ "productSubtotal", // 2415
+ "progId", // 2416
+ "progress", // 2417
+ "prompt", // 2418
+ "promptTitle", // 2419
+ "promptedSolutions", // 2420
+ "proofErr", // 2421
+ "proofState", // 2422
+ "property", // 2423
+ "propertyName", // 2424
+ "protected", // 2425
+ "protectedRange", // 2426
+ "protectedRanges", // 2427
+ "protection", // 2428
+ "provid", // 2429
+ "proxy", // 2430
+ "prst", // 2431
+ "prstClr", // 2432
+ "prstDash", // 2433
+ "prstGeom", // 2434
+ "prstMaterial", // 2435
+ "prstShdw", // 2436
+ "prstTxWarp", // 2437
+ "pt", // 2438
+ "ptCount", // 2439
+ "ptLst", // 2440
+ "ptType", // 2441
+ "ptab", // 2442
+ "ptsTypes", // 2443
+ "pubBrowser", // 2444
+ "publishItems", // 2445
+ "publishToServer", // 2446
+ "published", // 2447
+ "pull", // 2448
+ "push", // 2449
+ "qFormat", // 2450
+ "qs", // 2451
+ "qsCatId", // 2452
+ "qsTypeId", // 2453
+ "quadBezTo", // 2454
+ "qualifier", // 2455
+ "query", // 2456
+ "queryCache", // 2457
+ "queryFailed", // 2458
+ "queryTable", // 2459
+ "queryTableDeletedFields", // 2460
+ "queryTableField", // 2461
+ "queryTableFieldId", // 2462
+ "queryTableFields", // 2463
+ "queryTableRefresh", // 2464
+ "quickTimeFile", // 2465
+ "quotePrefix", // 2466
+ "r", // 2467
+ "r1", // 2468
+ "r2", // 2469
+ "r4", // 2470
+ "r8", // 2471
+ "rAng", // 2472
+ "rAngAx", // 2473
+ "rCtr", // 2474
+ "rFont", // 2475
+ "rFonts", // 2476
+ "rId", // 2477
+ "rIns", // 2478
+ "rMargin", // 2479
+ "rPh", // 2480
+ "rPr", // 2481
+ "rPrChange", // 2482
+ "rPrDefault", // 2483
+ "rSp", // 2484
+ "rSpRule", // 2485
+ "rStyle", // 2486
+ "ra", // 2487
+ "rad", // 2488
+ "radPr", // 2489
+ "radarChart", // 2490
+ "radarStyle", // 2491
+ "radiusrange", // 2492
+ "raf", // 2493
+ "random", // 2494
+ "randomBar", // 2495
+ "rangePr", // 2496
+ "rangeSet", // 2497
+ "rangeSets", // 2498
+ "rank", // 2499
+ "rankBy", // 2500
+ "rc", // 2501
+ "rcc", // 2502
+ "rcft", // 2503
+ "rcmt", // 2504
+ "rctx", // 2505
+ "rcv", // 2506
+ "rdn", // 2507
+ "readModeInkLockDown", // 2508
+ "readOnlyRecommended", // 2509
+ "readingOrder", // 2510
+ "recipientData", // 2511
+ "recipients", // 2512
+ "recolor", // 2513
+ "recolortarget", // 2514
+ "recommended", // 2515
+ "reconnectionMethod", // 2516
+ "recordCount", // 2517
+ "rect", // 2518
+ "red", // 2519
+ "redMod", // 2520
+ "redOff", // 2521
+ "ref", // 2522
+ "ref3D", // 2523
+ "refFor", // 2524
+ "refForName", // 2525
+ "refMode", // 2526
+ "refPtType", // 2527
+ "refType", // 2528
+ "reference", // 2529
+ "references", // 2530
+ "refersTo", // 2531
+ "reflection", // 2532
+ "refreshAllConnections", // 2533
+ "refreshError", // 2534
+ "refreshOnChange", // 2535
+ "refreshOnLoad", // 2536
+ "refreshedBy", // 2537
+ "refreshedDate", // 2538
+ "refreshedVersion", // 2539
+ "regroupid", // 2540
+ "regrouptable", // 2541
+ "regular", // 2542
+ "rel", // 2543
+ "relIds", // 2544
+ "relOff", // 2545
+ "relSizeAnchor", // 2546
+ "relation", // 2547
+ "relationtable", // 2548
+ "relative", // 2549
+ "relativeFrom", // 2550
+ "relativeHeight", // 2551
+ "relativeIndent", // 2552
+ "relativeTo", // 2553
+ "relid", // 2554
+ "relyOnVML", // 2555
+ "relyOnVml", // 2556
+ "removeDataOnSave", // 2557
+ "removeDateAndTime", // 2558
+ "removePersonalInfoOnSave", // 2559
+ "removePersonalInformation", // 2560
+ "render", // 2561
+ "repairLoad", // 2562
+ "repeatCount", // 2563
+ "repeatDur", // 2564
+ "resId", // 2565
+ "reservationPassword", // 2566
+ "resizeGraphics", // 2567
+ "resizeHandles", // 2568
+ "restart", // 2569
+ "restoredLeft", // 2570
+ "restoredTop", // 2571
+ "result", // 2572
+ "rev", // 2573
+ "reverse", // 2574
+ "reviewed", // 2575
+ "reviewedList", // 2576
+ "revisionId", // 2577
+ "revisionView", // 2578
+ "revisions", // 2579
+ "revisionsPassword", // 2580
+ "rfmt", // 2581
+ "rgb", // 2582
+ "rgbColor", // 2583
+ "rich", // 2584
+ "richText", // 2585
+ "rig", // 2586
+ "right", // 2587
+ "rightChars", // 2588
+ "rightFromText", // 2589
+ "rightToLeft", // 2590
+ "ris", // 2591
+ "rm", // 2592
+ "rot", // 2593
+ "rotWithShape", // 2594
+ "rotX", // 2595
+ "rotY", // 2596
+ "rotate", // 2597
+ "rotation", // 2598
+ "rotationangle", // 2599
+ "rotationcenter", // 2600
+ "round", // 2601
+ "roundedCorners", // 2602
+ "roundrect", // 2603
+ "row", // 2604
+ "rowBreaks", // 2605
+ "rowColShift", // 2606
+ "rowDrillCount", // 2607
+ "rowFields", // 2608
+ "rowGrandTotals", // 2609
+ "rowHeaderCaption", // 2610
+ "rowHierarchiesUsage", // 2611
+ "rowHierarchyUsage", // 2612
+ "rowItems", // 2613
+ "rowNumbers", // 2614
+ "rowOff", // 2615
+ "rowPageCount", // 2616
+ "rowSpan", // 2617
+ "rows", // 2618
+ "rqt", // 2619
+ "rrc", // 2620
+ "rsid", // 2621
+ "rsidDel", // 2622
+ "rsidP", // 2623
+ "rsidR", // 2624
+ "rsidRDefault", // 2625
+ "rsidRPr", // 2626
+ "rsidRoot", // 2627
+ "rsidSect", // 2628
+ "rsidTr", // 2629
+ "rsids", // 2630
+ "rsnm", // 2631
+ "rt", // 2632
+ "rtl", // 2633
+ "rtlCol", // 2634
+ "rtlGutter", // 2635
+ "rtn", // 2636
+ "ruby", // 2637
+ "rubyAlign", // 2638
+ "rubyBase", // 2639
+ "rubyPr", // 2640
+ "rule", // 2641
+ "ruleLst", // 2642
+ "rules", // 2643
+ "rupBuild", // 2644
+ "s", // 2645
+ "sId", // 2646
+ "sPre", // 2647
+ "sPrePr", // 2648
+ "sSub", // 2649
+ "sSubPr", // 2650
+ "sSubSup", // 2651
+ "sSubSupPr", // 2652
+ "sSup", // 2653
+ "sSupPr", // 2654
+ "salt", // 2655
+ "saltData", // 2656
+ "sampData", // 2657
+ "sat", // 2658
+ "satMod", // 2659
+ "satOff", // 2660
+ "saveData", // 2661
+ "saveExternalLinkValues", // 2662
+ "saveFormsData", // 2663
+ "saveInvalidXml", // 2664
+ "savePassword", // 2665
+ "savePreviewPicture", // 2666
+ "saveSmartTagsAsXml", // 2667
+ "saveSubsetFonts", // 2668
+ "saveThroughXslt", // 2669
+ "saveXmlDataOnly", // 2670
+ "sb", // 2671
+ "scale", // 2672
+ "scaleToFitPaper", // 2673
+ "scaleWithDoc", // 2674
+ "scaled", // 2675
+ "scaling", // 2676
+ "scatterChart", // 2677
+ "scatterStyle", // 2678
+ "scenario", // 2679
+ "scenarios", // 2680
+ "scene3d", // 2681
+ "schema", // 2682
+ "schemaLibrary", // 2683
+ "schemaLocation", // 2684
+ "schemaRef", // 2685
+ "schemaRefs", // 2686
+ "scheme", // 2687
+ "schemeClr", // 2688
+ "scope", // 2689
+ "scr", // 2690
+ "scrgbClr", // 2691
+ "script", // 2692
+ "scrollbar", // 2693
+ "sd", // 2694
+ "sdt", // 2695
+ "sdtContent", // 2696
+ "sdtEndPr", // 2697
+ "sdtPr", // 2698
+ "seCell", // 2699
+ "second", // 2700
+ "secondPiePt", // 2701
+ "secondPieSize", // 2702
+ "sectPr", // 2703
+ "sectPrChange", // 2704
+ "securityDescriptor", // 2705
+ "selectFldWithFirstOrLastChar", // 2706
+ "selectLockedCells", // 2707
+ "selectUnlockedCells", // 2708
+ "selected", // 2709
+ "selection", // 2710
+ "semiHidden", // 2711
+ "semicolon", // 2712
+ "sendLocale", // 2713
+ "sep", // 2714
+ "sepChr", // 2715
+ "separator", // 2716
+ "seq", // 2717
+ "ser", // 2718
+ "serAx", // 2719
+ "serLines", // 2720
+ "series", // 2721
+ "seriesIdx", // 2722
+ "serverCommand", // 2723
+ "serverField", // 2724
+ "serverFill", // 2725
+ "serverFont", // 2726
+ "serverFontColor", // 2727
+ "serverFormat", // 2728
+ "serverFormats", // 2729
+ "serverNumberFormat", // 2730
+ "serverSldId", // 2731
+ "serverSldModifiedTime", // 2732
+ "serverZoom", // 2733
+ "set", // 2734
+ "setDefinition", // 2735
+ "sets", // 2736
+ "settings", // 2737
+ "shade", // 2738
+ "shadeToTitle", // 2739
+ "shadow", // 2740
+ "shadowcolor", // 2741
+ "shadowok", // 2742
+ "shape", // 2743
+ "shapeDefaults", // 2744
+ "shapeId", // 2745
+ "shapeLayoutLikeWW8", // 2746
+ "shapedefaults", // 2747
+ "shapeid", // 2748
+ "shapelayout", // 2749
+ "shapetype", // 2750
+ "shared", // 2751
+ "sharedItems", // 2752
+ "shd", // 2753
+ "sheet", // 2754
+ "sheetCalcPr", // 2755
+ "sheetData", // 2756
+ "sheetDataSet", // 2757
+ "sheetFormatPr", // 2758
+ "sheetId", // 2759
+ "sheetIdMap", // 2760
+ "sheetName", // 2761
+ "sheetNames", // 2762
+ "sheetPosition", // 2763
+ "sheetPr", // 2764
+ "sheetProtection", // 2765
+ "sheetView", // 2766
+ "sheetViews", // 2767
+ "sheets", // 2768
+ "shininess", // 2769
+ "shortcutKey", // 2770
+ "show", // 2771
+ "showAll", // 2772
+ "showAnimation", // 2773
+ "showAsCaption", // 2774
+ "showAsIcon", // 2775
+ "showAutoFilter", // 2776
+ "showBorderUnselectedTables", // 2777
+ "showBreaksInFrames", // 2778
+ "showBubbleSize", // 2779
+ "showButton", // 2780
+ "showCalcMbrs", // 2781
+ "showCaptions", // 2782
+ "showCatName", // 2783
+ "showCell", // 2784
+ "showColHeaders", // 2785
+ "showColStripes", // 2786
+ "showColumnStripes", // 2787
+ "showComments", // 2788
+ "showDLblsOverMax", // 2789
+ "showDataAs", // 2790
+ "showDataDropDown", // 2791
+ "showDataTips", // 2792
+ "showDrill", // 2793
+ "showDropDown", // 2794
+ "showDropDowns", // 2795
+ "showDropZones", // 2796
+ "showEmptyCol", // 2797
+ "showEmptyRow", // 2798
+ "showEnvelope", // 2799
+ "showError", // 2800
+ "showErrorMessage", // 2801
+ "showFirstColumn", // 2802
+ "showFormatting", // 2803
+ "showFormulaBar", // 2804
+ "showFormulas", // 2805
+ "showGridLines", // 2806
+ "showGuides", // 2807
+ "showHeader", // 2808
+ "showHeaders", // 2809
+ "showHorizontalScroll", // 2810
+ "showHorzBorder", // 2811
+ "showInFieldList", // 2812
+ "showInkAnnotation", // 2813
+ "showInputMessage", // 2814
+ "showItems", // 2815
+ "showKeys", // 2816
+ "showLastColumn", // 2817
+ "showLeaderLines", // 2818
+ "showLegendKey", // 2819
+ "showMasterPhAnim", // 2820
+ "showMasterSp", // 2821
+ "showMemberPropertyTips", // 2822
+ "showMissing", // 2823
+ "showMultipleLabel", // 2824
+ "showNarration", // 2825
+ "showNegBubbles", // 2826
+ "showObjects", // 2827
+ "showOutline", // 2828
+ "showOutlineIcons", // 2829
+ "showOutlineSymbols", // 2830
+ "showPageBreaks", // 2831
+ "showPercent", // 2832
+ "showPivotChartFilter", // 2833
+ "showPr", // 2834
+ "showPropAsCaption", // 2835
+ "showPropCell", // 2836
+ "showPropTip", // 2837
+ "showRowCol", // 2838
+ "showRowColHeaders", // 2839
+ "showRowHeaders", // 2840
+ "showRowStripes", // 2841
+ "showRuler", // 2842
+ "showScrollbar", // 2843
+ "showSerName", // 2844
+ "showSheetTabs", // 2845
+ "showSpeakerNotes", // 2846
+ "showSpecialPlsOnTitleSld", // 2847
+ "showStatusbar", // 2848
+ "showTip", // 2849
+ "showVal", // 2850
+ "showValue", // 2851
+ "showVertBorder", // 2852
+ "showVerticalScroll", // 2853
+ "showWhenStopped", // 2854
+ "showWhiteSpace", // 2855
+ "showXMLTags", // 2856
+ "showZeros", // 2857
+ "showingPlcHdr", // 2858
+ "showsigndate", // 2859
+ "shp", // 2860
+ "shrinkToFit", // 2861
+ "si", // 2862
+ "sibTransId", // 2863
+ "side", // 2864
+ "sideWall", // 2865
+ "sig", // 2866
+ "signatureline", // 2867
+ "signinginstructions", // 2868
+ "signinginstructionsset", // 2869
+ "sigprovurl", // 2870
+ "simplePos", // 2871
+ "singleSignOnId", // 2872
+ "singleXmlCell", // 2873
+ "singleXmlCells", // 2874
+ "singleclick", // 2875
+ "size", // 2876
+ "sizeAuto", // 2877
+ "sizeRepresents", // 2878
+ "skew", // 2879
+ "skewamt", // 2880
+ "skewangle", // 2881
+ "sld", // 2882
+ "sldAll", // 2883
+ "sldId", // 2884
+ "sldIdLst", // 2885
+ "sldLayout", // 2886
+ "sldLayoutId", // 2887
+ "sldLayoutIdLst", // 2888
+ "sldLst", // 2889
+ "sldMaster", // 2890
+ "sldMasterId", // 2891
+ "sldMasterIdLst", // 2892
+ "sldNum", // 2893
+ "sldRg", // 2894
+ "sldSyncPr", // 2895
+ "sldSz", // 2896
+ "sldTgt", // 2897
+ "slideViewPr", // 2898
+ "smallCaps", // 2899
+ "smallFrac", // 2900
+ "smartTag", // 2901
+ "smartTagPr", // 2902
+ "smartTagType", // 2903
+ "smartTagTypes", // 2904
+ "smartTags", // 2905
+ "smooth", // 2906
+ "smtClean", // 2907
+ "smtId", // 2908
+ "snapToGrid", // 2909
+ "snapToObjects", // 2910
+ "snapVertSplitter", // 2911
+ "snd", // 2912
+ "sndAc", // 2913
+ "sndTgt", // 2914
+ "softEdge", // 2915
+ "softHyphen", // 2916
+ "solidFill", // 2917
+ "solutionID", // 2918
+ "solveOrder", // 2919
+ "sort", // 2920
+ "sortBy", // 2921
+ "sortByTuple", // 2922
+ "sortCondition", // 2923
+ "sortMethod", // 2924
+ "sortState", // 2925
+ "sortType", // 2926
+ "sorterViewPr", // 2927
+ "source", // 2928
+ "sourceData", // 2929
+ "sourceFile", // 2930
+ "sourceFileName", // 2931
+ "sourceLinked", // 2932
+ "sourceObject", // 2933
+ "sourceRef", // 2934
+ "sourceSheetId", // 2935
+ "sourceType", // 2936
+ "sp", // 2937
+ "sp3d", // 2938
+ "spAutoFit", // 2939
+ "spDef", // 2940
+ "spLocks", // 2941
+ "spPr", // 2942
+ "spTgt", // 2943
+ "spTree", // 2944
+ "space", // 2945
+ "spaceForUL", // 2946
+ "spacing", // 2947
+ "spacingInWholePoints", // 2948
+ "spans", // 2949
+ "spc", // 2950
+ "spcAft", // 2951
+ "spcBef", // 2952
+ "spcCol", // 2953
+ "spcFirstLastPara", // 2954
+ "spcPct", // 2955
+ "spcPts", // 2956
+ "spd", // 2957
+ "specVanish", // 2958
+ "specularity", // 2959
+ "spelling", // 2960
+ "spid", // 2961
+ "spidmax", // 2962
+ "spinCount", // 2963
+ "split", // 2964
+ "splitAll", // 2965
+ "splitFirst", // 2966
+ "splitPgBreakAndParaMark", // 2967
+ "splitPos", // 2968
+ "splitType", // 2969
+ "spokes", // 2970
+ "spt", // 2971
+ "sqlType", // 2972
+ "sqref", // 2973
+ "src", // 2974
+ "srcId", // 2975
+ "srcOrd", // 2976
+ "srcRect", // 2977
+ "srgbClr", // 2978
+ "sst", // 2979
+ "st", // 2980
+ "stA", // 2981
+ "stAng", // 2982
+ "stCondLst", // 2983
+ "stCxn", // 2984
+ "stPos", // 2985
+ "stSnd", // 2986
+ "start", // 2987
+ "startAngle", // 2988
+ "startAt", // 2989
+ "startDate", // 2990
+ "startNum", // 2991
+ "startOverride", // 2992
+ "startarrow", // 2993
+ "startarrowlength", // 2994
+ "startarrowwidth", // 2995
+ "state", // 2996
+ "status", // 2997
+ "statusBar", // 2998
+ "statusText", // 2999
+ "stdDev", // 3000
+ "stdDevPSubtotal", // 3001
+ "stdDevSubtotal", // 3002
+ "step", // 3003
+ "stockChart", // 3004
+ "stop", // 3005
+ "stopIfTrue", // 3006
+ "storage", // 3007
+ "storeItemID", // 3008
+ "storeMappedDataAs", // 3009
+ "stp", // 3010
+ "strCache", // 3011
+ "strLit", // 3012
+ "strRef", // 3013
+ "strVal", // 3014
+ "stream", // 3015
+ "stretch", // 3016
+ "strictFirstAndLastChars", // 3017
+ "strike", // 3018
+ "strikeBLTR", // 3019
+ "strikeH", // 3020
+ "strikeTLBR", // 3021
+ "strikeV", // 3022
+ "string", // 3023
+ "stringValue1", // 3024
+ "stringValue2", // 3025
+ "strips", // 3026
+ "stroke", // 3027
+ "strokecolor", // 3028
+ "stroked", // 3029
+ "strokeok", // 3030
+ "strokeweight", // 3031
+ "sty", // 3032
+ "style", // 3033
+ "styleData", // 3034
+ "styleDef", // 3035
+ "styleDefHdr", // 3036
+ "styleDefHdrLst", // 3037
+ "styleId", // 3038
+ "styleLbl", // 3039
+ "styleLink", // 3040
+ "styleLockQFSet", // 3041
+ "styleLockTheme", // 3042
+ "styleName", // 3043
+ "stylePaneFormatFilter", // 3044
+ "stylePaneSortMethod", // 3045
+ "styleSheet", // 3046
+ "styles", // 3047
+ "sub", // 3048
+ "subDoc", // 3049
+ "subFontBySize", // 3050
+ "subHide", // 3051
+ "subSp", // 3052
+ "subTnLst", // 3053
+ "subsetted", // 3054
+ "subtotal", // 3055
+ "subtotalCaption", // 3056
+ "subtotalHiddenItems", // 3057
+ "subtotalTop", // 3058
+ "suff", // 3059
+ "suggestedsigner", // 3060
+ "suggestedsigner2", // 3061
+ "suggestedsigneremail", // 3062
+ "sumSubtotal", // 3063
+ "summaryBelow", // 3064
+ "summaryLength", // 3065
+ "summaryRight", // 3066
+ "sup", // 3067
+ "supHide", // 3068
+ "supportAdvancedDrill", // 3069
+ "supportSubquery", // 3070
+ "suppressAutoHyphens", // 3071
+ "suppressBottomSpacing", // 3072
+ "suppressLineNumbers", // 3073
+ "suppressOverlap", // 3074
+ "suppressSpBfAfterPgBrk", // 3075
+ "suppressSpacingAtTopOfPage", // 3076
+ "suppressTopSpacing", // 3077
+ "suppressTopSpacingWP", // 3078
+ "surface3DChart", // 3079
+ "surfaceChart", // 3080
+ "swAng", // 3081
+ "swCell", // 3082
+ "swapBordersFacingPages", // 3083
+ "switch", // 3084
+ "sx", // 3085
+ "sy", // 3086
+ "sym", // 3087
+ "symbol", // 3088
+ "syncBehavior", // 3089
+ "syncHorizontal", // 3090
+ "syncRef", // 3091
+ "syncVertical", // 3092
+ "sysClr", // 3093
+ "sz", // 3094
+ "szCs", // 3095
+ "t", // 3096
+ "t1", // 3097
+ "t2", // 3098
+ "tIns", // 3099
+ "tab", // 3100
+ "tabColor", // 3101
+ "tabLst", // 3102
+ "tabRatio", // 3103
+ "tabSelected", // 3104
+ "table", // 3105
+ "tableBorderDxfId", // 3106
+ "tableColumn", // 3107
+ "tableColumnId", // 3108
+ "tableColumns", // 3109
+ "tablePart", // 3110
+ "tableParts", // 3111
+ "tableStyle", // 3112
+ "tableStyleElement", // 3113
+ "tableStyleId", // 3114
+ "tableStyleInfo", // 3115
+ "tableStyles", // 3116
+ "tableType", // 3117
+ "tablelimits", // 3118
+ "tableproperties", // 3119
+ "tables", // 3120
+ "tabs", // 3121
+ "tag", // 3122
+ "tagLst", // 3123
+ "tags", // 3124
+ "tailEnd", // 3125
+ "target", // 3126
+ "targetScreenSize", // 3127
+ "targetScreenSz", // 3128
+ "targetscreensize", // 3129
+ "tav", // 3130
+ "tavLst", // 3131
+ "tbl", // 3132
+ "tblBg", // 3133
+ "tblBorders", // 3134
+ "tblCellMar", // 3135
+ "tblCellSpacing", // 3136
+ "tblGrid", // 3137
+ "tblGridChange", // 3138
+ "tblHeader", // 3139
+ "tblInd", // 3140
+ "tblLayout", // 3141
+ "tblLook", // 3142
+ "tblOverlap", // 3143
+ "tblPr", // 3144
+ "tblPrChange", // 3145
+ "tblPrEx", // 3146
+ "tblPrExChange", // 3147
+ "tblStyle", // 3148
+ "tblStyleColBandSize", // 3149
+ "tblStyleLst", // 3150
+ "tblStylePr", // 3151
+ "tblStyleRowBandSize", // 3152
+ "tblW", // 3153
+ "tblpPr", // 3154
+ "tblpX", // 3155
+ "tblpXSpec", // 3156
+ "tblpY", // 3157
+ "tblpYSpec", // 3158
+ "tc", // 3159
+ "tcBdr", // 3160
+ "tcBorders", // 3161
+ "tcFitText", // 3162
+ "tcMar", // 3163
+ "tcPr", // 3164
+ "tcPrChange", // 3165
+ "tcStyle", // 3166
+ "tcTxStyle", // 3167
+ "tcW", // 3168
+ "temporary", // 3169
+ "tentative", // 3170
+ "text", // 3171
+ "textAlignment", // 3172
+ "textDates", // 3173
+ "textDirection", // 3174
+ "textField", // 3175
+ "textFields", // 3176
+ "textInput", // 3177
+ "textPr", // 3178
+ "textRotation", // 3179
+ "textborder", // 3180
+ "textbox", // 3181
+ "textboxTightWrap", // 3182
+ "textboxrect", // 3183
+ "textdata", // 3184
+ "textlink", // 3185
+ "textpath", // 3186
+ "textpathok", // 3187
+ "tgtEl", // 3188
+ "tgtFrame", // 3189
+ "theme", // 3190
+ "themeColor", // 3191
+ "themeElements", // 3192
+ "themeFill", // 3193
+ "themeFillShade", // 3194
+ "themeFillTint", // 3195
+ "themeFontLang", // 3196
+ "themeManager", // 3197
+ "themeOverride", // 3198
+ "themeShade", // 3199
+ "themeTint", // 3200
+ "thickBot", // 3201
+ "thickBottom", // 3202
+ "thickTop", // 3203
+ "thicket", // 3204
+ "thickness", // 3205
+ "thousands", // 3206
+ "thresh", // 3207
+ "thruBlk", // 3208
+ "tickLblPos", // 3209
+ "tickLblSkip", // 3210
+ "tickMarkSkip", // 3211
+ "tile", // 3212
+ "tileRect", // 3213
+ "time", // 3214
+ "timePeriod", // 3215
+ "timing", // 3216
+ "tint", // 3217
+ "title", // 3218
+ "titlePg", // 3219
+ "titleStyle", // 3220
+ "tl2br", // 3221
+ "tm", // 3222
+ "tmAbs", // 3223
+ "tmFilter", // 3224
+ "tmPct", // 3225
+ "tmpl", // 3226
+ "tmplLst", // 3227
+ "tn", // 3228
+ "tnLst", // 3229
+ "to", // 3230
+ "tooltip", // 3231
+ "top", // 3232
+ "top10", // 3233
+ "topAutoShow", // 3234
+ "topFromText", // 3235
+ "topLabels", // 3236
+ "topLeftCell", // 3237
+ "topLinePunct", // 3238
+ "totalsRowBorderDxfId", // 3239
+ "totalsRowCellStyle", // 3240
+ "totalsRowCount", // 3241
+ "totalsRowDxfId", // 3242
+ "totalsRowFormula", // 3243
+ "totalsRowFunction", // 3244
+ "totalsRowLabel", // 3245
+ "totalsRowShown", // 3246
+ "tp", // 3247
+ "tpl", // 3248
+ "tplc", // 3249
+ "tpls", // 3250
+ "tr", // 3251
+ "tr2bl", // 3252
+ "trHeight", // 3253
+ "trPr", // 3254
+ "trPrChange", // 3255
+ "track", // 3256
+ "trackRevisions", // 3257
+ "transition", // 3258
+ "transitionEntry", // 3259
+ "transitionEvaluation", // 3260
+ "transp", // 3261
+ "trend", // 3262
+ "trendline", // 3263
+ "trendlineLbl", // 3264
+ "trendlineType", // 3265
+ "trim", // 3266
+ "truncateFontHeightsLikeWP6", // 3267
+ "tupleCache", // 3268
+ "twoCellAnchor", // 3269
+ "twoDigitTextYear", // 3270
+ "tx", // 3271
+ "tx1", // 3272
+ "tx2", // 3273
+ "txBody", // 3274
+ "txBox", // 3275
+ "txDef", // 3276
+ "txEffectClrLst", // 3277
+ "txEl", // 3278
+ "txFillClrLst", // 3279
+ "txLinClrLst", // 3280
+ "txPr", // 3281
+ "txSp", // 3282
+ "txStyles", // 3283
+ "txbxContent", // 3284
+ "ty", // 3285
+ "type", // 3286
+ "typeface", // 3287
+ "types", // 3288
+ "u", // 3289
+ "uBounds", // 3290
+ "uFill", // 3291
+ "uFillTx", // 3292
+ "uLn", // 3293
+ "uLnTx", // 3294
+ "ua", // 3295
+ "udl", // 3296
+ "ui1", // 3297
+ "ui2", // 3298
+ "ui4", // 3299
+ "ui8", // 3300
+ "uiCompat97To2003", // 3301
+ "uiExpand", // 3302
+ "uiPriority", // 3303
+ "uint", // 3304
+ "ulTrailSpace", // 3305
+ "un", // 3306
+ "unbalanced", // 3307
+ "unbalancedGroup", // 3308
+ "unboundColumnsLeft", // 3309
+ "unboundColumnsRight", // 3310
+ "underlineTabInNumList", // 3311
+ "undo", // 3312
+ "undone", // 3313
+ "ungrouping", // 3314
+ "unhideWhenUsed", // 3315
+ "uniqueCount", // 3316
+ "uniqueId", // 3317
+ "uniqueList", // 3318
+ "uniqueMemberProperty", // 3319
+ "uniqueName", // 3320
+ "uniqueParent", // 3321
+ "uniqueTag", // 3322
+ "unlockedFormula", // 3323
+ "up", // 3324
+ "upBars", // 3325
+ "upDownBars", // 3326
+ "updateAutomatic", // 3327
+ "updateFields", // 3328
+ "updateLinks", // 3329
+ "updatedVersion", // 3330
+ "upgradeOnRefresh", // 3331
+ "upright", // 3332
+ "uri", // 3333
+ "url", // 3334
+ "usb0", // 3335
+ "usb1", // 3336
+ "usb2", // 3337
+ "usb3", // 3338
+ "useA", // 3339
+ "useAltKinsokuLineBreakRules", // 3340
+ "useAnsiKerningPairs", // 3341
+ "useAutoFormatting", // 3342
+ "useBgFill", // 3343
+ "useDef", // 3344
+ "useFELayout", // 3345
+ "useFirstPageNumber", // 3346
+ "useLongFilenames", // 3347
+ "useNormalStyleForList", // 3348
+ "usePrinterDefaults", // 3349
+ "usePrinterMetrics", // 3350
+ "useSingleBorderforContiguousCells", // 3351
+ "useSpRect", // 3352
+ "useTimings", // 3353
+ "useWord2002TableStyleRules", // 3354
+ "useWord97LineBreakRules", // 3355
+ "useXSLTWhenSaving", // 3356
+ "user", // 3357
+ "userDrawn", // 3358
+ "userInfo", // 3359
+ "userInterface", // 3360
+ "userName", // 3361
+ "userShapes", // 3362
+ "userdrawn", // 3363
+ "userhidden", // 3364
+ "users", // 3365
+ "v", // 3366
+ "vAlign", // 3367
+ "vAnchor", // 3368
+ "vMerge", // 3369
+ "vMergeOrig", // 3370
+ "vSpace", // 3371
+ "vacatedStyle", // 3372
+ "val", // 3373
+ "valAx", // 3374
+ "value", // 3375
+ "valueMetadata", // 3376
+ "valueType", // 3377
+ "values", // 3378
+ "vanish", // 3379
+ "varLst", // 3380
+ "varPSubtotal", // 3381
+ "varScale", // 3382
+ "varSubtotal", // 3383
+ "variant", // 3384
+ "varyColors", // 3385
+ "vbProcedure", // 3386
+ "vector", // 3387
+ "vendorID", // 3388
+ "version", // 3389
+ "vert", // 3390
+ "vertAlign", // 3391
+ "vertAnchor", // 3392
+ "vertBarState", // 3393
+ "vertCompress", // 3394
+ "vertJc", // 3395
+ "vertOverflow", // 3396
+ "vertical", // 3397
+ "verticalCentered", // 3398
+ "verticalDpi", // 3399
+ "verticies", // 3400
+ "video", // 3401
+ "videoFile", // 3402
+ "view", // 3403
+ "view3D", // 3404
+ "viewMergedData", // 3405
+ "viewPr", // 3406
+ "viewpoint", // 3407
+ "viewpointorigin", // 3408
+ "visibility", // 3409
+ "visualTotals", // 3410
+ "vm", // 3411
+ "vml", // 3412
+ "vocabulary", // 3413
+ "vol", // 3414
+ "volType", // 3415
+ "volTypes", // 3416
+ "vstream", // 3417
+ "w", // 3418
+ "wAfter", // 3419
+ "wBefore", // 3420
+ "wMode", // 3421
+ "wR", // 3422
+ "wavAudioFile", // 3423
+ "webHidden", // 3424
+ "webPr", // 3425
+ "webPublishItem", // 3426
+ "webPublishItems", // 3427
+ "webPublishObject", // 3428
+ "webPublishObjects", // 3429
+ "webPublishing", // 3430
+ "webSettings", // 3431
+ "wedge", // 3432
+ "weight", // 3433
+ "wheel", // 3434
+ "whole", // 3435
+ "wholeTbl", // 3436
+ "widowControl", // 3437
+ "width", // 3438
+ "windowHeight", // 3439
+ "windowProtection", // 3440
+ "windowWidth", // 3441
+ "wipe", // 3442
+ "wireframe", // 3443
+ "wordWrap", // 3444
+ "workbook", // 3445
+ "workbookParameter", // 3446
+ "workbookPassword", // 3447
+ "workbookPr", // 3448
+ "workbookProtection", // 3449
+ "workbookView", // 3450
+ "workbookViewId", // 3451
+ "worksheet", // 3452
+ "worksheetSource", // 3453
+ "wpJustification", // 3454
+ "wpSpaceWidth", // 3455
+ "wrap", // 3456
+ "wrapIndent", // 3457
+ "wrapNone", // 3458
+ "wrapPolygon", // 3459
+ "wrapRight", // 3460
+ "wrapSquare", // 3461
+ "wrapText", // 3462
+ "wrapThrough", // 3463
+ "wrapTight", // 3464
+ "wrapTopAndBottom", // 3465
+ "wrapTrailSpaces", // 3466
+ "wrapcoords", // 3467
+ "writeProtection", // 3468
+ "wsDr", // 3469
+ "x", // 3470
+ "xAlign", // 3471
+ "xMode", // 3472
+ "xSplit", // 3473
+ "xVal", // 3474
+ "xWindow", // 3475
+ "xf", // 3476
+ "xfDxf", // 3477
+ "xfId", // 3478
+ "xfrm", // 3479
+ "xfrmType", // 3480
+ "xl2000", // 3481
+ "xl97", // 3482
+ "xlm", // 3483
+ "xml", // 3484
+ "xmlBased", // 3485
+ "xmlCellPr", // 3486
+ "xmlColumnPr", // 3487
+ "xmlDataType", // 3488
+ "xmlPr", // 3489
+ "xpath", // 3490
+ "xrange", // 3491
+ "xscale", // 3492
+ "y", // 3493
+ "yAlign", // 3494
+ "yMode", // 3495
+ "ySplit", // 3496
+ "yVal", // 3497
+ "yWindow", // 3498
+ "year", // 3499
+ "yearLong", // 3500
+ "yearShort", // 3501
+ "yrange", // 3502
+ "z", // 3503
+ "zOrder", // 3504
+ "zOrderOff", // 3505
+ "zeroAsc", // 3506
+ "zeroDesc", // 3507
+ "zeroHeight", // 3508
+ "zeroValues", // 3509
+ "zeroWid", // 3510
+ "zoom", // 3511
+ "zoomContents", // 3512
+ "zoomScale", // 3513
+ "zoomScaleNormal", // 3514
+ "zoomScalePageLayoutView", // 3515
+ "zoomScaleSheetLayoutView", // 3516
+ "zoomToFit" // 3517
+};
+
+size_t token_name_count = 3518; \ No newline at end of file
diff --git a/src/liborcus/ooxml_types.cpp b/src/liborcus/ooxml_types.cpp
new file mode 100644
index 0000000..f5165a0
--- /dev/null
+++ b/src/liborcus/ooxml_types.cpp
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ooxml_types.hpp"
+
+namespace orcus {
+
+opc_rel_extra::~opc_rel_extra() = default;
+
+opc_rel_extras_t::opc_rel_extras_t() = default;
+opc_rel_extras_t::~opc_rel_extras_t() = default;
+
+opc_rel_extras_t::opc_rel_extras_t(opc_rel_extras_t&& other) :
+ data(std::move(other.data)) {}
+
+void opc_rel_extras_t::swap(opc_rel_extras_t& other)
+{
+ data.swap(other.data);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/ooxml_types.hpp b/src/liborcus/ooxml_types.hpp
new file mode 100644
index 0000000..2b9e43c
--- /dev/null
+++ b/src/liborcus/ooxml_types.hpp
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_OOXML_TYPES_HPP
+#define INCLUDED_ORCUS_OOXML_TYPES_HPP
+
+#include <iostream>
+#include <memory>
+#include <unordered_map>
+
+namespace orcus {
+
+typedef const char* content_type_t;
+typedef const char* schema_t;
+
+/**
+ * Part name (first) and content type (second).
+ */
+typedef ::std::pair<std::string_view, content_type_t> xml_part_t;
+
+/**
+ * Single OPC relationship that corresponds with a Relationship element in
+ * .rels parts.
+ */
+struct opc_rel_t
+{
+ std::string_view rid;
+ std::string_view target;
+ schema_t type;
+
+ opc_rel_t() : type(nullptr) {}
+ opc_rel_t(std::string_view _rid, const std::string_view& _target, schema_t _type) :
+ rid(_rid), target(_target), type(_type) {}
+};
+
+/**
+ * Used as a base struct only to allow storage of custom data associated
+ * with a relationship.
+ */
+struct opc_rel_extra
+{
+ virtual ~opc_rel_extra() = 0;
+};
+
+struct opc_rel_extras_t
+{
+ typedef std::unordered_map<std::string_view, std::unique_ptr<opc_rel_extra>> map_type;
+
+ /**
+ * Key is a textual relation ID, while the value is an arbitrary data
+ * associated with the relation ID.
+ */
+ map_type data;
+
+ opc_rel_extras_t(opc_rel_extras_t&& other);
+
+ opc_rel_extras_t(const opc_rel_extras_t&) = delete;
+ opc_rel_extras_t& operator=(const opc_rel_extras_t&) = delete;
+
+ opc_rel_extras_t();
+ ~opc_rel_extras_t();
+
+ void swap(opc_rel_extras_t& other);
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/opc_context.cpp b/src/liborcus/opc_context.cpp
new file mode 100644
index 0000000..e3b1bb5
--- /dev/null
+++ b/src/liborcus/opc_context.cpp
@@ -0,0 +1,310 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "opc_context.hpp"
+#include "opc_token_constants.hpp"
+#include "ooxml_content_types.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "ooxml_schemas.hpp"
+#include "session_context.hpp"
+
+#include "orcus/exception.hpp"
+
+#include <cassert>
+#include <iostream>
+#include <algorithm>
+
+namespace orcus {
+
+namespace {
+
+class part_ext_attr_parser
+{
+public:
+ part_ext_attr_parser(
+ opc_content_types_context::ct_cache_type* p_ct_cache, xml_token_t attr_name, const config* conf) :
+ mp_ct_cache(p_ct_cache),
+ m_attr_name(attr_name),
+ m_config(conf),
+ m_content_type(nullptr) {}
+
+ part_ext_attr_parser(const part_ext_attr_parser& r) :
+ mp_ct_cache(r.mp_ct_cache),
+ m_attr_name(r.m_attr_name),
+ m_config(r.m_config),
+ m_name(r.m_name),
+ m_content_type(r.m_content_type) {}
+
+ void operator() (const xml_token_attr_t& attr)
+ {
+ if (attr.name == m_attr_name)
+ m_name = attr.value;
+ else if (attr.name == XML_ContentType)
+ m_content_type = to_content_type(attr.value);
+ }
+
+ const std::string_view& get_name() const { return m_name; }
+ content_type_t get_content_type() const { return m_content_type; }
+
+private:
+ content_type_t to_content_type(const std::string_view& p) const
+ {
+ opc_content_types_context::ct_cache_type::const_iterator itr =
+ mp_ct_cache->find(p);
+ if (itr == mp_ct_cache->end())
+ {
+ if (m_config->debug)
+ std::cout << "unknown content type: " << p << std::endl;
+ return nullptr;
+ }
+ std::string_view val = *itr;
+ return val.data();
+ }
+
+private:
+ const opc_content_types_context::ct_cache_type* mp_ct_cache;
+ xml_token_t m_attr_name;
+ const config* m_config;
+ std::string_view m_name;
+ content_type_t m_content_type;
+};
+
+}
+
+opc_content_types_context::opc_content_types_context(session_context& session_cxt, const tokens& _tokens) :
+ xml_context_base(session_cxt, _tokens)
+{
+ // build content type cache.
+ for (const content_type_t* p = CT_all; *p; ++p)
+ m_ct_cache.insert(std::string_view(*p));
+}
+
+opc_content_types_context::~opc_content_types_context()
+{
+}
+
+xml_context_base* opc_content_types_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void opc_content_types_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void opc_content_types_context::start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t> &attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ switch (name)
+ {
+ case XML_Types:
+ {
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ if (get_config().debug)
+ print_attrs(get_tokens(), attrs);
+ }
+ break;
+ case XML_Override:
+ {
+ xml_element_expected(parent, NS_opc_ct, XML_Types);
+ part_ext_attr_parser func(&m_ct_cache, XML_PartName, &get_config());
+ func = for_each(attrs.begin(), attrs.end(), func);
+
+ // We need to use allocated strings for part names here because
+ // the part names need to survive after the [Content_Types].xml
+ // stream is destroyed.
+ std::string_view part_name = get_session_context().spool.intern(func.get_name()).first;
+ m_parts.push_back(
+ xml_part_t(part_name, func.get_content_type()));
+ }
+ break;
+ case XML_Default:
+ {
+ xml_element_expected(parent, NS_opc_ct, XML_Types);
+ part_ext_attr_parser func(&m_ct_cache, XML_Extension, &get_config());
+ func = for_each(attrs.begin(), attrs.end(), func);
+
+ // Like the part names, we need to use allocated strings for
+ // extension names.
+ std::string_view ext_name = get_session_context().spool.intern(func.get_name()).first;
+ m_ext_defaults.push_back(
+ xml_part_t(ext_name, func.get_content_type()));
+ }
+ break;
+ default:
+ warn_unhandled();
+ }
+}
+
+bool opc_content_types_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ return pop_stack(ns, name);
+}
+
+void opc_content_types_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+void opc_content_types_context::pop_parts(std::vector<xml_part_t>& parts)
+{
+ m_parts.swap(parts);
+}
+
+void opc_content_types_context::pop_ext_defaults(std::vector<xml_part_t>& ext_defaults)
+{
+ m_ext_defaults.swap(ext_defaults);
+}
+
+// ============================================================================
+
+namespace {
+
+class rel_attr_parser
+{
+public:
+ rel_attr_parser(session_context* cxt, const opc_relations_context::schema_cache_type* cache, const config* conf) :
+ m_cxt(cxt), mp_schema_cache(cache), mp_config(conf) {}
+
+ void operator() (const xml_token_attr_t& attr)
+ {
+ // Target and rId strings must be interned as they must survive after
+ // the rels part gets destroyed.
+
+ switch (attr.name)
+ {
+ case XML_Target:
+ m_rel.target = m_cxt->spool.intern(attr.value).first;
+ break;
+ case XML_Type:
+ m_rel.type = to_schema(attr.value);
+ break;
+ case XML_Id:
+ m_rel.rid = m_cxt->spool.intern(attr.value).first;
+ break;
+ }
+ }
+
+ const opc_rel_t& get_rel() const { return m_rel; }
+
+private:
+ schema_t to_schema(const std::string_view& p) const
+ {
+ opc_relations_context::schema_cache_type::const_iterator itr =
+ mp_schema_cache->find(p);
+ if (itr == mp_schema_cache->end())
+ {
+ if (mp_config->debug)
+ std::cout << "unknown schema: " << p << std::endl;
+ return nullptr;
+ }
+ std::string_view val = *itr;
+ return val.data();
+ }
+
+private:
+ session_context* m_cxt;
+ const opc_relations_context::schema_cache_type* mp_schema_cache;
+ const config* mp_config;
+ opc_rel_t m_rel;
+};
+
+/**
+ * Compare relations by the rId.
+ */
+struct compare_rels
+{
+ bool operator() (const opc_rel_t& r1, const opc_rel_t& r2) const
+ {
+ std::size_t n1 = r1.rid.size(), n2 = r2.rid.size();
+ std::size_t n = std::min(n1, n2);
+ const char *p1 = r1.rid.data(), *p2 = r2.rid.data();
+ for (std::size_t i = 0; i < n; ++i, ++p1, ++p2)
+ {
+ if (*p1 < *p2)
+ return true;
+ if (*p1 > *p2)
+ return false;
+ assert(*p1 == *p2);
+ }
+ return n1 < n2;
+ }
+};
+
+}
+
+opc_relations_context::opc_relations_context(session_context& session_cxt, const tokens &_tokens) :
+ xml_context_base(session_cxt, _tokens)
+{
+ // build content type cache.
+ for (schema_t* p = SCH_all; *p; ++p)
+ m_schema_cache.insert(std::string_view(*p));
+}
+
+opc_relations_context::~opc_relations_context()
+{
+}
+
+xml_context_base* opc_relations_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void opc_relations_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void opc_relations_context::start_element(
+ xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t> &attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ switch (name)
+ {
+ case XML_Relationships:
+ {
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ if (get_config().debug)
+ print_attrs(get_tokens(), attrs);
+ }
+ break;
+ case XML_Relationship:
+ {
+ rel_attr_parser func(&get_session_context(), &m_schema_cache, &get_config());
+ xml_element_expected(parent, NS_opc_rel, XML_Relationships);
+ func = for_each(attrs.begin(), attrs.end(), func);
+ const opc_rel_t& rel = func.get_rel();
+ if (rel.type)
+ m_rels.push_back(rel);
+ }
+ break;
+ default:
+ warn_unhandled();
+ }
+}
+
+bool opc_relations_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ return pop_stack(ns, name);
+}
+
+void opc_relations_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+void opc_relations_context::init()
+{
+ m_rels.clear();
+}
+
+void opc_relations_context::pop_rels(std::vector<opc_rel_t>& rels)
+{
+ // Sort by the rId.
+ sort(m_rels.begin(), m_rels.end(), compare_rels());
+ m_rels.swap(rels);
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/opc_context.hpp b/src/liborcus/opc_context.hpp
new file mode 100644
index 0000000..c965895
--- /dev/null
+++ b/src/liborcus/opc_context.hpp
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_OPC_CONTEXT_HPP
+#define INCLUDED_ORCUS_OPC_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "ooxml_types.hpp"
+
+#include <unordered_set>
+#include <vector>
+
+namespace orcus {
+
+/**
+ * Main context class for the [Content_Types].xml part. This context does
+ * not use any child contexts; [Content_Types].xml part is simple enough
+ * that we can handle all in a single context class.
+ */
+class opc_content_types_context : public xml_context_base
+{
+public:
+ typedef std::unordered_set<std::string_view> ct_cache_type;
+
+ opc_content_types_context(session_context& session_cxt, const tokens& _tokens);
+ virtual ~opc_content_types_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base *child);
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t> &attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+
+ /**
+ * Swap stored xml part info with the instance passed as the argument.
+ * Calling this will clear the storage.
+ *
+ * @param parts instance to swap the stored xml part info with.
+ */
+ void pop_parts(::std::vector<xml_part_t>& parts);
+
+ /**
+ * Swap stored xml extension info with the instance passed as the
+ * argument. Calling this will clear the storage.
+ *
+ * @param parts instance to swap the stored extension info with.
+ */
+ void pop_ext_defaults(::std::vector<xml_part_t>& ext_defaults);
+
+private:
+ ct_cache_type m_ct_cache; // content type cache;
+ ::std::vector<xml_part_t> m_parts;
+ ::std::vector<xml_part_t> m_ext_defaults;
+};
+
+/**
+ * Context class for relations parts.
+ */
+class opc_relations_context : public xml_context_base
+{
+public:
+ typedef std::unordered_set<std::string_view> schema_cache_type;
+
+ opc_relations_context(session_context& session_cxt, const tokens& _tokens);
+ virtual ~opc_relations_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base *child);
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t> &attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+
+ void init();
+ void pop_rels(::std::vector<opc_rel_t>& rels);
+
+private:
+ schema_cache_type m_schema_cache;
+ ::std::vector<opc_rel_t> m_rels;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/opc_reader.cpp b/src/liborcus/opc_reader.cpp
new file mode 100644
index 0000000..7126f66
--- /dev/null
+++ b/src/liborcus/opc_reader.cpp
@@ -0,0 +1,306 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "opc_reader.hpp"
+#include "xml_stream_parser.hpp"
+
+#include "ooxml_global.hpp"
+#include "opc_context.hpp"
+#include "ooxml_tokens.hpp"
+
+#include "orcus/config.hpp"
+
+#include <iostream>
+
+using namespace std;
+
+namespace orcus {
+
+namespace {
+
+class print_xml_content_types
+{
+public:
+ print_xml_content_types(const char* prefix) :
+ m_prefix(prefix) {}
+
+ void operator() (const xml_part_t& v) const
+ {
+ cout << "* " << m_prefix << ": " << v.first;
+ if (v.second)
+ cout << " (" << v.second << ")";
+ else
+ cout << " (<unknown content type>)";
+ cout << endl;
+ }
+private:
+ const char* m_prefix;
+};
+
+}
+
+opc_reader::part_handler::~part_handler() {}
+
+opc_reader::opc_reader(const config& opt, xmlns_repository& ns_repo, session_context& cxt, part_handler& handler) :
+ m_config(opt),
+ m_ns_repo(ns_repo),
+ m_session_cxt(cxt),
+ m_handler(handler),
+ m_opc_rel_handler(m_session_cxt, opc_tokens, std::make_unique<opc_relations_context>(m_session_cxt, opc_tokens)) {}
+
+void opc_reader::read_file(std::unique_ptr<zip_archive_stream>&& stream)
+{
+ m_archive_stream.reset(stream.release());
+ m_archive.reset(new zip_archive(m_archive_stream.get()));
+
+ m_archive->load();
+
+ m_dir_stack.push_back(string()); // push root directory.
+
+ if (m_config.debug)
+ list_content();
+ read_content();
+
+ m_archive.reset();
+ m_archive_stream.reset();
+}
+
+bool opc_reader::open_zip_stream(const string& path, vector<unsigned char>& buf)
+{
+ try
+ {
+ std::vector<unsigned char> entry = m_archive->read_file_entry(path.c_str());
+ buf.swap(entry);
+ return true;
+ }
+ catch (const std::exception&)
+ {
+ return false;
+ }
+}
+
+void opc_reader::read_part(std::string_view path, const schema_t type, opc_rel_extra* data)
+{
+ assert(!m_dir_stack.empty());
+
+ dir_stack_type dir_changed;
+
+ // Change current directory and read the in-file.
+ const char* p = path.data();
+ const char* p_name = nullptr;
+ size_t name_len = 0;
+ for (size_t i = 0, n = path.size(); i < n; ++i, ++p)
+ {
+ if (!p_name)
+ p_name = p;
+
+ ++name_len;
+
+ if (*p == '/')
+ {
+ // Push a new directory.
+ string dir_name(p_name, name_len);
+ if (dir_name == "..")
+ {
+ dir_changed.push_back(m_dir_stack.back());
+ m_dir_stack.pop_back();
+ }
+ else
+ {
+ m_dir_stack.push_back(dir_name);
+
+ // Add a null directory to the change record to remove it at the end.
+ dir_changed.push_back(string());
+ }
+
+ p_name = nullptr;
+ name_len = 0;
+ }
+ }
+
+ if (p_name)
+ {
+ // This is a file.
+ string file_name(p_name, name_len);
+ string cur_dir = get_current_dir();
+ string full_path = resolve_file_path(cur_dir, file_name);
+
+ if (m_handled_parts.count(full_path) > 0)
+ {
+ // This part has been previously read. Let's not read it twice.
+ if (m_config.debug)
+ {
+ cout << "---" << endl;
+ cout << "skipping previously read part: " << full_path << endl;
+ }
+ }
+ else if (m_handler.handle_part(type, cur_dir, file_name, data))
+ {
+ m_handled_parts.insert(full_path);
+ }
+ else if (m_config.debug)
+ {
+ cout << "---" << endl;
+ cout << "unhandled relationship type: " << type << endl;
+ }
+ }
+
+ // Unwind to the original directory.
+ while (!dir_changed.empty())
+ {
+ const string& dir = dir_changed.back();
+ if (dir.empty())
+ // remove added directory.
+ m_dir_stack.pop_back();
+ else
+ // re-add removed directory.
+ m_dir_stack.push_back(dir);
+
+ dir_changed.pop_back();
+ }
+}
+
+void opc_reader::check_relation_part(
+ const std::string& file_name, opc_rel_extras_t* extras, sort_compare_type* sorter)
+{
+ // Read the relationship file associated with this file, located at
+ // _rels/<file name>.rels.
+ vector<opc_rel_t> rels;
+ m_dir_stack.push_back(string("_rels/"));
+ string rels_file_name = file_name + ".rels";
+ read_relations(rels_file_name.c_str(), rels);
+ m_dir_stack.pop_back();
+
+ if (sorter)
+ std::sort(rels.begin(), rels.end(), *sorter);
+
+ if (m_config.debug)
+ for_each(rels.begin(), rels.end(), print_opc_rel());
+
+ for_each(rels.begin(), rels.end(),
+ [&](opc_rel_t& v)
+ {
+ opc_rel_extra* data = nullptr;
+ if (extras)
+ {
+ // See if there is an extra data associated with this relation ID.
+ opc_rel_extras_t::map_type::iterator it = extras->data.find(v.rid);
+ if (it != extras->data.end())
+ // There is one !
+ data = it->second.get();
+ }
+ read_part(v.target, v.type, data);
+ }
+ );
+}
+
+void opc_reader::list_content() const
+{
+ size_t num = m_archive->get_file_entry_count();
+ cout << "number of files this archive contains: " << num << endl;
+
+ for (size_t i = 0; i < num; ++i)
+ {
+ std::string_view filename = m_archive->get_file_entry_name(i);
+ cout << filename << endl;
+ }
+}
+
+void opc_reader::read_content()
+{
+ if (m_dir_stack.empty())
+ return;
+
+ // [Content_Types].xml
+
+ read_content_types();
+ if (m_config.debug)
+ {
+ for_each(m_parts.begin(), m_parts.end(), print_xml_content_types("part name"));
+ for_each(m_ext_defaults.begin(), m_ext_defaults.end(), print_xml_content_types("extension default"));
+ }
+
+ // _rels/.rels
+
+ m_dir_stack.push_back(string("_rels/"));
+ vector<opc_rel_t> rels;
+ read_relations(".rels", rels);
+ m_dir_stack.pop_back();
+
+ if (m_config.debug)
+ for_each(rels.begin(), rels.end(), print_opc_rel());
+
+ for_each(rels.begin(), rels.end(),
+ [this](opc_rel_t& v)
+ {
+ read_part(v.target, v.type, nullptr);
+ }
+ );
+}
+
+void opc_reader::read_content_types()
+{
+ string filepath("[Content_Types].xml");
+ vector<unsigned char> buffer;
+ if (!open_zip_stream(filepath, buffer))
+ return;
+
+ if (buffer.empty())
+ return;
+
+ xml_stream_parser parser(
+ m_config, m_ns_repo, opc_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+
+ auto handler = std::make_unique<xml_simple_stream_handler>(
+ m_session_cxt, opc_tokens,
+ std::make_unique<opc_content_types_context>(m_session_cxt, opc_tokens));
+
+ parser.set_handler(handler.get());
+ parser.parse();
+
+ opc_content_types_context& context =
+ static_cast<opc_content_types_context&>(handler->get_context());
+ context.pop_parts(m_parts);
+ context.pop_ext_defaults(m_ext_defaults);
+}
+
+void opc_reader::read_relations(const char* path, vector<opc_rel_t>& rels)
+{
+ string filepath = resolve_file_path(get_current_dir(), path);
+ if (m_config.debug)
+ cout << "relation file path: " << filepath << endl;
+
+ vector<unsigned char> buffer;
+ if (!open_zip_stream(filepath, buffer))
+ return;
+
+ if (buffer.empty())
+ return;
+
+ xml_stream_parser parser(
+ m_config, m_ns_repo, opc_tokens, reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+
+ opc_relations_context& context =
+ static_cast<opc_relations_context&>(m_opc_rel_handler.get_context());
+ context.init();
+ parser.set_handler(&m_opc_rel_handler);
+ parser.parse();
+ context.pop_rels(rels);
+}
+
+string opc_reader::get_current_dir() const
+{
+ string pwd;
+ vector<string>::const_iterator itr = m_dir_stack.begin(), itr_end = m_dir_stack.end();
+ for (; itr != itr_end; ++itr)
+ pwd += *itr;
+ return pwd;
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/opc_reader.hpp b/src/liborcus/opc_reader.hpp
new file mode 100644
index 0000000..5733c02
--- /dev/null
+++ b/src/liborcus/opc_reader.hpp
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_OPC_READER_HPP
+#define INCLUDED_ORCUS_OPC_READER_HPP
+
+#include "orcus/env.hpp"
+#include "orcus/zip_archive.hpp"
+#include "orcus/zip_archive_stream.hpp"
+
+#include "ooxml_schemas.hpp"
+#include "xml_simple_stream_handler.hpp"
+
+#include <vector>
+#include <string>
+#include <unordered_set>
+
+namespace orcus {
+
+struct config;
+
+class xmlns_repository;
+struct session_context;
+struct opc_rel_extra;
+
+/**
+ * Class to handle parsing through all xml parts stored in a file packaged
+ * according to the Open Package Convention (OPC).
+ */
+class opc_reader
+{
+ typedef std::vector<std::string> dir_stack_type;
+ typedef std::unordered_set<std::string> part_set_type;
+
+ opc_reader(const opc_reader&) = delete;
+ opc_reader& operator=(const opc_reader&) = delete;
+
+public:
+
+ using sort_compare_type = std::function<bool(const opc_rel_t&, const opc_rel_t&)>;
+
+ /**
+ * Interface class for the user of opc_reader to receive callback to
+ * handle each xml part.
+ */
+ class part_handler
+ {
+ public:
+ virtual ~part_handler() = 0;
+
+ /**
+ * Client code needs to implement this method to handle each xml part.
+ *
+ * @param type schema type signifying the content type stored in this
+ * part.
+ * @param dir_path directory path relative to package root.
+ * @param file_name name of the xml part without the directory path.
+ * @param data extra data passed on from the client code.
+ *
+ * @return true if handled, false if not handled.
+ */
+ virtual bool handle_part(
+ schema_t type, const std::string& dir_path, const std::string& file_name, opc_rel_extra* data) = 0;
+ };
+
+ opc_reader(const config& opt, xmlns_repository& ns_repo, session_context& session_cxt, part_handler& handler);
+
+ void read_file(std::unique_ptr<zip_archive_stream>&& stream);
+ bool open_zip_stream(const std::string& path, std::vector<unsigned char>& buf);
+
+ /**
+ * Read an xml part inside package. The path is relative to the relation
+ * file.
+ *
+ * @param path the path to the xml part.
+ * @param type schema type.
+ */
+ void read_part(std::string_view path, const schema_t type, opc_rel_extra* data);
+
+ /**
+ * Check if a relation file exists for a given xml part, and if it does,
+ * read and process it.
+ *
+ * @param file_name name of the current xml part.
+ * @param extras optional extra data file for client code to pass on to
+ * the next xml part(s).
+ * @param sorter optoinal comparator function used to sort the relation
+ * items prior to processing them.
+ */
+ void check_relation_part(
+ const std::string& file_name, opc_rel_extras_t* extras = nullptr,
+ sort_compare_type* sorter = nullptr);
+
+private:
+
+ void list_content() const;
+ void read_content();
+ void read_content_types();
+ void read_relations(const char* path, std::vector<opc_rel_t>& rels);
+
+ std::string get_current_dir() const;
+
+private:
+ const config& m_config;
+ xmlns_repository& m_ns_repo;
+ session_context& m_session_cxt;
+ part_handler& m_handler;
+
+ std::unique_ptr<zip_archive> m_archive;
+ std::unique_ptr<zip_archive_stream> m_archive_stream;
+
+ xml_simple_stream_handler m_opc_rel_handler;
+
+ std::vector<xml_part_t> m_parts;
+ std::vector<xml_part_t> m_ext_defaults;
+ dir_stack_type m_dir_stack;
+ part_set_type m_handled_parts;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/opc_token_constants.hpp b/src/liborcus/opc_token_constants.hpp
new file mode 100644
index 0000000..a7b1370
--- /dev/null
+++ b/src/liborcus/opc_token_constants.hpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_OPC_TOKEN_CONSTANTS_HPP__
+#define __ORCUS_OPC_TOKEN_CONSTANTS_HPP__
+
+#include "orcus/types.hpp"
+
+namespace orcus {
+
+#include "opc_token_constants.inl"
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/opc_token_constants.inl b/src/liborcus/opc_token_constants.inl
new file mode 100644
index 0000000..7f3c7da
--- /dev/null
+++ b/src/liborcus/opc_token_constants.inl
@@ -0,0 +1,31 @@
+// This file has been auto-generated. Do not hand-edit this.
+
+const xml_token_t XML_ContentType = 1;
+const xml_token_t XML_Default = 2;
+const xml_token_t XML_Extension = 3;
+const xml_token_t XML_Format = 4;
+const xml_token_t XML_Id = 5;
+const xml_token_t XML_Override = 6;
+const xml_token_t XML_PartName = 7;
+const xml_token_t XML_Relationship = 8;
+const xml_token_t XML_RelationshipReference = 9;
+const xml_token_t XML_Relationships = 10;
+const xml_token_t XML_RelationshipsGroupReference = 11;
+const xml_token_t XML_SignatureTime = 12;
+const xml_token_t XML_SourceId = 13;
+const xml_token_t XML_SourceType = 14;
+const xml_token_t XML_Target = 15;
+const xml_token_t XML_TargetMode = 16;
+const xml_token_t XML_Type = 17;
+const xml_token_t XML_Types = 18;
+const xml_token_t XML_Value = 19;
+const xml_token_t XML_category = 20;
+const xml_token_t XML_contentStatus = 21;
+const xml_token_t XML_contentType = 22;
+const xml_token_t XML_coreProperties = 23;
+const xml_token_t XML_keywords = 24;
+const xml_token_t XML_lastModifiedBy = 25;
+const xml_token_t XML_lastPrinted = 26;
+const xml_token_t XML_revision = 27;
+const xml_token_t XML_version = 28;
+
diff --git a/src/liborcus/opc_tokens.inl b/src/liborcus/opc_tokens.inl
new file mode 100644
index 0000000..5f72a6a
--- /dev/null
+++ b/src/liborcus/opc_tokens.inl
@@ -0,0 +1,36 @@
+// This file has been auto-generated. Do not hand-edit this.
+
+const char* token_names[] = {
+ "??", // 0
+ "ContentType", // 1
+ "Default", // 2
+ "Extension", // 3
+ "Format", // 4
+ "Id", // 5
+ "Override", // 6
+ "PartName", // 7
+ "Relationship", // 8
+ "RelationshipReference", // 9
+ "Relationships", // 10
+ "RelationshipsGroupReference", // 11
+ "SignatureTime", // 12
+ "SourceId", // 13
+ "SourceType", // 14
+ "Target", // 15
+ "TargetMode", // 16
+ "Type", // 17
+ "Types", // 18
+ "Value", // 19
+ "category", // 20
+ "contentStatus", // 21
+ "contentType", // 22
+ "coreProperties", // 23
+ "keywords", // 24
+ "lastModifiedBy", // 25
+ "lastPrinted", // 26
+ "revision", // 27
+ "version" // 28
+};
+
+size_t token_name_count = 29;
+
diff --git a/src/liborcus/orcus_csv.cpp b/src/liborcus/orcus_csv.cpp
new file mode 100644
index 0000000..dff2b2d
--- /dev/null
+++ b/src/liborcus/orcus_csv.cpp
@@ -0,0 +1,196 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_csv.hpp"
+
+#include "orcus/csv_parser.hpp"
+#include "orcus/stream.hpp"
+#include "orcus/spreadsheet/import_interface.hpp"
+#include "orcus/config.hpp"
+#include "orcus/string_pool.hpp"
+
+#include <cstring>
+#include <iostream>
+
+using namespace std;
+
+namespace orcus {
+
+namespace {
+
+constexpr const char* base_sheet_name = "data";
+
+struct header_cell
+{
+ spreadsheet::row_t row;
+ spreadsheet::col_t col;
+ std::string_view value;
+
+ header_cell(spreadsheet::row_t _row, spreadsheet::col_t _col, std::string_view _value) :
+ row(_row), col(_col), value(_value) {}
+};
+
+class max_row_size_reached {};
+
+class orcus_csv_handler
+{
+public:
+ orcus_csv_handler(spreadsheet::iface::import_factory& factory, const orcus::config& app_config) :
+ m_factory(factory),
+ m_app_config(app_config),
+ mp_sheet(nullptr),
+ m_sheet(0),
+ m_row(0),
+ m_col(0) {}
+
+ void begin_parse()
+ {
+ std::string sheet_name = get_sheet_name();
+ mp_sheet = m_factory.append_sheet(m_sheet, sheet_name);
+ }
+
+ void end_parse() {}
+ void begin_row()
+ {
+ // Check to see if this row is beyond the max row of the current
+ // sheet, and if so, append a new sheet and reset the current row to
+ // 0.
+ if (m_row >= mp_sheet->get_sheet_size().rows)
+ {
+ auto csv = std::get<config::csv_config>(m_app_config.data);
+
+ if (!csv.split_to_multiple_sheets)
+ throw max_row_size_reached();
+
+ // The next row will be outside the boundary of the current sheet.
+ ++m_sheet;
+ std::string sheet_name = get_sheet_name();
+ mp_sheet = m_factory.append_sheet(m_sheet, sheet_name);
+ m_row = 0;
+
+ if (!m_header_cells.empty())
+ {
+ // Duplicate the header rows from the first sheet.
+ for (const header_cell& c : m_header_cells)
+ mp_sheet->set_auto(c.row, c.col, c.value);
+
+ m_row += csv.header_row_size;
+ }
+ }
+ }
+
+ void end_row()
+ {
+ ++m_row;
+ m_col = 0;
+ }
+
+ void cell(std::string_view v, bool transient)
+ {
+ auto csv = std::get<config::csv_config>(m_app_config.data);
+
+ if (m_sheet == 0 && size_t(m_row) < csv.header_row_size)
+ {
+ if (transient)
+ v = m_pool.intern(v).first;
+
+ m_header_cells.emplace_back(m_row, m_col, v);
+ }
+
+ mp_sheet->set_auto(m_row, m_col, v);
+ ++m_col;
+ }
+
+private:
+ std::string get_sheet_name() const
+ {
+ if (!m_sheet)
+ // First sheet has no suffix.
+ return base_sheet_name;
+
+ // Add a suffix to keep the sheet name unique.
+ std::ostringstream os;
+ os << base_sheet_name << '_' << m_sheet;
+ return os.str();
+ }
+
+private:
+ string_pool m_pool;
+ std::vector<header_cell> m_header_cells;
+
+ spreadsheet::iface::import_factory& m_factory;
+ const config& m_app_config;
+ spreadsheet::iface::import_sheet* mp_sheet;
+ spreadsheet::sheet_t m_sheet;
+ spreadsheet::row_t m_row;
+ spreadsheet::col_t m_col;
+};
+
+}
+
+struct orcus_csv::impl
+{
+ spreadsheet::iface::import_factory* factory;
+
+ impl(spreadsheet::iface::import_factory* _factory) : factory(_factory) {}
+
+ void parse(std::string_view stream, const config& conf)
+ {
+ if (stream.empty())
+ return;
+
+ orcus_csv_handler handler(*factory, conf);
+ csv::parser_config config;
+ config.delimiters.push_back(',');
+ config.text_qualifier = '"';
+ csv_parser<orcus_csv_handler> parser(stream, handler, config);
+ try
+ {
+ parser.parse();
+ }
+ catch (const max_row_size_reached&)
+ {
+ // The parser has decided to end the import due to the destination
+ // sheet being full.
+ }
+ catch (const parse_error& e)
+ {
+ cout << "parse failed at offset " << e.offset() << ": " << e.what() << endl;
+ }
+ }
+};
+
+orcus_csv::orcus_csv(spreadsheet::iface::import_factory* factory) :
+ iface::import_filter(format_t::csv),
+ mp_impl(std::make_unique<impl>(factory)) {}
+
+orcus_csv::~orcus_csv() {}
+
+void orcus_csv::read_file(std::string_view filepath)
+{
+ file_content fc(filepath);
+ mp_impl->parse(fc.str(), get_config());
+ mp_impl->factory->finalize();
+}
+
+void orcus_csv::read_stream(std::string_view stream)
+{
+ if (stream.empty())
+ return;
+
+ mp_impl->parse(stream, get_config());
+ mp_impl->factory->finalize();
+}
+
+std::string_view orcus_csv::get_name() const
+{
+ return "csv";
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_gnumeric.cpp b/src/liborcus/orcus_gnumeric.cpp
new file mode 100644
index 0000000..849759b
--- /dev/null
+++ b/src/liborcus/orcus_gnumeric.cpp
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_gnumeric.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/spreadsheet/import_interface.hpp"
+#include "orcus/stream.hpp"
+#include "orcus/config.hpp"
+
+#include "xml_stream_parser.hpp"
+#include "gnumeric_handler.hpp"
+#include "gnumeric_tokens.hpp"
+#include "gnumeric_namespace_types.hpp"
+#include "gnumeric_detection_handler.hpp"
+#include "session_context.hpp"
+#include "detection_result.hpp"
+
+#define ORCUS_DEBUG_GNUMERIC 0
+#define BOOST_IOSTREAMS_NO_LIB 1
+
+#include <iostream>
+#include <string>
+
+#include <boost/iostreams/filtering_stream.hpp>
+#include <boost/iostreams/filter/gzip.hpp>
+
+using namespace std;
+
+namespace orcus {
+
+namespace {
+
+bool decompress_gzip(const char* buffer, size_t size, string& decompressed)
+{
+ string buf;
+
+ try
+ {
+ boost::iostreams::filtering_ostream os;
+ os.push(boost::iostreams::gzip_decompressor());
+ os.push(boost::iostreams::back_inserter(buf));
+ boost::iostreams::write(os, buffer, size);
+ os.flush();
+ }
+ catch (const exception&)
+ {
+ return false;
+ }
+
+ buf.swap(decompressed);
+ return true;
+}
+
+}
+
+struct orcus_gnumeric::impl
+{
+ xmlns_repository m_ns_repo;
+ session_context m_cxt;
+ spreadsheet::iface::import_factory* mp_factory;
+
+ impl(spreadsheet::iface::import_factory* im_factory) :
+ mp_factory(im_factory) {}
+
+ void read_content_xml(std::string_view s, const config& conf)
+ {
+ xml_stream_parser parser(conf, m_ns_repo, gnumeric_tokens, s.data(), s.size());
+
+ auto handler = std::make_unique<gnumeric_content_xml_handler>(
+ m_cxt, gnumeric_tokens, mp_factory);
+
+ parser.set_handler(handler.get());
+ parser.parse();
+ }
+};
+
+orcus_gnumeric::orcus_gnumeric(spreadsheet::iface::import_factory* factory) :
+ iface::import_filter(format_t::gnumeric),
+ mp_impl(std::make_unique<impl>(factory))
+{
+ mp_impl->m_ns_repo.add_predefined_values(NS_gnumeric_all);
+}
+
+orcus_gnumeric::~orcus_gnumeric()
+{
+}
+
+bool orcus_gnumeric::detect(const unsigned char* buffer, size_t size)
+{
+ // Detect gnumeric format that's already in memory.
+
+ string decompressed;
+ if (!decompress_gzip(reinterpret_cast<const char*>(buffer), size, decompressed))
+ return false;
+
+ if (decompressed.empty())
+ return false;
+
+ // Parse this xml stream for detection.
+ config opt(format_t::gnumeric);
+ xmlns_repository ns_repo;
+ ns_repo.add_predefined_values(NS_gnumeric_all);
+ session_context cxt;
+ xml_stream_parser parser(opt, ns_repo, gnumeric_tokens, &decompressed[0], decompressed.size());
+ gnumeric_detection_handler handler(cxt, gnumeric_tokens);
+ parser.set_handler(&handler);
+
+ try
+ {
+ parser.parse();
+ }
+ catch (const detection_result& res)
+ {
+ return res.get_result();
+ }
+ catch (...) {}
+
+ return false;
+}
+
+void orcus_gnumeric::read_file(std::string_view filepath)
+{
+#if ORCUS_DEBUG_GNUMERIC
+ cout << "reading " << filepath << endl;
+#endif
+
+ file_content content(filepath);
+ if (content.empty())
+ return;
+
+ read_stream(content.str());
+}
+
+void orcus_gnumeric::read_stream(std::string_view stream)
+{
+ if (stream.empty())
+ return;
+
+ std::string file_content;
+ if (!decompress_gzip(stream.data(), stream.size(), file_content))
+ return;
+
+ if (auto* gs = mp_impl->mp_factory->get_global_settings(); gs)
+ {
+ gs->set_origin_date(1899, 12, 30);
+ gs->set_default_formula_grammar(spreadsheet::formula_grammar_t::gnumeric);
+ }
+
+ mp_impl->read_content_xml(file_content, get_config());
+ mp_impl->mp_factory->finalize();
+}
+
+std::string_view orcus_gnumeric::get_name() const
+{
+ return "gnumeric";
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_import_ods.cpp b/src/liborcus/orcus_import_ods.cpp
new file mode 100644
index 0000000..0c73472
--- /dev/null
+++ b/src/liborcus/orcus_import_ods.cpp
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_import_ods.hpp"
+
+#include "orcus/xml_namespace.hpp"
+#include "orcus/spreadsheet/import_interface.hpp"
+#include "orcus/config.hpp"
+
+#include "odf_styles_context.hpp"
+#include "odf_tokens.hpp"
+#include "odf_namespace_types.hpp"
+#include "session_context.hpp"
+#include "ods_session_data.hpp"
+
+#include "xml_stream_parser.hpp"
+
+namespace orcus {
+
+void import_ods::read_styles(std::string_view s, spreadsheet::iface::import_styles* styles)
+{
+ if (!styles)
+ return;
+
+ if (s.empty())
+ return;
+
+ session_context cxt{std::make_unique<ods_session_data>()};
+ auto context = std::make_unique<styles_context>(cxt, odf_tokens, styles);
+
+ xml_stream_handler stream_handler(cxt, odf_tokens, std::move(context));
+
+ xmlns_repository ns_repo;
+ ns_repo.add_predefined_values(NS_odf_all);
+
+ orcus::config config(format_t::ods);
+ config.debug = true;
+ xml_stream_parser parser(
+ config, ns_repo, odf_tokens,
+ s.data(), s.size());
+ parser.set_handler(&stream_handler);
+ parser.parse();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_import_xlsx.cpp b/src/liborcus/orcus_import_xlsx.cpp
new file mode 100644
index 0000000..265f419
--- /dev/null
+++ b/src/liborcus/orcus_import_xlsx.cpp
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_import_xlsx.hpp"
+
+#include "orcus/xml_namespace.hpp"
+#include "orcus/spreadsheet/import_interface.hpp"
+#include "orcus/config.hpp"
+
+#include "xlsx_types.hpp"
+#include "xlsx_handler.hpp"
+#include "ooxml_tokens.hpp"
+
+#include "xml_stream_parser.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "xlsx_session_data.hpp"
+#include "ooxml_global.hpp"
+
+namespace orcus {
+
+void import_xlsx::read_table(
+ std::string_view s,
+ spreadsheet::iface::import_table& table,
+ spreadsheet::iface::import_reference_resolver& resolver)
+{
+ if (s.empty())
+ return;
+
+ session_context cxt;
+ auto handler = std::make_unique<xlsx_table_xml_handler>(cxt, ooxml_tokens, table, resolver);
+
+ xmlns_repository ns_repo;
+ ns_repo.add_predefined_values(NS_ooxml_all);
+ ns_repo.add_predefined_values(NS_opc_all);
+ ns_repo.add_predefined_values(NS_misc_all);
+
+ orcus::config config(format_t::xlsx);
+ xml_stream_parser parser(
+ config, ns_repo, ooxml_tokens,
+ s.data(), s.size());
+ parser.set_handler(handler.get());
+ parser.parse();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_json.cpp b/src/liborcus/orcus_json.cpp
new file mode 100644
index 0000000..9b6195f
--- /dev/null
+++ b/src/liborcus/orcus_json.cpp
@@ -0,0 +1,513 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/orcus_json.hpp>
+#include <orcus/json_document_tree.hpp>
+#include <orcus/json_structure_tree.hpp>
+#include <orcus/config.hpp>
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/json_parser.hpp>
+#include <orcus/stream.hpp>
+
+#include "json_map_tree.hpp"
+#include "json_structure_mapper.hpp"
+
+#include <iostream>
+#include <sstream>
+
+namespace orcus {
+
+namespace {
+
+struct json_value
+{
+ enum class value_type { string, numeric, boolean, null };
+
+ value_type type;
+
+ union
+ {
+ struct { const char* p; size_t n; } str;
+ double numeric;
+ bool boolean;
+
+ } value;
+
+ json_value(double v) : type(value_type::numeric)
+ {
+ value.numeric = v;
+ }
+
+ json_value(const char* p, size_t n) : type(value_type::string)
+ {
+ value.str.p = p;
+ value.str.n = n;
+ }
+
+ json_value(bool v) : type(value_type::boolean)
+ {
+ value.boolean = v;
+ }
+
+ json_value(value_type vt) : type(vt) {}
+
+ void commit(spreadsheet::iface::import_factory& im_factory, const cell_position_t& pos) const
+ {
+ spreadsheet::iface::import_sheet* sheet = im_factory.get_sheet(pos.sheet);
+
+ if (!sheet)
+ return;
+
+ switch (type)
+ {
+ case value_type::string:
+ {
+ spreadsheet::iface::import_shared_strings* ss = im_factory.get_shared_strings();
+ if (!ss)
+ break;
+
+ size_t sid = ss->add({value.str.p, value.str.n});
+ sheet->set_string(pos.row, pos.col, sid);
+ break;
+ }
+ case value_type::numeric:
+ sheet->set_value(pos.row, pos.col, value.numeric);
+ break;
+ case value_type::boolean:
+ sheet->set_bool(pos.row, pos.col, value.boolean);
+ break;
+ case value_type::null:
+ break;
+ }
+ }
+};
+
+class json_content_handler
+{
+ json_map_tree::walker m_walker;
+ json_map_tree::node* mp_current_node;
+ json_map_tree::range_reference_type* mp_increment_row;
+
+ struct row_group_scope
+ {
+ json_map_tree::node* node;
+ spreadsheet::row_t row_position;
+
+ row_group_scope(json_map_tree::node* _node, spreadsheet::row_t _row_position) :
+ node(_node), row_position(_row_position) {}
+ };
+
+ /**
+ * Stack of row group nodes, used to keep track of whether or not we are
+ * currently within a linked range.
+ */
+ std::vector<row_group_scope> m_row_group_stack;
+
+ spreadsheet::iface::import_factory& m_im_factory;
+
+public:
+ json_content_handler(const json_map_tree& map_tree, spreadsheet::iface::import_factory& im_factory) :
+ m_walker(map_tree.get_tree_walker()),
+ mp_current_node(nullptr),
+ mp_increment_row(nullptr),
+ m_im_factory(im_factory) {}
+
+ void begin_parse() {}
+ void end_parse() {}
+
+ void begin_array()
+ {
+ push_node(json_map_tree::input_node_type::array);
+ }
+
+ void end_array()
+ {
+ pop_node(json_map_tree::input_node_type::array);
+ }
+
+ void begin_object()
+ {
+ push_node(json_map_tree::input_node_type::object);
+ }
+
+ void object_key(std::string_view key, bool /*transient*/)
+ {
+ m_walker.set_object_key(key.data(), key.size());
+ }
+
+ void end_object()
+ {
+ pop_node(json_map_tree::input_node_type::object);
+ }
+
+ void boolean_true()
+ {
+ push_node(json_map_tree::input_node_type::value);
+ commit_value(true);
+ pop_node(json_map_tree::input_node_type::value);
+ }
+
+ void boolean_false()
+ {
+ push_node(json_map_tree::input_node_type::value);
+ commit_value(false);
+ pop_node(json_map_tree::input_node_type::value);
+ }
+
+ void null()
+ {
+ push_node(json_map_tree::input_node_type::value);
+ commit_value(json_value::value_type::null);
+ pop_node(json_map_tree::input_node_type::value);
+ }
+
+ void string(std::string_view val, bool /*transient*/)
+ {
+ push_node(json_map_tree::input_node_type::value);
+ commit_value(json_value(val.data(), val.size()));
+ pop_node(json_map_tree::input_node_type::value);
+ }
+
+ void number(double val)
+ {
+ push_node(json_map_tree::input_node_type::value);
+ commit_value(val);
+ pop_node(json_map_tree::input_node_type::value);
+ }
+
+private:
+
+ void push_node(json_map_tree::input_node_type nt)
+ {
+ if (!m_row_group_stack.empty() && mp_current_node)
+ {
+ if (mp_current_node->row_group && mp_increment_row == mp_current_node->row_group)
+ {
+ // The last closing node was a row group boundary. Increment the row position.
+ ++mp_current_node->row_group->row_position;
+ mp_increment_row = nullptr;
+ }
+ }
+
+ mp_current_node = m_walker.push_node(nt);
+
+ if (mp_current_node && mp_current_node->row_group)
+ {
+ m_row_group_stack.emplace_back(
+ mp_current_node, mp_current_node->row_group->row_position);
+ }
+ }
+
+ void pop_node(json_map_tree::input_node_type nt)
+ {
+ spreadsheet::row_t row_start = -1;
+ spreadsheet::row_t row_end = -1;
+ json_map_tree::range_reference_type* fill_down_ref = nullptr;
+
+ if (mp_current_node && mp_current_node->row_group)
+ {
+ // We are exiting a row group.
+ assert(!m_row_group_stack.empty());
+ assert(m_row_group_stack.back().node == mp_current_node);
+
+ // Record the current row range for this level.
+ row_start = m_row_group_stack.back().row_position;
+ row_end = mp_current_node->row_group->row_position;
+
+ if (row_end > row_start && m_row_group_stack.size() > 1)
+ {
+ // The current range is longer than 1. We need to perform fill-downs for the parent level.
+ fill_down_ref = mp_current_node->row_group;
+
+ if (fill_down_ref->row_header)
+ {
+ // Account for the row header.
+ ++row_start;
+ ++row_end;
+ }
+ }
+
+ m_row_group_stack.pop_back();
+ }
+
+ mp_current_node = m_walker.pop_node(nt);
+
+ if (!m_row_group_stack.empty())
+ {
+ if (mp_current_node && mp_current_node->row_group)
+ {
+ assert(m_row_group_stack.back().node == mp_current_node);
+ mp_increment_row = mp_current_node->row_group;
+ }
+
+ if (fill_down_ref)
+ {
+ // Perform fill-downs for all anchored fields.
+ const cell_position_t& pos = fill_down_ref->pos;
+ spreadsheet::iface::import_sheet* sheet = m_im_factory.get_sheet(pos.sheet);
+
+ if (sheet)
+ {
+ json_map_tree::node* node = m_row_group_stack.back().node;
+ for (const json_map_tree::node* anchored_field : node->anchored_fields)
+ {
+ spreadsheet::col_t col_offset =
+ anchored_field->value.range_field_ref->column_pos;
+ sheet->fill_down_cells(
+ pos.row + row_start, pos.col + col_offset, row_end - row_start);
+ }
+ }
+ }
+ }
+ }
+
+ void commit_value(const json_value& v)
+ {
+ if (!mp_current_node)
+ return;
+
+ switch (mp_current_node->type)
+ {
+ case json_map_tree::map_node_type::cell_ref:
+ {
+ // Single cell reference
+ v.commit(m_im_factory, mp_current_node->value.cell_ref->pos);
+ break;
+ }
+ case json_map_tree::map_node_type::range_field_ref:
+ {
+ // Range field reference. Offset from the origin before
+ // pushing the value.
+ spreadsheet::col_t col_offset = mp_current_node->value.range_field_ref->column_pos;
+ json_map_tree::range_reference_type* ref = mp_current_node->value.range_field_ref->ref;
+
+ cell_position_t pos = ref->pos; // copy
+ pos.col += col_offset;
+ pos.row += ref->row_position;
+ if (ref->row_header)
+ ++pos.row; // Account for the row header.
+
+ v.commit(m_im_factory, pos);
+ break;
+ }
+ default:
+ ;
+ }
+ }
+};
+
+} // anonymous namespace
+
+struct orcus_json::impl
+{
+ spreadsheet::iface::import_factory* im_factory;
+ spreadsheet::sheet_t sheet_count;
+ json_map_tree map_tree;
+
+ impl(spreadsheet::iface::import_factory* _im_factory) :
+ im_factory(_im_factory), sheet_count(0) {}
+};
+
+orcus_json::orcus_json(spreadsheet::iface::import_factory* im_fact) :
+ mp_impl(std::make_unique<impl>(im_fact)) {}
+
+orcus_json::~orcus_json() {}
+
+void orcus_json::set_cell_link(std::string_view path, std::string_view sheet, spreadsheet::row_t row, spreadsheet::col_t col)
+{
+ mp_impl->map_tree.set_cell_link(path, cell_position_t(sheet, row, col));
+}
+
+void orcus_json::start_range(std::string_view sheet, spreadsheet::row_t row, spreadsheet::col_t col, bool row_header)
+{
+ mp_impl->map_tree.start_range(cell_position_t(sheet, row, col), row_header);
+}
+
+void orcus_json::append_field_link(std::string_view path, std::string_view label)
+{
+ mp_impl->map_tree.append_field_link(path, label);
+}
+
+void orcus_json::set_range_row_group(std::string_view path)
+{
+ mp_impl->map_tree.set_range_row_group(path);
+}
+
+void orcus_json::commit_range()
+{
+ mp_impl->map_tree.commit_range();
+}
+
+void orcus_json::append_sheet(std::string_view name)
+{
+ if (name.empty())
+ return;
+
+ mp_impl->im_factory->append_sheet(mp_impl->sheet_count++, name);
+}
+
+void orcus_json::read_stream(std::string_view stream)
+{
+ if (!mp_impl->im_factory)
+ return;
+
+ spreadsheet::iface::import_shared_strings* ss = mp_impl->im_factory->get_shared_strings();
+ if (!ss)
+ return;
+
+ // Insert range headers first (if applicable).
+ for (const auto& entry : mp_impl->map_tree.get_range_references())
+ {
+ const json_map_tree::range_reference_type& ref = entry.second;
+ if (!ref.row_header)
+ // This range does not use row header.
+ continue;
+
+ const cell_position_t& origin = ref.pos;
+
+ spreadsheet::iface::import_sheet* sheet = mp_impl->im_factory->get_sheet(origin.sheet);
+
+ if (!sheet)
+ continue;
+
+ for (const json_map_tree::range_field_reference_type* field : ref.fields)
+ {
+ cell_position_t pos = origin;
+ pos.col += field->column_pos;
+ size_t sid = ss->add(field->label);
+ sheet->set_string(pos.row, pos.col, sid);
+ }
+ }
+
+ json_content_handler hdl(mp_impl->map_tree, *mp_impl->im_factory);
+ json_parser<json_content_handler> parser(stream, hdl);
+ parser.parse();
+
+ mp_impl->im_factory->finalize();
+}
+
+void orcus_json::read_map_definition(std::string_view stream)
+{
+ try
+ {
+ // Since a typical map file will likely be very small, let's be lazy and
+ // load the whole thing into a in-memory tree.
+ json::document_tree map_doc;
+ json_config jc;
+ jc.preserve_object_order = false;
+ jc.persistent_string_values = false;
+ jc.resolve_references = false;
+
+ map_doc.load(stream, jc);
+ json::const_node root = map_doc.get_document_root();
+
+ // Create sheets first.
+
+ if (!root.has_key("sheets"))
+ throw json_structure_error("The map definition must contains 'sheets' section.");
+
+ for (const json::const_node& node_name : root.child("sheets"))
+ append_sheet(node_name.string_value());
+
+ if (root.has_key("cells"))
+ {
+ // Set cell links.
+ for (const json::const_node& link_node : root.child("cells"))
+ {
+ std::string_view path = link_node.child("path").string_value();
+ std::string_view sheet = link_node.child("sheet").string_value();
+ spreadsheet::row_t row = link_node.child("row").numeric_value();
+ spreadsheet::col_t col = link_node.child("column").numeric_value();
+
+ set_cell_link(path, sheet, row, col);
+ }
+ }
+
+ if (root.has_key("ranges"))
+ {
+ // Set range links.
+ for (const json::const_node& link_node : root.child("ranges"))
+ {
+ std::string_view sheet = link_node.child("sheet").string_value();
+ spreadsheet::row_t row = link_node.child("row").numeric_value();
+ spreadsheet::col_t col = link_node.child("column").numeric_value();
+
+ bool row_header = link_node.has_key("row-header") && link_node.child("row-header").type() == json::node_t::boolean_true;
+
+ start_range(sheet, row, col, row_header);
+
+ for (const json::const_node& field_node : link_node.child("fields"))
+ {
+ std::string_view path = field_node.child("path").string_value();
+ std::string_view label;
+ if (field_node.has_key("label"))
+ {
+ json::const_node label_node = field_node.child("label");
+ if (label_node.type() == json::node_t::string)
+ label = label_node.string_value();
+ }
+
+ append_field_link(path, label);
+ }
+
+ for (const json::const_node& rg_node : link_node.child("row-groups"))
+ {
+ std::string_view path = rg_node.child("path").string_value();
+ set_range_row_group(path);
+ }
+
+ commit_range();
+ }
+ }
+ }
+ catch (const parse_error& e)
+ {
+ std::ostringstream os;
+ os << "Error parsing the map definition file:" << std::endl
+ << std::endl
+ << create_parse_error_output(stream, e.offset()) << std::endl
+ << e.what();
+
+ throw invalid_map_error(os.str());
+ }
+}
+
+void orcus_json::detect_map_definition(std::string_view stream)
+{
+ size_t range_count = 0;
+ std::string sheet_name_prefix = "range-";
+
+ json::structure_tree::range_handler_type rh = [&](json::table_range_t&& range)
+ {
+ // Build sheet name first and insert a new sheet.
+ std::ostringstream os_sheet_name;
+ os_sheet_name << sheet_name_prefix << range_count;
+ std::string sheet_name = os_sheet_name.str();
+ append_sheet(sheet_name);
+
+ // Push the linked range.
+ start_range(sheet_name, 0, 0, true);
+
+ for (const std::string& s : range.paths)
+ append_field_link(s, std::string_view());
+
+ for (const std::string& s : range.row_groups)
+ set_range_row_group(s);
+
+ commit_range();
+
+ ++range_count;
+ };
+
+ json::structure_tree structure;
+ structure.parse(stream);
+ structure.process_ranges(rh);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_ods.cpp b/src/liborcus/orcus_ods.cpp
new file mode 100644
index 0000000..41acf65
--- /dev/null
+++ b/src/liborcus/orcus_ods.cpp
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/orcus_ods.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <orcus/zip_archive.hpp>
+#include <orcus/zip_archive_stream.hpp>
+#include <orcus/measurement.hpp>
+
+#include "xml_stream_parser.hpp"
+#include "ods_content_xml_context.hpp"
+#include "ods_session_data.hpp"
+#include "odf_document_styles_context.hpp"
+#include "odf_tokens.hpp"
+#include "odf_styles.hpp"
+#include "odf_namespace_types.hpp"
+#include "session_context.hpp"
+
+#include <cstdlib>
+#include <iostream>
+#include <vector>
+#include <cstring>
+
+namespace orcus {
+
+struct orcus_ods::impl
+{
+ xmlns_repository ns_repo;
+ session_context cxt;
+ spreadsheet::iface::import_factory* xfactory;
+
+ impl(spreadsheet::iface::import_factory* im_factory) :
+ cxt(std::make_unique<ods_session_data>()), xfactory(im_factory) {}
+};
+
+orcus_ods::orcus_ods(spreadsheet::iface::import_factory* factory) :
+ iface::import_filter(format_t::ods),
+ mp_impl(std::make_unique<impl>(factory))
+{
+ mp_impl->ns_repo.add_predefined_values(NS_odf_all);
+}
+
+orcus_ods::~orcus_ods() = default;
+
+void orcus_ods::list_content(const zip_archive& archive)
+{
+ size_t num = archive.get_file_entry_count();
+ std::cout << "number of files this archive contains: " << num << std::endl;
+
+ for (size_t i = 0; i < num; ++i)
+ {
+ std::string_view filename = archive.get_file_entry_name(i);
+ if (filename.empty())
+ std::cout << "(empty)" << std::endl;
+ else
+ std::cout << filename << std::endl;
+ }
+}
+
+void orcus_ods::read_styles(const zip_archive& archive)
+{
+ auto* xstyles = mp_impl->xfactory->get_styles();
+ if (!xstyles)
+ return;
+
+ std::vector<unsigned char> buf;
+
+ try
+ {
+ buf = archive.read_file_entry("styles.xml");
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "failed to get stat on styles.xml (reason: " << e.what() << ")" << std::endl;
+ return;
+ }
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->ns_repo, odf_tokens,
+ reinterpret_cast<const char*>(buf.data()), buf.size());
+
+ auto& ods_data = mp_impl->cxt.get_data<ods_session_data>();
+ auto context = std::make_unique<document_styles_context>(
+ mp_impl->cxt, odf_tokens, ods_data.styles_map, xstyles);
+
+ xml_stream_handler handler(mp_impl->cxt, odf_tokens, std::move(context));
+
+ parser.set_handler(&handler);
+ parser.parse();
+
+ if (get_config().debug)
+ dump_state(ods_data.styles_map, std::cout);
+}
+
+void orcus_ods::read_content(const zip_archive& archive)
+{
+ std::vector<unsigned char> buf;
+
+ try
+ {
+ buf = archive.read_file_entry("content.xml");
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "failed to get stat on content.xml (reason: " << e.what() << ")" << std::endl;
+ return;
+ }
+
+ read_content_xml(buf.data(), buf.size());
+}
+
+void orcus_ods::read_content_xml(const unsigned char* p, size_t size)
+{
+ bool use_threads = true;
+
+ if (const char* p_env = std::getenv("ORCUS_ODS_USE_THREADS"); p_env)
+ use_threads = to_bool(p_env);
+
+ auto context = std::make_unique<ods_content_xml_context>(
+ mp_impl->cxt, odf_tokens, mp_impl->xfactory);
+
+ if (use_threads)
+ {
+ threaded_xml_stream_parser parser(
+ get_config(), mp_impl->ns_repo, odf_tokens,
+ reinterpret_cast<const char*>(p), size);
+
+ xml_stream_handler handler(mp_impl->cxt, odf_tokens, std::move(context));
+ parser.set_handler(&handler);
+ parser.parse();
+
+ string_pool this_pool;
+ parser.swap_string_pool(this_pool);
+ mp_impl->cxt.spool.merge(this_pool);
+ }
+ else
+ {
+ xml_stream_parser parser(
+ get_config(), mp_impl->ns_repo, odf_tokens,
+ reinterpret_cast<const char*>(p), size);
+
+ xml_stream_handler handler(mp_impl->cxt, odf_tokens, std::move(context));
+ parser.set_handler(&handler);
+ parser.parse();
+ }
+}
+
+bool orcus_ods::detect(const unsigned char* blob, size_t size)
+{
+ zip_archive_stream_blob stream(blob, size);
+ zip_archive archive(&stream);
+
+ try
+ {
+ archive.load();
+
+ std::vector<unsigned char> buf = archive.read_file_entry("mimetype");
+
+ if (buf.empty())
+ // mimetype is empty.
+ return false;
+
+ const char* mimetype = "application/vnd.oasis.opendocument.spreadsheet";
+ size_t n = std::strlen(mimetype);
+ if (buf.size() < n)
+ return false;
+
+ if (strncmp(mimetype, reinterpret_cast<const char*>(buf.data()), n))
+ // The mimetype content differs.
+ return false;
+ }
+ catch (const zip_error&)
+ {
+ // Not a valid zip archive.
+ return false;
+ }
+
+ return true;
+}
+
+void orcus_ods::read_file(std::string_view filepath)
+{
+ zip_archive_stream_fd stream(std::string{filepath}.c_str());
+ read_file_impl(&stream);
+}
+
+void orcus_ods::read_stream(std::string_view stream)
+{
+ zip_archive_stream_blob blob(
+ reinterpret_cast<const uint8_t*>(stream.data()), stream.size());
+ read_file_impl(&blob);
+}
+
+void orcus_ods::read_file_impl(zip_archive_stream* stream)
+{
+ zip_archive archive(stream);
+ archive.load();
+ if (get_config().debug)
+ list_content(archive);
+
+ spreadsheet::formula_grammar_t old_grammar = spreadsheet::formula_grammar_t::unknown;
+
+ spreadsheet::iface::import_global_settings* gs = mp_impl->xfactory->get_global_settings();
+ if (gs)
+ {
+ old_grammar = gs->get_default_formula_grammar();
+ gs->set_default_formula_grammar(spreadsheet::formula_grammar_t::ods);
+ }
+
+ read_styles(archive);
+ read_content(archive);
+
+ mp_impl->xfactory->finalize();
+
+ if (gs)
+ // This grammar will be used
+ gs->set_default_formula_grammar(old_grammar);
+}
+
+std::string_view orcus_ods::get_name() const
+{
+ return "ods";
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_parquet.cpp b/src/liborcus/orcus_parquet.cpp
new file mode 100644
index 0000000..2bd85ac
--- /dev/null
+++ b/src/liborcus/orcus_parquet.cpp
@@ -0,0 +1,547 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/orcus_parquet.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/config.hpp>
+#include <orcus/spreadsheet/types.hpp>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#include <arrow/io/file.h>
+#include <arrow/io/memory.h>
+#include <parquet/stream_reader.h>
+#include <parquet/arrow/reader.h>
+#pragma GCC diagnostic pop
+
+#include "filesystem_env.hpp"
+
+#include <iostream>
+#include <unordered_map>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+class orcus_parquet::impl
+{
+ using columns_type = std::vector<std::pair<ss::col_t, const parquet::ColumnDescriptor*>>;
+
+ const config& m_config;
+
+ ss::iface::import_factory* m_factory = nullptr;
+ ss::iface::import_shared_strings* m_sstrings = nullptr;
+ ss::iface::import_sheet* m_sheet = nullptr;
+
+ columns_type m_columns;
+
+ parquet::StreamReader m_stream;
+
+ static columns_type init_columns(const parquet::FileMetaData& file_md)
+ {
+ columns_type columns;
+
+ const parquet::SchemaDescriptor* schema_desc = file_md.schema();
+
+ if (!schema_desc)
+ return columns;
+
+ columns.reserve(schema_desc->num_columns());
+
+ for (int i = 0; i < schema_desc->num_columns(); ++i)
+ {
+ const parquet::ColumnDescriptor* col_desc = schema_desc->Column(i);
+ columns.emplace_back(i, col_desc);
+ }
+
+ return columns;
+ }
+
+ void warn(std::string_view msg) const
+ {
+ if (!m_config.debug)
+ return;
+
+ std::cerr << "warning: " << msg << std::endl;
+ }
+
+ /**
+ * Import column labels as the first row.
+ */
+ void import_column_labels()
+ {
+ // Import column labels as first row
+ for (const auto& [col, p] : m_columns)
+ {
+ if (!m_sstrings)
+ continue;
+
+ std::size_t si = m_sstrings->add(p->name());
+ m_sheet->set_string(0, col, si);
+ }
+ }
+
+ template<typename T>
+ std::optional<T> read_or_warn(ss::row_t row, ss::col_t col)
+ {
+ T v;
+
+ try
+ {
+ m_stream >> v;
+ return v;
+ }
+ catch (const std::exception& e)
+ {
+ std::ostringstream os;
+ os << "failed to read a value for (row=" << row << "; col=" << col << "): " << e.what();
+ warn(os.str());
+ }
+
+ return std::optional<T>{};
+ }
+
+ void import_byte_array(ss::row_t row, ss::col_t col, const parquet::ColumnDescriptor* p)
+ {
+ switch (p->converted_type())
+ {
+ case parquet::ConvertedType::UTF8:
+ {
+ if (!m_sstrings)
+ {
+ m_stream.SkipColumns(1);
+ break;
+ }
+
+ if (auto v = read_or_warn<std::string>(row, col); v)
+ {
+ std::size_t si = m_sstrings->add(*v);
+ m_sheet->set_string(row, col, si);
+ }
+ break;
+ }
+ default:
+ {
+ std::ostringstream os;
+ os << "WIP: unhandled converted type for BYTE_ARRAY (converted="
+ << p->converted_type() << ")";
+ warn(os.str());
+ m_stream.SkipColumns(1);
+ }
+ }
+ }
+
+ void import_fixed_len_byte_array(ss::row_t /*row*/, ss::col_t /*col*/, const parquet::ColumnDescriptor* /*p*/)
+ {
+ warn("WIP: physical=FIXED_LEN_BYTE_ARRAY not handled yet");
+ m_stream.SkipColumns(1);
+ }
+
+ void import_int32(ss::row_t row, ss::col_t col, const parquet::ColumnDescriptor* p)
+ {
+ switch (p->converted_type())
+ {
+ case parquet::ConvertedType::NONE:
+ {
+ if (auto v = read_or_warn<int32_t>(row, col); v)
+ m_sheet->set_value(row, col, *v);
+ break;
+ }
+ default:
+ warn("WIP: unhandled converted type for INT32");
+ m_stream.SkipColumns(1);
+ }
+ }
+
+ void import_int64(ss::row_t row, ss::col_t col, const parquet::ColumnDescriptor* p)
+ {
+ switch (p->converted_type())
+ {
+ case parquet::ConvertedType::NONE:
+ {
+ if (auto v = read_or_warn<int64_t>(row, col); v)
+ m_sheet->set_value(row, col, *v);
+ break;
+ }
+ default:
+ warn("WIP: unhandled converted type for INT64");
+ m_stream.SkipColumns(1);
+ }
+ }
+
+ void import_int96(ss::row_t /*row*/, ss::col_t /*col*/, const parquet::ColumnDescriptor* /*p*/)
+ {
+ warn("WIP: physical=INT96 not handled yet");
+ m_stream.SkipColumns(1);
+ }
+
+ void import_boolean(ss::row_t row, ss::col_t col, const parquet::ColumnDescriptor* p)
+ {
+ if (p->converted_type() != parquet::ConvertedType::NONE)
+ {
+ warn("WIP: unhandled covnerted type for BOOLEAN");
+ m_stream.SkipColumns(1);
+ return;
+ }
+
+ if (auto v = read_or_warn<bool>(row, col); v)
+ m_sheet->set_bool(row, col, *v);
+ }
+
+ void import_float(ss::row_t row, ss::col_t col, const parquet::ColumnDescriptor* p)
+ {
+ if (p->converted_type() != parquet::ConvertedType::NONE)
+ {
+ warn("WIP: unhandled covnerted type for FLOAT");
+ m_stream.SkipColumns(1);
+ return;
+ }
+
+ if (auto v = read_or_warn<float>(row, col); v)
+ m_sheet->set_value(row, col, *v);
+ }
+
+ void import_double(ss::row_t row, ss::col_t col, const parquet::ColumnDescriptor* p)
+ {
+ if (p->converted_type() != parquet::ConvertedType::NONE)
+ {
+ warn("WIP: unhandled covnerted type for DOUBLE");
+ m_stream.SkipColumns(1);
+ return;
+ }
+
+ if (auto v = read_or_warn<double>(row, col); v)
+ m_sheet->set_value(row, col, *v);
+ }
+
+ void dump_metadata(const parquet::FileMetaData& metadata) const
+ {
+ if (!m_config.debug)
+ return;
+
+ auto _bool_v = [](bool v) { return v ? "true" : "false"; };
+
+ auto _version_v = [](parquet::ParquetVersion::type t) -> std::string
+ {
+ const std::unordered_map<parquet::ParquetVersion::type, std::string_view> mapping =
+ {
+ { parquet::ParquetVersion::PARQUET_1_0, "PARQUET_1_0" },
+ { parquet::ParquetVersion::PARQUET_2_4, "PARQUET_2_4" },
+ { parquet::ParquetVersion::PARQUET_2_6, "PARQUET_2_6" },
+ };
+
+ std::ostringstream os;
+ auto it = mapping.find(t);
+ os << (it == mapping.end() ? "???" : it->second) << " (" << int(t) << ")";
+ return os.str();
+ };
+
+ auto _compression_v = [](parquet::Compression::type t) -> std::string
+ {
+ const std::unordered_map<parquet::Compression::type, std::string_view> mapping =
+ {
+ { parquet::Compression::UNCOMPRESSED, "UNCOMPRESSED" },
+ { parquet::Compression::SNAPPY, "SNAPPY" },
+ { parquet::Compression::GZIP, "GZIP" },
+ { parquet::Compression::BROTLI, "BROTLI" },
+ { parquet::Compression::ZSTD, "ZSTD" },
+ { parquet::Compression::LZ4, "LZ4" },
+ { parquet::Compression::LZ4_FRAME, "LZ4_FRAME" },
+ { parquet::Compression::LZO, "LZO" },
+ { parquet::Compression::BZ2, "BZ2" },
+ { parquet::Compression::LZ4_HADOOP, "LZ4_HADOOP" },
+ };
+
+ std::ostringstream os;
+ auto it = mapping.find(t);
+ os << (it == mapping.end() ? "???" : it->second) << " (" << int(t) << ")";
+ return os.str();
+ };
+
+ std::cerr << "metadata size: " << metadata.size() << std::endl;
+ std::cerr << "version: " << _version_v(metadata.version()) << std::endl;
+ std::cerr << "created by: " << metadata.created_by() << std::endl;
+ std::cerr << "num columns: " << metadata.num_columns() << std::endl;
+ std::cerr << "num rows: " << metadata.num_rows() << std::endl;
+ std::cerr << "num row groups: " << metadata.num_row_groups() << std::endl;
+ std::cerr << "num schema elements: " << metadata.num_schema_elements() << std::endl;
+ std::cerr << "can decompress: " << _bool_v(metadata.can_decompress()) << std::endl;
+
+ for (int i = 0; i < metadata.num_row_groups(); ++i)
+ {
+ std::cerr << "row group " << i << ":" << std::endl;
+ auto rg = metadata.RowGroup(i);
+ std::cerr << " num rows: " << rg->num_rows() << std::endl;
+ std::cerr << " total byte size: " << rg->total_byte_size() << std::endl;
+ std::cerr << " total compressed size: " << rg->total_compressed_size() << std::endl;
+ std::cerr << " file offset: " << rg->file_offset() << std::endl;
+ std::cerr << " num columns: " << rg->num_columns() << std::endl;
+
+ for (int j = 0; j < rg->num_columns(); ++j)
+ {
+ std::cerr << " column chunk " << j << ":" << std::endl;
+ auto cc = rg->ColumnChunk(j);
+ std::cerr << " file path: " << cc->file_path() << std::endl;
+ std::cerr << " num values: " << cc->num_values() << std::endl;
+ std::cerr << " type: " << cc->type() << std::endl;
+ std::cerr << " data page offset: " << std::dec << cc->data_page_offset() << std::endl;
+ std::cerr << " compression: " << _compression_v(cc->compression()) << std::endl;
+ std::cerr << " has dictionary page: " << _bool_v(cc->has_dictionary_page()) << std::endl;
+
+ if (cc->has_dictionary_page())
+ std::cerr << " dictionary page offset: " << cc->dictionary_page_offset() << std::endl;
+
+ std::cerr << " has index page: " << _bool_v(cc->has_index_page()) << std::endl;
+ if (cc->has_index_page())
+ std::cerr << " index page offset: " << cc->index_page_offset() << std::endl;
+ }
+ }
+
+ if (const parquet::SchemaDescriptor* schema_desc = metadata.schema(); schema_desc)
+ {
+ std::cerr << "schema:" << std::endl;
+ std::cerr << " name: " << schema_desc->name() << std::endl;
+ std::cerr << " num columns: " << schema_desc->num_columns() << std::endl;
+
+ for (int i = 0; i < schema_desc->num_columns(); ++i)
+ {
+ if (const parquet::ColumnDescriptor* col_desc = schema_desc->Column(i); col_desc)
+ {
+ std::cerr << " column " << i << ":" << std::endl;
+ std::cerr << " name: " << col_desc->name() << std::endl;
+ std::cerr << " physical type: " << col_desc->physical_type() << std::endl;
+ std::cerr << " converted type: " << col_desc->converted_type() << std::endl;
+ std::cerr << " type length: " << col_desc->type_length() << std::endl;
+ }
+ }
+ }
+ }
+
+ /**
+ * Check to see if this file is safe to load. There are some conditions
+ * that are known to lead to trouble if we proceed to load.
+ */
+ bool is_safe_to_load(const parquet::FileMetaData& metadata) const
+ {
+ const parquet::SchemaDescriptor* schema = metadata.schema();
+ if (!schema)
+ return false;
+
+ const auto* gnode = schema->group_node();
+ if (!gnode)
+ return false;
+
+ if (schema->group_node()->field_count() != schema->num_columns())
+ // StreamReader assumes these two values to be equal, and crashes
+ // if not. But with some files the two can be different.
+ return false;
+
+ return true;
+ }
+
+ void read_stream_with_sheet_name(std::string_view sheet_name, std::string_view stream)
+ {
+ auto buf = std::make_shared<arrow::io::BufferReader>(stream);
+
+ auto file_reader = parquet::ParquetFileReader::Open(buf);
+ if (!file_reader)
+ {
+ warn("failed to open a parquet file reader from an in-memory buffer.");
+ return;
+ }
+
+ auto file_md = file_reader->metadata();
+
+ dump_metadata(*file_md);
+
+ if (!is_safe_to_load(*file_md))
+ {
+ warn("aborting because this file exhibits a condition known to lead to issues if loaded.");
+ return;
+ }
+
+ if (file_md->num_rows() < 0 || file_md->num_columns() < 0)
+ // Nothing to import. Bail out.
+ return;
+
+ m_sheet = m_factory->append_sheet(0, sheet_name);
+
+ if (!m_sheet)
+ // Failed to append sheet. Bail out.
+ return;
+
+ m_columns = init_columns(*file_md);
+ if (m_columns.empty())
+ // Column data initialization failed. Bail out.
+ return;
+
+ m_stream = parquet::StreamReader{std::move(file_reader)};
+ if (m_stream.eof())
+ return;
+
+ m_sstrings = m_factory->get_shared_strings();
+
+ import_column_labels();
+
+ for (int i = 0; i < file_md->num_rows(); ++i)
+ {
+ ss::row_t row = i + 1; // account for the header row
+
+ for (const auto& [col, p] : m_columns)
+ {
+ switch (p->physical_type())
+ {
+ case parquet::Type::BOOLEAN:
+ {
+ import_boolean(row, col, p);
+ break;
+ }
+ case parquet::Type::INT32:
+ {
+ import_int32(row, col, p);
+ break;
+ }
+ case parquet::Type::INT64:
+ {
+ import_int64(row, col, p);
+ break;
+ }
+ case parquet::Type::INT96:
+ {
+ import_int96(row, col, p);
+ break;
+ }
+ case parquet::Type::FLOAT:
+ {
+ import_float(row, col, p);
+ break;
+ }
+ case parquet::Type::DOUBLE:
+ {
+ import_double(row, col, p);
+ break;
+ }
+ case parquet::Type::BYTE_ARRAY:
+ {
+ import_byte_array(row, col, p);
+ break;
+ }
+ case parquet::Type::FIXED_LEN_BYTE_ARRAY:
+ {
+ import_fixed_len_byte_array(row, col, p);
+ break;
+ }
+ default:
+ {
+ std::ostringstream os;
+ os << "WIP: type not handled: physical=" << p->physical_type() << "; converted=" << p->converted_type();
+ warn(os.str());
+ m_stream.SkipColumns(1);
+ }
+ }
+ }
+
+ m_stream >> parquet::EndRow;
+ }
+
+ m_factory->finalize();
+ }
+
+public:
+ impl(const config& c, ss::iface::import_factory* factory) : m_config(c), m_factory(factory) {}
+
+ void read_file(fs::path filepath)
+ {
+ file_content fc(filepath.string());
+ try
+ {
+ read_stream_with_sheet_name(filepath.stem().string(), fc.str());
+ }
+ catch (const std::exception& e)
+ {
+ warn(e.what());
+ m_factory->finalize();
+ }
+ }
+
+ void read_stream(std::string_view stream)
+ {
+ try
+ {
+ read_stream_with_sheet_name("Data", stream);
+ }
+ catch (const std::exception& e)
+ {
+ warn(e.what());
+ m_factory->finalize();
+ }
+ }
+};
+
+orcus_parquet::orcus_parquet(spreadsheet::iface::import_factory* factory) :
+ iface::import_filter(format_t::parquet),
+ mp_impl(std::make_unique<impl>(get_config(), factory))
+{
+}
+
+orcus_parquet::~orcus_parquet() = default;
+
+bool orcus_parquet::detect(const unsigned char* blob, std::size_t size)
+{
+ if (size < 12u)
+ // At minimum header magic bytes (4), footer magic bytes (4), and the
+ // footer metadata length (4).
+ return false;
+
+ const auto* p = blob;
+
+ // Check the first 4 bytes.
+ if (std::string_view(reinterpret_cast<const char*>(p), 4) != "PAR1")
+ return false;
+
+ // Check the last 4 bytes.
+ p += size - 4u;
+ if (std::string_view(reinterpret_cast<const char*>(p), 4) != "PAR1")
+ return false;
+
+ // Check the footer metadata size (little endian)
+ p -= 1u;
+ std::uint32_t footer_size = *p--;
+ footer_size <<= 8;
+ footer_size |= *p--;
+ footer_size <<= 8;
+ footer_size |= *p--;
+ footer_size <<= 8;
+ footer_size |= *p;
+
+ p -= footer_size;
+ if (p <= blob)
+ // footer metadata position must be within the stream.
+ return false;
+
+ return true;
+}
+
+void orcus_parquet::read_file(std::string_view filepath)
+{
+ mp_impl->read_file(fs::path{std::string{filepath}});
+}
+
+void orcus_parquet::read_stream(std::string_view stream)
+{
+ mp_impl->read_stream(stream);
+}
+
+std::string_view orcus_parquet::get_name() const
+{
+ return "parquet";
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_xls_xml.cpp b/src/liborcus/orcus_xls_xml.cpp
new file mode 100644
index 0000000..b37f9c5
--- /dev/null
+++ b/src/liborcus/orcus_xls_xml.cpp
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_xls_xml.hpp"
+#include "orcus/stream.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/config.hpp"
+#include "orcus/spreadsheet/import_interface.hpp"
+#include "orcus/parser_base.hpp"
+
+#include "xml_stream_parser.hpp"
+#include "xls_xml_handler.hpp"
+#include "xls_xml_detection_handler.hpp"
+#include "session_context.hpp"
+#include "xls_xml_tokens.hpp"
+#include "xls_xml_namespace_types.hpp"
+#include "detection_result.hpp"
+
+#include <iostream>
+#include <locale>
+#include <codecvt>
+
+using namespace std;
+
+namespace orcus {
+
+struct orcus_xls_xml::impl
+{
+ xmlns_repository m_ns_repo;
+ session_context m_cxt;
+ spreadsheet::iface::import_factory* mp_factory;
+
+ impl(spreadsheet::iface::import_factory* factory) : mp_factory(factory) {}
+
+ void read_stream(const char* content, size_t len, const config& cnf)
+ {
+ if (!content || !len)
+ return;
+
+ spreadsheet::iface::import_global_settings* gs =
+ mp_factory->get_global_settings();
+
+ if (!gs)
+ return;
+
+ gs->set_origin_date(1899, 12, 30);
+ gs->set_default_formula_grammar(spreadsheet::formula_grammar_t::xls_xml);
+
+ xml_stream_parser parser(cnf, m_ns_repo, xls_xml_tokens, content, len);
+
+ auto handler = std::make_unique<xls_xml_handler>(m_cxt, xls_xml_tokens, mp_factory);
+
+ parser.set_handler(handler.get());
+ try
+ {
+ parser.parse();
+ }
+ catch (const parse_error& e)
+ {
+ std::cerr << create_parse_error_output(std::string_view(content, len), e.offset()) << std::endl;
+ std::cerr << e.what() << std::endl;
+ return;
+ }
+
+ mp_factory->finalize();
+ }
+};
+
+orcus_xls_xml::orcus_xls_xml(spreadsheet::iface::import_factory* factory) :
+ iface::import_filter(format_t::xls_xml),
+ mp_impl(std::make_unique<impl>(factory))
+{
+ mp_impl->m_ns_repo.add_predefined_values(NS_xls_xml_all);
+}
+
+orcus_xls_xml::~orcus_xls_xml() = default;
+
+bool orcus_xls_xml::detect(const unsigned char* buffer, size_t size)
+{
+ memory_content mem_content({reinterpret_cast<const char*>(buffer), size});
+ mem_content.convert_to_utf8();
+
+ config opt(format_t::xls_xml);
+ xmlns_repository ns_repo;
+ ns_repo.add_predefined_values(NS_xls_xml_all);
+ xml_stream_parser parser(opt, ns_repo, xls_xml_tokens, mem_content.data(), mem_content.size());
+
+ session_context cxt;
+ xls_xml_detection_handler handler(cxt, xls_xml_tokens);
+ parser.set_handler(&handler);
+ try
+ {
+ parser.parse();
+ }
+ catch (const detection_result& res)
+ {
+ return res.get_result();
+ }
+ catch (...) {}
+
+ return false;
+}
+
+void orcus_xls_xml::read_file(std::string_view filepath)
+{
+ file_content content(filepath.data());
+ if (content.empty())
+ return;
+
+ content.convert_to_utf8();
+ mp_impl->read_stream(content.data(), content.size(), get_config());
+}
+
+void orcus_xls_xml::read_stream(std::string_view stream)
+{
+ memory_content mem_content(stream);
+ if (mem_content.empty())
+ return;
+
+ mem_content.convert_to_utf8();
+ mp_impl->read_stream(mem_content.data(), mem_content.size(), get_config());
+}
+
+std::string_view orcus_xls_xml::get_name() const
+{
+ return "xls-xml";
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_xlsx.cpp b/src/liborcus/orcus_xlsx.cpp
new file mode 100644
index 0000000..db55dd2
--- /dev/null
+++ b/src/liborcus/orcus_xlsx.cpp
@@ -0,0 +1,824 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_xlsx.hpp"
+
+#include "orcus/xml_namespace.hpp"
+#include "orcus/spreadsheet/import_interface.hpp"
+#include "orcus/exception.hpp"
+#include "orcus/config.hpp"
+#include "orcus/measurement.hpp"
+
+#include "xlsx_types.hpp"
+#include "xlsx_handler.hpp"
+#include "xlsx_shared_strings_context.hpp"
+#include "xlsx_styles_context.hpp"
+#include "xlsx_workbook_context.hpp"
+#include "xlsx_revision_context.hpp"
+#include "ooxml_tokens.hpp"
+
+#include "xml_stream_parser.hpp"
+#include "xml_simple_stream_handler.hpp"
+#include "opc_reader.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "xlsx_session_data.hpp"
+#include "opc_context.hpp"
+#include "ooxml_global.hpp"
+#include "spreadsheet_iface_util.hpp"
+#include "ooxml_content_types.hpp"
+
+#include <cstdlib>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <cstring>
+#include <sstream>
+
+using namespace std;
+
+namespace orcus {
+
+class xlsx_opc_handler : public opc_reader::part_handler
+{
+ orcus_xlsx& m_parent;
+public:
+ xlsx_opc_handler(orcus_xlsx& parent) : m_parent(parent) {}
+ virtual ~xlsx_opc_handler() {}
+
+ virtual bool handle_part(
+ schema_t type, const std::string& dir_path, const std::string& file_name, opc_rel_extra* data)
+ {
+ if (type == SCH_od_rels_office_doc)
+ {
+ m_parent.read_workbook(dir_path, file_name);
+ return true;
+ }
+ else if (type == SCH_od_rels_worksheet)
+ {
+ m_parent.read_sheet(dir_path, file_name, static_cast<xlsx_rel_sheet_info*>(data));
+ return true;
+ }
+ else if (type == SCH_od_rels_shared_strings)
+ {
+ m_parent.read_shared_strings(dir_path, file_name);
+ return true;
+ }
+ else if (type == SCH_od_rels_styles)
+ {
+ m_parent.read_styles(dir_path, file_name);
+ return true;
+ }
+ else if (type == SCH_od_rels_drawing)
+ {
+ m_parent.read_drawing(dir_path, file_name);
+ return true;
+ }
+ else if (type == SCH_od_rels_table)
+ {
+ m_parent.read_table(dir_path, file_name, static_cast<xlsx_rel_table_info*>(data));
+ return true;
+ }
+ else if (type == SCH_od_rels_pivot_cache_def)
+ {
+ m_parent.read_pivot_cache_def(
+ dir_path, file_name, static_cast<xlsx_rel_pivot_cache_info*>(data));
+ return true;
+ }
+ else if (type == SCH_od_rels_pivot_cache_rec)
+ {
+ m_parent.read_pivot_cache_rec(
+ dir_path, file_name,
+ static_cast<const xlsx_rel_pivot_cache_record_info*>(data));
+ return true;
+ }
+ else if (type == SCH_od_rels_pivot_table)
+ {
+ m_parent.read_pivot_table(dir_path, file_name);
+ return true;
+ }
+ else if (type == SCH_od_rels_rev_headers)
+ {
+ m_parent.read_rev_headers(dir_path, file_name);
+ return true;
+ }
+ else if (type == SCH_od_rels_rev_log)
+ {
+ m_parent.read_rev_log(dir_path, file_name);
+ return true;
+ }
+
+ return false;
+ }
+};
+
+struct orcus_xlsx::impl
+{
+ session_context m_cxt;
+ xmlns_repository m_ns_repo;
+ spreadsheet::iface::import_factory* mp_factory;
+ xlsx_opc_handler m_opc_handler;
+ opc_reader m_opc_reader;
+
+ impl(spreadsheet::iface::import_factory* factory, orcus_xlsx& parent) :
+ m_cxt(std::make_unique<xlsx_session_data>()),
+ mp_factory(factory),
+ m_opc_handler(parent),
+ m_opc_reader(parent.get_config(), m_ns_repo, m_cxt, m_opc_handler) {}
+};
+
+orcus_xlsx::orcus_xlsx(spreadsheet::iface::import_factory* factory) :
+ iface::import_filter(format_t::xlsx),
+ mp_impl(std::make_unique<impl>(factory, *this))
+{
+ if (!factory)
+ throw std::invalid_argument("factory instance is required.");
+
+ spreadsheet::iface::import_global_settings* gs = factory->get_global_settings();
+ if (gs)
+ {
+ gs->set_origin_date(1899, 12, 30);
+ gs->set_default_formula_grammar(spreadsheet::formula_grammar_t::xlsx);
+ }
+
+ mp_impl->m_ns_repo.add_predefined_values(NS_ooxml_all);
+ mp_impl->m_ns_repo.add_predefined_values(NS_opc_all);
+ mp_impl->m_ns_repo.add_predefined_values(NS_misc_all);
+}
+
+orcus_xlsx::~orcus_xlsx() {}
+
+bool orcus_xlsx::detect(const unsigned char* blob, size_t size)
+{
+ zip_archive_stream_blob stream(blob, size);
+ zip_archive archive(&stream);
+
+ try
+ {
+ archive.load();
+
+ // Find and parse [Content_Types].xml which is required for OPC package.
+ std::vector<unsigned char> buf = archive.read_file_entry("[Content_Types].xml");
+
+ if (buf.empty())
+ return false;
+
+ config opt(format_t::xlsx);
+ xmlns_repository ns_repo;
+ ns_repo.add_predefined_values(NS_opc_all);
+ session_context session_cxt;
+ xml_stream_parser parser(
+ opt, ns_repo, opc_tokens, reinterpret_cast<const char*>(&buf[0]), buf.size());
+
+ xml_simple_stream_handler handler(
+ session_cxt, opc_tokens,
+ std::make_unique<opc_content_types_context>(session_cxt, opc_tokens));
+ parser.set_handler(&handler);
+ parser.parse();
+
+ opc_content_types_context& context =
+ static_cast<opc_content_types_context&>(handler.get_context());
+
+ std::vector<xml_part_t> parts;
+ context.pop_parts(parts);
+
+ if (parts.empty())
+ return false;
+
+ // See if we can find the workbook stream.
+ xml_part_t workbook_part("/xl/workbook.xml", CT_ooxml_xlsx_sheet_main);
+ return std::find(parts.begin(), parts.end(), workbook_part) != parts.end();
+ }
+ catch (const std::exception&)
+ {
+ return false;
+ }
+}
+
+void orcus_xlsx::read_file(std::string_view filepath)
+{
+ std::unique_ptr<zip_archive_stream> stream(
+ new zip_archive_stream_fd(std::string{filepath}.c_str()));
+ mp_impl->m_opc_reader.read_file(std::move(stream));
+
+ // Formulas need to be inserted to the document after the shared string
+ // table get imported, because tokenization of formulas may add new shared
+ // string instances.
+ set_formulas_to_doc();
+
+ mp_impl->mp_factory->finalize();
+}
+
+void orcus_xlsx::read_stream(std::string_view stream)
+{
+ std::unique_ptr<zip_archive_stream> blob(
+ new zip_archive_stream_blob(
+ reinterpret_cast<const uint8_t*>(stream.data()), stream.size()));
+ mp_impl->m_opc_reader.read_file(std::move(blob));
+
+ // Formulas need to be inserted to the document after the shared string
+ // table get imported, because tokenization of formulas may add new shared
+ // string instances.
+ set_formulas_to_doc();
+
+ mp_impl->mp_factory->finalize();
+}
+
+std::string_view orcus_xlsx::get_name() const
+{
+ return "xlsx";
+}
+
+void orcus_xlsx::set_formulas_to_doc()
+{
+ auto push_formula_result = [this](spreadsheet::iface::import_formula* formula, const formula_result& res)
+ {
+ switch (res.type)
+ {
+ case formula_result::result_type::numeric:
+ formula->set_result_value(res.value_numeric);
+ break;
+ case formula_result::result_type::string:
+ formula->set_result_string({res.value_string.p, res.value_string.n});
+ break;
+ case formula_result::result_type::empty:
+ break;
+ default:
+ {
+ if (get_config().debug)
+ std::cerr << "warning: unhandled formula result (orcus_xlsx::set_formulas_to_doc)" << std::endl;
+ }
+ }
+ };
+
+ auto& sdata = mp_impl->m_cxt.get_data<xlsx_session_data>();
+
+ // Insert shared formulas first.
+ for (auto& p : sdata.m_shared_formulas)
+ {
+ xlsx_session_data::shared_formula& sf = *p;
+ spreadsheet::iface::import_sheet* sheet = mp_impl->mp_factory->get_sheet(sf.sheet);
+ if (!sheet)
+ continue;
+
+ spreadsheet::iface::import_formula* formula = sheet->get_formula();
+ if (!formula)
+ continue;
+
+ formula->set_position(sf.row, sf.column);
+ if (sf.master)
+ formula->set_formula(orcus::spreadsheet::formula_grammar_t::xlsx, sf.formula);
+ formula->set_shared_formula_index(sf.identifier);
+
+ push_formula_result(formula, sf.result);
+ formula->commit();
+ }
+
+ // Insert regular (non-shared) formulas.
+ for (auto& p : sdata.m_formulas)
+ {
+ xlsx_session_data::formula& f = *p;
+ spreadsheet::iface::import_sheet* sheet = mp_impl->mp_factory->get_sheet(f.sheet);
+ if (!sheet)
+ continue;
+
+ spreadsheet::iface::import_formula* formula = sheet->get_formula();
+ if (!formula)
+ continue;
+
+ formula->set_position(f.ref.row, f.ref.column);
+ formula->set_formula(orcus::spreadsheet::formula_grammar_t::xlsx, f.exp);
+
+ push_formula_result(formula, f.result);
+ formula->commit();
+ }
+
+ // Insert array formulas.
+ for (auto& p : sdata.m_array_formulas)
+ {
+ xlsx_session_data::array_formula& af = *p;
+ spreadsheet::iface::import_sheet* sheet = mp_impl->mp_factory->get_sheet(af.sheet);
+ if (!sheet)
+ continue;
+
+ spreadsheet::iface::import_array_formula* xaf = sheet->get_array_formula();
+ push_array_formula(xaf, af.ref, af.exp, spreadsheet::formula_grammar_t::xlsx, *af.results);
+ }
+}
+
+namespace {
+
+size_t get_schema_rank(const schema_t sch)
+{
+ using map_type = std::unordered_map <schema_t, size_t>;
+
+ static const schema_t schema_rank[] = {
+ SCH_od_rels_shared_strings,
+ SCH_od_rels_pivot_cache_def,
+ SCH_od_rels_worksheet,
+ nullptr
+ };
+
+ static map_type rank_map;
+
+ if (rank_map.empty())
+ {
+ // initialize it.
+ size_t rank = 0;
+ for (const schema_t* p = schema_rank; *p; ++rank, ++p)
+ {
+ rank_map.insert(
+ map_type::value_type(*p, rank));
+ }
+ }
+
+ auto it = rank_map.find(sch);
+ return it == rank_map.end() ? numeric_limits<size_t>::max() : it->second;
+}
+
+}
+
+void orcus_xlsx::read_workbook(const string& dir_path, const string& file_name)
+{
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ cout << "read_workbook: file path = " << filepath << endl;
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ return;
+
+ if (buffer.empty())
+ return;
+
+ auto handler = std::make_unique<xml_simple_stream_handler>(
+ mp_impl->m_cxt, ooxml_tokens,
+ std::make_unique<xlsx_workbook_context>(mp_impl->m_cxt, ooxml_tokens, *mp_impl->mp_factory));
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+ parser.set_handler(handler.get());
+ parser.parse();
+
+ // Get sheet info from the context instance.
+ xlsx_workbook_context& context =
+ static_cast<xlsx_workbook_context&>(handler->get_context());
+ opc_rel_extras_t workbook_data;
+ context.pop_workbook_info(workbook_data);
+ if (get_config().debug)
+ {
+ for_each(workbook_data.data.begin(), workbook_data.data.end(),
+ [](const opc_rel_extras_t::map_type::value_type& v)
+ {
+ const xlsx_rel_sheet_info* info =
+ dynamic_cast<const xlsx_rel_sheet_info*>(v.second.get());
+
+ if (info)
+ {
+ cout << "relationship id: " << v.first << "; sheet name: " << info->name << "; sheet id: " << info->id << endl;
+ }
+
+ const xlsx_rel_pivot_cache_info* info_pc =
+ dynamic_cast<const xlsx_rel_pivot_cache_info*>(v.second.get());
+
+ if (info_pc)
+ {
+ cout << "relationship id: " << v.first << "; pivot cache id: " << info_pc->id << endl;
+ }
+ }
+ );
+ }
+
+ handler.reset();
+
+ // Re-order the relation items so that shared strings get imported first,
+ // pivot caches get imported before the sheets and so on.
+
+ opc_reader::sort_compare_type sort_func =
+ [](const opc_rel_t& left, const opc_rel_t& right)
+ {
+ size_t rank_left = get_schema_rank(left.type), rank_right = get_schema_rank(right.type);
+ if (rank_left != rank_right)
+ return rank_left < rank_right;
+
+ std::string_view rid1 = left.rid, rid2 = right.rid;
+
+ if (rid1.size() > 1 && rid2.size() > 1)
+ {
+ // numerical comparison of relation ID's.
+ rid1 = std::string_view(rid1.data()+1, rid1.size()-1); // remove the 'r' prefix.
+ rid2 = std::string_view(rid2.data()+1, rid2.size()-1); // remove the 'r' prefix.
+ return to_long(rid1) < to_long(rid2);
+ }
+
+ // textural comparison of relation ID's.
+ return left.rid < right.rid;
+ };
+
+ mp_impl->m_opc_reader.check_relation_part(file_name, &workbook_data, &sort_func);
+}
+
+void orcus_xlsx::read_sheet(
+ const std::string& dir_path, const std::string& file_name, xlsx_rel_sheet_info* data)
+{
+ if (!data || !data->id)
+ // Sheet ID must not be 0.
+ return;
+
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "read_sheet: file path = " << filepath << endl;
+ }
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ return;
+
+ if (buffer.empty())
+ return;
+
+ if (get_config().debug)
+ {
+ cout << "relationship sheet data: " << endl;
+ cout << " sheet name: " << data->name << " sheet ID: " << data->id << endl;
+ }
+
+ spreadsheet::iface::import_sheet* sheet = mp_impl->mp_factory->get_sheet(data->name);
+ if (!sheet)
+ {
+ std::ostringstream os;
+ os << "orcus_xlsx::read_sheet: ";
+ os << "sheet named '" << data->name << "' doesn't exist.";
+ throw general_error(os.str());
+ }
+
+ spreadsheet::iface::import_reference_resolver* resolver =
+ mp_impl->mp_factory->get_reference_resolver(spreadsheet::formula_ref_context_t::global);
+ if (!resolver)
+ throw general_error("orcus_xlsx::read_sheet: reference resolver interface is not available.");
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+
+ auto handler = std::make_unique<xlsx_sheet_xml_handler>(
+ mp_impl->m_cxt, ooxml_tokens, data->id-1, *resolver, *sheet);
+
+ parser.set_handler(handler.get());
+ parser.parse();
+
+ opc_rel_extras_t table_info;
+ handler->pop_rel_extras(table_info);
+ handler.reset();
+ mp_impl->m_opc_reader.check_relation_part(file_name, &table_info);
+}
+
+void orcus_xlsx::read_shared_strings(const std::string& dir_path, const std::string& file_name)
+{
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "read_shared_strings: file path = " << filepath << endl;
+ }
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ return;
+
+ if (buffer.empty())
+ return;
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+
+ auto handler = std::make_unique<xml_simple_stream_handler>(
+ mp_impl->m_cxt, ooxml_tokens,
+ std::make_unique<xlsx_shared_strings_context>(
+ mp_impl->m_cxt, ooxml_tokens, mp_impl->mp_factory->get_shared_strings()));
+
+ parser.set_handler(handler.get());
+ parser.parse();
+}
+
+void orcus_xlsx::read_styles(const std::string& dir_path, const std::string& file_name)
+{
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "read_styles: file path = " << filepath << endl;
+ }
+
+ spreadsheet::iface::import_styles* styles = mp_impl->mp_factory->get_styles();
+ if (!styles)
+ // Client code doesn't support styles.
+ return;
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ return;
+
+ if (buffer.empty())
+ return;
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+
+ auto handler = std::make_unique<xml_simple_stream_handler>(
+ mp_impl->m_cxt, ooxml_tokens,
+ std::make_unique<xlsx_styles_context>(
+ mp_impl->m_cxt, ooxml_tokens, mp_impl->mp_factory->get_styles()));
+
+ parser.set_handler(handler.get());
+ parser.parse();
+}
+
+void orcus_xlsx::read_table(const std::string& dir_path, const std::string& file_name, xlsx_rel_table_info* data)
+{
+ if (!data || !data->sheet_interface)
+ return;
+
+ spreadsheet::iface::import_table* table = data->sheet_interface->get_table();
+ if (!table)
+ // Client code doesn't support tables. No point going further.
+ return;
+
+ spreadsheet::iface::import_reference_resolver* resolver =
+ mp_impl->mp_factory->get_reference_resolver(spreadsheet::formula_ref_context_t::global);
+
+ if (!resolver)
+ // This client doesn't support reference resolver, but is required.
+ return;
+
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "read_table: file path = " << filepath << endl;
+ }
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ {
+ cerr << "failed to open zip stream: " << filepath << endl;
+ return;
+ }
+
+ if (buffer.empty())
+ return;
+
+ auto handler = std::make_unique<xlsx_table_xml_handler>(
+ mp_impl->m_cxt, ooxml_tokens, *table, *resolver);
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+ parser.set_handler(handler.get());
+ parser.parse();
+
+ handler.reset();
+}
+
+void orcus_xlsx::read_pivot_cache_def(
+ const std::string& dir_path, const std::string& file_name,
+ const xlsx_rel_pivot_cache_info* data)
+{
+ if (!data)
+ {
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "required pivot cache relation info was not present." << endl;
+ }
+ return;
+ }
+
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "read_pivot_cache_def: file path = " << filepath
+ << "; cache id = " << data->id << endl;
+ }
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ {
+ cerr << "failed to open zip stream: " << filepath << endl;
+ return;
+ }
+
+ if (buffer.empty())
+ return;
+
+ spreadsheet::iface::import_pivot_cache_definition* pcache =
+ mp_impl->mp_factory->create_pivot_cache_definition(data->id);
+
+ if (!pcache)
+ // failed to create a cache instance for whatever reason.
+ return;
+
+ auto handler = std::make_unique<xlsx_pivot_cache_def_xml_handler>(
+ mp_impl->m_cxt, ooxml_tokens, *pcache, data->id);
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+ parser.set_handler(handler.get());
+ parser.parse();
+
+ opc_rel_extras_t pcache_info = handler->pop_rel_extras();
+
+ handler.reset();
+ mp_impl->m_opc_reader.check_relation_part(file_name, &pcache_info);
+}
+
+void orcus_xlsx::read_pivot_cache_rec(
+ const std::string& dir_path, const std::string& file_name,
+ const xlsx_rel_pivot_cache_record_info* data)
+{
+ if (!data)
+ {
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "required pivot cache record relation info was not present." << endl;
+ }
+ return;
+ }
+
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "read_pivot_cache_rec: file path = " << filepath << "; cache id = " << data->id << endl;
+ }
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ {
+ cerr << "failed to open zip stream: " << filepath << endl;
+ return;
+ }
+
+ if (buffer.empty())
+ return;
+
+ spreadsheet::iface::import_pivot_cache_records* pcache_records =
+ mp_impl->mp_factory->create_pivot_cache_records(data->id);
+
+ if (!pcache_records)
+ return;
+
+ auto handler = std::make_unique<xlsx_pivot_cache_rec_xml_handler>(
+ mp_impl->m_cxt, ooxml_tokens, *pcache_records);
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+ parser.set_handler(handler.get());
+ parser.parse();
+
+ handler.reset();
+}
+
+void orcus_xlsx::read_pivot_table(const std::string& dir_path, const std::string& file_name)
+{
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "read_pivot_table: file path = " << filepath << endl;
+ }
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ {
+ cerr << "failed to open zip stream: " << filepath << endl;
+ return;
+ }
+
+ if (buffer.empty())
+ return;
+
+ auto handler = std::make_unique<xlsx_pivot_table_xml_handler>(mp_impl->m_cxt, ooxml_tokens);
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+ parser.set_handler(handler.get());
+ parser.parse();
+
+ handler.reset();
+ mp_impl->m_opc_reader.check_relation_part(file_name, nullptr);
+}
+
+void orcus_xlsx::read_rev_headers(const std::string& dir_path, const std::string& file_name)
+{
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "read_rev_headers: file path = " << filepath << endl;
+ }
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ {
+ cerr << "failed to open zip stream: " << filepath << endl;
+ return;
+ }
+
+ if (buffer.empty())
+ return;
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+
+ auto handler = std::make_unique<xml_simple_stream_handler>(
+ mp_impl->m_cxt, ooxml_tokens,
+ std::make_unique<xlsx_revheaders_context>(mp_impl->m_cxt, ooxml_tokens));
+
+ parser.set_handler(handler.get());
+ parser.parse();
+
+ handler.reset();
+ mp_impl->m_opc_reader.check_relation_part(file_name, nullptr);
+}
+
+void orcus_xlsx::read_rev_log(const std::string& dir_path, const std::string& file_name)
+{
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "read_rev_log: file path = " << filepath << endl;
+ }
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ {
+ cerr << "failed to open zip stream: " << filepath << endl;
+ return;
+ }
+
+ if (buffer.empty())
+ return;
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+
+ auto handler = std::make_unique<xml_simple_stream_handler>(
+ mp_impl->m_cxt, ooxml_tokens,
+ std::make_unique<xlsx_revlog_context>(mp_impl->m_cxt, ooxml_tokens));
+
+ parser.set_handler(handler.get());
+ parser.parse();
+
+ handler.reset();
+}
+
+void orcus_xlsx::read_drawing(const std::string& dir_path, const std::string& file_name)
+{
+ std::string filepath = resolve_file_path(dir_path, file_name);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "read_drawing: file path = " << filepath << endl;
+ }
+
+ vector<unsigned char> buffer;
+ if (!mp_impl->m_opc_reader.open_zip_stream(filepath, buffer))
+ {
+ cerr << "failed to open zip stream: " << filepath << endl;
+ return;
+ }
+
+ if (buffer.empty())
+ return;
+
+ auto handler = std::make_unique<xlsx_drawing_xml_handler>(
+ mp_impl->m_cxt, ooxml_tokens);
+
+ xml_stream_parser parser(
+ get_config(), mp_impl->m_ns_repo, ooxml_tokens,
+ reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+ parser.set_handler(handler.get());
+ parser.parse();
+
+ handler.reset();
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_xml.cpp b/src/liborcus/orcus_xml.cpp
new file mode 100644
index 0000000..e123265
--- /dev/null
+++ b/src/liborcus/orcus_xml.cpp
@@ -0,0 +1,702 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/orcus_xml.hpp>
+#include <orcus/sax_ns_parser.hpp>
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/export_interface.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/string_pool.hpp>
+
+#include "orcus_xml_impl.hpp"
+
+#define ORCUS_DEBUG_XML 0
+
+#if ORCUS_DEBUG_XML
+#include <iostream>
+#endif
+
+#include <vector>
+#include <fstream>
+
+namespace orcus {
+
+namespace {
+
+class xml_data_sax_handler
+{
+ struct scope
+ {
+ xml_name_t name;
+ std::ptrdiff_t element_open_begin;
+ std::ptrdiff_t element_open_end;
+
+ xml_map_tree::element_type type;
+
+ scope(xmlns_id_t _ns, std::string_view _name) :
+ name(_ns, _name),
+ element_open_begin(0),
+ element_open_end(0),
+ type(xml_map_tree::element_type::unknown) {}
+ };
+
+ std::vector<sax_ns_parser_attribute> m_attrs;
+ std::vector<scope> m_scopes;
+
+ string_pool m_pool;
+ spreadsheet::iface::import_factory& m_factory;
+ xml_map_tree::const_element_list_type& m_link_positions;
+ const xml_map_tree& m_map_tree;
+ xml_map_tree::walker m_map_tree_walker;
+
+ xml_map_tree::element* mp_current_elem;
+ std::string_view m_current_chars;
+ bool m_in_range_ref;
+ xml_map_tree::range_reference* mp_increment_row;
+
+private:
+
+ const sax_ns_parser_attribute* find_attr_by_name(const xml_name_t& name)
+ {
+ for (const sax_ns_parser_attribute& attr : m_attrs)
+ {
+ if (attr.ns == name.ns && attr.name == name.name)
+ return &attr;
+ }
+ return nullptr;
+ }
+
+ void set_single_link_cell(const xml_map_tree::cell_reference& ref, std::string_view val)
+ {
+ spreadsheet::iface::import_sheet* sheet = m_factory.get_sheet(ref.pos.sheet);
+ if (sheet)
+ sheet->set_auto(ref.pos.row, ref.pos.col, val);
+ }
+
+ void set_field_link_cell(xml_map_tree::field_in_range& field, std::string_view val)
+ {
+ assert(field.ref);
+ assert(!field.ref->pos.sheet.empty());
+
+ const xml_map_tree::cell_position& pos = field.ref->pos;
+ spreadsheet::iface::import_sheet* sheet = m_factory.get_sheet(pos.sheet);
+ if (sheet)
+ sheet->set_auto(
+ pos.row + field.ref->row_position,
+ pos.col + field.column_pos,
+ val);
+ }
+
+public:
+ xml_data_sax_handler(
+ spreadsheet::iface::import_factory& factory,
+ xml_map_tree::const_element_list_type& link_positions,
+ const xml_map_tree& map_tree) :
+ m_factory(factory),
+ m_link_positions(link_positions),
+ m_map_tree(map_tree),
+ m_map_tree_walker(map_tree.get_tree_walker()),
+ mp_current_elem(nullptr),
+ m_in_range_ref(false),
+ mp_increment_row(nullptr) {}
+
+ void doctype(const sax::doctype_declaration&)
+ {
+ }
+
+ void start_declaration(std::string_view)
+ {
+ }
+
+ void end_declaration(std::string_view)
+ {
+ m_attrs.clear();
+ }
+
+ void start_element(const sax_ns_parser_element& elem)
+ {
+ m_scopes.emplace_back(elem.ns, elem.name);
+ scope& cur = m_scopes.back();
+ cur.element_open_begin = elem.begin_pos;
+ cur.element_open_end = elem.end_pos;
+ m_current_chars = std::string_view{};
+
+ mp_current_elem = m_map_tree_walker.push_element({elem.ns, elem.name});
+ if (mp_current_elem)
+ {
+ if (mp_current_elem->row_group && mp_increment_row == mp_current_elem->row_group)
+ {
+ // The last closing element was a row group boundary. Increment the row position.
+ xml_map_tree::range_reference* ref = mp_current_elem->row_group;
+ ++ref->row_position;
+ mp_increment_row = nullptr;
+ }
+
+ // Go through all linked attributes that belong to this element,
+ // and see if they exist in this content xml.
+ for (const auto& p_attr : mp_current_elem->attributes)
+ {
+ const xml_map_tree::attribute& linked_attr = *p_attr;
+ const sax_ns_parser_attribute* p = find_attr_by_name(linked_attr.name);
+ if (!p)
+ continue;
+
+ // This attribute is linked. Import its value.
+
+ std::string_view val_trimmed = trim(p->value);
+ switch (linked_attr.ref_type)
+ {
+ case xml_map_tree::reference_type::cell:
+ set_single_link_cell(*linked_attr.cell_ref, val_trimmed);
+ break;
+ case xml_map_tree::reference_type::range_field:
+ {
+ set_field_link_cell(*linked_attr.field_ref, val_trimmed);
+ break;
+ }
+ default:
+ ;
+ }
+
+ // Record the namespace alias used in the content stream.
+ linked_attr.ns_alias = m_map_tree.intern_string(p->ns_alias);
+ }
+
+ if (mp_current_elem->range_parent)
+ m_in_range_ref = true;
+ }
+ m_attrs.clear();
+ }
+
+ void end_element(const sax_ns_parser_element& elem)
+ {
+ assert(!m_scopes.empty());
+
+ if (mp_current_elem)
+ {
+ switch (mp_current_elem->ref_type)
+ {
+ case xml_map_tree::reference_type::cell:
+ {
+ set_single_link_cell(*mp_current_elem->cell_ref, m_current_chars);
+ break;
+ }
+ case xml_map_tree::reference_type::range_field:
+ {
+ set_field_link_cell(*mp_current_elem->field_ref, m_current_chars);
+ break;
+ }
+ default:
+ ;
+ }
+
+ if (mp_current_elem->row_group)
+ {
+ // This element defines a row-group boundary.
+ spreadsheet::row_t row_start = mp_current_elem->row_group_position;
+ spreadsheet::row_t row_end = mp_current_elem->row_group->row_position - 1;
+ if (row_end > row_start)
+ {
+ // This is the end of a parent row-group. Fill down the
+ // cell values.
+ const xml_map_tree::range_reference& ref = *mp_current_elem->row_group;
+
+ spreadsheet::iface::import_sheet* sheet = m_factory.get_sheet(ref.pos.sheet);
+
+ if (sheet)
+ {
+ row_start += ref.pos.row + 1;
+ row_end += ref.pos.row + 1;
+
+ for (spreadsheet::col_t col : mp_current_elem->linked_range_fields)
+ {
+ col += ref.pos.col;
+ sheet->fill_down_cells(row_start, col, row_end - row_start);
+ }
+ }
+ }
+
+ mp_current_elem->row_group_position = mp_current_elem->row_group->row_position;
+ mp_increment_row = mp_current_elem->row_group;
+ }
+
+ // Store the end element position in stream for linked elements.
+ const scope& cur = m_scopes.back();
+ if (mp_current_elem->ref_type == xml_map_tree::reference_type::cell ||
+ mp_current_elem->range_parent ||
+ (!m_in_range_ref && mp_current_elem->unlinked_attribute_anchor()))
+ {
+ // either single link element, parent of range link elements,
+ // or an unlinked attribute anchor outside linked ranges.
+ mp_current_elem->stream_pos.open_begin = cur.element_open_begin;
+ mp_current_elem->stream_pos.open_end = cur.element_open_end;
+ mp_current_elem->stream_pos.close_begin = elem.begin_pos;
+ mp_current_elem->stream_pos.close_end = elem.end_pos;
+ m_link_positions.push_back(mp_current_elem);
+ }
+
+ if (mp_current_elem->range_parent)
+ m_in_range_ref = false;
+
+ // Record the namespace alias used in the content stream.
+ mp_current_elem->ns_alias = m_map_tree.intern_string(elem.ns_alias);
+ }
+
+ m_scopes.pop_back();
+ mp_current_elem = m_map_tree_walker.pop_element({elem.ns, elem.name});
+ }
+
+ void characters(std::string_view val, bool transient)
+ {
+ if (!mp_current_elem)
+ return;
+
+ m_current_chars = trim(val);
+ if (transient)
+ m_current_chars = m_pool.intern(m_current_chars).first;
+ }
+
+ void attribute(std::string_view name, std::string_view val)
+ {
+ if (name == "encoding")
+ {
+ if (auto* gs = m_factory.get_global_settings(); gs)
+ {
+ character_set_t cs = to_character_set(val);
+ gs->set_character_set(cs);
+ }
+ }
+ }
+
+ void attribute(const sax_ns_parser_attribute& at)
+ {
+ m_attrs.push_back(at);
+ }
+};
+
+/**
+ * Used in write_range_reference_group().
+ */
+struct scope
+{
+ const xml_map_tree::element& element;
+ xml_map_tree::element_store_type::const_iterator current_child_pos;
+ xml_map_tree::element_store_type::const_iterator end_child_pos;
+ bool opened:1;
+
+ scope(const scope&) = delete;
+ scope& operator=(const scope&) = delete;
+
+ scope(const xml_map_tree::element& _elem) :
+ element(_elem), opened(false)
+ {
+ current_child_pos = end_child_pos;
+
+ if (element.elem_type == xml_map_tree::element_type::unlinked)
+ {
+ current_child_pos = element.child_elements->begin();
+ end_child_pos = element.child_elements->end();
+ }
+ }
+};
+
+typedef std::vector<std::unique_ptr<scope>> scopes_type;
+
+void write_opening_element(
+ std::ostream& os, const xml_map_tree::element& elem, const xml_map_tree::range_reference& ref,
+ const spreadsheet::iface::export_sheet& sheet, spreadsheet::row_t current_row, bool self_close)
+{
+ if (elem.attributes.empty())
+ {
+ // This element has no linked attributes. Just write the element name and be done with it.
+ os << '<' << elem << '>';
+ return;
+ }
+
+ // Element has one or more linked attributes.
+
+ os << '<' << elem;
+
+ for (const auto& p_attr : elem.attributes)
+ {
+ const xml_map_tree::attribute& attr = *p_attr;
+ if (attr.ref_type != xml_map_tree::reference_type::range_field)
+ // In theory this should never happen but it won't hurt to check.
+ continue;
+
+ os << ' ' << attr << "=\"";
+ sheet.write_string(os, ref.pos.row + 1 + current_row, ref.pos.col + attr.field_ref->column_pos);
+ os << "\"";
+ }
+
+ if (self_close)
+ os << '/';
+
+ os << '>';
+}
+
+void write_opening_element(
+ std::ostream& os, const xml_map_tree::element& elem, const spreadsheet::iface::export_factory& fact, bool self_close)
+{
+ os << '<' << elem;
+ for (const auto& p_attr : elem.attributes)
+ {
+ const xml_map_tree::attribute& attr = *p_attr;
+ if (attr.ref_type != xml_map_tree::reference_type::cell)
+ // We should only see single linked cell here, as all
+ // field links are handled by the range parent above.
+ continue;
+
+ const xml_map_tree::cell_position& pos = attr.cell_ref->pos;
+
+ const spreadsheet::iface::export_sheet* sheet = fact.get_sheet(pos.sheet);
+ if (!sheet)
+ continue;
+
+ os << ' ' << attr << "=\"";
+ sheet->write_string(os, pos.row, pos.col);
+ os << "\"";
+ }
+
+ if (self_close)
+ os << '/';
+
+ os << '>';
+}
+
+/**
+ * Write to the output stream a single range reference.
+ *
+ * @param os output stream.
+ * @param root root map tree element representing the root of a single range
+ * reference.
+ * @param ref range reference data.
+ * @param factory export factory instance.
+ */
+void write_range_reference_group(
+ std::ostream& os, const xml_map_tree::element& root, const xml_map_tree::range_reference& ref,
+ const spreadsheet::iface::export_factory& factory)
+{
+ const spreadsheet::iface::export_sheet* sheet = factory.get_sheet(ref.pos.sheet);
+ if (!sheet)
+ return;
+
+ scopes_type scopes;
+ for (spreadsheet::row_t current_row = 0; current_row < ref.row_position; ++current_row)
+ {
+ scopes.push_back(std::make_unique<scope>(root)); // root element
+
+ while (!scopes.empty())
+ {
+ bool new_scope = false;
+
+ scope& cur_scope = *scopes.back();
+
+ // Self-closing element has no child elements nor content.
+ bool self_close =
+ (cur_scope.current_child_pos == cur_scope.end_child_pos) &&
+ (cur_scope.element.ref_type != xml_map_tree::reference_type::range_field);
+
+ if (!cur_scope.opened)
+ {
+ // Write opening element of this scope only on the 1st entrance.
+ write_opening_element(os, cur_scope.element, ref, *sheet, current_row, self_close);
+ cur_scope.opened = true;
+ }
+
+ if (self_close)
+ {
+ scopes.pop_back();
+ continue;
+ }
+
+ // Go though all child elements.
+ for (; cur_scope.current_child_pos != cur_scope.end_child_pos; ++cur_scope.current_child_pos)
+ {
+ const xml_map_tree::element& child_elem = **cur_scope.current_child_pos;
+ if (child_elem.elem_type == xml_map_tree::element_type::unlinked)
+ {
+ // This is a non-leaf element. Push a new scope with this
+ // element and re-start the loop.
+ ++cur_scope.current_child_pos;
+ scopes.push_back(std::make_unique<scope>(child_elem));
+ new_scope = true;
+ break;
+ }
+
+ // This is a leaf element. This must be a field link element.
+ if (child_elem.ref_type == xml_map_tree::reference_type::range_field)
+ {
+ write_opening_element(os, child_elem, ref, *sheet, current_row, false);
+ sheet->write_string(os, ref.pos.row + 1 + current_row, ref.pos.col + child_elem.field_ref->column_pos);
+ os << "</" << child_elem << ">";
+ }
+ }
+
+ if (new_scope)
+ // Re-start the loop with a new scope.
+ continue;
+
+ // Write content of this element before closing it (if it's linked).
+ if (scopes.back()->element.ref_type == xml_map_tree::reference_type::range_field)
+ sheet->write_string(
+ os, ref.pos.row + 1 + current_row, ref.pos.col + scopes.back()->element.field_ref->column_pos);
+
+ // Close this element for good, and exit the current scope.
+ os << "</" << scopes.back()->element << ">";
+ scopes.pop_back();
+ }
+ }
+}
+
+/**
+ * Write to an output stream the sub-structure comprising one or more range
+ * references.
+ *
+ * @param os output stream
+ * @param elem_top topmost element in the range reference sub-structure.
+ */
+void write_range_reference(std::ostream& os, const xml_map_tree::element& elem_top, const spreadsheet::iface::export_factory& factory)
+{
+ // Top element is expected to have one or more child elements, and each
+ // child element represents a separate database range.
+ if (elem_top.elem_type != xml_map_tree::element_type::unlinked)
+ return;
+
+ assert(elem_top.child_elements);
+
+ if (elem_top.child_elements->empty())
+ return;
+
+ // TODO: For now, we assume that there is only one child element under the
+ // range ref parent.
+ write_range_reference_group(
+ os, **elem_top.child_elements->begin(), *elem_top.range_parent, factory);
+}
+
+struct less_by_opening_elem_pos
+{
+ bool operator() (const xml_map_tree::element* left, const xml_map_tree::element* right) const
+ {
+ return left->stream_pos.open_begin < right->stream_pos.open_begin;
+ }
+};
+
+} // anonymous namespace
+
+orcus_xml::orcus_xml(xmlns_repository& ns_repo, spreadsheet::iface::import_factory* im_fact, spreadsheet::iface::export_factory* ex_fact) :
+ mp_impl(std::make_unique<impl>(ns_repo))
+{
+ mp_impl->im_factory = im_fact;
+ mp_impl->ex_factory = ex_fact;
+}
+
+orcus_xml::~orcus_xml() {}
+
+void orcus_xml::set_namespace_alias(std::string_view alias, std::string_view uri, bool default_ns)
+{
+ mp_impl->map_tree.set_namespace_alias(alias, uri, default_ns);
+}
+
+void orcus_xml::set_cell_link(std::string_view xpath, std::string_view sheet, spreadsheet::row_t row, spreadsheet::col_t col)
+{
+ std::string_view sheet_safe = mp_impl->map_tree.intern_string(sheet);
+ mp_impl->map_tree.set_cell_link(xpath, xml_map_tree::cell_position(sheet_safe, row, col));
+}
+
+void orcus_xml::start_range(std::string_view sheet, spreadsheet::row_t row, spreadsheet::col_t col)
+{
+ std::string_view sheet_safe = mp_impl->map_tree.intern_string(sheet);
+ mp_impl->cur_range_ref = xml_map_tree::cell_position(sheet_safe, row, col);
+ mp_impl->map_tree.start_range(mp_impl->cur_range_ref);
+}
+
+void orcus_xml::append_field_link(std::string_view xpath, std::string_view label)
+{
+ mp_impl->map_tree.append_range_field_link(xpath, label);
+}
+
+void orcus_xml::set_range_row_group(std::string_view xpath)
+{
+ mp_impl->map_tree.set_range_row_group(xpath);
+}
+
+void orcus_xml::commit_range()
+{
+ mp_impl->cur_range_ref = xml_map_tree::cell_position();
+ mp_impl->map_tree.commit_range();
+}
+
+void orcus_xml::append_sheet(std::string_view name)
+{
+ if (name.empty())
+ return;
+
+ mp_impl->im_factory->append_sheet(mp_impl->sheet_count++, name);
+}
+
+void orcus_xml::read_stream(std::string_view stream)
+{
+ if (stream.empty())
+ return;
+
+ // Insert the range headers and reset the row size counters.
+ xml_map_tree::range_ref_map_type& range_refs = mp_impl->map_tree.get_range_references();
+
+ for (const auto& ref_pair : range_refs)
+ {
+ const xml_map_tree::cell_position& ref = ref_pair.first;
+ xml_map_tree::range_reference& range_ref = *ref_pair.second;
+ range_ref.row_position = 1; // Reset the row offset.
+
+ spreadsheet::iface::import_sheet* sheet = mp_impl->im_factory->get_sheet(ref.sheet);
+
+ if (!sheet)
+ continue;
+
+ spreadsheet::row_t row = ref.row;
+ spreadsheet::col_t col = ref.col;
+
+ for (const xml_map_tree::linkable* e : range_ref.field_nodes)
+ {
+ if (e->label.empty())
+ {
+ // No custom header label. Create a label from the name of the linkable.
+ std::string s = e->name.to_string(mp_impl->ns_repo);
+ if (!s.empty())
+ sheet->set_auto(row, col, s);
+ }
+ else
+ sheet->set_auto(row, col, e->label);
+
+ ++col;
+ }
+ }
+
+ // Parse the content xml.
+ xmlns_context ns_cxt = mp_impl->ns_repo.create_context(); // new ns context for the content xml stream.
+ xml_data_sax_handler handler(
+ *mp_impl->im_factory, mp_impl->link_positions, mp_impl->map_tree);
+
+ sax_ns_parser<xml_data_sax_handler> parser(stream, ns_cxt, handler);
+ parser.parse();
+}
+
+#if ORCUS_DEBUG_XML
+
+namespace {
+
+void dump_links(const xml_map_tree::const_element_list_type& links)
+{
+ cout << "link count: " << links.size() << endl;
+}
+
+}
+
+#endif
+
+void orcus_xml::write(std::string_view stream, std::ostream& out) const
+{
+ if (!mp_impl->ex_factory)
+ // We can't export data witout export factory.
+ return;
+
+ if (stream.empty())
+ // Source input stream is empty.
+ return;
+
+ xml_map_tree::const_element_list_type& links = mp_impl->link_positions;
+ if (links.empty())
+ // nothing to write.
+ return;
+
+ // Sort all link position by opening element positions.
+ std::sort(links.begin(), links.end(), less_by_opening_elem_pos());
+
+ spreadsheet::iface::export_factory& fact = *mp_impl->ex_factory;
+ xml_map_tree::const_element_list_type::const_iterator it = links.begin(), it_end = links.end();
+
+#if ORCUS_DEBUG_XML
+ dump_links(links);
+#endif
+
+ const char* p0 = stream.data();
+ std::ptrdiff_t begin_pos = 0;
+
+ for (; it != it_end; ++it)
+ {
+ const xml_map_tree::element& elem = **it;
+ if (elem.ref_type == xml_map_tree::reference_type::cell)
+ {
+ // Single cell link
+ const xml_map_tree::cell_position& pos = elem.cell_ref->pos;
+
+ const spreadsheet::iface::export_sheet* sheet = fact.get_sheet(pos.sheet);
+ if (!sheet)
+ continue;
+
+ std::ptrdiff_t open_begin = elem.stream_pos.open_begin;
+ std::ptrdiff_t close_begin = elem.stream_pos.close_begin;
+ std::ptrdiff_t close_end = elem.stream_pos.close_end;
+
+ assert(open_begin > begin_pos);
+ out << std::string_view(p0+begin_pos, open_begin-begin_pos); // stream since last linked element.
+
+ write_opening_element(out, elem, fact, false);
+ sheet->write_string(out, pos.row, pos.col);
+ out << std::string_view(p0+close_begin, close_end-close_begin); // closing element.
+ begin_pos = close_end;
+ }
+ else if (elem.range_parent)
+ {
+ // Range link
+ const xml_map_tree::range_reference& ref = *elem.range_parent;
+ const xml_map_tree::cell_position& pos = ref.pos;
+
+ const spreadsheet::iface::export_sheet* sheet = fact.get_sheet(pos.sheet);
+ if (!sheet)
+ continue;
+
+ std::ptrdiff_t open_begin = elem.stream_pos.open_begin;
+ std::ptrdiff_t close_begin = elem.stream_pos.close_begin;
+ std::ptrdiff_t close_end = elem.stream_pos.close_end;
+
+ assert(open_begin > begin_pos);
+ out << std::string_view(p0+begin_pos, open_begin-begin_pos); // stream since last linked element.
+
+ write_opening_element(out, elem, fact, false);
+ write_range_reference(out, elem, fact);
+ out << std::string_view(p0+close_begin, close_end-close_begin); // closing element.
+ begin_pos = close_end;
+ }
+ else if (elem.unlinked_attribute_anchor())
+ {
+ // Element is not linked but has one or more attributes that are
+ // linked. Here, only write the opening element with attributes.
+
+ std::ptrdiff_t open_begin = elem.stream_pos.open_begin;
+ std::ptrdiff_t open_end = elem.stream_pos.open_end;
+
+ bool self_close = elem.stream_pos.open_begin == elem.stream_pos.close_begin;
+
+ assert(open_begin > begin_pos);
+ out << std::string_view(p0+begin_pos, open_begin-begin_pos); // stream since last linked element.
+
+ write_opening_element(out, elem, fact, self_close);
+ begin_pos = open_end;
+ }
+ else
+ throw general_error("Non-link element type encountered.");
+ }
+
+ // Flush the remaining stream.
+ out << std::string_view(p0+begin_pos, stream.size()-begin_pos);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_xml_impl.cpp b/src/liborcus/orcus_xml_impl.cpp
new file mode 100644
index 0000000..4718f3c
--- /dev/null
+++ b/src/liborcus/orcus_xml_impl.cpp
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus_xml_impl.hpp"
+
+namespace orcus {
+
+orcus_xml::impl::impl(xmlns_repository& _ns_repo) :
+ im_factory(nullptr),
+ ex_factory(nullptr),
+ ns_repo(_ns_repo),
+ ns_cxt_map(ns_repo.create_context()),
+ map_tree(ns_repo),
+ sheet_count(0) {}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_xml_impl.hpp b/src/liborcus/orcus_xml_impl.hpp
new file mode 100644
index 0000000..56c8156
--- /dev/null
+++ b/src/liborcus/orcus_xml_impl.hpp
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_ORCUS_XML_IMPL_HPP
+#define INCLUDED_ORCUS_ORCUS_XML_IMPL_HPP
+
+#include "orcus/orcus_xml.hpp"
+#include "orcus/xml_namespace.hpp"
+
+#include "xml_map_tree.hpp"
+
+namespace orcus {
+
+struct orcus_xml::impl
+{
+ spreadsheet::iface::import_factory* im_factory;
+ spreadsheet::iface::export_factory* ex_factory;
+
+ /** xml namespace repository for the whole session. */
+ xmlns_repository& ns_repo;
+
+ /** xml namespace context */
+ xmlns_context ns_cxt_map;
+
+ /** xml element tree that represents all mapped paths. */
+ xml_map_tree map_tree;
+
+ spreadsheet::sheet_t sheet_count;
+
+ /**
+ * Positions of all linked elements, single and range reference alike.
+ * Stored link elements must be sorted in order of stream positions, and
+ * as such, no linked elements should be nested; there should never be a
+ * linked element inside the substructure of another linked element.
+ */
+ xml_map_tree::const_element_list_type link_positions;
+
+ xml_map_tree::cell_position cur_range_ref;
+
+ explicit impl(xmlns_repository& _ns_repo);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/orcus_xml_map_def.cpp b/src/liborcus/orcus_xml_map_def.cpp
new file mode 100644
index 0000000..5c484de
--- /dev/null
+++ b/src/liborcus/orcus_xml_map_def.cpp
@@ -0,0 +1,299 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_xml.hpp"
+#include "orcus/sax_parser_base.hpp"
+#include "orcus/sax_parser.hpp"
+#include "orcus/stream.hpp"
+#include "orcus/xml_structure_tree.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/xml_writer.hpp"
+#include "orcus/measurement.hpp"
+
+#include "orcus_xml_impl.hpp"
+
+#include <vector>
+#include <iostream>
+
+namespace orcus {
+
+namespace {
+
+class xml_map_sax_handler
+{
+ struct scope
+ {
+ std::string_view ns;
+ std::string_view name;
+
+ scope(std::string_view _ns, std::string_view _name) : ns(_ns), name(_name) {}
+ };
+
+ std::vector<sax::parser_attribute> m_attrs;
+ std::vector<scope> m_scopes;
+ orcus_xml& m_app;
+
+public:
+
+ xml_map_sax_handler(orcus_xml& app) : m_app(app) {}
+
+ void doctype(const sax::doctype_declaration&) {}
+ void start_declaration(std::string_view /*name*/) {}
+
+ void end_declaration(std::string_view /*name*/)
+ {
+ m_attrs.clear();
+ }
+
+ void start_element(const sax::parser_element& elem);
+
+ void end_element(const sax::parser_element& elem)
+ {
+ if (elem.name == "range")
+ m_app.commit_range();
+
+ m_scopes.pop_back();
+ }
+
+ void attribute(const sax::parser_attribute& attr)
+ {
+ m_attrs.push_back(attr);
+ }
+
+ void characters(std::string_view, bool) {}
+};
+
+void xml_map_sax_handler::start_element(const sax::parser_element& elem)
+{
+ std::string_view xpath, sheet, label;
+ spreadsheet::row_t row = -1;
+ spreadsheet::col_t col = -1;
+
+ auto to_row = [](std::string_view s) -> spreadsheet::row_t
+ {
+ long v;
+ parse_integer(s.data(), s.data() + s.size(), v);
+ return v;
+ };
+
+ auto to_col = [](std::string_view s) -> spreadsheet::col_t
+ {
+ long v;
+ parse_integer(s.data(), s.data() + s.size(), v);
+ return v;
+ };
+
+ if (elem.name == "ns")
+ {
+ // empty alias is associated with default namespace.
+ std::string_view alias, uri;
+ bool default_ns = false;
+
+ for (const sax::parser_attribute& attr : m_attrs)
+ {
+ if (attr.name == "alias")
+ alias = attr.value;
+ else if (attr.name == "uri")
+ uri = attr.value;
+ else if (attr.name == "default")
+ default_ns = to_bool(attr.value);
+ }
+
+ if (!uri.empty())
+ m_app.set_namespace_alias(alias, uri, default_ns);
+ }
+ else if (elem.name == "cell")
+ {
+ for (const sax::parser_attribute& attr : m_attrs)
+ {
+ if (attr.name == "path")
+ xpath = attr.value;
+ else if (attr.name == "sheet")
+ sheet = attr.value;
+ else if (attr.name == "row")
+ row = to_row(attr.value);
+ else if (attr.name == "column")
+ col = to_col(attr.value);
+ }
+
+ m_app.set_cell_link(xpath, sheet, row, col);
+ }
+ else if (elem.name == "range")
+ {
+ for (const sax::parser_attribute& attr : m_attrs)
+ {
+ if (attr.name == "sheet")
+ sheet = attr.value;
+ else if (attr.name == "row")
+ row = to_row(attr.value);
+ else if (attr.name == "column")
+ col = to_col(attr.value);
+ }
+
+ m_app.start_range(sheet, row, col);
+ }
+ else if (elem.name == "field")
+ {
+ for (const sax::parser_attribute& attr : m_attrs)
+ {
+ if (attr.name == "path")
+ xpath = attr.value;
+ else if (attr.name == "label")
+ label = attr.value;
+ }
+
+ m_app.append_field_link(xpath, label);
+ }
+ else if (elem.name == "row-group")
+ {
+ for (const sax::parser_attribute& attr : m_attrs)
+ {
+ if (attr.name == "path")
+ {
+ xpath = attr.value;
+ break;
+ }
+ }
+
+ m_app.set_range_row_group(xpath);
+ }
+ else if (elem.name == "sheet")
+ {
+ std::string_view sheet_name;
+ for (const sax::parser_attribute& attr : m_attrs)
+ {
+ if (attr.name == "name")
+ {
+ sheet_name = attr.value;
+ break;
+ }
+ }
+
+ if (!sheet_name.empty())
+ m_app.append_sheet(sheet_name);
+ }
+
+ m_scopes.push_back(scope(elem.ns, elem.name));
+ m_attrs.clear();
+}
+
+} // anonymous namespace
+
+void orcus_xml::read_map_definition(std::string_view stream)
+{
+ try
+ {
+ xml_map_sax_handler handler(*this);
+ sax_parser<xml_map_sax_handler> parser(stream, handler);
+ parser.parse();
+ }
+ catch (const parse_error& e)
+ {
+ std::ostringstream os;
+ os << "Error parsing the map definition file:" << std::endl
+ << std::endl
+ << create_parse_error_output(stream, e.offset()) << std::endl
+ << e.what();
+
+ throw invalid_map_error(os.str());
+ }
+}
+
+void orcus_xml::detect_map_definition(std::string_view stream)
+{
+ size_t range_count = 0;
+ std::string sheet_name_prefix = "range-";
+
+ xml_structure_tree::range_handler_type rh = [&](xml_table_range_t&& range)
+ {
+ // Build sheet name first and insert a new sheet.
+ std::ostringstream os_sheet_name;
+ os_sheet_name << sheet_name_prefix << range_count;
+ std::string sheet_name = os_sheet_name.str();
+ append_sheet(sheet_name);
+
+ // Push the linked range.
+ start_range(sheet_name, 0, 0);
+
+ for (const auto& path : range.paths)
+ append_field_link(path, std::string_view());
+
+ for (const auto& row_group : range.row_groups)
+ set_range_row_group(row_group);
+
+ commit_range();
+
+ ++range_count;
+ };
+
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+ xml_structure_tree structure(cxt);
+ structure.parse(stream);
+
+ // Register all namespace aliases first.
+ for (const xmlns_id_t& ns : cxt.get_all_namespaces())
+ set_namespace_alias(cxt.get_short_name(ns), std::string_view(ns));
+
+ structure.process_ranges(rh);
+}
+
+void orcus_xml::write_map_definition(std::string_view stream, std::ostream& out) const
+{
+ xmlns_context cxt = mp_impl->ns_repo.create_context();
+ xml_structure_tree tree(cxt);
+ tree.parse(stream);
+
+ xml_writer writer(mp_impl->ns_repo, out);
+ xmlns_id_t default_ns = writer.add_namespace("", "https://gitlab.com/orcus/orcus/xml-map-definition");
+ auto map_scope = writer.push_element_scope({default_ns, "map"});
+
+ for (const xmlns_id_t& ns : cxt.get_all_namespaces())
+ {
+ writer.add_attribute({default_ns, "alias"}, cxt.get_short_name(ns));
+ writer.add_attribute({default_ns, "uri"}, ns);
+ writer.push_element_scope({default_ns, "ns"});
+ }
+
+ size_t range_count = 0;
+ std::string sheet_name_prefix = "range-";
+
+ xml_structure_tree::range_handler_type rh = [&](xml_table_range_t&& range)
+ {
+ std::ostringstream os_sheet_name;
+ os_sheet_name << sheet_name_prefix << range_count;
+ std::string sheet_name = os_sheet_name.str();
+
+ writer.add_attribute({default_ns, "name"}, sheet_name);
+ writer.push_element_scope({default_ns, "sheet"});
+
+ writer.add_attribute({default_ns, "sheet"}, sheet_name);
+ writer.add_attribute({default_ns, "row"}, "0");
+ writer.add_attribute({default_ns, "column"}, "0");
+ auto range_scope = writer.push_element_scope({default_ns, "range"});
+
+ for (const auto& path : range.paths)
+ {
+ writer.add_attribute({default_ns, "path"}, path);
+ writer.push_element_scope({default_ns, "field"});
+ }
+
+ for (const auto& row_group : range.row_groups)
+ {
+ writer.add_attribute({default_ns, "path"}, row_group);
+ writer.push_element_scope({default_ns, "row-group"});
+ }
+
+ ++range_count;
+ };
+
+ tree.process_ranges(rh);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/session_context.cpp b/src/liborcus/session_context.cpp
new file mode 100644
index 0000000..b054106
--- /dev/null
+++ b/src/liborcus/session_context.cpp
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "session_context.hpp"
+
+namespace orcus {
+
+session_context::custom_data::~custom_data() {}
+
+session_context::session_context(std::unique_ptr<custom_data> data) : cdata(std::move(data)) {}
+
+std::string_view session_context::intern(const xml_token_attr_t& attr)
+{
+ // NB: always intern regardless of the transient flag since the string may
+ // be used in another stream.
+ return spool.intern(attr.value).first;
+}
+
+std::string_view session_context::intern(std::string_view s)
+{
+ return spool.intern(s).first;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/session_context.hpp b/src/liborcus/session_context.hpp
new file mode 100644
index 0000000..ab50836
--- /dev/null
+++ b/src/liborcus/session_context.hpp
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SESSION_CONTEXT_HPP
+#define INCLUDED_ORCUS_SESSION_CONTEXT_HPP
+
+#include <orcus/string_pool.hpp>
+#include <orcus/types.hpp>
+
+#include <memory>
+
+namespace orcus {
+
+struct session_context
+{
+ session_context(const session_context&) = delete;
+ session_context& operator=(const session_context&) = delete;
+
+ string_pool spool;
+
+ /**
+ * Derive from this class in case the filter needs to store its own
+ * session data.
+ */
+ struct custom_data
+ {
+ virtual ~custom_data() = 0;
+ };
+
+ std::unique_ptr<custom_data> cdata;
+
+ session_context() = default;
+ session_context(std::unique_ptr<custom_data> data);
+
+ template<typename CDataT>
+ CDataT& get_data()
+ {
+ return static_cast<CDataT&>(*cdata);
+ }
+
+ template<typename CDataT>
+ const CDataT& get_data() const
+ {
+ return static_cast<const CDataT&>(*cdata);
+ }
+
+ std::string_view intern(const xml_token_attr_t& attr);
+ std::string_view intern(std::string_view s);
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/spreadsheet_iface_util.cpp b/src/liborcus/spreadsheet_iface_util.cpp
new file mode 100644
index 0000000..740864c
--- /dev/null
+++ b/src/liborcus/spreadsheet_iface_util.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "spreadsheet_iface_util.hpp"
+#include "formula_result.hpp"
+
+#include "orcus/spreadsheet/import_interface.hpp"
+
+namespace orcus {
+
+void push_array_formula(
+ spreadsheet::iface::import_array_formula* xformula,
+ const spreadsheet::range_t& range, std::string_view formula,
+ spreadsheet::formula_grammar_t grammar, const range_formula_results& results)
+{
+ xformula->set_range(range);
+ xformula->set_formula(grammar, formula);
+
+ for (size_t row = 0; row < results.row_size(); ++row)
+ {
+ for (size_t col = 0; col < results.col_size(); ++col)
+ {
+ const formula_result& v = results.get(row, col);
+ switch (v.type)
+ {
+ case formula_result::result_type::numeric:
+ xformula->set_result_value(row, col, v.value_numeric);
+ break;
+ case formula_result::result_type::string:
+ xformula->set_result_string(row, col, {v.value_string.p, v.value_string.n});
+ break;
+ case formula_result::result_type::boolean:
+ xformula->set_result_bool(row, col, v.value_boolean);
+ break;
+ case formula_result::result_type::empty:
+ xformula->set_result_empty(row, col);
+ break;
+ default:
+ ;
+ }
+ }
+ }
+
+ xformula->commit();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/spreadsheet_iface_util.hpp b/src/liborcus/spreadsheet_iface_util.hpp
new file mode 100644
index 0000000..1262be6
--- /dev/null
+++ b/src/liborcus/spreadsheet_iface_util.hpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_IFACE_UTIL_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_IFACE_UTIL_HPP
+
+#include "orcus/spreadsheet/types.hpp"
+
+namespace orcus {
+
+class range_formula_results;
+
+namespace spreadsheet {
+
+namespace iface {
+
+class import_array_formula;
+
+}
+
+}
+
+void push_array_formula(
+ spreadsheet::iface::import_array_formula* xformula,
+ const spreadsheet::range_t& range, std::string_view formula,
+ spreadsheet::formula_grammar_t grammar, const range_formula_results& results);
+
+} // namespace orcus
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/spreadsheet_impl_types.cpp b/src/liborcus/spreadsheet_impl_types.cpp
new file mode 100644
index 0000000..735f546
--- /dev/null
+++ b/src/liborcus/spreadsheet_impl_types.cpp
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "spreadsheet_impl_types.hpp"
+
+#include <ostream>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+cell_position_t::cell_position_t() : row(-1), col(-1) {}
+
+cell_position_t::cell_position_t(std::string_view _sheet, spreadsheet::row_t _row, spreadsheet::col_t _col) :
+ sheet(_sheet), row(_row), col(_col) {}
+
+cell_position_t::cell_position_t(const cell_position_t& r) : sheet(r.sheet), row(r.row), col(r.col) {}
+
+bool cell_position_t::operator== (const cell_position_t& other) const
+{
+ return sheet == other.sheet && row == other.row && col == other.col;
+}
+
+bool cell_position_t::operator!= (const cell_position_t& other) const
+{
+ return !operator==(other);
+}
+
+std::ostream& operator<< (std::ostream& os, const cell_position_t& ref)
+{
+ os << "[sheet='" << ref.sheet << "' row=" << ref.row << " column=" << ref.col << "]";
+ return os;
+}
+
+bool operator< (const cell_position_t& left, const cell_position_t& right)
+{
+ if (left.sheet != right.sheet)
+ return left.sheet < right.sheet;
+
+ if (left.row != right.row)
+ return left.row < right.row;
+
+ return left.col < right.col;
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/spreadsheet_impl_types.hpp b/src/liborcus/spreadsheet_impl_types.hpp
new file mode 100644
index 0000000..0c2c110
--- /dev/null
+++ b/src/liborcus/spreadsheet_impl_types.hpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_IMPL_TYPES_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_IMPL_TYPES_HPP
+
+#include "orcus/spreadsheet/types.hpp"
+
+#include <iosfwd>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+struct cell_position_t
+{
+ std::string_view sheet;
+ spreadsheet::row_t row;
+ spreadsheet::col_t col;
+
+ cell_position_t();
+ cell_position_t(std::string_view _sheet, spreadsheet::row_t _row, spreadsheet::col_t _col);
+ cell_position_t(const cell_position_t& r);
+
+ bool operator== (const cell_position_t& other) const;
+ bool operator!= (const cell_position_t& other) const;
+};
+
+std::ostream& operator<< (std::ostream& os, const cell_position_t& ref);
+
+bool operator< (const cell_position_t& left, const cell_position_t& right);
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/spreadsheet_interface.cpp b/src/liborcus/spreadsheet_interface.cpp
new file mode 100644
index 0000000..0accf63
--- /dev/null
+++ b/src/liborcus/spreadsheet_interface.cpp
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+#include <orcus/spreadsheet/import_interface_pivot.hpp>
+#include <orcus/spreadsheet/import_interface_view.hpp>
+#include <orcus/spreadsheet/export_interface.hpp>
+
+namespace orcus { namespace spreadsheet { namespace iface {
+
+import_sheet_view::~import_sheet_view() {}
+
+import_pivot_cache_definition::~import_pivot_cache_definition() {}
+
+import_pivot_cache_field_group::~import_pivot_cache_field_group() {}
+
+import_pivot_cache_records::~import_pivot_cache_records() {}
+
+import_shared_strings::~import_shared_strings() {}
+
+import_styles::~import_styles() {}
+
+import_font_style::~import_font_style() {}
+
+import_fill_style::~import_fill_style() {}
+
+import_border_style::~import_border_style() {}
+
+import_cell_protection::~import_cell_protection() {}
+
+import_number_format::~import_number_format() {}
+
+import_xf::~import_xf() {}
+
+import_cell_style::~import_cell_style() {}
+
+import_sheet_properties::~import_sheet_properties() {}
+
+import_named_expression::~import_named_expression() {}
+
+import_data_table::~import_data_table() {}
+
+import_auto_filter::~import_auto_filter() {}
+
+import_table::~import_table() {}
+
+import_conditional_format::~import_conditional_format() {}
+
+import_auto_filter* import_table::get_auto_filter()
+{
+ return nullptr;
+}
+
+import_formula::~import_formula() {}
+
+import_array_formula::~import_array_formula() {}
+
+import_sheet::~import_sheet() {}
+
+import_sheet_view* import_sheet::get_sheet_view()
+{
+ return nullptr;
+}
+
+import_sheet_properties* import_sheet::get_sheet_properties()
+{
+ return nullptr;
+}
+
+import_data_table* import_sheet::get_data_table()
+{
+ return nullptr;
+}
+
+import_auto_filter* import_sheet::get_auto_filter()
+{
+ return nullptr;
+}
+
+import_table* import_sheet::get_table()
+{
+ return nullptr;
+}
+
+import_conditional_format* import_sheet::get_conditional_format()
+{
+ return nullptr;
+}
+
+import_named_expression* import_sheet::get_named_expression()
+{
+ return nullptr;
+}
+
+import_array_formula* import_sheet::get_array_formula()
+{
+ return nullptr;
+}
+
+import_formula* import_sheet::get_formula()
+{
+ return nullptr;
+}
+
+import_global_settings::~import_global_settings() {}
+
+import_reference_resolver::~import_reference_resolver() {}
+
+import_factory::~import_factory() {}
+
+import_global_settings* import_factory::get_global_settings()
+{
+ return nullptr;
+}
+
+import_shared_strings* import_factory::get_shared_strings()
+{
+ return nullptr;
+}
+
+import_named_expression* import_factory::get_named_expression()
+{
+ return nullptr;
+}
+
+import_styles* import_factory::get_styles()
+{
+ return nullptr;
+}
+
+import_reference_resolver* import_factory::get_reference_resolver(formula_ref_context_t /*cxt*/)
+{
+ return nullptr;
+}
+
+import_pivot_cache_definition* import_factory::create_pivot_cache_definition(
+ orcus::spreadsheet::pivot_cache_id_t /*cache_id*/)
+{
+ return nullptr;
+}
+
+import_pivot_cache_records* import_factory::create_pivot_cache_records(
+ orcus::spreadsheet::pivot_cache_id_t /*cache_id*/)
+{
+ return nullptr;
+}
+
+export_sheet::~export_sheet() {}
+
+export_factory::~export_factory() {}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/spreadsheet_types.cpp b/src/liborcus/spreadsheet_types.cpp
new file mode 100644
index 0000000..3b7d357
--- /dev/null
+++ b/src/liborcus/spreadsheet_types.cpp
@@ -0,0 +1,763 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/spreadsheet/types.hpp>
+#include <orcus/exception.hpp>
+
+#include <limits>
+#include <sstream>
+
+#include <mdds/sorted_string_map.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+namespace trf {
+
+using map_type = mdds::sorted_string_map<totals_row_function_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "average", totals_row_function_t::average },
+ { "count", totals_row_function_t::count },
+ { "countNums", totals_row_function_t::count_numbers },
+ { "custom", totals_row_function_t::custom },
+ { "max", totals_row_function_t::maximum },
+ { "min", totals_row_function_t::minimum },
+ { "none", totals_row_function_t::none },
+ { "stdDev", totals_row_function_t::standard_deviation },
+ { "sum", totals_row_function_t::sum },
+ { "var", totals_row_function_t::variance },
+};
+
+const map_type& get()
+{
+ static const map_type map(entries, std::size(entries), totals_row_function_t::none);
+ return map;
+}
+
+} // namespace trf
+
+namespace pc_group_by {
+
+using map_type = mdds::sorted_string_map<pivot_cache_group_by_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "days", pivot_cache_group_by_t::days },
+ { "hours", pivot_cache_group_by_t::hours },
+ { "minutes", pivot_cache_group_by_t::minutes },
+ { "months", pivot_cache_group_by_t::months },
+ { "quarters", pivot_cache_group_by_t::quarters },
+ { "range", pivot_cache_group_by_t::range },
+ { "seconds", pivot_cache_group_by_t::seconds },
+ { "years", pivot_cache_group_by_t::years },
+};
+
+const map_type& get()
+{
+ static const map_type map(entries, std::size(entries), pivot_cache_group_by_t::unknown);
+ return map;
+}
+
+} // namespace pc_group_by
+
+namespace error_value {
+
+using map_type = mdds::sorted_string_map<error_value_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] =
+{
+ { "#DIV/0!", error_value_t::div0 },
+ { "#N/A!", error_value_t::na },
+ { "#NAME?", error_value_t::name },
+ { "#NULL!", error_value_t::null },
+ { "#NUM!", error_value_t::num },
+ { "#REF!", error_value_t::ref },
+ { "#VALUE!", error_value_t::value },
+};
+
+const map_type& get()
+{
+ static const map_type map(entries, std::size(entries), error_value_t::unknown);
+ return map;
+}
+
+} // namespace error_value
+
+namespace named_colors {
+
+using map_type = mdds::sorted_string_map<color_rgb_t, mdds::string_view_map_entry>;
+
+constexpr map_type::entry entries[] =
+{
+ { "aliceblue", { 0xF0, 0xF8, 0xFF } },
+ { "antiquewhite", { 0xFA, 0xEB, 0xD7 } },
+ { "aquamarine", { 0x7F, 0xFF, 0xD4 } },
+ { "azure", { 0xF0, 0xFF, 0xFF } },
+ { "beige", { 0xF5, 0xF5, 0xDC } },
+ { "bisque", { 0xFF, 0xE4, 0xC4 } },
+ { "black", { 0x00, 0x00, 0x00 } },
+ { "blanchedalmond", { 0xFF, 0xEB, 0xCD } },
+ { "blue", { 0x00, 0x00, 0xFF } },
+ { "blueviolet", { 0x8A, 0x2B, 0xE2 } },
+ { "brown", { 0xA5, 0x2A, 0x2A } },
+ { "burlywood", { 0xDE, 0xB8, 0x87 } },
+ { "cadetblue", { 0x5F, 0x9E, 0xA0 } },
+ { "chartreuse", { 0x7F, 0xFF, 0x00 } },
+ { "chocolate", { 0xD2, 0x69, 0x1E } },
+ { "coral", { 0xFF, 0x7F, 0x50 } },
+ { "cornflowerblue", { 0x64, 0x95, 0xED } },
+ { "cornsilk", { 0xFF, 0xF8, 0xDC } },
+ { "crimson", { 0xDC, 0x14, 0x3C } },
+ { "cyan", { 0x00, 0xFF, 0xFF } },
+ { "darkblue", { 0x00, 0x00, 0x8B } },
+ { "darkcyan", { 0x00, 0x8B, 0x8B } },
+ { "darkgoldenrod", { 0xB8, 0x86, 0x0B } },
+ { "darkgray", { 0xA9, 0xA9, 0xA9 } },
+ { "darkgreen", { 0x00, 0x64, 0x00 } },
+ { "darkkhaki", { 0xBD, 0xB7, 0x6B } },
+ { "darkmagenta", { 0x8B, 0x00, 0x8B } },
+ { "darkolivegreen", { 0x55, 0x6B, 0x2F } },
+ { "darkorange", { 0xFF, 0x8C, 0x00 } },
+ { "darkorchid", { 0x99, 0x32, 0xCC } },
+ { "darkred", { 0x8B, 0x00, 0x00 } },
+ { "darksalmon", { 0xE9, 0x96, 0x7A } },
+ { "darkseagreen", { 0x8F, 0xBC, 0x8F } },
+ { "darkslateblue", { 0x48, 0x3D, 0x8B } },
+ { "darkslategray", { 0x2F, 0x4F, 0x4F } },
+ { "darkturquoise", { 0x00, 0xCE, 0xD1 } },
+ { "darkviolet", { 0x94, 0x00, 0xD3 } },
+ { "deeppink", { 0xFF, 0x14, 0x93 } },
+ { "deepskyblue", { 0x00, 0xBF, 0xFF } },
+ { "dimgray", { 0x69, 0x69, 0x69 } },
+ { "dodgerblue", { 0x1E, 0x90, 0xFF } },
+ { "firebrick", { 0xB2, 0x22, 0x22 } },
+ { "floralwhite", { 0xFF, 0xFA, 0xF0 } },
+ { "forestgreen", { 0x22, 0x8B, 0x22 } },
+ { "gainsboro", { 0xDC, 0xDC, 0xDC } },
+ { "ghostwhite", { 0xF8, 0xF8, 0xFF } },
+ { "gold", { 0xFF, 0xD7, 0x00 } },
+ { "goldenrod", { 0xDA, 0xA5, 0x20 } },
+ { "gray", { 0x80, 0x80, 0x80 } },
+ { "green", { 0x00, 0x80, 0x00 } },
+ { "greenyellow", { 0xAD, 0xFF, 0x2F } },
+ { "honeydew", { 0xF0, 0xFF, 0xF0 } },
+ { "hotpink", { 0xFF, 0x69, 0xB4 } },
+ { "indianred", { 0xCD, 0x5C, 0x5C } },
+ { "indigo", { 0x4B, 0x00, 0x82 } },
+ { "ivory", { 0xFF, 0xFF, 0xF0 } },
+ { "khaki", { 0xF0, 0xE6, 0x8C } },
+ { "lavender", { 0xE6, 0xE6, 0xFA } },
+ { "lavenderblush", { 0xFF, 0xF0, 0xF5 } },
+ { "lawngreen", { 0x7C, 0xFC, 0x00 } },
+ { "lemonchiffon", { 0xFF, 0xFA, 0xCD } },
+ { "lightblue", { 0xAD, 0xD8, 0xE6 } },
+ { "lightcoral", { 0xF0, 0x80, 0x80 } },
+ { "lightcyan", { 0xE0, 0xFF, 0xFF } },
+ { "lightgoldenrodyellow", { 0xFA, 0xFA, 0xD2 } },
+ { "lightgray", { 0xD3, 0xD3, 0xD3 } },
+ { "lightgreen", { 0x90, 0xEE, 0x90 } },
+ { "lightpink", { 0xFF, 0xB6, 0xC1 } },
+ { "lightsalmon", { 0xFF, 0xA0, 0x7A } },
+ { "lightseagreen", { 0x20, 0xB2, 0xAA } },
+ { "lightskyblue", { 0x87, 0xCE, 0xFA } },
+ { "lightslategray", { 0x77, 0x88, 0x99 } },
+ { "lightsteelblue", { 0xB0, 0xC4, 0xDE } },
+ { "lightyellow", { 0xFF, 0xFF, 0xE0 } },
+ { "lime", { 0x00, 0xFF, 0x00 } },
+ { "limegreen", { 0x32, 0xCD, 0x32 } },
+ { "linen", { 0xFA, 0xF0, 0xE6 } },
+ { "magenta", { 0xFF, 0x00, 0xFF } },
+ { "maroon", { 0x80, 0x00, 0x00 } },
+ { "mediumaquamarine", { 0x66, 0xCD, 0xAA } },
+ { "mediumblue", { 0x00, 0x00, 0xCD } },
+ { "mediumorchid", { 0xBA, 0x55, 0xD3 } },
+ { "mediumpurple", { 0x93, 0x70, 0xDB } },
+ { "mediumseagreen", { 0x3C, 0xB3, 0x71 } },
+ { "mediumslateblue", { 0x7B, 0x68, 0xEE } },
+ { "mediumspringgreen", { 0x00, 0xFA, 0x9A } },
+ { "mediumturquoise", { 0x48, 0xD1, 0xCC } },
+ { "mediumvioletred", { 0xC7, 0x15, 0x85 } },
+ { "midnightblue", { 0x19, 0x19, 0x70 } },
+ { "mintcream", { 0xF5, 0xFF, 0xFA } },
+ { "mistyrose", { 0xFF, 0xE4, 0xE1 } },
+ { "moccasin", { 0xFF, 0xE4, 0xB5 } },
+ { "navajowhite", { 0xFF, 0xDE, 0xAD } },
+ { "navy", { 0x00, 0x00, 0x80 } },
+ { "oldlace", { 0xFD, 0xF5, 0xE6 } },
+ { "olive", { 0x80, 0x80, 0x00 } },
+ { "olivedrab", { 0x6B, 0x8E, 0x23 } },
+ { "orange", { 0xFF, 0xA5, 0x00 } },
+ { "orangered", { 0xFF, 0x45, 0x00 } },
+ { "orchid", { 0xDA, 0x70, 0xD6 } },
+ { "palegoldenrod", { 0xEE, 0xE8, 0xAA } },
+ { "palegreen", { 0x98, 0xFB, 0x98 } },
+ { "paleturquoise", { 0xAF, 0xEE, 0xEE } },
+ { "palevioletred", { 0xDB, 0x70, 0x93 } },
+ { "papayawhip", { 0xFF, 0xEF, 0xD5 } },
+ { "peachpuff", { 0xFF, 0xDA, 0xB9 } },
+ { "peru", { 0xCD, 0x85, 0x3F } },
+ { "pink", { 0xFF, 0xC0, 0xCB } },
+ { "plum", { 0xDD, 0xA0, 0xDD } },
+ { "powderblue", { 0xB0, 0xE0, 0xE6 } },
+ { "purple", { 0x80, 0x00, 0x80 } },
+ { "red", { 0xFF, 0x00, 0x00 } },
+ { "rosybrown", { 0xBC, 0x8F, 0x8F } },
+ { "royalblue", { 0x41, 0x69, 0xE1 } },
+ { "saddlebrown", { 0x8B, 0x45, 0x13 } },
+ { "salmon", { 0xFA, 0x80, 0x72 } },
+ { "sandybrown", { 0xF4, 0xA4, 0x60 } },
+ { "seagreen", { 0x2E, 0x8B, 0x57 } },
+ { "seashell", { 0xFF, 0xF5, 0xEE } },
+ { "sienna", { 0xA0, 0x52, 0x2D } },
+ { "silver", { 0xC0, 0xC0, 0xC0 } },
+ { "skyblue", { 0x87, 0xCE, 0xEB } },
+ { "slateblue", { 0x6A, 0x5A, 0xCD } },
+ { "slategray", { 0x70, 0x80, 0x90 } },
+ { "snow", { 0xFF, 0xFA, 0xFA } },
+ { "springgreen", { 0x00, 0xFF, 0x7F } },
+ { "steelblue", { 0x46, 0x82, 0xB4 } },
+ { "tan", { 0xD2, 0xB4, 0x8C } },
+ { "teal", { 0x00, 0x80, 0x80 } },
+ { "thistle", { 0xD8, 0xBF, 0xD8 } },
+ { "tomato", { 0xFF, 0x63, 0x47 } },
+ { "turquoise", { 0x40, 0xE0, 0xD0 } },
+ { "violet", { 0xEE, 0x82, 0xEE } },
+ { "wheat", { 0xF5, 0xDE, 0xB3 } },
+ { "white", { 0xFF, 0xFF, 0xFF } },
+ { "whitesmoke", { 0xF5, 0xF5, 0xF5 } },
+ { "yellow", { 0xFF, 0xFF, 0x00 } },
+ { "yellowgreen", { 0x9A, 0xCD, 0x32 } },
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), { 0x00, 0x00, 0x00 });
+ return mt;
+}
+
+} // namespace named_color
+
+namespace formula_error_policy {
+
+using map_type = mdds::sorted_string_map<formula_error_policy_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "fail", formula_error_policy_t::fail },
+ { "skip", formula_error_policy_t::skip },
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), formula_error_policy_t::unknown);
+ return mt;
+}
+
+}
+
+class to_size_t
+{
+ std::size_t m_value;
+
+public:
+ template<typename T>
+ to_size_t(T v) : m_value(static_cast<std::size_t>(v))
+ {
+ static_assert(std::is_enum_v<T>, "source value type must be enum!");
+ }
+
+ operator std::size_t() const
+ {
+ return m_value;
+ }
+};
+
+std::ostream& write_name_for_pos(
+ std::ostream& os, const std::string_view* names, std::size_t n_names, to_size_t pos)
+{
+ if (pos < n_names)
+ os << names[pos];
+ else
+ os << "???";
+
+ return os;
+}
+
+} // anonymous namespace
+
+address_t to_rc_address(const src_address_t& r)
+{
+ address_t ret;
+ ret.row = r.row;
+ ret.column = r.column;
+ return ret;
+}
+
+range_t to_rc_range(const src_range_t& r)
+{
+ range_t ret;
+ ret.first.row = r.first.row;
+ ret.first.column = r.first.column;
+ ret.last.row = r.last.row;
+ ret.last.column = r.last.column;
+ return ret;
+}
+
+bool operator== (const address_t& left, const address_t& right)
+{
+ return left.column == right.column && left.row == right.row;
+}
+
+bool operator!= (const address_t& left, const address_t& right)
+{
+ return !operator== (left, right);
+}
+
+bool operator== (const src_address_t& left, const src_address_t& right)
+{
+ return left.column == right.column && left.row == right.row;
+}
+
+bool operator!= (const src_address_t& left, const src_address_t& right)
+{
+ return !operator== (left, right);
+}
+
+bool operator== (const range_t& left, const range_t& right)
+{
+ return left.first == right.first && left.last == right.last;
+}
+
+bool operator!= (const range_t& left, const range_t& right)
+{
+ return !operator== (left, right);
+}
+
+bool operator== (const src_range_t& left, const src_range_t& right)
+{
+ return left.first == right.first && left.last == right.last;
+}
+
+bool operator!= (const src_range_t& left, const src_range_t& right)
+{
+ return !operator== (left, right);
+}
+
+bool operator< (const range_t& left, const range_t& right)
+{
+ if (left.first.row != right.first.row)
+ return left.first.row < right.first.row;
+
+ if (left.first.column != right.first.column)
+ return left.first.column < right.first.column;
+
+ if (left.last.row != right.last.row)
+ return left.last.row < right.last.row;
+
+ return left.last.column < right.last.column;
+}
+
+bool operator> (const range_t& left, const range_t& right)
+{
+ if (left.first.row != right.first.row)
+ return left.first.row > right.first.row;
+
+ if (left.first.column != right.first.column)
+ return left.first.column > right.first.column;
+
+ if (left.last.row != right.last.row)
+ return left.last.row > right.last.row;
+
+ return left.last.column > right.last.column;
+}
+
+range_t& operator+= (range_t& left, const address_t& right)
+{
+ left.first.column += right.column;
+ left.first.row += right.row;
+ left.last.column += right.column;
+ left.last.row += right.row;
+
+ return left;
+}
+
+range_t& operator-= (range_t& left, const address_t& right)
+{
+ left.first.column -= right.column;
+ left.first.row -= right.row;
+ left.last.column -= right.column;
+ left.last.row -= right.row;
+
+ return left;
+}
+
+std::ostream& operator<< (std::ostream& os, const address_t& v)
+{
+ os << "(column=" << v.column << ",row=" << v.row << ")";
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const src_address_t& v)
+{
+ os << "(sheet=" << v.sheet << ",column=" << v.column << ",row=" << v.row << ")";
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const range_t& v)
+{
+ os << v.first << "-" << v.last;
+ return os;
+}
+
+col_width_t get_default_column_width()
+{
+ return std::numeric_limits<col_width_t>::max();
+}
+
+row_height_t get_default_row_height()
+{
+ return std::numeric_limits<row_height_t>::max();
+}
+
+totals_row_function_t to_totals_row_function_enum(std::string_view s)
+{
+ return trf::get().find(s);
+}
+
+pivot_cache_group_by_t to_pivot_cache_group_by_enum(std::string_view s)
+{
+ return pc_group_by::get().find(s);
+}
+
+error_value_t to_error_value_enum(std::string_view s)
+{
+ return error_value::get().find(s);
+}
+
+color_rgb_t to_color_rgb(std::string_view s)
+{
+ const char* p = s.data();
+ std::size_t n = s.size();
+
+ // RGB string is a 6-character string representing 24-bit hexadecimal
+ // number e.g. '004A12' (red - green - blue)
+
+ // store the original head position and size.
+ const char* p0 = p;
+ size_t n0 = n;
+
+ if (n == 7 && *p == '#')
+ {
+ // Skip the leading '#' character.
+ --n;
+ ++p;
+ }
+
+ if (n != 6)
+ {
+ std::ostringstream os;
+ os << "'" << std::string_view(p0, n0) << "' is not a valid RGB color string.";
+ throw value_error(os.str());
+ }
+
+ color_rgb_t ret;
+ long converted = 0;
+ const char* p_end = p + n;
+
+ for (; p != p_end; ++p)
+ {
+ converted <<= 4;
+
+ char c = *p;
+ long this_val = 0;
+
+ if ('0' <= c && c <= '9')
+ this_val = c - '0';
+ else if ('a' <= c && c <= 'f')
+ this_val = 10 + c - 'a';
+ else if ('A' <= c && c <= 'F')
+ this_val = 10 + c - 'A';
+ else
+ {
+ std::ostringstream os;
+ os << "'" << std::string_view(p0, n0) << "' is not a valid RGB color string.";
+ throw value_error(os.str());
+ }
+
+ converted += this_val;
+ }
+
+ ret.blue = (0x000000FF & converted);
+ converted >>= 8;
+ ret.green = (0x000000FF & converted);
+ converted >>= 8;
+ ret.red = (0x000000FF & converted);
+
+ return ret;
+}
+
+color_rgb_t to_color_rgb_from_name(std::string_view s)
+{
+ return named_colors::get().find(s);
+}
+
+formula_error_policy_t to_formula_error_policy(std::string_view s)
+{
+ return formula_error_policy::get().find(s);
+}
+
+std::ostream& operator<< (std::ostream& os, error_value_t ev)
+{
+ switch (ev)
+ {
+ case error_value_t::div0:
+ os << error_value::entries[0].key;
+ break;
+ case error_value_t::na:
+ os << error_value::entries[1].key;
+ break;
+ case error_value_t::name:
+ os << error_value::entries[2].key;
+ break;
+ case error_value_t::null:
+ os << error_value::entries[3].key;
+ break;
+ case error_value_t::num:
+ os << error_value::entries[4].key;
+ break;
+ case error_value_t::ref:
+ os << error_value::entries[5].key;
+ break;
+ case error_value_t::value:
+ os << error_value::entries[6].key;
+ break;
+ case error_value_t::unknown:
+ default:
+ ;
+ }
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, border_style_t border)
+{
+ static constexpr std::string_view names[] = {
+ "unknown",
+ "none",
+ "solid",
+ "dash_dot",
+ "dash_dot_dot",
+ "dashed",
+ "dotted",
+ "double_border",
+ "hair",
+ "medium",
+ "medium_dash_dot",
+ "medium_dash_dot_dot",
+ "medium_dashed",
+ "slant_dash_dot",
+ "thick",
+ "thin",
+ "double_thin",
+ "fine_dashed",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), border);
+}
+
+std::ostream& operator<< (std::ostream& os, formula_grammar_t grammar)
+{
+ static constexpr std::string_view names[] = {
+ "unknown",
+ "xls_xml",
+ "xlsx",
+ "ods",
+ "gnumeric"
+ };
+
+ return write_name_for_pos(os, names, std::size(names), grammar);
+}
+
+std::ostream& operator<< (std::ostream& os, underline_t uline)
+{
+ static constexpr std::string_view names[] = {
+ "none",
+ "single_line",
+ "single_accounting",
+ "double_line",
+ "double_accounting",
+ "dotted",
+ "dash",
+ "long_dash",
+ "dot_dash",
+ "dot_dot_dash",
+ "wave",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), uline);
+}
+
+std::ostream& operator<< (std::ostream& os, underline_width_t ulwidth)
+{
+ static constexpr std::string_view names[] = {
+ "none",
+ "automatic",
+ "bold",
+ "dash",
+ "medium",
+ "thick",
+ "thin",
+ "percent",
+ "positive_integer",
+ "positive_length",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), ulwidth);
+}
+
+std::ostream& operator<< (std::ostream& os, underline_mode_t ulmode)
+{
+ static constexpr std::string_view names[] = {
+ "continuous",
+ "skip_white_space",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), ulmode);
+}
+
+std::ostream& operator<< (std::ostream& os, underline_type_t ultype)
+{
+ static constexpr std::string_view names[] = {
+ "none",
+ "single_type",
+ "double_type",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), ultype);
+}
+
+std::ostream& operator<< (std::ostream& os, hor_alignment_t halign)
+{
+ static constexpr std::string_view names[] = {
+ "unknown",
+ "left",
+ "center",
+ "right",
+ "justified",
+ "distributed",
+ "filled",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), halign);
+}
+
+std::ostream& operator<< (std::ostream& os, ver_alignment_t valign)
+{
+ static constexpr std::string_view names[] = {
+ "unknown",
+ "top",
+ "middle",
+ "bottom",
+ "justified",
+ "distributed",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), valign);
+}
+
+std::ostream& operator<< (std::ostream& os, const color_rgb_t& color)
+{
+ os << "(r=" << (int)color.red << ",g=" << (int)color.green << ",b=" << (int)color.blue << ")";
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const fill_pattern_t& fill)
+{
+ static constexpr std::string_view names[] = {
+ "none",
+ "solid",
+ "dark_down",
+ "dark_gray",
+ "dark_grid",
+ "dark_horizontal",
+ "dark_trellis",
+ "dark_up",
+ "dark_vertical",
+ "gray_0625",
+ "gray_125",
+ "light_down",
+ "light_gray",
+ "light_grid",
+ "light_horizontal",
+ "light_trellis",
+ "light_up",
+ "light_vertical",
+ "medium_gray",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), fill);
+}
+
+std::ostream& operator<< (std::ostream& os, const strikethrough_style_t& ss)
+{
+ static constexpr std::string_view names[] = {
+ "none",
+ "solid",
+ "dash",
+ "dot_dash",
+ "dot_dot_dash",
+ "dotted",
+ "long_dash",
+ "wave",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), ss);
+}
+
+std::ostream& operator<< (std::ostream& os, const strikethrough_type_t& st)
+{
+ static constexpr std::string_view names[] = {
+ "unknown",
+ "none",
+ "single_type",
+ "double_type",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), st);
+}
+
+std::ostream& operator<< (std::ostream& os, const strikethrough_width_t& sw)
+{
+ static constexpr std::string_view names[] = {
+ "unknown",
+ "width_auto",
+ "thin",
+ "medium",
+ "thick",
+ "bold",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), sw);
+}
+
+std::ostream& operator<< (std::ostream& os, const strikethrough_text_t& st)
+{
+ static constexpr std::string_view names[] = {
+ "unknown",
+ "slash",
+ "cross",
+ };
+
+ return write_name_for_pos(os, names, std::size(names), st);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/string_helper.cpp b/src/liborcus/string_helper.cpp
new file mode 100644
index 0000000..3bf9c63
--- /dev/null
+++ b/src/liborcus/string_helper.cpp
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "string_helper.hpp"
+
+namespace orcus {
+
+std::vector<std::string_view> string_helper::split_string(std::string_view str, const char sep)
+{
+ std::vector<std::string_view> ret;
+
+ std::size_t len = 0;
+ const char* start = str.data();
+ for (size_t i = 0, n = str.size(); i < n; ++i)
+ {
+ if (str[i] == sep)
+ {
+ ret.emplace_back(start, len);
+
+ // if not at the end move the start string
+ if (i < n-1)
+ start = start + len + 1;
+
+ len = 0;
+ }
+ else
+ ++len;
+ }
+ ret.emplace_back(start, len);
+
+ return ret;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/string_helper.hpp b/src/liborcus/string_helper.hpp
new file mode 100644
index 0000000..1885a33
--- /dev/null
+++ b/src/liborcus/string_helper.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <vector>
+#include <string_view>
+
+namespace orcus {
+
+class string_helper
+{
+public:
+ static std::vector<std::string_view> split_string(std::string_view str, const char sep);
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_context.cpp b/src/liborcus/xls_xml_context.cpp
new file mode 100644
index 0000000..ed30616
--- /dev/null
+++ b/src/liborcus/xls_xml_context.cpp
@@ -0,0 +1,2396 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xls_xml_context.hpp"
+#include "xls_xml_namespace_types.hpp"
+#include "xls_xml_token_constants.hpp"
+#include "spreadsheet_iface_util.hpp"
+#include "impl_utils.hpp"
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+#include <orcus/spreadsheet/import_interface_view.hpp>
+#include <orcus/measurement.hpp>
+
+#include <mdds/sorted_string_map.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <limits>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+ss::color_rgb_t to_rgb(std::string_view s)
+{
+ if (!s.empty() && s[0] == '#')
+ return ss::to_color_rgb(s);
+ else
+ {
+ // This may be a color name. Lower-case it before sending it to the
+ // function.
+ std::string s_lower(s.size(), '\0');
+ const char* p = s.data();
+ std::transform(p, p + s.size(), s_lower.begin(),
+ [](char c) -> char
+ {
+ if ('A' <= c && c <= 'Z')
+ c += 'a' - 'A';
+ return c;
+ }
+ );
+
+ return ss::to_color_rgb_from_name(s_lower);
+ }
+}
+
+namespace border_dir {
+
+using map_type = mdds::sorted_string_map<ss::border_direction_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "Bottom", ss::border_direction_t::bottom },
+ { "DiagonalLeft", ss::border_direction_t::diagonal_tl_br },
+ { "DiagonalRight", ss::border_direction_t::diagonal_bl_tr },
+ { "Left", ss::border_direction_t::left },
+ { "Right", ss::border_direction_t::right },
+ { "Top", ss::border_direction_t::top },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::border_direction_t::unknown);
+ return mt;
+}
+
+} // namespace border_dir
+
+namespace border_style {
+
+using map_type = mdds::sorted_string_map<ss::border_style_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "Continuous", ss::border_style_t::solid },
+ { "Dash", ss::border_style_t::dashed },
+ { "DashDot", ss::border_style_t::dash_dot },
+ { "DashDotDot", ss::border_style_t::dash_dot_dot },
+ { "Dot", ss::border_style_t::dotted },
+ { "Double", ss::border_style_t::double_border },
+ { "SlantDashDot", ss::border_style_t::slant_dash_dot },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::border_style_t::unknown);
+ return mt;
+}
+
+}
+
+namespace hor_align {
+
+using map_type = mdds::sorted_string_map<ss::hor_alignment_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "Center", ss::hor_alignment_t::center },
+ { "Distributed", ss::hor_alignment_t::distributed },
+ { "Justify", ss::hor_alignment_t::justified },
+ { "Left", ss::hor_alignment_t::left },
+ { "Right", ss::hor_alignment_t::right },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::hor_alignment_t::unknown);
+ return mt;
+}
+
+}
+
+namespace ver_align {
+
+using map_type = mdds::sorted_string_map<ss::ver_alignment_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "Bottom", ss::ver_alignment_t::bottom },
+ { "Center", ss::ver_alignment_t::middle },
+ { "Distributed", ss::ver_alignment_t::distributed },
+ { "Justify", ss::ver_alignment_t::justified },
+ { "Top", ss::ver_alignment_t::top },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::ver_alignment_t::unknown);
+ return mt;
+}
+
+}
+
+namespace num_format {
+
+using map_type = mdds::sorted_string_map<std::string_view, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "Currency", "$#,##0.00_);[Red]($#,##0.00)" },
+ { "Euro Currency", "[$\xe2\x82\xac-x-euro2] #,##0.00_);[Red]([$\xe2\x82\xac-x-euro2] #,##0.00)" },
+ { "Fixed", "0.00" },
+ { "General Date", "m/d/yyyy h:mm" },
+ { "General Number", "General" },
+ { "Long Date", "d-mmm-yy" },
+ { "Long Time", "h:mm:ss AM/PM" },
+ { "Medium Date", "d-mmm-yy" },
+ { "Medium Time", "h:mm AM/PM" },
+ { "On/Off", "\"On\";\"On\";\"Off\"" },
+ { "Percent", "0.00%" },
+ { "Scientific", "0.00E+00" },
+ { "Short Date", "m/d/yyyy" },
+ { "Short Time", "h:mm" },
+ { "Standard", "#,##0.00" },
+ { "True/False", "\"True\";\"True\";\"False\"" },
+ { "Yes/No", "\"Yes\";\"Yes\";\"No\"" },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), std::string_view{});
+ return mt;
+}
+
+} // namespace num_format
+
+namespace underline {
+
+using map_type = mdds::sorted_string_map<ss::underline_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "Double", ss::underline_t::double_line },
+ { "DoubleAccounting", ss::underline_t::double_accounting },
+ { "None", ss::underline_t::none },
+ { "Single", ss::underline_t::single_line },
+ { "SingleAccounting", ss::underline_t::single_accounting },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::underline_t::none);
+ return mt;
+}
+
+} // namespace underline
+
+} // anonymous namespace
+
+void xls_xml_data_context::format_type::merge(const format_type& fmt)
+{
+ if (fmt.bold)
+ bold = fmt.bold;
+
+ if (fmt.italic)
+ italic = fmt.italic;
+
+ if (fmt.underline)
+ underline = fmt.underline;
+
+ if (fmt.strikethrough)
+ strikethrough = fmt.strikethrough;
+
+ if (fmt.subscript)
+ subscript = fmt.subscript;
+
+ if (fmt.superscript)
+ superscript = fmt.superscript;
+
+ if (fmt.font_face)
+ font_face = fmt.font_face;
+
+ if (fmt.font_size)
+ font_size = fmt.font_size;
+
+ if (fmt.color)
+ color = fmt.color;
+}
+
+bool xls_xml_data_context::format_type::formatted() const
+{
+ return bold || italic || underline || strikethrough
+ || subscript || superscript || font_face || font_size
+ || color;
+}
+
+xls_xml_data_context::string_segment_type::string_segment_type(std::string_view _str) :
+ str(_str) {}
+
+xls_xml_data_context::xls_xml_data_context(
+ session_context& session_cxt, const tokens& tokens, xls_xml_context& parent_cxt) :
+ xml_context_base(session_cxt, tokens),
+ m_parent_cxt(parent_cxt),
+ m_cell_type(ct_unknown),
+ m_cell_value(std::numeric_limits<double>::quiet_NaN())
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_xls_xml_ss, XML_Data }, // root element
+ { NS_xls_xml_html, XML_B, NS_xls_xml_html, XML_Font },
+ { NS_xls_xml_html, XML_Font, NS_xls_xml_html, XML_B },
+ { NS_xls_xml_html, XML_Font, NS_xls_xml_html, XML_I },
+ { NS_xls_xml_html, XML_Font, NS_xls_xml_html, XML_S },
+ { NS_xls_xml_html, XML_Font, NS_xls_xml_html, XML_Sub },
+ { NS_xls_xml_html, XML_Font, NS_xls_xml_html, XML_Sup },
+ { NS_xls_xml_html, XML_Font, NS_xls_xml_html, XML_U },
+ { NS_xls_xml_html, XML_I, NS_xls_xml_html, XML_Font },
+ { NS_xls_xml_html, XML_S, NS_xls_xml_html, XML_Font },
+ { NS_xls_xml_html, XML_Sub, NS_xls_xml_html, XML_Font },
+ { NS_xls_xml_html, XML_Sup, NS_xls_xml_html, XML_Font },
+ { NS_xls_xml_html, XML_U, NS_xls_xml_html, XML_Font },
+ { NS_xls_xml_ss, XML_Data, NS_xls_xml_html, XML_B },
+ { NS_xls_xml_ss, XML_Data, NS_xls_xml_html, XML_Font },
+ { NS_xls_xml_ss, XML_Data, NS_xls_xml_html, XML_I },
+ { NS_xls_xml_ss, XML_Data, NS_xls_xml_html, XML_S },
+ { NS_xls_xml_ss, XML_Data, NS_xls_xml_html, XML_Sub },
+ { NS_xls_xml_ss, XML_Data, NS_xls_xml_html, XML_Sup },
+ { NS_xls_xml_ss, XML_Data, NS_xls_xml_html, XML_U },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+xls_xml_data_context::~xls_xml_data_context() {}
+
+xml_context_base* xls_xml_data_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xls_xml_data_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xls_xml_data_context::start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+
+ if (ns == NS_xls_xml_ss)
+ {
+ switch (name)
+ {
+ case XML_Data:
+ start_element_data(parent, attrs);
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else if (ns == NS_xls_xml_html)
+ {
+ switch (name)
+ {
+ case XML_B:
+ m_format_stack.emplace_back();
+ m_format_stack.back().bold = true;
+ update_current_format();
+ break;
+ case XML_I:
+ m_format_stack.emplace_back();
+ m_format_stack.back().italic = true;
+ update_current_format();
+ break;
+ case XML_U:
+ m_format_stack.emplace_back();
+ m_format_stack.back().underline = true;
+ update_current_format();
+ break;
+ case XML_S:
+ m_format_stack.emplace_back();
+ m_format_stack.back().strikethrough = true;
+ update_current_format();
+ break;
+ case XML_Sub:
+ m_format_stack.emplace_back();
+ m_format_stack.back().subscript = true;
+ update_current_format();
+ break;
+ case XML_Sup:
+ m_format_stack.emplace_back();
+ m_format_stack.back().superscript = true;
+ update_current_format();
+ break;
+ case XML_Font:
+ {
+ m_format_stack.emplace_back();
+ format_type& fmt = m_format_stack.back();
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (ns == NS_xls_xml_html)
+ {
+ switch (attr.name)
+ {
+ case XML_Color:
+ fmt.color = to_rgb(attr.value);
+ break;
+ case XML_Face:
+ fmt.font_face = attr.transient ? intern(attr.value) : attr.value;
+ break;
+ case XML_Size:
+ {
+ const char* p_end = nullptr;
+ double v = to_double(attr.value, &p_end);
+ if (attr.value.data() < p_end)
+ fmt.font_size = v;
+ break;
+ }
+ }
+ }
+ }
+
+ update_current_format();
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+void xls_xml_data_context::characters(std::string_view str, bool transient)
+{
+ if (str.empty())
+ return;
+
+ switch (m_cell_type)
+ {
+ case ct_unknown:
+ break;
+ case ct_string:
+ {
+ if (transient)
+ m_cell_string.emplace_back(intern(str));
+ else
+ m_cell_string.emplace_back(str);
+
+ if (m_current_format.formatted())
+ {
+ // Apply the current format to this string segment.
+ string_segment_type& ss = m_cell_string.back();
+ ss.format = m_current_format;
+ ss.formatted = true;
+ }
+
+ break;
+ }
+ case ct_number:
+ {
+ m_cell_value = to_double(str);
+ break;
+ }
+ case ct_datetime:
+ m_cell_datetime = date_time_t::from_chars(str);
+ break;
+ default:
+ {
+ std::ostringstream os;
+ os << "unknown cell type '" << m_cell_type << "': characters='" << str << "'";
+ warn(os.str());
+ }
+ }
+}
+
+bool xls_xml_data_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_xls_xml_ss)
+ {
+ switch (name)
+ {
+ case XML_Data:
+ end_element_data();
+ break;
+ default:
+ ;
+ }
+ }
+ else if (ns == NS_xls_xml_html)
+ {
+ switch (name)
+ {
+ case XML_B:
+ case XML_I:
+ case XML_U:
+ case XML_S:
+ case XML_Sub:
+ case XML_Sup:
+ case XML_Font:
+ assert(!m_format_stack.empty());
+ m_format_stack.pop_back();
+ update_current_format();
+ break;
+ default:
+ ;
+ }
+ }
+
+ return pop_stack(ns, name);
+}
+
+void xls_xml_data_context::reset()
+{
+ m_format_stack.clear();
+ m_format_stack.emplace_back(); // set default format.
+ update_current_format();
+
+ m_cell_type = ct_unknown;
+ m_cell_string.clear();
+
+ m_cell_value = std::numeric_limits<double>::quiet_NaN();
+ m_cell_datetime = date_time_t();
+}
+
+void xls_xml_data_context::start_element_data(
+ const xml_token_pair_t& /*parent*/, const xml_token_attrs_t& attrs)
+{
+ m_cell_type = ct_unknown;
+ m_cell_string.clear();
+ m_cell_datetime = date_time_t();
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns != NS_xls_xml_ss)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_Type:
+ {
+ if (attr.value == "String")
+ m_cell_type = ct_string;
+ else if (attr.value == "Number")
+ m_cell_type = ct_number;
+ else if (attr.value == "DateTime")
+ m_cell_type = ct_datetime;
+ break;
+ }
+ default:
+ ;
+ }
+ }
+}
+
+void xls_xml_data_context::end_element_data()
+{
+ auto formula = m_parent_cxt.pop_and_clear_formula();
+
+ if (!formula.empty())
+ {
+ if (m_parent_cxt.is_array_formula())
+ store_array_formula_parent_cell(formula);
+ else
+ push_formula_cell(formula);
+ m_cell_type = ct_unknown;
+ return;
+ }
+
+ if (handle_array_formula_result())
+ {
+ m_cell_type = ct_unknown;
+ return;
+ }
+
+ ss::iface::import_sheet* sheet = m_parent_cxt.get_import_sheet();
+ ss::address_t pos = m_parent_cxt.get_current_pos();
+
+ switch (m_cell_type)
+ {
+ case ct_unknown:
+ break;
+ case ct_number:
+ sheet->set_value(pos.row, pos.column, m_cell_value);
+ break;
+ case ct_string:
+ {
+ ss::iface::import_shared_strings* ss =
+ m_parent_cxt.get_import_factory()->get_shared_strings();
+
+ if (!ss)
+ break;
+
+ if (m_cell_string.empty())
+ break;
+
+ if (m_cell_string.size() == 1 && !m_cell_string[0].formatted)
+ {
+ // Unformatted string.
+ std::string_view s = m_cell_string.back().str;
+ sheet->set_string(pos.row, pos.column, ss->append(s));
+ }
+ else
+ {
+ // Formatted string. Note that an absence of a format type
+ // appears to mean its negative value is implied.
+
+ for (const string_segment_type& sstr : m_cell_string)
+ {
+ if (sstr.format.bold)
+ ss->set_segment_bold(*sstr.format.bold);
+ else
+ ss->set_segment_bold(false); // implied
+
+ if (sstr.format.italic)
+ ss->set_segment_italic(*sstr.format.italic);
+ else
+ ss->set_segment_italic(false); // implied
+
+ if (sstr.format.font_face)
+ ss->set_segment_font_name(*sstr.format.font_face);
+
+ if (sstr.format.font_size)
+ ss->set_segment_font_size(*sstr.format.font_size);
+
+ if (sstr.format.color)
+ ss->set_segment_font_color(
+ 255,
+ sstr.format.color->red,
+ sstr.format.color->green,
+ sstr.format.color->blue);
+
+ ss->append_segment(sstr.str);
+ }
+
+ size_t si = ss->commit_segments();
+ sheet->set_string(pos.row, pos.column, si);
+ }
+
+ m_cell_string.clear();
+
+ break;
+ }
+ case ct_datetime:
+ {
+ sheet->set_date_time(
+ pos.row, pos.column,
+ m_cell_datetime.year, m_cell_datetime.month, m_cell_datetime.day,
+ m_cell_datetime.hour, m_cell_datetime.minute, m_cell_datetime.second);
+ break;
+ }
+ default:
+ {
+ std::ostringstream os;
+ os <<"unknown cell type '" << m_cell_type << "': value not pushed.";
+ warn(os.str());
+ }
+ }
+
+ m_cell_type = ct_unknown;
+}
+
+bool xls_xml_data_context::handle_array_formula_result()
+{
+ xls_xml_context::array_formulas_type& store = m_parent_cxt.get_array_formula_store();
+ ss::address_t cur_pos = m_parent_cxt.get_current_pos();
+
+ // See if the current cell is within an array formula range.
+ auto it = store.begin(), ite = store.end();
+
+ while (it != ite)
+ {
+ const ss::range_t& ref = it->first;
+ xls_xml_context::array_formula_type& af = *it->second;
+
+ if (ref.last.row < cur_pos.row)
+ {
+ // If this result range lies above the current row, push the array
+ // and delete it from the list.
+
+ ss::iface::import_sheet* sheet = m_parent_cxt.get_import_sheet();
+ ss::iface::import_array_formula* array = nullptr;
+
+ if (sheet)
+ array = sheet->get_array_formula();
+
+ if (array)
+ {
+ push_array_formula(
+ array, ref, af.formula, ss::formula_grammar_t::xls_xml, af.results);
+ }
+
+ store.erase(it++);
+ continue;
+ }
+
+ if (cur_pos.column < ref.first.column || ref.last.column < cur_pos.column ||
+ cur_pos.row < ref.first.row || ref.last.row < cur_pos.row)
+ {
+ // This cell is not within this array formula range. Move on to
+ // the next one.
+ ++it;
+ continue;
+ }
+
+ size_t row_offset = cur_pos.row - ref.first.row;
+ size_t col_offset = cur_pos.column - ref.first.column;
+ range_formula_results& res = af.results;
+ push_array_result(res, row_offset, col_offset);
+
+ return true;
+ }
+
+ return false;
+}
+
+void xls_xml_data_context::push_array_result(
+ range_formula_results& res, size_t row_offset, size_t col_offset)
+{
+ switch (m_cell_type)
+ {
+ case ct_number:
+ {
+ res.set(row_offset, col_offset, m_cell_value);
+ break;
+ }
+ case ct_unknown:
+ case ct_datetime:
+ case ct_string:
+ default:
+ {
+ std::ostringstream os;
+ os << "unknown cell type '" << m_cell_type << "': value not pushed.";
+ warn(os.str());
+ }
+ }
+}
+
+void xls_xml_data_context::push_formula_cell(std::string_view formula)
+{
+ switch (m_cell_type)
+ {
+ case ct_number:
+ m_parent_cxt.store_cell_formula(formula, m_cell_value);
+ break;
+ default:
+ {
+ formula_result res;
+ m_parent_cxt.store_cell_formula(formula, res);
+ }
+ }
+}
+
+void xls_xml_data_context::store_array_formula_parent_cell(std::string_view formula)
+{
+ ss::address_t pos = m_parent_cxt.get_current_pos();
+ ss::range_t range = m_parent_cxt.get_array_range();
+ xls_xml_context::array_formulas_type& store = m_parent_cxt.get_array_formula_store();
+
+ range += pos;
+
+ store.push_back(
+ std::make_pair(
+ range,
+ std::make_unique<xls_xml_context::array_formula_type>(range, formula)));
+
+ xls_xml_context::array_formula_type& af = *store.back().second;
+
+ switch (m_cell_type)
+ {
+ case ct_number:
+ af.results.set(0, 0, m_cell_value);
+ break;
+ default:
+ ;
+ }
+}
+
+void xls_xml_data_context::update_current_format()
+{
+ // format stack should have at least one entry at any given moment.
+ assert(!m_format_stack.empty());
+
+ // Grab the bottom format.
+ auto it = m_format_stack.begin();
+ m_current_format = *it;
+ ++it;
+
+ // Merge in the rest of the format data.
+ std::for_each(it, m_format_stack.end(),
+ [&](const format_type& fmt)
+ {
+ m_current_format.merge(fmt);
+ }
+ );
+}
+
+xls_xml_context::array_formula_type::array_formula_type(
+ const ss::range_t& _range, std::string_view _formula) :
+ formula(_formula),
+ results(_range.last.row-_range.first.row+1, _range.last.column-_range.first.column+1) {}
+
+xls_xml_context::named_exp::named_exp(std::string_view _name, std::string_view _expression, ss::sheet_t _scope) :
+ name(_name), expression(_expression), scope(_scope) {}
+
+xls_xml_context::selection::selection() : pane(ss::sheet_pane_t::unspecified), col(-1), row(-1)
+{
+ range.first.column = -1;
+ range.first.row = -1;
+ range.last.column = -1;
+ range.last.row = -1;
+}
+
+void xls_xml_context::selection::reset()
+{
+ pane = ss::sheet_pane_t::unspecified;
+ col = 0;
+ row = 0;
+
+ range.first.column = -1;
+ range.first.row = -1;
+ range.last.column = -1;
+ range.last.row = -1;
+}
+
+bool xls_xml_context::selection::valid_cursor() const
+{
+ return col >= 0 && row >= 0;
+}
+
+bool xls_xml_context::selection::valid_range() const
+{
+ return range.first.column >= 0 && range.first.row >= 0 && range.last.column >= 0 && range.last.row >= 0;
+}
+
+xls_xml_context::split_pane::split_pane() :
+ pane_state(ss::pane_state_t::split),
+ active_pane(ss::sheet_pane_t::top_left),
+ split_horizontal(0.0), split_vertical(0.0),
+ top_row_bottom_pane(0), left_col_right_pane(0) {}
+
+void xls_xml_context::split_pane::reset()
+{
+ pane_state = ss::pane_state_t::split;
+ active_pane = ss::sheet_pane_t::top_left;
+ split_horizontal = 0.0;
+ split_vertical = 0.0;
+ top_row_bottom_pane = 0;
+ left_col_right_pane = 0;
+}
+
+bool xls_xml_context::split_pane::split() const
+{
+ return (split_horizontal || split_vertical) && (top_row_bottom_pane || left_col_right_pane);
+}
+
+ss::address_t xls_xml_context::split_pane::get_top_left_cell() const
+{
+ ss::address_t pos;
+ pos.column = left_col_right_pane;
+ pos.row = top_row_bottom_pane;
+ return pos;
+}
+
+xls_xml_context::table_properties::table_properties()
+{
+ reset();
+}
+
+void xls_xml_context::table_properties::reset()
+{
+ pos.row = 0;
+ pos.column = 0;
+}
+
+xls_xml_context::xls_xml_context(session_context& session_cxt, const tokens& tokens, ss::iface::import_factory* factory) :
+ xml_context_base(session_cxt, tokens),
+ mp_factory(factory),
+ mp_cur_sheet(nullptr),
+ mp_sheet_props(nullptr),
+ m_cur_sheet(-1),
+ m_cur_row(0), m_cur_col(0),
+ m_cur_prop_col(0),
+ m_cur_merge_down(0), m_cur_merge_across(0),
+ m_cc_data(session_cxt, tokens, *this)
+{
+ register_child(&m_cc_data);
+
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_xls_xml_ss, XML_Workbook }, // root element
+ { NS_xls_xml_o, XML_DocumentProperties, NS_xls_xml_o, XML_Author },
+ { NS_xls_xml_o, XML_DocumentProperties, NS_xls_xml_o, XML_Company },
+ { NS_xls_xml_o, XML_DocumentProperties, NS_xls_xml_o, XML_Created },
+ { NS_xls_xml_o, XML_DocumentProperties, NS_xls_xml_o, XML_LastAuthor },
+ { NS_xls_xml_o, XML_DocumentProperties, NS_xls_xml_o, XML_LastSaved },
+ { NS_xls_xml_o, XML_DocumentProperties, NS_xls_xml_o, XML_Version },
+ { NS_xls_xml_o, XML_OfficeDocumentSettings, NS_xls_xml_o, XML_AllowPNG },
+ { NS_xls_xml_o, XML_OfficeDocumentSettings, NS_xls_xml_o, XML_DownloadComponents },
+ { NS_xls_xml_o, XML_OfficeDocumentSettings, NS_xls_xml_o, XML_LocationOfComponents },
+ { NS_xls_xml_ss, XML_Borders, NS_xls_xml_ss, XML_Border },
+ { NS_xls_xml_ss, XML_Cell, NS_xls_xml_ss, XML_Data },
+ { NS_xls_xml_ss, XML_Cell, NS_xls_xml_ss, XML_NamedCell },
+ { NS_xls_xml_ss, XML_Names, NS_xls_xml_ss, XML_NamedRange },
+ { NS_xls_xml_ss, XML_Row, NS_xls_xml_ss, XML_Cell },
+ { NS_xls_xml_ss, XML_Style, NS_xls_xml_ss, XML_Alignment },
+ { NS_xls_xml_ss, XML_Style, NS_xls_xml_ss, XML_Borders },
+ { NS_xls_xml_ss, XML_Style, NS_xls_xml_ss, XML_Font },
+ { NS_xls_xml_ss, XML_Style, NS_xls_xml_ss, XML_Interior },
+ { NS_xls_xml_ss, XML_Style, NS_xls_xml_ss, XML_NumberFormat },
+ { NS_xls_xml_ss, XML_Style, NS_xls_xml_ss, XML_Protection },
+ { NS_xls_xml_ss, XML_Styles, NS_xls_xml_ss, XML_Style },
+ { NS_xls_xml_ss, XML_Table, NS_xls_xml_ss, XML_Column },
+ { NS_xls_xml_ss, XML_Table, NS_xls_xml_ss, XML_Row },
+ { NS_xls_xml_ss, XML_Workbook, NS_xls_xml_o, XML_DocumentProperties },
+ { NS_xls_xml_ss, XML_Workbook, NS_xls_xml_o, XML_OfficeDocumentSettings },
+ { NS_xls_xml_ss, XML_Workbook, NS_xls_xml_ss, XML_Names },
+ { NS_xls_xml_ss, XML_Workbook, NS_xls_xml_ss, XML_Styles },
+ { NS_xls_xml_ss, XML_Workbook, NS_xls_xml_ss, XML_Worksheet },
+ { NS_xls_xml_ss, XML_Workbook, NS_xls_xml_x, XML_ExcelWorkbook },
+ { NS_xls_xml_ss, XML_Worksheet, NS_xls_xml_ss, XML_Names },
+ { NS_xls_xml_ss, XML_Worksheet, NS_xls_xml_ss, XML_Table },
+ { NS_xls_xml_ss, XML_Worksheet, NS_xls_xml_x, XML_AutoFilter },
+ { NS_xls_xml_ss, XML_Worksheet, NS_xls_xml_x, XML_WorksheetOptions },
+ { NS_xls_xml_x, XML_AutoFilter, NS_xls_xml_x, XML_AutoFilterColumn },
+ { NS_xls_xml_x, XML_AutoFilterColumn, NS_xls_xml_x, XML_AutoFilterCondition },
+ { NS_xls_xml_x, XML_AutoFilterColumn, NS_xls_xml_x, XML_AutoFilterOr },
+ { NS_xls_xml_x, XML_AutoFilterOr, NS_xls_xml_x, XML_AutoFilterCondition },
+ { NS_xls_xml_x, XML_ExcelWorkbook, NS_xls_xml_x, XML_ActiveSheet },
+ { NS_xls_xml_x, XML_ExcelWorkbook, NS_xls_xml_x, XML_FirstVisibleSheet },
+ { NS_xls_xml_x, XML_ExcelWorkbook, NS_xls_xml_x, XML_ProtectStructure },
+ { NS_xls_xml_x, XML_ExcelWorkbook, NS_xls_xml_x, XML_ProtectWindows },
+ { NS_xls_xml_x, XML_ExcelWorkbook, NS_xls_xml_x, XML_RefModeR1C1 },
+ { NS_xls_xml_x, XML_ExcelWorkbook, NS_xls_xml_x, XML_TabRatio },
+ { NS_xls_xml_x, XML_ExcelWorkbook, NS_xls_xml_x, XML_WindowHeight },
+ { NS_xls_xml_x, XML_ExcelWorkbook, NS_xls_xml_x, XML_WindowTopX },
+ { NS_xls_xml_x, XML_ExcelWorkbook, NS_xls_xml_x, XML_WindowTopY },
+ { NS_xls_xml_x, XML_ExcelWorkbook, NS_xls_xml_x, XML_WindowWidth },
+ { NS_xls_xml_x, XML_PageSetup, NS_xls_xml_x, XML_Footer },
+ { NS_xls_xml_x, XML_PageSetup, NS_xls_xml_x, XML_Header },
+ { NS_xls_xml_x, XML_PageSetup, NS_xls_xml_x, XML_PageMargins },
+ { NS_xls_xml_x, XML_Pane, NS_xls_xml_x, XML_ActiveCol },
+ { NS_xls_xml_x, XML_Pane, NS_xls_xml_x, XML_ActiveRow },
+ { NS_xls_xml_x, XML_Pane, NS_xls_xml_x, XML_Number },
+ { NS_xls_xml_x, XML_Pane, NS_xls_xml_x, XML_RangeSelection },
+ { NS_xls_xml_x, XML_Panes, NS_xls_xml_x, XML_Pane },
+ { NS_xls_xml_x, XML_Print, NS_xls_xml_x, XML_HorizontalResolution },
+ { NS_xls_xml_x, XML_Print, NS_xls_xml_x, XML_ValidPrinterInfo },
+ { NS_xls_xml_x, XML_Print, NS_xls_xml_x, XML_VerticalResolution },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_ActivePane },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_FilterOn },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_FreezePanes },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_FrozenNoSplit },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_LeftColumnRightPane },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_PageSetup },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_Panes },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_Print },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_ProtectObjects },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_ProtectScenarios },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_Selected },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_SplitHorizontal },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_SplitVertical },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_TopRowBottomPane },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_TopRowVisible },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_Unsynced },
+ { NS_xls_xml_x, XML_WorksheetOptions, NS_xls_xml_x, XML_Zoom },
+ };
+
+ init_element_validator(rules, std::size(rules));
+
+ m_cur_array_range.first.column = -1;
+ m_cur_array_range.first.row = -1;
+ m_cur_array_range.last = m_cur_array_range.first;
+}
+
+xls_xml_context::~xls_xml_context()
+{
+}
+
+void xls_xml_context::declaration(const xml_declaration_t& decl)
+{
+ ss::iface::import_global_settings* gs = mp_factory->get_global_settings();
+ if (!gs)
+ return;
+
+ gs->set_character_set(decl.encoding);
+}
+
+xml_context_base* xls_xml_context::create_child_context(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_xls_xml_ss)
+ {
+ switch (name)
+ {
+ case XML_Data:
+ {
+ // Move the cell formula string to the Data element context.
+ m_cc_data.reset();
+ return &m_cc_data;
+ }
+ default:
+ ;
+ }
+ }
+ return nullptr;
+}
+
+void xls_xml_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xls_xml_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ push_stack(ns, name);
+
+ if (ns == NS_xls_xml_ss)
+ {
+ switch (name)
+ {
+ case XML_Workbook:
+ // Do nothing.
+ break;
+ case XML_Worksheet:
+ {
+ start_element_worksheet(attrs);
+ break;
+ }
+ case XML_Table:
+ start_element_table(attrs);
+ break;
+ case XML_Row:
+ start_element_row(attrs);
+ break;
+ case XML_Cell:
+ start_element_cell(attrs);
+ break;
+ case XML_Column:
+ start_element_column(attrs);
+ break;
+ case XML_Names:
+ break;
+ case XML_NamedRange:
+ {
+ std::string_view name_s, exp;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns != NS_xls_xml_ss)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_Name:
+ name_s = intern(attr);
+ break;
+ case XML_RefersTo:
+ {
+ exp = attr.value;
+ if (exp.size() > 1 && exp[0] == '=')
+ exp = std::string_view{exp.data()+1, exp.size()-1};
+ if (!exp.empty() && attr.transient)
+ exp = intern(exp);
+ break;
+ }
+ default:
+ ;
+ }
+ }
+
+ if (!name_s.empty() && !exp.empty())
+ {
+ if (m_cur_sheet >= 0)
+ m_named_exps_sheet.emplace_back(name_s, exp, m_cur_sheet);
+ else
+ m_named_exps_global.emplace_back(name_s, exp, -1);
+ }
+
+ break;
+ }
+ case XML_Styles:
+ break;
+ case XML_Style:
+ {
+ m_current_style = std::make_unique<style_type>();
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns != NS_xls_xml_ss)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_ID:
+ m_current_style->id = intern(attr);
+ break;
+ case XML_Name:
+ m_current_style->name = intern(attr);
+ break;
+ case XML_Parent:
+ m_current_style->parent_id = intern(attr);
+ break;
+ default:
+ ;
+ }
+ }
+
+ break;
+ }
+ case XML_Borders:
+ start_element_borders(attrs);
+ break;
+ case XML_Border:
+ start_element_border(attrs);
+ break;
+ case XML_NumberFormat:
+ start_element_number_format(attrs);
+ break;
+ case XML_Font:
+ {
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns != NS_xls_xml_ss)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_FontName:
+ {
+ m_current_style->font.name = intern(attr);
+ break;
+ }
+ case XML_Bold:
+ {
+ m_current_style->font.bold = to_bool(attr.value);
+ break;
+ }
+ case XML_Italic:
+ {
+ m_current_style->font.italic = to_bool(attr.value);
+ break;
+ }
+ case XML_Color:
+ {
+ m_current_style->font.color = to_rgb(attr.value);
+ break;
+ }
+ case XML_Size:
+ {
+ m_current_style->font.size = to_double(attr.value);
+ break;
+ }
+ case XML_Underline:
+ {
+ m_current_style->font.underline = underline::get().find(attr.value);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case XML_Interior:
+ {
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns != NS_xls_xml_ss)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_Color:
+ {
+ m_current_style->fill.color = to_rgb(attr.value);
+ break;
+ }
+ case XML_Pattern:
+ {
+ // TODO : support fill types other than 'solid'.
+ m_current_style->fill.solid = (attr.value == "Solid");
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ break;
+ }
+ case XML_Alignment:
+ {
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns != NS_xls_xml_ss)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_Horizontal:
+ {
+ m_current_style->text_alignment.hor = hor_align::get().find(attr.value);
+ break;
+ }
+ case XML_Vertical:
+ {
+ m_current_style->text_alignment.ver = ver_align::get().find(attr.value);
+ break;
+ }
+ case XML_Indent:
+ {
+ m_current_style->text_alignment.indent = to_long(attr.value);
+ break;
+ }
+ case XML_WrapText:
+ {
+ m_current_style->text_alignment.wrap_text = to_bool(attr.value);
+ break;
+ }
+ case XML_ShrinkToFit:
+ {
+ m_current_style->text_alignment.shrink_to_fit = to_bool(attr.value);
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ break;
+ }
+ case XML_Protection:
+ {
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_xls_xml_x && attr.name == XML_HideFormula)
+ {
+ m_current_style->cell_protection.hide_formula = to_bool(attr.value);
+ }
+ else if (attr.ns == NS_xls_xml_ss && attr.name == XML_Protected)
+ {
+ m_current_style->cell_protection.locked = to_bool(attr.value);
+ }
+ }
+ }
+ default:
+ warn_unhandled();
+ }
+ }
+ else if (ns == NS_xls_xml_x)
+ {
+ switch (name)
+ {
+ case XML_WorksheetOptions:
+ m_split_pane.reset();
+ break;
+ case XML_FreezePanes:
+ // TODO : check if this is correct.
+ m_split_pane.pane_state = ss::pane_state_t::frozen_split;
+ break;
+ case XML_FrozenNoSplit:
+ m_split_pane.pane_state = ss::pane_state_t::frozen;
+ break;
+ case XML_ActivePane:
+ m_split_pane.active_pane = ss::sheet_pane_t::unspecified;
+ break;
+ case XML_SplitHorizontal:
+ m_split_pane.split_horizontal = 0.0;
+ break;
+ case XML_SplitVertical:
+ m_split_pane.split_vertical = 0.0;
+ break;
+ case XML_TopRowBottomPane:
+ m_split_pane.top_row_bottom_pane = 0;
+ break;
+ case XML_LeftColumnRightPane:
+ m_split_pane.left_col_right_pane = 0;
+ break;
+ case XML_Panes:
+ break;
+ case XML_Pane:
+ m_cursor_selection.reset();
+ break;
+ case XML_Number:
+ break;
+ case XML_ActiveCol:
+ break;
+ case XML_ActiveRow:
+ break;
+ case XML_RangeSelection:
+ break;
+ case XML_Selected:
+ {
+ if (mp_cur_sheet)
+ {
+ ss::iface::import_sheet_view* sv = mp_cur_sheet->get_sheet_view();
+ if (sv)
+ sv->set_sheet_active();
+ }
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool xls_xml_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_xls_xml_ss)
+ {
+ switch (name)
+ {
+ case XML_Borders:
+ end_element_borders();
+ break;
+ case XML_Border:
+ end_element_border();
+ break;
+ case XML_NumberFormat:
+ end_element_number_format();
+ break;
+ case XML_Row:
+ end_element_row();
+ break;
+ case XML_Cell:
+ end_element_cell();
+ break;
+ case XML_Column:
+ end_element_column();
+ break;
+ case XML_Table:
+ end_element_table();
+ break;
+ case XML_Workbook:
+ end_element_workbook();
+ break;
+ case XML_Worksheet:
+ end_element_worksheet();
+ break;
+ case XML_Style:
+ {
+ if (m_current_style)
+ {
+ if (m_current_style->id == "Default")
+ m_default_style = std::move(m_current_style);
+ else
+ m_styles.push_back(std::move(m_current_style));
+ }
+ break;
+ }
+ case XML_Styles:
+ {
+ end_element_styles();
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ else if (ns == NS_xls_xml_x)
+ {
+ switch (name)
+ {
+ case XML_Pane:
+ end_element_pane();
+ break;
+ case XML_WorksheetOptions:
+ end_element_worksheet_options();
+ break;
+ default:
+ ;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+namespace {
+
+ss::sheet_pane_t to_sheet_pane(long v)
+{
+ static const std::vector<ss::sheet_pane_t> mapping = {
+ ss::sheet_pane_t::bottom_right, // 0
+ ss::sheet_pane_t::top_right, // 1
+ ss::sheet_pane_t::bottom_left, // 2
+ ss::sheet_pane_t::top_left, // 3
+ };
+
+ if (v < 0 || size_t(v) >= mapping.size())
+ return ss::sheet_pane_t::unspecified;
+
+ return mapping[v];
+}
+
+}
+
+void xls_xml_context::characters(std::string_view str, bool /*transient*/)
+{
+ if (str.empty())
+ return;
+
+ xml_token_pair_t ce = get_current_element();
+
+ if (ce.first == NS_xls_xml_x)
+ {
+ switch (ce.second)
+ {
+ case XML_Number:
+ // sheet pane position.
+ // 3 | 1
+ //---+---
+ // 2 | 0
+ m_cursor_selection.pane = to_sheet_pane(to_long(str));
+ break;
+ case XML_ActiveCol:
+ m_cursor_selection.col = to_long(str);
+ break;
+ case XML_ActiveRow:
+ m_cursor_selection.row = to_long(str);
+ break;
+ case XML_ActivePane:
+ m_split_pane.active_pane = to_sheet_pane(to_long(str));
+ break;
+ case XML_SplitHorizontal:
+ m_split_pane.split_horizontal = to_double(str);
+ break;
+ case XML_SplitVertical:
+ m_split_pane.split_vertical = to_double(str);
+ break;
+ case XML_TopRowBottomPane:
+ m_split_pane.top_row_bottom_pane = to_long(str);
+ break;
+ case XML_LeftColumnRightPane:
+ m_split_pane.left_col_right_pane = to_long(str);
+ break;
+ case XML_RangeSelection:
+ {
+ ss::iface::import_reference_resolver* resolver =
+ mp_factory->get_reference_resolver(ss::formula_ref_context_t::global);
+
+ if (resolver)
+ m_cursor_selection.range = to_rc_range(resolver->resolve_range(str));
+
+ break;
+ }
+ default:
+ ;
+ }
+ }
+}
+
+void xls_xml_context::start_element_borders(const xml_token_attrs_t& /*attrs*/)
+{
+ m_current_style->borders.clear();
+}
+
+void xls_xml_context::start_element_border(const xml_token_attrs_t& attrs)
+{
+ ss::border_direction_t dir = ss::border_direction_t::unknown;
+ ss::border_style_t style = ss::border_style_t::unknown;
+ std::optional<ss::color_rgb_t> color;
+ long weight = 0;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns != NS_xls_xml_ss)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_Position:
+ {
+ dir = border_dir::get().find(attr.value);
+ break;
+ }
+ case XML_LineStyle:
+ {
+ style = border_style::get().find(attr.value);
+ break;
+ }
+ case XML_Weight:
+ {
+ weight = to_long(attr.value);
+ break;
+ }
+ case XML_Color:
+ {
+ color = to_rgb(attr.value);
+ break;
+ }
+ default:
+ ;
+ }
+ }
+
+ if (dir == ss::border_direction_t::unknown || style == ss::border_style_t::unknown)
+ return;
+
+ m_current_style->borders.emplace_back();
+ border_style_type& bs = m_current_style->borders.back();
+ bs.dir = dir;
+ bs.style = style;
+ bs.color = color;
+
+ switch (bs.style)
+ {
+ case ss::border_style_t::solid:
+ {
+ switch (weight)
+ {
+ case 0:
+ bs.style = ss::border_style_t::hair;
+ break;
+ case 1:
+ bs.style = ss::border_style_t::thin;
+ break;
+ case 2:
+ bs.style = ss::border_style_t::medium;
+ break;
+ case 3:
+ bs.style = ss::border_style_t::thick;
+ break;
+ default:
+ ;
+ }
+ break;
+ }
+ case ss::border_style_t::dashed:
+ if (weight > 1)
+ bs.style = ss::border_style_t::medium_dashed;
+ break;
+ case ss::border_style_t::dash_dot:
+ if (weight > 1)
+ bs.style = ss::border_style_t::medium_dash_dot;
+ break;
+ case ss::border_style_t::dash_dot_dot:
+ if (weight > 1)
+ bs.style = ss::border_style_t::medium_dash_dot_dot;
+ break;
+ default:
+ ;
+ }
+}
+
+void xls_xml_context::start_element_number_format(const xml_token_attrs_t& attrs)
+{
+ m_current_style->number_format = std::string_view{};
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns != NS_xls_xml_ss)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_Format:
+ {
+ std::string_view code = num_format::get().find(attr.value);
+ m_current_style->number_format = code.empty() ? intern(attr) : code;
+ break;
+ }
+ default:
+ ;
+ }
+ }
+}
+
+void xls_xml_context::start_element_cell(const xml_token_attrs_t& attrs)
+{
+ long col_index = 0;
+ std::string_view formula;
+ m_cur_cell_style_id = std::string_view{};
+
+ m_cur_merge_across = 0; // extra column(s) that are part of the merged cell.
+ m_cur_merge_down = 0; // extra row(s) that are part of the merged cell.
+
+ m_cur_array_range.first.column = -1;
+ m_cur_array_range.first.row = -1;
+ m_cur_array_range.last = m_cur_array_range.first;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.value.empty())
+ return;
+
+ if (attr.ns != NS_xls_xml_ss)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_Index:
+ col_index = to_long(attr.value);
+ break;
+ case XML_Formula:
+ if (attr.value[0] == '=' && attr.value.size() > 1)
+ {
+ std::string_view s{attr.value.data()+1, attr.value.size()-1};
+ formula = s;
+ if (attr.transient)
+ formula = intern(s);
+ }
+ break;
+ case XML_MergeAcross:
+ m_cur_merge_across = to_long(attr.value);
+ break;
+ case XML_MergeDown:
+ m_cur_merge_down = to_long(attr.value);
+ break;
+ case XML_StyleID:
+ m_cur_cell_style_id = intern(attr);
+ break;
+ case XML_ArrayRange:
+ {
+ ss::iface::import_reference_resolver* resolver =
+ mp_factory->get_reference_resolver(ss::formula_ref_context_t::global);
+ if (resolver)
+ m_cur_array_range = to_rc_range(resolver->resolve_range(attr.value));
+
+ break;
+ }
+ default:
+ ;
+ }
+ }
+
+ if (!formula.empty())
+ m_cur_cell_formula = formula;
+
+ if (col_index > 0)
+ {
+ // 1-based column index. Convert it to a 0-based one.
+ m_cur_col = m_table_props.pos.column + col_index - 1;
+ }
+}
+
+void xls_xml_context::start_element_column(const xml_token_attrs_t& attrs)
+{
+ if (!mp_sheet_props && !mp_cur_sheet)
+ return;
+
+ ss::col_t col_index = m_cur_prop_col;
+ ss::col_t span = 0;
+ double width = 0.0;
+ bool hidden = false;
+ std::optional<std::string_view> style_id;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.value.empty())
+ continue;
+
+ if (attr.ns != NS_xls_xml_ss)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_Index:
+ {
+ // Convert from 1-based to 0-based.
+ const char* p_end = nullptr;
+ long v = to_long(attr.value, &p_end);
+ if (attr.value.data() < p_end)
+ col_index = m_table_props.pos.column + v - 1;
+ break;
+ }
+ case XML_Width:
+ width = to_double(attr.value);
+ break;
+ case XML_Span:
+ // Span is the number of extra columns after the first one i.e.
+ // if the span is 1, the properties get applied to two
+ // consecutive columns. Not very intuitive, but this is how it
+ // appears to work.
+ span = to_long(attr.value);
+ break;
+ case XML_Hidden:
+ hidden = to_long(attr.value) != 0;
+ break;
+ case XML_StyleID:
+ style_id = attr.value; // no need to intern since it gets used in the same function scope
+ break;
+ }
+ }
+
+ if (mp_sheet_props)
+ {
+ // Column widths are stored as points.
+ mp_sheet_props->set_column_width(col_index, span + 1, width, orcus::length_unit_t::point);
+ mp_sheet_props->set_column_hidden(col_index, span + 1, hidden);
+ }
+
+ if (mp_cur_sheet && style_id)
+ {
+ auto it = m_style_map_cell.find(*style_id);
+ if (it != m_style_map_cell.end())
+ {
+ std::size_t xfid = it->second;
+ mp_cur_sheet->set_column_format(col_index, span + 1, xfid);
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "xfid for the style ID of '" << *style_id << "' not found in the cache";
+ warn(os.str());
+ }
+ }
+
+ m_cur_prop_col = col_index + span + 1;
+}
+
+void xls_xml_context::start_element_row(const xml_token_attrs_t& attrs)
+{
+ m_cur_col = m_table_props.pos.column;
+ ss::row_t row_index = -1;
+ bool has_height = false;
+ bool hidden = false;
+ double height = 0.0;
+ std::optional<std::string_view> style_id;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.value.empty())
+ return;
+
+ if (attr.ns == NS_xls_xml_ss)
+ {
+ switch (attr.name)
+ {
+ case XML_Index:
+ row_index = to_long(attr.value);
+ break;
+ case XML_Height:
+ has_height = true;
+ height = to_double(attr.value);
+ break;
+ case XML_Hidden:
+ hidden = to_long(attr.value) != 0;
+ break;
+ case XML_StyleID:
+ style_id = attr.value; // no need to intern since it gets used in the same function scope
+ break;
+ }
+ }
+ }
+
+ if (row_index > 0)
+ {
+ // 1-based row index. Convert it to a 0-based one.
+ m_cur_row = row_index - 1;
+ }
+
+ if (mp_cur_sheet && style_id)
+ {
+ auto it = m_style_map_cell.find(*style_id);
+ if (it != m_style_map_cell.end())
+ {
+ std::size_t xfid = it->second;
+ mp_cur_sheet->set_row_format(m_cur_row, xfid);
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "xfid for the style ID of '" << *style_id << "' not found in the cache";
+ warn(os.str());
+ }
+ }
+
+ if (mp_sheet_props)
+ {
+ if (has_height)
+ mp_sheet_props->set_row_height(m_cur_row, height, length_unit_t::point);
+
+ if (hidden)
+ mp_sheet_props->set_row_hidden(m_cur_row, true);
+ }
+}
+
+void xls_xml_context::start_element_table(const xml_token_attrs_t& attrs)
+{
+ ss::row_t row_index = -1;
+ ss::col_t col_index = -1;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.value.empty())
+ return;
+
+ if (attr.ns == NS_xls_xml_ss)
+ {
+ switch (attr.name)
+ {
+ case XML_TopCell:
+ col_index = to_long(attr.value);
+ break;
+ case XML_LeftCell:
+ row_index = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ }
+
+ // Convert 1-based indices to 0-based.
+
+ if (row_index > 0)
+ m_table_props.pos.row = row_index - 1;
+
+ if (col_index > 0)
+ m_table_props.pos.column = col_index - 1;
+
+ m_cur_row = m_table_props.pos.row;
+ m_cur_prop_col = m_table_props.pos.column;
+}
+
+void xls_xml_context::start_element_worksheet(const xml_token_attrs_t& attrs)
+{
+ ++m_cur_sheet;
+ std::string_view sheet_name;
+ m_cell_formulas.emplace_back();
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns == NS_xls_xml_ss)
+ {
+ switch (attr.name)
+ {
+ case XML_Name:
+ sheet_name = attr.value;
+ break;
+ default:
+ ;
+ }
+ }
+ }
+
+ mp_cur_sheet = mp_factory->append_sheet(m_cur_sheet, sheet_name);
+ ss::iface::import_named_expression* sheet_named_exp = nullptr;
+ if (mp_cur_sheet)
+ {
+ mp_sheet_props = mp_cur_sheet->get_sheet_properties();
+ sheet_named_exp = mp_cur_sheet->get_named_expression();
+ }
+
+ m_sheet_named_exps.push_back(sheet_named_exp);
+
+ m_cur_row = 0;
+ m_cur_col = 0;
+
+ if (get_config().debug)
+ std::cout << "worksheet: name: '" << sheet_name << "'" << std::endl;
+}
+
+void xls_xml_context::end_element_borders()
+{
+}
+
+void xls_xml_context::end_element_border()
+{
+}
+
+void xls_xml_context::end_element_number_format()
+{
+}
+
+void xls_xml_context::end_element_cell()
+{
+ if (mp_sheet_props && (m_cur_merge_across > 0 || m_cur_merge_down > 0))
+ {
+ ss::range_t merge_range;
+ merge_range.first.column = m_cur_col;
+ merge_range.first.row = m_cur_row;
+ merge_range.last.column = m_cur_col + m_cur_merge_across;
+ merge_range.last.row = m_cur_row + m_cur_merge_down;
+
+ mp_sheet_props->set_merge_cell_range(merge_range);
+ }
+
+ if (mp_cur_sheet && !m_cur_cell_style_id.empty())
+ {
+ auto it = m_style_map_cell.find(m_cur_cell_style_id);
+ if (it != m_style_map_cell.end())
+ {
+ auto xf_id = it->second;
+ mp_cur_sheet->set_format(m_cur_row, m_cur_col, xf_id);
+ }
+ }
+
+ if (mp_cur_sheet && !m_cur_cell_formula.empty())
+ {
+ // Likely a Cell element without a child Data element.
+ store_cell_formula(m_cur_cell_formula, formula_result());
+ }
+
+ m_cur_cell_formula = std::string_view{};
+
+ ++m_cur_col;
+ if (m_cur_merge_across > 0)
+ m_cur_col += m_cur_merge_across;
+}
+
+void xls_xml_context::end_element_column()
+{
+}
+
+void xls_xml_context::end_element_row()
+{
+ ++m_cur_row;
+}
+
+void xls_xml_context::end_element_table()
+{
+ push_all_array_formulas();
+ m_array_formulas.clear();
+ m_table_props.reset();
+ m_cur_row = 0;
+ m_cur_prop_col = 0;
+}
+
+void xls_xml_context::end_element_worksheet()
+{
+ mp_cur_sheet = nullptr;
+}
+
+void xls_xml_context::end_element_workbook()
+{
+ if (!mp_factory)
+ return;
+
+ ss::iface::import_named_expression* ne_global = mp_factory->get_named_expression();
+ if (ne_global)
+ {
+ // global scope named expressions.
+
+ for (const named_exp& ne : m_named_exps_global)
+ {
+ ne_global->set_named_expression(ne.name, ne.expression);
+ ne_global->commit();
+ }
+ }
+
+ // sheet-local named expressions follow.
+
+ for (const named_exp& ne : m_named_exps_sheet)
+ {
+ ss::iface::import_named_expression* p = nullptr;
+ if (ne.scope >= 0 && size_t(ne.scope) < m_sheet_named_exps.size())
+ p = m_sheet_named_exps[ne.scope]; // it may be nullptr.
+
+ if (p)
+ {
+ p->set_named_expression(ne.name, ne.expression);
+ p->commit();
+ }
+ }
+
+ // push all cell formulas
+ for (size_t sheet_pos = 0; sheet_pos < m_cell_formulas.size(); ++sheet_pos)
+ {
+ ss::iface::import_sheet* sheet = mp_factory->get_sheet(sheet_pos);
+ if (!sheet)
+ continue;
+
+ ss::iface::import_formula* xformula = sheet->get_formula();
+ if (!xformula)
+ continue;
+
+ const std::deque<cell_formula_type>& store = m_cell_formulas[sheet_pos];
+ for (const cell_formula_type& cf : store)
+ {
+ xformula->set_position(cf.pos.row, cf.pos.column);
+ xformula->set_formula(ss::formula_grammar_t::xls_xml, cf.formula);
+
+ switch (cf.result.type)
+ {
+ case formula_result::result_type::numeric:
+ xformula->set_result_value(cf.result.value_numeric);
+ break;
+ case formula_result::result_type::string:
+ case formula_result::result_type::boolean:
+ case formula_result::result_type::empty:
+ ;
+ }
+
+ xformula->commit();
+ }
+ }
+}
+
+void xls_xml_context::end_element_styles()
+{
+ commit_default_style(); // Commit the default style first.
+ commit_styles();
+}
+
+void xls_xml_context::end_element_pane()
+{
+ ss::iface::import_sheet_view* sv = mp_cur_sheet->get_sheet_view();
+ if (!sv)
+ return;
+
+ if (m_cursor_selection.pane == ss::sheet_pane_t::unspecified)
+ return;
+
+ if (m_cursor_selection.valid_range())
+ {
+ sv->set_selected_range(m_cursor_selection.pane, m_cursor_selection.range);
+ }
+ else if (m_cursor_selection.valid_cursor())
+ {
+ ss::range_t sel;
+ sel.first.column = m_cursor_selection.col;
+ sel.first.row = m_cursor_selection.row;
+ sel.last = sel.first;
+
+ sv->set_selected_range(m_cursor_selection.pane, sel);
+ }
+}
+
+void xls_xml_context::end_element_worksheet_options()
+{
+ commit_split_pane();
+}
+
+void xls_xml_context::commit_split_pane()
+{
+ ss::iface::import_sheet_view* sv = mp_cur_sheet->get_sheet_view();
+ if (!sv)
+ return;
+
+ if (!m_split_pane.split())
+ return;
+
+ switch (m_split_pane.pane_state)
+ {
+ case ss::pane_state_t::split:
+ {
+ ss::address_t top_left_cell = m_split_pane.get_top_left_cell();
+
+ // NB: The term "split vertical" in Excel 2003 XML refers to the
+ // vertical split bar position which in this case corresponds with
+ // the "horizontal split" position of the set_split_pane() call,
+ // and vice versa.
+ sv->set_split_pane(
+ m_split_pane.split_vertical, m_split_pane.split_horizontal,
+ top_left_cell, m_split_pane.active_pane);
+ break;
+ }
+ case ss::pane_state_t::frozen:
+ {
+ ss::address_t top_left_cell = m_split_pane.get_top_left_cell();
+
+ // NB: Note for the split pane above also applies here.
+ ss::col_t visible_cols = m_split_pane.split_vertical;
+ ss::row_t visible_rows = m_split_pane.split_horizontal;
+
+ sv->set_frozen_pane(
+ visible_cols, visible_rows,
+ top_left_cell, m_split_pane.active_pane);
+ break;
+ }
+ case ss::pane_state_t::frozen_split:
+ // not handled yet.
+ break;
+ case ss::pane_state_t::unspecified:
+ default:
+ ;
+ }
+
+ m_split_pane.reset();
+}
+
+void xls_xml_context::commit_default_style()
+{
+ ss::iface::import_styles* styles = mp_factory->get_styles();
+ if (!styles)
+ return;
+
+ ss::iface::import_font_style* font_style = styles->start_font_style();
+ ENSURE_INTERFACE(font_style, import_font_style);
+
+ if (m_default_style)
+ {
+ const auto& font = m_default_style->font;
+
+ if (!font.name.empty())
+ font_style->set_name(font.name);
+
+ if (font.size)
+ font_style->set_size(*font.size);
+
+ if (font.underline)
+ font_style->set_underline(*font.underline);
+
+ font_style->set_bold(font.bold);
+ font_style->set_italic(font.italic);
+ font_style->set_color(255, font.color.red, font.color.green, font.color.blue);
+ }
+
+ std::size_t id = font_style->commit();
+ assert(id == 0);
+
+ ss::iface::import_fill_style* fill_style = styles->start_fill_style();
+ ENSURE_INTERFACE(fill_style, import_fill_style);
+
+ if (m_default_style)
+ {
+ if (m_default_style->fill.solid)
+ fill_style->set_pattern_type(ss::fill_pattern_t::solid);
+
+ fill_style->set_fg_color(
+ 255,
+ m_default_style->fill.color.red,
+ m_default_style->fill.color.green,
+ m_default_style->fill.color.blue
+ );
+ }
+
+ id = fill_style->commit();
+ assert(id == 0);
+
+ auto* border_style = styles->start_border_style();
+ ENSURE_INTERFACE(border_style, import_border_style);
+
+ if (m_default_style && !m_default_style->borders.empty())
+ {
+ for (const border_style_type& b : m_default_style->borders)
+ {
+ if (b.dir == ss::border_direction_t::unknown)
+ continue;
+
+ if (b.style != ss::border_style_t::unknown)
+ border_style->set_style(b.dir, b.style);
+
+ if (b.color)
+ border_style->set_color(b.dir, 255, b.color->red, b.color->green, b.color->blue);
+ }
+ }
+
+ id = border_style->commit();
+ assert(id == 0);
+
+ auto* cell_protection = styles->start_cell_protection();
+ ENSURE_INTERFACE(cell_protection, import_cell_protection);
+
+ if (m_default_style)
+ {
+ const auto& cp = m_default_style->cell_protection;
+ cell_protection->set_locked(cp.locked);
+ cell_protection->set_formula_hidden(cp.hide_formula);
+ }
+
+ id = cell_protection->commit();
+ assert(id == 0);
+
+ auto* number_format = styles->start_number_format();
+ ENSURE_INTERFACE(number_format, import_number_format);
+
+ if (m_default_style)
+ number_format->set_code(m_default_style->number_format);
+
+ id = number_format->commit();
+ assert(id == 0);
+
+ auto* xf = styles->start_xf(ss::xf_category_t::cell);
+ ENSURE_INTERFACE(xf, import_xf);
+
+ auto set_default_style = [this](ss::iface::import_xf* ixf)
+ {
+ bool apply_alignment =
+ m_default_style->text_alignment.hor != ss::hor_alignment_t::unknown ||
+ m_default_style->text_alignment.ver != ss::ver_alignment_t::unknown ||
+ m_default_style->text_alignment.wrap_text || m_default_style->text_alignment.shrink_to_fit;
+
+ ixf->set_apply_alignment(apply_alignment);
+ ixf->set_horizontal_alignment(m_default_style->text_alignment.hor);
+ ixf->set_vertical_alignment(m_default_style->text_alignment.ver);
+ ixf->set_wrap_text(m_default_style->text_alignment.wrap_text);
+ ixf->set_shrink_to_fit(m_default_style->text_alignment.shrink_to_fit);
+ };
+
+ if (m_default_style)
+ set_default_style(xf);
+
+ id = xf->commit();
+ assert(id == 0);
+
+ xf = styles->start_xf(ss::xf_category_t::cell_style);
+ ENSURE_INTERFACE(xf, import_xf);
+
+ if (m_default_style && m_default_style->name == "Normal")
+ set_default_style(xf);
+
+ id = xf->commit();
+ assert(id == 0);
+
+ auto* cell_style = styles->start_cell_style();
+ ENSURE_INTERFACE(cell_style, import_cell_style);
+
+ if (m_default_style && m_default_style->name == "Normal")
+ {
+ if (!m_default_style->name.empty())
+ cell_style->set_name(m_default_style->name);
+ }
+
+ cell_style->commit();
+}
+
+void xls_xml_context::commit_styles()
+{
+ if (m_styles.empty())
+ return;
+
+ ss::iface::import_styles* styles = mp_factory->get_styles();
+ if (!styles)
+ return;
+
+ // Build a map of cell style textural ID's to cell format (xf) numeric ID's.
+
+ for (const std::unique_ptr<style_type>& style : m_styles)
+ {
+ auto category = style->name.empty() ? ss::xf_category_t::cell : ss::xf_category_t::cell_style;
+
+ auto* xf = styles->start_xf(category);
+ ENSURE_INTERFACE(xf, import_xf);
+
+ if (!style->parent_id.empty())
+ {
+ auto it = m_style_map_named_style.find(style->parent_id);
+ if (it == m_style_map_named_style.end())
+ {
+ std::ostringstream os;
+ os << "style '" << style->id << "' inherits from a parent style of '" << style->parent_id << "' but no record for the parent style exists";
+ warn(os.str());
+ }
+ else
+ xf->set_style_xf(it->second);
+ }
+
+ auto* font_style = styles->start_font_style();
+ ENSURE_INTERFACE(font_style, import_font_style);
+
+ if (!style->font.name.empty())
+ font_style->set_name(style->font.name);
+
+ if (style->font.size)
+ font_style->set_size(*style->font.size);
+
+ if (style->font.underline)
+ font_style->set_underline(*style->font.underline);
+
+ font_style->set_bold(style->font.bold);
+ font_style->set_italic(style->font.italic);
+ font_style->set_color(255,
+ style->font.color.red,
+ style->font.color.green,
+ style->font.color.blue);
+
+ size_t font_id = font_style->commit();
+
+ xf->set_font(font_id);
+
+ auto* fill_style = styles->start_fill_style();
+ ENSURE_INTERFACE(fill_style, import_fill_style);
+
+ if (style->fill.solid)
+ {
+ // TODO : add support for fill types other than 'solid'.
+ fill_style->set_pattern_type(ss::fill_pattern_t::solid);
+ fill_style->set_fg_color(255,
+ style->fill.color.red,
+ style->fill.color.green,
+ style->fill.color.blue);
+
+ size_t fill_id = fill_style->commit();
+ xf->set_fill(fill_id);
+ }
+
+ auto* protect = styles->start_cell_protection();
+ ENSURE_INTERFACE(protect, import_cell_protection);
+
+ protect->set_locked(style->cell_protection.locked);
+ protect->set_formula_hidden(style->cell_protection.hide_formula);
+
+ std::size_t protect_id = protect->commit();
+ xf->set_protection(protect_id);
+
+ if (!style->borders.empty())
+ {
+ styles->set_border_count(style->borders.size());
+
+ auto* border_style = styles->start_border_style();
+ ENSURE_INTERFACE(border_style, import_border_style);
+
+ for (const border_style_type& b : style->borders)
+ {
+ if (b.dir == ss::border_direction_t::unknown)
+ continue;
+
+ if (b.style != ss::border_style_t::unknown)
+ border_style->set_style(b.dir, b.style);
+
+ if (b.color)
+ border_style->set_color(b.dir, 255, b.color->red, b.color->green, b.color->blue);
+ }
+
+ size_t border_id = border_style->commit();
+ xf->set_border(border_id);
+ }
+
+ bool apply_alignment =
+ style->text_alignment.hor != ss::hor_alignment_t::unknown ||
+ style->text_alignment.ver != ss::ver_alignment_t::unknown ||
+ style->text_alignment.wrap_text || style->text_alignment.shrink_to_fit;
+
+ xf->set_apply_alignment(apply_alignment);
+ xf->set_horizontal_alignment(style->text_alignment.hor);
+ xf->set_vertical_alignment(style->text_alignment.ver);
+ xf->set_wrap_text(style->text_alignment.wrap_text);
+ xf->set_shrink_to_fit(style->text_alignment.shrink_to_fit);
+
+ if (!style->number_format.empty())
+ {
+ auto* number_format = styles->start_number_format();
+ ENSURE_INTERFACE(number_format, import_number_format);
+ number_format->set_code(style->number_format);
+ size_t number_format_id = number_format->commit();
+ xf->set_number_format(number_format_id);
+ }
+
+ // TODO : handle text indent level.
+
+ std::size_t xfid = xf->commit();
+
+ switch (category)
+ {
+ case ss::xf_category_t::cell:
+ {
+ m_style_map_cell.insert({style->id, xfid});
+ break;
+ }
+ case ss::xf_category_t::cell_style:
+ {
+ m_style_map_named_style.insert({style->id, xfid});
+
+ // Push the named cell style record.
+ auto* cell_style = styles->start_cell_style();
+ ENSURE_INTERFACE(cell_style, import_cell_style);
+ cell_style->set_name(style->name);
+ cell_style->set_xf(xfid);
+ cell_style->commit();
+
+ // Since we don't allow directly referencing a named cell style,
+ // we will create a regular cell style that references the named
+ // style instead.
+ auto* xf_cell = styles->start_xf(ss::xf_category_t::cell);
+ ENSURE_INTERFACE(xf_cell, import_xf);
+ xf_cell->set_style_xf(xfid); // reference the named style
+ xfid = xf_cell->commit();
+ m_style_map_cell.insert({style->id, xfid});
+ break;
+ }
+ case ss::xf_category_t::differential:
+ {
+ std::ostringstream os;
+ os << "differential cell format type is not supported";
+ warn(os.str());
+ break;
+ }
+ case ss::xf_category_t::unknown:
+ {
+ std::ostringstream os;
+ os << "cell format type is unknown";
+ warn(os.str());
+ break;
+ }
+ }
+ }
+}
+
+void xls_xml_context::push_all_array_formulas()
+{
+ if (!mp_cur_sheet)
+ return;
+
+ ss::iface::import_array_formula* array = mp_cur_sheet->get_array_formula();
+ if (!array)
+ return;
+
+ for (const array_formula_pair_type& pair : m_array_formulas)
+ {
+ const array_formula_type& af = *pair.second;
+ push_array_formula(
+ array, pair.first, af.formula, ss::formula_grammar_t::xls_xml, af.results);
+ }
+}
+
+ss::iface::import_factory* xls_xml_context::get_import_factory()
+{
+ return mp_factory;
+}
+
+ss::iface::import_sheet* xls_xml_context::get_import_sheet()
+{
+ return mp_cur_sheet;
+}
+
+ss::address_t xls_xml_context::get_current_pos() const
+{
+ ss::address_t pos;
+ pos.row = m_cur_row;
+ pos.column = m_cur_col;
+ return pos;
+}
+
+std::string_view xls_xml_context::pop_and_clear_formula()
+{
+ std::string_view f = m_cur_cell_formula;
+ m_cur_cell_formula = std::string_view{};
+ return f;
+}
+
+bool xls_xml_context::is_array_formula() const
+{
+ if (m_cur_array_range.first.column < 0 || m_cur_array_range.first.row < 0)
+ return false;
+
+ if (m_cur_array_range.last.column < 0 || m_cur_array_range.last.row < 0)
+ return false;
+
+ if (m_cur_array_range.first.column > m_cur_array_range.last.column ||
+ m_cur_array_range.first.row > m_cur_array_range.last.row)
+ return false;
+
+ return true;
+}
+
+const ss::range_t& xls_xml_context::get_array_range() const
+{
+ return m_cur_array_range;
+}
+
+xls_xml_context::array_formulas_type& xls_xml_context::get_array_formula_store()
+{
+ return m_array_formulas;
+}
+
+void xls_xml_context::store_cell_formula(std::string_view formula, const formula_result& res)
+{
+ assert(m_cur_sheet < ss::sheet_t(m_cell_formulas.size()));
+
+ cell_formula_type cf;
+ cf.pos = get_current_pos();
+ cf.formula = formula;
+ cf.result = res;
+ std::deque<cell_formula_type>& store = m_cell_formulas[m_cur_sheet];
+ store.push_back(std::move(cf));
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_context.hpp b/src/liborcus/xls_xml_context.hpp
new file mode 100644
index 0000000..24cb803
--- /dev/null
+++ b/src/liborcus/xls_xml_context.hpp
@@ -0,0 +1,334 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_XLS_XML_CONTEXT_HPP
+#define INCLUDED_ORCUS_XLS_XML_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "orcus/spreadsheet/types.hpp"
+#include "orcus/spreadsheet/view_types.hpp"
+#include "orcus/string_pool.hpp"
+
+#include "formula_result.hpp"
+
+#include <string>
+#include <unordered_map>
+#include <list>
+#include <deque>
+#include <optional>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_factory;
+class import_sheet;
+class import_sheet_properties;
+class import_named_expression;
+class import_array_formula;
+
+}}
+
+class xls_xml_context;
+
+/**
+ * Context for handling <Data> element scopes.
+ */
+class xls_xml_data_context : public xml_context_base
+{
+ struct format_type
+ {
+ std::optional<bool> bold;
+ std::optional<bool> italic;
+ std::optional<bool> underline;
+ std::optional<bool> strikethrough;
+ std::optional<bool> subscript;
+ std::optional<bool> superscript;
+
+ std::optional<std::string_view> font_face;
+ std::optional<double> font_size;
+ std::optional<spreadsheet::color_rgb_t> color;
+
+ void merge(const format_type& other);
+ bool formatted() const;
+ };
+
+ struct string_segment_type
+ {
+ std::string_view str;
+ format_type format;
+ bool formatted = false;
+
+ string_segment_type(std::string_view _str);
+ };
+
+ enum cell_type { ct_unknown = 0, ct_string, ct_number, ct_datetime };
+
+ xls_xml_context& m_parent_cxt;
+
+ cell_type m_cell_type;
+ std::vector<string_segment_type> m_cell_string;
+ std::vector<format_type> m_format_stack;
+
+ format_type m_current_format;
+
+ double m_cell_value;
+ date_time_t m_cell_datetime;
+
+public:
+ xls_xml_data_context(session_context& session_cxt, const tokens& tokens, xls_xml_context& parent_cxt);
+ virtual ~xls_xml_data_context() override;
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name) override;
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child) override;
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs) override;
+ virtual void characters(std::string_view str, bool transient) override;
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+
+ /**
+ * Intendted to be called from the parent context instance, to reset its
+ * internal state before its use.
+ */
+ void reset();
+
+private:
+
+ void start_element_data(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void end_element_data();
+
+ bool handle_array_formula_result();
+ void push_array_result(
+ range_formula_results& res, size_t row_offset, size_t col_offset);
+
+ void push_formula_cell(std::string_view formula);
+ void store_array_formula_parent_cell(std::string_view formula);
+ void update_current_format();
+};
+
+class xls_xml_context : public xml_context_base
+{
+ friend class xls_xml_data_context;
+
+ struct cell_formula_type
+ {
+ spreadsheet::address_t pos;
+ std::string_view formula;
+ formula_result result;
+ };
+
+ struct array_formula_type
+ {
+ std::string_view formula;
+ range_formula_results results;
+
+ array_formula_type(const spreadsheet::range_t& _range, std::string_view _formula);
+ };
+
+ struct border_style_type
+ {
+ spreadsheet::border_direction_t dir = spreadsheet::border_direction_t::unknown;
+ spreadsheet::border_style_t style = spreadsheet::border_style_t::unknown;
+ std::optional<spreadsheet::color_rgb_t> color;
+ };
+
+ struct font_style_type
+ {
+ std::string_view name;
+ std::string_view family;
+ std::optional<double> size;
+ std::optional<spreadsheet::underline_t> underline;
+ bool bold = false;
+ bool italic = false;
+
+ spreadsheet::color_rgb_t color;
+ };
+
+ /**
+ * TODO: we only support solid fill for now. More fill types to be added
+ * later.
+ */
+ struct fill_style_type
+ {
+ bool solid = false;
+ spreadsheet::color_rgb_t color;
+ };
+
+ struct text_alignment_type
+ {
+ spreadsheet::hor_alignment_t hor = spreadsheet::hor_alignment_t::unknown;
+ spreadsheet::ver_alignment_t ver = spreadsheet::ver_alignment_t::unknown;
+ int8_t indent = 0;
+ bool wrap_text = false;
+ bool shrink_to_fit = false;
+ };
+
+ struct cell_protection_type
+ {
+ bool locked = true; // NB: default is locked
+ bool hide_formula = false;
+ };
+
+ struct style_type
+ {
+ std::string_view id;
+ std::string_view parent_id;
+ std::string_view name;
+
+ font_style_type font;
+ fill_style_type fill;
+ text_alignment_type text_alignment;
+ cell_protection_type cell_protection;
+ std::string_view number_format;
+ std::vector<border_style_type> borders;
+ };
+
+ struct named_exp
+ {
+ std::string_view name;
+ std::string_view expression;
+ spreadsheet::sheet_t scope;
+
+ named_exp(std::string_view _name, std::string_view _expression, spreadsheet::sheet_t _scope);
+ };
+
+ struct selection
+ {
+ spreadsheet::sheet_pane_t pane;
+ spreadsheet::col_t col;
+ spreadsheet::row_t row;
+ spreadsheet::range_t range;
+
+ selection();
+ void reset();
+ bool valid_cursor() const;
+ bool valid_range() const;
+ };
+
+ struct split_pane
+ {
+ spreadsheet::pane_state_t pane_state;
+ spreadsheet::sheet_pane_t active_pane;
+ double split_horizontal;
+ double split_vertical;
+ spreadsheet::row_t top_row_bottom_pane;
+ spreadsheet::col_t left_col_right_pane;
+
+ split_pane();
+ void reset();
+ bool split() const;
+ spreadsheet::address_t get_top_left_cell() const;
+ };
+
+ struct table_properties
+ {
+ spreadsheet::address_t pos; // top-left position
+
+ table_properties();
+ void reset();
+ };
+
+ using named_expressions_type = std::vector<named_exp>;
+ using styles_type = std::vector<std::unique_ptr<style_type>>;
+ using style_id_xf_map_type = std::unordered_map<std::string_view, std::size_t>;
+ using array_formula_pair_type = std::pair<spreadsheet::range_t, std::unique_ptr<array_formula_type>>;
+ using array_formulas_type = std::list<array_formula_pair_type>;
+ using cell_formulas_type = std::deque<std::deque<cell_formula_type>>;
+
+public:
+ xls_xml_context(session_context& session_cxt, const tokens& tokens, spreadsheet::iface::import_factory* factory);
+ virtual ~xls_xml_context();
+
+ virtual void declaration(const xml_declaration_t& decl) override;
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name) override;
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child) override;
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs) override;
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ virtual void characters(std::string_view str, bool transient) override;
+
+private:
+
+ void start_element_borders(const xml_token_attrs_t& attrs);
+ void start_element_border(const xml_token_attrs_t& attrs);
+ void start_element_number_format(const xml_token_attrs_t& attrs);
+ void start_element_cell(const xml_token_attrs_t& attrs);
+ void start_element_column(const xml_token_attrs_t& attrs);
+ void start_element_row(const xml_token_attrs_t& attrs);
+ void start_element_table(const xml_token_attrs_t& attrs);
+ void start_element_worksheet(const xml_token_attrs_t& attrs);
+
+ void end_element_borders();
+ void end_element_border();
+ void end_element_number_format();
+ void end_element_cell();
+ void end_element_column();
+ void end_element_row();
+ void end_element_table();
+ void end_element_worksheet();
+ void end_element_workbook();
+ void end_element_styles();
+ void end_element_pane();
+ void end_element_worksheet_options();
+
+ void commit_split_pane();
+ void commit_default_style();
+ void commit_styles();
+
+ void push_all_array_formulas();
+
+private:
+ spreadsheet::iface::import_factory* get_import_factory();
+ spreadsheet::iface::import_sheet* get_import_sheet();
+ spreadsheet::address_t get_current_pos() const;
+ std::string_view pop_and_clear_formula();
+ bool is_array_formula() const;
+ const spreadsheet::range_t& get_array_range() const;
+ array_formulas_type& get_array_formula_store();
+
+ void store_cell_formula(std::string_view formula, const formula_result& res);
+
+private:
+ spreadsheet::iface::import_factory* mp_factory;
+ spreadsheet::iface::import_sheet* mp_cur_sheet;
+ spreadsheet::iface::import_sheet_properties* mp_sheet_props;
+
+ std::vector<spreadsheet::iface::import_named_expression*> m_sheet_named_exps;
+
+ spreadsheet::sheet_t m_cur_sheet;
+ spreadsheet::row_t m_cur_row;
+ spreadsheet::col_t m_cur_col;
+ spreadsheet::col_t m_cur_prop_col; /// current column position for column properties.
+ spreadsheet::row_t m_cur_merge_down;
+ spreadsheet::col_t m_cur_merge_across;
+ spreadsheet::range_t m_cur_array_range;
+ std::string_view m_cur_cell_formula;
+ std::string_view m_cur_cell_style_id;
+
+ cell_formulas_type m_cell_formulas;
+ array_formulas_type m_array_formulas;
+ named_expressions_type m_named_exps_global;
+ named_expressions_type m_named_exps_sheet;
+ selection m_cursor_selection; /// cursor selection in a single pane.
+ split_pane m_split_pane;
+
+ std::unique_ptr<style_type> m_current_style;
+ std::unique_ptr<style_type> m_default_style;
+ styles_type m_styles;
+ table_properties m_table_props;
+
+ style_id_xf_map_type m_style_map_cell;
+ style_id_xf_map_type m_style_map_named_style;
+
+ xls_xml_data_context m_cc_data;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_detection_handler.cpp b/src/liborcus/xls_xml_detection_handler.cpp
new file mode 100644
index 0000000..775cfb7
--- /dev/null
+++ b/src/liborcus/xls_xml_detection_handler.cpp
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xls_xml_detection_handler.hpp"
+#include "xls_xml_token_constants.hpp"
+#include "xls_xml_namespace_types.hpp"
+#include "xml_context_base.hpp"
+#include "detection_result.hpp"
+
+namespace orcus {
+
+namespace {
+
+/**
+ * Try to parse the XML stream up to the 1st Worksheet element while
+ * checking its structure along the way. If the structure up to that element
+ * is correct, then we call it "detected".
+ */
+class xls_xml_detection_context : public xml_context_base
+{
+public:
+ xls_xml_detection_context(session_context& session_cxt, const tokens& tokens) :
+ xml_context_base(session_cxt, tokens) {}
+
+ virtual xml_context_base* create_child_context(xmlns_id_t, xml_token_t)
+ {
+ return nullptr;
+ }
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& /*attrs*/)
+ {
+ xml_token_pair_t parent = push_stack(ns, name);
+ if (ns == NS_xls_xml_ss)
+ {
+ switch (name)
+ {
+ case XML_Workbook:
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ break;
+ case XML_Styles:
+ case XML_Worksheet:
+ {
+ xml_element_expected(parent, NS_xls_xml_ss, XML_Workbook);
+
+ // All good. Let's call it detected.
+ throw detection_result(true);
+ }
+ break;
+ case XML_Style:
+ xml_element_expected(parent, NS_xls_xml_ss, XML_Style);
+ break;
+ default:
+ ;
+ }
+ }
+ else if (ns == NS_xls_xml_o)
+ {
+ switch (name)
+ {
+ case XML_DocumentProperties:
+ case XML_OfficeDocumentSettings:
+ xml_element_expected(parent, NS_xls_xml_ss, XML_Workbook);
+ break;
+ default:
+ ;
+ }
+ }
+ else if (ns == NS_xls_xml_x)
+ {
+ switch (name)
+ {
+ case XML_ExcelWorkbook:
+ xml_element_expected(parent, NS_xls_xml_ss, XML_Workbook);
+ break;
+ default:
+ ;
+ }
+ }
+ }
+
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name)
+ {
+ return pop_stack(ns, name);
+ }
+
+ virtual void characters(std::string_view, bool)
+ {
+ }
+
+ virtual void end_child_context(xmlns_id_t, xml_token_t, xml_context_base*)
+ {
+ }
+};
+
+}
+
+xls_xml_detection_handler::xls_xml_detection_handler(
+ session_context& session_cxt, const tokens& t) :
+ xml_stream_handler(session_cxt, t, std::make_unique<xls_xml_detection_context>(session_cxt, t))
+{
+}
+
+xls_xml_detection_handler::~xls_xml_detection_handler() {}
+
+void xls_xml_detection_handler::start_document() {}
+void xls_xml_detection_handler::end_document() {}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_detection_handler.hpp b/src/liborcus/xls_xml_detection_handler.hpp
new file mode 100644
index 0000000..e8fd57d
--- /dev/null
+++ b/src/liborcus/xls_xml_detection_handler.hpp
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLS_XML_DETECTION_HANDLER_HPP
+#define ORCUS_XLS_XML_DETECTION_HANDLER_HPP
+
+#include "xml_stream_handler.hpp"
+
+namespace orcus {
+
+class tokens;
+struct session_context;
+
+class xls_xml_detection_handler : public xml_stream_handler
+{
+public:
+ xls_xml_detection_handler(session_context& session_cxt, const tokens& t);
+ virtual ~xls_xml_detection_handler();
+
+ virtual void start_document();
+ virtual void end_document();
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_handler.cpp b/src/liborcus/xls_xml_handler.cpp
new file mode 100644
index 0000000..5095b1e
--- /dev/null
+++ b/src/liborcus/xls_xml_handler.cpp
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xls_xml_handler.hpp"
+#include "xls_xml_context.hpp"
+
+namespace orcus {
+
+xls_xml_handler::xls_xml_handler(
+ session_context& session_cxt, const tokens& t, spreadsheet::iface::import_factory* factory) :
+ xml_stream_handler(session_cxt, t, std::make_unique<xls_xml_context>(session_cxt, t, factory))
+{
+}
+
+xls_xml_handler::~xls_xml_handler() {}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_handler.hpp b/src/liborcus/xls_xml_handler.hpp
new file mode 100644
index 0000000..d9a454b
--- /dev/null
+++ b/src/liborcus/xls_xml_handler.hpp
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLS_XML_HANDLER_HPP
+#define ORCUS_XLS_XML_HANDLER_HPP
+
+#include "xml_stream_handler.hpp"
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_factory;
+
+}}
+
+class tokens;
+struct session_context;
+
+class xls_xml_handler : public xml_stream_handler
+{
+public:
+ xls_xml_handler(session_context& session_cxt, const tokens& t, spreadsheet::iface::import_factory* factory);
+ virtual ~xls_xml_handler() override;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_namespace_types.cpp b/src/liborcus/xls_xml_namespace_types.cpp
new file mode 100644
index 0000000..96ccf6d
--- /dev/null
+++ b/src/liborcus/xls_xml_namespace_types.cpp
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xls_xml_namespace_types.hpp"
+
+namespace orcus {
+
+const xmlns_id_t NS_xls_xml_ss = "urn:schemas-microsoft-com:office:spreadsheet";
+const xmlns_id_t NS_xls_xml_o ="urn:schemas-microsoft-com:office:office";
+const xmlns_id_t NS_xls_xml_x ="urn:schemas-microsoft-com:office:excel";
+const xmlns_id_t NS_xls_xml_html ="http://www.w3.org/TR/REC-html40";
+
+namespace {
+
+xmlns_id_t xls_xml_ns[] = {
+ NS_xls_xml_ss,
+ NS_xls_xml_o,
+ NS_xls_xml_x,
+ NS_xls_xml_html,
+ nullptr
+};
+
+}
+
+const xmlns_id_t* NS_xls_xml_all = xls_xml_ns;
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_namespace_types.hpp b/src/liborcus/xls_xml_namespace_types.hpp
new file mode 100644
index 0000000..37de5b0
--- /dev/null
+++ b/src/liborcus/xls_xml_namespace_types.hpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLS_XML_NAMESPACE_TYPES_HPP
+#define ORCUS_XLS_XML_NAMESPACE_TYPES_HPP
+
+#include "orcus/types.hpp"
+
+namespace orcus {
+
+extern const xmlns_id_t NS_xls_xml_ss;
+extern const xmlns_id_t NS_xls_xml_o;
+extern const xmlns_id_t NS_xls_xml_x;
+extern const xmlns_id_t NS_xls_xml_html;
+
+/**
+ * Null-terminated array of all xls xml namespaces.
+ */
+extern const xmlns_id_t* NS_xls_xml_all;
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_token_constants.hpp b/src/liborcus/xls_xml_token_constants.hpp
new file mode 100644
index 0000000..9aca315
--- /dev/null
+++ b/src/liborcus/xls_xml_token_constants.hpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLS_XML_TOKEN_CONSTANTS_HPP
+#define ORCUS_XLS_XML_TOKEN_CONSTANTS_HPP
+
+#include "orcus/types.hpp"
+
+namespace orcus {
+
+#include "xls_xml_token_constants.inl"
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_token_constants.inl b/src/liborcus/xls_xml_token_constants.inl
new file mode 100644
index 0000000..902e2d5
--- /dev/null
+++ b/src/liborcus/xls_xml_token_constants.inl
@@ -0,0 +1,992 @@
+// This file has been auto-generated. Do not hand-edit this.
+
+const xml_token_t XML_AcceptLabelsInFormulas = 1;
+const xml_token_t XML_Action = 2;
+const xml_token_t XML_ActiveChart = 3;
+const xml_token_t XML_ActiveCol = 4;
+const xml_token_t XML_ActiveColumn = 5;
+const xml_token_t XML_ActivePane = 6;
+const xml_token_t XML_ActiveRow = 7;
+const xml_token_t XML_ActiveRows = 8;
+const xml_token_t XML_ActiveSheet = 9;
+const xml_token_t XML_Aggregate = 10;
+const xml_token_t XML_AlertVersion = 11;
+const xml_token_t XML_Alignment = 12;
+const xml_token_t XML_AllItemName = 13;
+const xml_token_t XML_AllowDeleteCols = 14;
+const xml_token_t XML_AllowDeleteRows = 15;
+const xml_token_t XML_AllowFilter = 16;
+const xml_token_t XML_AllowFormatCells = 17;
+const xml_token_t XML_AllowInsertCols = 18;
+const xml_token_t XML_AllowInsertHyperlinks = 19;
+const xml_token_t XML_AllowInsertRows = 20;
+const xml_token_t XML_AllowPNG = 21;
+const xml_token_t XML_AllowSizeCols = 22;
+const xml_token_t XML_AllowSizeRows = 23;
+const xml_token_t XML_AllowSort = 24;
+const xml_token_t XML_AllowUsePivotTables = 25;
+const xml_token_t XML_AlternateMethod = 26;
+const xml_token_t XML_AppName = 27;
+const xml_token_t XML_Append = 28;
+const xml_token_t XML_ApplyAutomaticOutlineStyles = 29;
+const xml_token_t XML_Area = 30;
+const xml_token_t XML_ArrayRange = 31;
+const xml_token_t XML_Async = 32;
+const xml_token_t XML_Attribute = 33;
+const xml_token_t XML_AttributeType = 34;
+const xml_token_t XML_Authentication = 35;
+const xml_token_t XML_Author = 36;
+const xml_token_t XML_AutoFilter = 37;
+const xml_token_t XML_AutoFilterAnd = 38;
+const xml_token_t XML_AutoFilterColumn = 39;
+const xml_token_t XML_AutoFilterCondition = 40;
+const xml_token_t XML_AutoFilterOr = 41;
+const xml_token_t XML_AutoFitHeight = 42;
+const xml_token_t XML_AutoFitWidth = 43;
+const xml_token_t XML_AutoFormatAlignment = 44;
+const xml_token_t XML_AutoFormatBorder = 45;
+const xml_token_t XML_AutoFormatFont = 46;
+const xml_token_t XML_AutoFormatName = 47;
+const xml_token_t XML_AutoFormatNumber = 48;
+const xml_token_t XML_AutoFormatPattern = 49;
+const xml_token_t XML_AutoFormatWidth = 50;
+const xml_token_t XML_AutoRepublish = 51;
+const xml_token_t XML_AutoShowCount = 52;
+const xml_token_t XML_AutoShowField = 53;
+const xml_token_t XML_AutoShowRange = 54;
+const xml_token_t XML_AutoShowType = 55;
+const xml_token_t XML_AutoSortField = 56;
+const xml_token_t XML_AutoSortOrder = 57;
+const xml_token_t XML_B = 58;
+const xml_token_t XML_BackgroundQuery = 59;
+const xml_token_t XML_BaseField = 60;
+const xml_token_t XML_BaseItem = 61;
+const xml_token_t XML_Basic = 62;
+const xml_token_t XML_Behavior = 63;
+const xml_token_t XML_Binding = 64;
+const xml_token_t XML_BlackAndWhite = 65;
+const xml_token_t XML_BlankLineAfterItems = 66;
+const xml_token_t XML_BlockTotal = 67;
+const xml_token_t XML_Bold = 68;
+const xml_token_t XML_Boolean = 69;
+const xml_token_t XML_Border = 70;
+const xml_token_t XML_Borders = 71;
+const xml_token_t XML_Bottom = 72;
+const xml_token_t XML_BoundField = 73;
+const xml_token_t XML_Bytes = 74;
+const xml_token_t XML_CacheDetails = 75;
+const xml_token_t XML_CacheFile = 76;
+const xml_token_t XML_CacheIndex = 77;
+const xml_token_t XML_CachePosition = 78;
+const xml_token_t XML_CalculatedMember = 79;
+const xml_token_t XML_Calculation = 80;
+const xml_token_t XML_CantGetUniqueItems = 81;
+const xml_token_t XML_Caption = 82;
+const xml_token_t XML_CaptionAlignment = 83;
+const xml_token_t XML_CaseSensitive = 84;
+const xml_token_t XML_Category = 85;
+const xml_token_t XML_Cell = 86;
+const xml_token_t XML_CellRangeList = 87;
+const xml_token_t XML_CellsExpanded = 88;
+const xml_token_t XML_CellsExpandedSeqNum = 89;
+const xml_token_t XML_CellsNotExpanded = 90;
+const xml_token_t XML_CenterHorizontal = 91;
+const xml_token_t XML_CenterVertical = 92;
+const xml_token_t XML_Cf = 93;
+const xml_token_t XML_CharSet = 94;
+const xml_token_t XML_Characters = 95;
+const xml_token_t XML_CharactersWithSpaces = 96;
+const xml_token_t XML_ClientParameter = 97;
+const xml_token_t XML_ClientParameterBinding = 98;
+const xml_token_t XML_ClientParameterBindings = 99;
+const xml_token_t XML_ClientParameterValue = 100;
+const xml_token_t XML_Clipped = 101;
+const xml_token_t XML_CodeName = 102;
+const xml_token_t XML_Col1 = 103;
+const xml_token_t XML_Col10 = 104;
+const xml_token_t XML_Col11 = 105;
+const xml_token_t XML_Col12 = 106;
+const xml_token_t XML_Col13 = 107;
+const xml_token_t XML_Col14 = 108;
+const xml_token_t XML_Col15 = 109;
+const xml_token_t XML_Col16 = 110;
+const xml_token_t XML_Col17 = 111;
+const xml_token_t XML_Col18 = 112;
+const xml_token_t XML_Col19 = 113;
+const xml_token_t XML_Col2 = 114;
+const xml_token_t XML_Col20 = 115;
+const xml_token_t XML_Col3 = 116;
+const xml_token_t XML_Col4 = 117;
+const xml_token_t XML_Col5 = 118;
+const xml_token_t XML_Col6 = 119;
+const xml_token_t XML_Col7 = 120;
+const xml_token_t XML_Col8 = 121;
+const xml_token_t XML_Col9 = 122;
+const xml_token_t XML_ColBreak = 123;
+const xml_token_t XML_ColBreaks = 124;
+const xml_token_t XML_ColFirst = 125;
+const xml_token_t XML_ColLast = 126;
+const xml_token_t XML_Color = 127;
+const xml_token_t XML_Column = 128;
+const xml_token_t XML_ColumnInfo = 129;
+const xml_token_t XML_ColumnInputCell = 130;
+const xml_token_t XML_ColumnName = 131;
+const xml_token_t XML_ComboHide = 132;
+const xml_token_t XML_Comma = 133;
+const xml_token_t XML_CommandText = 134;
+const xml_token_t XML_CommandTextOrignal = 135;
+const xml_token_t XML_CommandType = 136;
+const xml_token_t XML_Comment = 137;
+const xml_token_t XML_CommentsLayout = 138;
+const xml_token_t XML_Company = 139;
+const xml_token_t XML_ComponentOptions = 140;
+const xml_token_t XML_Condition = 141;
+const xml_token_t XML_ConditionalFormatting = 142;
+const xml_token_t XML_Connection = 143;
+const xml_token_t XML_ConnectionInfo = 144;
+const xml_token_t XML_ConnectionString = 145;
+const xml_token_t XML_Consecutive = 146;
+const xml_token_t XML_ConsolidationReference = 147;
+const xml_token_t XML_Count = 148;
+const xml_token_t XML_CountOfSameItems = 149;
+const xml_token_t XML_CreateBackup = 150;
+const xml_token_t XML_Created = 151;
+const xml_token_t XML_Credential = 152;
+const xml_token_t XML_CredentialBinding = 153;
+const xml_token_t XML_CredentialValue = 154;
+const xml_token_t XML_Crn = 155;
+const xml_token_t XML_CubeField = 156;
+const xml_token_t XML_CubeSource = 157;
+const xml_token_t XML_CurrentPage = 158;
+const xml_token_t XML_Custom = 159;
+const xml_token_t XML_CustomDocumentProperties = 160;
+const xml_token_t XML_Data = 161;
+const xml_token_t XML_DataAxisEmpty = 162;
+const xml_token_t XML_DataField = 163;
+const xml_token_t XML_DataMember = 164;
+const xml_token_t XML_DataSource = 165;
+const xml_token_t XML_DataTable = 166;
+const xml_token_t XML_DataType = 167;
+const xml_token_t XML_DataValidation = 168;
+const xml_token_t XML_DataValueEditing = 169;
+const xml_token_t XML_Date1904 = 170;
+const xml_token_t XML_Decimal = 171;
+const xml_token_t XML_DefaultColumnWidth = 172;
+const xml_token_t XML_DefaultItem = 173;
+const xml_token_t XML_DefaultRowHeight = 174;
+const xml_token_t XML_DefaultValue = 175;
+const xml_token_t XML_DefaultVersion = 176;
+const xml_token_t XML_DeletedTitle = 177;
+const xml_token_t XML_Delimiters = 178;
+const xml_token_t XML_Descending = 179;
+const xml_token_t XML_Description = 180;
+const xml_token_t XML_DetailFormat = 181;
+const xml_token_t XML_DetailMaxHeight = 182;
+const xml_token_t XML_DetailMaxWidth = 183;
+const xml_token_t XML_DetailRowHeight = 184;
+const xml_token_t XML_DetailSortOrder = 185;
+const xml_token_t XML_DetailWidth = 186;
+const xml_token_t XML_Dimension = 187;
+const xml_token_t XML_DisableDateRecognition = 188;
+const xml_token_t XML_DisableDrillDown = 189;
+const xml_token_t XML_DisableEdit = 190;
+const xml_token_t XML_DisableFieldDialog = 191;
+const xml_token_t XML_DisableRefresh = 192;
+const xml_token_t XML_DisableWizard = 193;
+const xml_token_t XML_DisplayDrawingObjects = 194;
+const xml_token_t XML_DisplayEmptyMembers = 195;
+const xml_token_t XML_DisplayErrorString = 196;
+const xml_token_t XML_DisplayFieldList = 197;
+const xml_token_t XML_DisplayFormulas = 198;
+const xml_token_t XML_DisplayIn = 199;
+const xml_token_t XML_DisplayInkNotes = 200;
+const xml_token_t XML_DisplayPageBreak = 201;
+const xml_token_t XML_DisplayRightToLeft = 202;
+const xml_token_t XML_DivID = 203;
+const xml_token_t XML_DoNotCalculateBeforeSave = 204;
+const xml_token_t XML_DoNotDisplayColHeaders = 205;
+const xml_token_t XML_DoNotDisplayGridlines = 206;
+const xml_token_t XML_DoNotDisplayHeadings = 207;
+const xml_token_t XML_DoNotDisplayOutline = 208;
+const xml_token_t XML_DoNotDisplayRowHeaders = 209;
+const xml_token_t XML_DoNotDisplayZeros = 210;
+const xml_token_t XML_DoNotJoinDelimiters = 211;
+const xml_token_t XML_DoNotPersist = 212;
+const xml_token_t XML_DoNotPersistSort = 213;
+const xml_token_t XML_DoNotPersstAF = 214;
+const xml_token_t XML_DoNotPromptForFile = 215;
+const xml_token_t XML_DoNotSaveLinkValues = 216;
+const xml_token_t XML_DocumentProperties = 217;
+const xml_token_t XML_DontShowInFieldList = 218;
+const xml_token_t XML_DownloadComponents = 219;
+const xml_token_t XML_DraftQuality = 220;
+const xml_token_t XML_DrawAspect = 221;
+const xml_token_t XML_DrilledLevel = 222;
+const xml_token_t XML_DrilledMember = 223;
+const xml_token_t XML_EditWebPage = 224;
+const xml_token_t XML_ElementType = 225;
+const xml_token_t XML_EmbedSaveSmartTags = 226;
+const xml_token_t XML_EnableMultiplePageItems = 227;
+const xml_token_t XML_EnableRedirections = 228;
+const xml_token_t XML_EnableSelection = 229;
+const xml_token_t XML_Encode = 230;
+const xml_token_t XML_EntirePage = 231;
+const xml_token_t XML_Entry = 232;
+const xml_token_t XML_Error = 233;
+const xml_token_t XML_ErrorHide = 234;
+const xml_token_t XML_ErrorMessage = 235;
+const xml_token_t XML_ErrorString = 236;
+const xml_token_t XML_ErrorStyle = 237;
+const xml_token_t XML_ErrorTitle = 238;
+const xml_token_t XML_ExcelName = 239;
+const xml_token_t XML_ExcelType = 240;
+const xml_token_t XML_ExcelWorkbook = 241;
+const xml_token_t XML_ExcelWorksheetType = 242;
+const xml_token_t XML_Expanded = 243;
+const xml_token_t XML_ExpandedColumnCount = 244;
+const xml_token_t XML_ExpandedRowCount = 245;
+const xml_token_t XML_ExternName = 246;
+const xml_token_t XML_ExtraLeftColumns = 247;
+const xml_token_t XML_ExtraRightColumns = 248;
+const xml_token_t XML_Face = 249;
+const xml_token_t XML_Family = 250;
+const xml_token_t XML_Field = 251;
+const xml_token_t XML_FieldLabelFormat = 252;
+const xml_token_t XML_FieldListBottom = 253;
+const xml_token_t XML_FieldListLeft = 254;
+const xml_token_t XML_FieldListRight = 255;
+const xml_token_t XML_FieldListTop = 256;
+const xml_token_t XML_FieldStart = 257;
+const xml_token_t XML_FieldType = 258;
+const xml_token_t XML_File = 259;
+const xml_token_t XML_FileName = 260;
+const xml_token_t XML_FillDown = 261;
+const xml_token_t XML_Filled = 262;
+const xml_token_t XML_FilterCaption = 263;
+const xml_token_t XML_FilterMember = 264;
+const xml_token_t XML_FilterOn = 265;
+const xml_token_t XML_FirstVisibleSheet = 266;
+const xml_token_t XML_FitHeight = 267;
+const xml_token_t XML_FitToPage = 268;
+const xml_token_t XML_FitWidth = 269;
+const xml_token_t XML_Font = 270;
+const xml_token_t XML_FontName = 271;
+const xml_token_t XML_Footer = 272;
+const xml_token_t XML_Format = 273;
+const xml_token_t XML_FormatSettings = 274;
+const xml_token_t XML_FormatType = 275;
+const xml_token_t XML_Formula = 276;
+const xml_token_t XML_FormulaIndex = 277;
+const xml_token_t XML_FormulaV10 = 278;
+const xml_token_t XML_FreezePanes = 279;
+const xml_token_t XML_FrozenNoSplit = 280;
+const xml_token_t XML_FullColumns = 281;
+const xml_token_t XML_FullRows = 282;
+const xml_token_t XML_Function = 283;
+const xml_token_t XML_FunctionGroup = 284;
+const xml_token_t XML_FunctionGroupIndex = 285;
+const xml_token_t XML_FuturePersist = 286;
+const xml_token_t XML_FutureVer = 287;
+const xml_token_t XML_GrandTotalString = 288;
+const xml_token_t XML_GridlineColor = 289;
+const xml_token_t XML_GridlineColorIndex = 290;
+const xml_token_t XML_Gridlines = 291;
+const xml_token_t XML_GroupBy = 292;
+const xml_token_t XML_GroupDefinition = 293;
+const xml_token_t XML_GroupEnd = 294;
+const xml_token_t XML_GroupEndAuto = 295;
+const xml_token_t XML_GroupLevel = 296;
+const xml_token_t XML_GroupMember = 297;
+const xml_token_t XML_GroupNumber = 298;
+const xml_token_t XML_GroupStart = 299;
+const xml_token_t XML_GroupStartAuto = 300;
+const xml_token_t XML_GroupType = 301;
+const xml_token_t XML_GroupedWidth = 302;
+const xml_token_t XML_Guid = 303;
+const xml_token_t XML_HRef = 304;
+const xml_token_t XML_HRefScreenTip = 305;
+const xml_token_t XML_HTMLFormat = 306;
+const xml_token_t XML_HTMLTables = 307;
+const xml_token_t XML_HasNoAutoFormat = 308;
+const xml_token_t XML_HasNoRecords = 309;
+const xml_token_t XML_Header = 310;
+const xml_token_t XML_HeaderRange = 311;
+const xml_token_t XML_HeaderRow = 312;
+const xml_token_t XML_Height = 313;
+const xml_token_t XML_Hidden = 314;
+const xml_token_t XML_HideDetail = 315;
+const xml_token_t XML_HideDropDowns = 316;
+const xml_token_t XML_HideFormula = 317;
+const xml_token_t XML_HideHorizontalScrollBar = 318;
+const xml_token_t XML_HideInactiveListBorder = 319;
+const xml_token_t XML_HideOfficeLogo = 320;
+const xml_token_t XML_HidePivotTableFieldList = 321;
+const xml_token_t XML_HideTotalsAnnotation = 322;
+const xml_token_t XML_HideVerticalScrollBar = 323;
+const xml_token_t XML_HideWorkbookTabs = 324;
+const xml_token_t XML_Horizontal = 325;
+const xml_token_t XML_HorizontalResolution = 326;
+const xml_token_t XML_Href = 327;
+const xml_token_t XML_HtmlType = 328;
+const xml_token_t XML_HyperlinkBase = 329;
+const xml_token_t XML_I = 330;
+const xml_token_t XML_ID = 331;
+const xml_token_t XML_IMEMode = 332;
+const xml_token_t XML_Id = 333;
+const xml_token_t XML_IdWrapped = 334;
+const xml_token_t XML_If = 335;
+const xml_token_t XML_ImmediateItemsOnDrop = 336;
+const xml_token_t XML_Indent = 337;
+const xml_token_t XML_Index = 338;
+const xml_token_t XML_IndividualCellBorders = 339;
+const xml_token_t XML_InputHide = 340;
+const xml_token_t XML_InputMessage = 341;
+const xml_token_t XML_InputTitle = 342;
+const xml_token_t XML_InsertEntireRows = 343;
+const xml_token_t XML_InstanceShape = 344;
+const xml_token_t XML_Interior = 345;
+const xml_token_t XML_IntlMacro = 346;
+const xml_token_t XML_Invalid = 347;
+const xml_token_t XML_InvertedColumnMember = 348;
+const xml_token_t XML_InvertedRowMember = 349;
+const xml_token_t XML_IsGroupLevel = 350;
+const xml_token_t XML_IsMemberProperty = 351;
+const xml_token_t XML_IsNotFiltered = 352;
+const xml_token_t XML_Italic = 353;
+const xml_token_t XML_Item = 354;
+const xml_token_t XML_ItemType = 355;
+const xml_token_t XML_Iteration = 356;
+const xml_token_t XML_KeyboardShortcut = 357;
+const xml_token_t XML_Keywords = 358;
+const xml_token_t XML_Label = 359;
+const xml_token_t XML_LastAuthor = 360;
+const xml_token_t XML_LastPrinted = 361;
+const xml_token_t XML_LastSaved = 362;
+const xml_token_t XML_Layout = 363;
+const xml_token_t XML_LayoutForm = 364;
+const xml_token_t XML_LayoutPageBreak = 365;
+const xml_token_t XML_LayoutSubtotalLocation = 366;
+const xml_token_t XML_LeafColumnMember = 367;
+const xml_token_t XML_LeafRowMember = 368;
+const xml_token_t XML_Left = 369;
+const xml_token_t XML_LeftCell = 370;
+const xml_token_t XML_LeftColumnRightPane = 371;
+const xml_token_t XML_LeftColumnVisible = 372;
+const xml_token_t XML_LeftToRight = 373;
+const xml_token_t XML_LengthLevelUniqueName = 374;
+const xml_token_t XML_Level = 375;
+const xml_token_t XML_LineStyle = 376;
+const xml_token_t XML_Lines = 377;
+const xml_token_t XML_LoadMode = 378;
+const xml_token_t XML_LocalConnection = 379;
+const xml_token_t XML_Location = 380;
+const xml_token_t XML_LocationOfComponents = 381;
+const xml_token_t XML_Macro = 382;
+const xml_token_t XML_MainFile = 383;
+const xml_token_t XML_Maintain = 384;
+const xml_token_t XML_MajorVersion = 385;
+const xml_token_t XML_Manager = 386;
+const xml_token_t XML_Map = 387;
+const xml_token_t XML_MapChildItems = 388;
+const xml_token_t XML_MapID = 389;
+const xml_token_t XML_MapInfo = 390;
+const xml_token_t XML_Mapdata = 391;
+const xml_token_t XML_Margin = 392;
+const xml_token_t XML_Max = 393;
+const xml_token_t XML_MaxChange = 394;
+const xml_token_t XML_MaxHeight = 395;
+const xml_token_t XML_MaxIterations = 396;
+const xml_token_t XML_MaxWidth = 397;
+const xml_token_t XML_Measure = 398;
+const xml_token_t XML_Member = 399;
+const xml_token_t XML_MemberExpand = 400;
+const xml_token_t XML_MemberFormat = 401;
+const xml_token_t XML_MemberName = 402;
+const xml_token_t XML_MemberPropertiesOrder = 403;
+const xml_token_t XML_MemberProperty = 404;
+const xml_token_t XML_MemberPropertyParent = 405;
+const xml_token_t XML_MergeAcross = 406;
+const xml_token_t XML_MergeDown = 407;
+const xml_token_t XML_MergeLabels = 408;
+const xml_token_t XML_Min = 409;
+const xml_token_t XML_MinorVersion = 410;
+const xml_token_t XML_Missing = 411;
+const xml_token_t XML_MissingItemsLimit = 412;
+const xml_token_t XML_Moper = 413;
+const xml_token_t XML_MoveAfterReturn = 414;
+const xml_token_t XML_Name = 415;
+const xml_token_t XML_NamedCell = 416;
+const xml_token_t XML_NamedRange = 417;
+const xml_token_t XML_Names = 418;
+const xml_token_t XML_Namespace = 419;
+const xml_token_t XML_NewAsync = 420;
+const xml_token_t XML_NewItemsHidden = 421;
+const xml_token_t XML_NextId = 422;
+const xml_token_t XML_NextSheetNumber = 423;
+const xml_token_t XML_NoAutoFit = 424;
+const xml_token_t XML_NoAutoFormatWidth = 425;
+const xml_token_t XML_NoAutoPage = 426;
+const xml_token_t XML_NoAutoRecover = 427;
+const xml_token_t XML_NoAutofit = 428;
+const xml_token_t XML_NoColumnGrand = 429;
+const xml_token_t XML_NoDetailAutoFit = 430;
+const xml_token_t XML_NoDisplayNullString = 431;
+const xml_token_t XML_NoDragToColumn = 432;
+const xml_token_t XML_NoDragToData = 433;
+const xml_token_t XML_NoDragToHide = 434;
+const xml_token_t XML_NoDragToPage = 435;
+const xml_token_t XML_NoDragToRow = 436;
+const xml_token_t XML_NoInserts = 437;
+const xml_token_t XML_NoPreserveFormatting = 438;
+const xml_token_t XML_NoPrintRepeatItems = 439;
+const xml_token_t XML_NoPrinterInfo = 440;
+const xml_token_t XML_NoRefreshCache = 441;
+const xml_token_t XML_NoRowGrand = 442;
+const xml_token_t XML_NoSaveData = 443;
+const xml_token_t XML_NoSummaryColumnsRightDetail = 444;
+const xml_token_t XML_NoSummaryRowsBelowDetail = 445;
+const xml_token_t XML_NoTextToColumns = 446;
+const xml_token_t XML_NoTitles = 447;
+const xml_token_t XML_NoToggleDataHeader = 448;
+const xml_token_t XML_NoViewCalculatedMembers = 449;
+const xml_token_t XML_NonDefaultName = 450;
+const xml_token_t XML_NotInverted = 451;
+const xml_token_t XML_NotVisible = 452;
+const xml_token_t XML_NullString = 453;
+const xml_token_t XML_Number = 454;
+const xml_token_t XML_NumberFormat = 455;
+const xml_token_t XML_NumberOfCopies = 456;
+const xml_token_t XML_OLEObject = 457;
+const xml_token_t XML_OWCVersion = 458;
+const xml_token_t XML_ObjectID = 459;
+const xml_token_t XML_OfficeDocumentSettings = 460;
+const xml_token_t XML_OleLink = 461;
+const xml_token_t XML_Operator = 462;
+const xml_token_t XML_OptimizeCache = 463;
+const xml_token_t XML_Orientation = 464;
+const xml_token_t XML_Outline = 465;
+const xml_token_t XML_OverwriteCells = 466;
+const xml_token_t XML_PLCaption = 467;
+const xml_token_t XML_PLDataOrientation = 468;
+const xml_token_t XML_PLExport = 469;
+const xml_token_t XML_PLGroupType = 470;
+const xml_token_t XML_PLName = 471;
+const xml_token_t XML_PLPivotField = 472;
+const xml_token_t XML_PLPosition = 473;
+const xml_token_t XML_PLSubtotal = 474;
+const xml_token_t XML_PLTPivotItem = 475;
+const xml_token_t XML_PLTotal = 476;
+const xml_token_t XML_PTFormat = 477;
+const xml_token_t XML_PTFormula = 478;
+const xml_token_t XML_PTLineItem = 479;
+const xml_token_t XML_PTLineItems = 480;
+const xml_token_t XML_PTPivotData = 481;
+const xml_token_t XML_PTRule = 482;
+const xml_token_t XML_PTSource = 483;
+const xml_token_t XML_PageBreakZoom = 484;
+const xml_token_t XML_PageBreaks = 485;
+const xml_token_t XML_PageFieldOrder = 486;
+const xml_token_t XML_PageFieldStyle = 487;
+const xml_token_t XML_PageFieldWrapCount = 488;
+const xml_token_t XML_PageMargins = 489;
+const xml_token_t XML_PageSetup = 490;
+const xml_token_t XML_Pages = 491;
+const xml_token_t XML_Pane = 492;
+const xml_token_t XML_Panes = 493;
+const xml_token_t XML_PaperSizeIndex = 494;
+const xml_token_t XML_Paragraphs = 495;
+const xml_token_t XML_Parameter = 496;
+const xml_token_t XML_ParameterType = 497;
+const xml_token_t XML_ParameterValue = 498;
+const xml_token_t XML_Parent = 499;
+const xml_token_t XML_ParentField = 500;
+const xml_token_t XML_ParentIsOther = 501;
+const xml_token_t XML_ParentName = 502;
+const xml_token_t XML_ParentUniqueName = 503;
+const xml_token_t XML_ParseFormulaAsV10 = 504;
+const xml_token_t XML_ParseRuleAsV10 = 505;
+const xml_token_t XML_PasteFormula = 506;
+const xml_token_t XML_PasteRefersTo = 507;
+const xml_token_t XML_Path = 508;
+const xml_token_t XML_Pattern = 509;
+const xml_token_t XML_PatternColor = 510;
+const xml_token_t XML_PivotAxis = 511;
+const xml_token_t XML_PivotCache = 512;
+const xml_token_t XML_PivotField = 513;
+const xml_token_t XML_PivotItem = 514;
+const xml_token_t XML_PivotTable = 515;
+const xml_token_t XML_PivotView = 516;
+const xml_token_t XML_Position = 517;
+const xml_token_t XML_PrecisionAsDisplayed = 518;
+const xml_token_t XML_PresentationFormat = 519;
+const xml_token_t XML_Print = 520;
+const xml_token_t XML_PrintErrors = 521;
+const xml_token_t XML_PrintSetTitles = 522;
+const xml_token_t XML_ProgID = 523;
+const xml_token_t XML_PromptString = 524;
+const xml_token_t XML_ProtectContents = 525;
+const xml_token_t XML_ProtectObjects = 526;
+const xml_token_t XML_ProtectScenarios = 527;
+const xml_token_t XML_ProtectStructure = 528;
+const xml_token_t XML_ProtectWindows = 529;
+const xml_token_t XML_Protected = 530;
+const xml_token_t XML_Protection = 531;
+const xml_token_t XML_Proxy = 532;
+const xml_token_t XML_PublishObject = 533;
+const xml_token_t XML_PublishObjects = 534;
+const xml_token_t XML_Purpose = 535;
+const xml_token_t XML_QTSource = 536;
+const xml_token_t XML_Qualifier = 537;
+const xml_token_t XML_Query97 = 538;
+const xml_token_t XML_QuerySource = 539;
+const xml_token_t XML_QueryTable = 540;
+const xml_token_t XML_QueryType = 541;
+const xml_token_t XML_Range = 542;
+const xml_token_t XML_RangeSelection = 543;
+const xml_token_t XML_ReadOnly = 544;
+const xml_token_t XML_ReadingOrder = 545;
+const xml_token_t XML_RefModeR1C1 = 546;
+const xml_token_t XML_Reference = 547;
+const xml_token_t XML_RefersTo = 548;
+const xml_token_t XML_RefreshDate = 549;
+const xml_token_t XML_RefreshDateCopy = 550;
+const xml_token_t XML_RefreshInfo = 551;
+const xml_token_t XML_RefreshName = 552;
+const xml_token_t XML_RefreshOnChange = 553;
+const xml_token_t XML_RefreshOnFileOpen = 554;
+const xml_token_t XML_RefreshTimeSpan = 555;
+const xml_token_t XML_RefreshedInXl9 = 556;
+const xml_token_t XML_Resource = 557;
+const xml_token_t XML_Revision = 558;
+const xml_token_t XML_Right = 559;
+const xml_token_t XML_RightToLeft = 560;
+const xml_token_t XML_RobustConnect = 561;
+const xml_token_t XML_RootElement = 562;
+const xml_token_t XML_Rotate = 563;
+const xml_token_t XML_Rotation = 564;
+const xml_token_t XML_Row = 565;
+const xml_token_t XML_RowBreak = 566;
+const xml_token_t XML_RowBreaks = 567;
+const xml_token_t XML_RowColHeadings = 568;
+const xml_token_t XML_RowInputCell = 569;
+const xml_token_t XML_RowLast = 570;
+const xml_token_t XML_RowNumbers = 571;
+const xml_token_t XML_Rule = 572;
+const xml_token_t XML_RuleType = 573;
+const xml_token_t XML_RuleV10 = 574;
+const xml_token_t XML_S = 575;
+const xml_token_t XML_SOAPAction = 576;
+const xml_token_t XML_SQLType = 577;
+const xml_token_t XML_Scale = 578;
+const xml_token_t XML_Schema = 579;
+const xml_token_t XML_SchemaID = 580;
+const xml_token_t XML_SchemaRef = 581;
+const xml_token_t XML_Selected = 582;
+const xml_token_t XML_SelectedSheets = 583;
+const xml_token_t XML_Selection = 584;
+const xml_token_t XML_SelectionNamespaces = 585;
+const xml_token_t XML_SemiColon = 586;
+const xml_token_t XML_SeqNum = 587;
+const xml_token_t XML_Sequence = 588;
+const xml_token_t XML_ServerBased = 589;
+const xml_token_t XML_ServerSortOrder = 590;
+const xml_token_t XML_Set = 591;
+const xml_token_t XML_Shadow = 592;
+const xml_token_t XML_ShapeID = 593;
+const xml_token_t XML_SheetIndex = 594;
+const xml_token_t XML_SheetName = 595;
+const xml_token_t XML_ShowAllItems = 596;
+const xml_token_t XML_ShowAlways = 597;
+const xml_token_t XML_ShowCellBackgroundFromOLAP = 598;
+const xml_token_t XML_ShowImportExportValidationErrors = 599;
+const xml_token_t XML_ShowPageBreakZoom = 600;
+const xml_token_t XML_ShowPageMultipleItemLabel = 601;
+const xml_token_t XML_ShowTotals = 602;
+const xml_token_t XML_ShrinkToFit = 603;
+const xml_token_t XML_Size = 604;
+const xml_token_t XML_SmallGrid = 605;
+const xml_token_t XML_SmartTagType = 606;
+const xml_token_t XML_SmartTags = 607;
+const xml_token_t XML_SolveOrder = 608;
+const xml_token_t XML_Sort = 609;
+const xml_token_t XML_SortKey = 610;
+const xml_token_t XML_SortOrder = 611;
+const xml_token_t XML_Sorting = 612;
+const xml_token_t XML_Source = 613;
+const xml_token_t XML_SourceConnectionFile = 614;
+const xml_token_t XML_SourceConsolidation = 615;
+const xml_token_t XML_SourceDataFile = 616;
+const xml_token_t XML_SourceHierarchy = 617;
+const xml_token_t XML_SourceHierarchyLevel = 618;
+const xml_token_t XML_SourceName = 619;
+const xml_token_t XML_SourceType = 620;
+const xml_token_t XML_Space = 621;
+const xml_token_t XML_SpaceAbove = 622;
+const xml_token_t XML_SpaceBelow = 623;
+const xml_token_t XML_Span = 624;
+const xml_token_t XML_SplitHorizontal = 625;
+const xml_token_t XML_SplitVertical = 626;
+const xml_token_t XML_SpreadsheetAutoFit = 627;
+const xml_token_t XML_StandardWidth = 628;
+const xml_token_t XML_StartPageNumber = 629;
+const xml_token_t XML_StartRow = 630;
+const xml_token_t XML_StrikeThrough = 631;
+const xml_token_t XML_Style = 632;
+const xml_token_t XML_StyleID = 633;
+const xml_token_t XML_Styles = 634;
+const xml_token_t XML_Sub = 635;
+const xml_token_t XML_SubType = 636;
+const xml_token_t XML_Subject = 637;
+const xml_token_t XML_Subtotal = 638;
+const xml_token_t XML_SubtotalFormat = 639;
+const xml_token_t XML_SubtotalHiddenPageItems = 640;
+const xml_token_t XML_SubtotalName = 641;
+const xml_token_t XML_Sup = 642;
+const xml_token_t XML_SupBook = 643;
+const xml_token_t XML_Synchronous = 644;
+const xml_token_t XML_Tab = 645;
+const xml_token_t XML_TabColorIndex = 646;
+const xml_token_t XML_TabRatio = 647;
+const xml_token_t XML_Table = 648;
+const xml_token_t XML_TableStyle = 649;
+const xml_token_t XML_Tag = 650;
+const xml_token_t XML_Text = 651;
+const xml_token_t XML_TextQualifier = 652;
+const xml_token_t XML_TextWizardSettings = 653;
+const xml_token_t XML_ThousandSeparator = 654;
+const xml_token_t XML_Ticked = 655;
+const xml_token_t XML_Title = 656;
+const xml_token_t XML_Toolbar = 657;
+const xml_token_t XML_TooltipInfo = 658;
+const xml_token_t XML_Top = 659;
+const xml_token_t XML_TopCell = 660;
+const xml_token_t XML_TopRowBottomPane = 661;
+const xml_token_t XML_TopRowVisible = 662;
+const xml_token_t XML_TotalAlignment = 663;
+const xml_token_t XML_TotalAllMembers = 664;
+const xml_token_t XML_TotalCaptionAlignment = 665;
+const xml_token_t XML_TotalFormat = 666;
+const xml_token_t XML_TotalTime = 667;
+const xml_token_t XML_TotalWidth = 668;
+const xml_token_t XML_TransitionExpressionEvaluation = 669;
+const xml_token_t XML_TransitionFormulaEntry = 670;
+const xml_token_t XML_Type = 671;
+const xml_token_t XML_U = 672;
+const xml_token_t XML_URLString = 673;
+const xml_token_t XML_Uncalced = 674;
+const xml_token_t XML_Underline = 675;
+const xml_token_t XML_UniqueName = 676;
+const xml_token_t XML_Unsynced = 677;
+const xml_token_t XML_UseBlank = 678;
+const xml_token_t XML_UseLocalConnection = 679;
+const xml_token_t XML_UseSameSettings = 680;
+const xml_token_t XML_User = 681;
+const xml_token_t XML_VMLFrame = 682;
+const xml_token_t XML_VacatedStyle = 683;
+const xml_token_t XML_ValidPrinterInfo = 684;
+const xml_token_t XML_Value = 685;
+const xml_token_t XML_Value1 = 686;
+const xml_token_t XML_Value2 = 687;
+const xml_token_t XML_Version = 688;
+const xml_token_t XML_VersionLastEdit = 689;
+const xml_token_t XML_VersionLastRefresh = 690;
+const xml_token_t XML_VersionLastUpdate = 691;
+const xml_token_t XML_VersionRefreshableMin = 692;
+const xml_token_t XML_VersionUpdateableMin = 693;
+const xml_token_t XML_Vertical = 694;
+const xml_token_t XML_VerticalAlign = 695;
+const xml_token_t XML_VerticalResolution = 696;
+const xml_token_t XML_VerticalText = 697;
+const xml_token_t XML_ViewableRange = 698;
+const xml_token_t XML_Visible = 699;
+const xml_token_t XML_VisualTotals = 700;
+const xml_token_t XML_WantAdvise = 701;
+const xml_token_t XML_WantPict = 702;
+const xml_token_t XML_Watch = 703;
+const xml_token_t XML_Watches = 704;
+const xml_token_t XML_WebPostString = 705;
+const xml_token_t XML_Weight = 706;
+const xml_token_t XML_Width = 707;
+const xml_token_t XML_WindowHeight = 708;
+const xml_token_t XML_WindowHidden = 709;
+const xml_token_t XML_WindowIconic = 710;
+const xml_token_t XML_WindowTopX = 711;
+const xml_token_t XML_WindowTopY = 712;
+const xml_token_t XML_WindowWidth = 713;
+const xml_token_t XML_Windows = 714;
+const xml_token_t XML_Words = 715;
+const xml_token_t XML_Workbook = 716;
+const xml_token_t XML_WorkbookOptions = 717;
+const xml_token_t XML_Worksheet = 718;
+const xml_token_t XML_WorksheetOptions = 719;
+const xml_token_t XML_WorksheetSource = 720;
+const xml_token_t XML_WrapText = 721;
+const xml_token_t XML_XPath = 722;
+const xml_token_t XML_XSDType = 723;
+const xml_token_t XML_Xct = 724;
+const xml_token_t XML_ZeroHeight = 725;
+const xml_token_t XML_Zoom = 726;
+const xml_token_t XML_accentbar = 727;
+const xml_token_t XML_adj = 728;
+const xml_token_t XML_adjusthandles = 729;
+const xml_token_t XML_alignshape = 730;
+const xml_token_t XML_allowincell = 731;
+const xml_token_t XML_allowoverlap = 732;
+const xml_token_t XML_alt = 733;
+const xml_token_t XML_althref = 734;
+const xml_token_t XML_angle = 735;
+const xml_token_t XML_arc = 736;
+const xml_token_t XML_arcsize = 737;
+const xml_token_t XML_arrowok = 738;
+const xml_token_t XML_aspect = 739;
+const xml_token_t XML_aspectratio = 740;
+const xml_token_t XML_attribute = 741;
+const xml_token_t XML_autorotationcenter = 742;
+const xml_token_t XML_backdepth = 743;
+const xml_token_t XML_background = 744;
+const xml_token_t XML_bilevel = 745;
+const xml_token_t XML_blacklevel = 746;
+const xml_token_t XML_borderbottomcolor = 747;
+const xml_token_t XML_borderleftcolor = 748;
+const xml_token_t XML_borderrightcolor = 749;
+const xml_token_t XML_bordertopcolor = 750;
+const xml_token_t XML_brightness = 751;
+const xml_token_t XML_bullet = 752;
+const xml_token_t XML_button = 753;
+const xml_token_t XML_bwmode = 754;
+const xml_token_t XML_bwnormal = 755;
+const xml_token_t XML_bwpure = 756;
+const xml_token_t XML_callout = 757;
+const xml_token_t XML_caption = 758;
+const xml_token_t XML_chromakey = 759;
+const xml_token_t XML_class = 760;
+const xml_token_t XML_clip = 761;
+const xml_token_t XML_color = 762;
+const xml_token_t XML_color2 = 763;
+const xml_token_t XML_colormenu = 764;
+const xml_token_t XML_colormode = 765;
+const xml_token_t XML_colormru = 766;
+const xml_token_t XML_colors = 767;
+const xml_token_t XML_complex = 768;
+const xml_token_t XML_connectangles = 769;
+const xml_token_t XML_connectloc = 770;
+const xml_token_t XML_connectlocs = 771;
+const xml_token_t XML_connectortype = 772;
+const xml_token_t XML_connecttype = 773;
+const xml_token_t XML_content = 774;
+const xml_token_t XML_control1 = 775;
+const xml_token_t XML_control2 = 776;
+const xml_token_t XML_coordorigin = 777;
+const xml_token_t XML_coordsize = 778;
+const xml_token_t XML_cropbottom = 779;
+const xml_token_t XML_cropleft = 780;
+const xml_token_t XML_cropping = 781;
+const xml_token_t XML_cropright = 782;
+const xml_token_t XML_croptop = 783;
+const xml_token_t XML_curve = 784;
+const xml_token_t XML_dashstyle = 785;
+const xml_token_t XML_data = 786;
+const xml_token_t XML_datatype = 787;
+const xml_token_t XML_detectmouseclick = 788;
+const xml_token_t XML_diffusity = 789;
+const xml_token_t XML_displaycustomheaders = 790;
+const xml_token_t XML_distance = 791;
+const xml_token_t XML_doubleclicknotify = 792;
+const xml_token_t XML_drop = 793;
+const xml_token_t XML_dropauto = 794;
+const xml_token_t XML_dt = 795;
+const xml_token_t XML_edge = 796;
+const xml_token_t XML_editas = 797;
+const xml_token_t XML_embosscolor = 798;
+const xml_token_t XML_end = 799;
+const xml_token_t XML_endAngle = 800;
+const xml_token_t XML_endarrow = 801;
+const xml_token_t XML_endarrowlength = 802;
+const xml_token_t XML_endarrowwidth = 803;
+const xml_token_t XML_endcap = 804;
+const xml_token_t XML_entry = 805;
+const xml_token_t XML_eqn = 806;
+const xml_token_t XML_ext = 807;
+const xml_token_t XML_extends = 808;
+const xml_token_t XML_extrusion = 809;
+const xml_token_t XML_extrusioncolor = 810;
+const xml_token_t XML_extrusionok = 811;
+const xml_token_t XML_f = 812;
+const xml_token_t XML_facet = 813;
+const xml_token_t XML_fill = 814;
+const xml_token_t XML_fillcolor = 815;
+const xml_token_t XML_filled = 816;
+const xml_token_t XML_fillok = 817;
+const xml_token_t XML_filltype = 818;
+const xml_token_t XML_fitpath = 819;
+const xml_token_t XML_fitshape = 820;
+const xml_token_t XML_focus = 821;
+const xml_token_t XML_focusposition = 822;
+const xml_token_t XML_focussize = 823;
+const xml_token_t XML_forcedash = 824;
+const xml_token_t XML_foredepth = 825;
+const xml_token_t XML_formulas = 826;
+const xml_token_t XML_from = 827;
+const xml_token_t XML_gain = 828;
+const xml_token_t XML_gamma = 829;
+const xml_token_t XML_gap = 830;
+const xml_token_t XML_gradientshapeok = 831;
+const xml_token_t XML_grayscale = 832;
+const xml_token_t XML_group = 833;
+const xml_token_t XML_grouping = 834;
+const xml_token_t XML_h = 835;
+const xml_token_t XML_handles = 836;
+const xml_token_t XML_hidden = 837;
+const xml_token_t XML_how = 838;
+const xml_token_t XML_hr = 839;
+const xml_token_t XML_hralign = 840;
+const xml_token_t XML_href = 841;
+const xml_token_t XML_hrheight = 842;
+const xml_token_t XML_hrnoshade = 843;
+const xml_token_t XML_hrpct = 844;
+const xml_token_t XML_hrstd = 845;
+const xml_token_t XML_hrwidth = 846;
+const xml_token_t XML_id = 847;
+const xml_token_t XML_idmap = 848;
+const xml_token_t XML_idref = 849;
+const xml_token_t XML_image = 850;
+const xml_token_t XML_imagealignshape = 851;
+const xml_token_t XML_imageaspect = 852;
+const xml_token_t XML_imagedata = 853;
+const xml_token_t XML_imagesize = 854;
+const xml_token_t XML_inset = 855;
+const xml_token_t XML_insetmode = 856;
+const xml_token_t XML_invx = 857;
+const xml_token_t XML_invy = 858;
+const xml_token_t XML_joinstyle = 859;
+const xml_token_t XML_length = 860;
+const xml_token_t XML_lengthspecified = 861;
+const xml_token_t XML_lightface = 862;
+const xml_token_t XML_lightharsh = 863;
+const xml_token_t XML_lightharsh2 = 864;
+const xml_token_t XML_lightlevel = 865;
+const xml_token_t XML_lightlevel2 = 866;
+const xml_token_t XML_lightposition = 867;
+const xml_token_t XML_lightposition2 = 868;
+const xml_token_t XML_limo = 869;
+const xml_token_t XML_line = 870;
+const xml_token_t XML_linestyle = 871;
+const xml_token_t XML_lock = 872;
+const xml_token_t XML_lockrotationcenter = 873;
+const xml_token_t XML_map = 874;
+const xml_token_t XML_master = 875;
+const xml_token_t XML_matrix = 876;
+const xml_token_t XML_maxLength = 877;
+const xml_token_t XML_metal = 878;
+const xml_token_t XML_method = 879;
+const xml_token_t XML_minusx = 880;
+const xml_token_t XML_minusy = 881;
+const xml_token_t XML_miterlimit = 882;
+const xml_token_t XML_movie = 883;
+const xml_token_t XML_name = 884;
+const xml_token_t XML_namespaceuri = 885;
+const xml_token_t XML_new = 886;
+const xml_token_t XML_obscured = 887;
+const xml_token_t XML_offset = 888;
+const xml_token_t XML_offset2 = 889;
+const xml_token_t XML_old = 890;
+const xml_token_t XML_ole = 891;
+const xml_token_t XML_oleicon = 892;
+const xml_token_t XML_oleid = 893;
+const xml_token_t XML_on = 894;
+const xml_token_t XML_oned = 895;
+const xml_token_t XML_onmouseover = 896;
+const xml_token_t XML_opacity = 897;
+const xml_token_t XML_opacity2 = 898;
+const xml_token_t XML_orientation = 899;
+const xml_token_t XML_orientationangle = 900;
+const xml_token_t XML_origin = 901;
+const xml_token_t XML_oval = 902;
+const xml_token_t XML_password = 903;
+const xml_token_t XML_path = 904;
+const xml_token_t XML_phonetictext = 905;
+const xml_token_t XML_plane = 906;
+const xml_token_t XML_points = 907;
+const xml_token_t XML_polar = 908;
+const xml_token_t XML_polyline = 909;
+const xml_token_t XML_position = 910;
+const xml_token_t XML_preferrelative = 911;
+const xml_token_t XML_print = 912;
+const xml_token_t XML_proxy = 913;
+const xml_token_t XML_r = 914;
+const xml_token_t XML_radiusrange = 915;
+const xml_token_t XML_rect = 916;
+const xml_token_t XML_regroupid = 917;
+const xml_token_t XML_regrouptable = 918;
+const xml_token_t XML_relativeposition = 919;
+const xml_token_t XML_render = 920;
+const xml_token_t XML_rotation = 921;
+const xml_token_t XML_rotationangle = 922;
+const xml_token_t XML_rotationcenter = 923;
+const xml_token_t XML_roundrect = 924;
+const xml_token_t XML_row = 925;
+const xml_token_t XML_ruleinitiator = 926;
+const xml_token_t XML_ruleproxy = 927;
+const xml_token_t XML_rules = 928;
+const xml_token_t XML_selection = 929;
+const xml_token_t XML_shadow = 930;
+const xml_token_t XML_shadowcolor = 931;
+const xml_token_t XML_shadowok = 932;
+const xml_token_t XML_shape = 933;
+const xml_token_t XML_shapedefaults = 934;
+const xml_token_t XML_shapelayout = 935;
+const xml_token_t XML_shapetype = 936;
+const xml_token_t XML_shininess = 937;
+const xml_token_t XML_singleclick = 938;
+const xml_token_t XML_size = 939;
+const xml_token_t XML_skew = 940;
+const xml_token_t XML_skewamt = 941;
+const xml_token_t XML_skewangle = 942;
+const xml_token_t XML_specularity = 943;
+const xml_token_t XML_spid = 944;
+const xml_token_t XML_spidmax = 945;
+const xml_token_t XML_spt = 946;
+const xml_token_t XML_src = 947;
+const xml_token_t XML_start = 948;
+const xml_token_t XML_startAngle = 949;
+const xml_token_t XML_startarrow = 950;
+const xml_token_t XML_startarrowlength = 951;
+const xml_token_t XML_startarrowwidth = 952;
+const xml_token_t XML_string = 953;
+const xml_token_t XML_stroke = 954;
+const xml_token_t XML_strokecolor = 955;
+const xml_token_t XML_stroked = 956;
+const xml_token_t XML_strokeok = 957;
+const xml_token_t XML_strokeweight = 958;
+const xml_token_t XML_style = 959;
+const xml_token_t XML_switch = 960;
+const xml_token_t XML_tablelimits = 961;
+const xml_token_t XML_tableproperties = 962;
+const xml_token_t XML_target = 963;
+const xml_token_t XML_targetscreensize = 964;
+const xml_token_t XML_text = 965;
+const xml_token_t XML_textborder = 966;
+const xml_token_t XML_textbox = 967;
+const xml_token_t XML_textboxrect = 968;
+const xml_token_t XML_textpath = 969;
+const xml_token_t XML_textpathok = 970;
+const xml_token_t XML_title = 971;
+const xml_token_t XML_to = 972;
+const xml_token_t XML_trim = 973;
+const xml_token_t XML_type = 974;
+const xml_token_t XML_url = 975;
+const xml_token_t XML_useExplicit = 976;
+const xml_token_t XML_userId = 977;
+const xml_token_t XML_userdrawn = 978;
+const xml_token_t XML_userhidden = 979;
+const xml_token_t XML_v = 980;
+const xml_token_t XML_verticies = 981;
+const xml_token_t XML_viewpoint = 982;
+const xml_token_t XML_viewpointorigin = 983;
+const xml_token_t XML_visible = 984;
+const xml_token_t XML_weight = 985;
+const xml_token_t XML_worksheetoptions = 986;
+const xml_token_t XML_wrapcoords = 987;
+const xml_token_t XML_xrange = 988;
+const xml_token_t XML_xscale = 989;
+const xml_token_t XML_yrange = 990;
diff --git a/src/liborcus/xls_xml_tokens.cpp b/src/liborcus/xls_xml_tokens.cpp
new file mode 100644
index 0000000..1ba9001
--- /dev/null
+++ b/src/liborcus/xls_xml_tokens.cpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xls_xml_tokens.hpp"
+
+namespace orcus {
+
+namespace {
+
+#include "xls_xml_tokens.inl"
+
+}
+
+tokens xls_xml_tokens = tokens(token_names, token_name_count);
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_tokens.hpp b/src/liborcus/xls_xml_tokens.hpp
new file mode 100644
index 0000000..0180db1
--- /dev/null
+++ b/src/liborcus/xls_xml_tokens.hpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLS_XML_TOKENS_HPP
+#define ORCUS_XLS_XML_TOKENS_HPP
+
+#include "orcus/tokens.hpp"
+
+namespace orcus {
+
+extern tokens xls_xml_tokens;
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xls_xml_tokens.inl b/src/liborcus/xls_xml_tokens.inl
new file mode 100644
index 0000000..73cd1fc
--- /dev/null
+++ b/src/liborcus/xls_xml_tokens.inl
@@ -0,0 +1,997 @@
+// This file has been auto-generated. Do not hand-edit this.
+
+const char* token_names[] = {
+ "??", // 0
+ "AcceptLabelsInFormulas", // 1
+ "Action", // 2
+ "ActiveChart", // 3
+ "ActiveCol", // 4
+ "ActiveColumn", // 5
+ "ActivePane", // 6
+ "ActiveRow", // 7
+ "ActiveRows", // 8
+ "ActiveSheet", // 9
+ "Aggregate", // 10
+ "AlertVersion", // 11
+ "Alignment", // 12
+ "AllItemName", // 13
+ "AllowDeleteCols", // 14
+ "AllowDeleteRows", // 15
+ "AllowFilter", // 16
+ "AllowFormatCells", // 17
+ "AllowInsertCols", // 18
+ "AllowInsertHyperlinks", // 19
+ "AllowInsertRows", // 20
+ "AllowPNG", // 21
+ "AllowSizeCols", // 22
+ "AllowSizeRows", // 23
+ "AllowSort", // 24
+ "AllowUsePivotTables", // 25
+ "AlternateMethod", // 26
+ "AppName", // 27
+ "Append", // 28
+ "ApplyAutomaticOutlineStyles", // 29
+ "Area", // 30
+ "ArrayRange", // 31
+ "Async", // 32
+ "Attribute", // 33
+ "AttributeType", // 34
+ "Authentication", // 35
+ "Author", // 36
+ "AutoFilter", // 37
+ "AutoFilterAnd", // 38
+ "AutoFilterColumn", // 39
+ "AutoFilterCondition", // 40
+ "AutoFilterOr", // 41
+ "AutoFitHeight", // 42
+ "AutoFitWidth", // 43
+ "AutoFormatAlignment", // 44
+ "AutoFormatBorder", // 45
+ "AutoFormatFont", // 46
+ "AutoFormatName", // 47
+ "AutoFormatNumber", // 48
+ "AutoFormatPattern", // 49
+ "AutoFormatWidth", // 50
+ "AutoRepublish", // 51
+ "AutoShowCount", // 52
+ "AutoShowField", // 53
+ "AutoShowRange", // 54
+ "AutoShowType", // 55
+ "AutoSortField", // 56
+ "AutoSortOrder", // 57
+ "B", // 58
+ "BackgroundQuery", // 59
+ "BaseField", // 60
+ "BaseItem", // 61
+ "Basic", // 62
+ "Behavior", // 63
+ "Binding", // 64
+ "BlackAndWhite", // 65
+ "BlankLineAfterItems", // 66
+ "BlockTotal", // 67
+ "Bold", // 68
+ "Boolean", // 69
+ "Border", // 70
+ "Borders", // 71
+ "Bottom", // 72
+ "BoundField", // 73
+ "Bytes", // 74
+ "CacheDetails", // 75
+ "CacheFile", // 76
+ "CacheIndex", // 77
+ "CachePosition", // 78
+ "CalculatedMember", // 79
+ "Calculation", // 80
+ "CantGetUniqueItems", // 81
+ "Caption", // 82
+ "CaptionAlignment", // 83
+ "CaseSensitive", // 84
+ "Category", // 85
+ "Cell", // 86
+ "CellRangeList", // 87
+ "CellsExpanded", // 88
+ "CellsExpandedSeqNum", // 89
+ "CellsNotExpanded", // 90
+ "CenterHorizontal", // 91
+ "CenterVertical", // 92
+ "Cf", // 93
+ "CharSet", // 94
+ "Characters", // 95
+ "CharactersWithSpaces", // 96
+ "ClientParameter", // 97
+ "ClientParameterBinding", // 98
+ "ClientParameterBindings", // 99
+ "ClientParameterValue", // 100
+ "Clipped", // 101
+ "CodeName", // 102
+ "Col1", // 103
+ "Col10", // 104
+ "Col11", // 105
+ "Col12", // 106
+ "Col13", // 107
+ "Col14", // 108
+ "Col15", // 109
+ "Col16", // 110
+ "Col17", // 111
+ "Col18", // 112
+ "Col19", // 113
+ "Col2", // 114
+ "Col20", // 115
+ "Col3", // 116
+ "Col4", // 117
+ "Col5", // 118
+ "Col6", // 119
+ "Col7", // 120
+ "Col8", // 121
+ "Col9", // 122
+ "ColBreak", // 123
+ "ColBreaks", // 124
+ "ColFirst", // 125
+ "ColLast", // 126
+ "Color", // 127
+ "Column", // 128
+ "ColumnInfo", // 129
+ "ColumnInputCell", // 130
+ "ColumnName", // 131
+ "ComboHide", // 132
+ "Comma", // 133
+ "CommandText", // 134
+ "CommandTextOrignal", // 135
+ "CommandType", // 136
+ "Comment", // 137
+ "CommentsLayout", // 138
+ "Company", // 139
+ "ComponentOptions", // 140
+ "Condition", // 141
+ "ConditionalFormatting", // 142
+ "Connection", // 143
+ "ConnectionInfo", // 144
+ "ConnectionString", // 145
+ "Consecutive", // 146
+ "ConsolidationReference", // 147
+ "Count", // 148
+ "CountOfSameItems", // 149
+ "CreateBackup", // 150
+ "Created", // 151
+ "Credential", // 152
+ "CredentialBinding", // 153
+ "CredentialValue", // 154
+ "Crn", // 155
+ "CubeField", // 156
+ "CubeSource", // 157
+ "CurrentPage", // 158
+ "Custom", // 159
+ "CustomDocumentProperties", // 160
+ "Data", // 161
+ "DataAxisEmpty", // 162
+ "DataField", // 163
+ "DataMember", // 164
+ "DataSource", // 165
+ "DataTable", // 166
+ "DataType", // 167
+ "DataValidation", // 168
+ "DataValueEditing", // 169
+ "Date1904", // 170
+ "Decimal", // 171
+ "DefaultColumnWidth", // 172
+ "DefaultItem", // 173
+ "DefaultRowHeight", // 174
+ "DefaultValue", // 175
+ "DefaultVersion", // 176
+ "DeletedTitle", // 177
+ "Delimiters", // 178
+ "Descending", // 179
+ "Description", // 180
+ "DetailFormat", // 181
+ "DetailMaxHeight", // 182
+ "DetailMaxWidth", // 183
+ "DetailRowHeight", // 184
+ "DetailSortOrder", // 185
+ "DetailWidth", // 186
+ "Dimension", // 187
+ "DisableDateRecognition", // 188
+ "DisableDrillDown", // 189
+ "DisableEdit", // 190
+ "DisableFieldDialog", // 191
+ "DisableRefresh", // 192
+ "DisableWizard", // 193
+ "DisplayDrawingObjects", // 194
+ "DisplayEmptyMembers", // 195
+ "DisplayErrorString", // 196
+ "DisplayFieldList", // 197
+ "DisplayFormulas", // 198
+ "DisplayIn", // 199
+ "DisplayInkNotes", // 200
+ "DisplayPageBreak", // 201
+ "DisplayRightToLeft", // 202
+ "DivID", // 203
+ "DoNotCalculateBeforeSave", // 204
+ "DoNotDisplayColHeaders", // 205
+ "DoNotDisplayGridlines", // 206
+ "DoNotDisplayHeadings", // 207
+ "DoNotDisplayOutline", // 208
+ "DoNotDisplayRowHeaders", // 209
+ "DoNotDisplayZeros", // 210
+ "DoNotJoinDelimiters", // 211
+ "DoNotPersist", // 212
+ "DoNotPersistSort", // 213
+ "DoNotPersstAF", // 214
+ "DoNotPromptForFile", // 215
+ "DoNotSaveLinkValues", // 216
+ "DocumentProperties", // 217
+ "DontShowInFieldList", // 218
+ "DownloadComponents", // 219
+ "DraftQuality", // 220
+ "DrawAspect", // 221
+ "DrilledLevel", // 222
+ "DrilledMember", // 223
+ "EditWebPage", // 224
+ "ElementType", // 225
+ "EmbedSaveSmartTags", // 226
+ "EnableMultiplePageItems", // 227
+ "EnableRedirections", // 228
+ "EnableSelection", // 229
+ "Encode", // 230
+ "EntirePage", // 231
+ "Entry", // 232
+ "Error", // 233
+ "ErrorHide", // 234
+ "ErrorMessage", // 235
+ "ErrorString", // 236
+ "ErrorStyle", // 237
+ "ErrorTitle", // 238
+ "ExcelName", // 239
+ "ExcelType", // 240
+ "ExcelWorkbook", // 241
+ "ExcelWorksheetType", // 242
+ "Expanded", // 243
+ "ExpandedColumnCount", // 244
+ "ExpandedRowCount", // 245
+ "ExternName", // 246
+ "ExtraLeftColumns", // 247
+ "ExtraRightColumns", // 248
+ "Face", // 249
+ "Family", // 250
+ "Field", // 251
+ "FieldLabelFormat", // 252
+ "FieldListBottom", // 253
+ "FieldListLeft", // 254
+ "FieldListRight", // 255
+ "FieldListTop", // 256
+ "FieldStart", // 257
+ "FieldType", // 258
+ "File", // 259
+ "FileName", // 260
+ "FillDown", // 261
+ "Filled", // 262
+ "FilterCaption", // 263
+ "FilterMember", // 264
+ "FilterOn", // 265
+ "FirstVisibleSheet", // 266
+ "FitHeight", // 267
+ "FitToPage", // 268
+ "FitWidth", // 269
+ "Font", // 270
+ "FontName", // 271
+ "Footer", // 272
+ "Format", // 273
+ "FormatSettings", // 274
+ "FormatType", // 275
+ "Formula", // 276
+ "FormulaIndex", // 277
+ "FormulaV10", // 278
+ "FreezePanes", // 279
+ "FrozenNoSplit", // 280
+ "FullColumns", // 281
+ "FullRows", // 282
+ "Function", // 283
+ "FunctionGroup", // 284
+ "FunctionGroupIndex", // 285
+ "FuturePersist", // 286
+ "FutureVer", // 287
+ "GrandTotalString", // 288
+ "GridlineColor", // 289
+ "GridlineColorIndex", // 290
+ "Gridlines", // 291
+ "GroupBy", // 292
+ "GroupDefinition", // 293
+ "GroupEnd", // 294
+ "GroupEndAuto", // 295
+ "GroupLevel", // 296
+ "GroupMember", // 297
+ "GroupNumber", // 298
+ "GroupStart", // 299
+ "GroupStartAuto", // 300
+ "GroupType", // 301
+ "GroupedWidth", // 302
+ "Guid", // 303
+ "HRef", // 304
+ "HRefScreenTip", // 305
+ "HTMLFormat", // 306
+ "HTMLTables", // 307
+ "HasNoAutoFormat", // 308
+ "HasNoRecords", // 309
+ "Header", // 310
+ "HeaderRange", // 311
+ "HeaderRow", // 312
+ "Height", // 313
+ "Hidden", // 314
+ "HideDetail", // 315
+ "HideDropDowns", // 316
+ "HideFormula", // 317
+ "HideHorizontalScrollBar", // 318
+ "HideInactiveListBorder", // 319
+ "HideOfficeLogo", // 320
+ "HidePivotTableFieldList", // 321
+ "HideTotalsAnnotation", // 322
+ "HideVerticalScrollBar", // 323
+ "HideWorkbookTabs", // 324
+ "Horizontal", // 325
+ "HorizontalResolution", // 326
+ "Href", // 327
+ "HtmlType", // 328
+ "HyperlinkBase", // 329
+ "I", // 330
+ "ID", // 331
+ "IMEMode", // 332
+ "Id", // 333
+ "IdWrapped", // 334
+ "If", // 335
+ "ImmediateItemsOnDrop", // 336
+ "Indent", // 337
+ "Index", // 338
+ "IndividualCellBorders", // 339
+ "InputHide", // 340
+ "InputMessage", // 341
+ "InputTitle", // 342
+ "InsertEntireRows", // 343
+ "InstanceShape", // 344
+ "Interior", // 345
+ "IntlMacro", // 346
+ "Invalid", // 347
+ "InvertedColumnMember", // 348
+ "InvertedRowMember", // 349
+ "IsGroupLevel", // 350
+ "IsMemberProperty", // 351
+ "IsNotFiltered", // 352
+ "Italic", // 353
+ "Item", // 354
+ "ItemType", // 355
+ "Iteration", // 356
+ "KeyboardShortcut", // 357
+ "Keywords", // 358
+ "Label", // 359
+ "LastAuthor", // 360
+ "LastPrinted", // 361
+ "LastSaved", // 362
+ "Layout", // 363
+ "LayoutForm", // 364
+ "LayoutPageBreak", // 365
+ "LayoutSubtotalLocation", // 366
+ "LeafColumnMember", // 367
+ "LeafRowMember", // 368
+ "Left", // 369
+ "LeftCell", // 370
+ "LeftColumnRightPane", // 371
+ "LeftColumnVisible", // 372
+ "LeftToRight", // 373
+ "LengthLevelUniqueName", // 374
+ "Level", // 375
+ "LineStyle", // 376
+ "Lines", // 377
+ "LoadMode", // 378
+ "LocalConnection", // 379
+ "Location", // 380
+ "LocationOfComponents", // 381
+ "Macro", // 382
+ "MainFile", // 383
+ "Maintain", // 384
+ "MajorVersion", // 385
+ "Manager", // 386
+ "Map", // 387
+ "MapChildItems", // 388
+ "MapID", // 389
+ "MapInfo", // 390
+ "Mapdata", // 391
+ "Margin", // 392
+ "Max", // 393
+ "MaxChange", // 394
+ "MaxHeight", // 395
+ "MaxIterations", // 396
+ "MaxWidth", // 397
+ "Measure", // 398
+ "Member", // 399
+ "MemberExpand", // 400
+ "MemberFormat", // 401
+ "MemberName", // 402
+ "MemberPropertiesOrder", // 403
+ "MemberProperty", // 404
+ "MemberPropertyParent", // 405
+ "MergeAcross", // 406
+ "MergeDown", // 407
+ "MergeLabels", // 408
+ "Min", // 409
+ "MinorVersion", // 410
+ "Missing", // 411
+ "MissingItemsLimit", // 412
+ "Moper", // 413
+ "MoveAfterReturn", // 414
+ "Name", // 415
+ "NamedCell", // 416
+ "NamedRange", // 417
+ "Names", // 418
+ "Namespace", // 419
+ "NewAsync", // 420
+ "NewItemsHidden", // 421
+ "NextId", // 422
+ "NextSheetNumber", // 423
+ "NoAutoFit", // 424
+ "NoAutoFormatWidth", // 425
+ "NoAutoPage", // 426
+ "NoAutoRecover", // 427
+ "NoAutofit", // 428
+ "NoColumnGrand", // 429
+ "NoDetailAutoFit", // 430
+ "NoDisplayNullString", // 431
+ "NoDragToColumn", // 432
+ "NoDragToData", // 433
+ "NoDragToHide", // 434
+ "NoDragToPage", // 435
+ "NoDragToRow", // 436
+ "NoInserts", // 437
+ "NoPreserveFormatting", // 438
+ "NoPrintRepeatItems", // 439
+ "NoPrinterInfo", // 440
+ "NoRefreshCache", // 441
+ "NoRowGrand", // 442
+ "NoSaveData", // 443
+ "NoSummaryColumnsRightDetail", // 444
+ "NoSummaryRowsBelowDetail", // 445
+ "NoTextToColumns", // 446
+ "NoTitles", // 447
+ "NoToggleDataHeader", // 448
+ "NoViewCalculatedMembers", // 449
+ "NonDefaultName", // 450
+ "NotInverted", // 451
+ "NotVisible", // 452
+ "NullString", // 453
+ "Number", // 454
+ "NumberFormat", // 455
+ "NumberOfCopies", // 456
+ "OLEObject", // 457
+ "OWCVersion", // 458
+ "ObjectID", // 459
+ "OfficeDocumentSettings", // 460
+ "OleLink", // 461
+ "Operator", // 462
+ "OptimizeCache", // 463
+ "Orientation", // 464
+ "Outline", // 465
+ "OverwriteCells", // 466
+ "PLCaption", // 467
+ "PLDataOrientation", // 468
+ "PLExport", // 469
+ "PLGroupType", // 470
+ "PLName", // 471
+ "PLPivotField", // 472
+ "PLPosition", // 473
+ "PLSubtotal", // 474
+ "PLTPivotItem", // 475
+ "PLTotal", // 476
+ "PTFormat", // 477
+ "PTFormula", // 478
+ "PTLineItem", // 479
+ "PTLineItems", // 480
+ "PTPivotData", // 481
+ "PTRule", // 482
+ "PTSource", // 483
+ "PageBreakZoom", // 484
+ "PageBreaks", // 485
+ "PageFieldOrder", // 486
+ "PageFieldStyle", // 487
+ "PageFieldWrapCount", // 488
+ "PageMargins", // 489
+ "PageSetup", // 490
+ "Pages", // 491
+ "Pane", // 492
+ "Panes", // 493
+ "PaperSizeIndex", // 494
+ "Paragraphs", // 495
+ "Parameter", // 496
+ "ParameterType", // 497
+ "ParameterValue", // 498
+ "Parent", // 499
+ "ParentField", // 500
+ "ParentIsOther", // 501
+ "ParentName", // 502
+ "ParentUniqueName", // 503
+ "ParseFormulaAsV10", // 504
+ "ParseRuleAsV10", // 505
+ "PasteFormula", // 506
+ "PasteRefersTo", // 507
+ "Path", // 508
+ "Pattern", // 509
+ "PatternColor", // 510
+ "PivotAxis", // 511
+ "PivotCache", // 512
+ "PivotField", // 513
+ "PivotItem", // 514
+ "PivotTable", // 515
+ "PivotView", // 516
+ "Position", // 517
+ "PrecisionAsDisplayed", // 518
+ "PresentationFormat", // 519
+ "Print", // 520
+ "PrintErrors", // 521
+ "PrintSetTitles", // 522
+ "ProgID", // 523
+ "PromptString", // 524
+ "ProtectContents", // 525
+ "ProtectObjects", // 526
+ "ProtectScenarios", // 527
+ "ProtectStructure", // 528
+ "ProtectWindows", // 529
+ "Protected", // 530
+ "Protection", // 531
+ "Proxy", // 532
+ "PublishObject", // 533
+ "PublishObjects", // 534
+ "Purpose", // 535
+ "QTSource", // 536
+ "Qualifier", // 537
+ "Query97", // 538
+ "QuerySource", // 539
+ "QueryTable", // 540
+ "QueryType", // 541
+ "Range", // 542
+ "RangeSelection", // 543
+ "ReadOnly", // 544
+ "ReadingOrder", // 545
+ "RefModeR1C1", // 546
+ "Reference", // 547
+ "RefersTo", // 548
+ "RefreshDate", // 549
+ "RefreshDateCopy", // 550
+ "RefreshInfo", // 551
+ "RefreshName", // 552
+ "RefreshOnChange", // 553
+ "RefreshOnFileOpen", // 554
+ "RefreshTimeSpan", // 555
+ "RefreshedInXl9", // 556
+ "Resource", // 557
+ "Revision", // 558
+ "Right", // 559
+ "RightToLeft", // 560
+ "RobustConnect", // 561
+ "RootElement", // 562
+ "Rotate", // 563
+ "Rotation", // 564
+ "Row", // 565
+ "RowBreak", // 566
+ "RowBreaks", // 567
+ "RowColHeadings", // 568
+ "RowInputCell", // 569
+ "RowLast", // 570
+ "RowNumbers", // 571
+ "Rule", // 572
+ "RuleType", // 573
+ "RuleV10", // 574
+ "S", // 575
+ "SOAPAction", // 576
+ "SQLType", // 577
+ "Scale", // 578
+ "Schema", // 579
+ "SchemaID", // 580
+ "SchemaRef", // 581
+ "Selected", // 582
+ "SelectedSheets", // 583
+ "Selection", // 584
+ "SelectionNamespaces", // 585
+ "SemiColon", // 586
+ "SeqNum", // 587
+ "Sequence", // 588
+ "ServerBased", // 589
+ "ServerSortOrder", // 590
+ "Set", // 591
+ "Shadow", // 592
+ "ShapeID", // 593
+ "SheetIndex", // 594
+ "SheetName", // 595
+ "ShowAllItems", // 596
+ "ShowAlways", // 597
+ "ShowCellBackgroundFromOLAP", // 598
+ "ShowImportExportValidationErrors", // 599
+ "ShowPageBreakZoom", // 600
+ "ShowPageMultipleItemLabel", // 601
+ "ShowTotals", // 602
+ "ShrinkToFit", // 603
+ "Size", // 604
+ "SmallGrid", // 605
+ "SmartTagType", // 606
+ "SmartTags", // 607
+ "SolveOrder", // 608
+ "Sort", // 609
+ "SortKey", // 610
+ "SortOrder", // 611
+ "Sorting", // 612
+ "Source", // 613
+ "SourceConnectionFile", // 614
+ "SourceConsolidation", // 615
+ "SourceDataFile", // 616
+ "SourceHierarchy", // 617
+ "SourceHierarchyLevel", // 618
+ "SourceName", // 619
+ "SourceType", // 620
+ "Space", // 621
+ "SpaceAbove", // 622
+ "SpaceBelow", // 623
+ "Span", // 624
+ "SplitHorizontal", // 625
+ "SplitVertical", // 626
+ "SpreadsheetAutoFit", // 627
+ "StandardWidth", // 628
+ "StartPageNumber", // 629
+ "StartRow", // 630
+ "StrikeThrough", // 631
+ "Style", // 632
+ "StyleID", // 633
+ "Styles", // 634
+ "Sub", // 635
+ "SubType", // 636
+ "Subject", // 637
+ "Subtotal", // 638
+ "SubtotalFormat", // 639
+ "SubtotalHiddenPageItems", // 640
+ "SubtotalName", // 641
+ "Sup", // 642
+ "SupBook", // 643
+ "Synchronous", // 644
+ "Tab", // 645
+ "TabColorIndex", // 646
+ "TabRatio", // 647
+ "Table", // 648
+ "TableStyle", // 649
+ "Tag", // 650
+ "Text", // 651
+ "TextQualifier", // 652
+ "TextWizardSettings", // 653
+ "ThousandSeparator", // 654
+ "Ticked", // 655
+ "Title", // 656
+ "Toolbar", // 657
+ "TooltipInfo", // 658
+ "Top", // 659
+ "TopCell", // 660
+ "TopRowBottomPane", // 661
+ "TopRowVisible", // 662
+ "TotalAlignment", // 663
+ "TotalAllMembers", // 664
+ "TotalCaptionAlignment", // 665
+ "TotalFormat", // 666
+ "TotalTime", // 667
+ "TotalWidth", // 668
+ "TransitionExpressionEvaluation", // 669
+ "TransitionFormulaEntry", // 670
+ "Type", // 671
+ "U", // 672
+ "URLString", // 673
+ "Uncalced", // 674
+ "Underline", // 675
+ "UniqueName", // 676
+ "Unsynced", // 677
+ "UseBlank", // 678
+ "UseLocalConnection", // 679
+ "UseSameSettings", // 680
+ "User", // 681
+ "VMLFrame", // 682
+ "VacatedStyle", // 683
+ "ValidPrinterInfo", // 684
+ "Value", // 685
+ "Value1", // 686
+ "Value2", // 687
+ "Version", // 688
+ "VersionLastEdit", // 689
+ "VersionLastRefresh", // 690
+ "VersionLastUpdate", // 691
+ "VersionRefreshableMin", // 692
+ "VersionUpdateableMin", // 693
+ "Vertical", // 694
+ "VerticalAlign", // 695
+ "VerticalResolution", // 696
+ "VerticalText", // 697
+ "ViewableRange", // 698
+ "Visible", // 699
+ "VisualTotals", // 700
+ "WantAdvise", // 701
+ "WantPict", // 702
+ "Watch", // 703
+ "Watches", // 704
+ "WebPostString", // 705
+ "Weight", // 706
+ "Width", // 707
+ "WindowHeight", // 708
+ "WindowHidden", // 709
+ "WindowIconic", // 710
+ "WindowTopX", // 711
+ "WindowTopY", // 712
+ "WindowWidth", // 713
+ "Windows", // 714
+ "Words", // 715
+ "Workbook", // 716
+ "WorkbookOptions", // 717
+ "Worksheet", // 718
+ "WorksheetOptions", // 719
+ "WorksheetSource", // 720
+ "WrapText", // 721
+ "XPath", // 722
+ "XSDType", // 723
+ "Xct", // 724
+ "ZeroHeight", // 725
+ "Zoom", // 726
+ "accentbar", // 727
+ "adj", // 728
+ "adjusthandles", // 729
+ "alignshape", // 730
+ "allowincell", // 731
+ "allowoverlap", // 732
+ "alt", // 733
+ "althref", // 734
+ "angle", // 735
+ "arc", // 736
+ "arcsize", // 737
+ "arrowok", // 738
+ "aspect", // 739
+ "aspectratio", // 740
+ "attribute", // 741
+ "autorotationcenter", // 742
+ "backdepth", // 743
+ "background", // 744
+ "bilevel", // 745
+ "blacklevel", // 746
+ "borderbottomcolor", // 747
+ "borderleftcolor", // 748
+ "borderrightcolor", // 749
+ "bordertopcolor", // 750
+ "brightness", // 751
+ "bullet", // 752
+ "button", // 753
+ "bwmode", // 754
+ "bwnormal", // 755
+ "bwpure", // 756
+ "callout", // 757
+ "caption", // 758
+ "chromakey", // 759
+ "class", // 760
+ "clip", // 761
+ "color", // 762
+ "color2", // 763
+ "colormenu", // 764
+ "colormode", // 765
+ "colormru", // 766
+ "colors", // 767
+ "complex", // 768
+ "connectangles", // 769
+ "connectloc", // 770
+ "connectlocs", // 771
+ "connectortype", // 772
+ "connecttype", // 773
+ "content", // 774
+ "control1", // 775
+ "control2", // 776
+ "coordorigin", // 777
+ "coordsize", // 778
+ "cropbottom", // 779
+ "cropleft", // 780
+ "cropping", // 781
+ "cropright", // 782
+ "croptop", // 783
+ "curve", // 784
+ "dashstyle", // 785
+ "data", // 786
+ "datatype", // 787
+ "detectmouseclick", // 788
+ "diffusity", // 789
+ "displaycustomheaders", // 790
+ "distance", // 791
+ "doubleclicknotify", // 792
+ "drop", // 793
+ "dropauto", // 794
+ "dt", // 795
+ "edge", // 796
+ "editas", // 797
+ "embosscolor", // 798
+ "end", // 799
+ "endAngle", // 800
+ "endarrow", // 801
+ "endarrowlength", // 802
+ "endarrowwidth", // 803
+ "endcap", // 804
+ "entry", // 805
+ "eqn", // 806
+ "ext", // 807
+ "extends", // 808
+ "extrusion", // 809
+ "extrusioncolor", // 810
+ "extrusionok", // 811
+ "f", // 812
+ "facet", // 813
+ "fill", // 814
+ "fillcolor", // 815
+ "filled", // 816
+ "fillok", // 817
+ "filltype", // 818
+ "fitpath", // 819
+ "fitshape", // 820
+ "focus", // 821
+ "focusposition", // 822
+ "focussize", // 823
+ "forcedash", // 824
+ "foredepth", // 825
+ "formulas", // 826
+ "from", // 827
+ "gain", // 828
+ "gamma", // 829
+ "gap", // 830
+ "gradientshapeok", // 831
+ "grayscale", // 832
+ "group", // 833
+ "grouping", // 834
+ "h", // 835
+ "handles", // 836
+ "hidden", // 837
+ "how", // 838
+ "hr", // 839
+ "hralign", // 840
+ "href", // 841
+ "hrheight", // 842
+ "hrnoshade", // 843
+ "hrpct", // 844
+ "hrstd", // 845
+ "hrwidth", // 846
+ "id", // 847
+ "idmap", // 848
+ "idref", // 849
+ "image", // 850
+ "imagealignshape", // 851
+ "imageaspect", // 852
+ "imagedata", // 853
+ "imagesize", // 854
+ "inset", // 855
+ "insetmode", // 856
+ "invx", // 857
+ "invy", // 858
+ "joinstyle", // 859
+ "length", // 860
+ "lengthspecified", // 861
+ "lightface", // 862
+ "lightharsh", // 863
+ "lightharsh2", // 864
+ "lightlevel", // 865
+ "lightlevel2", // 866
+ "lightposition", // 867
+ "lightposition2", // 868
+ "limo", // 869
+ "line", // 870
+ "linestyle", // 871
+ "lock", // 872
+ "lockrotationcenter", // 873
+ "map", // 874
+ "master", // 875
+ "matrix", // 876
+ "maxLength", // 877
+ "metal", // 878
+ "method", // 879
+ "minusx", // 880
+ "minusy", // 881
+ "miterlimit", // 882
+ "movie", // 883
+ "name", // 884
+ "namespaceuri", // 885
+ "new", // 886
+ "obscured", // 887
+ "offset", // 888
+ "offset2", // 889
+ "old", // 890
+ "ole", // 891
+ "oleicon", // 892
+ "oleid", // 893
+ "on", // 894
+ "oned", // 895
+ "onmouseover", // 896
+ "opacity", // 897
+ "opacity2", // 898
+ "orientation", // 899
+ "orientationangle", // 900
+ "origin", // 901
+ "oval", // 902
+ "password", // 903
+ "path", // 904
+ "phonetictext", // 905
+ "plane", // 906
+ "points", // 907
+ "polar", // 908
+ "polyline", // 909
+ "position", // 910
+ "preferrelative", // 911
+ "print", // 912
+ "proxy", // 913
+ "r", // 914
+ "radiusrange", // 915
+ "rect", // 916
+ "regroupid", // 917
+ "regrouptable", // 918
+ "relativeposition", // 919
+ "render", // 920
+ "rotation", // 921
+ "rotationangle", // 922
+ "rotationcenter", // 923
+ "roundrect", // 924
+ "row", // 925
+ "ruleinitiator", // 926
+ "ruleproxy", // 927
+ "rules", // 928
+ "selection", // 929
+ "shadow", // 930
+ "shadowcolor", // 931
+ "shadowok", // 932
+ "shape", // 933
+ "shapedefaults", // 934
+ "shapelayout", // 935
+ "shapetype", // 936
+ "shininess", // 937
+ "singleclick", // 938
+ "size", // 939
+ "skew", // 940
+ "skewamt", // 941
+ "skewangle", // 942
+ "specularity", // 943
+ "spid", // 944
+ "spidmax", // 945
+ "spt", // 946
+ "src", // 947
+ "start", // 948
+ "startAngle", // 949
+ "startarrow", // 950
+ "startarrowlength", // 951
+ "startarrowwidth", // 952
+ "string", // 953
+ "stroke", // 954
+ "strokecolor", // 955
+ "stroked", // 956
+ "strokeok", // 957
+ "strokeweight", // 958
+ "style", // 959
+ "switch", // 960
+ "tablelimits", // 961
+ "tableproperties", // 962
+ "target", // 963
+ "targetscreensize", // 964
+ "text", // 965
+ "textborder", // 966
+ "textbox", // 967
+ "textboxrect", // 968
+ "textpath", // 969
+ "textpathok", // 970
+ "title", // 971
+ "to", // 972
+ "trim", // 973
+ "type", // 974
+ "url", // 975
+ "useExplicit", // 976
+ "userId", // 977
+ "userdrawn", // 978
+ "userhidden", // 979
+ "v", // 980
+ "verticies", // 981
+ "viewpoint", // 982
+ "viewpointorigin", // 983
+ "visible", // 984
+ "weight", // 985
+ "worksheetoptions", // 986
+ "wrapcoords", // 987
+ "xrange", // 988
+ "xscale", // 989
+ "yrange" // 990
+};
+
+size_t token_name_count = 991;
diff --git a/src/liborcus/xlsx_autofilter_context.cpp b/src/liborcus/xlsx_autofilter_context.cpp
new file mode 100644
index 0000000..7a4d5ab
--- /dev/null
+++ b/src/liborcus/xlsx_autofilter_context.cpp
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_autofilter_context.hpp"
+#include "xml_context_global.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "ooxml_token_constants.hpp"
+
+#include "orcus/spreadsheet/import_interface.hpp"
+
+#include <iostream>
+
+using namespace std;
+
+namespace orcus {
+
+xlsx_autofilter_context::xlsx_autofilter_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_reference_resolver& resolver) :
+ xml_context_base(session_cxt, tokens),
+ m_resolver(resolver),
+ m_cur_col(-1) {}
+
+xlsx_autofilter_context::~xlsx_autofilter_context() {}
+
+xml_context_base* xlsx_autofilter_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xlsx_autofilter_context::end_child_context(
+ xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xlsx_autofilter_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+
+ if (ns != NS_ooxml_xlsx)
+ return;
+
+ switch (name)
+ {
+ case XML_autoFilter:
+ {
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ m_ref_range = for_each(
+ attrs.begin(), attrs.end(),
+ single_attr_getter(m_pool, NS_ooxml_xlsx, XML_ref)).get_value();
+ }
+ break;
+ case XML_filterColumn:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_autoFilter);
+ m_cur_col = for_each(
+ attrs.begin(), attrs.end(),
+ single_long_attr_getter(NS_ooxml_xlsx, XML_colId)).get_value();
+ }
+ break;
+ case XML_filters:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_filterColumn);
+ break;
+ case XML_filter:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_filters);
+ std::string_view val = for_each(
+ attrs.begin(), attrs.end(),
+ single_attr_getter(m_pool, NS_ooxml_xlsx, XML_val)).get_value();
+ if (!val.empty())
+ m_cur_match_values.push_back(val);
+ }
+ break;
+ default:
+ warn_unhandled();
+ }
+}
+
+bool xlsx_autofilter_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_filterColumn:
+ {
+ if (m_cur_col >= 0)
+ {
+ m_column_filters.insert(
+ column_filters_type::value_type(m_cur_col, m_cur_match_values));
+ }
+ m_cur_col = -1;
+ m_cur_match_values.clear();
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void xlsx_autofilter_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+void xlsx_autofilter_context::push_to_model(spreadsheet::iface::import_auto_filter& af) const
+{
+ spreadsheet::src_range_t range = m_resolver.resolve_range(m_ref_range);
+ af.set_range(to_rc_range(range));
+
+ for (const auto& v : m_column_filters)
+ {
+ spreadsheet::col_t col = v.first;
+ const match_values_type& match_values = v.second;
+
+ af.set_column(col);
+ for (std::string_view value : match_values)
+ af.append_column_match_value(value);
+ af.commit_column();
+ }
+ af.commit();
+}
+
+void xlsx_autofilter_context::reset()
+{
+ m_pool.clear();
+ m_ref_range = std::string_view{};
+ m_cur_col = -1;
+ m_cur_match_values.clear();
+ m_column_filters.clear();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_autofilter_context.hpp b/src/liborcus/xlsx_autofilter_context.hpp
new file mode 100644
index 0000000..27f5e7b
--- /dev/null
+++ b/src/liborcus/xlsx_autofilter_context.hpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLSX_AUTOFILTER_CONTEXT_HPP
+#define ORCUS_XLSX_AUTOFILTER_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "orcus/string_pool.hpp"
+#include "orcus/spreadsheet/types.hpp"
+
+#include <vector>
+#include <map>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_auto_filter;
+class import_reference_resolver;
+
+}}
+
+class xlsx_autofilter_context : public xml_context_base
+{
+public:
+ typedef std::vector<std::string_view> match_values_type;
+ typedef std::map<spreadsheet::col_t, match_values_type> column_filters_type;
+
+ xlsx_autofilter_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_reference_resolver& resolver);
+ virtual ~xlsx_autofilter_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+
+ void push_to_model(spreadsheet::iface::import_auto_filter& af) const;
+
+ void reset();
+
+private:
+ spreadsheet::iface::import_reference_resolver& m_resolver;
+
+ string_pool m_pool;
+
+ std::string_view m_ref_range;
+ spreadsheet::col_t m_cur_col;
+ match_values_type m_cur_match_values;
+ column_filters_type m_column_filters;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_conditional_format_context.cpp b/src/liborcus/xlsx_conditional_format_context.cpp
new file mode 100644
index 0000000..e667d83
--- /dev/null
+++ b/src/liborcus/xlsx_conditional_format_context.cpp
@@ -0,0 +1,878 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_conditional_format_context.hpp"
+#include "xlsx_helper.hpp"
+#include "xlsx_types.hpp"
+#include "ooxml_token_constants.hpp"
+#include "ooxml_namespace_types.hpp"
+
+#include "orcus/exception.hpp"
+#include "orcus/spreadsheet/import_interface.hpp"
+#include "orcus/measurement.hpp"
+
+#include <mdds/sorted_string_map.hpp>
+#include <mdds/global.hpp>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+enum xlsx_cond_format_type
+{
+ none = 0,
+ expression,
+ cellIs,
+ colorScale,
+ dataBar,
+ iconSet,
+ top10,
+ uniqueValues,
+ duplicateValues,
+ containsText,
+ notContainsText,
+ beginsWith,
+ endsWith,
+ containsBlanks,
+ notContainsBlanks,
+ containsErrors,
+ notContainsErrors,
+ timePeriod,
+ aboveAverage
+};
+
+enum xlsx_cond_format_operator
+{
+ operator_default = 0,
+ operator_beginsWith,
+ operator_between,
+ operator_containsText,
+ operator_endsWith,
+ operator_equal,
+ operator_greaterThan,
+ operator_greaterThanOrEqual,
+ operator_lessThan,
+ operator_lessThanOrEqual,
+ operator_notBetween,
+ operator_notContains,
+ operator_notEqual
+};
+
+enum xlsx_cond_format_date
+{
+ date_default = 0,
+ date_last7Days,
+ date_lastMonth,
+ date_lastWeek,
+ date_nextMonth,
+ date_thisMonth,
+ date_thisWeek,
+ date_today,
+ date_tomorrow,
+ date_yesterday
+};
+
+enum xlsx_cond_format_boolean
+{
+ boolean_default = 0,
+ boolean_true,
+ boolean_false
+};
+
+typedef mdds::sorted_string_map<xlsx_cond_format_type> cond_format_type_map;
+
+typedef mdds::sorted_string_map<xlsx_cond_format_boolean> cond_format_boolean_map;
+
+typedef mdds::sorted_string_map<xlsx_cond_format_operator> cond_format_operator_map;
+
+typedef mdds::sorted_string_map<xlsx_cond_format_date> cond_format_date_map;
+
+cond_format_type_map::entry cond_format_type_entries[] =
+{
+ { MDDS_ASCII("aboveAverage"), aboveAverage },
+ { MDDS_ASCII("beginsWith"), beginsWith },
+ { MDDS_ASCII("cellIs"), cellIs },
+ { MDDS_ASCII("colorScale"), colorScale },
+ { MDDS_ASCII("containsBlanks"), containsBlanks },
+ { MDDS_ASCII("containsErrors"), containsErrors },
+ { MDDS_ASCII("containsText"), containsText },
+ { MDDS_ASCII("dataBar"), dataBar },
+ { MDDS_ASCII("duplicateValues"), duplicateValues },
+ { MDDS_ASCII("endsWith"), endsWith },
+ { MDDS_ASCII("expression"), expression },
+ { MDDS_ASCII("iconSet"), iconSet },
+ { MDDS_ASCII("notContainsErrors"), notContainsErrors },
+ { MDDS_ASCII("notContainsText"), notContainsText },
+ { MDDS_ASCII("timePeriod"), timePeriod },
+ { MDDS_ASCII("top10"), top10 },
+ { MDDS_ASCII("uniqueValues"), uniqueValues }
+};
+
+cond_format_operator_map::entry cond_format_operator_entries[] =
+{
+ { MDDS_ASCII("beginsWith"), operator_beginsWith },
+ { MDDS_ASCII("between"), operator_between },
+ { MDDS_ASCII("containsText"), operator_containsText },
+ { MDDS_ASCII("endsWith"), operator_endsWith },
+ { MDDS_ASCII("equal"), operator_equal },
+ { MDDS_ASCII("greaterThan"), operator_greaterThan },
+ { MDDS_ASCII("greaterThanOrEqual"), operator_greaterThanOrEqual },
+ { MDDS_ASCII("lessThan"), operator_lessThan },
+ { MDDS_ASCII("lessThanOrEqual"), operator_lessThanOrEqual },
+ { MDDS_ASCII("notBetween"), operator_notBetween },
+ { MDDS_ASCII("notContains"), operator_notContains },
+ { MDDS_ASCII("notEqual"), operator_notEqual }
+};
+
+cond_format_date_map::entry cond_format_date_entries[] =
+{
+ { MDDS_ASCII("last7Days"), date_last7Days },
+ { MDDS_ASCII("lastMonth"), date_lastMonth },
+ { MDDS_ASCII("lastWeek"), date_lastWeek },
+ { MDDS_ASCII("nextMonth"), date_nextMonth },
+ { MDDS_ASCII("thisMonth"), date_thisMonth },
+ { MDDS_ASCII("thisWeek"), date_thisWeek },
+ { MDDS_ASCII("today"), date_today },
+ { MDDS_ASCII("tomorrow"), date_tomorrow },
+ { MDDS_ASCII("yesterday"), date_yesterday }
+};
+
+cond_format_boolean_map::entry cond_format_boolean_entries[] =
+{
+ { MDDS_ASCII("0"), boolean_false },
+ { MDDS_ASCII("1"), boolean_true },
+ { MDDS_ASCII("false"), boolean_true },
+ { MDDS_ASCII("true"), boolean_false }
+};
+
+bool parse_boolean_flag(const xml_token_attr_t& attr, bool default_value)
+{
+ static const cond_format_boolean_map boolean_map(cond_format_boolean_entries, sizeof(cond_format_boolean_entries)/sizeof(cond_format_boolean_entries[0]), boolean_default);
+ xlsx_cond_format_boolean val = boolean_map.find(attr.value.data(), attr.value.size());
+ switch (val)
+ {
+ case boolean_default:
+ return default_value;
+ case boolean_true:
+ return true;
+ case boolean_false:
+ return false;
+ }
+
+ return default_value;
+}
+
+struct cfRule_attr_parser
+{
+
+ cfRule_attr_parser(ss::iface::import_conditional_format& cond_format):
+ m_cond_format(cond_format),
+ m_type(none),
+ m_operator(operator_default),
+ m_date(date_default),
+ m_above_average(true),
+ m_equal_average(false),
+ m_percent(false),
+ m_bottom(false)
+ {
+ }
+
+ void operator()(const xml_token_attr_t& attr)
+ {
+ switch(attr.name)
+ {
+ case XML_type:
+ {
+ cond_format_type_map type_map(cond_format_type_entries, sizeof(cond_format_type_entries)/sizeof(cond_format_type_entries[0]), none);
+ m_type = type_map.find(attr.value.data(), attr.value.size());
+ }
+ break;
+ case XML_dxfId:
+ {
+ // TODO: actually we need to translate between dxf id and xf id
+ size_t dxf_id = to_long(attr.value);
+ m_cond_format.set_xf_id(dxf_id);
+ }
+ break;
+ case XML_aboveAverage:
+ {
+ m_above_average = parse_boolean_flag(attr, true);
+ }
+ break;
+ case XML_percent:
+ m_percent = parse_boolean_flag(attr, false);
+ break;
+ case XML_bottom:
+ m_bottom = parse_boolean_flag(attr, false);
+ break;
+ case XML_operator:
+ {
+ cond_format_operator_map operator_map(cond_format_operator_entries, sizeof(cond_format_operator_entries)/sizeof(cond_format_operator_entries[0]), operator_default);
+ m_operator = operator_map.find(attr.value.data(), attr.value.size());
+ }
+ break;
+ case XML_text:
+ // do we need to worry about the transient flag here?
+ m_text = attr.value;
+ break;
+ case XML_timePeriod:
+ {
+ cond_format_date_map date_map(cond_format_date_entries, sizeof(cond_format_date_entries)/sizeof(cond_format_date_entries[0]), date_default);
+ m_date = date_map.find(attr.value.data(), attr.value.size());
+ }
+ break;
+ case XML_rank:
+ // do we need to worry about the transient flag here?
+ m_rank = attr.value;
+ break;
+ case XML_stdDev:
+ // do we need to worry about the transient flag here?
+ m_std_dev = attr.value;
+ break;
+ case XML_equalAverage:
+ m_equal_average = parse_boolean_flag(attr, false);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void set_type()
+ {
+ switch (m_type)
+ {
+ case expression:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::expression);
+ break;
+ case cellIs:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::expression);
+ switch (m_operator)
+ {
+ case operator_beginsWith:
+ m_cond_format.set_operator(ss::condition_operator_t::begins_with);
+ break;
+ case operator_between:
+ m_cond_format.set_operator(ss::condition_operator_t::between);
+ break;
+ case operator_containsText:
+ m_cond_format.set_operator(ss::condition_operator_t::contains);
+ break;
+ case operator_endsWith:
+ m_cond_format.set_operator(ss::condition_operator_t::ends_with);
+ break;
+ case operator_equal:
+ m_cond_format.set_operator(ss::condition_operator_t::equal);
+ break;
+ case operator_greaterThan:
+ m_cond_format.set_operator(ss::condition_operator_t::greater);
+ break;
+ case operator_greaterThanOrEqual:
+ m_cond_format.set_operator(ss::condition_operator_t::greater_equal);
+ break;
+ case operator_lessThan:
+ m_cond_format.set_operator(ss::condition_operator_t::less);
+ break;
+ case operator_lessThanOrEqual:
+ m_cond_format.set_operator(ss::condition_operator_t::less_equal);
+ break;
+ case operator_notBetween:
+ m_cond_format.set_operator(ss::condition_operator_t::not_between);
+ break;
+ case operator_notContains:
+ m_cond_format.set_operator(ss::condition_operator_t::not_contains);
+ break;
+ case operator_notEqual:
+ m_cond_format.set_operator(ss::condition_operator_t::not_equal);
+ break;
+ default:
+ break;
+ }
+ break;
+ case colorScale:
+ m_cond_format.set_type(ss::conditional_format_t::colorscale);
+ break;
+ case dataBar:
+ m_cond_format.set_type(ss::conditional_format_t::databar);
+ break;
+ case iconSet:
+ m_cond_format.set_type(ss::conditional_format_t::iconset);
+ break;
+ case top10:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ if (m_bottom)
+ {
+ m_cond_format.set_operator(ss::condition_operator_t::bottom_n);
+ }
+ else
+ {
+ m_cond_format.set_operator(ss::condition_operator_t::top_n);
+ }
+ m_cond_format.set_formula(m_rank);
+ break;
+ case uniqueValues:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::unique);
+ break;
+ case duplicateValues:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::duplicate);
+ break;
+ case containsText:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::contains);
+ m_cond_format.set_formula(m_text);
+ break;
+ case notContainsText:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::not_contains);
+ m_cond_format.set_formula(m_text);
+ break;
+ case beginsWith:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::begins_with);
+ m_cond_format.set_formula(m_text);
+ break;
+ case endsWith:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::ends_with);
+ m_cond_format.set_formula(m_text);
+ break;
+ case containsBlanks:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::contains_blanks);
+ break;
+ case containsErrors:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::contains_error);
+ break;
+ case notContainsErrors:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ m_cond_format.set_operator(ss::condition_operator_t::contains_no_error);
+ break;
+ case timePeriod:
+ m_cond_format.set_type(ss::conditional_format_t::date);
+ switch (m_date)
+ {
+ case date_last7Days:
+ m_cond_format.set_date(ss::condition_date_t::last_7_days);
+ break;
+ case date_lastMonth:
+ m_cond_format.set_date(ss::condition_date_t::last_month);
+ break;
+ case date_lastWeek:
+ m_cond_format.set_date(ss::condition_date_t::last_week);
+ break;
+ case date_nextMonth:
+ m_cond_format.set_date(ss::condition_date_t::next_month);
+ break;
+ case date_thisMonth:
+ m_cond_format.set_date(ss::condition_date_t::this_month);
+ break;
+ case date_thisWeek:
+ m_cond_format.set_date(ss::condition_date_t::this_week);
+ break;
+ case date_today:
+ m_cond_format.set_date(ss::condition_date_t::today);
+ break;
+ case date_tomorrow:
+ m_cond_format.set_date(ss::condition_date_t::tomorrow);
+ break;
+ case date_yesterday:
+ m_cond_format.set_date(ss::condition_date_t::yesterday);
+ break;
+ default:
+ break;
+ }
+ break;
+ case aboveAverage:
+ m_cond_format.set_type(ss::conditional_format_t::condition);
+ if (!m_std_dev.empty())
+ {
+ // TODO: we need a way to mark that as std dev in the interfaces
+ m_cond_format.set_formula(m_std_dev);
+ }
+ if (m_above_average)
+ {
+ if (m_equal_average)
+ {
+ m_cond_format.set_operator(ss::condition_operator_t::above_equal_average);
+ }
+ else
+ {
+ m_cond_format.set_operator(ss::condition_operator_t::above_average);
+ }
+ }
+ else
+ {
+ if (m_equal_average)
+ {
+ m_cond_format.set_operator(ss::condition_operator_t::below_equal_average);
+ }
+ else
+ {
+ m_cond_format.set_operator(ss::condition_operator_t::below_average);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+private:
+ ss::iface::import_conditional_format& m_cond_format;
+ xlsx_cond_format_type m_type;
+ xlsx_cond_format_operator m_operator;
+ xlsx_cond_format_date m_date;
+ bool m_above_average;
+ bool m_equal_average;
+ bool m_percent;
+ bool m_bottom;
+ std::string_view m_text;
+ std::string_view m_std_dev;
+ std::string_view m_rank;
+};
+
+struct conditional_formatting_attr_parser
+{
+ conditional_formatting_attr_parser(ss::iface::import_conditional_format* cond_format):
+ m_cond_format(cond_format)
+ {
+ }
+
+ void operator()(const xml_token_attr_t& attr)
+ {
+ switch (attr.name)
+ {
+ case XML_sqref:
+ m_cond_format->set_range(attr.value);
+ break;
+ }
+ }
+
+private:
+ ss::iface::import_conditional_format* m_cond_format;
+};
+
+enum xlsx_cond_format_cfvo_type
+{
+ cfvo_default = 0,
+ cfvo_num,
+ cfvo_percent,
+ cfvo_max,
+ cfvo_min,
+ cfvo_formula,
+ cfvo_percentile
+};
+
+typedef mdds::sorted_string_map<xlsx_cond_format_cfvo_type> cond_format_cfvo_type_map;
+
+cond_format_cfvo_type_map::entry cond_format_cfvo_entries[] =
+{
+ { MDDS_ASCII("num"), cfvo_num },
+ { MDDS_ASCII("percent"), cfvo_percent },
+ { MDDS_ASCII("max"), cfvo_max },
+ { MDDS_ASCII("min"), cfvo_min },
+ { MDDS_ASCII("formula"), cfvo_formula },
+ { MDDS_ASCII("percentile"), cfvo_percentile },
+};
+
+}
+
+struct cfvo_values
+{
+ cfvo_values():
+ m_include_equal(true),
+ m_type(cfvo_default)
+ {
+ }
+
+ bool m_include_equal;
+ xlsx_cond_format_cfvo_type m_type;
+ std::string_view m_value;
+};
+
+namespace {
+
+struct cfvo_attr_parser
+{
+ cfvo_attr_parser(string_pool& pool):
+ m_string_pool(pool)
+ {
+ }
+
+ void operator()(const xml_token_attr_t& attr)
+ {
+ switch (attr.name)
+ {
+ case XML_gte:
+ m_values.m_include_equal = parse_boolean_flag(attr, true);
+ break;
+ case XML_type:
+ {
+ cond_format_cfvo_type_map cfvo_type_map(cond_format_cfvo_entries, sizeof(cond_format_cfvo_entries)/sizeof(cond_format_cfvo_entries[0]), cfvo_default);
+ m_values.m_type = cfvo_type_map.find(attr.value.data(), attr.value.size());
+ }
+ break;
+ case XML_val:
+ if (attr.transient)
+ {
+ m_values.m_value = m_string_pool.intern(attr.value).first;
+ }
+ else
+ {
+ m_values.m_value = attr.value;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ cfvo_values get_values()
+ {
+ return m_values;
+ }
+
+private:
+ cfvo_values m_values;
+ string_pool& m_string_pool;
+};
+
+struct data_bar_attr_parser
+{
+ data_bar_attr_parser():
+ m_show_value(true),
+ m_min_length(10),
+ m_max_length(90)
+ {
+ }
+
+ void operator()(const xml_token_attr_t& attr)
+ {
+ switch (attr.name)
+ {
+ case XML_showValue:
+ m_show_value = parse_boolean_flag(attr, true);
+ break;
+ case XML_maxLength:
+ m_max_length = to_long(attr.value);
+ break;
+ case XML_minLength:
+ m_min_length = to_long(attr.value);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void import_data(ss::iface::import_conditional_format& cond_format)
+ {
+ cond_format.set_show_value(m_show_value);
+ cond_format.set_min_databar_length(m_min_length);
+ cond_format.set_max_databar_length(m_max_length);
+ }
+
+private:
+ bool m_show_value;
+ size_t m_min_length;
+ size_t m_max_length;
+};
+
+struct icon_set_attr_parser
+{
+ icon_set_attr_parser():
+ m_reverse(false),
+ m_percent(true),
+ m_show_value(true),
+ icon_name("3Arrows")
+ {
+ }
+
+ void operator()(const xml_token_attr_t& attr)
+ {
+ switch (attr.name)
+ {
+ case XML_iconSet:
+ icon_name = attr.value;
+ break;
+ case XML_percent:
+ m_percent = parse_boolean_flag(attr, true);
+ break;
+ case XML_reverse:
+ m_reverse = parse_boolean_flag(attr, false);
+ break;
+ case XML_showValue:
+ m_show_value = parse_boolean_flag(attr, true);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void import_data(ss::iface::import_conditional_format& cond_format)
+ {
+ cond_format.set_show_value(m_show_value);
+ cond_format.set_iconset_reverse(m_reverse);
+ cond_format.set_icon_name(icon_name);
+ }
+
+private:
+ bool m_reverse;
+ bool m_percent;
+ bool m_show_value;
+ std::string_view icon_name;
+};
+
+}
+
+xlsx_conditional_format_context::xlsx_conditional_format_context(
+ session_context& session_cxt, const tokens& tokens,
+ ss::iface::import_conditional_format* import_cond_format):
+ xml_context_base(session_cxt, tokens),
+ m_cond_format(import_cond_format)
+{
+}
+
+xlsx_conditional_format_context::~xlsx_conditional_format_context()
+{
+}
+
+xml_context_base* xlsx_conditional_format_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xlsx_conditional_format_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xlsx_conditional_format_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+
+ switch (name)
+ {
+ case XML_conditionalFormatting:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_worksheet);
+ if (m_cond_format)
+ std::for_each(attrs.begin(), attrs.end(), conditional_formatting_attr_parser(m_cond_format));
+ break;
+ }
+ case XML_cfRule:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_conditionalFormatting);
+ if (m_cond_format)
+ {
+ cfRule_attr_parser parser = std::for_each(attrs.begin(), attrs.end(), cfRule_attr_parser(*m_cond_format));
+ parser.set_type();
+ }
+ break;
+ }
+ case XML_cfvo:
+ {
+ cfvo_attr_parser parser = std::for_each(attrs.begin(), attrs.end(), cfvo_attr_parser(m_pool));
+ m_cfvo_values.push_back(parser.get_values());
+ break;
+ }
+ case XML_dataBar:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_cfRule);
+ data_bar_attr_parser parser = std::for_each(attrs.begin(), attrs.end(), data_bar_attr_parser());
+ if (m_cond_format)
+ parser.import_data(*m_cond_format);
+ break;
+ }
+ case XML_iconSet:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_cfRule);
+ icon_set_attr_parser parser = std::for_each(attrs.begin(), attrs.end(), icon_set_attr_parser());
+ if (m_cond_format)
+ parser.import_data(*m_cond_format);
+ break;
+ }
+ case XML_color:
+ {
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_rgb:
+ {
+ argb_color color;
+ if (to_rgb(attr.value, color.alpha, color.red, color.green, color.blue))
+ m_colors.push_back(color);
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ break;
+ }
+ case XML_formula:
+ break;
+ case XML_colorScale:
+ break;
+ default:
+ warn_unhandled();
+ }
+}
+
+namespace {
+
+void import_cfvo(const cfvo_values& values, ss::iface::import_conditional_format& cond_format)
+{
+ if (!values.m_value.empty())
+ cond_format.set_formula(values.m_value);
+
+ switch (values.m_type)
+ {
+ case cfvo_num:
+ cond_format.set_condition_type(ss::condition_type_t::value);
+ break;
+ case cfvo_percent:
+ cond_format.set_condition_type(ss::condition_type_t::percent);
+ break;
+ case cfvo_max:
+ cond_format.set_condition_type(ss::condition_type_t::max);
+ break;
+ case cfvo_min:
+ cond_format.set_condition_type(ss::condition_type_t::min);
+ break;
+ case cfvo_formula:
+ cond_format.set_condition_type(ss::condition_type_t::formula);
+ break;
+ case cfvo_percentile:
+ cond_format.set_condition_type(ss::condition_type_t::percentile);
+ break;
+ default:;
+ }
+}
+
+}
+
+bool xlsx_conditional_format_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ switch (name)
+ {
+ case XML_conditionalFormatting:
+ {
+ if (m_cond_format)
+ m_cond_format->commit_format();
+ break;
+ }
+ case XML_cfRule:
+ {
+ if (m_cond_format)
+ m_cond_format->commit_entry();
+ m_cfvo_values.clear();
+ m_colors.clear();
+ break;
+ }
+ case XML_cfvo:
+ break;
+ case XML_color:
+ break;
+ case XML_formula:
+ {
+ if (m_cond_format)
+ {
+ m_cond_format->set_formula(m_cur_str);
+ m_cond_format->commit_condition();
+ }
+ break;
+ }
+ case XML_dataBar:
+ {
+ if (m_colors.size() != 1)
+ throw general_error("invalid dataBar record");
+
+ if (m_cfvo_values.size() != 2)
+ throw general_error("invalid dataBar record");
+
+ if (m_cond_format)
+ {
+ argb_color& color = m_colors[0];
+ m_cond_format->set_databar_color_positive(color.alpha, color.red,
+ color.green, color.blue);
+ m_cond_format->set_databar_color_negative(color.alpha, color.red,
+ color.green, color.blue);
+
+ for (const auto& cfvo : m_cfvo_values)
+ {
+ import_cfvo(cfvo, *m_cond_format);
+ m_cond_format->commit_condition();
+ }
+ }
+ break;
+ }
+ case XML_iconSet:
+ {
+ if (m_cfvo_values.size() < 2)
+ throw general_error("invalid iconSet record");
+
+ if (m_cond_format)
+ {
+ for (const auto& cfvo : m_cfvo_values)
+ {
+ import_cfvo(cfvo, *m_cond_format);
+ m_cond_format->commit_condition();
+ }
+ }
+ break;
+ }
+ case XML_colorScale:
+ {
+ if (m_cfvo_values.size() < 2)
+ throw general_error("invalid colorScale record");
+
+ if (m_cfvo_values.size() != m_colors.size())
+ throw general_error("invalid colorScale record");
+
+ if (m_cond_format)
+ {
+ std::vector<argb_color>::const_iterator itrColor = m_colors.begin();
+ for (std::vector<cfvo_values>::const_iterator itr = m_cfvo_values.begin(); itr != m_cfvo_values.end(); ++itr, ++itrColor)
+ {
+ import_cfvo(*itr, *m_cond_format);
+ m_cond_format->set_color(itrColor->alpha, itrColor->red,
+ itrColor->green, itrColor->blue);
+ m_cond_format->commit_condition();
+ }
+ }
+ break;
+ }
+ }
+
+ m_cur_str = std::string_view{};
+ return pop_stack(ns, name);
+}
+
+void xlsx_conditional_format_context::characters(std::string_view str, bool transient)
+{
+ m_cur_str = str;
+ if (transient)
+ m_cur_str = m_pool.intern(m_cur_str).first;
+}
+
+void xlsx_conditional_format_context::reset()
+{
+ m_pool.clear();
+ m_cur_str = std::string_view{};
+ m_cfvo_values.clear();
+ m_colors.clear();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_conditional_format_context.hpp b/src/liborcus/xlsx_conditional_format_context.hpp
new file mode 100644
index 0000000..f03d53d
--- /dev/null
+++ b/src/liborcus/xlsx_conditional_format_context.hpp
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLSX_CONDITIONAL_FORMAT_CONTEXT_HPP
+#define ORCUS_XLSX_CONDITIONAL_FORMAT_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "ooxml_types.hpp"
+#include "xlsx_types.hpp"
+
+#include "orcus/spreadsheet/types.hpp"
+#include "orcus/string_pool.hpp"
+
+namespace orcus {
+
+struct session_context;
+
+namespace spreadsheet { namespace iface {
+ class import_conditional_format;
+} }
+
+struct cfvo_values;
+
+struct argb_color
+{
+ spreadsheet::color_elem_t alpha;
+ spreadsheet::color_elem_t red;
+ spreadsheet::color_elem_t green;
+ spreadsheet::color_elem_t blue;
+};
+
+class xlsx_conditional_format_context : public xml_context_base
+{
+public:
+
+ xlsx_conditional_format_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_conditional_format* import_cond_format);
+ virtual ~xlsx_conditional_format_context() override;
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name) override;
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child) override;
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs) override;
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+ virtual void characters(std::string_view str, bool transient) override;
+
+ void reset();
+
+private:
+ spreadsheet::iface::import_conditional_format* m_cond_format;
+
+ string_pool m_pool;
+ std::string_view m_cur_str;
+
+ std::vector<cfvo_values> m_cfvo_values;
+ std::vector<argb_color> m_colors;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_drawing_context.cpp b/src/liborcus/xlsx_drawing_context.cpp
new file mode 100644
index 0000000..606cd62
--- /dev/null
+++ b/src/liborcus/xlsx_drawing_context.cpp
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_drawing_context.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "ooxml_token_constants.hpp"
+#include "ooxml_global.hpp"
+
+#include "orcus/measurement.hpp"
+
+#include <iostream>
+
+using namespace std;
+
+namespace orcus {
+
+xlsx_drawing_context::xlsx_drawing_context(session_context& cxt, const tokens& tkns) :
+ xml_context_base(cxt, tkns),
+ m_col(-1), m_row(-1), m_col_offset(-1), m_row_offset(-1)
+{
+ init_ooxml_context(*this);
+}
+
+xlsx_drawing_context::~xlsx_drawing_context() {}
+
+xml_context_base* xlsx_drawing_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xlsx_drawing_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xlsx_drawing_context::start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& /*attrs*/)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+
+ if (ns == NS_ooxml_xdr)
+ {
+ switch (name)
+ {
+ case XML_oneCellAnchor:
+ case XML_twoCellAnchor:
+ {
+ xml_element_expected(parent, NS_ooxml_xdr, XML_wsDr);
+ reset();
+ break;
+ }
+ case XML_from:
+ case XML_sp:
+ case XML_clientData:
+ {
+ const xml_elem_set_t expected = {
+ { NS_ooxml_xdr, XML_absoluteAnchor },
+ { NS_ooxml_xdr, XML_grpSp },
+ { NS_ooxml_xdr, XML_oneCellAnchor },
+ { NS_ooxml_xdr, XML_twoCellAnchor },
+ };
+ xml_element_expected(parent, expected);
+ break;
+ }
+ case XML_to:
+ {
+ xml_element_expected(parent, NS_ooxml_xdr, XML_twoCellAnchor);
+ break;
+ }
+ case XML_col:
+ case XML_colOff:
+ case XML_row:
+ case XML_rowOff:
+ {
+ xml_elem_stack_t expected;
+ expected.emplace_back(NS_ooxml_xdr, XML_from);
+ expected.emplace_back(NS_ooxml_xdr, XML_to);
+ xml_element_expected(parent, expected);
+ break;
+ }
+ case XML_nvSpPr:
+ case XML_style:
+ case XML_txBody:
+ {
+ const xml_elem_stack_t expected = {
+ { NS_ooxml_xdr, XML_cxnSp },
+ { NS_ooxml_xdr, XML_sp },
+ };
+ xml_element_expected(parent, expected);
+ break;
+ }
+ case XML_spPr:
+ {
+ const xml_elem_stack_t expected = {
+ { NS_ooxml_xdr, XML_cxnSp },
+ { NS_ooxml_xdr, XML_sp },
+ { NS_ooxml_xdr, XML_pic },
+ };
+ xml_element_expected(parent, expected);
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+ }
+ else if (ns == NS_ooxml_a)
+ {
+ warn_unhandled();
+ }
+ else
+ warn_unhandled();
+}
+
+bool xlsx_drawing_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xdr)
+ {
+ switch (name)
+ {
+ case XML_twoCellAnchor:
+ case XML_oneCellAnchor:
+ if (get_config().debug)
+ cout << "col: " << m_col << "; row: " << m_row << "; col offset: " << m_col_offset << "; row offset: " << m_row_offset << endl;
+ break;
+ default:
+ ;
+ }
+ }
+ else if (ns == NS_ooxml_a)
+ {
+
+ }
+ return pop_stack(ns, name);
+}
+
+void xlsx_drawing_context::characters(std::string_view str, bool /*transient*/)
+{
+ xml_token_pair_t elem = get_current_element();
+ if (elem.first == NS_ooxml_xdr)
+ {
+ switch (elem.second)
+ {
+ case XML_col:
+ m_col = to_long(str);
+ break;
+ case XML_row:
+ m_row = to_long(str);
+ break;
+ case XML_colOff:
+ m_col_offset = to_long(str);
+ break;
+ case XML_rowOff:
+ m_row_offset = to_long(str);
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+void xlsx_drawing_context::reset()
+{
+ m_col = -1;
+ m_row = -1;
+ m_col_offset = -1;
+ m_row_offset = -1;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_drawing_context.hpp b/src/liborcus/xlsx_drawing_context.hpp
new file mode 100644
index 0000000..5089326
--- /dev/null
+++ b/src/liborcus/xlsx_drawing_context.hpp
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_XLSX_DRAWING_CONTEXT_HPP
+#define INCLUDED_ORCUS_XLSX_DRAWING_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+
+namespace orcus {
+
+struct session_context;
+class tokens;
+
+class xlsx_drawing_context : public xml_context_base
+{
+ long m_col;
+ long m_row;
+ long m_col_offset;
+ long m_row_offset;
+
+public:
+ xlsx_drawing_context(session_context& cxt, const tokens& tkns);
+
+ virtual ~xlsx_drawing_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs);
+
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+
+ virtual void characters(std::string_view str, bool transient);
+
+private:
+ void reset();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_handler.cpp b/src/liborcus/xlsx_handler.cpp
new file mode 100644
index 0000000..e013bde
--- /dev/null
+++ b/src/liborcus/xlsx_handler.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_handler.hpp"
+#include "xlsx_sheet_context.hpp"
+#include "xlsx_table_context.hpp"
+#include "xlsx_pivot_context.hpp"
+#include "xlsx_drawing_context.hpp"
+
+#include <iostream>
+
+using namespace std;
+
+namespace orcus {
+
+xlsx_sheet_xml_handler::xlsx_sheet_xml_handler(
+ session_context& session_cxt, const tokens& t,
+ spreadsheet::sheet_t sheet_id,
+ spreadsheet::iface::import_reference_resolver& resolver,
+ spreadsheet::iface::import_sheet& sheet) :
+ xml_stream_handler(session_cxt, t, std::make_unique<xlsx_sheet_context>(session_cxt, t, sheet_id, resolver, sheet))
+{
+}
+
+xlsx_sheet_xml_handler::~xlsx_sheet_xml_handler()
+{
+}
+
+void xlsx_sheet_xml_handler::pop_rel_extras(opc_rel_extras_t& other)
+{
+ xlsx_sheet_context& cxt = static_cast<xlsx_sheet_context&>(get_root_context());
+ cxt.pop_rel_extras(other);
+}
+
+xlsx_table_xml_handler::xlsx_table_xml_handler(
+ session_context& session_cxt, const tokens& t,
+ spreadsheet::iface::import_table& table,
+ spreadsheet::iface::import_reference_resolver& resolver) :
+ xml_stream_handler(session_cxt, t, std::make_unique<xlsx_table_context>(session_cxt, t, table, resolver))
+{
+}
+
+xlsx_pivot_cache_def_xml_handler::xlsx_pivot_cache_def_xml_handler(
+ session_context& cxt, const tokens& t,
+ spreadsheet::iface::import_pivot_cache_definition& pcache,
+ spreadsheet::pivot_cache_id_t pcache_id) :
+ xml_stream_handler(cxt, t, std::make_unique<xlsx_pivot_cache_def_context>(cxt, t, pcache, pcache_id)) {}
+
+opc_rel_extras_t xlsx_pivot_cache_def_xml_handler::pop_rel_extras()
+{
+ xlsx_pivot_cache_def_context& cxt =
+ static_cast<xlsx_pivot_cache_def_context&>(get_root_context());
+
+ return cxt.pop_rel_extras();
+}
+
+xlsx_pivot_cache_rec_xml_handler::xlsx_pivot_cache_rec_xml_handler(
+ session_context& cxt, const tokens& t,
+ spreadsheet::iface::import_pivot_cache_records& pc_records) :
+ xml_stream_handler(cxt, t, std::make_unique<xlsx_pivot_cache_rec_context>(cxt, t, pc_records)) {}
+
+xlsx_pivot_table_xml_handler::xlsx_pivot_table_xml_handler(
+ session_context& cxt, const tokens& t) :
+ xml_stream_handler(cxt, t, std::make_unique<xlsx_pivot_table_context>(cxt, t)) {}
+
+xlsx_drawing_xml_handler::xlsx_drawing_xml_handler(
+ session_context& cxt, const tokens& t) :
+ xml_stream_handler(cxt, t, std::make_unique<xlsx_drawing_context>(cxt, t)) {}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_handler.hpp b/src/liborcus/xlsx_handler.hpp
new file mode 100644
index 0000000..81676c5
--- /dev/null
+++ b/src/liborcus/xlsx_handler.hpp
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_XLSX_HANDLER_HPP
+#define INCLUDED_ORCUS_XLSX_HANDLER_HPP
+
+#include "xml_stream_handler.hpp"
+#include "xml_context_base.hpp"
+
+#include "orcus/spreadsheet/types.hpp"
+
+#include <string>
+#include <vector>
+
+namespace orcus {
+
+struct session_context;
+struct opc_rel_extras_t;
+
+namespace spreadsheet { namespace iface {
+
+class import_sheet;
+class import_table;
+class import_reference_resolver;
+class import_pivot_cache_definition;
+class import_pivot_cache_records;
+
+}}
+
+class xlsx_sheet_xml_handler : public xml_stream_handler
+{
+public:
+ xlsx_sheet_xml_handler(
+ session_context& cxt, const tokens& t,
+ spreadsheet::sheet_t sheet_id,
+ spreadsheet::iface::import_reference_resolver& resolver,
+ spreadsheet::iface::import_sheet& sheet);
+
+ virtual ~xlsx_sheet_xml_handler();
+
+ void pop_rel_extras(opc_rel_extras_t& other);
+};
+
+class xlsx_table_xml_handler : public xml_stream_handler
+{
+public:
+ xlsx_table_xml_handler(
+ session_context& cxt, const tokens& t,
+ spreadsheet::iface::import_table& table,
+ spreadsheet::iface::import_reference_resolver& resolver);
+};
+
+class xlsx_pivot_cache_def_xml_handler : public xml_stream_handler
+{
+public:
+ xlsx_pivot_cache_def_xml_handler(
+ session_context& cxt, const tokens& t,
+ spreadsheet::iface::import_pivot_cache_definition& pcache,
+ spreadsheet::pivot_cache_id_t pcache_id);
+
+ opc_rel_extras_t pop_rel_extras();
+};
+
+class xlsx_pivot_cache_rec_xml_handler : public xml_stream_handler
+{
+public:
+ xlsx_pivot_cache_rec_xml_handler(
+ session_context& cxt, const tokens& t,
+ spreadsheet::iface::import_pivot_cache_records& pc_records);
+};
+
+class xlsx_pivot_table_xml_handler : public xml_stream_handler
+{
+public:
+ xlsx_pivot_table_xml_handler(session_context& cxt, const tokens& t);
+};
+
+class xlsx_drawing_xml_handler : public xml_stream_handler
+{
+public:
+ xlsx_drawing_xml_handler(session_context& cxt, const tokens& t);
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_helper.cpp b/src/liborcus/xlsx_helper.cpp
new file mode 100644
index 0000000..9559d2b
--- /dev/null
+++ b/src/liborcus/xlsx_helper.cpp
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_helper.hpp"
+
+namespace orcus {
+
+bool to_rgb(
+ std::string_view ps, spreadsheet::color_elem_t& alpha,
+ spreadsheet::color_elem_t& red, spreadsheet::color_elem_t& green, spreadsheet::color_elem_t& blue)
+{
+ // RGB string is a 8-character string representing 32-bit hexadecimal
+ // number e.g. 'FF004A12' (alpha - red - green - blue)
+ size_t n = ps.size();
+ if (n != 8)
+ return false;
+
+ unsigned long v = strtoul(ps.data(), nullptr, 16);
+ blue = (0x000000FF & v);
+ green = (0x000000FF & (v >> 8));
+ red = (0x000000FF & (v >> 16));
+ alpha = (0x000000FF & (v >> 24));
+
+ return true;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_helper.hpp b/src/liborcus/xlsx_helper.hpp
new file mode 100644
index 0000000..1643db1
--- /dev/null
+++ b/src/liborcus/xlsx_helper.hpp
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/spreadsheet/types.hpp>
+
+namespace orcus {
+
+bool to_rgb(std::string_view ps, spreadsheet::color_elem_t& alpha,
+ spreadsheet::color_elem_t& red, spreadsheet::color_elem_t& gree,
+ spreadsheet::color_elem_t& blue);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_pivot_context.cpp b/src/liborcus/xlsx_pivot_context.cpp
new file mode 100644
index 0000000..026914d
--- /dev/null
+++ b/src/liborcus/xlsx_pivot_context.cpp
@@ -0,0 +1,1734 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_pivot_context.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "ooxml_token_constants.hpp"
+#include "xml_context_global.hpp"
+#include "session_context.hpp"
+#include "xlsx_types.hpp"
+
+#include "orcus/measurement.hpp"
+#include "orcus/spreadsheet/import_interface_pivot.hpp"
+
+#include <iostream>
+#include <optional>
+#include <mdds/sorted_string_map.hpp>
+
+using std::cout;
+using std::endl;
+
+namespace orcus {
+
+namespace {
+
+namespace pc_source {
+
+using map_type = mdds::sorted_string_map<xlsx_pivot_cache_def_context::source_type, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "consolidation", xlsx_pivot_cache_def_context::source_type::consolidation },
+ { "external", xlsx_pivot_cache_def_context::source_type::external },
+ { "scenario", xlsx_pivot_cache_def_context::source_type::scenario },
+ { "worksheet", xlsx_pivot_cache_def_context::source_type::worksheet },
+};
+
+const map_type& get()
+{
+ static const map_type map(
+ entries, std::size(entries),
+ xlsx_pivot_cache_def_context::source_type::unknown);
+
+ return map;
+}
+
+} // namespace pc_source
+
+}
+
+xlsx_pivot_cache_def_context::xlsx_pivot_cache_def_context(
+ session_context& cxt, const tokens& tokens,
+ spreadsheet::iface::import_pivot_cache_definition& pcache,
+ spreadsheet::pivot_cache_id_t pcache_id) :
+ xml_context_base(cxt, tokens), m_pcache(pcache), m_pcache_id(pcache_id) {}
+
+xml_context_base* xlsx_pivot_cache_def_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xlsx_pivot_cache_def_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xlsx_pivot_cache_def_context::start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ if (ns != NS_ooxml_xlsx)
+ return;
+
+ switch (name)
+ {
+ case XML_pivotCacheDefinition:
+ {
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+
+ std::string_view refreshed_by;
+ std::string_view rid;
+ long record_count = -1;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (!attr.ns || attr.ns == NS_ooxml_xlsx)
+ {
+ switch (attr.name)
+ {
+ case XML_refreshedBy:
+ refreshed_by = attr.value;
+ break;
+ case XML_recordCount:
+ record_count = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ else if (attr.ns == NS_ooxml_r)
+ {
+ switch (attr.name)
+ {
+ case XML_id:
+ // relation id for its cache record.
+ rid = attr.value;
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ );
+
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "pivot cache definition" << endl;
+ cout << "refreshed by: " << refreshed_by << endl;
+ cout << "record count: " << record_count << endl;
+ cout << "rid: " << rid << endl;
+ }
+
+ if (!rid.empty())
+ {
+ // The rid string here must be persistent beyond the current
+ // context.
+ rid = get_session_context().spool.intern(rid).first;
+
+ m_pcache_info.data.insert(
+ opc_rel_extras_t::map_type::value_type(
+ rid, std::make_unique<xlsx_rel_pivot_cache_record_info>(m_pcache_id)));
+ }
+
+ break;
+ }
+ case XML_cacheSource:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotCacheDefinition);
+
+ std::string_view source_type_s;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_type:
+ m_source_type = pc_source::get().find(attr.value);
+ source_type_s = attr.value;
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ if (get_config().debug)
+ cout << "type: " << source_type_s << endl;
+
+ break;
+ }
+ case XML_worksheetSource:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_cacheSource);
+ if (m_source_type != source_type::worksheet)
+ throw xml_structure_error(
+ "worksheetSource element encountered while the source type is not worksheet.");
+
+ std::string_view ref, sheet_name, table_name;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_ref:
+ ref = attr.value;
+ break;
+ case XML_sheet:
+ sheet_name = attr.value;
+ break;
+ case XML_name:
+ table_name = attr.value;
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ if (get_config().debug)
+ {
+ cout << "table: " << table_name << endl;
+ cout << "ref: " << ref << endl;
+ cout << "sheet: " << sheet_name << endl;
+ }
+
+ if (!table_name.empty())
+ m_pcache.set_worksheet_source(table_name);
+ else
+ m_pcache.set_worksheet_source(ref, sheet_name);
+ break;
+ }
+ case XML_cacheFields:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotCacheDefinition);
+ single_long_attr_getter func(NS_ooxml_xlsx, XML_count);
+ long field_count = for_each(attrs.begin(), attrs.end(), func).get_value();
+
+ if (get_config().debug)
+ cout << "field count: " << field_count << endl;
+
+ if (field_count < 0)
+ throw xml_structure_error("field count of a pivot cache must be positive.");
+
+ m_pcache.set_field_count(field_count);
+ break;
+ }
+ case XML_cacheField:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_cacheFields);
+
+ std::string_view field_name;
+ long numfmt_id = -1;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_name:
+ field_name = attr.value;
+ break;
+ case XML_numFmtId:
+ numfmt_id = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ // TODO : Handle number format ID here.
+ m_pcache.set_field_name(field_name);
+
+ if (get_config().debug)
+ {
+ cout << "* name: " << field_name << endl;
+ cout << " number format id: " << numfmt_id << endl;
+ }
+ break;
+ }
+ case XML_fieldGroup:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_cacheField);
+ long group_parent = -1;
+ long group_base = -1;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_par:
+ group_parent = to_long(attr.value);
+ break;
+ case XML_base:
+ group_base = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ if (get_config().debug)
+ {
+ if (group_parent >= 0)
+ cout << " * group parent index: " << group_parent << endl;
+ if (group_base >= 0)
+ cout << " * group base index: " << group_base << endl;
+ }
+
+ if (group_base >= 0)
+ {
+ // This is a group field.
+ m_pcache_field_group = m_pcache.start_field_group(group_base);
+ }
+ break;
+ }
+ case XML_discretePr:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_fieldGroup);
+
+ long count = -1;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_count:
+ count = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ if (get_config().debug)
+ cout << " * group child member count: " << count << endl;
+
+ break;
+ }
+ case XML_rangePr:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_fieldGroup);
+
+ bool auto_start = true;
+ bool auto_end = true;
+ double start = 0.0;
+ double end = 0.0;
+ double interval = 1.0;
+
+ std::optional<date_time_t> start_date;
+ std::optional<date_time_t> end_date;
+
+ // Default group-by type appears to be 'range'.
+ spreadsheet::pivot_cache_group_by_t group_by =
+ spreadsheet::pivot_cache_group_by_t::range;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_autoStart:
+ auto_start = to_bool(attr.value);
+ break;
+ case XML_autoEnd:
+ auto_end = to_bool(attr.value);
+ break;
+ case XML_startNum:
+ start = to_double(attr.value);
+ break;
+ case XML_endNum:
+ end = to_double(attr.value);
+ break;
+ case XML_groupInterval:
+ interval = to_double(attr.value);
+ break;
+ case XML_startDate:
+ start_date = date_time_t::from_chars(attr.value);
+ break;
+ case XML_endDate:
+ end_date = date_time_t::from_chars(attr.value);
+ break;
+ case XML_groupBy:
+ group_by = spreadsheet::to_pivot_cache_group_by_enum(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ if (m_pcache_field_group)
+ {
+ // Pass the values to the interface.
+ m_pcache_field_group->set_range_grouping_type(group_by);
+ m_pcache_field_group->set_range_auto_start(auto_start);
+ m_pcache_field_group->set_range_auto_end(auto_end);
+ m_pcache_field_group->set_range_start_number(start);
+ m_pcache_field_group->set_range_end_number(end);
+ m_pcache_field_group->set_range_interval(interval);
+
+ if (start_date)
+ m_pcache_field_group->set_range_start_date(*start_date);
+ if (end_date)
+ m_pcache_field_group->set_range_end_date(*end_date);
+ }
+
+ if (get_config().debug)
+ {
+ cout << " auto start: " << auto_start << endl;
+ cout << " auto end: " << auto_end << endl;
+ cout << " start: " << start << endl;
+ cout << " end: " << end << endl;
+ cout << " interval: " << interval << endl;
+
+ if (start_date)
+ cout << "start date: " << *start_date << endl;
+ if (end_date)
+ cout << "end date: " << *end_date << endl;
+ }
+
+ break;
+ }
+ case XML_sharedItems:
+ {
+ start_element_shared_items(parent, attrs);
+ break;
+ }
+ case XML_groupItems:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_fieldGroup);
+
+ long count = -1;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_count:
+ count = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ if (get_config().debug)
+ cout << " * group member count: " << count << endl;
+
+ break;
+ }
+ case XML_s:
+ {
+ start_element_s(parent, attrs);
+ break;
+ }
+ case XML_n:
+ {
+ start_element_n(parent, attrs);
+ break;
+ }
+ case XML_d:
+ {
+ start_element_d(parent, attrs);
+ break;
+ }
+ case XML_e:
+ {
+ start_element_e(parent, attrs);
+ break;
+ }
+ case XML_x:
+ {
+ const xml_elem_set_t expected = {
+ { NS_ooxml_xlsx, XML_discretePr },
+ { NS_ooxml_xlsx, XML_reference },
+ };
+ xml_element_expected(parent, expected);
+
+ long index = -1;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_v:
+ index = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ if (index < 0)
+ throw xml_structure_error("element 'x' without a required attribute 'v'.");
+
+ if (get_config().debug)
+ cout << " * index = " << index << endl;
+
+ if (m_pcache_field_group)
+ m_pcache_field_group->link_base_to_group_items(index);
+
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+}
+
+bool xlsx_pivot_cache_def_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_pivotCacheDefinition:
+ {
+ m_pcache.commit();
+ break;
+ }
+ case XML_cacheField:
+ {
+ m_pcache.commit_field();
+ m_pcache_field_group = nullptr;
+ break;
+ }
+ case XML_discretePr:
+ {
+ break;
+ }
+ case XML_fieldGroup:
+ {
+ if (m_pcache_field_group)
+ m_pcache_field_group->commit();
+ break;
+ }
+ case XML_s:
+ end_element_s();
+ break;
+ case XML_n:
+ end_element_n();
+ break;
+ case XML_d:
+ end_element_d();
+ break;
+ case XML_e:
+ end_element_e();
+ break;
+ default:
+ ;
+ }
+ }
+
+ return pop_stack(ns, name);
+}
+
+void xlsx_pivot_cache_def_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+opc_rel_extras_t xlsx_pivot_cache_def_context::pop_rel_extras()
+{
+ return std::move(m_pcache_info);
+}
+
+void xlsx_pivot_cache_def_context::start_element_s(
+ const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs)
+{
+ if (parent.first != NS_ooxml_xlsx)
+ {
+ warn_unhandled();
+ return;
+ }
+
+ std::string_view value;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_v:
+ value = attr.value;
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ switch (parent.second)
+ {
+ case XML_sharedItems:
+ {
+ // regular (non-group) field member name.
+
+ if (get_config().debug)
+ cout << " * field member: " << value << endl;
+
+ m_field_item_used = true;
+ m_pcache.set_field_item_string(value);
+ break;
+ }
+ case XML_groupItems:
+ {
+ // group field member name.
+
+ if (get_config().debug)
+ cout << " * group field member: " << value << endl;
+
+ m_field_item_used = true;
+ if (m_pcache_field_group)
+ m_pcache_field_group->set_field_item_string(value);
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+}
+
+void xlsx_pivot_cache_def_context::end_element_s()
+{
+ const xml_token_pair_t& parent = get_parent_element();
+ if (parent.first != NS_ooxml_xlsx)
+ return;
+
+ switch (parent.second)
+ {
+ case XML_sharedItems:
+ {
+ if (m_field_item_used)
+ m_pcache.commit_field_item();
+ break;
+ }
+ case XML_groupItems:
+ {
+ if (m_pcache_field_group && m_field_item_used)
+ m_pcache_field_group->commit_field_item();
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+void xlsx_pivot_cache_def_context::start_element_n(
+ const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs)
+{
+ if (parent.first != NS_ooxml_xlsx)
+ {
+ warn_unhandled();
+ return;
+ }
+
+ switch (parent.second)
+ {
+ case XML_sharedItems:
+ {
+ // numeric item of a cache field.
+ double value = 0.0;
+ m_field_item_used = true;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_v:
+ value = to_double(attr.value);
+ break;
+ case XML_u:
+ // flag for unused item.
+ m_field_item_used = !to_bool(attr.value);
+ default:
+ ;
+ }
+ }
+ );
+
+ if (get_config().debug)
+ {
+ cout << " * n: " << value;
+ if (!m_field_item_used)
+ cout << " (unused)";
+ cout << endl;
+
+ }
+
+ if (m_field_item_used)
+ m_pcache.set_field_item_numeric(value);
+
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+}
+
+void xlsx_pivot_cache_def_context::end_element_n()
+{
+ const xml_token_pair_t& parent = get_parent_element();
+ if (parent.first != NS_ooxml_xlsx)
+ return;
+
+ switch (parent.second)
+ {
+ case XML_sharedItems:
+ {
+ if (m_field_item_used)
+ m_pcache.commit_field_item();
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+void xlsx_pivot_cache_def_context::start_element_d(
+ const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs)
+{
+ if (parent.first != NS_ooxml_xlsx)
+ {
+ warn_unhandled();
+ return;
+ }
+
+ switch (parent.second)
+ {
+ case XML_sharedItems:
+ {
+ // date item of a cache field.
+ date_time_t dt;
+ m_field_item_used = true;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_v:
+ dt = date_time_t::from_chars(attr.value);
+ break;
+ case XML_u:
+ // flag for unused item.
+ m_field_item_used = !to_bool(attr.value);
+ default:
+ ;
+ }
+ }
+ );
+
+ if (get_config().debug)
+ {
+ cout << " * d: " << dt;
+ if (!m_field_item_used)
+ cout << " (unused)";
+ cout << endl;
+
+ }
+
+ if (m_field_item_used)
+ m_pcache.set_field_item_date_time(dt);
+
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+void xlsx_pivot_cache_def_context::end_element_d()
+{
+ const xml_token_pair_t& parent = get_parent_element();
+ if (parent.first != NS_ooxml_xlsx)
+ return;
+
+ switch (parent.second)
+ {
+ case XML_sharedItems:
+ {
+ if (m_field_item_used)
+ m_pcache.commit_field_item();
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+void xlsx_pivot_cache_def_context::start_element_e(
+ const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs)
+{
+ if (parent.first != NS_ooxml_xlsx)
+ {
+ warn_unhandled();
+ return;
+ }
+
+ switch (parent.second)
+ {
+ case XML_sharedItems:
+ {
+ // error value item of a cache field.
+ spreadsheet::error_value_t ev = spreadsheet::error_value_t::unknown;
+ m_field_item_used = true;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_v:
+ ev = spreadsheet::to_error_value_enum(attr.value);
+ break;
+ case XML_u:
+ // flag for unused item.
+ m_field_item_used = !to_bool(attr.value);
+ default:
+ ;
+ }
+ }
+ );
+
+ if (get_config().debug)
+ {
+ cout << " * e: " << ev;
+ if (!m_field_item_used)
+ cout << " (unused)";
+ cout << endl;
+ }
+
+ if (m_field_item_used)
+ m_pcache.set_field_item_error(ev);
+
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+void xlsx_pivot_cache_def_context::end_element_e()
+{
+ const xml_token_pair_t& parent = get_parent_element();
+ if (parent.first != NS_ooxml_xlsx)
+ return;
+
+ switch (parent.second)
+ {
+ case XML_sharedItems:
+ {
+ if (m_field_item_used)
+ m_pcache.commit_field_item();
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+void xlsx_pivot_cache_def_context::start_element_shared_items(
+ const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs)
+{
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_cacheField);
+
+ // If "semi-mixed types" is set, the field contains text values and at
+ // least one other type.
+ bool semi_mixed_types = true;
+
+ bool has_non_date = true;
+ bool has_date = false;
+ bool has_string = true;
+ bool has_blank = false;
+
+ // If "mixed types" is set, the field contains more than one data types.
+ bool mixed_types = false;
+
+ bool has_number = false;
+ bool has_integer = false;
+ bool has_long_text = false;
+
+ long count = -1;
+ std::optional<double> min_value;
+ std::optional<double> max_value;
+ std::optional<date_time_t> min_date;
+ std::optional<date_time_t> max_date;
+
+ for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_count:
+ count = to_long(attr.value);
+ break;
+ case XML_containsMixedTypes:
+ mixed_types = to_bool(attr.value);
+ break;
+ case XML_containsSemiMixedTypes:
+ semi_mixed_types = to_bool(attr.value);
+ break;
+ case XML_containsNonDate:
+ has_non_date = to_bool(attr.value);
+ break;
+ case XML_containsString:
+ has_string = to_bool(attr.value);
+ break;
+ case XML_containsBlank:
+ has_blank = to_bool(attr.value);
+ break;
+ case XML_containsNumber:
+ has_number = to_bool(attr.value);
+ break;
+ case XML_containsInteger:
+ has_integer = to_bool(attr.value);
+ break;
+ case XML_minValue:
+ min_value = to_double(attr.value);
+ break;
+ case XML_maxValue:
+ max_value = to_double(attr.value);
+ break;
+ case XML_minDate:
+ min_date = date_time_t::from_chars(attr.value);
+ break;
+ case XML_maxDate:
+ max_date = date_time_t::from_chars(attr.value);
+ break;
+ case XML_longText:
+ has_long_text = to_bool(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ if (min_value)
+ m_pcache.set_field_min_value(*min_value);
+
+ if (max_value)
+ m_pcache.set_field_max_value(*max_value);
+
+ if (min_date)
+ m_pcache.set_field_min_date(*min_date);
+
+ if (max_date)
+ m_pcache.set_field_max_date(*max_date);
+
+ if (get_config().debug)
+ {
+ cout << " contains semi-mixed types: " << semi_mixed_types << endl;
+ cout << " contains non-date: " << has_non_date << endl;
+ cout << " contains date: " << has_date << endl;
+ cout << " contains string: " << has_string << endl;
+ cout << " contains blank: " << has_blank << endl;
+ cout << " contains mixed types: " << mixed_types << endl;
+ cout << " contains number: " << has_number << endl;
+ cout << " contains integer: " << has_integer << endl;
+ cout << " contains long text: " << has_long_text << endl;
+ cout << " count: " << count << endl;
+
+ if (min_value)
+ cout << " min value: " << *min_value << endl;
+ if (max_value)
+ cout << " max value: " << *max_value << endl;
+ if (min_date)
+ cout << " min date: " << *min_date << endl;
+ if (max_date)
+ cout << " max date: " << *max_date << endl;
+ }
+}
+
+xlsx_pivot_cache_rec_context::xlsx_pivot_cache_rec_context(
+ session_context& cxt, const tokens& tokens,
+ spreadsheet::iface::import_pivot_cache_records& pc_records) :
+ xml_context_base(cxt, tokens),
+ m_pc_records(pc_records) {}
+
+xml_context_base* xlsx_pivot_cache_rec_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xlsx_pivot_cache_rec_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xlsx_pivot_cache_rec_context::start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+
+ if (ns != NS_ooxml_xlsx)
+ return;
+
+ switch (name)
+ {
+ case XML_pivotCacheRecords:
+ {
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ long count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
+
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "pivot cache record (count: " << count << ")" << endl;
+ }
+
+ m_pc_records.set_record_count(count);
+ break;
+ }
+ case XML_r: // record
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotCacheRecords);
+ if (get_config().debug)
+ cout << "* record" << endl;
+
+ break;
+ case XML_s: // character value
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_r);
+
+ std::string_view cv = single_attr_getter::get(attrs, NS_ooxml_xlsx, XML_v);
+
+ if (get_config().debug)
+ cout << " * s = '" << cv << "'" << endl;
+
+ m_pc_records.append_record_value_character(cv);
+ break;
+ }
+ case XML_x: // shared item index
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_r);
+ long v = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_v);
+ if (get_config().debug)
+ cout << " * x = " << v << endl;
+
+ m_pc_records.append_record_value_shared_item(v);
+ break;
+ }
+ case XML_n: // numeric
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_r);
+ double val = single_double_attr_getter::get(attrs, NS_ooxml_xlsx, XML_v);
+ if (get_config().debug)
+ cout << " * n = " << val << endl;
+
+ m_pc_records.append_record_value_numeric(val);
+ break;
+ }
+ case XML_e: // error value
+ {
+ std::string_view cv = single_attr_getter::get(attrs, NS_ooxml_xlsx, XML_v);
+
+ if (get_config().debug)
+ cout << " * e = " << cv << endl;
+
+ break;
+ }
+ case XML_b: // boolean
+ case XML_d: // date time
+ case XML_m: // no value
+ default:
+ warn_unhandled();
+ }
+}
+
+bool xlsx_pivot_cache_rec_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_pivotCacheRecords:
+ m_pc_records.commit();
+ break;
+ case XML_r: // record
+ m_pc_records.commit_record();
+ break;
+ default:
+ ;
+ }
+ }
+
+ return pop_stack(ns, name);
+}
+
+xlsx_pivot_table_context::xlsx_pivot_table_context(session_context& cxt, const tokens& tokens) :
+ xml_context_base(cxt, tokens) {}
+
+xml_context_base* xlsx_pivot_table_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xlsx_pivot_table_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xlsx_pivot_table_context::start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_pivotTableDefinition:
+ {
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ if (get_config().debug)
+ cout << "---" << endl;
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ continue;
+
+ long v = 0;
+ bool b = false;
+
+ switch (attr.name)
+ {
+ case XML_name:
+ if (get_config().debug)
+ cout << "name: " << attr.value << endl;
+ break;
+ case XML_cacheId:
+ v = to_long(attr.value);
+ if (get_config().debug)
+ cout << "cache ID: " << v << endl;
+ break;
+ case XML_applyNumberFormats:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "apply number formats: " << b << endl;
+ break;
+ case XML_applyBorderFormats:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "apply border formats: " << b << endl;
+ break;
+ case XML_applyFontFormats:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "apply font formats: " << b << endl;
+ break;
+ case XML_applyPatternFormats:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "apply pattern formats: " << b << endl;
+ break;
+ case XML_applyAlignmentFormats:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "apply alignment formats: " << b << endl;
+ break;
+ case XML_applyWidthHeightFormats:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "apply width/height formats: " << b << endl;
+ break;
+ case XML_dataCaption:
+ if (get_config().debug)
+ cout << "data caption: " << attr.value << endl;
+ break;
+ case XML_updatedVersion:
+ v = to_long(attr.value);
+ if (get_config().debug)
+ cout << "updated version: " << v << endl;
+ break;
+ case XML_minRefreshableVersion:
+ v = to_long(attr.value);
+ if (get_config().debug)
+ cout << "minimum refreshable version: " << v << endl;
+ break;
+ case XML_showCalcMbrs:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "show calc members (?): " << b << endl;
+ break;
+ case XML_useAutoFormatting:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "use auto formatting: " << b << endl;
+ break;
+ case XML_itemPrintTitles:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "item print titles (?): " << b << endl;
+ break;
+ case XML_createdVersion:
+ v = to_long(attr.value);
+ if (get_config().debug)
+ cout << "created version: " << v << endl;
+ break;
+ case XML_indent:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "indent: " << b << endl;
+ break;
+ case XML_compact:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "compact: " << b << endl;
+ break;
+ case XML_compactData:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "compact data: " << b << endl;
+ break;
+ case XML_outline:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "outline: " << b << endl;
+ break;
+ case XML_outlineData:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "outline data: " << b << endl;
+ break;
+ case XML_gridDropZones:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "grid drop zones: " << b << endl;
+ break;
+ case XML_multipleFieldFilters:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "multiple field filters: " << b << endl;
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ break;
+ case XML_location:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ continue;
+
+ long v = -1;
+ switch (attr.name)
+ {
+ case XML_ref:
+ if (get_config().debug)
+ cout << "ref: " << attr.value << endl;
+ break;
+ case XML_firstHeaderRow:
+ v = to_long(attr.value);
+ if (get_config().debug)
+ cout << "first header row: " << v << endl;
+ break;
+ case XML_firstDataRow:
+ v = to_long(attr.value);
+ if (get_config().debug)
+ cout << "first data row: " << v << endl;
+ break;
+ case XML_firstDataCol:
+ v = to_long(attr.value);
+ if (get_config().debug)
+ cout << "first data column: " << v << endl;
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ break;
+ case XML_pivotFields:
+ {
+ // pivotFields and its child elements represent the visual
+ // appearances of the fields inside pivot table.
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
+ size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
+ if (get_config().debug)
+ cout << "field count: " << count << endl;
+ }
+ break;
+ case XML_pivotField:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotFields);
+
+ if (get_config().debug)
+ cout << "---" << endl;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_axis:
+ if (get_config().debug)
+ cout << " * axis: " << attr.value << endl;
+ break;
+ case XML_compact:
+ {
+ bool b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << " * compact: " << b << endl;
+ }
+ break;
+ case XML_outline:
+ {
+ bool b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << " * outline: " << b << endl;
+ }
+ break;
+ case XML_showAll:
+ {
+ bool b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << " * show all: " << b << endl;
+ }
+ break;
+ case XML_dataField:
+ {
+ bool b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << " * data field: " << b << endl;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ break;
+ case XML_items:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotField);
+ size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
+ if (get_config().debug)
+ cout << " * item count: " << count << endl;
+ }
+ break;
+ case XML_item:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_items);
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_x:
+ {
+ // field item index as defined in the pivot cache.
+ long idx = to_long(attr.value);
+ if (get_config().debug)
+ cout << " * x = " << idx << endl;
+ }
+ break;
+ case XML_t:
+ {
+ // When the <item> element has attribute 't', it's subtotal or
+ // some sort of function item. See 3.18.45 ST_ItemType
+ // (PivotItem Type) for possible values.
+ if (get_config().debug)
+ cout << " * type = " << attr.value << endl;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ break;
+ case XML_rowFields:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
+ size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "row field count: " << count << endl;
+ }
+ }
+ break;
+ case XML_colFields:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
+ size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "column field count: " << count << endl;
+ }
+ }
+ break;
+ case XML_pageFields:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
+ size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "page field count: " << count << endl;
+ }
+ }
+ break;
+ case XML_pageField:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pageFields);
+
+ if (get_config().debug)
+ cout << " * page field:";
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_fld:
+ {
+ long fld = to_long(attr.value);
+ if (get_config().debug)
+ cout << "field index = " << fld << "; ";
+ break;
+ }
+ case XML_item:
+ {
+ long item = to_long(attr.value);
+ if (get_config().debug)
+ cout << "item index = " << item << "; ";
+ break;
+ }
+ case XML_hier:
+ {
+ long hier = to_long(attr.value);
+ // -1 if not applicable.
+ if (get_config().debug)
+ cout << "OLAP hierarchy index = " << hier << "; ";
+ break;
+ }
+ default:
+ ;
+ }
+ }
+
+ if (get_config().debug)
+ cout << endl;
+ break;
+ }
+ case XML_field:
+ {
+ xml_elem_stack_t expected;
+ expected.reserve(3);
+ expected.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_rowFields));
+ expected.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_colFields));
+ xml_element_expected(parent, expected);
+
+ // Index into the list of <pivotField> collection which is
+ // given earlier under the <pivotFields> element. The value
+ // of -2 represents a special field that displays the list of
+ // data fields when the pivot table contains more than one
+ // data field.
+ long idx = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_x);
+ if (get_config().debug)
+ cout << " * x = " << idx << endl;
+ }
+ break;
+ case XML_dataFields:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
+ size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "data field count: " << count << endl;
+ }
+ }
+ break;
+ case XML_dataField:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_dataFields);
+
+ if (get_config().debug)
+ cout << " * data field: ";
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_name:
+ {
+ if (get_config().debug)
+ cout << "name = " << attr.value << "; ";
+ break;
+ }
+ case XML_fld:
+ {
+ long fld = to_long(attr.value);
+ if (get_config().debug)
+ cout << "field = " << fld << "; ";
+ break;
+ }
+ case XML_baseField:
+ {
+ long fld = to_long(attr.value);
+ if (get_config().debug)
+ cout << "base field = " << fld << "; ";
+ break;
+ }
+ case XML_baseItem:
+ {
+ long fld = to_long(attr.value);
+ if (get_config().debug)
+ cout << "base item = " << fld << "; ";
+ break;
+ }
+ case XML_subtotal:
+ {
+ if (get_config().debug)
+ cout << "subtotal = " << attr.value << "; ";
+ break;
+ }
+ default:
+ ;
+ }
+ }
+
+ if (get_config().debug)
+ cout << endl;
+ }
+ break;
+ case XML_rowItems:
+ {
+ // <rowItems> structure describes the displayed content of
+ // cells in the row field area. Each <i> child element
+ // represents a single row.
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
+ size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "row item count: " << count << endl;
+ }
+ }
+ break;
+ case XML_colItems:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
+ size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "column item count: " << count << endl;
+ }
+ }
+ break;
+ case XML_i:
+ {
+ xml_elem_stack_t expected;
+ expected.reserve(2);
+ expected.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_rowItems));
+ expected.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_colItems));
+ xml_element_expected(parent, expected);
+
+ if (get_config().debug)
+ cout << "---" << endl;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_t:
+ {
+ // total or subtotal function type.
+ if (get_config().debug)
+ cout << " * type = " << attr.value << endl;
+ }
+ break;
+ case XML_r:
+ {
+ // "repeated item count" which basically is the number of
+ // blank cells that occur after the preivous non-empty cell on
+ // the same row (in the classic layout mode).
+ long v = to_long(attr.value);
+ if (get_config().debug)
+ cout << " * repeat item count = " << v << endl;
+ }
+ break;
+ case XML_i:
+ {
+ // zero-based data field index in case of multiple data fields.
+ long v = to_long(attr.value);
+ if (get_config().debug)
+ cout << " * data field index = " << v << endl;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ break;
+ case XML_x:
+ {
+ if (parent.first != NS_ooxml_xlsx)
+ {
+ warn_unhandled();
+ break;
+ }
+
+ if (parent.second == XML_i)
+ {
+ long idx = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_v);
+ if (idx < 0)
+ // 0 is default when not set.
+ idx = 0;
+
+ if (get_config().debug)
+ cout << " * v = " << idx << endl;
+ break;
+ }
+
+ warn_unhandled();
+ }
+ break;
+ case XML_pivotTableStyleInfo:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
+
+ if (get_config().debug)
+ {
+ cout << "---" << endl;
+ cout << "* style info: ";
+ }
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ continue;
+
+ bool b = false;
+
+ switch (attr.name)
+ {
+ case XML_name:
+ if (get_config().debug)
+ cout << "name='" << attr.value << "'; ";
+ break;
+ case XML_showRowHeaders:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "show row headers=" << b << "; ";
+ break;
+ case XML_showColHeaders:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "show column headers=" << b << "; ";
+ break;
+ case XML_showRowStripes:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "show row stripes=" << b << "; ";
+ break;
+ case XML_showColStripes:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "show column stripes=" << b << "; ";
+ break;
+ case XML_showLastColumn:
+ b = to_bool(attr.value);
+ if (get_config().debug)
+ cout << "show last column=" << b << "; ";
+ break;
+ default:
+ ;
+ }
+ }
+
+ if (get_config().debug)
+ cout << endl;
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool xlsx_pivot_table_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ return pop_stack(ns, name);
+}
+
+void xlsx_pivot_table_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_pivot_context.hpp b/src/liborcus/xlsx_pivot_context.hpp
new file mode 100644
index 0000000..f9610ba
--- /dev/null
+++ b/src/liborcus/xlsx_pivot_context.hpp
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLSX_PIVOT_CONTEXT_HPP
+#define ORCUS_XLSX_PIVOT_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "ooxml_types.hpp"
+#include "orcus/spreadsheet/types.hpp"
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_pivot_cache_definition;
+class import_pivot_cache_field_group;
+class import_pivot_cache_records;
+
+}}
+
+/**
+ * Base context for pivotCacheDefinition[n].xml part, which defines the
+ * structure of a pivot cache.
+ */
+class xlsx_pivot_cache_def_context : public xml_context_base
+{
+public:
+ enum class source_type {
+ unknown = 0,
+ worksheet,
+ external,
+ consolidation,
+ scenario
+ };
+
+private:
+ spreadsheet::iface::import_pivot_cache_definition& m_pcache;
+ spreadsheet::pivot_cache_id_t m_pcache_id;
+ spreadsheet::iface::import_pivot_cache_field_group* m_pcache_field_group = nullptr;
+ source_type m_source_type = source_type::unknown;
+ bool m_field_item_used = true;
+
+ opc_rel_extras_t m_pcache_info;
+
+public:
+ xlsx_pivot_cache_def_context(
+ session_context& cxt, const tokens& tokens,
+ spreadsheet::iface::import_pivot_cache_definition& pcache,
+ spreadsheet::pivot_cache_id_t pcache_id);
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+
+ opc_rel_extras_t pop_rel_extras();
+
+private:
+ void start_element_s(const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs);
+ void end_element_s();
+
+ void start_element_n(const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs);
+ void end_element_n();
+
+ void start_element_d(const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs);
+ void end_element_d();
+
+ void start_element_e(const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs);
+ void end_element_e();
+
+ void start_element_shared_items(const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs);
+};
+
+/**
+ * Context for pivotCacheRecords[n].xml part, which contains the records in
+ * a pivot cache.
+ */
+class xlsx_pivot_cache_rec_context : public xml_context_base
+{
+ spreadsheet::iface::import_pivot_cache_records& m_pc_records;
+
+public:
+ xlsx_pivot_cache_rec_context(
+ session_context& cxt, const tokens& tokens,
+ spreadsheet::iface::import_pivot_cache_records& pc_records);
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+};
+
+/**
+ * Context for pivotTable[n].xml part which defines the structure of a pivot
+ * table model.
+ */
+class xlsx_pivot_table_context : public xml_context_base
+{
+public:
+ xlsx_pivot_table_context(session_context& cxt, const tokens& tokens);
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_revision_context.cpp b/src/liborcus/xlsx_revision_context.cpp
new file mode 100644
index 0000000..637659f
--- /dev/null
+++ b/src/liborcus/xlsx_revision_context.cpp
@@ -0,0 +1,578 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_revision_context.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "ooxml_token_constants.hpp"
+#include "session_context.hpp"
+#include "xml_context_global.hpp"
+
+#include "orcus/measurement.hpp"
+#include "orcus/string_pool.hpp"
+
+#include <iostream>
+#include <limits>
+
+using namespace std;
+
+namespace orcus {
+
+namespace {
+
+class headers_attr_parser
+{
+ std::string_view m_guid;
+ long m_highest_revid;
+ long m_version;
+ bool m_disk_revisions;
+
+public:
+ headers_attr_parser() : m_highest_revid(-1), m_version(-1), m_disk_revisions(false) {}
+
+ std::string_view get_last_guid() const { return m_guid; }
+ long get_highest_revid() const { return m_highest_revid; }
+ long get_version() const { return m_version; }
+ bool is_disk_revisions() const { return m_disk_revisions; }
+
+ void operator() (const xml_token_attr_t& attr)
+ {
+ if (attr.ns != NS_ooxml_xlsx)
+ // All attributes are in the xlsx namespace.
+ return;
+
+ switch (attr.name)
+ {
+ case XML_guid:
+ // guid should never be transient as it's not supposed to contain any encoded characters.
+ // TODO : We should convert guid to a numeric value here.
+ m_guid = attr.value;
+ break;
+ case XML_diskRevisions:
+ m_disk_revisions = to_long(attr.value) != 0;
+ break;
+ case XML_revisionId:
+ m_highest_revid = to_long(attr.value);
+ break;
+ case XML_version:
+ m_version = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+};
+
+class header_attr_parser
+{
+ string_pool* m_pool;
+
+ std::string_view m_guid;
+ std::string_view m_username;
+ std::string_view m_rid;
+
+ date_time_t m_date_time;
+ long m_next_sheet_id;
+ long m_min_revid;
+ long m_max_revid;
+
+public:
+ header_attr_parser(string_pool& pool) :
+ m_pool(&pool), m_next_sheet_id(-1), m_min_revid(-1), m_max_revid(-1) {}
+
+ std::string_view get_guid() const { return m_guid; }
+ std::string_view get_username() const { return m_username; }
+ std::string_view get_rid() const { return m_rid; }
+ date_time_t get_date_time() const { return m_date_time; }
+ long get_next_sheet_id() const { return m_next_sheet_id; }
+ long get_min_revid() const { return m_min_revid; }
+ long get_max_revid() const { return m_max_revid; }
+
+ void operator() (const xml_token_attr_t& attr)
+ {
+ if (attr.ns == NS_ooxml_xlsx)
+ {
+ switch (attr.name)
+ {
+ case XML_guid:
+ m_guid = attr.value;
+ break;
+ case XML_dateTime:
+ m_date_time = date_time_t::from_chars(attr.value);
+ break;
+ case XML_maxSheetId:
+ m_next_sheet_id = to_long(attr.value);
+ break;
+ case XML_userName:
+ m_username = attr.value;
+ if (attr.transient)
+ m_username = m_pool->intern(m_username).first;
+ break;
+ case XML_minRId:
+ m_min_revid = to_long(attr.value);
+ break;
+ case XML_maxRId:
+ m_max_revid = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ else if (attr.ns == NS_ooxml_r && attr.name == XML_id)
+ {
+ // Pick up a rel id here.
+ if (attr.transient)
+ // Rel ID's should never be transient.
+ return;
+
+ m_rid = attr.value;
+ }
+ }
+};
+
+}
+
+xlsx_revheaders_context::xlsx_revheaders_context(session_context& session_cxt, const tokens& tokens) :
+ xml_context_base(session_cxt, tokens) {}
+
+xlsx_revheaders_context::~xlsx_revheaders_context() {}
+
+xml_context_base* xlsx_revheaders_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xlsx_revheaders_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xlsx_revheaders_context::start_element(xmlns_id_t ns, xml_token_t name, const vector<xml_token_attr_t>& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_headers:
+ {
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ headers_attr_parser func;
+ func = for_each(attrs.begin(), attrs.end(), func);
+ cout << "* last guid: " << func.get_last_guid() << endl;
+ cout << "* highest revision ID: " << func.get_highest_revid() << endl;
+ cout << "* version: " << func.get_version() << endl;
+ cout << "* disk revisions: " << func.is_disk_revisions() << endl;
+ }
+ break;
+ case XML_header:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_headers);
+ header_attr_parser func(get_session_context().spool);
+ func = for_each(attrs.begin(), attrs.end(), func);
+ cout << "* revision header (guid:" << func.get_guid() << ")" << endl;
+ cout << " - timestamp: " << func.get_date_time().to_string() << endl;
+ cout << " - user name: " << func.get_username() << endl;
+
+ if (func.get_min_revid() != -1 && func.get_max_revid() != -1)
+ cout << " - revision range: " << func.get_min_revid() << "-" << func.get_max_revid() << endl;
+
+ long next_sheet = func.get_next_sheet_id();
+ if (next_sheet != -1)
+ cout << " - next available sheet: " << (next_sheet - 1) << endl;
+
+ cout << " - revision log rid: " << func.get_rid() << endl;
+ // TODO : Intern the rid here when passing it to the revision log stream.
+ }
+ break;
+ case XML_sheetIdMap:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_header);
+ m_cur_sheet_ids.clear();
+ long n = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
+ if (n > 0)
+ m_cur_sheet_ids.reserve(n);
+ }
+ break;
+ case XML_sheetId:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_sheetIdMap);
+ long val = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_val);
+ if (val > 0)
+ m_cur_sheet_ids.push_back(val-1); // convert from 1-based to 0-based.
+ }
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+}
+
+bool xlsx_revheaders_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_sheetIdMap:
+ {
+ cout << " - sheet indices: ";
+ for (size_t i = 0; i < m_cur_sheet_ids.size(); ++i)
+ cout << m_cur_sheet_ids[i] << " ";
+ cout << endl;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void xlsx_revheaders_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+namespace {
+
+class rcc_attr_parser
+{
+ long m_revision_id;
+ long m_sheet_id;
+
+public:
+ rcc_attr_parser() : m_revision_id(-1), m_sheet_id(-1) {}
+
+ long get_revision_id() const { return m_revision_id; }
+ long get_sheet_id() const { return m_sheet_id; }
+
+ void operator() (const xml_token_attr_t& attr)
+ {
+ if (attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_rId:
+ // revision ID
+ m_revision_id = to_long(attr.value);
+ break;
+ case XML_sId:
+ // sheet ID
+ m_sheet_id = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+};
+
+class rrc_attr_parser
+{
+ long m_revision_id;
+ long m_sheet_id;
+
+ std::string_view m_ref;
+ xlsx_rev_row_column_action_t m_action_type;
+
+ bool m_end_of_list;
+
+public:
+ rrc_attr_parser() : m_revision_id(-1), m_sheet_id(-1),
+ m_action_type(xlsx_rev_rca_unknown), m_end_of_list(false) {}
+
+ long get_revision_id() const { return m_revision_id; }
+ long get_sheet_id() const { return m_sheet_id; }
+ bool is_end_of_list() const { return m_end_of_list; }
+ std::string_view get_ref() const { return m_ref; }
+ xlsx_rev_row_column_action_t get_action_type() const { return m_action_type; }
+
+ void operator() (const xml_token_attr_t& attr)
+ {
+ if (attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_rId:
+ // revision ID
+ m_revision_id = to_long(attr.value);
+ break;
+ case XML_sId:
+ // sheet ID
+ m_sheet_id = to_long(attr.value);
+ break;
+ case XML_eol:
+ m_end_of_list = to_long(attr.value) > 0;
+ break;
+ case XML_ref:
+ if (!attr.transient)
+ m_ref = attr.value;
+ break;
+ case XML_action:
+ m_action_type = to_xlsx_rev_row_column_action_type(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+};
+
+class cell_data_attr_parser
+{
+ std::string_view m_ref;
+ xlsx_cell_t m_type;
+
+public:
+ cell_data_attr_parser() : m_type(xlsx_ct_numeric) {}
+
+ std::string_view get_ref() const { return m_ref; }
+ xlsx_cell_t get_cell_type() const { return m_type; }
+
+ void operator() (const xml_token_attr_t& attr)
+ {
+ if (attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_r:
+ if (!attr.transient)
+ m_ref = attr.value;
+ break;
+ case XML_t:
+ m_type = to_xlsx_cell_type(attr.value);
+ default:
+ ;
+ }
+ }
+};
+
+}
+
+xlsx_revlog_context::xlsx_revlog_context(session_context& session_cxt, const tokens& tokens) :
+ xml_context_base(session_cxt, tokens),
+ m_cur_value(std::numeric_limits<double>::quiet_NaN()),
+ m_cur_cell_type(xlsx_ct_unknown), m_cur_formula(false)
+{
+}
+
+xlsx_revlog_context::~xlsx_revlog_context() {}
+
+xml_context_base* xlsx_revlog_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xlsx_revlog_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xlsx_revlog_context::start_element(xmlns_id_t ns, xml_token_t name, const vector<xml_token_attr_t>& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_revisions:
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ break;
+ case XML_raf:
+ // revision auto format
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ break;
+ case XML_rcc:
+ {
+ // revision cell change
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ rcc_attr_parser func;
+ func = for_each(attrs.begin(), attrs.end(), func);
+ cout << "* revision id: " << func.get_revision_id() << " type: cell change" << endl;
+ cout << " - sheet index: " << func.get_sheet_id() << endl;
+ m_cur_cell_type = xlsx_ct_unknown;
+ }
+ break;
+ case XML_rcft:
+ // revision merge conflict
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ break;
+ case XML_rcmt:
+ // revision cell comment
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ break;
+ case XML_rcv:
+ // revision custom view
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ break;
+ case XML_rdn:
+ // revision defined name
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ break;
+ case XML_rfmt:
+ {
+ // revision format
+ const xml_elem_set_t expected = {
+ { NS_ooxml_xlsx, XML_revisions },
+ { NS_ooxml_xlsx, XML_rm },
+ { NS_ooxml_xlsx, XML_rrc },
+ };
+ xml_element_expected(parent, expected);
+ break;
+ }
+ case XML_ris:
+ // revision insert sheet
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ break;
+ case XML_rm:
+ // revision cell move
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ break;
+ case XML_rqt:
+ // revision query table
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ break;
+ case XML_rrc:
+ {
+ // revision row column insert delete
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ rrc_attr_parser func;
+ func = for_each(attrs.begin(), attrs.end(), func);
+ cout << "* revision id: " << func.get_revision_id() << " type: row column insert delete" << endl;
+ cout << " - sheet index: " << func.get_sheet_id() << endl;
+ cout << " - action type: " << to_string(func.get_action_type()) << endl;
+ cout << " - range: " << func.get_ref() << endl;
+ cout << " - end of list: " << (func.is_end_of_list() ? "true":"false") << endl;
+ }
+ break;
+ case XML_rsnm:
+ // revision sheet name
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_revisions);
+ break;
+ case XML_oc:
+ // old cell data
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_rcc);
+ break;
+ case XML_nc:
+ {
+ // new cell data
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_rcc);
+ cell_data_attr_parser func;
+ func = for_each(attrs.begin(), attrs.end(), func);
+ m_cur_cell_type = func.get_cell_type();
+
+ m_cur_formula = false;
+ m_cur_value = 0.0;
+ m_cur_string = std::string_view{};
+
+ cout << " - new cell position: " << func.get_ref() << endl;
+ cout << " - new cell type: " << to_string(m_cur_cell_type) << endl;
+ }
+ break;
+ case XML_f:
+ {
+ xml_elem_stack_t elems;
+ elems.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_oc));
+ elems.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_nc));
+ xml_element_expected(parent, elems);
+ }
+ break;
+ case XML_v:
+ {
+ xml_elem_stack_t elems;
+ elems.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_oc));
+ elems.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_nc));
+ xml_element_expected(parent, elems);
+ }
+ break;
+ case XML_is:
+ {
+ xml_elem_stack_t elems;
+ elems.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_oc));
+ elems.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_nc));
+ xml_element_expected(parent, elems);
+ }
+ break;
+ case XML_t:
+ {
+ xml_elem_stack_t elems;
+ elems.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_is));
+ elems.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_r));
+ xml_element_expected(parent, elems);
+ }
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+}
+
+bool xlsx_revlog_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_nc:
+ {
+ cout << " - new cell value: ";
+ switch (m_cur_cell_type)
+ {
+ case xlsx_ct_boolean:
+ if (m_cur_value != 0.0)
+ cout << "true";
+ else
+ cout << "false";
+ break;
+ case xlsx_ct_numeric:
+ if (m_cur_formula)
+ cout << m_cur_string;
+ else
+ cout << m_cur_value;
+ break;
+ case xlsx_ct_inline_string:
+ cout << m_cur_string;
+ break;
+ default:
+ ;
+ }
+ cout << endl;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void xlsx_revlog_context::characters(std::string_view str, bool transient)
+{
+ xml_token_pair_t elem = get_current_element();
+ if (elem.first == NS_ooxml_xlsx)
+ {
+ switch (elem.second)
+ {
+ case XML_v:
+ m_cur_value = to_double(str);
+ break;
+ case XML_f:
+ m_cur_formula = true;
+ // fall through to get the string.
+ case XML_t:
+ m_cur_string = str;
+ if (transient)
+ m_cur_string = get_session_context().spool.intern(m_cur_string).first;
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_revision_context.hpp b/src/liborcus/xlsx_revision_context.hpp
new file mode 100644
index 0000000..a560e07
--- /dev/null
+++ b/src/liborcus/xlsx_revision_context.hpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLSX_REVHEADERS_CONTEXT_HPP
+#define ORCUS_XLSX_REVHEADERS_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "xlsx_types.hpp"
+
+namespace orcus {
+
+class xlsx_revheaders_context : public xml_context_base
+{
+ std::vector<long> m_cur_sheet_ids; /// current sheet ID's.
+public:
+ xlsx_revheaders_context(session_context& session_cxt, const tokens& tokens);
+ virtual ~xlsx_revheaders_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+};
+
+class xlsx_revlog_context : public xml_context_base
+{
+ double m_cur_value;
+ std::string_view m_cur_string;
+ xlsx_cell_t m_cur_cell_type;
+
+ bool m_cur_formula;
+
+public:
+ xlsx_revlog_context(session_context& session_cxt, const tokens& tokens);
+ virtual ~xlsx_revlog_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_session_data.cpp b/src/liborcus/xlsx_session_data.cpp
new file mode 100644
index 0000000..599a136
--- /dev/null
+++ b/src/liborcus/xlsx_session_data.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_session_data.hpp"
+
+namespace orcus {
+
+xlsx_session_data::formula::formula(
+ spreadsheet::sheet_t _sheet, spreadsheet::row_t _row, spreadsheet::col_t _column,
+ std::string_view _exp) :
+ sheet(_sheet), exp(_exp)
+{
+ ref.column = _column;
+ ref.row = _row;
+}
+
+xlsx_session_data::array_formula::array_formula(
+ spreadsheet::sheet_t _sheet, const spreadsheet::range_t& _ref, std::string_view _exp) :
+ sheet(_sheet),
+ ref(_ref),
+ exp(_exp),
+ results(
+ std::make_shared<range_formula_results>(
+ ref.last.row-ref.first.row+1,
+ ref.last.column-ref.first.column+1))
+{
+}
+
+xlsx_session_data::shared_formula::shared_formula(
+ spreadsheet::sheet_t _sheet, spreadsheet::row_t _row, spreadsheet::col_t _column, size_t _identifier) :
+ sheet(_sheet), row(_row), column(_column), identifier(_identifier), master(false) {}
+
+xlsx_session_data::shared_formula::shared_formula(
+ spreadsheet::sheet_t _sheet, spreadsheet::row_t _row, spreadsheet::col_t _column,
+ size_t _identifier, std::string_view _formula) :
+ sheet(_sheet), row(_row), column(_column),
+ identifier(_identifier), formula(_formula), master(true) {}
+
+xlsx_session_data::~xlsx_session_data() = default;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_session_data.hpp b/src/liborcus/xlsx_session_data.hpp
new file mode 100644
index 0000000..af254d0
--- /dev/null
+++ b/src/liborcus/xlsx_session_data.hpp
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_XLSX_SESSION_DATA_HPP
+#define INCLUDED_ORCUS_XLSX_SESSION_DATA_HPP
+
+#include "session_context.hpp"
+#include "formula_result.hpp"
+
+#include "orcus/spreadsheet/types.hpp"
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <unordered_map>
+
+namespace orcus {
+
+/**
+ * Collection of global data that need to be persistent across different
+ * parts during a single import session.
+ */
+struct xlsx_session_data : public session_context::custom_data
+{
+ struct formula
+ {
+ spreadsheet::sheet_t sheet;
+ spreadsheet::address_t ref;
+ std::string exp;
+
+ formula_result result;
+
+ formula(
+ spreadsheet::sheet_t _sheet, spreadsheet::row_t _row, spreadsheet::col_t _column,
+ std::string_view _exp);
+ };
+
+ struct array_formula
+ {
+ spreadsheet::sheet_t sheet;
+ spreadsheet::range_t ref;
+ std::string exp;
+
+ std::shared_ptr<range_formula_results> results;
+
+ array_formula(
+ spreadsheet::sheet_t sheet, const spreadsheet::range_t& ref,
+ std::string_view exp);
+ };
+
+ struct shared_formula
+ {
+ spreadsheet::sheet_t sheet;
+ spreadsheet::row_t row;
+ spreadsheet::col_t column;
+ size_t identifier;
+ std::string formula;
+ bool master;
+
+ formula_result result;
+
+ shared_formula(
+ spreadsheet::sheet_t _sheet, spreadsheet::row_t _row, spreadsheet::col_t _column,
+ size_t _identifier);
+
+ shared_formula(
+ spreadsheet::sheet_t _sheet, spreadsheet::row_t _row, spreadsheet::col_t _column,
+ size_t _identifier, std::string_view _formula);
+ };
+
+ typedef std::vector<std::unique_ptr<formula>> formulas_type;
+ typedef std::vector<std::unique_ptr<array_formula>> array_formulas_type;
+ typedef std::vector<std::unique_ptr<shared_formula>> shared_formulas_type;
+ typedef std::unordered_map<std::string_view, spreadsheet::sheet_t> sheet_name_map_type;
+
+ formulas_type m_formulas;
+ array_formulas_type m_array_formulas;
+ shared_formulas_type m_shared_formulas;
+ string_pool m_formula_result_strings;
+
+ virtual ~xlsx_session_data();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_shared_strings_context.cpp b/src/liborcus/xlsx_shared_strings_context.cpp
new file mode 100644
index 0000000..29fac3e
--- /dev/null
+++ b/src/liborcus/xlsx_shared_strings_context.cpp
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_shared_strings_context.hpp"
+#include "ooxml_token_constants.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "xlsx_helper.hpp"
+#include "xml_context_global.hpp"
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/measurement.hpp>
+
+#include <optional>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+class shared_strings_root_attr_parser
+{
+public:
+ shared_strings_root_attr_parser() : m_count(0), m_unique_count(0) {}
+
+ void operator() (const xml_token_attr_t &attr)
+ {
+ switch (attr.name)
+ {
+ case XML_count:
+ m_count = to_long(attr.value);
+ break;
+ case XML_uniqueCount:
+ m_unique_count = to_long(attr.value);
+ break;
+ }
+ }
+
+ shared_strings_root_attr_parser& operator= (const shared_strings_root_attr_parser& r)
+ {
+ m_count = r.m_count;
+ m_unique_count = r.m_unique_count;
+ return *this;
+ }
+
+ size_t get_count() const { return m_count; }
+ size_t get_unique_count() const { return m_unique_count; }
+private:
+ size_t m_count;
+ size_t m_unique_count;
+};
+
+}
+
+xlsx_shared_strings_context::xlsx_shared_strings_context(session_context& session_cxt, const tokens& tokens, spreadsheet::iface::import_shared_strings* strings) :
+ xml_context_base(session_cxt, tokens), mp_strings(strings), m_in_segments(false) {}
+
+xlsx_shared_strings_context::~xlsx_shared_strings_context() {}
+
+void xlsx_shared_strings_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ switch (name)
+ {
+ case XML_sst:
+ {
+ // root element for the shared string part.
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ if (get_config().debug)
+ print_attrs(get_tokens(), attrs);
+
+ shared_strings_root_attr_parser func;
+ func = for_each(attrs.begin(), attrs.end(), func);
+
+ if (get_config().debug)
+ std::cout << "count: " << func.get_count() << " unique count: " << func.get_unique_count() << std::endl;
+ }
+ break;
+ case XML_si:
+ // single shared string entry.
+ m_in_segments = false;
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_sst);
+ break;
+ case XML_r:
+ // rich text run
+ m_in_segments = true;
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_si);
+ break;
+ case XML_rPr:
+ // rich text run property
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_r);
+ break;
+ case XML_b:
+ // bold
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_rPr);
+ break;
+ case XML_i:
+ // italic
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_rPr);
+ break;
+ case XML_sz:
+ {
+ // font size
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_rPr);
+ std::string_view s = for_each(attrs.begin(), attrs.end(), single_attr_getter(m_pool, NS_ooxml_xlsx, XML_val)).get_value();
+ double point = to_double(s);
+ mp_strings->set_segment_font_size(point);
+ }
+ break;
+ case XML_color:
+ {
+ // font color
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_rPr);
+
+ std::optional<std::string_view> rgb;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_rgb:
+ rgb = attr.value;
+ break;
+ case XML_theme:
+ // TODO : handle this.
+ break;
+ }
+ }
+
+ if (rgb)
+ {
+ ss::color_elem_t alpha;
+ ss::color_elem_t red;
+ ss::color_elem_t green;
+ ss::color_elem_t blue;
+ if (to_rgb(*rgb, alpha, red, green, blue))
+ mp_strings->set_segment_font_color(alpha, red, green, blue);
+ }
+ }
+ break;
+ case XML_rFont:
+ {
+ // font
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_rPr);
+ std::string_view font = for_each(attrs.begin(), attrs.end(), single_attr_getter(m_pool, NS_ooxml_xlsx, XML_val)).get_value();
+ mp_strings->set_segment_font_name(font);
+ }
+ break;
+ case XML_family:
+ // font family
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_rPr);
+ break;
+ case XML_scheme:
+ // font scheme
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_rPr);
+ break;
+ case XML_t:
+ {
+ // actual text stored as its content.
+ const xml_elem_set_t expected = {
+ { NS_ooxml_xlsx, XML_r },
+ { NS_ooxml_xlsx, XML_rPh },
+ { NS_ooxml_xlsx, XML_si },
+ };
+ xml_element_expected(parent, expected);
+ }
+ break;
+ default:
+ warn_unhandled();
+ }
+}
+
+bool xlsx_shared_strings_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ switch (name)
+ {
+ case XML_t:
+ break;
+ case XML_b:
+ mp_strings->set_segment_bold(true);
+ break;
+ case XML_i:
+ mp_strings->set_segment_italic(true);
+ break;
+ case XML_r:
+ mp_strings->append_segment(m_cur_str);
+ break;
+ case XML_si:
+ {
+ if (m_in_segments)
+ // commit all formatted segments.
+ mp_strings->commit_segments();
+ else
+ {
+ // unformatted text should only have one text segment.
+ mp_strings->append(m_cur_str);
+ }
+ }
+ break;
+ }
+ return pop_stack(ns, name);
+}
+
+void xlsx_shared_strings_context::characters(std::string_view str, bool transient)
+{
+ xml_token_pair_t cur_token = get_current_element();
+ if (cur_token.first == NS_ooxml_xlsx && cur_token.second == XML_t)
+ {
+ m_cur_str = str;
+
+ // In case the string contains carriage returns (CRs), remove them.
+ m_cell_buffer.reset();
+ const char* p = m_cur_str.data();
+ const char* p_end = p + m_cur_str.size();
+ const char* p0 = nullptr;
+
+ for (; p != p_end; ++p)
+ {
+ if (!p0)
+ p0 = p;
+
+ if (*p == 0x0D)
+ {
+ // Append the segment up to this CR, and skip the CR.
+ m_cell_buffer.append(p0, std::distance(p0, p));
+ p0 = nullptr;
+ }
+ }
+
+ if (!m_cell_buffer.empty())
+ {
+ // This string contains at least one CR.
+
+ if (p0)
+ // Append the tail end.
+ m_cell_buffer.append(p0, std::distance(p0, p));
+
+ m_cur_str = m_pool.intern(m_cell_buffer.str()).first;
+ transient = false;
+ }
+
+ if (transient)
+ m_cur_str = m_pool.intern(m_cur_str).first;
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_shared_strings_context.hpp b/src/liborcus/xlsx_shared_strings_context.hpp
new file mode 100644
index 0000000..b10d9fd
--- /dev/null
+++ b/src/liborcus/xlsx_shared_strings_context.hpp
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <orcus/spreadsheet/types.hpp>
+#include <orcus/string_pool.hpp>
+#include <orcus/cell_buffer.hpp>
+
+#include "xml_context_base.hpp"
+#include "xlsx_types.hpp"
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+ class import_shared_strings;
+}}
+
+/**
+ * Context for xl/sharedStrings.xml part.
+ */
+class xlsx_shared_strings_context : public xml_context_base
+{
+public:
+ xlsx_shared_strings_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_shared_strings* strings);
+ virtual ~xlsx_shared_strings_context();
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+
+private:
+ spreadsheet::iface::import_shared_strings* mp_strings = nullptr;
+ string_pool m_pool;
+ cell_buffer m_cell_buffer;
+ std::string_view m_cur_str;
+ bool m_in_segments;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_sheet_context.cpp b/src/liborcus/xlsx_sheet_context.cpp
new file mode 100644
index 0000000..1363c51
--- /dev/null
+++ b/src/liborcus/xlsx_sheet_context.cpp
@@ -0,0 +1,943 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_sheet_context.hpp"
+#include "xlsx_session_data.hpp"
+#include "xlsx_types.hpp"
+#include "ooxml_global.hpp"
+#include "ooxml_schemas.hpp"
+#include "ooxml_token_constants.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "xml_context_global.hpp"
+#include "orcus/exception.hpp"
+#include "orcus/spreadsheet/import_interface.hpp"
+#include "orcus/spreadsheet/import_interface_view.hpp"
+#include "orcus/measurement.hpp"
+
+#include <mdds/sorted_string_map.hpp>
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+#include <optional>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+namespace sheet_pane {
+
+using map_type = mdds::sorted_string_map<ss::sheet_pane_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "bottomLeft", ss::sheet_pane_t::bottom_left },
+ { "bottomRight", ss::sheet_pane_t::bottom_right },
+ { "topLeft", ss::sheet_pane_t::top_left },
+ { "topRight", ss::sheet_pane_t::top_right },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::sheet_pane_t::unspecified);
+ return mt;
+}
+
+}
+
+namespace pane_state {
+
+using map_type = mdds::sorted_string_map<ss::pane_state_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "frozen", ss::pane_state_t::frozen },
+ { "frozenSplit", ss::pane_state_t::frozen_split },
+ { "split", ss::pane_state_t::split },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::pane_state_t::unspecified);
+ return mt;
+}
+
+} // namespace pane_state
+
+namespace formula_type {
+
+using map_type = mdds::sorted_string_map<ss::formula_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "array", ss::formula_t::array },
+ { "dataTable", ss::formula_t::data_table },
+ { "normal", ss::formula_t::normal },
+ { "shared", ss::formula_t::shared },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::formula_t::unknown);
+ return mt;
+}
+
+} // namespace formula_type
+
+} // anonymous namespace
+
+xlsx_sheet_context::formula::formula() :
+ type(ss::formula_t::unknown),
+ str(),
+ data_table_ref1(),
+ data_table_ref2(),
+ shared_id(-1),
+ data_table_2d(false),
+ data_table_row_based(false),
+ data_table_ref1_deleted(false),
+ data_table_ref2_deleted(false)
+{
+ ref.first.column = -1;
+ ref.first.row = -1;
+ ref.last = ref.first;
+}
+
+void xlsx_sheet_context::formula::reset()
+{
+ *this = formula();
+}
+
+xlsx_sheet_context::xlsx_sheet_context(
+ session_context& session_cxt, const tokens& tokens, ss::sheet_t sheet_id,
+ ss::iface::import_reference_resolver& resolver,
+ ss::iface::import_sheet& sheet) :
+ xml_context_base(session_cxt, tokens),
+ m_resolver(resolver),
+ m_sheet(sheet),
+ m_sheet_id(sheet_id),
+ m_cur_row(-1),
+ m_cur_col(-1),
+ m_cur_cell_type(xlsx_ct_numeric),
+ m_cur_cell_xf(0),
+ m_cxt_autofilter(session_cxt, tokens, m_resolver),
+ m_cxt_cond_format(session_cxt, tokens, m_sheet.get_conditional_format())
+{
+ register_child(&m_cxt_autofilter);
+ register_child(&m_cxt_cond_format);
+
+ init_ooxml_context(*this);
+}
+
+xlsx_sheet_context::~xlsx_sheet_context()
+{
+}
+
+xml_context_base* xlsx_sheet_context::create_child_context(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xlsx && name == XML_autoFilter)
+ {
+ m_cxt_autofilter.reset();
+ return &m_cxt_autofilter;
+ }
+ else if (ns == NS_ooxml_xlsx && name == XML_conditionalFormatting)
+ {
+ m_cxt_cond_format.reset();
+ return &m_cxt_cond_format;
+ }
+ return nullptr;
+}
+
+void xlsx_sheet_context::end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child)
+{
+ if (!child)
+ return;
+
+ if (ns == NS_ooxml_xlsx && name == XML_autoFilter)
+ {
+ ss::iface::import_auto_filter* af = m_sheet.get_auto_filter();
+ if (!af)
+ return;
+
+ const xlsx_autofilter_context& cxt = static_cast<const xlsx_autofilter_context&>(*child);
+ cxt.push_to_model(*af);
+ }
+}
+
+void xlsx_sheet_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_worksheet:
+ {
+ if (get_config().debug)
+ print_attrs(get_tokens(), attrs);
+ break;
+ }
+ case XML_cols:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_worksheet);
+ break;
+ case XML_col:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_cols);
+ start_element_col(attrs);
+ break;
+ }
+ case XML_dimension:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_worksheet);
+ break;
+ case XML_mergeCells:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_worksheet);
+ break;
+ case XML_mergeCell:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_mergeCells);
+
+ ss::iface::import_sheet_properties* sheet_props = m_sheet.get_sheet_properties();
+ if (sheet_props)
+ {
+ // ref contains merged range in A1 reference style.
+ std::string_view ref = for_each(
+ attrs.begin(), attrs.end(), single_attr_getter(m_pool, NS_ooxml_xlsx, XML_ref)).get_value();
+
+ ss::src_range_t range = m_resolver.resolve_range(ref);
+ sheet_props->set_merge_cell_range(to_rc_range(range));
+ }
+ break;
+ }
+ case XML_pageMargins:
+ {
+ xml_elem_stack_t elems;
+ elems.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_worksheet));
+ elems.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_customSheetView));
+ xml_element_expected(parent, elems);
+ break;
+ }
+ case XML_sheetViews:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_worksheet);
+ break;
+ case XML_sheetView:
+ start_element_sheet_view(parent, attrs);
+ break;
+ case XML_selection:
+ start_element_selection(parent, attrs);
+ break;
+ case XML_pane:
+ start_element_pane(parent, attrs);
+ break;
+ case XML_sheetData:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_worksheet);
+ break;
+ case XML_sheetFormatPr:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_worksheet);
+ break;
+ case XML_row:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_sheetData);
+ start_element_row(attrs);
+ break;
+ }
+ case XML_c:
+ {
+ start_element_cell(parent, attrs);
+ break;
+ }
+ case XML_f:
+ start_element_formula(parent, attrs);
+ break;
+ case XML_v:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_c);
+ break;
+ case XML_tableParts:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_worksheet);
+ break;
+ case XML_tablePart:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_tableParts);
+
+ // The rid string must be pooled to the session context's string
+ // pool as it is used long after thet sheet context is deleted.
+ single_attr_getter func(get_session_context().spool, NS_ooxml_r, XML_id);
+ std::string_view rid = for_each(attrs.begin(), attrs.end(), func).get_value();
+
+ std::unique_ptr<xlsx_rel_table_info> p(new xlsx_rel_table_info);
+ p->sheet_interface = &m_sheet;
+ m_rel_extras.data.insert(
+ opc_rel_extras_t::map_type::value_type(rid, std::move(p)));
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool xlsx_sheet_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_c:
+ end_element_cell();
+ break;
+ case XML_f:
+ m_cur_formula.str = m_cur_str;
+ break;
+ case XML_v:
+ m_cur_value = m_cur_str;
+ break;
+ default:
+ ;
+ }
+ }
+
+ m_cur_str = std::string_view{};
+ return pop_stack(ns, name);
+}
+
+void xlsx_sheet_context::characters(std::string_view str, bool transient)
+{
+ m_cur_str = intern_in_context(str, transient);
+}
+
+void xlsx_sheet_context::start_element_formula(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ const xml_elem_set_t expected = {
+ { NS_ooxml_xlsx, XML_c },
+ { NS_mso_x14, XML_cfRule },
+ };
+ xml_element_expected(parent, expected);
+
+ m_cur_formula.reset();
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_t:
+ m_cur_formula.type = formula_type::get().find(attr.value);
+ break;
+ case XML_ref:
+ m_cur_formula.ref = to_rc_range(m_resolver.resolve_range(attr.value));
+ break;
+ case XML_si:
+ m_cur_formula.shared_id = to_long(attr.value);
+ break;
+ case XML_dt2D:
+ m_cur_formula.data_table_2d = to_long(attr.value) != 0;
+ break;
+ case XML_dtr:
+ m_cur_formula.data_table_row_based = to_long(attr.value) != 0;
+ break;
+ case XML_del1:
+ m_cur_formula.data_table_ref1_deleted = to_long(attr.value) != 0;
+ break;
+ case XML_del2:
+ m_cur_formula.data_table_ref2_deleted = to_long(attr.value) != 0;
+ break;
+ case XML_r1:
+ m_cur_formula.data_table_ref1 = intern_in_context(attr);
+ break;
+ case XML_r2:
+ m_cur_formula.data_table_ref2 = intern_in_context(attr);
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+void xlsx_sheet_context::start_element_sheet_view(
+ const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_sheetViews);
+
+ ss::iface::import_sheet_view* view = m_sheet.get_sheet_view();
+ if (!view)
+ return;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (!attr.ns || attr.ns == NS_ooxml_xlsx)
+ {
+ switch (attr.name)
+ {
+ case XML_tabSelected:
+ {
+ bool v = to_bool(attr.value);
+ if (v)
+ // This sheet is active.
+ view->set_sheet_active();
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ }
+}
+
+void xlsx_sheet_context::start_element_selection(
+ const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ xml_elem_stack_t elems;
+ elems.emplace_back(NS_ooxml_xlsx, XML_sheetView);
+ elems.emplace_back(NS_ooxml_xlsx, XML_customSheetView);
+ xml_element_expected(parent, elems);
+
+ ss::iface::import_sheet_view* view = m_sheet.get_sheet_view();
+ if (!view)
+ return;
+
+ // example: <selection pane="topRight" activeCell="H2" sqref="H2:L2"/>
+
+ ss::sheet_pane_t pane = ss::sheet_pane_t::unspecified;
+ ss::range_t range;
+ range.first.column = -1;
+ range.first.row = -1;
+ range.last = range.first;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (!attr.ns || attr.ns == NS_ooxml_xlsx)
+ {
+ switch (attr.name)
+ {
+ case XML_pane:
+ {
+ pane = sheet_pane::get().find(attr.value);
+ break;
+ }
+ case XML_activeCell:
+ // Single cell where the cursor is. Ignore this for now.
+ break;
+ case XML_sqref:
+ {
+ // Single cell address for a non-range cursor, or range
+ // address if a range selection is present.
+ range = to_rc_range(m_resolver.resolve_range(attr.value));
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ }
+
+ if (pane == ss::sheet_pane_t::unspecified)
+ pane = ss::sheet_pane_t::top_left;
+
+ view->set_selected_range(pane, range);
+}
+
+void xlsx_sheet_context::start_element_pane(
+ const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ xml_elem_stack_t elems;
+ elems.emplace_back(NS_ooxml_xlsx, XML_sheetView);
+ elems.emplace_back(NS_ooxml_xlsx, XML_customSheetView);
+ xml_element_expected(parent, elems);
+
+ ss::iface::import_sheet_view* view = m_sheet.get_sheet_view();
+ if (!view)
+ return;
+
+ // <pane xSplit="4" ySplit="8" topLeftCell="E9" activePane="bottomRight" state="frozen"/>
+
+ double xsplit = 0.0, ysplit = 0.0;
+ ss::address_t top_left_cell;
+ ss::sheet_pane_t active_pane = ss::sheet_pane_t::unspecified;
+ ss::pane_state_t pane_state = ss::pane_state_t::unspecified;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_xSplit:
+ xsplit = to_double(attr.value);
+ break;
+ case XML_ySplit:
+ ysplit = to_double(attr.value);
+ break;
+ case XML_topLeftCell:
+ top_left_cell = to_rc_address(m_resolver.resolve_address(attr.value));
+ break;
+ case XML_activePane:
+ active_pane = sheet_pane::get().find(attr.value);
+ break;
+ case XML_state:
+ pane_state = pane_state::get().find(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+
+ if (active_pane == ss::sheet_pane_t::unspecified)
+ active_pane = ss::sheet_pane_t::top_left;
+
+ if (pane_state == ss::pane_state_t::unspecified)
+ pane_state = ss::pane_state_t::split;
+
+ switch (pane_state)
+ {
+ case ss::pane_state_t::frozen:
+ view->set_frozen_pane(xsplit, ysplit, top_left_cell, active_pane);
+ break;
+ case ss::pane_state_t::split:
+ view->set_split_pane(xsplit, ysplit, top_left_cell, active_pane);
+ break;
+ case ss::pane_state_t::frozen_split:
+ warn("FIXME: frozen-split state not yet handled.");
+ break;
+ default:
+ ;
+ }
+}
+
+void xlsx_sheet_context::start_element_cell(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs)
+{
+ xlsx_cell_t cell_type = xlsx_ct_numeric;
+ ss::address_t address;
+ address.column = 0;
+ address.row = 0;
+ size_t xf = 0;
+ bool contains_address = false;
+
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_row);
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_r:
+ // cell address in A1 notation.
+ address = to_rc_address(
+ m_resolver.resolve_address(attr.value));
+
+ contains_address = true;
+ break;
+ case XML_t:
+ // cell type
+ cell_type = to_xlsx_cell_type(attr.value);
+ break;
+ case XML_s:
+ // cell style
+ xf = to_long(attr.value);
+ break;
+ }
+ }
+
+ if (contains_address)
+ {
+ if (m_cur_row != address.row)
+ {
+ std::ostringstream os;
+ os << "row numbers differ! (current=" << m_cur_row << ")";
+ throw xml_structure_error(os.str());
+ }
+
+ m_cur_col = address.column;
+ }
+ else
+ {
+ ++m_cur_col;
+ }
+
+ m_cur_cell_type = cell_type;
+ m_cur_cell_xf = xf;
+}
+
+void xlsx_sheet_context::start_element_col(const xml_token_attrs_t& attrs)
+{
+ long col_min = 0; // 1-based
+ long col_max = 0; // 1-based
+ bool col_hidden = false;
+ std::optional<double> col_width;
+ std::optional<std::size_t> xfid;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.value.empty())
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_min:
+ col_min = to_long(attr.value);
+ break;
+ case XML_max:
+ col_max = to_long(attr.value);
+ break;
+ case XML_width:
+ col_width = to_double(attr.value);
+ break;
+ case XML_hidden:
+ col_hidden = to_long(attr.value);
+ break;
+ case XML_style:
+ xfid = to_long(attr.value);
+ break;
+ }
+ }
+
+ if (!col_min || !col_max || col_min > col_max)
+ {
+ std::ostringstream os;
+ os << "column element has invalid column indices: (min=" << col_min << "; max=" << col_max << ")";
+ warn(os.str());
+ return;
+ }
+
+ if (xfid)
+ m_sheet.set_column_format(col_min - 1, col_max - col_min + 1, *xfid);
+
+ ss::iface::import_sheet_properties* sheet_props = m_sheet.get_sheet_properties();
+ if (sheet_props)
+ {
+ if (col_width)
+ sheet_props->set_column_width(
+ col_min - 1, col_max - col_min + 1, *col_width, length_unit_t::xlsx_column_digit);
+
+ sheet_props->set_column_hidden(col_min - 1, col_max - col_min + 1, col_hidden);
+ }
+}
+
+void xlsx_sheet_context::start_element_row(const xml_token_attrs_t& attrs)
+{
+ std::optional<ss::row_t> row;
+ length_t height;
+ bool hidden = false;
+ bool custom_format = false;
+ std::optional<std::size_t> xfid;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_r:
+ {
+ // row index
+ long this_row = to_long(attr.value);
+ if (!this_row)
+ throw xml_structure_error("row number can never be zero!");
+
+ this_row -= 1; // from 1-based to 0-based.
+ row = this_row;
+ break;
+ }
+ case XML_ht:
+ {
+ height.value = to_double(attr.value);
+ height.unit = length_unit_t::point;
+ break;
+ }
+ case XML_hidden:
+ hidden = to_long(attr.value) != 0;
+ break;
+ case XML_s:
+ xfid = to_long(attr.value);
+ break;
+ case XML_customFormat:
+ custom_format = to_bool(attr.value);
+ break;
+ }
+ }
+
+ if (row)
+ m_cur_row = *row;
+ else
+ ++m_cur_row;
+
+ m_cur_col = -1;
+
+ if (custom_format && xfid)
+ // The specs say we only honor this style id only when the custom format is set.
+ m_sheet.set_row_format(m_cur_row, *xfid);
+
+ ss::iface::import_sheet_properties* sheet_props = m_sheet.get_sheet_properties();
+ if (sheet_props)
+ {
+ if (height.unit != length_unit_t::unknown)
+ sheet_props->set_row_height(m_cur_row, height.value, height.unit);
+
+ sheet_props->set_row_hidden(m_cur_row, hidden);
+ }
+}
+
+void xlsx_sheet_context::end_element_cell()
+{
+ session_context& cxt = get_session_context();
+ auto& session_data = cxt.get_data<xlsx_session_data>();
+
+ bool array_formula_result = handle_array_formula_result(session_data);
+
+ if (array_formula_result)
+ {
+ // Do nothing.
+ }
+ else if (!m_cur_formula.str.empty())
+ {
+ if (m_cur_formula.type == ss::formula_t::shared && m_cur_formula.shared_id >= 0)
+ {
+ // shared formula expression
+ session_data.m_shared_formulas.push_back(
+ std::make_unique<xlsx_session_data::shared_formula>(
+ m_sheet_id, m_cur_row, m_cur_col, m_cur_formula.shared_id,
+ m_cur_formula.str
+ )
+ );
+
+ xlsx_session_data::shared_formula& f = *session_data.m_shared_formulas.back();
+ push_raw_cell_result(f.result, session_data);
+ }
+ else if (m_cur_formula.type == ss::formula_t::array)
+ {
+ // array formula expression
+ session_data.m_array_formulas.push_back(
+ std::make_unique<xlsx_session_data::array_formula>(
+ m_sheet_id, m_cur_formula.ref, m_cur_formula.str
+ )
+ );
+
+ xlsx_session_data::array_formula& af = *session_data.m_array_formulas.back();
+ push_raw_cell_result(*af.results, 0, 0, session_data);
+ m_array_formula_results.push_back(std::make_pair(m_cur_formula.ref, af.results));
+ }
+ else
+ {
+ // normal (non-shared) formula expression
+ session_data.m_formulas.push_back(
+ std::make_unique<xlsx_session_data::formula>(
+ m_sheet_id, m_cur_row, m_cur_col, m_cur_formula.str
+ )
+ );
+
+ xlsx_session_data::formula& f = *session_data.m_formulas.back();
+ push_raw_cell_result(f.result, session_data);
+ }
+ }
+ else if (m_cur_formula.type == ss::formula_t::shared && m_cur_formula.shared_id >= 0)
+ {
+ // shared formula without formula expression
+ session_data.m_shared_formulas.push_back(
+ std::make_unique<xlsx_session_data::shared_formula>(
+ m_sheet_id, m_cur_row, m_cur_col, m_cur_formula.shared_id));
+
+ xlsx_session_data::shared_formula& f = *session_data.m_shared_formulas.back();
+ push_raw_cell_result(f.result, session_data);
+ }
+ else if (m_cur_formula.type == ss::formula_t::data_table)
+ {
+ // Import data table.
+ ss::iface::import_data_table* dt = m_sheet.get_data_table();
+ if (dt)
+ {
+ if (m_cur_formula.data_table_2d)
+ {
+ dt->set_type(ss::data_table_type_t::both);
+ dt->set_range(m_cur_formula.ref);
+ dt->set_first_reference(
+ m_cur_formula.data_table_ref1,
+ m_cur_formula.data_table_ref1_deleted);
+ dt->set_second_reference(
+ m_cur_formula.data_table_ref2,
+ m_cur_formula.data_table_ref2_deleted);
+ }
+ else if (m_cur_formula.data_table_row_based)
+ {
+ dt->set_type(ss::data_table_type_t::row);
+ dt->set_range(m_cur_formula.ref);
+ dt->set_first_reference(
+ m_cur_formula.data_table_ref1,
+ m_cur_formula.data_table_ref1_deleted);
+ }
+ else
+ {
+ dt->set_type(ss::data_table_type_t::column);
+ dt->set_range(m_cur_formula.ref);
+ dt->set_first_reference(
+ m_cur_formula.data_table_ref1,
+ m_cur_formula.data_table_ref1_deleted);
+ }
+ dt->commit();
+ }
+
+ push_raw_cell_value();
+ }
+ else if (!m_cur_value.empty())
+ {
+ push_raw_cell_value();
+ }
+
+ if (m_cur_cell_xf)
+ m_sheet.set_format(m_cur_row, m_cur_col, m_cur_cell_xf);
+
+ // reset cell related parameters.
+ m_cur_value = std::string_view{};
+ m_cur_formula.reset();
+ m_cur_cell_xf = 0;
+ m_cur_cell_type = xlsx_ct_numeric;
+}
+
+void xlsx_sheet_context::push_raw_cell_value()
+{
+ if (m_cur_value.empty())
+ return;
+
+ switch (m_cur_cell_type)
+ {
+ case xlsx_ct_shared_string:
+ {
+ // string cell
+ size_t str_id = to_long(m_cur_value);
+ m_sheet.set_string(m_cur_row, m_cur_col, str_id);
+ }
+ break;
+ case xlsx_ct_numeric:
+ {
+ // value cell
+ double val = to_double(m_cur_value);
+ m_sheet.set_value(m_cur_row, m_cur_col, val);
+ }
+ break;
+ case xlsx_ct_boolean:
+ {
+ // boolean cell
+ bool val = to_long(m_cur_value) != 0;
+ m_sheet.set_bool(m_cur_row, m_cur_col, val);
+ }
+ break;
+ default:
+ warn("unhanlded cell content type");
+ }
+}
+
+void xlsx_sheet_context::push_raw_cell_result(
+ range_formula_results& res, size_t row_offset, size_t col_offset, xlsx_session_data& /*session_data*/) const
+{
+ if (m_cur_value.empty())
+ return;
+
+ switch (m_cur_cell_type)
+ {
+ case xlsx_ct_numeric:
+ {
+ // value cell
+ double val = to_double(m_cur_value);
+ res.set(row_offset, col_offset, val);
+ break;
+ }
+ case xlsx_ct_boolean:
+ {
+ // boolean cell
+ bool val = to_long(m_cur_value) != 0;
+ res.set(row_offset, col_offset, val);
+ break;
+ }
+ default:
+ warn("unhanlded cell content type");
+ }
+}
+
+void xlsx_sheet_context::push_raw_cell_result(formula_result& res, xlsx_session_data& session_data) const
+{
+ switch (m_cur_cell_type)
+ {
+ case xlsx_ct_numeric:
+ res.type = formula_result::result_type::numeric;
+ res.value_numeric = to_double(m_cur_value);
+ break;
+ case xlsx_ct_formula_string:
+ {
+ std::string_view interned = session_data.m_formula_result_strings.intern(m_cur_value).first;
+ res.type = formula_result::result_type::string;
+ res.value_string.p = interned.data();
+ res.value_string.n = interned.size();
+ break;
+ }
+ default:
+ {
+ std::ostringstream os;
+ os << "unhandled cached formula result (type=" << m_cur_cell_type << ")";
+ warn(os.str().data());
+ }
+ }
+}
+
+bool xlsx_sheet_context::handle_array_formula_result(xlsx_session_data& session_data)
+{
+ // See if the current cell is within an array formula range.
+ auto it = m_array_formula_results.begin(), ite = m_array_formula_results.end();
+
+ while (it != ite)
+ {
+ const ss::range_t& ref = it->first;
+
+ if (ref.last.row < m_cur_row)
+ {
+ // If this result range lies above the current row, delete it as
+ // we no longer have use for it.
+
+ m_array_formula_results.erase(it++);
+ continue;
+ }
+
+ if (m_cur_col < ref.first.column || ref.last.column < m_cur_col || m_cur_row < ref.first.row || ref.last.row < m_cur_row)
+ {
+ // This cell is not within this array formula range. Move on to
+ // the next one.
+ ++it;
+ continue;
+ }
+
+ size_t row_offset = m_cur_row - ref.first.row;
+ size_t col_offset = m_cur_col - ref.first.column;
+ range_formula_results& res = *it->second;
+ push_raw_cell_result(res, row_offset, col_offset, session_data);
+
+ return true;
+ }
+
+ return false;
+}
+
+std::string_view xlsx_sheet_context::intern_in_context(const xml_token_attr_t& attr)
+{
+ return intern_in_context(attr.value, attr.transient);
+}
+
+std::string_view xlsx_sheet_context::intern_in_context(const std::string_view& str, bool transient)
+{
+ if (transient)
+ return m_pool.intern(str).first;
+
+ return str;
+}
+
+void xlsx_sheet_context::pop_rel_extras(opc_rel_extras_t& other)
+{
+ m_rel_extras.swap(other);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_sheet_context.hpp b/src/liborcus/xlsx_sheet_context.hpp
new file mode 100644
index 0000000..c91382d
--- /dev/null
+++ b/src/liborcus/xlsx_sheet_context.hpp
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLSX_SHEET_CONTEXT_HPP
+#define ORCUS_XLSX_SHEET_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "ooxml_types.hpp"
+#include "xlsx_types.hpp"
+#include "xlsx_autofilter_context.hpp"
+#include "xlsx_conditional_format_context.hpp"
+
+#include "orcus/spreadsheet/types.hpp"
+#include "orcus/string_pool.hpp"
+
+#include <list>
+
+namespace orcus {
+
+struct session_context;
+struct formula_result;
+struct xlsx_session_data;
+class range_formula_results;
+
+namespace spreadsheet { namespace iface {
+
+class import_sheet;
+class import_reference_resolver;
+
+}}
+
+/**
+ * Top-level context for xl/worksheets/sheet<num>.xml.
+ */
+class xlsx_sheet_context : public xml_context_base
+{
+public:
+
+ struct formula
+ {
+ spreadsheet::formula_t type;
+ spreadsheet::range_t ref; /// formula reference range
+ std::string_view str; /// formula expression string
+ std::string_view data_table_ref1;
+ std::string_view data_table_ref2;
+ int shared_id;
+ bool data_table_2d:1;
+ bool data_table_row_based:1;
+ bool data_table_ref1_deleted:1;
+ bool data_table_ref2_deleted:1;
+ formula();
+
+ void reset();
+ };
+
+ using array_formula_pair_type = std::pair<spreadsheet::range_t, std::shared_ptr<range_formula_results>>;
+ using array_formula_results_type = std::list<array_formula_pair_type>;
+
+ xlsx_sheet_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::sheet_t sheet_id,
+ spreadsheet::iface::import_reference_resolver& resolver,
+ spreadsheet::iface::import_sheet& sheet);
+ virtual ~xlsx_sheet_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+
+ void pop_rel_extras(opc_rel_extras_t& other);
+
+private:
+ void start_element_formula(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void start_element_sheet_view(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void start_element_selection(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void start_element_pane(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void start_element_cell(const xml_token_pair_t& parent, const xml_token_attrs_t& attrs);
+ void start_element_col(const xml_token_attrs_t& attrs);
+ void start_element_row(const xml_token_attrs_t& attrs);
+
+ void end_element_cell();
+ void push_raw_cell_value();
+ void push_raw_cell_result(range_formula_results& res, size_t row_offset, size_t col_offset, xlsx_session_data& session_data) const;
+ void push_raw_cell_result(formula_result& res, xlsx_session_data& session_data) const;
+
+ /**
+ * See if the current cell is a part of an array formula, and if so, store
+ * its value as a cached result.
+ *
+ * @return true if this is part of an array formula, false otherwise.
+ */
+ bool handle_array_formula_result(xlsx_session_data& session_data);
+
+ /**
+ * Potentially intern a transient attribute string value for the duration
+ * of the current sheet context.
+ */
+ std::string_view intern_in_context(const xml_token_attr_t& attr);
+
+ /**
+ * Potentially intern a transient string value for the duration of the
+ * current sheet context.
+ */
+ std::string_view intern_in_context(const std::string_view& str, bool transient);
+
+private:
+ spreadsheet::iface::import_reference_resolver& m_resolver;
+ spreadsheet::iface::import_sheet& m_sheet; /// sheet model instance for the loaded document.
+ string_pool m_pool;
+ spreadsheet::sheet_t m_sheet_id; /// ID of this sheet.
+ spreadsheet::row_t m_cur_row;
+ spreadsheet::col_t m_cur_col;
+ xlsx_cell_t m_cur_cell_type;
+ size_t m_cur_cell_xf;
+ std::string_view m_cur_str;
+ std::string_view m_cur_value;
+ formula m_cur_formula;
+
+ array_formula_results_type m_array_formula_results;
+
+ /**
+ * Extra data to pass on to subsequent parts via relations.
+ */
+ opc_rel_extras_t m_rel_extras;
+
+ xlsx_autofilter_context m_cxt_autofilter;
+ xlsx_conditional_format_context m_cxt_cond_format;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_sheet_context_test.cpp b/src/liborcus/xlsx_sheet_context_test.cpp
new file mode 100644
index 0000000..20492b5
--- /dev/null
+++ b/src/liborcus/xlsx_sheet_context_test.cpp
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include "mock_spreadsheet.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "ooxml_tokens.hpp"
+#include "ooxml_schemas.hpp"
+#include "xlsx_sheet_context.hpp"
+#include "ooxml_token_constants.hpp"
+#include "xlsx_session_data.hpp"
+#include "orcus/types.hpp"
+#include "orcus/config.hpp"
+
+using namespace orcus;
+using namespace std;
+using namespace orcus::spreadsheet;
+using namespace orcus::spreadsheet::mock;
+
+namespace {
+
+class mock_ref_resolver : public import_reference_resolver
+{
+ virtual src_address_t resolve_address(std::string_view) override
+ {
+ src_address_t ret;
+ ret.sheet = 0;
+ ret.row = 0;
+ ret.column = 0;
+
+ return ret;
+ }
+
+ virtual src_range_t resolve_range(std::string_view) override
+ {
+ src_range_t ret;
+ ret.first.sheet = 0;
+ ret.first.row = 0;
+ ret.first.column = 0;
+ ret.last.sheet = 0;
+ ret.last.row = 0;
+ ret.last.column = 0;
+
+ return ret;
+ }
+};
+
+class mock_array_formula : public import_array_formula
+{
+public:
+ virtual void set_range(const range_t& range) override
+ {
+ assert(range.first.row == 2);
+ assert(range.first.column == 1);
+ assert(range.last.row == 3);
+ assert(range.last.column == 1);
+ }
+
+ virtual void set_formula(formula_grammar_t grammar, std::string_view formula) override
+ {
+ assert(grammar == formula_grammar_t::xlsx);
+ assert(formula == "A1:A2");
+ }
+
+ virtual void set_result_bool(row_t, col_t, bool) override
+ {
+ }
+
+ virtual void set_result_empty(row_t, col_t) override
+ {
+ }
+
+ virtual void set_result_string(row_t, col_t, std::string_view) override
+ {
+ }
+
+ virtual void set_result_value(row_t, col_t, double) override
+ {
+ }
+
+ virtual void commit() override
+ {
+ }
+};
+
+class mock_sheet : public import_sheet
+{
+ mock_array_formula m_array_formula;
+
+public:
+ virtual void set_value(row_t row, col_t col, double val) override
+ {
+ assert(row == -1);
+ assert(col == 0);
+ assert(val == 5.0);
+ }
+
+ virtual void set_bool(row_t row, col_t col, bool val) override
+ {
+ assert(row == -1);
+ assert(col == 0);
+ assert(val == true);
+ }
+
+ virtual iface::import_array_formula* get_array_formula() override
+ {
+ return &m_array_formula;
+ }
+};
+
+class mock_sheet_properties : public import_sheet_properties
+{
+public:
+ void set_column_hidden(col_t col, col_t col_span, bool hidden)
+ {
+ assert(col == 1);
+ assert(col_span == 1);
+ assert(hidden);
+ }
+
+ void set_row_hidden(row_t row, bool hidden)
+ {
+ assert(row == 3);
+ assert(hidden);
+ }
+};
+
+class mock_sheet2 : public import_sheet
+{
+public:
+ virtual import_sheet_properties* get_sheet_properties()
+ {
+ return &m_sheet_prop;
+ }
+
+private:
+ mock_sheet_properties m_sheet_prop;
+};
+
+void test_cell_value()
+{
+ mock_sheet sheet;
+ mock_ref_resolver resolver;
+ session_context cxt(std::make_unique<xlsx_session_data>());
+ config opt(format_t::xlsx);
+ opt.structure_check = false;
+
+ orcus::xlsx_sheet_context context(cxt, orcus::ooxml_tokens, 0, resolver, sheet);
+ context.set_config(opt);
+
+ orcus::xmlns_id_t ns = NS_ooxml_xlsx;
+ orcus::xml_token_t elem = XML_c;
+ orcus::xml_token_attrs_t attrs;
+ context.start_element(ns, elem, attrs);
+
+ {
+ xml_token_attrs_t val_attrs;
+ context.start_element(ns, XML_v, val_attrs);
+ context.characters("5", false);
+ context.end_element(ns, XML_v);
+ }
+
+ context.end_element(ns, elem);
+}
+
+void test_cell_bool()
+{
+ mock_sheet sheet;
+ mock_ref_resolver resolver;
+ session_context cxt(std::make_unique<xlsx_session_data>());
+ config opt(format_t::xlsx);
+ opt.structure_check = false;
+
+ orcus::xlsx_sheet_context context(cxt, orcus::ooxml_tokens, 0, resolver, sheet);
+ context.set_config(opt);
+
+ orcus::xmlns_id_t ns = NS_ooxml_xlsx;
+ orcus::xml_token_t elem = XML_c;
+ orcus::xml_token_attrs_t attrs;
+ attrs.push_back(xml_token_attr_t(NS_ooxml_xlsx, XML_t, "b", false));
+ context.start_element(ns, elem, attrs);
+
+ {
+ xml_token_attrs_t val_attrs;
+ context.start_element(ns, XML_v, val_attrs);
+ context.characters("1", false);
+ context.end_element(ns, XML_v);
+ }
+
+ context.end_element(ns, elem);
+}
+
+void test_array_formula()
+{
+ mock_sheet sheet;
+ mock_ref_resolver resolver;
+ session_context cxt(std::make_unique<xlsx_session_data>());
+ config opt(format_t::xlsx);
+ opt.structure_check = false;
+
+ orcus::xlsx_sheet_context context(cxt, orcus::ooxml_tokens, 0, resolver, sheet);
+ context.set_config(opt);
+
+ orcus::xmlns_id_t ns = NS_ooxml_xlsx;
+ orcus::xml_token_t elem = XML_c;
+ orcus::xml_token_attrs_t attrs;
+ context.start_element(ns, elem, attrs);
+
+ {
+ xml_token_attrs_t formula_attrs;
+ formula_attrs.push_back(xml_token_attr_t(NS_ooxml_xlsx, XML_t, "array", false));
+ formula_attrs.push_back(xml_token_attr_t(NS_ooxml_xlsx, XML_ref, "B3:B4", false));
+ context.start_element(ns, XML_f, formula_attrs);
+ context.characters("A1:A2", false);
+ context.end_element(ns, XML_f);
+ }
+ {
+ xml_token_attrs_t val_attrs;
+ context.start_element(ns, XML_v, val_attrs);
+ context.characters("5", false);
+ context.end_element(ns, XML_v);
+ }
+
+ context.end_element(ns, elem);
+}
+
+void test_hidden_col()
+{
+ mock_sheet2 sheet;
+ mock_ref_resolver resolver;
+ session_context cxt(std::make_unique<xlsx_session_data>());
+ config opt(format_t::xlsx);
+ opt.structure_check = false;
+
+ orcus::xlsx_sheet_context context(cxt, orcus::ooxml_tokens, 0, resolver, sheet);
+ context.set_config(opt);
+
+ orcus::xmlns_id_t ns = NS_ooxml_xlsx;
+ orcus::xml_token_t elem = XML_col;
+ orcus::xml_token_attrs_t attrs;
+ attrs.push_back(orcus::xml_token_attr_t(ns, XML_min, "2", false));
+ attrs.push_back(orcus::xml_token_attr_t(ns, XML_max, "2", false));
+ attrs.push_back(orcus::xml_token_attr_t(ns, XML_hidden, "1", false));
+ context.start_element(ns, elem, attrs);
+ context.end_element(ns, elem);
+}
+
+void test_hidden_row()
+{
+ mock_sheet2 sheet;
+ mock_ref_resolver resolver;
+ session_context cxt(std::make_unique<xlsx_session_data>());
+ config opt(format_t::xlsx);
+ opt.structure_check = false;
+
+ orcus::xlsx_sheet_context context(cxt, orcus::ooxml_tokens, 0, resolver, sheet);
+ context.set_config(opt);
+
+ orcus::xmlns_id_t ns = NS_ooxml_xlsx;
+ orcus::xml_token_t elem = XML_row;
+ orcus::xml_token_attrs_t attrs;
+ attrs.push_back(orcus::xml_token_attr_t(ns, XML_r, "4", false));
+ attrs.push_back(orcus::xml_token_attr_t(ns, XML_hidden, "1", false));
+ context.start_element(ns, elem, attrs);
+ context.end_element(ns, elem);
+}
+
+}
+
+int main()
+{
+ test_cell_value();
+ test_cell_bool();
+ test_array_formula();
+ test_hidden_col();
+ test_hidden_row();
+ return 0;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_styles_context.cpp b/src/liborcus/xlsx_styles_context.cpp
new file mode 100644
index 0000000..29454b1
--- /dev/null
+++ b/src/liborcus/xlsx_styles_context.cpp
@@ -0,0 +1,1055 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_styles_context.hpp"
+#include "impl_utils.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "ooxml_token_constants.hpp"
+#include "xlsx_helper.hpp"
+#include "xml_context_global.hpp"
+
+#include <orcus/tokens.hpp>
+#include <orcus/measurement.hpp>
+#include <orcus/spreadsheet/import_interface_styles.hpp>
+
+#include <mdds/sorted_string_map.hpp>
+#include <mdds/global.hpp>
+
+#include <optional>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+namespace border_style {
+
+using map_type = mdds::sorted_string_map<ss::border_style_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "dashDot", ss::border_style_t::dash_dot },
+ { "dashDotDot", ss::border_style_t::dash_dot_dot },
+ { "dashed", ss::border_style_t::dashed },
+ { "dotted", ss::border_style_t::dotted },
+ { "double", ss::border_style_t::double_border },
+ { "hair", ss::border_style_t::hair },
+ { "medium", ss::border_style_t::medium },
+ { "mediumDashDot", ss::border_style_t::medium_dash_dot },
+ { "mediumDashDotDot", ss::border_style_t::medium_dash_dot_dot },
+ { "mediumDashed", ss::border_style_t::medium_dashed },
+ { "none", ss::border_style_t::none },
+ { "slantDashDot", ss::border_style_t::slant_dash_dot },
+ { "thick", ss::border_style_t::thick },
+ { "thin", ss::border_style_t::thin }
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::border_style_t::none);
+ return mt;
+}
+
+} // border_style namespace
+
+namespace fill_pattern {
+
+using map_type = mdds::sorted_string_map<ss::fill_pattern_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "darkDown", ss::fill_pattern_t::dark_down },
+ { "darkGray", ss::fill_pattern_t::dark_gray },
+ { "darkGrid", ss::fill_pattern_t::dark_grid },
+ { "darkHorizontal", ss::fill_pattern_t::dark_horizontal },
+ { "darkTrellis", ss::fill_pattern_t::dark_trellis },
+ { "darkUp", ss::fill_pattern_t::dark_up },
+ { "darkVertical", ss::fill_pattern_t::dark_vertical },
+ { "gray0625", ss::fill_pattern_t::gray_0625 },
+ { "gray125", ss::fill_pattern_t::gray_125 },
+ { "lightDown", ss::fill_pattern_t::light_down },
+ { "lightGray", ss::fill_pattern_t::light_gray },
+ { "lightGrid", ss::fill_pattern_t::light_grid },
+ { "lightHorizontal", ss::fill_pattern_t::light_horizontal },
+ { "lightTrellis", ss::fill_pattern_t::light_trellis },
+ { "lightUp", ss::fill_pattern_t::light_up },
+ { "lightVertical", ss::fill_pattern_t::light_vertical },
+ { "mediumGray", ss::fill_pattern_t::medium_gray },
+ { "none", ss::fill_pattern_t::none },
+ { "solid", ss::fill_pattern_t::solid },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::fill_pattern_t::none);
+ return mt;
+}
+
+} // fill_pattern namespace
+
+namespace underline {
+
+using map_type = mdds::sorted_string_map<ss::underline_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "double", ss::underline_t::double_line },
+ { "doubleAccounting", ss::underline_t::double_accounting },
+ { "none", ss::underline_t::none },
+ { "single", ss::underline_t::single_line },
+ { "singleAccounting", ss::underline_t::single_accounting },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), ss::underline_t::none);
+ return mt;
+}
+
+} // namespace underline
+
+class border_attr_parser
+{
+ ss::border_direction_t m_dir;
+ ss::iface::import_border_style& m_border_style;
+public:
+ border_attr_parser(ss::border_direction_t dir, ss::iface::import_border_style& style) :
+ m_dir(dir), m_border_style(style) {}
+
+ void operator() (const xml_token_attr_t& attr)
+ {
+ switch (attr.name)
+ {
+ case XML_style:
+ {
+ m_border_style.set_style(m_dir,
+ border_style::get().find(attr.value.data(), attr.value.size()));
+ break;
+ }
+ }
+ }
+};
+
+std::optional<std::size_t> extract_count(const xml_token_attrs_t& attrs)
+{
+ std::optional<std::size_t> count;
+
+ for (const auto& attr : attrs)
+ {
+ if (attr.ns)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_count:
+ {
+ const char* p_end = nullptr;
+ long v = to_long(attr.value, &p_end);
+ if (attr.value.data() < p_end && v >= 0)
+ count = v;
+ break;
+ }
+ }
+ }
+
+ return count;
+}
+
+} // anonymous namespace
+
+xlsx_styles_context::xlsx_styles_context(session_context& session_cxt, const tokens& tokens, ss::iface::import_styles* styles) :
+ xml_context_base(session_cxt, tokens),
+ mp_styles(styles),
+ m_diagonal_up(false), m_diagonal_down(false),
+ m_cur_border_dir(ss::border_direction_t::unknown)
+{
+ static const xml_element_validator::rule rules[] = {
+ // parent element -> child element
+ { XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN, NS_ooxml_xlsx, XML_styleSheet }, // root element
+ { NS_ooxml_xlsx, XML_border, NS_ooxml_xlsx, XML_bottom },
+ { NS_ooxml_xlsx, XML_border, NS_ooxml_xlsx, XML_diagonal },
+ { NS_ooxml_xlsx, XML_border, NS_ooxml_xlsx, XML_left },
+ { NS_ooxml_xlsx, XML_border, NS_ooxml_xlsx, XML_right },
+ { NS_ooxml_xlsx, XML_border, NS_ooxml_xlsx, XML_top },
+ { NS_ooxml_xlsx, XML_borders, NS_ooxml_xlsx, XML_border },
+ { NS_ooxml_xlsx, XML_bottom, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_cellStyleXfs, NS_ooxml_xlsx, XML_xf },
+ { NS_ooxml_xlsx, XML_cellStyles, NS_ooxml_xlsx, XML_cellStyle },
+ { NS_ooxml_xlsx, XML_cellXfs, NS_ooxml_xlsx, XML_xf },
+ { NS_ooxml_xlsx, XML_diagonal, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_dx, NS_ooxml_xlsx, XML_fill },
+ { NS_ooxml_xlsx, XML_dxf, NS_ooxml_xlsx, XML_alignment },
+ { NS_ooxml_xlsx, XML_dxf, NS_ooxml_xlsx, XML_border },
+ { NS_ooxml_xlsx, XML_dxf, NS_ooxml_xlsx, XML_font },
+ { NS_ooxml_xlsx, XML_dxf, NS_ooxml_xlsx, XML_numFmt },
+ { NS_ooxml_xlsx, XML_dxf, NS_ooxml_xlsx, XML_protection },
+ { NS_ooxml_xlsx, XML_end, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_fill, NS_ooxml_xlsx, XML_patternFill },
+ { NS_ooxml_xlsx, XML_fills, NS_ooxml_xlsx, XML_fill },
+ { NS_ooxml_xlsx, XML_font, NS_ooxml_xlsx, XML_b },
+ { NS_ooxml_xlsx, XML_font, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_font, NS_ooxml_xlsx, XML_family },
+ { NS_ooxml_xlsx, XML_font, NS_ooxml_xlsx, XML_i },
+ { NS_ooxml_xlsx, XML_font, NS_ooxml_xlsx, XML_name },
+ { NS_ooxml_xlsx, XML_font, NS_ooxml_xlsx, XML_scheme },
+ { NS_ooxml_xlsx, XML_font, NS_ooxml_xlsx, XML_sz },
+ { NS_ooxml_xlsx, XML_font, NS_ooxml_xlsx, XML_u },
+ { NS_ooxml_xlsx, XML_fonts, NS_ooxml_xlsx, XML_font },
+ { NS_ooxml_xlsx, XML_horizontal, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_left, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_mruColors, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_numFmts, NS_ooxml_xlsx, XML_numFmt },
+ { NS_ooxml_xlsx, XML_patternFill, NS_ooxml_xlsx, XML_bgColor },
+ { NS_ooxml_xlsx, XML_patternFill, NS_ooxml_xlsx, XML_fgColor },
+ { NS_ooxml_xlsx, XML_right, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_start, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_stop, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_styleSheet, NS_ooxml_xlsx, XML_borders },
+ { NS_ooxml_xlsx, XML_styleSheet, NS_ooxml_xlsx, XML_cellStyleXfs },
+ { NS_ooxml_xlsx, XML_styleSheet, NS_ooxml_xlsx, XML_cellStyles },
+ { NS_ooxml_xlsx, XML_styleSheet, NS_ooxml_xlsx, XML_cellXfs },
+ { NS_ooxml_xlsx, XML_styleSheet, NS_ooxml_xlsx, XML_dxfs },
+ { NS_ooxml_xlsx, XML_styleSheet, NS_ooxml_xlsx, XML_fills },
+ { NS_ooxml_xlsx, XML_styleSheet, NS_ooxml_xlsx, XML_fonts },
+ { NS_ooxml_xlsx, XML_styleSheet, NS_ooxml_xlsx, XML_numFmts },
+ { NS_ooxml_xlsx, XML_top, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_vertical, NS_ooxml_xlsx, XML_color },
+ { NS_ooxml_xlsx, XML_xf, NS_ooxml_xlsx, XML_alignment },
+ { NS_ooxml_xlsx, XML_xf, NS_ooxml_xlsx, XML_protection },
+ };
+
+ init_element_validator(rules, std::size(rules));
+}
+
+xlsx_styles_context::~xlsx_styles_context() = default;
+
+void xlsx_styles_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_styleSheet:
+ {
+ // root element
+ if (get_config().debug)
+ print_attrs(get_tokens(), attrs);
+ break;
+ }
+ case XML_fonts:
+ {
+ std::string_view ps = for_each(
+ attrs.begin(), attrs.end(), single_attr_getter(m_pool, NS_ooxml_xlsx, XML_count)).get_value();
+ size_t font_count = to_long(ps);
+ mp_styles->set_font_count(font_count);
+ m_font_ids.reserve(font_count);
+ break;
+ }
+ case XML_font:
+ {
+ mp_font = mp_styles->start_font_style();
+ ENSURE_INTERFACE(mp_font, import_font_style);
+ break;
+ }
+ case XML_b:
+ assert(mp_font);
+ mp_font->set_bold(true);
+ break;
+ case XML_i:
+ assert(mp_font);
+ mp_font->set_italic(true);
+ break;
+ case XML_u:
+ {
+ assert(mp_font);
+ ss::underline_t v = ss::underline_t::single_line; // default value
+
+ for (const auto& attr : attrs)
+ {
+ switch (name)
+ {
+ case XML_val:
+ v = underline::get().find(attr.value);
+ break;
+ }
+ }
+
+ mp_font->set_underline(v);
+ break;
+ }
+ case XML_sz:
+ {
+ assert(mp_font);
+ std::optional<double> font_size;
+
+ for (const auto& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_val:
+ {
+ const char* p_end = nullptr;
+ double v = to_double(attr.value, &p_end);
+ if (attr.value.data() < p_end)
+ font_size = v;
+ break;
+ }
+ }
+ }
+
+ if (font_size)
+ mp_font->set_size(*font_size);
+
+ break;
+ }
+ case XML_color:
+ {
+ if (parent.first == NS_ooxml_xlsx)
+ {
+ switch (parent.second)
+ {
+ case XML_top:
+ case XML_bottom:
+ case XML_left:
+ case XML_right:
+ case XML_diagonal:
+ // This color is for a border.
+ start_border_color(attrs);
+ break;
+ case XML_font:
+ start_font_color(attrs);
+ default:
+ ;
+ }
+ }
+ break;
+ }
+ case XML_name:
+ {
+ std::string_view ps = for_each(
+ attrs.begin(), attrs.end(), single_attr_getter(m_pool, NS_ooxml_xlsx, XML_val)).get_value();
+ mp_font->set_name(ps);
+ break;
+ }
+ case XML_fills:
+ {
+ std::string_view ps = for_each(
+ attrs.begin(), attrs.end(), single_attr_getter(m_pool, NS_ooxml_xlsx, XML_count)).get_value();
+ size_t fill_count = to_long(ps);
+ mp_styles->set_fill_count(fill_count);
+ m_fill_ids.reserve(fill_count);
+ break;
+ }
+ case XML_fill:
+ {
+ mp_fill = mp_styles->start_fill_style();
+ ENSURE_INTERFACE(mp_fill, import_fill_style);
+
+ break;
+ }
+ case XML_patternFill:
+ {
+ std::string_view ps = for_each(
+ attrs.begin(), attrs.end(), single_attr_getter(m_pool, NS_ooxml_xlsx, XML_patternType)).get_value();
+ assert(mp_fill);
+ mp_fill->set_pattern_type(fill_pattern::get().find(ps.data(), ps.size()));
+ break;
+ }
+ case XML_fgColor:
+ {
+ assert(mp_fill);
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_rgb:
+ {
+ ss::color_elem_t alpha;
+ ss::color_elem_t red;
+ ss::color_elem_t green;
+ ss::color_elem_t blue;
+ if (!to_rgb(attr.value, alpha, red, green, blue))
+ // invalid RGB color format.
+ continue;
+
+ mp_fill->set_fg_color(alpha, red, green, blue);
+ break;
+ }
+ case XML_indexed:
+ break;
+ default:
+ if (get_config().debug)
+ std::cerr << "warning: unknown attribute [ " << get_tokens().get_token_name(attr.name) << " ]" << std::endl;
+ }
+ }
+
+ break;
+ }
+ case XML_bgColor:
+ {
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_rgb:
+ {
+ ss::color_elem_t alpha;
+ ss::color_elem_t red;
+ ss::color_elem_t green;
+ ss::color_elem_t blue;
+ if (!to_rgb(attr.value, alpha, red, green, blue))
+ // invalid RGB color format.
+ continue;
+
+ mp_fill->set_bg_color(alpha, red, green, blue);
+ break;
+ }
+ case XML_indexed:
+ break;
+ default:
+ if (get_config().debug)
+ std::cerr << "warning: unknown attribute [ " << get_tokens().get_token_name(attr.name) << " ]" << std::endl;
+ }
+ }
+
+ break;
+ }
+ case XML_borders:
+ {
+ std::string_view ps = for_each(
+ attrs.begin(), attrs.end(), single_attr_getter(m_pool, NS_ooxml_xlsx, XML_count)).get_value();
+ size_t border_count = to_long(ps);
+ mp_styles->set_border_count(border_count);
+ m_border_ids.reserve(border_count);
+ break;
+ }
+ case XML_border:
+ {
+ start_element_border(attrs);
+
+ mp_border = mp_styles->start_border_style();
+ ENSURE_INTERFACE(mp_border, import_border_style);
+
+ break;
+ }
+ case XML_top:
+ {
+ assert(mp_border);
+ m_cur_border_dir = ss::border_direction_t::top;
+ border_attr_parser func(ss::border_direction_t::top, *mp_border);
+ for_each(attrs.begin(), attrs.end(), func);
+ break;
+ }
+ case XML_bottom:
+ {
+ assert(mp_border);
+ m_cur_border_dir = ss::border_direction_t::bottom;
+ border_attr_parser func(ss::border_direction_t::bottom, *mp_border);
+ for_each(attrs.begin(), attrs.end(), func);
+ break;
+ }
+ case XML_left:
+ {
+ assert(mp_border);
+ m_cur_border_dir = ss::border_direction_t::left;
+ border_attr_parser func(ss::border_direction_t::left, *mp_border);
+ for_each(attrs.begin(), attrs.end(), func);
+ break;
+ }
+ case XML_right:
+ {
+ assert(mp_border);
+ m_cur_border_dir = ss::border_direction_t::right;
+ border_attr_parser func(ss::border_direction_t::right, *mp_border);
+ for_each(attrs.begin(), attrs.end(), func);
+ break;
+ }
+ case XML_diagonal:
+ {
+ start_element_diagonal(attrs);
+ break;
+ }
+ case XML_cellStyleXfs:
+ {
+ if (std::optional<std::size_t> count = extract_count(attrs); count)
+ {
+ mp_styles->set_xf_count(ss::xf_category_t::cell_style, *count);
+ m_cell_style_xf_ids.reserve(*count);
+ }
+
+ mp_xf = mp_styles->start_xf(ss::xf_category_t::cell_style);
+ ENSURE_INTERFACE(mp_xf, import_xf);
+ m_xf_type = ss::xf_category_t::cell_style;
+ break;
+ }
+ case XML_cellXfs:
+ {
+ if (std::optional<std::size_t> count = extract_count(attrs); count)
+ mp_styles->set_xf_count(ss::xf_category_t::cell, *count);
+
+ mp_xf = mp_styles->start_xf(ss::xf_category_t::cell);
+ ENSURE_INTERFACE(mp_xf, import_xf);
+ m_xf_type = ss::xf_category_t::cell;
+ break;
+ }
+ case XML_dxfs:
+ {
+ if (std::optional<std::size_t> count = extract_count(attrs); count)
+ mp_styles->set_xf_count(ss::xf_category_t::differential, *count);
+
+ mp_xf = mp_styles->start_xf(ss::xf_category_t::differential);
+ ENSURE_INTERFACE(mp_xf, import_xf);
+ m_xf_type = ss::xf_category_t::differential;
+ break;
+ }
+ case XML_cellStyles:
+ {
+ std::string_view ps = for_each(
+ attrs.begin(), attrs.end(), single_attr_getter(m_pool, NS_ooxml_xlsx, XML_count)).get_value();
+ if (!ps.empty())
+ {
+ size_t n = strtoul(ps.data(), nullptr, 10);
+ mp_styles->set_cell_style_count(n);
+ }
+ mp_cell_style = mp_styles->start_cell_style();
+ ENSURE_INTERFACE(mp_cell_style, import_cell_style);
+ break;
+ }
+ case XML_cellStyle:
+ {
+ // named cell style, some of which are built-in such as 'Normal'.
+ assert(mp_cell_style);
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_name:
+ mp_cell_style->set_name(attr.value);
+ break;
+ case XML_xfId:
+ {
+ // reference ID to an xf entry in cellStyleXfs
+ const char* p_end = nullptr;
+ size_t n = to_long(attr.value, &p_end);
+ if (attr.value.data() < p_end)
+ {
+ if (n < m_cell_style_xf_ids.size())
+ mp_cell_style->set_xf(m_cell_style_xf_ids[n]);
+ else
+ {
+ std::ostringstream os;
+ os << "out-of-bound cellStyle@xfId: id=" << n << "; count=" << m_cell_style_xf_ids.size();
+ warn(os.str());
+ }
+ }
+ break;
+ }
+ case XML_builtinId:
+ {
+ size_t n = to_long(attr.value);
+ mp_cell_style->set_builtin(n);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case XML_xf:
+ {
+ start_xf(attrs);
+ break;
+ }
+ case XML_protection:
+ {
+ mp_protection = mp_styles->start_cell_protection();
+ ENSURE_INTERFACE(mp_protection, import_cell_protection);
+
+ for (const auto& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_hidden:
+ {
+ bool b = to_long(attr.value) != 0;
+ mp_protection->set_hidden(b);
+ break;
+ }
+ case XML_locked:
+ {
+ bool b = to_long(attr.value) != 0;
+ mp_protection->set_locked(b);
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ case XML_alignment:
+ {
+ assert(mp_xf);
+
+ // NB: default vertical alignment is 'bottom'.
+ ss::hor_alignment_t hor_align = ss::hor_alignment_t::unknown;
+ ss::ver_alignment_t ver_align = ss::ver_alignment_t::bottom;
+ bool wrap_text = false;
+ bool shrink_to_fit = false;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_horizontal:
+ {
+ if (attr.value == "center")
+ hor_align = ss::hor_alignment_t::center;
+ else if (attr.value == "right")
+ hor_align = ss::hor_alignment_t::right;
+ else if (attr.value == "left")
+ hor_align = ss::hor_alignment_t::left;
+ else if (attr.value == "justify")
+ hor_align = ss::hor_alignment_t::justified;
+ else if (attr.value == "distributed")
+ hor_align = ss::hor_alignment_t::distributed;
+ break;
+ }
+ case XML_vertical:
+ {
+ if (attr.value == "top")
+ ver_align = ss::ver_alignment_t::top;
+ else if (attr.value == "center")
+ ver_align = ss::ver_alignment_t::middle;
+ else if (attr.value == "bottom")
+ ver_align = ss::ver_alignment_t::bottom;
+ else if (attr.value == "justify")
+ ver_align = ss::ver_alignment_t::justified;
+ else if (attr.value == "distributed")
+ ver_align = ss::ver_alignment_t::distributed;
+ break;
+ }
+ case XML_wrapText:
+ wrap_text = to_bool(attr.value);
+ break;
+ case XML_shrinkToFit:
+ shrink_to_fit = to_bool(attr.value);
+ break;
+ }
+ }
+
+ mp_xf->set_horizontal_alignment(hor_align);
+ mp_xf->set_vertical_alignment(ver_align);
+ mp_xf->set_wrap_text(wrap_text);
+ mp_xf->set_shrink_to_fit(shrink_to_fit);
+ break;
+ }
+ case XML_numFmts:
+ {
+ std::string_view val =
+ for_each(
+ attrs.begin(), attrs.end(),
+ single_attr_getter(m_pool, NS_ooxml_xlsx, XML_count)).get_value();
+ if (!val.empty())
+ {
+ size_t n = to_long(val);
+ mp_styles->set_number_format_count(n);
+ }
+ break;
+ }
+ case XML_numFmt:
+ start_number_format(attrs);
+ break;
+ default:
+ warn_unhandled();
+ }
+ }
+ else
+ warn_unhandled();
+}
+
+bool xlsx_styles_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ switch (name)
+ {
+ case XML_font:
+ {
+ assert(mp_font);
+ std::size_t id = mp_font->commit();
+ m_font_ids.push_back(id);
+ mp_font = nullptr;
+ break;
+ }
+ case XML_fill:
+ {
+ assert(mp_fill);
+ std::size_t id = mp_fill->commit();
+ m_fill_ids.push_back(id);
+ mp_fill = nullptr;
+ break;
+ }
+ case XML_border:
+ {
+ assert(mp_border);
+ std::size_t id = mp_border->commit();
+ m_border_ids.push_back(id);
+ mp_border = nullptr;
+ break;
+ }
+ case XML_cellStyle:
+ assert(mp_cell_style);
+ mp_cell_style->commit();
+ break;
+ case XML_cellStyles:
+ assert(mp_cell_style);
+ mp_cell_style = nullptr;
+ break;
+ case XML_cellStyleXfs:
+ case XML_cellXfs:
+ case XML_dxfs:
+ assert(mp_xf);
+ mp_xf = nullptr;
+ m_xf_type = ss::xf_category_t::unknown;
+ break;
+ case XML_xf:
+ case XML_dxf:
+ {
+ assert(mp_xf);
+ std::size_t id = mp_xf->commit();
+ switch (m_xf_type)
+ {
+ break;
+ case ss::xf_category_t::cell_style:
+ // only cell style xf ID is referenced.
+ m_cell_style_xf_ids.push_back(id);
+ break;
+ case ss::xf_category_t::cell:
+ case ss::xf_category_t::differential:
+ // not used
+ break;
+ case ss::xf_category_t::unknown:
+ warn("xf entry committed while the current xf category is unknown");
+ break;
+ }
+ break;
+ }
+ case XML_protection:
+ {
+ assert(mp_protection);
+ size_t prot_id = mp_protection->commit();
+ assert(mp_xf);
+ mp_xf->set_protection(prot_id);
+ break;
+ }
+ case XML_numFmt:
+ end_number_format();
+ break;
+ }
+ return pop_stack(ns, name);
+}
+
+void xlsx_styles_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+ // not used in the styles.xml part.
+}
+
+void xlsx_styles_context::start_number_format(const xml_token_attrs_t& attrs)
+{
+ if (!mp_styles)
+ return;
+
+ mp_numfmt = mp_styles->start_number_format();
+ ENSURE_INTERFACE(mp_numfmt, import_number_format);
+
+ m_cur_numfmt_id.reset();
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_numFmtId:
+ {
+ const char* p_end = nullptr;
+ long id = to_long(attr.value, &p_end);
+ if (attr.value.data() < p_end && id >= 0)
+ {
+ mp_numfmt->set_identifier(id);
+ m_cur_numfmt_id = id;
+ }
+ break;
+ }
+ case XML_formatCode:
+ {
+ mp_numfmt->set_code(attr.value);
+ break;
+ }
+ }
+ }
+}
+
+void xlsx_styles_context::start_element_border(const xml_token_attrs_t& attrs)
+{
+ bool diagonal_up = false;
+ bool diagonal_down = false;
+
+ std::for_each(attrs.begin(), attrs.end(),
+ [&diagonal_up,&diagonal_down](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_diagonalDown:
+ // top-left to bottom-right.
+ diagonal_down = to_long(attr.value) != 0;
+ break;
+ case XML_diagonalUp:
+ // bottom-left to top-right.
+ diagonal_up = to_long(attr.value) != 0;
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ m_diagonal_up = diagonal_up;
+ m_diagonal_down = diagonal_down;
+}
+
+void xlsx_styles_context::start_element_diagonal(const xml_token_attrs_t& attrs)
+{
+ assert(mp_border);
+
+ m_cur_border_dir = ss::border_direction_t::unknown;
+
+ if (m_diagonal_up)
+ {
+ m_cur_border_dir = m_diagonal_down ?
+ ss::border_direction_t::diagonal :
+ ss::border_direction_t::diagonal_bl_tr;
+ }
+ else
+ {
+ m_cur_border_dir = m_diagonal_down ?
+ ss::border_direction_t::diagonal_tl_br :
+ ss::border_direction_t::unknown;
+ }
+
+ if (m_cur_border_dir == ss::border_direction_t::unknown)
+ return;
+
+ border_attr_parser func(m_cur_border_dir, *mp_border);
+ for_each(attrs.begin(), attrs.end(), func);
+}
+
+void xlsx_styles_context::start_border_color(const xml_token_attrs_t& attrs)
+{
+ assert(mp_border);
+
+ std::optional<std::string_view> rgb;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_rgb:
+ rgb = attr.value;
+ break;
+ case XML_theme:
+ // TODO : handle this.
+ break;
+ }
+ }
+
+ if (rgb)
+ {
+ ss::color_elem_t alpha;
+ ss::color_elem_t red;
+ ss::color_elem_t green;
+ ss::color_elem_t blue;
+
+ if (to_rgb(*rgb, alpha, red, green, blue))
+ mp_border->set_color(m_cur_border_dir, alpha, red, green, blue);
+ }
+}
+
+void xlsx_styles_context::start_font_color(const xml_token_attrs_t& attrs)
+{
+ assert(mp_font);
+
+ std::optional<std::string_view> rgb;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_rgb:
+ rgb = attr.value;
+ break;
+ case XML_theme:
+ // TODO : handle this.
+ break;
+ }
+ }
+
+ if (rgb)
+ {
+ ss::color_elem_t alpha;
+ ss::color_elem_t red;
+ ss::color_elem_t green;
+ ss::color_elem_t blue;
+ if (to_rgb(*rgb, alpha, red, green, blue))
+ mp_font->set_color(alpha, red, green, blue);
+ }
+}
+
+void xlsx_styles_context::start_xf(const xml_token_attrs_t& attrs)
+{
+ assert(mp_xf);
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ switch (attr.name)
+ {
+ case XML_borderId:
+ {
+ const char* p_end = nullptr;
+ size_t n = to_long(attr.value, &p_end);
+ if (attr.value.data() < p_end)
+ {
+ if (n < m_border_ids.size())
+ mp_xf->set_border(m_border_ids[n]);
+ else
+ {
+ std::ostringstream os;
+ os << "out-of-bound borderId: id=" << n << "; count=" << m_border_ids.size();
+ warn(os.str());
+ }
+ }
+ break;
+ }
+ case XML_fillId:
+ {
+ const char* p_end = nullptr;
+ size_t n = to_long(attr.value, &p_end);
+ if (attr.value.data() < p_end)
+ {
+ if (n < m_fill_ids.size())
+ mp_xf->set_fill(m_fill_ids[n]);
+ else
+ {
+ std::ostringstream os;
+ os << "out-of-bound fillId: id=" << n << "; count=" << m_fill_ids.size();
+ warn(os.str());
+ }
+ }
+ break;
+ }
+ case XML_fontId:
+ {
+ const char* p_end = nullptr;
+ size_t n = to_long(attr.value, &p_end);
+ if (attr.value.data() < p_end)
+ {
+ if (n < m_font_ids.size())
+ mp_xf->set_font(m_font_ids[n]);
+ else
+ {
+ std::ostringstream os;
+ os << "out-of-bound fontId: id=" << n << "; count=" << m_font_ids.size();
+ warn(os.str());
+ }
+ }
+ break;
+ }
+ case XML_numFmtId:
+ {
+ const char* p_end = nullptr;
+ long n = to_long(attr.value, &p_end);
+ if (attr.value.data() < p_end && n >= 0)
+ {
+ auto it = m_numfmt_ids.find(n);
+ if (it == m_numfmt_ids.end())
+ {
+ std::ostringstream os;
+ os << "no entry for xf@numFmtId = " << n;
+ warn(os.str());
+ }
+ else
+ mp_xf->set_number_format(it->second);
+ }
+ break;
+ }
+ case XML_xfId:
+ {
+ // reference ID to an xf entry in cellStyleXfs
+ const char* p_end = nullptr;
+ size_t n = to_long(attr.value, &p_end);
+ if (attr.value.data() < p_end)
+ {
+ if (n < m_cell_style_xf_ids.size())
+ mp_xf->set_style_xf(m_cell_style_xf_ids[n]);
+ else
+ {
+ std::ostringstream os;
+ os << "out-of-bound xf@xfId: id=" << n << "; count=" << m_cell_style_xf_ids.size();
+ warn(os.str());
+ }
+ }
+ break;
+ }
+ case XML_applyBorder:
+ break;
+ case XML_applyFill:
+ break;
+ case XML_applyFont:
+ break;
+ case XML_applyNumberFormat:
+ break;
+ case XML_applyAlignment:
+ {
+ bool b = to_long(attr.value) != 0;
+ mp_xf->set_apply_alignment(b);
+ break;
+ }
+ }
+ }
+}
+
+void xlsx_styles_context::end_number_format()
+{
+ if (!mp_styles)
+ return;
+
+ assert(mp_numfmt);
+ std::size_t id = mp_numfmt->commit();
+ mp_numfmt = nullptr;
+
+ if (m_cur_numfmt_id)
+ {
+ auto res = m_numfmt_ids.insert_or_assign(*m_cur_numfmt_id, id);
+ if (!res.second)
+ {
+ // assigned to an existing key
+ std::ostringstream os;
+ os << "number format id of " << *m_cur_numfmt_id << " referenced multiple times";
+ warn(os.str());
+ }
+ }
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_styles_context.hpp b/src/liborcus/xlsx_styles_context.hpp
new file mode 100644
index 0000000..3cd8310
--- /dev/null
+++ b/src/liborcus/xlsx_styles_context.hpp
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "xml_context_base.hpp"
+#include "xlsx_types.hpp"
+
+#include <orcus/string_pool.hpp>
+
+#include <vector>
+#include <unordered_map>
+#include <optional>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+ class import_styles;
+ class import_font_style;
+ class import_fill_style;
+ class import_border_style;
+ class import_cell_protection;
+ class import_number_format;
+ class import_xf;
+ class import_cell_style;
+}}
+
+/**
+ * Context for xl/styles.xml part. This part contains various styles used
+ * in the sheets.
+ */
+class xlsx_styles_context : public xml_context_base
+{
+public:
+ xlsx_styles_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_styles* import_styles);
+ virtual ~xlsx_styles_context();
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+
+private:
+ void start_number_format(const xml_token_attrs_t& attrs);
+
+ void start_element_border(const xml_token_attrs_t& attrs);
+ void start_element_diagonal(const xml_token_attrs_t& attrs);
+ void start_border_color(const xml_token_attrs_t& attrs);
+ void start_font_color(const xml_token_attrs_t& attrs);
+ void start_xf(const xml_token_attrs_t& attrs);
+
+ void end_number_format();
+
+private:
+ spreadsheet::iface::import_styles* mp_styles = nullptr;
+ spreadsheet::iface::import_font_style* mp_font = nullptr;
+ spreadsheet::iface::import_fill_style* mp_fill = nullptr;
+ spreadsheet::iface::import_border_style* mp_border = nullptr;
+ spreadsheet::iface::import_cell_protection* mp_protection = nullptr;
+ spreadsheet::iface::import_number_format* mp_numfmt = nullptr;
+ spreadsheet::iface::import_xf* mp_xf = nullptr;
+ spreadsheet::iface::import_cell_style* mp_cell_style = nullptr;
+ spreadsheet::xf_category_t m_xf_type = spreadsheet::xf_category_t::unknown;
+
+ string_pool m_pool;
+ bool m_diagonal_up;
+ bool m_diagonal_down;
+ spreadsheet::border_direction_t m_cur_border_dir;
+
+ std::vector<std::size_t> m_font_ids;
+ std::vector<std::size_t> m_fill_ids;
+ std::vector<std::size_t> m_border_ids;
+ std::vector<std::size_t> m_cell_style_xf_ids;
+ // numFmt@numFmtId values as keys
+ std::unordered_map<std::size_t, std::size_t> m_numfmt_ids;
+ std::optional<std::size_t> m_cur_numfmt_id;
+};
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_table_context.cpp b/src/liborcus/xlsx_table_context.cpp
new file mode 100644
index 0000000..06f16ce
--- /dev/null
+++ b/src/liborcus/xlsx_table_context.cpp
@@ -0,0 +1,319 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_table_context.hpp"
+#include "xlsx_autofilter_context.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "ooxml_token_constants.hpp"
+#include "ooxml_global.hpp"
+#include "session_context.hpp"
+#include "xml_context_global.hpp"
+
+#include "orcus/measurement.hpp"
+#include "orcus/spreadsheet/import_interface.hpp"
+
+#include <iostream>
+#include <optional>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus {
+
+namespace {
+
+class table_column_attr_parser
+{
+ string_pool* m_pool;
+
+ long m_id;
+ std::string_view m_name;
+ std::string_view m_totals_row_label;
+ spreadsheet::totals_row_function_t m_totals_row_func;
+
+public:
+ table_column_attr_parser(string_pool* pool) :
+ m_pool(pool), m_id(-1), m_totals_row_func(spreadsheet::totals_row_function_t::none) {}
+
+ void operator() (const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_id:
+ m_id = to_long(attr.value);
+ break;
+ case XML_name:
+ m_name = attr.value;
+ if (attr.transient)
+ m_name = m_pool->intern(m_name).first;
+ break;
+ case XML_totalsRowLabel:
+ m_totals_row_label = attr.value;
+ if (attr.transient)
+ m_totals_row_label = m_pool->intern(m_totals_row_label).first;
+ break;
+ case XML_totalsRowFunction:
+ m_totals_row_func = spreadsheet::to_totals_row_function_enum(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+
+ long get_id() const { return m_id; }
+ std::string_view get_name() const { return m_name; }
+ std::string_view get_totals_row_label() const { return m_totals_row_label; }
+ spreadsheet::totals_row_function_t get_totals_row_function() const { return m_totals_row_func; }
+};
+
+class table_style_info_attr_parser
+{
+ spreadsheet::iface::import_table* mp_table;
+ bool m_debug;
+
+public:
+ table_style_info_attr_parser(spreadsheet::iface::import_table* table, bool debug) :
+ mp_table(table), m_debug(debug) {}
+
+ void operator() (const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ bool b = false;
+
+ switch (attr.name)
+ {
+ case XML_name:
+ mp_table->set_style_name(attr.value);
+ if (m_debug)
+ std::cout << " * table style info (name=" << attr.value << ")" << std::endl;
+ break;
+ case XML_showFirstColumn:
+ b = to_bool(attr.value);
+ mp_table->set_style_show_first_column(b);
+ if (m_debug)
+ std::cout << " * show first column: " << b << std::endl;
+ break;
+ case XML_showLastColumn:
+ b = to_bool(attr.value);
+ mp_table->set_style_show_last_column(b);
+ if (m_debug)
+ std::cout << " * show last column: " << b << std::endl;
+ break;
+ case XML_showRowStripes:
+ b = to_bool(attr.value);
+ mp_table->set_style_show_row_stripes(b);
+ if (m_debug)
+ std::cout << " * show row stripes: " << b << std::endl;
+ break;
+ case XML_showColumnStripes:
+ b = to_bool(attr.value);
+ mp_table->set_style_show_column_stripes(b);
+ if (m_debug)
+ std::cout << " * show column stripes: " << b << std::endl;
+ break;
+ default:
+ ;
+ }
+ }
+};
+
+}
+
+xlsx_table_context::xlsx_table_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_table& table,
+ spreadsheet::iface::import_reference_resolver& resolver) :
+ xml_context_base(session_cxt, tokens), m_table(table), m_resolver(resolver),
+ m_cxt_autofilter(session_cxt, tokens, resolver)
+{
+ register_child(&m_cxt_autofilter);
+
+ init_ooxml_context(*this);
+}
+
+xlsx_table_context::~xlsx_table_context() {}
+
+xml_context_base* xlsx_table_context::create_child_context(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xlsx && name == XML_autoFilter)
+ {
+ m_cxt_autofilter.reset();
+ return &m_cxt_autofilter;
+ }
+ return nullptr;
+}
+
+void xlsx_table_context::end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child)
+{
+ if (ns == NS_ooxml_xlsx && name == XML_autoFilter)
+ {
+ assert(child == &m_cxt_autofilter);
+
+ spreadsheet::iface::import_auto_filter* af = m_table.get_auto_filter();
+ if (!af)
+ return;
+
+ const xlsx_autofilter_context& cxt = static_cast<const xlsx_autofilter_context&>(*child);
+ cxt.push_to_model(*af);
+ }
+}
+
+void xlsx_table_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ if (ns != NS_ooxml_xlsx)
+ return;
+
+ std::string_view str;
+
+ switch (name)
+ {
+ case XML_table:
+ {
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ start_element_table(attrs);
+ break;
+ }
+ case XML_tableColumns:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_table);
+ single_long_attr_getter func(NS_ooxml_xlsx, XML_count);
+ long column_count = for_each(attrs.begin(), attrs.end(), func).get_value();
+ if (get_config().debug)
+ std::cout << " * column count: " << column_count << std::endl;
+
+ m_table.set_column_count(column_count);
+ }
+ break;
+ case XML_tableColumn:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_tableColumns);
+ table_column_attr_parser func(&get_session_context().spool);
+ func = for_each(attrs.begin(), attrs.end(), func);
+ if (get_config().debug)
+ {
+ std::cout << " * table column (id=" << func.get_id() << "; name=" << func.get_name() << ")" << std::endl;
+ std::cout << " * totals row label: " << func.get_totals_row_label() << std::endl;
+ std::cout << " * totals func: " << static_cast<int>(func.get_totals_row_function()) << std::endl;
+ }
+
+ m_table.set_column_identifier(func.get_id());
+ str = func.get_name();
+ m_table.set_column_name(str);
+ str = func.get_totals_row_label();
+ m_table.set_column_totals_row_label(str);
+ m_table.set_column_totals_row_function(func.get_totals_row_function());
+ }
+ break;
+ case XML_tableStyleInfo:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_table);
+ table_style_info_attr_parser func(&m_table, get_config().debug);
+ for_each(attrs.begin(), attrs.end(), func);
+ }
+ break;
+ default:
+ warn_unhandled();
+ }
+
+}
+
+bool xlsx_table_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_table:
+ m_table.commit();
+ break;
+ case XML_tableColumn:
+ m_table.commit_column();
+ break;
+ default:
+ ;
+ }
+ }
+
+ return pop_stack(ns, name);
+}
+
+void xlsx_table_context::start_element_table(const xml_token_attrs_t& attrs)
+{
+ long id = -1;
+ long totals_row_count = -1;
+
+ std::optional<std::string_view> name;
+ std::optional<std::string_view> display_name;
+ std::optional<std::string_view> ref;
+
+ for (const xml_token_attr_t& attr : attrs)
+ {
+ if (attr.ns)
+ continue;
+
+ switch (attr.name)
+ {
+ case XML_id:
+ id = to_long(attr.value);
+ break;
+ case XML_totalsRowCount:
+ totals_row_count = to_long(attr.value);
+ break;
+ case XML_name:
+ name = attr.value;
+ break;
+ case XML_displayName:
+ display_name = attr.value;
+ break;
+ case XML_ref:
+ ref = attr.value;
+ break;
+ }
+ }
+
+ if (get_config().debug)
+ {
+ auto str_or_not = [](const auto& v) -> std::string_view
+ {
+ return v ? *v : "-";
+ };
+
+ std::cout << "* table (range=" << str_or_not(ref)
+ << "; id=" << id
+ << "; name=" << str_or_not(name)
+ << "; display name=" << str_or_not(display_name) << ")" << std::endl;
+
+ std::cout << " * totals row count: " << totals_row_count << std::endl;
+ }
+
+ if (id >= 0)
+ m_table.set_identifier(id);
+
+ if (ref)
+ {
+ ss::range_t range = to_rc_range(m_resolver.resolve_range(*ref));
+ m_table.set_range(range);
+ }
+
+ if (name)
+ m_table.set_name(*name);
+
+ if (display_name)
+ m_table.set_display_name(*display_name);
+
+ if (totals_row_count >= 0)
+ m_table.set_totals_row_count(totals_row_count);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_table_context.hpp b/src/liborcus/xlsx_table_context.hpp
new file mode 100644
index 0000000..8b3e629
--- /dev/null
+++ b/src/liborcus/xlsx_table_context.hpp
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XLSX_TABLE_CONTEXT_HPP
+#define ORCUS_XLSX_TABLE_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "xlsx_autofilter_context.hpp"
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_table;
+class import_reference_resolver;
+
+}}
+
+class xlsx_table_context : public xml_context_base
+{
+public:
+ xlsx_table_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_table& table,
+ spreadsheet::iface::import_reference_resolver& resolver);
+ virtual ~xlsx_table_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+
+private:
+ void start_element_table(const xml_token_attrs_t& attrs);
+
+private:
+ spreadsheet::iface::import_table& m_table;
+ spreadsheet::iface::import_reference_resolver& m_resolver;
+
+ xlsx_autofilter_context m_cxt_autofilter;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_types.cpp b/src/liborcus/xlsx_types.cpp
new file mode 100644
index 0000000..3c0ba2a
--- /dev/null
+++ b/src/liborcus/xlsx_types.cpp
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_types.hpp"
+
+#include <mdds/sorted_string_map.hpp>
+
+namespace orcus {
+
+namespace {
+
+constexpr std::string_view str_unknown = "unknown";
+
+namespace cell_type {
+
+using map_type = mdds::sorted_string_map<xlsx_cell_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "b", xlsx_ct_boolean },
+ { "e", xlsx_ct_error },
+ { "inlineStr", xlsx_ct_inline_string },
+ { "n", xlsx_ct_numeric },
+ { "s", xlsx_ct_shared_string },
+ { "str", xlsx_ct_formula_string }
+};
+
+const map_type& get()
+{
+ static const map_type map(entries, std::size(entries), xlsx_ct_unknown);
+ return map;
+}
+
+} // namespace cell_type
+
+namespace rca {
+
+using map_type = mdds::sorted_string_map<xlsx_rev_row_column_action_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "deleteCol", xlsx_rev_rca_delete_column },
+ { "deleteRow", xlsx_rev_rca_delete_row },
+ { "insertCol", xlsx_rev_rca_insert_column },
+ { "insertRow", xlsx_rev_rca_insert_row }
+};
+
+const map_type& get()
+{
+ static const map_type map(entries, std::size(entries), xlsx_rev_rca_unknown);
+ return map;
+}
+
+} // namespace rca
+
+} // anonymous namespace
+
+xlsx_cell_t to_xlsx_cell_type(std::string_view s)
+{
+ return cell_type::get().find(s);
+}
+
+std::string_view to_string(xlsx_cell_t type)
+{
+ switch (type)
+ {
+ case xlsx_ct_boolean:
+ return cell_type::entries[0].key;
+ case xlsx_ct_error:
+ return cell_type::entries[1].key;
+ case xlsx_ct_inline_string:
+ return cell_type::entries[2].key;
+ case xlsx_ct_numeric:
+ return cell_type::entries[3].key;
+ case xlsx_ct_shared_string:
+ return cell_type::entries[4].key;
+ case xlsx_ct_formula_string:
+ return cell_type::entries[5].key;
+ default:
+ ;
+ }
+ return str_unknown;
+}
+
+xlsx_rev_row_column_action_t to_xlsx_rev_row_column_action_type(std::string_view s)
+{
+ return rca::get().find(s);
+}
+
+std::string_view to_string(xlsx_rev_row_column_action_t type)
+{
+ switch (type)
+ {
+ case xlsx_rev_rca_delete_column:
+ return rca::entries[0].key;
+ case xlsx_rev_rca_delete_row:
+ return rca::entries[1].key;
+ case xlsx_rev_rca_insert_column:
+ return rca::entries[2].key;
+ case xlsx_rev_rca_insert_row:
+ return rca::entries[3].key;
+ case xlsx_rev_rca_unknown:
+ default:
+ ;
+ }
+
+ return str_unknown;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_types.hpp b/src/liborcus/xlsx_types.hpp
new file mode 100644
index 0000000..6d61e1f
--- /dev/null
+++ b/src/liborcus/xlsx_types.hpp
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_XLSX_TYPES_HPP__
+#define __ORCUS_XLSX_TYPES_HPP__
+
+#include "ooxml_types.hpp"
+#include "orcus/spreadsheet/types.hpp"
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_sheet;
+
+}}
+
+struct xlsx_rel_sheet_info : public opc_rel_extra
+{
+ std::string_view name;
+ size_t id;
+
+ xlsx_rel_sheet_info() : id(0) {}
+
+ virtual ~xlsx_rel_sheet_info() override {}
+};
+
+struct xlsx_rel_pivot_cache_info : public opc_rel_extra
+{
+ spreadsheet::pivot_cache_id_t id;
+
+ xlsx_rel_pivot_cache_info(spreadsheet::pivot_cache_id_t _id) : id(_id) {}
+
+ virtual ~xlsx_rel_pivot_cache_info() override {}
+};
+
+/**
+ * Data to pass to the pivot cache record handler.
+ */
+struct xlsx_rel_pivot_cache_record_info : public opc_rel_extra
+{
+ spreadsheet::pivot_cache_id_t id;
+
+ xlsx_rel_pivot_cache_record_info(spreadsheet::pivot_cache_id_t _id) : id(_id) {}
+
+ virtual ~xlsx_rel_pivot_cache_record_info() override {}
+};
+
+struct xlsx_rel_table_info : public opc_rel_extra
+{
+ spreadsheet::iface::import_sheet* sheet_interface;
+
+ xlsx_rel_table_info() : sheet_interface(nullptr) {}
+
+ virtual ~xlsx_rel_table_info() override {}
+};
+
+enum xlsx_cell_t
+{
+ xlsx_ct_unknown = 0,
+ xlsx_ct_boolean,
+ xlsx_ct_error,
+ xlsx_ct_numeric,
+ xlsx_ct_inline_string,
+ xlsx_ct_shared_string,
+ xlsx_ct_formula_string,
+};
+
+xlsx_cell_t to_xlsx_cell_type(std::string_view s);
+
+std::string_view to_string(xlsx_cell_t type);
+
+enum xlsx_rev_row_column_action_t
+{
+ xlsx_rev_rca_unknown = 0,
+ xlsx_rev_rca_delete_column,
+ xlsx_rev_rca_delete_row,
+ xlsx_rev_rca_insert_column,
+ xlsx_rev_rca_insert_row
+};
+
+xlsx_rev_row_column_action_t to_xlsx_rev_row_column_action_type(std::string_view s);
+
+std::string_view to_string(xlsx_rev_row_column_action_t type);
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_workbook_context.cpp b/src/liborcus/xlsx_workbook_context.cpp
new file mode 100644
index 0000000..4980418
--- /dev/null
+++ b/src/liborcus/xlsx_workbook_context.cpp
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx_workbook_context.hpp"
+#include "ooxml_global.hpp"
+#include "ooxml_schemas.hpp"
+#include "ooxml_token_constants.hpp"
+#include "ooxml_namespace_types.hpp"
+#include "session_context.hpp"
+#include "xlsx_session_data.hpp"
+
+#include "orcus/measurement.hpp"
+#include "orcus/spreadsheet/import_interface.hpp"
+
+namespace orcus {
+
+xlsx_workbook_context::xlsx_workbook_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_factory& factory) :
+ xml_context_base(session_cxt, tokens),
+ m_defined_name_scope(-1),
+ m_sheet_count(0),
+ m_factory(factory),
+ mp_named_exp(factory.get_named_expression())
+{
+ init_ooxml_context(*this);
+}
+
+xlsx_workbook_context::~xlsx_workbook_context() = default;
+
+xml_context_base* xlsx_workbook_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xlsx_workbook_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xlsx_workbook_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs)
+{
+ xml_token_pair_t parent = push_stack(ns, name);
+ session_context& cxt = get_session_context();
+ string_pool& sp = cxt.spool;
+
+ if (ns == NS_ooxml_xlsx)
+ {
+ switch (name)
+ {
+ case XML_workbook:
+ {
+ xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
+ if (get_config().debug)
+ print_attrs(get_tokens(), attrs);
+
+ break;
+ }
+ case XML_sheets:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_workbook);
+ break;
+ case XML_sheet:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_sheets);
+
+ std::string_view rid;
+ xlsx_rel_sheet_info sheet;
+
+ std::for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (!attr.ns || attr.ns == NS_ooxml_xlsx)
+ {
+ switch (attr.name)
+ {
+ case XML_name:
+ sheet.name = sp.intern(attr.value).first;
+ break;
+ case XML_sheetId:
+ {
+ if (!attr.value.empty())
+ sheet.id = to_long(attr.value);
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ else if (attr.ns == NS_ooxml_r && attr.name == XML_id)
+ {
+ rid = sp.intern(attr.value).first;
+ }
+ }
+ );
+
+ if (sheet.name.empty())
+ throw xml_structure_error("workbook.xml: sheet element must have a valid name element.");
+
+ // Insert the sheet here so that we have all the sheets available
+ // prior to parsing global named expressions.
+ m_factory.append_sheet(m_sheet_count++, sheet.name);
+
+ m_workbook_info.data.insert(
+ opc_rel_extras_t::map_type::value_type(
+ rid, std::make_unique<xlsx_rel_sheet_info>(sheet)));
+
+ break;
+ }
+ case XML_definedNames:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_workbook);
+ break;
+ case XML_definedName:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_definedNames);
+
+ std::for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (attr.ns && attr.ns != NS_ooxml_xlsx)
+ return;
+
+ switch (attr.name)
+ {
+ case XML_name:
+ {
+ m_defined_name = attr.value;
+ if (attr.transient)
+ {
+ m_defined_name =
+ cxt.spool.intern(m_defined_name).first;
+ }
+ break;
+ }
+ case XML_localSheetId:
+ m_defined_name_scope = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ break;
+ }
+ case XML_pivotCaches:
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_workbook);
+ break;
+ case XML_pivotCache:
+ {
+ xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotCaches);
+
+ std::string_view rid;
+ long cache_id = -1;
+ std::for_each(attrs.begin(), attrs.end(),
+ [&](const xml_token_attr_t& attr)
+ {
+ if (!attr.ns || attr.ns == NS_ooxml_xlsx)
+ {
+ switch (attr.name)
+ {
+ case XML_cacheId:
+ cache_id = to_long(attr.value);
+ break;
+ default:
+ ;
+ }
+ }
+ else if (attr.ns == NS_ooxml_r)
+ {
+ switch (attr.name)
+ {
+ case XML_id:
+ rid = attr.value;
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ );
+
+ m_workbook_info.data.insert(
+ opc_rel_extras_t::map_type::value_type(
+ rid, std::make_unique<xlsx_rel_pivot_cache_info>(cache_id)));
+
+ break;
+ }
+ default:
+ warn_unhandled();
+ }
+ }
+}
+
+bool xlsx_workbook_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ if (ns == NS_ooxml_xlsx)
+ {
+ if (name == XML_definedName)
+ {
+ push_defined_name();
+
+ m_defined_name = std::string_view{};
+ m_defined_name_exp = std::string_view{};
+ m_defined_name_scope = -1;
+ }
+ }
+ return pop_stack(ns, name);
+}
+
+void xlsx_workbook_context::characters(std::string_view str, bool transient)
+{
+ std::string_view sv(str);
+ xml_token_pair_t cur = get_current_element();
+ string_pool& sp = get_session_context().spool;
+
+ if (cur.first == NS_ooxml_xlsx)
+ {
+ if (cur.second == XML_definedName)
+ m_defined_name_exp = transient ? sp.intern(sv).first : sv;
+ }
+}
+
+void xlsx_workbook_context::pop_workbook_info(opc_rel_extras_t& workbook_data)
+{
+ m_workbook_info.swap(workbook_data);
+}
+
+void xlsx_workbook_context::push_defined_name()
+{
+ spreadsheet::iface::import_named_expression* named_exp = mp_named_exp;
+
+ if (m_defined_name_scope >= 0)
+ {
+ // sheet local scope.
+ spreadsheet::iface::import_sheet* sheet = m_factory.get_sheet(m_defined_name_scope);
+ if (!sheet)
+ return;
+
+ named_exp = sheet->get_named_expression();
+ }
+
+ if (named_exp)
+ {
+ named_exp->set_named_expression(m_defined_name, m_defined_name_exp);
+ named_exp->commit();
+ }
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xlsx_workbook_context.hpp b/src/liborcus/xlsx_workbook_context.hpp
new file mode 100644
index 0000000..71d1958
--- /dev/null
+++ b/src/liborcus/xlsx_workbook_context.hpp
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_XLSX_WORKBOOK_CONTEXT_HPP
+#define INCLUDED_ORCUS_XLSX_WORKBOOK_CONTEXT_HPP
+
+#include "xml_context_base.hpp"
+#include "orcus/spreadsheet/types.hpp"
+#include "xlsx_types.hpp"
+
+#include <unordered_map>
+
+namespace orcus {
+
+namespace spreadsheet { namespace iface {
+
+class import_factory;
+class import_named_expression;
+
+}}
+
+/**
+ * Context for xl/workbook.xml.
+ */
+class xlsx_workbook_context : public xml_context_base
+{
+public:
+ typedef std::unordered_map<std::string_view, xlsx_rel_sheet_info> sheet_info_type;
+
+ xlsx_workbook_context(
+ session_context& session_cxt, const tokens& tokens,
+ spreadsheet::iface::import_factory& factory);
+
+ virtual ~xlsx_workbook_context();
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const xml_token_attrs_t& attrs);
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name);
+ virtual void characters(std::string_view str, bool transient);
+
+ void pop_workbook_info(opc_rel_extras_t& sheets);
+
+private:
+ void push_defined_name();
+
+private:
+ opc_rel_extras_t m_workbook_info;
+ std::string_view m_defined_name;
+ std::string_view m_defined_name_exp;
+ spreadsheet::sheet_t m_defined_name_scope;
+ size_t m_sheet_count;
+ spreadsheet::iface::import_factory& m_factory;
+ spreadsheet::iface::import_named_expression* mp_named_exp;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_context_base.cpp b/src/liborcus/xml_context_base.cpp
new file mode 100644
index 0000000..4d61926
--- /dev/null
+++ b/src/liborcus/xml_context_base.cpp
@@ -0,0 +1,348 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_context_base.hpp"
+#include "session_context.hpp"
+
+#include "orcus/exception.hpp"
+#include "orcus/tokens.hpp"
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+
+namespace orcus {
+
+namespace {
+
+void print_stack(const tokens& tokens, const xml_elem_stack_t& elem_stack, const xmlns_context* ns_cxt)
+{
+ cerr << "[ ";
+ xml_elem_stack_t::const_iterator itr, itr_beg = elem_stack.begin(), itr_end = elem_stack.end();
+ for (itr = itr_beg; itr != itr_end; ++itr)
+ {
+ if (itr != itr_beg)
+ cerr << " -> ";
+
+ xmlns_id_t ns = itr->first;
+ if (ns_cxt)
+ {
+ std::string_view alias = ns_cxt->get_alias(ns);
+ if (!alias.empty())
+ cerr << alias << ":";
+ }
+ else
+ cerr << ns << ":";
+
+ cerr << tokens.get_token_name(itr->second);
+ }
+ cerr << " ]";
+}
+
+}
+
+xml_context_base::xml_context_base(session_context& session_cxt, const tokens& tokens) :
+ m_config(format_t::unknown),
+ mp_ns_cxt(nullptr), m_session_cxt(session_cxt), m_tokens(tokens),
+ m_elem_printer(m_tokens)
+{
+}
+
+xml_context_base::~xml_context_base()
+{
+}
+
+void xml_context_base::declaration(const xml_declaration_t& /*decl*/)
+{
+}
+
+xml_context_base* xml_context_base::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xml_context_base::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xml_context_base::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+bool xml_context_base::evaluate_child_element(xmlns_id_t ns, xml_token_t name) const
+{
+ const xml_token_pair_t parent = get_current_element();
+
+ if (xml_element_always_allowed(parent))
+ return true;
+
+ const xml_token_pair_t child(ns, name);
+
+ xml_element_validator::result res = m_elem_validator.validate(parent, child);
+
+ if (get_config().debug)
+ {
+ switch (res)
+ {
+ case xml_element_validator::result::child_invalid:
+ {
+ std::ostringstream os;
+ print_element(os, child);
+ os << " cannot be a child element of ";
+ print_element(os, parent);
+ warn(os.str());
+ break;
+ }
+ case xml_element_validator::result::parent_unknown:
+ {
+ std::ostringstream os;
+ os << "parent ";
+ print_element(os, parent);
+ os << " does not have any rules defined (child: ";
+ print_element(os, child);
+ os << ')';
+ warn(os.str());
+ break;
+ }
+ case xml_element_validator::result::child_valid:
+ break;
+ }
+ }
+
+ return res != xml_element_validator::result::child_invalid;
+}
+
+void xml_context_base::set_ns_context(const xmlns_context* p)
+{
+ mp_ns_cxt = p;
+ m_elem_printer.set_ns_context(p);
+
+ for (auto* child : m_child_contexts)
+ child->set_ns_context(p);
+}
+
+void xml_context_base::set_config(const config& opt)
+{
+ m_config = opt;
+
+ for (auto* child : m_child_contexts)
+ child->set_config(opt);
+}
+
+void xml_context_base::set_always_allowed_elements(xml_elem_set_t elems)
+{
+ m_always_allowed_elements = std::move(elems);
+}
+
+void xml_context_base::init_element_validator(
+ const xml_element_validator::rule* rules, std::size_t n_rules)
+{
+ m_elem_validator.init(rules, n_rules);
+}
+
+session_context& xml_context_base::get_session_context()
+{
+ return m_session_cxt;
+}
+
+const session_context& xml_context_base::get_session_context() const
+{
+ return m_session_cxt;
+}
+
+const tokens& xml_context_base::get_tokens() const
+{
+ return m_tokens;
+}
+
+xml_token_pair_t xml_context_base::push_stack(xmlns_id_t ns, xml_token_t name)
+{
+ xml_token_pair_t parent = get_current_element();
+ m_stack.emplace_back(ns, name);
+ return parent;
+}
+
+bool xml_context_base::pop_stack(xmlns_id_t ns, xml_token_t name)
+{
+ const xml_token_pair_t& r = m_stack.back();
+
+ if (ns != r.first || name != r.second)
+ throw general_error("mismatched element name");
+
+ m_stack.pop_back();
+ return m_stack.empty();
+}
+
+xml_token_pair_t xml_context_base::get_current_element() const
+{
+ return m_stack.empty() ? xml_token_pair_t(XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN) : m_stack.back();
+}
+
+const xml_token_pair_t& xml_context_base::get_parent_element() const
+{
+ if (m_stack.size() < 2)
+ throw general_error("element stack has no parent element");
+
+ return m_stack[m_stack.size() - 2];
+}
+
+void xml_context_base::warn_unhandled() const
+{
+ if (!m_config.debug)
+ return;
+
+ cerr << "warning: unhandled element ";
+ print_stack(m_tokens, m_stack, mp_ns_cxt);
+ cerr << endl;
+}
+
+void xml_context_base::warn_unexpected() const
+{
+ if (!m_config.debug)
+ return;
+
+ cerr << "warning: unexpected element ";
+ print_stack(m_tokens, m_stack, mp_ns_cxt);
+ cerr << endl;
+}
+
+void xml_context_base::warn(std::string_view msg) const
+{
+ if (!m_config.debug)
+ return;
+
+ cerr << "warning: " << msg << endl;
+}
+
+void xml_context_base::xml_element_expected(
+ const xml_token_pair_t& elem, xmlns_id_t ns, xml_token_t name,
+ const string* error) const
+{
+ if (!m_config.structure_check)
+ return;
+
+ if (elem.first == ns && elem.second == name)
+ // This is an expected element. Good.
+ return;
+
+ if (m_always_allowed_elements.count(elem))
+ return;
+
+ if (error)
+ {
+ throw xml_structure_error(*error);
+ }
+
+ // Create a generic error message.
+ std::ostringstream os;
+ os << "element ";
+ print_element(os, {ns, name});
+ os << " expected, but ";
+ print_element(os, elem);
+ os << " encountered." << std::endl << std::endl;
+
+ print_current_element_stack(os);
+ throw xml_structure_error(os.str());
+}
+
+void xml_context_base::xml_element_expected(
+ const xml_token_pair_t& elem, const xml_elem_stack_t& expected_elems) const
+{
+ if (!m_config.structure_check)
+ return;
+
+ for (const xml_token_pair_t& e : expected_elems)
+ {
+ if (elem == e)
+ return;
+ }
+
+ if (m_always_allowed_elements.count(elem))
+ return;
+
+ throw_unknown_element_error(elem);
+}
+
+void xml_context_base::xml_element_expected(
+ const xml_token_pair_t& elem, const xml_elem_set_t& expected_elems) const
+{
+ if (!m_config.structure_check)
+ return;
+
+ if (expected_elems.count(elem))
+ return;
+
+ if (m_always_allowed_elements.count(elem))
+ return;
+
+ throw_unknown_element_error(elem);
+}
+
+bool xml_context_base::xml_element_always_allowed(const xml_token_pair_t& elem) const
+{
+ return m_always_allowed_elements.count(elem) > 0;
+}
+
+void xml_context_base::print_namespace(std::ostream& os, xmlns_id_t ns) const
+{
+ m_elem_printer.print_namespace(os, ns);
+}
+
+void xml_context_base::print_element(std::ostream& os, const xml_token_pair_t& elem) const
+{
+ m_elem_printer.print_element(os, elem.first, elem.second);
+}
+
+void xml_context_base::print_current_element_stack(std::ostream& os) const
+{
+ os << "current element stack:" << std::endl << std::endl;
+
+ for (const auto& [ns, name] : m_stack)
+ {
+ os << " - ";
+ print_element(os, {ns, name});
+ os << std::endl;
+ }
+}
+
+void xml_context_base::throw_unknown_element_error(const xml_token_pair_t& elem) const
+{
+ // Create a generic error message.
+ std::ostringstream os;
+ os << "unexpected element encountered: ";
+ print_element(os, elem);
+ os << std::endl << std::endl;
+
+ print_current_element_stack(os);
+ throw xml_structure_error(os.str());
+}
+
+const config& xml_context_base::get_config() const
+{
+ return m_config;
+}
+
+std::string_view xml_context_base::intern(const xml_token_attr_t& attr)
+{
+ return m_session_cxt.intern(attr);
+}
+
+std::string_view xml_context_base::intern(std::string_view s)
+{
+ return m_session_cxt.intern(s);
+}
+
+void xml_context_base::register_child(xml_context_base* child)
+{
+ assert(child);
+ m_child_contexts.push_back(child);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_context_base.hpp b/src/liborcus/xml_context_base.hpp
new file mode 100644
index 0000000..6956806
--- /dev/null
+++ b/src/liborcus/xml_context_base.hpp
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_XML_CONTEXT_BASE_HPP
+#define INCLUDED_ORCUS_XML_CONTEXT_BASE_HPP
+
+#include "xml_element_validator.hpp"
+#include "xml_stream_handler.hpp"
+#include "xml_util.hpp"
+
+namespace orcus {
+
+struct session_context;
+class tokens;
+class xmlns_context;
+class xml_element_validator;
+
+class xml_context_base
+{
+public:
+ xml_context_base(const xml_context_base&) = delete;
+ xml_context_base& operator=(const xml_context_base&) = delete;
+
+ xml_context_base(session_context& session_cxt, const tokens& tokens);
+ virtual ~xml_context_base() = 0;
+
+ /**
+ * This gets called at the end of the initial XML declaration block i.e.
+ * &lt;?xml ... ?&gt;. Obviously this gets called only on the root context.
+ *
+ * @param decl XML declaration attributes
+ */
+ virtual void declaration(const xml_declaration_t& decl);
+
+ /**
+ * This method gets called by the stream handler to fetch a child context
+ * object if applicable. If the current context can handle the specified
+ * element, it should return nullptr. If the current context should spawn a
+ * new context to handle the specified element and its sub structure, then
+ * it should return a pointer to a child context.
+ *
+ * @note The caller is not responsible for managing the life cycle of the
+ * returned context object; the current context object must manage the life
+ * cycle of the context object it returns.
+ *
+ * @param ns namespace value for the element.
+ * @param name name of the element.
+ *
+ * @return pointer to the context object that should handle the specified
+ * element, or nullptr if the current context can handle the
+ * element.
+ */
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name);
+
+ /**
+ * This method gets called when the child context is about to get phased
+ * out, to give the parent context object to communicate with the child
+ * context object before it gets phased out.
+ *
+ * @param ns namespace value for the element.
+ * @param name name of the element.
+ * @param child pointer to the child context object that is about to get
+ * phased out.
+ */
+ virtual void end_child_context(xmlns_id_t ns, xml_token_t name, xml_context_base* child);
+
+ /**
+ * Called on the opening of each element. The implementor should call
+ * push_stack() at the beginning of this method to have the base class keep
+ * track of the element stack. Be sure to also call pop_stack() in
+ * end_element() to maintain correct element stack.
+ *
+ * @param ns namespace token
+ * @param name element name
+ * @param attrs attributes
+ */
+ virtual void start_element(xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) = 0;
+
+ /**
+ * Called on the closing of each element.
+ *
+ * @param ns namespace token
+ * @param name element name
+ *
+ * @return true if the element that's closing is the root element of the
+ * context, else return false. The implementor should simply call
+ * pop_stack() and use the returned value from it as this method's
+ * return value.
+ */
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) = 0;
+
+ /**
+ * Called when passing xml content. When the content value is transient,
+ * the value is not expected to survive beyond the scope of the callback.
+ *
+ * @param str content value.
+ * @param transient whether or not the value is transient.
+ */
+ virtual void characters(std::string_view str, bool transient);
+
+ bool evaluate_child_element(xmlns_id_t ns, xml_token_t name) const;
+
+ void set_ns_context(const xmlns_context* p);
+
+ const config& get_config() const;
+
+ void set_config(const config& opt);
+
+ void set_always_allowed_elements(xml_elem_set_t elems);
+
+protected:
+ void init_element_validator(const xml_element_validator::rule* rules, std::size_t n_rules);
+
+ session_context& get_session_context();
+ const session_context& get_session_context() const;
+ const tokens& get_tokens() const;
+ xml_token_pair_t push_stack(xmlns_id_t ns, xml_token_t name);
+ bool pop_stack(xmlns_id_t ns, xml_token_t name);
+ xml_token_pair_t get_current_stack(xmlns_id_t ns, xml_token_t name);
+ xml_token_pair_t get_current_element() const;
+
+ /**
+ * @warning Don't call this at the root element, or it will throw an
+ * exception.
+ */
+ const xml_token_pair_t& get_parent_element() const;
+ void warn_unhandled() const;
+ void warn_unexpected() const;
+ void warn(std::string_view msg) const;
+
+ /**
+ * Check if observed element equals expected element. If not, it throws an
+ * xml_structure_error exception.
+ *
+ * @param elem element observed.
+ * @param ns namespace of expected element.
+ * @param name name of expected element.
+ * @param error custom error message if needed.
+ */
+ void xml_element_expected(
+ const xml_token_pair_t& elem, xmlns_id_t ns, xml_token_t name,
+ const ::std::string* error = nullptr) const;
+
+ void xml_element_expected(
+ const xml_token_pair_t& elem, const xml_elem_stack_t& expected_elems) const;
+
+ void xml_element_expected(
+ const xml_token_pair_t& elem, const xml_elem_set_t& expected_elems) const;
+
+ bool xml_element_always_allowed(const xml_token_pair_t& elem) const;
+
+ void print_namespace(std::ostream& os, xmlns_id_t ns) const;
+
+ void print_element(std::ostream& os, const xml_token_pair_t& elem) const;
+
+ void print_current_element_stack(std::ostream& os) const;
+
+ /**
+ * Throw a viewer-friendly XML structure error with the information about an
+ * unknown element encountered.
+ *
+ * @param elem unknown element encountered.
+ */
+ void throw_unknown_element_error(const xml_token_pair_t& elem) const;
+
+ std::string_view intern(const xml_token_attr_t& attr);
+ std::string_view intern(std::string_view s);
+
+ void register_child(xml_context_base* child);
+
+private:
+ std::vector<xml_context_base*> m_child_contexts;
+
+ config m_config;
+ const xmlns_context* mp_ns_cxt;
+ session_context& m_session_cxt;
+ const tokens& m_tokens;
+ xml_element_printer m_elem_printer;
+ xml_element_validator m_elem_validator;
+ xml_elem_stack_t m_stack;
+ xml_elem_set_t m_always_allowed_elements;
+};
+
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_context_global.cpp b/src/liborcus/xml_context_global.cpp
new file mode 100644
index 0000000..5c98f07
--- /dev/null
+++ b/src/liborcus/xml_context_global.cpp
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_context_global.hpp"
+#include "orcus/string_pool.hpp"
+#include "orcus/measurement.hpp"
+
+#include <algorithm>
+
+namespace orcus {
+
+single_attr_getter::single_attr_getter(string_pool& pool, xmlns_id_t ns, xml_token_t name) :
+ m_pool(&pool), m_ns(ns), m_name(name) {}
+
+single_attr_getter::single_attr_getter(xmlns_id_t ns, xml_token_t name) :
+ m_pool(nullptr), m_ns(ns), m_name(name) {}
+
+void single_attr_getter::operator() (const xml_token_attr_t& attr)
+{
+ if (attr.name != m_name)
+ return;
+
+ if (attr.ns && attr.ns != m_ns)
+ return;
+
+ m_value = attr.value;
+ if (attr.transient && m_pool)
+ m_value = m_pool->intern(m_value).first;
+}
+
+std::string_view single_attr_getter::get_value() const
+{
+ return m_value;
+}
+
+std::string_view single_attr_getter::get(
+ const std::vector<xml_token_attr_t>& attrs, xmlns_id_t ns, xml_token_t name)
+{
+ single_attr_getter func(ns, name);
+ return std::for_each(attrs.begin(), attrs.end(), func).get_value();
+}
+
+std::string_view single_attr_getter::get(
+ const std::vector<xml_token_attr_t>& attrs, string_pool& pool, xmlns_id_t ns, xml_token_t name)
+{
+ single_attr_getter func(pool, ns, name);
+ return std::for_each(attrs.begin(), attrs.end(), func).get_value();
+}
+
+single_long_attr_getter::single_long_attr_getter(xmlns_id_t ns, xml_token_t name) :
+ m_value(-1), m_ns(ns), m_name(name) {}
+
+void single_long_attr_getter::operator() (const xml_token_attr_t& attr)
+{
+ if (attr.name != m_name)
+ return;
+
+ if (attr.ns && attr.ns != m_ns)
+ return;
+
+ m_value = to_long(attr.value);
+}
+
+long single_long_attr_getter::get_value() const
+{
+ return m_value;
+}
+
+long single_long_attr_getter::get(const std::vector<xml_token_attr_t>& attrs, xmlns_id_t ns, xml_token_t name)
+{
+ single_long_attr_getter func(ns, name);
+ return std::for_each(attrs.begin(), attrs.end(), func).get_value();
+}
+
+single_double_attr_getter::single_double_attr_getter(xmlns_id_t ns, xml_token_t name) :
+ m_value(-1.0), m_ns(ns), m_name(name) {}
+
+void single_double_attr_getter::operator() (const xml_token_attr_t& attr)
+{
+ if (attr.name != m_name)
+ return;
+
+ if (attr.ns && attr.ns != m_ns)
+ return;
+
+ m_value = to_double(attr.value);
+}
+
+double single_double_attr_getter::get_value() const
+{
+ return m_value;
+}
+
+double single_double_attr_getter::get(const std::vector<xml_token_attr_t>& attrs, xmlns_id_t ns, xml_token_t name)
+{
+ single_double_attr_getter func(ns, name);
+ return std::for_each(attrs.begin(), attrs.end(), func).get_value();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_context_global.hpp b/src/liborcus/xml_context_global.hpp
new file mode 100644
index 0000000..b05dd28
--- /dev/null
+++ b/src/liborcus/xml_context_global.hpp
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XML_CONTEXT_GLOBAL_HPP
+#define ORCUS_XML_CONTEXT_GLOBAL_HPP
+
+#include <orcus/types.hpp>
+
+#include <functional>
+
+namespace orcus {
+
+class string_pool;
+
+/**
+ * Use this just to get the value of a single attribute for a given element.
+ */
+class single_attr_getter
+{
+ string_pool* m_pool;
+ std::string_view m_value;
+ xmlns_id_t m_ns;
+ xml_token_t m_name;
+
+public:
+ single_attr_getter(xmlns_id_t ns, xml_token_t name);
+ single_attr_getter(string_pool& pool, xmlns_id_t ns, xml_token_t name);
+
+ void operator() (const xml_token_attr_t& attr);
+ std::string_view get_value() const;
+
+ static std::string_view get(const std::vector<xml_token_attr_t>& attrs, xmlns_id_t ns, xml_token_t name);
+ static std::string_view get(const std::vector<xml_token_attr_t>& attrs, string_pool& pool, xmlns_id_t ns, xml_token_t name);
+};
+
+class single_long_attr_getter
+{
+ long m_value;
+ xmlns_id_t m_ns;
+ xml_token_t m_name;
+
+public:
+ single_long_attr_getter(xmlns_id_t ns, xml_token_t name);
+ void operator() (const xml_token_attr_t& attr);
+ long get_value() const;
+
+ static long get(const std::vector<xml_token_attr_t>& attrs, xmlns_id_t ns, xml_token_t name);
+};
+
+class single_double_attr_getter
+{
+ double m_value;
+ xmlns_id_t m_ns;
+ xml_token_t m_name;
+
+public:
+ single_double_attr_getter(xmlns_id_t ns, xml_token_t name);
+ void operator() (const xml_token_attr_t& attr);
+ double get_value() const;
+
+ static double get(const std::vector<xml_token_attr_t>& attrs, xmlns_id_t ns, xml_token_t name);
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_element_types.cpp b/src/liborcus/xml_element_types.cpp
new file mode 100644
index 0000000..967b4d4
--- /dev/null
+++ b/src/liborcus/xml_element_types.cpp
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_element_types.hpp"
+
+namespace orcus {
+
+size_t xml_token_pair_hash::operator()(const xml_token_pair_t& v) const
+{
+ return std::hash<const char*>()(v.first) ^ std::hash<size_t>()(v.second);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_element_types.hpp b/src/liborcus/xml_element_types.hpp
new file mode 100644
index 0000000..2e7bc15
--- /dev/null
+++ b/src/liborcus/xml_element_types.hpp
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <orcus/types.hpp>
+
+namespace orcus {
+
+/**
+ * Holds a pair of XML namespace identifier and an element token. Typically
+ * used when managing the element stack inside element context classes.
+ */
+using xml_token_pair_t = std::pair<xmlns_id_t, xml_token_t>;
+
+struct xml_token_pair_hash
+{
+ size_t operator()(const xml_token_pair_t& v) const;
+};
+
+using xml_elem_stack_t = std::vector<xml_token_pair_t>;
+using xml_elem_set_t = std::unordered_set<xml_token_pair_t, xml_token_pair_hash>;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_element_validator.cpp b/src/liborcus/xml_element_validator.cpp
new file mode 100644
index 0000000..ceb632c
--- /dev/null
+++ b/src/liborcus/xml_element_validator.cpp
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_element_validator.hpp"
+
+namespace orcus {
+
+xml_element_validator::xml_element_validator()
+{
+}
+
+xml_element_validator::xml_element_validator(const rule* rules, std::size_t n_rules)
+{
+ init(rules, n_rules);
+}
+
+void xml_element_validator::init(const rule* rules, std::size_t n_rules)
+{
+ const rule* end_rules = rules + n_rules;
+
+ for (; rules != end_rules; ++rules)
+ {
+ const xml_token_pair_t parent(rules->ns_parent, rules->name_parent);
+ const xml_token_pair_t child(rules->ns_child, rules->name_child);
+
+ auto it = m_rules.find(parent);
+ if (it == m_rules.end())
+ {
+ auto res = m_rules.emplace(parent, xml_elem_set_t{});
+ it = res.first;
+ }
+
+ xml_elem_set_t& children = it->second;
+ children.insert(child);
+ }
+}
+
+xml_element_validator::result xml_element_validator::validate(
+ const xml_token_pair_t& parent, const xml_token_pair_t& child) const
+{
+ if (m_rules.empty())
+ // No rules are defined. Allow everything.
+ return result::child_valid;
+
+ auto it = m_rules.find(parent);
+ if (it == m_rules.end())
+ // No rules for this parent.
+ return result::parent_unknown;
+
+ const xml_elem_set_t& rules = it->second;
+ return rules.count(child) > 0 ? result::child_valid : result::child_invalid;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_element_validator.hpp b/src/liborcus/xml_element_validator.hpp
new file mode 100644
index 0000000..43a44e0
--- /dev/null
+++ b/src/liborcus/xml_element_validator.hpp
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "xml_element_types.hpp"
+
+#include <unordered_map>
+
+namespace orcus {
+
+class xml_element_validator
+{
+ using rule_map_type = std::unordered_map<xml_token_pair_t, xml_elem_set_t, xml_token_pair_hash>;
+ rule_map_type m_rules;
+
+public:
+
+ /** represents a single parent to child mapping rule. It must be a POD. */
+ struct rule
+ {
+ const xmlns_id_t ns_parent;
+ const xml_token_t name_parent;
+ const xmlns_id_t ns_child;
+ const xml_token_t name_child;
+ };
+
+ /** validation result */
+ enum class result
+ {
+ parent_unknown, //< no rules defined for this parent
+ child_valid, //< parent allows this child
+ child_invalid //< parent does not allow this child
+ };
+
+ xml_element_validator();
+ xml_element_validator(const rule* rules, std::size_t n_rules);
+
+ void init(const rule* rules, std::size_t n_rules);
+
+ result validate(const xml_token_pair_t& parent, const xml_token_pair_t& child) const;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_empty_context.cpp b/src/liborcus/xml_empty_context.cpp
new file mode 100644
index 0000000..f39636b
--- /dev/null
+++ b/src/liborcus/xml_empty_context.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_empty_context.hpp"
+
+namespace orcus {
+
+xml_empty_context::xml_empty_context(session_context& session_cxt, const tokens& tokens) :
+ xml_context_base(session_cxt, tokens)
+{
+}
+
+xml_context_base* xml_empty_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
+{
+ return nullptr;
+}
+
+void xml_empty_context::end_child_context(
+ xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
+{
+}
+
+void xml_empty_context::start_element(
+ xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& /*attrs*/)
+{
+ push_stack(ns, name);
+}
+
+bool xml_empty_context::end_element(xmlns_id_t ns, xml_token_t name)
+{
+ return pop_stack(ns, name);
+}
+
+void xml_empty_context::characters(std::string_view /*str*/, bool /*transient*/)
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_empty_context.hpp b/src/liborcus/xml_empty_context.hpp
new file mode 100644
index 0000000..502e199
--- /dev/null
+++ b/src/liborcus/xml_empty_context.hpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "xml_context_base.hpp"
+
+namespace orcus {
+
+/**
+ * This context only tracks the scopes of all encountered elements but does
+ * nothing else. It is to be used when you need to ignore a whole sub
+ * structure of an XML document.
+ */
+class xml_empty_context : public xml_context_base
+{
+public:
+ xml_empty_context(session_context& session_cxt, const tokens& tokens);
+
+ virtual xml_context_base* create_child_context(xmlns_id_t ns, xml_token_t name) override;
+
+ virtual void end_child_context(
+ xmlns_id_t ns, xml_token_t name, xml_context_base* child) override;
+
+ virtual void start_element(
+ xmlns_id_t ns, xml_token_t name, const std::vector<xml_token_attr_t>& attrs) override;
+
+ virtual bool end_element(xmlns_id_t ns, xml_token_t name) override;
+
+ virtual void characters(std::string_view str, bool transient) override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_map_tree.cpp b/src/liborcus/xml_map_tree.cpp
new file mode 100644
index 0000000..5d2ea72
--- /dev/null
+++ b/src/liborcus/xml_map_tree.cpp
@@ -0,0 +1,772 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_map_tree.hpp"
+#include "xpath_parser.hpp"
+
+#define ORCUS_DEBUG_XML_MAP_TREE 0
+
+#if ORCUS_DEBUG_XML_MAP_TREE
+#include <iostream>
+#endif
+
+#include <cassert>
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+
+namespace orcus {
+
+namespace {
+
+template<typename T>
+void print_element_stack(std::ostream& os, const T& elem_stack)
+{
+ for (const auto& elem : elem_stack)
+ os << '/' << elem->name.name;
+}
+
+} // anonymous namespace
+
+xml_map_tree::range_field_link::range_field_link(std::string_view _xpath, std::string_view _label) :
+ xpath(_xpath), label(_label) {}
+
+xml_map_tree::element_position::element_position() :
+ open_begin(0), open_end(0), close_begin(0), close_end(0) {}
+
+xml_map_tree::cell_reference::cell_reference() {}
+
+xml_map_tree::range_reference::range_reference(const cell_position& _pos) :
+ pos(_pos), row_position(0) {}
+
+xml_map_tree::linkable::linkable(
+ xml_map_tree& parent, const xml_name_t& _name, linkable_node_type _node_type, reference_type _ref_type) :
+ name(_name), node_type(_node_type), ref_type(_ref_type)
+{
+ parent.create_ref_store(*this);
+}
+
+xml_map_tree::attribute::attribute(args_type args) :
+ linkable(std::get<0>(args), xml_name_t(std::get<1>(args)), linkable_node_type::attribute, std::get<2>(args)) {}
+
+xml_map_tree::attribute::~attribute() {}
+
+xml_map_tree::element::element(args_type args) :
+ linkable(std::get<0>(args), std::get<1>(args), linkable_node_type::element, std::get<3>(args)),
+ elem_type(std::get<2>(args)),
+ child_elements(nullptr),
+ range_parent(nullptr),
+ row_group(nullptr),
+ row_group_position(0)
+{
+ xml_map_tree& parent = std::get<0>(args);
+
+ if (elem_type == element_type::unlinked)
+ {
+ child_elements = parent.m_element_store_pool.construct();
+ return;
+ }
+
+ assert(elem_type == element_type::linked);
+}
+
+xml_map_tree::element::~element() {}
+
+xml_map_tree::element* xml_map_tree::element::get_child(const xml_name_t& _name)
+{
+ if (elem_type != element_type::unlinked)
+ return nullptr;
+
+ assert(child_elements);
+
+ auto it = std::find_if(
+ child_elements->begin(), child_elements->end(),
+ [&_name](const element* p) -> bool
+ {
+ return p->name == _name;
+ }
+ );
+
+ return it == child_elements->end() ? nullptr : *it;
+}
+
+xml_map_tree::element* xml_map_tree::element::get_or_create_child(
+ xml_map_tree& parent, const xml_name_t& _name)
+{
+ auto it = std::find_if(
+ child_elements->begin(), child_elements->end(),
+ [&_name](const element* p) -> bool
+ {
+ return p->name == _name;
+ }
+ );
+
+ if (it != child_elements->end())
+ return *it;
+
+ string_pool& sp = parent.m_names;
+
+ // Insert a new element of this name.
+ auto const nm = sp.intern(_name.name).first; // work around LLVM < 7 libc++ bug
+ child_elements->push_back(
+ parent.m_element_pool.construct(
+ element::args_type(
+ parent,
+ xml_name_t(_name.ns, nm),
+ element_type::unlinked,
+ reference_type::unknown
+ )
+ )
+ );
+
+ return child_elements->back();
+}
+
+xml_map_tree::element* xml_map_tree::element::get_or_create_linked_child(
+ xml_map_tree& parent, const xml_name_t& _name, reference_type _ref_type)
+{
+ if (!child_elements)
+ {
+ assert(elem_type == element_type::linked);
+ std::ostringstream os;
+ constexpr xml_name_t::to_string_type type = xml_name_t::use_alias;
+
+ os << "You can't add a child element under an already linked element (this='"
+ << name.to_string(parent.m_xmlns_cxt, type) << "'; child='"
+ << _name.to_string(parent.m_xmlns_cxt, type) << "')";
+
+ throw invalid_map_error(os.str());
+ }
+
+ auto it = std::find_if(
+ child_elements->begin(), child_elements->end(),
+ [&_name](const element* p) -> bool
+ {
+ return p->name == _name;
+ }
+ );
+
+ if (it != child_elements->end())
+ {
+ // Specified child element already exists. Make sure it's unlinked.
+ element* elem = *it;
+ if (elem->ref_type != reference_type::unknown || elem->elem_type != element_type::unlinked)
+ throw xpath_error("This element is already linked. You can't link the same element twice.");
+
+ elem->link_reference(parent, _ref_type);
+ return elem;
+ }
+
+ string_pool& sp = parent.m_names;
+
+ // Insert a new linked element of this name.
+ auto const nm = sp.intern(_name.name).first; // work around LLVM < 7 libc++ bug
+ child_elements->push_back(
+ parent.m_element_pool.construct(
+ element::args_type(
+ parent,
+ xml_name_t(_name.ns, nm),
+ element_type::linked,
+ _ref_type
+ )
+ )
+ );
+
+ return child_elements->back();
+}
+
+void xml_map_tree::element::link_reference(xml_map_tree& parent, reference_type _ref_type)
+{
+ if (elem_type == element_type::unlinked)
+ parent.m_element_store_pool.destroy(child_elements);
+
+ elem_type = element_type::linked;
+ ref_type = _ref_type;
+ parent.create_ref_store(*this);
+}
+
+bool xml_map_tree::element::unlinked_attribute_anchor() const
+{
+ return elem_type == element_type::unlinked && ref_type == reference_type::unknown && !attributes.empty();
+}
+
+xml_map_tree::walker::walker(const xml_map_tree& parent) :
+ m_parent(parent) {}
+xml_map_tree::walker::walker(const xml_map_tree::walker& r) :
+ m_parent(r.m_parent), m_stack(r.m_stack), m_unlinked_stack(r.m_unlinked_stack) {}
+
+void xml_map_tree::walker::reset()
+{
+ m_stack.clear();
+ m_unlinked_stack.clear();
+}
+
+xml_map_tree::element* xml_map_tree::walker::push_element(const xml_name_t& name)
+{
+ if (!m_unlinked_stack.empty())
+ {
+ // We're still in the unlinked region.
+ m_unlinked_stack.push_back(name);
+ return nullptr;
+ }
+
+ if (m_stack.empty())
+ {
+ if (!m_parent.mp_root)
+ {
+ // Tree is empty.
+ m_unlinked_stack.push_back(name);
+ return nullptr;
+ }
+
+ element* p = m_parent.mp_root;
+ if (p->name != name)
+ {
+ // Names differ.
+ m_unlinked_stack.push_back(name);
+ return nullptr;
+ }
+
+ m_stack.push_back(p);
+ return p;
+ }
+
+ if (m_stack.back()->elem_type == element_type::unlinked)
+ {
+ // Check if the current element has a child of the same name.
+ element* p = m_stack.back()->get_child(name);
+ if (p)
+ {
+ m_stack.push_back(p);
+ return p;
+ }
+ }
+
+ m_unlinked_stack.push_back(name);
+ return nullptr;
+}
+
+xml_map_tree::element* xml_map_tree::walker::pop_element(const xml_name_t& name)
+{
+ if (!m_unlinked_stack.empty())
+ {
+ // We're in the unlinked region. Pop element from the unlinked stack.
+ if (m_unlinked_stack.back() != name)
+ throw general_error("Closing element has a different name than the opening element. (unlinked stack)");
+
+ m_unlinked_stack.pop_back();
+
+ if (!m_unlinked_stack.empty())
+ // We are still in the unlinked region.
+ return nullptr;
+
+ return m_stack.empty() ? nullptr : m_stack.back();
+ }
+
+ if (m_stack.empty())
+ throw general_error("Element was popped while the stack was empty.");
+
+ if (m_stack.back()->name != name)
+ throw general_error("Closing element has a different name than the opening element. (linked stack)");
+
+ m_stack.pop_back();
+ return m_stack.empty() ? nullptr : m_stack.back();
+}
+
+xml_map_tree::xml_map_tree(xmlns_repository& xmlns_repo) :
+ m_xmlns_cxt(xmlns_repo.create_context()),
+ mp_root(nullptr),
+ m_default_ns(XMLNS_UNKNOWN_ID) {}
+
+xml_map_tree::~xml_map_tree() {}
+
+void xml_map_tree::set_namespace_alias(std::string_view alias, std::string_view uri, bool default_ns)
+{
+#if ORCUS_DEBUG_XML_MAP_TREE
+ cout << "xml_map_tree::set_namespace_alias: alias='" << alias << "', uri='" << uri << "', default=" << default_ns << endl;
+#endif
+ // We need to turn the alias string persistent because the xmlns context
+ // doesn't intern the alias strings.
+ std::string_view alias_safe = m_names.intern(alias).first;
+ xmlns_id_t ns = m_xmlns_cxt.push(alias_safe, uri);
+
+ if (default_ns)
+ m_default_ns = ns;
+}
+
+xmlns_id_t xml_map_tree::get_namespace(std::string_view alias) const
+{
+ return m_xmlns_cxt.get(alias);
+}
+
+void xml_map_tree::set_cell_link(std::string_view xpath, const cell_position& ref)
+{
+ if (xpath.empty())
+ return;
+
+#if ORCUS_DEBUG_XML_MAP_TREE
+ cout << "xml_map_tree::set_cell_link: xpath='" << xpath << "' (ref=" << ref << ")" << endl;
+#endif
+
+ linked_node_type linked_node = get_linked_node(xpath, reference_type::cell);
+ assert(linked_node.node);
+ assert(!linked_node.elem_stack.empty());
+ cell_reference* cell_ref = nullptr;
+ switch (linked_node.node->node_type)
+ {
+ case linkable_node_type::element:
+ assert(static_cast<element*>(linked_node.node)->cell_ref);
+ cell_ref = static_cast<element*>(linked_node.node)->cell_ref;
+ break;
+ case linkable_node_type::attribute:
+ assert(static_cast<attribute*>(linked_node.node)->cell_ref);
+ cell_ref = static_cast<attribute*>(linked_node.node)->cell_ref;
+ break;
+ default:
+ throw general_error("unknown node type returned from get_element_stack call in xml_map_tree::set_cell_link().");
+ }
+
+ cell_ref->pos = ref;
+}
+
+void xml_map_tree::start_range(const cell_position& pos)
+{
+ m_cur_range_field_links.clear();
+ m_cur_range_pos = pos;
+}
+
+void xml_map_tree::append_range_field_link(std::string_view xpath, std::string_view label)
+{
+ if (xpath.empty())
+ return;
+
+ m_cur_range_field_links.emplace_back(xpath, label);
+}
+
+void xml_map_tree::insert_range_field_link(
+ range_reference& range_ref, element_list_type& range_parent, const range_field_link& field)
+{
+ linked_node_type linked_node = get_linked_node(field.xpath, reference_type::range_field);
+ if (linked_node.elem_stack.size() < 2)
+ throw xpath_error("Path of a range field link must be at least 2 levels.");
+
+ if (linked_node.node->node_type == linkable_node_type::unknown)
+ throw xpath_error("Unrecognized node type");
+
+ if (linked_node.anchor_elem)
+ linked_node.anchor_elem->linked_range_fields.push_back(range_ref.field_nodes.size());
+
+ if (!field.label.empty())
+ linked_node.node->label = intern_string(field.label);
+
+ switch (linked_node.node->node_type)
+ {
+ case linkable_node_type::element:
+ {
+ element* p = static_cast<element*>(linked_node.node);
+ assert(p && p->ref_type == reference_type::range_field && p->field_ref);
+ p->field_ref->ref = &range_ref;
+ p->field_ref->column_pos = range_ref.field_nodes.size();
+
+ range_ref.field_nodes.push_back(p);
+ break;
+ }
+ case linkable_node_type::attribute:
+ {
+ attribute* p = static_cast<attribute*>(linked_node.node);
+ assert(p && p->ref_type == reference_type::range_field && p->field_ref);
+ p->field_ref->ref = &range_ref;
+ p->field_ref->column_pos = range_ref.field_nodes.size();
+
+ range_ref.field_nodes.push_back(p);
+ break;
+ }
+ default:
+ ;
+ }
+
+ // Determine the deepest common element for all field link elements in the
+ // current range reference.
+ if (range_parent.empty())
+ {
+ // First field link in this range. Find the first row-group element
+ // going up from the linked node.
+ auto rit = linked_node.elem_stack.rbegin();
+ while (rit != linked_node.elem_stack.rend() && !(*rit)->row_group)
+ ++rit;
+
+ ++rit; // parent of the raw group
+ auto it_end = rit.base();
+
+ range_parent.assign(linked_node.elem_stack.begin(), it_end);
+ }
+ else
+ {
+ // Determine the deepest common element between the two.
+ element_list_type::iterator it_elem = linked_node.elem_stack.begin(), it_elem_end = linked_node.elem_stack.end();
+ element_list_type::iterator it_cur = range_parent.begin(), it_cur_end = range_parent.end();
+ if (*it_elem != *it_cur)
+ throw xpath_error("Two field links in the same range reference start with different root elements.");
+
+ ++it_elem;
+ ++it_cur;
+
+ for (; it_elem != it_elem_end && it_cur != it_cur_end; ++it_elem, ++it_cur)
+ {
+ if (*it_elem == *it_cur)
+ continue;
+
+ // The two elements differ. Take their parent element as the new common element.
+ range_parent.assign(linked_node.elem_stack.begin(), it_elem); // current elemnt excluded.
+ break;
+ }
+
+ if (range_parent.empty())
+ throw xpath_error("Two field links in the same range reference must at least share the first level of their paths.");
+ }
+
+#if ORCUS_DEBUG_XML_MAP_TREE
+ print_element_stack(std::cout, range_parent);
+ std::cout << std::endl;
+#endif
+}
+
+void xml_map_tree::set_range_row_group(std::string_view xpath)
+{
+ if (xpath.empty())
+ return;
+
+ range_reference* range_ref = get_range_reference(m_cur_range_pos);
+ assert(range_ref);
+
+ element* elem = get_element(xpath);
+ assert(elem);
+ elem->row_group = range_ref;
+}
+
+void xml_map_tree::commit_range()
+{
+ if (m_cur_range_field_links.empty())
+ // Nothing to commit.
+ return;
+
+ range_reference* range_ref = get_range_reference(m_cur_range_pos);
+ assert(range_ref);
+
+ // commont parent element for this range.
+ element_list_type range_parent;
+
+ for (const range_field_link& field : m_cur_range_field_links)
+ insert_range_field_link(*range_ref, range_parent, field);
+
+#if ORCUS_DEBUG_XML_MAP_TREE
+ cout << "parent element path for this range: ";
+ for (const element* elem : range_parent)
+ cout << "/" << elem->name.to_string(m_xmlns_cxt, xml_name_t::use_alias);
+ cout << endl;
+#endif
+
+ assert(!range_parent.empty());
+ // Mark the range parent element.
+ range_parent.back()->range_parent = range_ref;
+
+ // Set the current position invalid.
+ m_cur_range_pos.row = -1;
+ m_cur_range_pos.col = -1;
+}
+
+const xml_map_tree::linkable* xml_map_tree::get_link(std::string_view xpath) const
+{
+ if (!mp_root)
+ return nullptr;
+
+ if (xpath.empty())
+ return nullptr;
+
+#if ORCUS_DEBUG_XML_MAP_TREE
+ cout << "xml_map_tree::get_link: xpath = '" << xpath << "'" << endl;
+#endif
+ const linkable* cur_node = mp_root;
+
+ xpath_parser parser(m_xmlns_cxt, xpath.data(), xpath.size(), m_default_ns);
+
+ // Check the root element first.
+ xpath_parser::token token = parser.next();
+ if (cur_node->name.ns != token.ns || cur_node->name.name != token.name)
+ // Root element name doesn't match.
+ return nullptr;
+
+#if ORCUS_DEBUG_XML_MAP_TREE
+ cout << "xml_map_tree::get_link: root = (ns=" << token.ns << ", name=" << token.name << ")" << endl;
+#endif
+ for (token = parser.next(); !token.name.empty(); token = parser.next())
+ {
+ if (token.attribute)
+ {
+ // The current node should be an element and should have an attribute of the same name.
+ if (cur_node->node_type != linkable_node_type::element)
+ return nullptr;
+
+ const element* elem = static_cast<const element*>(cur_node);
+ const attribute_store_type& attrs = elem->attributes;
+ auto it = std::find_if(
+ attrs.begin(), attrs.end(),
+ [&token](const attribute* p) -> bool
+ {
+ return p->name.ns == token.ns && p->name.name == token.name;
+ }
+ );
+
+ if (it == attrs.end())
+ // No such attribute exists.
+ return nullptr;
+
+ return *it;
+ }
+
+ // See if an element of this name exists below the current element.
+
+ if (cur_node->node_type != linkable_node_type::element)
+ return nullptr;
+
+ const element* elem = static_cast<const element*>(cur_node);
+ if (elem->elem_type != element_type::unlinked)
+ return nullptr;
+
+ if (!elem->child_elements)
+ return nullptr;
+
+ auto it = std::find_if(
+ elem->child_elements->begin(), elem->child_elements->end(),
+ [&token](const element* p) -> bool
+ {
+ return p->name.ns == token.ns && p->name.name == token.name;
+ }
+ );
+
+ if (it == elem->child_elements->end())
+ // No such child element exists.
+ return nullptr;
+
+ cur_node = *it;
+ }
+
+ if (cur_node->node_type != linkable_node_type::element || static_cast<const element*>(cur_node)->elem_type == element_type::unlinked)
+ // Non-leaf elements are not links.
+ return nullptr;
+
+ return cur_node;
+}
+
+xml_map_tree::walker xml_map_tree::get_tree_walker() const
+{
+ return walker(*this);
+}
+
+xml_map_tree::range_ref_map_type& xml_map_tree::get_range_references()
+{
+ return m_field_refs;
+}
+
+std::string_view xml_map_tree::intern_string(std::string_view str) const
+{
+ return m_names.intern(str).first;
+}
+
+xml_map_tree::range_reference* xml_map_tree::get_range_reference(const cell_position& pos)
+{
+ range_ref_map_type::iterator it = m_field_refs.lower_bound(pos);
+ if (it == m_field_refs.end() || m_field_refs.key_comp()(pos, it->first))
+ {
+ // This reference does not exist yet. Insert a new one.
+
+ // Make sure the sheet name string is persistent.
+ cell_position pos_safe = pos;
+ pos_safe.sheet = m_names.intern(pos.sheet).first;
+
+ it = m_field_refs.insert(
+ it, range_ref_map_type::value_type(
+ pos_safe,
+ m_range_reference_pool.construct(pos_safe)));
+ }
+
+ return it->second;
+}
+
+void xml_map_tree::create_ref_store(linkable& node)
+{
+ switch (node.ref_type)
+ {
+ case xml_map_tree::reference_type::cell:
+ node.cell_ref = m_cell_reference_pool.construct();
+ break;
+ case xml_map_tree::reference_type::range_field:
+ node.field_ref = m_field_in_range_pool.construct();
+ break;
+ case xml_map_tree::reference_type::unknown:
+ break;
+ }
+}
+
+xml_map_tree::linked_node_type xml_map_tree::get_linked_node(std::string_view xpath, reference_type ref_type)
+{
+ linked_node_type ret;
+
+ assert(!xpath.empty());
+ xpath_parser parser(m_xmlns_cxt, xpath.data(), xpath.size(), m_default_ns);
+
+ // Get the root element first.
+ xpath_parser::token token = parser.next();
+ if (mp_root)
+ {
+ // Make sure the root element's names are the same.
+ if (mp_root->name.ns != token.ns || mp_root->name.name != token.name)
+ throw xpath_error("path begins with inconsistent root level name.");
+ }
+ else
+ {
+ // First time the root element is encountered.
+ if (token.attribute)
+ throw xpath_error("root element cannot be an attribute.");
+
+ auto const nm = m_names.intern(token.name).first; // work around LLVM < 7 libc++ bug
+ mp_root = m_element_pool.construct(
+ element::args_type(
+ *this,
+ xml_name_t(token.ns, nm),
+ element_type::unlinked,
+ reference_type::unknown
+ )
+ );
+ }
+
+ ret.elem_stack.push_back(mp_root);
+ element* cur_element = ret.elem_stack.back();
+ assert(cur_element);
+ assert(cur_element->child_elements);
+
+ element* row_group_elem = nullptr;
+
+ token = parser.next();
+ for (xpath_parser::token token_next = parser.next(); !token_next.name.empty(); token_next = parser.next())
+ {
+ // Check if the current element contains a child element of the same name.
+ if (token.attribute)
+ throw xpath_error("attribute must always be at the end of the path.");
+
+ cur_element = cur_element->get_or_create_child(*this, {token.ns, token.name});
+ ret.elem_stack.push_back(cur_element);
+ token = token_next;
+
+ if (cur_element->row_group)
+ row_group_elem = cur_element;
+ }
+
+ assert(cur_element);
+
+ // Insert a leaf node.
+
+ if (token.attribute)
+ {
+ // This is an attribute. Insert it into the current element.
+ attribute_store_type& attrs = cur_element->attributes;
+
+ // Check if an attribute of the same name already exists.
+ auto it = std::find_if(
+ attrs.begin(), attrs.end(),
+ [&token](const attribute* p) -> bool
+ {
+ return p->name.ns == token.ns && p->name.name == token.name;
+ }
+ );
+
+ if (it != attrs.end())
+ throw xpath_error("This attribute is already linked. You can't link the same attribute twice.");
+
+ auto const nm = m_names.intern(token.name).first; // work around LLVM < 7 libc++ bug
+ attribute* p = m_attribute_pool.construct(
+ attribute::args_type(
+ *this,
+ xml_name_t(token.ns, nm),
+ ref_type
+ )
+ );
+
+ attrs.push_back(p);
+ ret.node = attrs.back();
+ }
+ else
+ {
+ element* elem = cur_element->get_or_create_linked_child(*this, {token.ns, token.name}, ref_type);
+ ret.elem_stack.push_back(elem);
+ ret.node = elem;
+
+ if (elem->row_group)
+ row_group_elem = elem;
+ }
+
+ ret.anchor_elem = row_group_elem;
+ return ret;
+}
+
+xml_map_tree::element* xml_map_tree::get_element(std::string_view xpath)
+{
+ assert(!xpath.empty());
+ xpath_parser parser(m_xmlns_cxt, xpath.data(), xpath.size(), m_default_ns);
+
+ // Get the root element first.
+ xpath_parser::token token = parser.next();
+ if (mp_root)
+ {
+ // Make sure the root element's names are the same.
+ if (mp_root->name.ns != token.ns || mp_root->name.name != token.name)
+ throw xpath_error("path begins with inconsistent root level name.");
+ }
+ else
+ {
+ // First time the root element is encountered.
+ if (token.attribute)
+ throw xpath_error("root element cannot be an attribute.");
+
+ auto const nm = m_names.intern(token.name).first; // work around LLVM < 7 libc++ bug
+ mp_root = m_element_pool.construct(
+ element::args_type(
+ *this,
+ xml_name_t(token.ns, nm),
+ element_type::unlinked,
+ reference_type::unknown
+ )
+ );
+ }
+
+ element* cur_element = mp_root;
+ assert(cur_element->child_elements);
+
+ for (token = parser.next(); !token.name.empty(); token = parser.next())
+ {
+ // Check if the current element contains a child element of the same name.
+ if (token.attribute)
+ throw xpath_error("attribute was not expected.");
+
+ cur_element = cur_element->get_or_create_child(*this, {token.ns, token.name});
+ }
+
+ assert(cur_element);
+ return cur_element;
+}
+
+std::ostream& operator<< (std::ostream& os, const xml_map_tree::linkable& link)
+{
+ if (!link.ns_alias.empty())
+ os << link.ns_alias << ':';
+ os << link.name.name;
+ return os;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_map_tree.hpp b/src/liborcus/xml_map_tree.hpp
new file mode 100644
index 0000000..841df0d
--- /dev/null
+++ b/src/liborcus/xml_map_tree.hpp
@@ -0,0 +1,316 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_XML_MAP_TREE_HPP
+#define INCLUDED_ORCUS_XML_MAP_TREE_HPP
+
+#include "orcus/spreadsheet/types.hpp"
+#include "orcus/exception.hpp"
+#include "orcus/types.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/string_pool.hpp"
+
+#include "spreadsheet_impl_types.hpp"
+
+#include <ostream>
+#include <map>
+#include <vector>
+#include <deque>
+#include <memory>
+
+#include <boost/pool/object_pool.hpp>
+
+namespace orcus {
+
+class xmlns_repository;
+
+/**
+ * Tree structure representing XML-to-sheet mapping rules for mapped XML
+ * import. This structure only contains linked elements and attributes and
+ * their parent elements; it does not contain the entire structure of the
+ * imported XML.
+ */
+class xml_map_tree
+{
+ struct range_field_link
+ {
+ std::string_view xpath;
+ std::string_view label;
+
+ range_field_link(std::string_view _xpath, std::string_view _label);
+ };
+
+public:
+ /**
+ * A single cell position. Used both for single cell as well as range
+ * links. For a range link, this represents the upper-left cell of a
+ * range.
+ */
+ using cell_position = spreadsheet::detail::cell_position_t;
+
+ /**
+ * Positions of opening and closing elements in xml stream.
+ */
+ struct element_position
+ {
+ std::ptrdiff_t open_begin;
+ std::ptrdiff_t open_end;
+ std::ptrdiff_t close_begin;
+ std::ptrdiff_t close_end;
+
+ element_position();
+ };
+
+ struct cell_reference
+ {
+ cell_position pos;
+
+ cell_reference(const cell_reference&) = delete;
+ cell_reference& operator=(const cell_reference&) = delete;
+
+ cell_reference();
+ };
+
+ struct element;
+ struct linkable;
+ using element_store_type = std::deque<element*>;
+ using element_list_type = std::vector<element*>;
+ using const_element_list_type = std::vector<const element*>;
+
+ struct range_reference
+ {
+ cell_position pos;
+
+ /**
+ * List of elements comprising the fields, in order of appearance from
+ * left to right.
+ */
+ std::vector<const linkable*> field_nodes;
+
+ /**
+ * Total number of rows comprising data. This does not include the
+ * label row at the top.
+ */
+ spreadsheet::row_t row_position;
+
+ range_reference(const range_reference&) = delete;
+ range_reference& operator=(const range_reference&) = delete;
+
+ range_reference(const cell_position& _pos);
+
+ void reset();
+ };
+
+ struct field_in_range
+ {
+ range_reference* ref = nullptr;
+ spreadsheet::col_t column_pos = -1;
+ };
+
+ typedef std::map<cell_position, range_reference*> range_ref_map_type;
+
+ enum class linkable_node_type { unknown, element, attribute };
+ enum class reference_type { unknown, cell, range_field };
+ enum class element_type { unknown, linked, unlinked };
+
+ struct linkable
+ {
+ xml_name_t name;
+ linkable_node_type node_type;
+ reference_type ref_type;
+
+ union
+ {
+ cell_reference* cell_ref = nullptr;
+ field_in_range* field_ref;
+ };
+
+ std::string_view label; // custom header label
+ mutable std::string_view ns_alias; // namespace alias used in the content stream.
+
+ linkable(const linkable&) = delete;
+ linkable& operator=(const linkable&) = delete;
+
+ linkable(xml_map_tree& parent, const xml_name_t& _name, linkable_node_type _node_type, reference_type _ref_type);
+ };
+
+ struct attribute : public linkable
+ {
+ using args_type = std::tuple<xml_map_tree&, const xml_name_t&, reference_type>;
+
+ attribute(args_type args);
+ ~attribute();
+ };
+
+ using attribute_store_type = std::deque<attribute*>;
+
+ struct element : public linkable
+ {
+ element_type elem_type;
+ element_store_type* child_elements;
+
+ mutable element_position stream_pos; // position of this element in the content stream
+
+ attribute_store_type attributes;
+
+ /**
+ * Points to a range reference instance of which this element is a
+ * parent. nullptr if this element is not a parent element of any range
+ * reference.
+ */
+ range_reference* range_parent;
+
+ /**
+ * The element is a row-group element (element that defines a row
+ * boundary) if this value is not null. If this is not null, it
+ * points to the range_reference instance it belongs to.
+ */
+ range_reference* row_group;
+
+ spreadsheet::row_t row_group_position;
+
+ std::vector<spreadsheet::col_t> linked_range_fields;
+
+ using args_type = std::tuple<xml_map_tree&, const xml_name_t&, element_type, reference_type>;
+
+ element(args_type args);
+ ~element();
+
+ element* get_child(const xml_name_t& _name);
+
+ element* get_or_create_child(
+ xml_map_tree& parent, const xml_name_t& _name);
+
+ element* get_or_create_linked_child(
+ xml_map_tree& parent, const xml_name_t& _name, reference_type _ref_type);
+
+ void link_reference(xml_map_tree& parent, reference_type _ref_type);
+
+ /**
+ * Unlinked attribute anchor is an element that's not linked but has
+ * one or more attributes that are linked.
+ *
+ * @return true if the element is an unlinked attribute anchor, false
+ * otherwise.
+ */
+ bool unlinked_attribute_anchor() const;
+ };
+
+ friend struct linkable;
+
+public:
+
+ /**
+ * Wrapper class to allow walking through the element tree.
+ */
+ class walker
+ {
+ typedef std::vector<element*> ref_element_stack_type;
+ typedef std::vector<xml_name_t> name_stack_type;
+ const xml_map_tree& m_parent;
+ ref_element_stack_type m_stack;
+ name_stack_type m_unlinked_stack;
+ public:
+ walker(const xml_map_tree& parent);
+ walker(const walker& r);
+
+ void reset();
+ element* push_element(const xml_name_t& name);
+ element* pop_element(const xml_name_t& name);
+ };
+
+ xml_map_tree() = delete;
+ xml_map_tree(const xml_map_tree&) = delete;
+ xml_map_tree& operator=(const xml_map_tree&) = delete;
+
+ xml_map_tree(xmlns_repository& xmlns_repo);
+ ~xml_map_tree();
+
+ void set_namespace_alias(std::string_view alias, std::string_view uri, bool default_ns);
+ xmlns_id_t get_namespace(std::string_view alias) const;
+
+ void set_cell_link(std::string_view xpath, const cell_position& ref);
+
+ void start_range(const cell_position& pos);
+ void append_range_field_link(std::string_view xpath, std::string_view label);
+ void set_range_row_group(std::string_view xpath);
+ void commit_range();
+
+ const linkable* get_link(std::string_view xpath) const;
+
+ walker get_tree_walker() const;
+
+ range_ref_map_type& get_range_references();
+
+ std::string_view intern_string(std::string_view str) const;
+
+private:
+ void insert_range_field_link(
+ range_reference& range_ref, element_list_type& range_parent, const range_field_link& field);
+
+ range_reference* get_range_reference(const cell_position& pos);
+
+ void create_ref_store(linkable& node);
+
+ struct linked_node_type
+ {
+ element_list_type elem_stack;
+ linkable* node = nullptr;
+ element* anchor_elem = nullptr;
+ };
+
+ /**
+ * Get a linked node (element or attribute) referenced by the specified
+ * xpath.
+ *
+ * @param xpath path to the linked node.
+ * @param type type of reference, either a cell or a range field.
+ */
+ linked_node_type get_linked_node(std::string_view xpath, reference_type type);
+
+ element* get_element(std::string_view xpath);
+
+private:
+
+ using range_field_links = std::vector<range_field_link>;
+
+ xmlns_context m_xmlns_cxt;
+
+ /**
+ * Stores field links to insert into the current range reference.
+ */
+ range_field_links m_cur_range_field_links;
+
+ cell_position m_cur_range_pos;
+
+ /**
+ * All range references present in the tree. This container manages the
+ * life cycles of stored range references.
+ */
+ range_ref_map_type m_field_refs;
+
+ /** pool of element names. */
+ mutable string_pool m_names;
+
+ boost::object_pool<element_store_type> m_element_store_pool;
+ boost::object_pool<cell_reference> m_cell_reference_pool;
+ boost::object_pool<range_reference> m_range_reference_pool;
+ boost::object_pool<field_in_range> m_field_in_range_pool;
+ boost::object_pool<attribute> m_attribute_pool;
+ boost::object_pool<element> m_element_pool;
+
+ element* mp_root;
+
+ xmlns_id_t m_default_ns;
+};
+
+std::ostream& operator<< (std::ostream& os, const xml_map_tree::linkable& link);
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_map_tree_test.cpp b/src/liborcus/xml_map_tree_test.cpp
new file mode 100644
index 0000000..f3523f1
--- /dev/null
+++ b/src/liborcus/xml_map_tree_test.cpp
@@ -0,0 +1,274 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "xml_map_tree.hpp"
+#include "orcus/xml_namespace.hpp"
+
+#include <cstdlib>
+#include <cassert>
+#include <iostream>
+
+using namespace orcus;
+
+void test_path_insertion()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ xmlns_repository repo;
+ xml_map_tree tree(repo);
+ xml_map_tree::cell_position ref;
+ ref.sheet = std::string_view{"test"};
+ ref.row = 2;
+ ref.col = 1;
+
+ // Single cell links
+ tree.set_cell_link("/data/elem1", ref);
+ const xml_map_tree::linkable* p0 = tree.get_link("/data/elem1");
+ assert(p0 && p0->node_type == xml_map_tree::linkable_node_type::element);
+ const xml_map_tree::element* p = static_cast<const xml_map_tree::element*>(p0);
+ assert(p->ref_type == xml_map_tree::reference_type::cell);
+ assert(p->cell_ref->pos.sheet == "test");
+ assert(p->cell_ref->pos.row == 2);
+ assert(p->cell_ref->pos.col == 1);
+
+ const xml_map_tree::element* elem1 = p;
+
+ ref.row = 3;
+ ref.col = 2;
+ tree.set_cell_link("/data/elem2", ref);
+ p0 = tree.get_link("/data/elem2");
+ assert(p0 && p0->node_type == xml_map_tree::linkable_node_type::element);
+ p = static_cast<const xml_map_tree::element*>(p0);
+ assert(p && p->ref_type == xml_map_tree::reference_type::cell);
+ assert(p->cell_ref->pos.sheet == "test");
+ assert(p->cell_ref->pos.row == 3);
+ assert(p->cell_ref->pos.col == 2);
+
+ // The link in elem1 should be unchanged.
+ p0 = tree.get_link("/data/elem1");
+ assert(p0 == elem1);
+
+ ref.sheet = std::string_view{"test2"};
+ ref.row = 10;
+ ref.col = 5;
+ tree.set_cell_link("/data/meta/title", ref);
+ p0 = tree.get_link("/data/meta/title");
+ assert(p0 && p0->node_type == xml_map_tree::linkable_node_type::element);
+ p = static_cast<const xml_map_tree::element*>(p0);
+ assert(p && p->ref_type == xml_map_tree::reference_type::cell);
+ assert(p->cell_ref->pos.sheet == "test2");
+ assert(p->cell_ref->pos.row == 10);
+ assert(p->cell_ref->pos.col == 5);
+
+ // Range field links
+ ref.row = 5;
+ ref.col = 0;
+ ref.sheet = std::string_view{"test3"};
+ tree.start_range(ref);
+ tree.append_range_field_link("/data/entries/entry/id", std::string_view{});
+ tree.append_range_field_link("/data/entries/entry/name", std::string_view{});
+ tree.append_range_field_link("/data/entries/entry/score", std::string_view{});
+ tree.set_range_row_group("/data/entries/entry");
+ tree.commit_range();
+ p0 = tree.get_link("/data/entries/entry/id");
+ assert(p0 && p0->node_type == xml_map_tree::linkable_node_type::element);
+ p = static_cast<const xml_map_tree::element*>(p0);
+ assert(p && p->ref_type == xml_map_tree::reference_type::range_field);
+ assert(p->field_ref->ref->pos.sheet == "test3");
+ assert(p->field_ref->ref->pos.row == 5);
+ assert(p->field_ref->ref->pos.col == 0);
+ assert(p->field_ref->column_pos == 0);
+
+ p0 = tree.get_link("/data/entries/entry/name");
+ assert(p0 && p0->node_type == xml_map_tree::linkable_node_type::element);
+ p = static_cast<const xml_map_tree::element*>(p0);
+ assert(p && p->ref_type == xml_map_tree::reference_type::range_field);
+ assert(p->field_ref->ref->pos.sheet == "test3");
+ assert(p->field_ref->ref->pos.row == 5);
+ assert(p->field_ref->ref->pos.col == 0);
+ assert(p->field_ref->column_pos == 1);
+
+ p0 = tree.get_link("/data/entries/entry/score");
+ assert(p0 && p0->node_type == xml_map_tree::linkable_node_type::element);
+ p = static_cast<const xml_map_tree::element*>(p0);
+ assert(p && p->ref_type == xml_map_tree::reference_type::range_field);
+ assert(p->field_ref->ref->pos.sheet == "test3");
+ assert(p->field_ref->ref->pos.row == 5);
+ assert(p->field_ref->ref->pos.col == 0);
+ assert(p->field_ref->column_pos == 2);
+}
+
+void test_attr_path_insertion()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ xmlns_repository repo;
+ xml_map_tree tree(repo);
+ xml_map_tree::cell_position ref;
+ ref.sheet = std::string_view{"test"};
+ ref.row = 2;
+ ref.col = 3;
+
+ // 'attr1' is an attribute of 'elem'.
+ tree.set_cell_link("/root/elem/@attr1", ref);
+ const xml_map_tree::linkable* p = tree.get_link("/root/elem/@attr1");
+ assert(p && p->node_type == xml_map_tree::linkable_node_type::attribute);
+ const xml_map_tree::attribute* attr = static_cast<const xml_map_tree::attribute*>(p);
+ assert(attr->ref_type == xml_map_tree::reference_type::cell);
+ assert(attr->cell_ref->pos.sheet == "test");
+ assert(attr->cell_ref->pos.row == 2);
+ assert(attr->cell_ref->pos.col == 3);
+
+ // Insert another attribute in the same element.
+ ref.sheet = std::string_view{"test2"};
+ ref.row = 11;
+ ref.col = 4;
+ tree.set_cell_link("/root/elem/@attr2", ref);
+ p = tree.get_link("/root/elem/@attr2");
+ assert(p && p->node_type == xml_map_tree::linkable_node_type::attribute);
+ attr = static_cast<const xml_map_tree::attribute*>(p);
+ assert(attr->ref_type == xml_map_tree::reference_type::cell);
+ assert(attr->cell_ref->pos.sheet == "test2");
+ assert(attr->cell_ref->pos.row == 11);
+ assert(attr->cell_ref->pos.col == 4);
+
+ // At this point, /root/elem is not linked.
+ p = tree.get_link("/root/elem");
+ assert(!p);
+
+ // Now, link /root/elem.
+ ref.sheet = std::string_view{"test3"};
+ ref.row = 4;
+ ref.col = 6;
+ tree.set_cell_link("/root/elem", ref);
+ p = tree.get_link("/root/elem");
+ assert(p && p->node_type == xml_map_tree::linkable_node_type::element);
+ const xml_map_tree::element* elem = static_cast<const xml_map_tree::element*>(p);
+ assert(elem->elem_type == xml_map_tree::element_type::linked);
+ assert(elem->ref_type == xml_map_tree::reference_type::cell);
+ assert(elem->cell_ref->pos.sheet == "test3");
+ assert(elem->cell_ref->pos.row == 4);
+ assert(elem->cell_ref->pos.col == 6);
+}
+
+void test_tree_walk()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ xmlns_repository repo;
+ xml_map_tree tree(repo);
+ xml_map_tree::cell_position ref;
+ ref.sheet = std::string_view{"test"};
+ ref.row = 2;
+ ref.col = 1;
+
+ tree.set_cell_link("/data/header/title", ref);
+ xml_map_tree::walker walker = tree.get_tree_walker();
+ walker.reset();
+
+ // Root element.
+ const xml_map_tree::element* elem = walker.push_element({XMLNS_UNKNOWN_ID, "data"});
+ assert(elem);
+ assert(elem->name.name == "data");
+ assert(elem->elem_type == xml_map_tree::element_type::unlinked);
+
+ elem = walker.push_element({XMLNS_UNKNOWN_ID, "header"});
+ assert(elem);
+ assert(elem->name.name == "header");
+ assert(elem->elem_type == xml_map_tree::element_type::unlinked);
+
+ elem = walker.push_element({XMLNS_UNKNOWN_ID, "title"});
+ assert(elem);
+ assert(elem->name.name == "title");
+ assert(elem->ref_type == xml_map_tree::reference_type::cell);
+
+ elem = walker.pop_element({XMLNS_UNKNOWN_ID, "title"});
+ assert(elem);
+ assert(elem->name.name == "header");
+ assert(elem->elem_type == xml_map_tree::element_type::unlinked);
+
+ elem = walker.pop_element({XMLNS_UNKNOWN_ID, "header"});
+ assert(elem);
+ assert(elem->name.name == "data");
+ assert(elem->elem_type == xml_map_tree::element_type::unlinked);
+
+ elem = walker.pop_element({XMLNS_UNKNOWN_ID, "data"});
+ assert(!elem);
+}
+
+void test_tree_walk_namespace()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ xmlns_repository repo;
+ xml_map_tree tree(repo);
+ xml_map_tree::cell_position ref;
+ ref.sheet = std::string_view{"data"};
+ ref.row = 1;
+ ref.col = 2;
+
+ tree.set_namespace_alias("a", "http://some-namespace", false);
+ tree.set_namespace_alias("skip", "http://namespace-to-skip", false);
+ tree.set_cell_link("/a:table/a:title", ref);
+ tree.start_range(ref);
+ ref.row = 2;
+ ref.col = 0;
+ tree.append_range_field_link("/a:table/a:rows/a:row/a:city", std::string_view{});
+ ++ref.col;
+ tree.append_range_field_link("/a:table/a:rows/a:row/a:population", std::string_view{});
+ ++ref.col;
+ tree.append_range_field_link("/a:table/a:rows/a:row/a:year", std::string_view{});
+ tree.set_range_row_group("/a:table/a:rows/a:row");
+ tree.commit_range();
+
+ xmlns_id_t ns_a = tree.get_namespace("a");
+ assert(ns_a != XMLNS_UNKNOWN_ID);
+ xmlns_id_t ns_skip = tree.get_namespace("skip");
+ assert(ns_skip != XMLNS_UNKNOWN_ID);
+
+ xml_map_tree::walker walker = tree.get_tree_walker();
+ walker.reset();
+
+ // Root element. This is not linked.
+ const xml_map_tree::element* elem = walker.push_element({ns_a, "table"});
+ assert(elem);
+ assert(elem->name.ns == ns_a);
+ assert(elem->name.name == "table");
+ assert(elem->node_type == xml_map_tree::linkable_node_type::element);
+ assert(elem->elem_type == xml_map_tree::element_type::unlinked);
+ assert(elem->ref_type == xml_map_tree::reference_type::unknown);
+
+ // Intentionally push a foreign element.
+ const xml_map_tree::element* elem_old = elem;
+ elem = walker.push_element({ns_skip, "foo"});
+ assert(!elem);
+ elem = walker.pop_element({ns_skip, "foo"});
+ assert(elem == elem_old);
+
+ // Push a foreign element and a valid element under it. A valid element
+ // placed under a foreign element should be invalid.
+ elem_old = elem;
+ elem = walker.push_element({ns_skip, "foo"});
+ assert(!elem);
+ elem = walker.push_element({ns_a, "title"});
+ assert(!elem);
+ elem = walker.pop_element({ns_a, "title"});
+ assert(!elem);
+ elem = walker.pop_element({ns_skip, "foo"});
+ assert(elem == elem_old);
+}
+
+int main()
+{
+ test_path_insertion();
+ test_attr_path_insertion();
+ test_tree_walk();
+ test_tree_walk_namespace();
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_simple_stream_handler.cpp b/src/liborcus/xml_simple_stream_handler.cpp
new file mode 100644
index 0000000..1ee7c1d
--- /dev/null
+++ b/src/liborcus/xml_simple_stream_handler.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_simple_stream_handler.hpp"
+#include "xml_context_base.hpp"
+
+#include <cassert>
+
+namespace orcus {
+
+xml_simple_stream_handler::xml_simple_stream_handler(
+ session_context& session_cxt, const tokens& t, std::unique_ptr<xml_context_base> context) :
+ xml_stream_handler(session_cxt, t, std::move(context))
+{
+}
+
+xml_simple_stream_handler::~xml_simple_stream_handler()
+{
+}
+
+xml_context_base& xml_simple_stream_handler::get_context()
+{
+ return get_current_context();
+}
+
+void xml_simple_stream_handler::start_document()
+{
+}
+
+void xml_simple_stream_handler::end_document()
+{
+}
+
+void xml_simple_stream_handler::start_element(const xml_token_element_t& elem)
+{
+ get_current_context().start_element(elem.ns, elem.name, elem.attrs);
+}
+
+void xml_simple_stream_handler::end_element(const xml_token_element_t& elem)
+{
+ get_current_context().end_element(elem.ns, elem.name);
+}
+
+void xml_simple_stream_handler::characters(std::string_view str, bool transient)
+{
+ get_current_context().characters(str, transient);
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_simple_stream_handler.hpp b/src/liborcus/xml_simple_stream_handler.hpp
new file mode 100644
index 0000000..186e7d3
--- /dev/null
+++ b/src/liborcus/xml_simple_stream_handler.hpp
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __ORCUS_XML_SIMPLE_HANDLER_HPP__
+#define __ORCUS_XML_SIMPLE_HANDLER_HPP__
+
+#include "xml_stream_handler.hpp"
+
+namespace orcus {
+
+class xml_context_base;
+
+/**
+ * Simple stream handler that only uses a single context instance.
+ */
+class xml_simple_stream_handler : public xml_stream_handler
+{
+public:
+ xml_simple_stream_handler(
+ session_context& session_cxt, const tokens& t, std::unique_ptr<xml_context_base> context);
+ virtual ~xml_simple_stream_handler() override;
+
+ xml_context_base& get_context();
+
+ virtual void start_document() override;
+ virtual void end_document() override;
+
+ virtual void start_element(const xml_token_element_t& elem) override;
+ virtual void end_element(const xml_token_element_t& elem) override;
+ virtual void characters(std::string_view str, bool transient) override;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_stream_handler.cpp b/src/liborcus/xml_stream_handler.cpp
new file mode 100644
index 0000000..859a08f
--- /dev/null
+++ b/src/liborcus/xml_stream_handler.cpp
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_stream_handler.hpp"
+#include "xml_context_base.hpp"
+#include "xml_empty_context.hpp"
+
+#include "orcus/exception.hpp"
+
+#include <iostream>
+
+namespace orcus {
+
+xml_stream_handler::xml_stream_handler(
+ session_context& session_cxt, const tokens& t, std::unique_ptr<xml_context_base> root_context) :
+ m_session_cxt(session_cxt),
+ m_tokens(t),
+ m_config(format_t::unknown),
+ m_elem_printer(m_tokens),
+ mp_root_context(std::move(root_context)),
+ mp_invalid_context(std::make_unique<xml_empty_context>(session_cxt, t))
+{
+ assert(mp_root_context);
+ m_context_stack.push_back(mp_root_context.get());
+}
+
+xml_stream_handler::~xml_stream_handler()
+{
+}
+
+void xml_stream_handler::start_document()
+{
+}
+
+void xml_stream_handler::end_document()
+{
+}
+
+void xml_stream_handler::declaration(const xml_declaration_t& decl)
+{
+ get_current_context().declaration(decl);
+}
+
+void xml_stream_handler::start_element(const xml_token_element_t& elem)
+{
+ xml_context_base& cur = get_current_context();
+ if (cur.evaluate_child_element(elem.ns, elem.name))
+ {
+ // new child element is valid against parent element.
+ xml_context_base* p = cur.create_child_context(elem.ns, elem.name);
+ if (p)
+ m_context_stack.push_back(p);
+ }
+ else
+ {
+ // new child element is not valid for the current element. Ignore the
+ // whole sub structure.
+ m_context_stack.push_back(&get_invalid_context());
+
+ if (m_config.debug)
+ {
+ // TODO: print the top element of the sub structure being ignored.
+ std::cerr << "warning: ignoring the whole sub-structure below ";
+ m_elem_printer.print_element(std::cerr, elem.ns, elem.name);
+ std::cerr << std::endl;
+ }
+ }
+
+ get_current_context().start_element(elem.ns, elem.name, elem.attrs);
+}
+
+void xml_stream_handler::end_element(const xml_token_element_t& elem)
+{
+ bool ended = get_current_context().end_element(elem.ns, elem.name);
+
+ if (ended)
+ {
+ size_t n = m_context_stack.size();
+
+ if (n > 1)
+ {
+ // Call end_child_context of the parent context to provide a way for
+ // the two adjacent contexts to communicate with each other.
+ context_stack_type::reverse_iterator itr_cur = m_context_stack.rbegin();
+ context_stack_type::reverse_iterator itr_par = itr_cur + 1;
+ (*itr_par)->end_child_context(elem.ns, elem.name, *itr_cur);
+ }
+
+ m_context_stack.pop_back();
+ }
+}
+
+void xml_stream_handler::characters(std::string_view str, bool transient)
+{
+ get_current_context().characters(str, transient);
+}
+
+void xml_stream_handler::set_ns_context(const xmlns_context* p)
+{
+ for (auto* context : m_context_stack)
+ context->set_ns_context(p);
+
+ mp_invalid_context->set_ns_context(p);
+ m_elem_printer.set_ns_context(p);
+}
+
+void xml_stream_handler::set_config(const config& opt)
+{
+ m_config = opt;
+ for (auto* context : m_context_stack)
+ context->set_config(m_config);
+
+ mp_invalid_context->set_config(m_config);
+}
+
+xml_context_base& xml_stream_handler::get_current_context()
+{
+ if (m_context_stack.empty())
+ return *mp_root_context;
+
+ return *m_context_stack.back();
+}
+
+xml_context_base& xml_stream_handler::get_root_context()
+{
+ return *mp_root_context;
+}
+
+xml_context_base& xml_stream_handler::get_invalid_context()
+{
+ return *mp_invalid_context;
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_stream_handler.hpp b/src/liborcus/xml_stream_handler.hpp
new file mode 100644
index 0000000..2b09c95
--- /dev/null
+++ b/src/liborcus/xml_stream_handler.hpp
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_XML_STREAM_HANDLER_HPP
+#define ORCUS_XML_STREAM_HANDLER_HPP
+
+#include <orcus/sax_token_parser.hpp>
+#include <orcus/config.hpp>
+
+#include "xml_util.hpp"
+
+#include <cstdlib>
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace orcus {
+
+class xml_context_base;
+class xmlns_context;
+struct session_context;
+
+class xml_stream_handler
+{
+ session_context& m_session_cxt;
+ const tokens& m_tokens;
+
+ config m_config;
+ xml_element_printer m_elem_printer;
+ std::unique_ptr<xml_context_base> mp_root_context;
+ std::unique_ptr<xml_context_base> mp_invalid_context;
+ typedef std::vector<xml_context_base*> context_stack_type;
+ context_stack_type m_context_stack;
+
+public:
+ xml_stream_handler() = delete;
+ xml_stream_handler(const xml_stream_handler&) = delete;
+
+ xml_stream_handler(session_context& session_cxt, const tokens& t, std::unique_ptr<xml_context_base> root_context);
+ virtual ~xml_stream_handler();
+
+ virtual void start_document();
+ virtual void end_document();
+
+ virtual void declaration(const xml_declaration_t& decl);
+ virtual void start_element(const xml_token_element_t& elem);
+ virtual void end_element(const xml_token_element_t& elem);
+ virtual void characters(std::string_view str, bool transient);
+
+ void set_ns_context(const xmlns_context* p);
+ void set_config(const config& opt);
+
+protected:
+ xml_context_base& get_current_context();
+ xml_context_base& get_root_context();
+ xml_context_base& get_invalid_context();
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_stream_parser.cpp b/src/liborcus/xml_stream_parser.cpp
new file mode 100644
index 0000000..895821c
--- /dev/null
+++ b/src/liborcus/xml_stream_parser.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_stream_parser.hpp"
+#include "xml_stream_handler.hpp"
+
+#include "orcus/tokens.hpp"
+
+#include "orcus/threaded_sax_token_parser.hpp"
+#include "orcus/sax_token_parser.hpp"
+
+#include <iostream>
+#include <vector>
+#include <sstream>
+
+using namespace std;
+
+namespace orcus {
+
+xml_stream_parser_base::xml_stream_parser_base(
+ const config& opt,
+ xmlns_repository& ns_repo, const tokens& tokens, const char* content, size_t size) :
+ m_config(opt),
+ m_ns_cxt(ns_repo.create_context()),
+ m_tokens(tokens),
+ mp_handler(nullptr),
+ m_content(content),
+ m_size(size)
+{
+}
+
+xml_stream_parser_base::~xml_stream_parser_base()
+{
+}
+
+void xml_stream_parser_base::set_handler(xml_stream_handler* handler)
+{
+ mp_handler = handler;
+ if (mp_handler)
+ {
+ mp_handler->set_ns_context(&m_ns_cxt);
+ mp_handler->set_config(m_config);
+ }
+}
+
+xml_stream_handler* xml_stream_parser_base::get_handler() const
+{
+ return mp_handler;
+}
+
+xml_stream_parser::xml_stream_parser(
+ const config& opt,
+ xmlns_repository& ns_repo, const tokens& tokens, const char* content, size_t size) :
+ xml_stream_parser_base(opt, ns_repo, tokens, content, size) {}
+
+xml_stream_parser::~xml_stream_parser() {}
+
+void xml_stream_parser::parse()
+{
+ if (!mp_handler)
+ return;
+
+ sax_token_parser<xml_stream_handler> sax({m_content, m_size}, m_tokens, m_ns_cxt, *mp_handler);
+ sax.parse();
+}
+
+threaded_xml_stream_parser::threaded_xml_stream_parser(
+ const config& opt,
+ xmlns_repository& ns_repo, const tokens& tokens, const char* content, size_t size) :
+ xml_stream_parser_base(opt, ns_repo, tokens, content, size) {}
+
+threaded_xml_stream_parser::~threaded_xml_stream_parser() {}
+
+void threaded_xml_stream_parser::parse()
+{
+ if (!mp_handler)
+ return;
+
+ threaded_sax_token_parser<xml_stream_handler> sax(m_content, m_size, m_tokens, m_ns_cxt, *mp_handler, 1000);
+ sax.parse();
+
+ sax.swap_string_pool(m_pool);
+}
+
+void threaded_xml_stream_parser::swap_string_pool(string_pool& pool)
+{
+ m_pool.swap(pool);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_stream_parser.hpp b/src/liborcus/xml_stream_parser.hpp
new file mode 100644
index 0000000..0b75222
--- /dev/null
+++ b/src/liborcus/xml_stream_parser.hpp
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_XMLPARSER_HPP
+#define INCLUDED_ORCUS_XMLPARSER_HPP
+
+#include <cstdlib>
+#include <string>
+#include <exception>
+
+#include "orcus/xml_namespace.hpp"
+#include "orcus/string_pool.hpp"
+
+namespace orcus {
+
+struct config;
+
+class xml_stream_handler;
+class tokens;
+
+/**
+ * This class does NOT store the stream content which is just a pointer to
+ * the first char of the content stream. Make sure you finish parsing while
+ * the content pointer is valid.
+ */
+class xml_stream_parser_base
+{
+public:
+ xml_stream_parser_base() = delete;
+
+ virtual void parse() = 0;
+
+ void set_handler(xml_stream_handler* handler);
+ xml_stream_handler* get_handler() const;
+
+protected:
+ xml_stream_parser_base(
+ const config& opt,
+ xmlns_repository& ns_repo, const tokens& tokens, const char* content, size_t size);
+ virtual ~xml_stream_parser_base();
+
+ const config& m_config;
+ xmlns_context m_ns_cxt;
+ const tokens& m_tokens;
+ xml_stream_handler* mp_handler;
+ const char* m_content;
+ size_t m_size;
+};
+
+class xml_stream_parser : public xml_stream_parser_base
+{
+public:
+ xml_stream_parser(
+ const config& opt,
+ xmlns_repository& ns_repo, const tokens& tokens, const char* content, size_t size);
+ virtual ~xml_stream_parser() override;
+
+ virtual void parse() override;
+};
+
+class threaded_xml_stream_parser : public xml_stream_parser_base
+{
+ string_pool m_pool;
+
+public:
+ threaded_xml_stream_parser(
+ const config& opt,
+ xmlns_repository& ns_repo, const tokens& tokens, const char* content, size_t size);
+ virtual ~threaded_xml_stream_parser() override;
+
+ virtual void parse() override;
+
+ void swap_string_pool(string_pool& pool);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_structure_mapper.cpp b/src/liborcus/xml_structure_mapper.cpp
new file mode 100644
index 0000000..1242947
--- /dev/null
+++ b/src/liborcus/xml_structure_mapper.cpp
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_structure_mapper.hpp"
+
+namespace orcus { namespace detail {
+
+xml_structure_mapper::xml_structure_mapper(
+ xml_structure_tree::range_handler_type rh, const xml_structure_tree::walker& walker) :
+ m_range_handler(std::move(rh)),
+ m_walker(walker),
+ m_repeat_count(0)
+{
+}
+
+void xml_structure_mapper::run()
+{
+ reset();
+ traverse();
+}
+
+void xml_structure_mapper::reset()
+{
+ m_cur_elem = m_walker.root();
+ m_repeat_count = 0;
+}
+
+void xml_structure_mapper::traverse()
+{
+ auto elem = m_cur_elem;
+ const bool row_group = elem.repeat;
+
+ if (row_group)
+ {
+ ++m_repeat_count;
+ m_current_range.row_groups.push_back(m_walker.get_path());
+ }
+
+ xml_structure_tree::entity_names_type children = m_walker.get_children();
+
+ if (m_repeat_count)
+ {
+ std::string path = m_walker.get_path();
+
+ xml_structure_tree::entity_names_type attr_names = m_walker.get_attributes();
+ for (const auto& attr_name : attr_names)
+ {
+ std::string attr_path = path + "/@" + m_walker.to_string(attr_name);
+ m_current_range.paths.push_back(attr_path);
+ }
+
+ if (children.empty() && elem.has_content)
+ // Only add leaf elements to the range, and only those with contents.
+ m_current_range.paths.push_back(path);
+ }
+
+ for (const auto& child_name : children)
+ {
+ m_cur_elem = m_walker.descend(child_name);
+ traverse();
+ m_cur_elem = m_walker.ascend();
+ }
+
+ if (row_group)
+ {
+ --m_repeat_count;
+
+ if (!m_repeat_count)
+ push_range();
+ }
+}
+
+void xml_structure_mapper::push_range()
+{
+ m_range_handler(std::move(m_current_range));
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_structure_mapper.hpp b/src/liborcus/xml_structure_mapper.hpp
new file mode 100644
index 0000000..aae4bfa
--- /dev/null
+++ b/src/liborcus/xml_structure_mapper.hpp
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_XML_STRUCTURE_MAPPER_HPP
+#define INCLUDED_XML_STRUCTURE_MAPPER_HPP
+
+#include "orcus/xml_structure_tree.hpp"
+
+namespace orcus { namespace detail {
+
+class xml_structure_mapper
+{
+ xml_table_range_t m_current_range;
+
+ xml_structure_tree::range_handler_type m_range_handler;
+ xml_structure_tree::walker m_walker;
+ xml_structure_tree::element m_cur_elem;
+ size_t m_repeat_count;
+
+ void reset();
+
+ void traverse();
+
+ void push_range();
+
+public:
+ xml_structure_mapper(xml_structure_tree::range_handler_type rh, const xml_structure_tree::walker& walker);
+
+ void run();
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_structure_tree.cpp b/src/liborcus/xml_structure_tree.cpp
new file mode 100644
index 0000000..dbdb029
--- /dev/null
+++ b/src/liborcus/xml_structure_tree.cpp
@@ -0,0 +1,625 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/xml_structure_tree.hpp>
+#include <orcus/sax_ns_parser.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <orcus/exception.hpp>
+#include <orcus/string_pool.hpp>
+
+#include "string_helper.hpp"
+#include "xml_structure_mapper.hpp"
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <cstdio>
+#include <memory>
+
+#include <unordered_map>
+#include <unordered_set>
+
+namespace orcus {
+
+namespace {
+
+/** Element properties. */
+struct elem_prop
+{
+ using element_store_type = std::unordered_map<
+ xml_structure_tree::entity_name, std::unique_ptr<elem_prop>, xml_structure_tree::entity_name::hash>;
+
+ using attribute_names_type = std::unordered_set<
+ xml_structure_tree::entity_name, xml_structure_tree::entity_name::hash>;
+
+ element_store_type child_elements;
+ attribute_names_type attributes;
+
+ /** Store child element names in order of appearance. */
+ xml_structure_tree::entity_names_type child_element_names;
+
+ /** Store attribute names in order of appearance. */
+ xml_structure_tree::entity_names_type attribute_names;
+
+ size_t appearance_order;
+
+ size_t in_scope_count;
+
+ /**
+ * When true, this element is the base element of repeated structures.
+ * This flag is set only with the base element; none of the child
+ * elements below the base element have this flag set.
+ */
+ bool repeat;
+
+ bool has_content;
+
+ elem_prop(const elem_prop&) = delete;
+ elem_prop& operator=(const elem_prop&) = delete;
+
+ elem_prop() :
+ appearance_order(0),
+ in_scope_count(1),
+ repeat(false),
+ has_content(false) {}
+
+ elem_prop(size_t _appearance_order) :
+ appearance_order(_appearance_order),
+ in_scope_count(1),
+ repeat(false),
+ has_content(false) {}
+};
+
+struct root
+{
+ xml_structure_tree::entity_name name;
+ elem_prop prop;
+};
+
+struct element_ref
+{
+ xml_structure_tree::entity_name name;
+ elem_prop* prop;
+
+ element_ref() : prop(nullptr) {}
+ element_ref(xml_structure_tree::entity_name _name, elem_prop* _prop) :
+ name(_name), prop(_prop) {}
+};
+
+typedef std::vector<element_ref> elements_type;
+
+class xml_sax_handler
+{
+ string_pool& m_pool;
+ std::unique_ptr<root> mp_root;
+ elements_type m_stack;
+ xml_structure_tree::entity_names_type m_attrs;
+
+private:
+ void merge_attributes(elem_prop& prop)
+ {
+ xml_structure_tree::entity_names_type::const_iterator it = m_attrs.begin(), it_end = m_attrs.end();
+ for (; it != it_end; ++it)
+ {
+ if (prop.attributes.find(*it) == prop.attributes.end())
+ {
+ // New attribute. Insert it.
+ prop.attributes.insert(*it);
+ prop.attribute_names.push_back(*it);
+ }
+ }
+
+ m_attrs.clear();
+ }
+
+public:
+ xml_sax_handler(string_pool& pool) :
+ m_pool(pool), mp_root(nullptr) {}
+
+ void doctype(const sax::doctype_declaration&) {}
+
+ void start_declaration(std::string_view /*name*/)
+ {
+ }
+
+ void end_declaration(std::string_view /*name*/)
+ {
+ m_attrs.clear();
+ }
+
+ void start_element(const sax_ns_parser_element& elem)
+ {
+ if (!mp_root)
+ {
+ // This is a root element.
+ mp_root.reset(new root);
+ mp_root->name.ns = elem.ns;
+ mp_root->name.name = m_pool.intern(elem.name).first;
+ element_ref ref(mp_root->name, &mp_root->prop);
+ merge_attributes(mp_root->prop);
+ m_stack.push_back(ref);
+ return;
+ }
+
+ // See if the current element already has a child element of the same name.
+ assert(!m_stack.empty());
+ element_ref& current = m_stack.back();
+ xml_structure_tree::entity_name key(elem.ns, elem.name);
+ auto it = current.prop->child_elements.find(key);
+ if (it != current.prop->child_elements.end())
+ {
+ // Recurring element. Set its repeat flag only when it occurs
+ // multiple times in the same scope.
+ ++it->second->in_scope_count;
+ if (it->second->in_scope_count > 1)
+ it->second->repeat = true;
+
+ element_ref ref(it->first, it->second.get());
+ merge_attributes(*it->second);
+ m_stack.push_back(ref);
+ return;
+ }
+
+ // New element.
+ size_t order = current.prop->child_elements.size();
+ key.name = m_pool.intern(key.name).first;
+ auto r = current.prop->child_elements.insert(
+ std::make_pair(key, std::make_unique<elem_prop>(order)));
+
+ if (!r.second)
+ throw general_error("Insertion failed");
+
+ current.prop->child_element_names.push_back(key);
+
+ it = r.first;
+ element_ref ref(it->first, it->second.get());
+ merge_attributes(*it->second);
+ m_stack.push_back(ref);
+ }
+
+ void end_element(const sax_ns_parser_element& /*elem*/)
+ {
+ if (m_stack.empty())
+ throw general_error("Element stack is empty.");
+
+ const element_ref& current = m_stack.back();
+
+ // Reset the in-scope count of all child elements to 0 before ending
+ // the current scope.
+ for (auto& [name, p] : current.prop->child_elements)
+ p->in_scope_count = 0;
+
+ m_stack.pop_back();
+ }
+
+ void characters(std::string_view, bool)
+ {
+ if (m_stack.empty())
+ return;
+
+ element_ref& current = m_stack.back();
+ current.prop->has_content = true;
+ }
+
+ void attribute(std::string_view, std::string_view)
+ {
+ // Attribute for declaration. We don't handle this.
+ }
+
+ void attribute(const sax_ns_parser_attribute& attr)
+ {
+ m_attrs.push_back(xml_structure_tree::entity_name(attr.ns, attr.name));
+ }
+
+ std::unique_ptr<root> release_root_element()
+ {
+ return std::move(mp_root);
+ }
+};
+
+struct sort_by_appearance
+{
+ bool operator() (const element_ref& left, const element_ref& right) const
+ {
+ return left.prop->appearance_order < right.prop->appearance_order;
+ }
+};
+
+struct scope
+{
+ xml_structure_tree::entity_name name;
+ elements_type elements;
+ elements_type::const_iterator current_pos;
+ bool repeat:1;
+
+ scope(const scope&) = delete;
+ scope& operator=(const scope&) = delete;
+
+ scope(const xml_structure_tree::entity_name& _name, bool _repeat, const element_ref& _elem) :
+ name(_name), repeat(_repeat)
+ {
+ elements.push_back(_elem);
+ current_pos = elements.begin();
+ }
+
+ scope(const xml_structure_tree::entity_name& _name, bool _repeat) :
+ name(_name), repeat(_repeat) {}
+};
+
+typedef std::vector<std::unique_ptr<scope>> scopes_type;
+
+void print_scope(std::ostream& os, const scopes_type& scopes, const xmlns_context& cxt)
+{
+ if (scopes.empty())
+ throw general_error("scope stack shouldn't be empty while dumping tree.");
+
+ // Skip the first scope which is root.
+ scopes_type::const_iterator it = scopes.begin(), it_end = scopes.end();
+ for (++it; it != it_end; ++it)
+ {
+ os << "/";
+ size_t num_id = cxt.get_index((*it)->name.ns);
+ if (num_id != INDEX_NOT_FOUND)
+ os << "ns" << num_id << ":";
+ os << (*it)->name.name;
+ if ((*it)->repeat)
+ os << "[*]";
+ }
+}
+
+}
+
+xml_table_range_t::xml_table_range_t() {}
+
+xml_table_range_t::~xml_table_range_t() {}
+
+struct xml_structure_tree::impl
+{
+ string_pool m_pool;
+ xmlns_context& m_xmlns_cxt;
+ std::unique_ptr<root> mp_root;
+
+ impl(const impl&) = delete;
+ impl& operator=(const impl&) = delete;
+
+ impl(xmlns_context& xmlns_cxt) : m_xmlns_cxt(xmlns_cxt) {}
+ ~impl() {}
+
+ std::string to_string(const xml_structure_tree::entity_name& name) const
+ {
+ std::ostringstream ss;
+ if (m_xmlns_cxt.get_index(name.ns) != INDEX_NOT_FOUND)
+ ss << m_xmlns_cxt.get_short_name(name.ns) << ":";
+ ss << name.name;
+ return ss.str();
+ }
+};
+
+struct xml_structure_tree::walker_impl
+{
+ const xml_structure_tree::impl& m_parent_impl;
+ root* mp_root; /// Root element of the authoritative tree.
+ element_ref m_cur_elem;
+ std::vector<element_ref> m_scopes;
+
+ walker_impl& operator=(const walker_impl&) = delete;
+
+ walker_impl(const xml_structure_tree::impl& parent_impl) :
+ m_parent_impl(parent_impl), mp_root(parent_impl.mp_root.get()) {}
+
+ walker_impl(const walker_impl& r) :
+ m_parent_impl(r.m_parent_impl), mp_root(r.mp_root), m_cur_elem(r.m_cur_elem), m_scopes(r.m_scopes) {}
+};
+
+xml_structure_tree::entity_name::entity_name() :
+ ns(XMLNS_UNKNOWN_ID) {}
+
+xml_structure_tree::entity_name::entity_name(xmlns_id_t _ns, std::string_view _name) :
+ ns(_ns), name(_name) {}
+
+bool xml_structure_tree::entity_name::operator< (const entity_name& r) const
+{
+ if (ns != r.ns)
+ return ns < r.ns;
+
+ return name < r.name;
+}
+
+bool xml_structure_tree::entity_name::operator== (const entity_name& r) const
+{
+ return ns == r.ns && name == r.name;
+}
+
+size_t xml_structure_tree::entity_name::hash::operator() (const entity_name& val) const
+{
+ size_t n = reinterpret_cast<size_t>(val.ns);
+ n += std::hash<std::string_view>{}(val.name);
+ return n;
+}
+
+xml_structure_tree::element::element() :
+ repeat(false), has_content(false) {}
+
+xml_structure_tree::element::element(const entity_name& _name, bool _repeat, bool _has_content) :
+ name(_name), repeat(_repeat), has_content(_has_content) {}
+
+xml_structure_tree::walker::walker(const xml_structure_tree::impl& parent_impl) :
+ mp_impl(std::make_unique<walker_impl>(parent_impl))
+{
+}
+
+xml_structure_tree::walker::walker(const walker& r) :
+ mp_impl(std::make_unique<walker_impl>(*r.mp_impl))
+{
+}
+
+xml_structure_tree::walker::~walker() {}
+
+xml_structure_tree::walker& xml_structure_tree::walker::operator= (const walker& r)
+{
+ mp_impl->mp_root = r.mp_impl->mp_root;
+ return *this;
+}
+
+xml_structure_tree::element xml_structure_tree::walker::root()
+{
+ if (!mp_impl->mp_root)
+ throw general_error("Tree is empty.");
+
+ mp_impl->m_scopes.clear();
+
+ // Set the current element to root.
+ element_ref ref(mp_impl->mp_root->name, &mp_impl->mp_root->prop);
+ mp_impl->m_cur_elem = ref;
+ mp_impl->m_scopes.push_back(ref);
+ return xml_structure_tree::element(ref.name, false, ref.prop->has_content);
+}
+
+xml_structure_tree::element xml_structure_tree::walker::descend(const entity_name& name)
+{
+ if (mp_impl->m_scopes.empty())
+ throw general_error("Scope is empty.");
+
+ assert(mp_impl->m_scopes.back().prop);
+ const auto& child_elems = mp_impl->m_scopes.back().prop->child_elements;
+ auto it = child_elems.find(name);
+
+ if (it == child_elems.end())
+ throw general_error("Specified child element does not exist.");
+
+ // Push this new child element onto the stack.
+ element_ref ref(name, it->second.get());
+ mp_impl->m_scopes.push_back(ref);
+
+ return element(name, it->second->repeat, it->second->has_content);
+}
+
+xml_structure_tree::element xml_structure_tree::walker::ascend()
+{
+ if (mp_impl->m_scopes.empty())
+ throw general_error("Scope is empty.");
+
+ if (mp_impl->m_scopes.size() == 1)
+ throw general_error("You can't ascend from the root element.");
+
+ mp_impl->m_scopes.pop_back();
+ const element_ref& ref = mp_impl->m_scopes.back();
+ return element(ref.name, ref.prop->repeat, ref.prop->has_content);
+}
+
+xml_structure_tree::entity_names_type xml_structure_tree::walker::get_children()
+{
+ if (mp_impl->m_scopes.empty())
+ throw general_error("Scope is empty.");
+
+ entity_names_type names;
+ assert(mp_impl->m_scopes.back().prop);
+ const elem_prop& prop = *mp_impl->m_scopes.back().prop;
+ names.assign(prop.child_element_names.begin(), prop.child_element_names.end());
+ return names;
+}
+
+xml_structure_tree::entity_names_type xml_structure_tree::walker::get_attributes()
+{
+ if (mp_impl->m_scopes.empty())
+ throw general_error("Scope is empty.");
+
+ entity_names_type names;
+ assert(mp_impl->m_scopes.back().prop);
+ const elem_prop& prop = *mp_impl->m_scopes.back().prop;
+ names.assign(prop.attribute_names.begin(), prop.attribute_names.end());
+ return names;
+}
+
+size_t xml_structure_tree::walker::get_xmlns_index(xmlns_id_t ns) const
+{
+ return mp_impl->m_parent_impl.m_xmlns_cxt.get_index(ns);
+}
+
+std::string xml_structure_tree::walker::get_xmlns_short_name(xmlns_id_t ns) const
+{
+ return mp_impl->m_parent_impl.m_xmlns_cxt.get_short_name(ns);
+}
+
+std::string xml_structure_tree::walker::to_string(const entity_name& name) const
+{
+ return mp_impl->m_parent_impl.to_string(name);
+}
+
+std::string xml_structure_tree::walker::get_path() const
+{
+ std::ostringstream ss;
+ for (auto& element : mp_impl->m_scopes)
+ {
+ ss << "/" << mp_impl->m_parent_impl.to_string(element.name);
+ }
+
+ return ss.str();
+}
+
+xml_structure_tree::element xml_structure_tree::walker::move_to(const std::string& path)
+{
+ auto parts = string_helper::split_string(path, '/');
+ if (parts.empty())
+ throw general_error("invalid format for path");
+
+ // string_helper::split_string will create an empty first element due to leading '/'
+ if (parts[0] != "")
+ {
+ throw general_error("invalid format for path");
+ }
+ else
+ {
+ parts.erase(parts.begin());
+ }
+
+ if (parts.empty())
+ throw general_error("invalid format for path");
+
+ element_ref root_ref(mp_impl->mp_root->name, &mp_impl->mp_root->prop);
+ if (mp_impl->m_parent_impl.to_string(root_ref.name) != parts[0])
+ throw general_error("path does not match any element");
+
+ std::vector<element_ref> scopes;
+ scopes.push_back(root_ref);
+
+ for (size_t i = 1; i < parts.size(); ++i)
+ {
+ const elem_prop& prop = *scopes.back().prop;
+ bool found = false;
+ for (auto& child : prop.child_elements)
+ {
+ if (mp_impl->m_parent_impl.to_string(child.first) == parts[i])
+ {
+ scopes.emplace_back(child.first, child.second.get());
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ throw general_error("path does not match any element");
+ }
+
+ std::swap(mp_impl->m_scopes, scopes);
+ const element_ref& ref = mp_impl->m_scopes.back();
+ return element(ref.name, ref.prop->repeat, ref.prop->has_content);
+}
+
+xml_structure_tree::xml_structure_tree(xmlns_context& xmlns_cxt) :
+ mp_impl(std::make_unique<impl>(xmlns_cxt)) {}
+
+xml_structure_tree::xml_structure_tree(xml_structure_tree&& other) :
+ mp_impl(std::move(other.mp_impl))
+{
+ other.mp_impl = std::make_unique<impl>(mp_impl->m_xmlns_cxt);
+}
+
+xml_structure_tree::~xml_structure_tree() {}
+
+void xml_structure_tree::parse(std::string_view s)
+{
+ xml_sax_handler hdl(mp_impl->m_pool);
+ sax_ns_parser<xml_sax_handler> parser(s, mp_impl->m_xmlns_cxt, hdl);
+ parser.parse();
+ mp_impl->mp_root = hdl.release_root_element();
+}
+
+void xml_structure_tree::dump_compact(std::ostream& os) const
+{
+ if (!mp_impl->mp_root)
+ return;
+
+ scopes_type scopes;
+ const xmlns_context& cxt = mp_impl->m_xmlns_cxt;
+
+ // Dump all namespaces first.
+ cxt.dump(os);
+
+ element_ref ref(mp_impl->mp_root->name, &mp_impl->mp_root->prop);
+ scopes.push_back(std::make_unique<scope>(entity_name(), false, ref));
+ while (!scopes.empty())
+ {
+ bool new_scope = false;
+
+ // Iterate through all elements in the current scope.
+ scope& cur_scope = *scopes.back();
+ for (; cur_scope.current_pos != cur_scope.elements.end(); ++cur_scope.current_pos)
+ {
+ const element_ref& this_elem = *cur_scope.current_pos;
+ std::ostringstream ss;
+ print_scope(ss, scopes, cxt);
+
+ ss << "/";
+ size_t num_id = cxt.get_index(this_elem.name.ns);
+ if (num_id != INDEX_NOT_FOUND)
+ ss << "ns" << num_id << ":";
+ ss << this_elem.name.name;
+ if (this_elem.prop->repeat)
+ ss << "[*]";
+
+ std::string elem_name = ss.str();
+ os << elem_name << std::endl;
+
+ // Print all attributes that belong to this element.
+ for (const entity_name& attr : this_elem.prop->attribute_names)
+ os << elem_name << "/@" << mp_impl->to_string(attr) << std::endl;
+
+ if (this_elem.prop->child_elements.empty())
+ continue;
+
+ // This element has child elements. Push a new scope and populate
+ // it with all child elements.
+ elements_type elems;
+ for (const auto& entry : this_elem.prop->child_elements)
+ {
+ ref.name = entry.first;
+ ref.prop = entry.second.get();
+ elems.push_back(ref);
+ }
+
+ // Sort the elements by order of appearance.
+ std::sort(elems.begin(), elems.end(), sort_by_appearance());
+
+ assert(!elems.empty());
+
+ // Push a new scope, and restart the loop with the new scope.
+ ++cur_scope.current_pos;
+ scopes.push_back(std::make_unique<scope>(this_elem.name, this_elem.prop->repeat));
+ scope& child_scope = *scopes.back();
+ child_scope.elements.swap(elems);
+ child_scope.current_pos = child_scope.elements.begin();
+
+ new_scope = true;
+ break;
+ }
+
+ if (new_scope)
+ continue;
+
+ scopes.pop_back();
+ }
+}
+
+xml_structure_tree::walker xml_structure_tree::get_walker() const
+{
+ return walker(*mp_impl);
+}
+
+void xml_structure_tree::process_ranges(range_handler_type rh) const
+{
+ detail::xml_structure_mapper mapper(rh, get_walker());
+ mapper.run();
+}
+
+void xml_structure_tree::swap(xml_structure_tree& other)
+{
+ mp_impl.swap(other.mp_impl);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_structure_tree_test.cpp b/src/liborcus/xml_structure_tree_test.cpp
new file mode 100644
index 0000000..ba8b550
--- /dev/null
+++ b/src/liborcus/xml_structure_tree_test.cpp
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/xml_structure_tree.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/parser_global.hpp>
+
+#include <cstdlib>
+#include <cassert>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include "filesystem_env.hpp"
+
+using namespace std;
+using namespace orcus;
+
+const fs::path test_base_dir(SRCDIR"/test/xml-structure");
+
+std::vector<fs::path> base_dirs = {
+ test_base_dir / "basic-1/",
+ test_base_dir / "basic-2/",
+ test_base_dir / "basic-3/",
+ test_base_dir / "attribute-1/",
+ test_base_dir / "nested-repeat-1/",
+ test_base_dir / "namespace-default/"
+};
+
+struct loaded_tree
+{
+ xmlns_context cxt;
+ file_content strm;
+ xml_structure_tree tree;
+
+ loaded_tree(xmlns_repository& repo) :
+ cxt(repo.create_context()),
+ tree(cxt) {}
+
+ loaded_tree(const loaded_tree&) = delete;
+};
+
+std::unique_ptr<loaded_tree> load_tree(xmlns_repository& repo, fs::path& filepath)
+{
+ auto ret = std::make_unique<loaded_tree>(repo);
+ ret->strm.load(filepath.string().data());
+ assert(!ret->strm.empty());
+ xml_structure_tree tree(ret->cxt);
+ tree.parse(ret->strm.str());
+ ret->tree.swap(tree);
+
+ return ret;
+}
+
+void test_basic()
+{
+ xmlns_repository xmlns_repo;
+
+ for (const fs::path& base_dir : base_dirs)
+ {
+ fs::path filepath = base_dir / "input.xml";
+ cout << filepath << endl;
+ auto lt = load_tree(xmlns_repo, filepath);
+
+ std::ostringstream os;
+ lt->tree.dump_compact(os);
+ string data_content = os.str();
+ cout << "--" << endl;
+ cout << data_content;
+
+ // Check the dump content against known datum.
+ filepath = base_dir / "check.txt";
+ file_content strm_check(filepath.string().data());
+ assert(!strm_check.empty());
+
+ // They should be identical, plus or minus leading/trailing whitespaces.
+ std::string_view s1(data_content.data(), data_content.size());
+ std::string_view s2 = strm_check.str();
+ assert(trim(s1) == trim(s2));
+ }
+}
+
+void test_walker()
+{
+ xmlns_repository xmlns_repo;
+
+ {
+ fs::path filepath = base_dirs[0] / "input.xml";
+ auto lt = load_tree(xmlns_repo, filepath);
+
+ // Get walker from the tree.
+ xml_structure_tree::entity_names_type elem_names;
+ xml_structure_tree::walker wkr = lt->tree.get_walker();
+
+ // Root element.
+ xml_structure_tree::element elem = wkr.root();
+ assert(elem.name.name == "root");
+ assert(!elem.repeat);
+
+ // Get names of child elements. There should only one one and it should be 'entry'.
+ elem_names = wkr.get_children();
+ assert(elem_names.size() == 1);
+ xml_structure_tree::entity_name elem_name = elem_names.front();
+ assert(elem_name.name == "entry");
+
+ // Descend into 'entry'.
+ elem = wkr.descend(elem_name);
+ assert(elem.name.name == "entry");
+ assert(elem.repeat);
+
+ // Element 'entry' should have 2 child elements 'name' and 'id' in this order.
+ elem_names = wkr.get_children();
+ assert(elem_names.size() == 2);
+ assert(elem_names[0].name == "name");
+ assert(elem_names[1].name == "id");
+
+ // Descend into 'name'.
+ elem_name = elem_names[0];
+ elem = wkr.descend(elem_name);
+ assert(elem.name.name == "name");
+ assert(!elem.repeat);
+
+ // This is a leaf element. It should have no child elements.
+ xml_structure_tree::entity_names_type test_names = wkr.get_children();
+ assert(test_names.empty());
+
+ // Move up to 'entry'.
+ elem = wkr.ascend();
+ assert(elem.name.name == "entry");
+ assert(elem.repeat);
+
+ // Move down to 'id'.
+ elem = wkr.descend(elem_names[1]);
+ assert(elem.name.name == "id");
+ assert(!elem.repeat);
+
+ // Move up to 'entry' again.
+ elem = wkr.ascend();
+ assert(elem.name.name == "entry");
+ assert(elem.repeat);
+
+ // Move up to 'root'.
+ elem = wkr.ascend();
+ assert(elem.name.name == "root");
+ assert(!elem.repeat);
+ }
+
+ {
+ fs::path filepath = base_dirs[3] / "input.xml"; // attribute-1
+ auto lt = load_tree(xmlns_repo, filepath);
+
+ // Get walker from the tree.
+ xml_structure_tree::entity_names_type elem_names;
+ xml_structure_tree::walker wkr = lt->tree.get_walker();
+
+ // Root element.
+ xml_structure_tree::element elem = wkr.root();
+ assert(elem.name.name == "root");
+ assert(!elem.repeat);
+
+ // Check attributes of root, which should have 'version' and 'type' in this order.
+ xml_structure_tree::entity_names_type names = wkr.get_attributes();
+ assert(names.size() == 2);
+ assert(names[0].name == "version");
+ assert(names[1].name == "type");
+
+ // Root element should have only one child element 'entry'.
+ names = wkr.get_children();
+ assert(names.size() == 1);
+ assert(names[0].name == "entry");
+ elem = wkr.descend(names[0]);
+ assert(elem.name.name == "entry");
+ assert(elem.repeat);
+
+ // The 'entry' element should have 3 attributes 'attr1', 'attr2', and 'attr3'.
+ names = wkr.get_attributes();
+ assert(names.size() == 3);
+ assert(names[0].name == "attr1");
+ assert(names[1].name == "attr2");
+ assert(names[2].name == "attr3");
+ }
+}
+
+void test_walker_path()
+{
+ fs::path filepath = base_dirs[0] / "input.xml";
+ xmlns_repository xmlns_repo;
+ auto lt = load_tree(xmlns_repo, filepath);
+
+ // Get walker from the tree.
+ xml_structure_tree::entity_names_type elem_names;
+ xml_structure_tree::walker wkr = lt->tree.get_walker();
+ wkr.root();
+ assert("/root" == wkr.get_path());
+
+ elem_names = wkr.get_children();
+ xml_structure_tree::entity_name elem_name = elem_names.front();
+ wkr.descend(elem_name);
+ assert("/root/entry" == wkr.get_path());
+
+ xml_structure_tree::element element = wkr.move_to("/root/entry");
+ assert(element.name.name == "entry");
+
+ try
+ {
+ wkr.move_to("/root/not-there");
+ assert(false);
+ }
+ catch (...)
+ {
+ }
+
+ try
+ {
+ wkr.move_to("something_different");
+ assert(false);
+ }
+ catch (...)
+ {
+ }
+
+ try
+ {
+ wkr.move_to("/non-exist");
+ assert(false);
+ }
+ catch (...)
+ {
+ }
+}
+
+void test_element_contents()
+{
+ xmlns_repository xmlns_repo;
+
+ {
+ fs::path filepath = test_base_dir / "attribute-1" / "input.xml";
+ auto lt = load_tree(xmlns_repo, filepath);
+ auto wkr = lt->tree.get_walker();
+ auto elem = wkr.move_to("/root/entry");
+ assert(wkr.to_string(elem.name) == "entry");
+ assert(elem.repeat);
+ assert(!elem.has_content);
+ }
+
+ {
+ fs::path filepath = test_base_dir / "basic-1" / "input.xml";
+ auto lt = load_tree(xmlns_repo, filepath);
+ auto wkr = lt->tree.get_walker();
+ auto elem = wkr.move_to("/root/entry/name");
+ assert(wkr.to_string(elem.name) == "name");
+ assert(!elem.repeat);
+ assert(elem.has_content);
+
+ elem = wkr.move_to("/root/entry/id");
+ assert(wkr.to_string(elem.name) == "id");
+ assert(!elem.repeat);
+ assert(elem.has_content);
+ }
+
+ {
+ fs::path filepath = test_base_dir / "nested-repeat-1" / "input.xml";
+ auto lt = load_tree(xmlns_repo, filepath);
+ auto wkr = lt->tree.get_walker();
+ auto elem = wkr.move_to("/root/mode/insert/command");
+ assert(wkr.to_string(elem.name) == "command");
+ assert(!elem.repeat);
+ assert(!elem.has_content);
+ }
+}
+
+int main()
+{
+ test_basic();
+ test_walker();
+ test_walker_path();
+ test_element_contents();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_util.cpp b/src/liborcus/xml_util.cpp
new file mode 100644
index 0000000..7c15adf
--- /dev/null
+++ b/src/liborcus/xml_util.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xml_util.hpp"
+
+#include <orcus/xml_namespace.hpp>
+#include <orcus/tokens.hpp>
+
+#include <sstream>
+#include <iostream>
+
+namespace orcus {
+
+xml_element_printer::xml_element_printer(const tokens& t) :
+ m_tokens(t)
+{
+}
+
+void xml_element_printer::set_ns_context(const xmlns_context* ns_cxt)
+{
+ mp_ns_cxt = ns_cxt;
+}
+
+void xml_element_printer::print_namespace(std::ostream& os, xmlns_id_t ns) const
+{
+ if (mp_ns_cxt)
+ {
+ std::string_view alias = mp_ns_cxt->get_alias(ns);
+ if (!alias.empty())
+ os << alias;
+ else
+ os << mp_ns_cxt->get_short_name(ns);
+ }
+ else
+ os << ns;
+}
+
+void xml_element_printer::print_element(std::ostream& os, xmlns_id_t ns, xml_token_t name) const
+{
+ os << '<';
+
+ std::ostringstream os_ns;
+ print_namespace(os_ns, ns);
+ std::string ns_str = os_ns.str();
+
+ if (!ns_str.empty())
+ os << ns_str << ':';
+
+ os << m_tokens.get_token_name(name) << '>';
+}
+
+void print_attrs(const tokens& tokens, const xml_token_attrs_t& attrs)
+{
+ for (const auto& attr : attrs)
+ {
+ std::cout << " ";
+ if (attr.ns != XMLNS_UNKNOWN_ID)
+ std::cout << attr.ns << ":";
+
+ std::cout << tokens.get_token_name(attr.name) << " = \"" << attr.value << "\"" << std::endl;
+ }
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xml_util.hpp b/src/liborcus/xml_util.hpp
new file mode 100644
index 0000000..1021ccf
--- /dev/null
+++ b/src/liborcus/xml_util.hpp
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <orcus/types.hpp>
+
+#include <ostream>
+
+namespace orcus {
+
+class tokens;
+class xmlns_context;
+
+class xml_element_printer
+{
+ const tokens& m_tokens;
+ const xmlns_context* mp_ns_cxt = nullptr;
+
+public:
+ xml_element_printer(const tokens& t);
+
+ void set_ns_context(const xmlns_context* ns_cxt);
+
+ void print_namespace(std::ostream& os, xmlns_id_t ns) const;
+
+ void print_element(std::ostream& os, xmlns_id_t ns, xml_token_t name) const;
+};
+
+void print_element(std::ostream& os, const tokens& t, xmlns_id_t ns, xml_token_t name);
+
+/**
+ * Print attributes to stdout for debugging purposes.
+ */
+void print_attrs(const tokens& tokens, const xml_token_attrs_t& attrs);
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xpath_parser.cpp b/src/liborcus/xpath_parser.cpp
new file mode 100644
index 0000000..306b367
--- /dev/null
+++ b/src/liborcus/xpath_parser.cpp
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xpath_parser.hpp"
+#include "orcus/exception.hpp"
+#include "orcus/xml_namespace.hpp"
+
+#define ORCUS_DEBUG_XPATH_PARSER 0
+
+namespace orcus {
+
+xpath_parser::token::token(xmlns_id_t _ns, std::string_view _name, bool _attribute) :
+ ns(_ns), name(_name), attribute(_attribute)
+{
+#if ORCUS_DEBUG_XPATH_PARSER
+ cout << "xpath_parser::token: (ns='" << (ns ? ns : "none") << "', name='" << name << "', attribute=" << attribute << ")" << endl;
+#endif
+}
+
+xpath_parser::token::token() : ns(XMLNS_UNKNOWN_ID), attribute(false) {}
+xpath_parser::token::token(const token& r) : ns(r.ns), name(r.name), attribute(r.attribute) {}
+
+xpath_parser::xpath_parser(const xmlns_context& cxt, const char* p, size_t n, xmlns_id_t default_ns) :
+ m_cxt(cxt),
+ mp_char(p),
+ mp_end(p+n),
+ m_default_ns(default_ns)
+{
+ if (!n)
+ throw xpath_error("empty path");
+
+ if (*p != '/')
+ throw xpath_error("first character must be '/'.");
+
+ ++mp_char;
+}
+
+xpath_parser::token xpath_parser::next()
+{
+ if (mp_char == mp_end)
+ return token();
+
+ const char* p0 = nullptr;
+ size_t len = 0;
+ xmlns_id_t ns = m_default_ns;
+
+ bool attribute = *mp_char == '@';
+ if (attribute)
+ ++mp_char;
+
+ for (; mp_char != mp_end; ++mp_char, ++len)
+ {
+ if (!p0)
+ {
+ p0 = mp_char;
+ len = 0;
+ }
+
+ switch (*mp_char)
+ {
+ case '/':
+ {
+ ++mp_char; // skip the '/'.
+ return token(ns, std::string_view(p0, len), attribute);
+ }
+ case ':':
+ {
+ // What comes before ':' is a namespace. Reset the name and
+ // convert the namespace to a proper ID.
+ std::string_view ns_name(p0, len);
+ ns = m_cxt.get(ns_name);
+ p0 = nullptr; // reset the name.
+ break;
+ }
+ default:
+ ;
+ }
+ }
+
+ // '/' has never been encountered. It must be the last name in the path.
+ return token(ns, std::string_view(p0, len), attribute);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xpath_parser.hpp b/src/liborcus/xpath_parser.hpp
new file mode 100644
index 0000000..211d749
--- /dev/null
+++ b/src/liborcus/xpath_parser.hpp
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_XPATH_PARSER_HPP
+#define INCLUDED_ORCUS_XPATH_PARSER_HPP
+
+#include <orcus/types.hpp>
+
+namespace orcus {
+
+class xmlns_context;
+
+class xpath_parser
+{
+ const xmlns_context& m_cxt;
+ const char* mp_char;
+ const char* mp_end;
+
+ xmlns_id_t m_default_ns;
+
+ enum class token_type { element, attribute };
+
+public:
+
+ struct token
+ {
+ xmlns_id_t ns;
+ std::string_view name;
+ bool attribute;
+
+ token(xmlns_id_t _ns, std::string_view _name, bool _attribute);
+ token();
+ token(const token& r);
+ };
+
+ xpath_parser(const xmlns_context& cxt, const char* p, size_t n, xmlns_id_t default_ns);
+
+ token next();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/xpath_parser_test.cpp b/src/liborcus/xpath_parser_test.cpp
new file mode 100644
index 0000000..26e7d6b
--- /dev/null
+++ b/src/liborcus/xpath_parser_test.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xpath_parser.hpp"
+#include "orcus/xml_namespace.hpp"
+
+#include <iostream>
+#include <cassert>
+
+using namespace orcus;
+
+void test_elements()
+{
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+
+ std::string_view path("/A/B/C");
+
+ xpath_parser parser(cxt, path.data(), path.size(), XMLNS_UNKNOWN_ID);
+ auto token = parser.next();
+ assert(token.name == "A");
+ assert(!token.attribute);
+
+ token = parser.next();
+ assert(token.name == "B");
+ assert(!token.attribute);
+
+ token = parser.next();
+ assert(token.name == "C");
+ assert(!token.attribute);
+
+ token = parser.next();
+ assert(token.name.empty());
+}
+
+void test_attributes()
+{
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+
+ std::string_view path("/A/B/C/@foo");
+
+ xpath_parser parser(cxt, path.data(), path.size(), XMLNS_UNKNOWN_ID);
+ auto token = parser.next();
+ assert(token.name == "A");
+ assert(!token.attribute);
+
+ token = parser.next();
+ assert(token.name == "B");
+ assert(!token.attribute);
+
+ token = parser.next();
+ assert(token.name == "C");
+ assert(!token.attribute);
+
+ token = parser.next();
+ assert(token.name == "foo");
+ assert(token.attribute);
+}
+
+int main()
+{
+ test_elements();
+ test_attributes();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/liborcus/yaml_document_tree.cpp b/src/liborcus/yaml_document_tree.cpp
new file mode 100644
index 0000000..1bd37a8
--- /dev/null
+++ b/src/liborcus/yaml_document_tree.cpp
@@ -0,0 +1,856 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/yaml_document_tree.hpp"
+#include "orcus/yaml_parser.hpp"
+
+#include "json_util.hpp"
+
+#include <vector>
+#include <memory>
+#include <unordered_map>
+#include <algorithm>
+#include <iostream>
+
+#include <boost/current_function.hpp>
+
+#define ORCUS_DEBUG_YAML_TREE 0
+
+#if ORCUS_DEBUG_YAML_TREE
+#include <iostream>
+#endif
+
+namespace orcus { namespace yaml {
+
+document_error::document_error(const std::string& msg) :
+ general_error("yaml_document_error", msg) {}
+
+document_error::~document_error() = default;
+
+struct yaml_value
+{
+ node_t type;
+ yaml_value* parent;
+
+ yaml_value() : type(node_t::unset), parent(nullptr) {}
+ yaml_value(node_t _type) : type(_type), parent(nullptr) {}
+ virtual ~yaml_value() {}
+
+ virtual size_t get_hash() const
+ {
+ return reinterpret_cast<size_t>(this);
+ }
+
+ virtual std::string print() const
+ {
+ std::ostringstream os;
+ os << "type: ";
+ switch (type)
+ {
+ case node_t::unset:
+ os << "unset";
+ break;
+ case node_t::string:
+ os << "string";
+ break;
+ case node_t::number:
+ os << "number";
+ break;
+ case node_t::map:
+ os << "map";
+ break;
+ case node_t::sequence:
+ os << "sequence";
+ break;
+ case node_t::boolean_true:
+ os << "true";
+ break;
+ case node_t::boolean_false:
+ os << "false";
+ break;
+ case node_t::null:
+ os << "null";
+ break;
+ }
+ return os.str();
+ }
+
+ struct hash
+ {
+ size_t operator() (const yaml_value& v) const
+ {
+ return v.get_hash();
+ }
+ };
+};
+
+namespace {
+
+struct yaml_value_string : public yaml_value
+{
+ std::string value_string;
+
+ yaml_value_string() : yaml_value(node_t::string) {}
+ yaml_value_string(std::string_view s) : yaml_value(node_t::string), value_string(s) {}
+ virtual ~yaml_value_string() {}
+
+ virtual std::string print() const
+ {
+ std::ostringstream os;
+ os << "type: string, value: " << value_string;
+ return os.str();
+ }
+};
+
+struct yaml_value_number : public yaml_value
+{
+ double value_number;
+
+ yaml_value_number(double num) : yaml_value(node_t::number), value_number(num) {}
+ virtual ~yaml_value_number() {}
+
+ virtual std::string print() const
+ {
+ std::ostringstream os;
+ os << "type: number, value: " << value_number;
+ return os.str();
+ }
+};
+
+struct yaml_value_sequence : public yaml_value
+{
+ std::vector<std::unique_ptr<yaml_value>> value_sequence;
+
+ yaml_value_sequence() : yaml_value(node_t::sequence) {}
+ virtual ~yaml_value_sequence() {}
+};
+
+struct yaml_value_map : public yaml_value
+{
+ std::vector<std::unique_ptr<yaml_value>> key_order; // owns the key instances.
+ std::unordered_map<const yaml_value*, std::unique_ptr<yaml_value>> value_map;
+
+ yaml_value_map() : yaml_value(node_t::map) {}
+ virtual ~yaml_value_map() {}
+};
+
+struct parser_stack
+{
+ std::unique_ptr<yaml_value> key;
+ yaml_value* node;
+
+ parser_stack(yaml_value* _node) : node(_node) {}
+ parser_stack(const parser_stack&) = delete;
+ parser_stack(parser_stack&& r) : key(std::move(r.key)), node(r.node) {}
+};
+
+typedef std::unique_ptr<yaml_value> document_root_type;
+
+class handler
+{
+ std::vector<document_root_type> m_docs;
+
+ std::vector<parser_stack> m_stack;
+ std::vector<parser_stack> m_key_stack;
+
+ document_root_type m_root;
+ document_root_type m_key_root;
+
+ bool m_in_document;
+
+#if ORCUS_DEBUG_YAML_TREE
+ void print_stack()
+ {
+ std::ostringstream os;
+ os << '(';
+ for (auto i = m_stack.begin(), ie = m_stack.end(); i != ie; ++i)
+ os << i->node->print() << ',';
+ os << ')';
+ std::cout << os.str() << std::endl;
+ }
+#endif
+
+ yaml_value* push_value(std::unique_ptr<yaml_value>&& value)
+ {
+ assert(!m_stack.empty());
+ parser_stack& cur = m_stack.back();
+
+ switch (cur.node->type)
+ {
+ case node_t::sequence:
+ {
+ yaml_value_sequence* yvs = static_cast<yaml_value_sequence*>(cur.node);
+ value->parent = yvs;
+ yvs->value_sequence.push_back(std::move(value));
+ return yvs->value_sequence.back().get();
+ }
+ case node_t::map:
+ {
+ yaml_value_map* yvm = static_cast<yaml_value_map*>(cur.node);
+ value->parent = yvm;
+
+ yvm->key_order.push_back(std::move(cur.key));
+
+ auto r = yvm->value_map.insert(
+ std::make_pair(
+ yvm->key_order.back().get(), std::move(value)));
+
+ return r.first->second.get();
+ }
+ default:
+ break;
+ }
+
+ std::ostringstream os;
+ os << BOOST_CURRENT_FUNCTION << ": unstackable YAML value type (" << cur.node->print() << ").";
+ throw document_error(os.str());
+ }
+
+public:
+ handler() : m_in_document(false) {}
+
+ void begin_parse()
+ {
+ }
+
+ void end_parse()
+ {
+ }
+
+ void begin_document()
+ {
+ assert(!m_in_document);
+ m_in_document = true;
+ m_root.reset();
+ }
+
+ void end_document()
+ {
+ assert(m_stack.empty());
+ m_in_document = false;
+ m_docs.push_back(std::move(m_root));
+ }
+
+ void begin_sequence()
+ {
+ assert(m_in_document);
+
+ if (m_root)
+ {
+ yaml_value* yv = push_value(std::make_unique<yaml_value_sequence>());
+ assert(yv && yv->type == node_t::sequence);
+ m_stack.push_back(parser_stack(yv));
+ }
+ else
+ {
+ m_root = std::make_unique<yaml_value_sequence>();
+ m_stack.push_back(parser_stack(m_root.get()));
+ }
+ }
+
+ void end_sequence()
+ {
+ assert(!m_stack.empty());
+ m_stack.pop_back();
+ }
+
+ void begin_map()
+ {
+ assert(m_in_document);
+ if (m_root)
+ {
+ yaml_value* yv = push_value(std::make_unique<yaml_value_map>());
+ assert(yv && yv->type == node_t::map);
+ m_stack.push_back(parser_stack(yv));
+ }
+ else
+ {
+ m_root = std::make_unique<yaml_value_map>();
+ m_stack.push_back(parser_stack(m_root.get()));
+ }
+ }
+
+ void begin_map_key()
+ {
+ assert(!m_key_root);
+ assert(m_key_stack.empty());
+ m_key_root.swap(m_root);
+ m_key_stack.swap(m_stack);
+ }
+
+ void end_map_key()
+ {
+ m_key_root.swap(m_root);
+ m_key_stack.swap(m_stack);
+
+ assert(!m_stack.empty());
+ parser_stack& cur = m_stack.back();
+ cur.key.swap(m_key_root);
+ m_key_stack.clear();
+ m_key_root.reset();
+ }
+
+ void end_map()
+ {
+ assert(!m_stack.empty());
+ m_stack.pop_back();
+ }
+
+ void string(std::string_view v)
+ {
+ assert(m_in_document);
+
+ if (m_root)
+ {
+ yaml_value* yv = push_value(std::make_unique<yaml_value_string>(v));
+ assert(yv && yv->type == node_t::string);
+ }
+ else
+ m_root = std::make_unique<yaml_value_string>(v);
+ }
+
+ void number(double val)
+ {
+ assert(m_in_document);
+ if (m_root)
+ {
+ yaml_value* yv = push_value(std::make_unique<yaml_value_number>(val));
+ assert(yv && yv->type == node_t::number);
+ }
+ else
+ m_root = std::make_unique<yaml_value_number>(val);
+ }
+
+ void boolean_true()
+ {
+ assert(m_in_document);
+ if (m_root)
+ {
+ yaml_value* yv = push_value(std::make_unique<yaml_value>(node_t::boolean_true));
+ assert(yv && yv->type == node_t::boolean_true);
+ }
+ else
+ m_root = std::make_unique<yaml_value>(node_t::boolean_true);
+ }
+
+ void boolean_false()
+ {
+ assert(m_in_document);
+ if (m_root)
+ {
+ yaml_value* yv = push_value(std::make_unique<yaml_value>(node_t::boolean_false));
+ assert(yv && yv->type == node_t::boolean_false);
+ }
+ else
+ m_root = std::make_unique<yaml_value>(node_t::boolean_false);
+ }
+
+ void null()
+ {
+ assert(m_in_document);
+ if (m_root)
+ {
+ yaml_value* yv = push_value(std::make_unique<yaml_value>(node_t::null));
+ assert(yv && yv->type == node_t::null);
+ }
+ else
+ m_root = std::make_unique<yaml_value>(node_t::null);
+ }
+
+ void swap(std::vector<document_root_type>& docs)
+ {
+ m_docs.swap(docs);
+ }
+};
+
+} // anonymous namespace
+
+struct document_tree::impl
+{
+ std::vector<document_root_type> m_docs;
+};
+
+struct const_node::impl
+{
+ const yaml_value* m_node;
+
+ impl(const yaml_value* yv) : m_node(yv) {}
+};
+
+const_node::const_node(const yaml_value* yv) : mp_impl(std::make_unique<impl>(yv)) {}
+const_node::const_node(const const_node& other) : mp_impl(std::make_unique<impl>(other.mp_impl->m_node)) {}
+const_node::const_node(const_node&& rhs) : mp_impl(std::move(rhs.mp_impl)) {}
+const_node::~const_node() {}
+
+const_node& const_node::operator=(const const_node& other)
+{
+ if (this == &other)
+ return *this;
+
+ const_node tmp(other);
+ mp_impl.swap(tmp.mp_impl);
+ return *this;
+}
+
+uintptr_t const_node::identity() const
+{
+ return reinterpret_cast<uintptr_t>(mp_impl->m_node);
+}
+
+node_t const_node::type() const
+{
+ return mp_impl->m_node->type;
+}
+
+size_t const_node::child_count() const
+{
+ switch (mp_impl->m_node->type)
+ {
+ case node_t::map:
+ return static_cast<const yaml_value_map*>(mp_impl->m_node)->value_map.size();
+ case node_t::sequence:
+ return static_cast<const yaml_value_sequence*>(mp_impl->m_node)->value_sequence.size();
+ case node_t::string:
+ case node_t::number:
+ case node_t::boolean_true:
+ case node_t::boolean_false:
+ case node_t::null:
+ case node_t::unset:
+ default:
+ ;
+ }
+ return 0;
+}
+
+std::vector<const_node> const_node::keys() const
+{
+ if (mp_impl->m_node->type != node_t::map)
+ throw document_error("node::keys: this node is not of map type.");
+
+ const yaml_value_map* yvm = static_cast<const yaml_value_map*>(mp_impl->m_node);
+ std::vector<const_node> keys;
+ std::for_each(yvm->key_order.begin(), yvm->key_order.end(),
+ [&](const std::unique_ptr<yaml_value>& key)
+ {
+ keys.push_back(const_node(key.get()));
+ }
+ );
+
+ return keys;
+}
+
+const_node const_node::key(size_t index) const
+{
+ if (mp_impl->m_node->type != node_t::map)
+ throw document_error("node::key: this node is not of map type.");
+
+ const yaml_value_map* yvm = static_cast<const yaml_value_map*>(mp_impl->m_node);
+ if (index >= yvm->key_order.size())
+ throw std::out_of_range("node::key: index is out-of-range.");
+
+ return const_node(yvm->key_order[index].get());
+}
+
+const_node const_node::child(size_t index) const
+{
+ switch (mp_impl->m_node->type)
+ {
+ case node_t::map:
+ {
+ const yaml_value_map* yvm = static_cast<const yaml_value_map*>(mp_impl->m_node);
+ if (index >= yvm->key_order.size())
+ throw std::out_of_range("node::child: index is out-of-range");
+
+ const yaml_value* key = yvm->key_order[index].get();
+ auto it = yvm->value_map.find(key);
+ assert(it != yvm->value_map.end());
+ return const_node(it->second.get());
+ }
+ break;
+ case node_t::sequence:
+ {
+ const yaml_value_sequence* yvs = static_cast<const yaml_value_sequence*>(mp_impl->m_node);
+ if (index >= yvs->value_sequence.size())
+ throw std::out_of_range("node::child: index is out-of-range");
+
+ return const_node(yvs->value_sequence[index].get());
+ }
+ break;
+ case node_t::string:
+ case node_t::number:
+ case node_t::boolean_true:
+ case node_t::boolean_false:
+ case node_t::null:
+ case node_t::unset:
+ default:
+ throw document_error("node::child: this node cannot have child nodes.");
+ }
+}
+
+const_node const_node::child(const const_node& key) const
+{
+ if (mp_impl->m_node->type != node_t::map)
+ throw document_error("node::child: this node is not of map type.");
+
+ const yaml_value_map* yvm = static_cast<const yaml_value_map*>(mp_impl->m_node);
+ auto it = yvm->value_map.find(key.mp_impl->m_node);
+ if (it == yvm->value_map.end())
+ throw document_error("node::child: this map does not have the specified key.");
+
+ return const_node(it->second.get());
+}
+
+const_node const_node::parent() const
+{
+ if (!mp_impl->m_node->parent)
+ throw document_error("node::parent: this node has no parent.");
+
+ return const_node(mp_impl->m_node->parent);
+}
+
+std::string_view const_node::string_value() const
+{
+ if (mp_impl->m_node->type != node_t::string)
+ throw document_error("node::key: current node is not of string type.");
+
+ const yaml_value_string* yvs = static_cast<const yaml_value_string*>(mp_impl->m_node);
+ return yvs->value_string;
+}
+
+double const_node::numeric_value() const
+{
+ if (mp_impl->m_node->type != node_t::number)
+ throw document_error("node::key: current node is not of numeric type.");
+
+ const yaml_value_number* yvn = static_cast<const yaml_value_number*>(mp_impl->m_node);
+ return yvn->value_number;
+}
+
+document_tree::document_tree() :
+ mp_impl(std::make_unique<impl>()) {}
+
+document_tree::document_tree(document_tree&& other) :
+ mp_impl(std::move(other.mp_impl)) {}
+
+document_tree::~document_tree() {}
+
+void document_tree::load(std::string_view s)
+{
+ handler hdl;
+ yaml_parser<handler> parser(s, hdl);
+ parser.parse();
+ hdl.swap(mp_impl->m_docs);
+}
+
+size_t document_tree::get_document_count() const
+{
+ return mp_impl->m_docs.size();
+}
+
+const_node document_tree::get_document_root(size_t index) const
+{
+ return const_node(mp_impl->m_docs[index].get());
+}
+
+namespace {
+
+const char* indent = " ";
+const char* kw_true = "true";
+const char* kw_false = "false";
+const char* kw_tilde = "~";
+const char* kw_null = "null";
+
+const char quote = '"';
+
+void dump_indent(std::ostringstream& os, size_t scope)
+{
+ for (size_t i = 0; i < scope; ++i)
+ os << indent;
+}
+
+bool needs_quoting(const std::string& s)
+{
+ // See if it contains certain characters...
+ for (auto it = s.begin(), ite = s.end(); it != ite; ++it)
+ if (is_in(*it, "#'"))
+ return true;
+
+ // See if the whole string is parsed as a number.
+ const char* p = s.data();
+ const char* p_end = p + s.size();
+ double v;
+ p = parse_numeric(p, p_end, v);
+ if (p == p_end)
+ return true;
+
+ return false;
+}
+
+void dump_yaml_string(std::ostringstream& os, const std::string& s)
+{
+ if (needs_quoting(s))
+ os << quote << s << quote;
+ else
+ os << s;
+}
+
+void dump_yaml_map(std::ostringstream& os, const yaml_value& node, size_t scope);
+void dump_yaml_sequence(std::ostringstream& os, const yaml_value& node, size_t scope);
+
+void dump_yaml_node(std::ostringstream& os, const yaml_value& node, size_t scope)
+{
+ switch (node.type)
+ {
+ case node_t::map:
+ dump_yaml_map(os, node, scope);
+ break;
+ case node_t::sequence:
+ dump_yaml_sequence(os, node, scope);
+ break;
+ case node_t::boolean_true:
+ dump_indent(os, scope);
+ os << kw_true << std::endl;
+ break;
+ case node_t::boolean_false:
+ dump_indent(os, scope);
+ os << kw_false << std::endl;
+ break;
+ case node_t::null:
+ dump_indent(os, scope);
+ os << kw_tilde << std::endl;
+ break;
+ case node_t::number:
+ dump_indent(os, scope);
+ os << static_cast<const yaml_value_number&>(node).value_number << std::endl;
+ break;
+ case node_t::string:
+ dump_indent(os, scope);
+ dump_yaml_string(os, static_cast<const yaml_value_string&>(node).value_string);
+ os << std::endl;
+ break;
+ case node_t::unset:
+ default:
+ ;
+ }
+}
+
+void dump_yaml_container_item(std::ostringstream& os, const yaml_value& node, size_t scope)
+{
+ switch (node.type)
+ {
+ case node_t::map:
+ case node_t::sequence:
+ // End the line and dump this child container in the next scope.
+ os << std::endl;
+ dump_yaml_node(os, node, scope+1);
+ break;
+ default:
+ // Dump inline.
+ os << " ";
+ dump_yaml_node(os, node, 0);
+ }
+}
+
+void dump_yaml_map(std::ostringstream& os, const yaml_value& node, size_t scope)
+{
+ const yaml_value_map& yvm = static_cast<const yaml_value_map&>(node);
+
+ std::for_each(yvm.key_order.begin(), yvm.key_order.end(),
+ [&](const std::unique_ptr<yaml_value>& pkey)
+ {
+ const yaml_value* key = pkey.get();
+
+ switch (key->type)
+ {
+ case node_t::map:
+ // TODO
+ break;
+ case node_t::sequence:
+ // TODO
+ break;
+ case node_t::boolean_true:
+ dump_indent(os, scope);
+ os << kw_true;
+ break;
+ case node_t::boolean_false:
+ dump_indent(os, scope);
+ os << kw_false;
+ break;
+ case node_t::null:
+ dump_indent(os, scope);
+ os << kw_tilde;
+ break;
+ case node_t::number:
+ dump_indent(os, scope);
+ os << static_cast<const yaml_value_number*>(key)->value_number;
+ break;
+ case node_t::string:
+ dump_indent(os, scope);
+ dump_yaml_string(os, static_cast<const yaml_value_string*>(key)->value_string);
+ break;
+ case node_t::unset:
+ default:
+ ;
+ }
+
+ os << ":";
+ auto it = yvm.value_map.find(key);
+ assert(it != yvm.value_map.end());
+ const yaml_value& value = *it->second;
+ dump_yaml_container_item(os, value, scope);
+ }
+ );
+}
+
+void dump_yaml_sequence(std::ostringstream& os, const yaml_value& node, size_t scope)
+{
+ const yaml_value_sequence& yvs = static_cast<const yaml_value_sequence&>(node);
+
+ std::for_each(yvs.value_sequence.begin(), yvs.value_sequence.end(),
+ [&](const std::unique_ptr<yaml_value>& p)
+ {
+ const yaml_value& child = *p;
+ dump_indent(os, scope);
+ os << "-";
+ dump_yaml_container_item(os, child, scope);
+ }
+ );
+}
+
+void dump_yaml_document(std::ostringstream& os, const yaml_value& root)
+{
+ os << "---" << std::endl;
+ dump_yaml_node(os, root, 0);
+}
+
+void dump_json_node(std::ostringstream& os, const yaml_value& node, size_t scope, const std::string* key);
+
+void dump_json_item(
+ std::ostringstream& os, const std::string* key, const yaml_value& val,
+ size_t scope, bool sep)
+{
+ dump_json_node(os, val, scope+1, key);
+ if (sep)
+ os << ",";
+ os << std::endl;
+}
+
+void dump_json_node(std::ostringstream& os, const yaml_value& node, size_t scope, const std::string* key = nullptr)
+{
+ dump_indent(os, scope);
+
+ if (key)
+ {
+ os << quote << *key << quote << ": ";
+ }
+
+ switch (node.type)
+ {
+ case node_t::map:
+ {
+ auto& key_order = static_cast<const yaml_value_map&>(node).key_order;
+ auto& vals = static_cast<const yaml_value_map&>(node).value_map;
+ os << "{" << std::endl;
+ size_t n = vals.size();
+
+ // Dump them based on key's original ordering.
+ size_t pos = 0;
+ for (auto it = key_order.begin(), ite = key_order.end(); it != ite; ++it, ++pos)
+ {
+ const yaml_value* this_key = it->get();
+ if (this_key->type != node_t::string)
+ throw document_error("JSON doesn't support non-string key.");
+
+ auto val_pos = vals.find(this_key);
+ assert(val_pos != vals.end());
+
+ dump_json_item(
+ os,
+ &static_cast<const yaml_value_string*>(this_key)->value_string,
+ *val_pos->second, scope, pos < (n-1));
+ }
+
+ dump_indent(os, scope);
+ os << "}";
+ }
+ break;
+ case node_t::sequence:
+ {
+ auto& vals = static_cast<const yaml_value_sequence&>(node).value_sequence;
+ os << "[" << std::endl;
+ size_t n = vals.size();
+ size_t pos = 0;
+ for (auto it = vals.begin(), ite = vals.end(); it != ite; ++it, ++pos)
+ dump_json_item(os, nullptr, **it, scope, pos < (n-1));
+
+ dump_indent(os, scope);
+ os << "]";
+ }
+ break;
+ case node_t::boolean_true:
+ os << kw_true;
+ break;
+ case node_t::boolean_false:
+ os << kw_false;
+ break;
+ case node_t::null:
+ os << kw_null;
+ break;
+ case node_t::number:
+ os << static_cast<const yaml_value_number&>(node).value_number;
+ break;
+ case node_t::string:
+ json::dump_string(os, static_cast<const yaml_value_string&>(node).value_string);
+ break;
+ case node_t::unset:
+ default:
+ ;
+ }
+}
+
+const char* warning_multiple_documents =
+"warning: this YAML file contains multiple documents. Only the first document\n"
+"will be written.";
+
+}
+
+std::string document_tree::dump_yaml() const
+{
+ std::ostringstream os;
+
+ std::for_each(
+ mp_impl->m_docs.begin(), mp_impl->m_docs.end(),
+ [&](const document_root_type& root)
+ {
+ dump_yaml_document(os, *root);
+ }
+ );
+
+ return os.str();
+}
+
+std::string document_tree::dump_json() const
+{
+ if (mp_impl->m_docs.empty())
+ return std::string();
+
+ if (mp_impl->m_docs.size() > 1)
+ std::cerr << warning_multiple_documents << std::endl;
+
+ const yaml_value& root = *mp_impl->m_docs.front();
+
+ std::ostringstream os;
+ dump_json_node(os, root, 0);
+
+ os << std::endl;
+
+ return os.str();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/liborcus/yaml_document_tree_test.cpp b/src/liborcus/yaml_document_tree_test.cpp
new file mode 100644
index 0000000..cb674ea
--- /dev/null
+++ b/src/liborcus/yaml_document_tree_test.cpp
@@ -0,0 +1,642 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/yaml_document_tree.hpp"
+#include "orcus/stream.hpp"
+#include "orcus/yaml_parser_base.hpp"
+
+#include <cassert>
+#include <iostream>
+#include <cmath>
+
+#include "filesystem_env.hpp"
+
+using namespace orcus;
+using namespace std;
+
+bool string_expected(const yaml::const_node& node, const char* expected)
+{
+ if (node.type() != yaml::node_t::string)
+ return false;
+
+ if (node.string_value() == expected)
+ return true;
+
+ cerr << "expected='" << expected << "', actual='" << node.string_value() << "'" << endl;
+ return false;
+}
+
+bool number_expected(
+ const yaml::const_node& node, double expected,
+ double decimal = 0.0, double exponent = 0.0)
+{
+ if (node.type() != yaml::node_t::number)
+ return false;
+
+ double actual = node.numeric_value();
+ if (!decimal || !exponent)
+ return actual == expected;
+
+ // Remove the exponent component.
+ actual /= std::pow(10.0, exponent);
+ expected /= std::pow(10.0, exponent);
+
+ // Only compare down to the specified decimal place.
+ actual *= std::pow(10.0, decimal);
+ expected *= std::pow(10.0, decimal);
+
+ actual = std::round(actual);
+ expected = std::round(expected);
+
+ return actual == expected;
+}
+
+yaml::document_tree load_doc(const char* filepath)
+{
+ cout << filepath << endl;
+ file_content strm(filepath);
+ cout << strm.str() << endl;
+ yaml::document_tree doc;
+ doc.load(strm.str());
+
+ return doc;
+}
+
+void test_yaml_invalids()
+{
+ // Get all yaml files in this directory.
+ fs::path dirpath(SRCDIR"/test/yaml/invalids/");
+ fs::directory_iterator it_end;
+
+ size_t file_count = 0;
+
+ for (fs::directory_iterator it(dirpath); it != it_end; ++it)
+ {
+ auto path = it->path();
+ if (!fs::is_regular_file(path))
+ continue;
+
+ if (path.extension().string() != ".yaml")
+ continue;
+
+ ++file_count;
+
+ file_content strm(path.string().data());
+ yaml::document_tree doc;
+
+ try
+ {
+ doc.load(strm.str());
+ assert(!"yaml::parse_error was not thrown, but expected to be.");
+ }
+ catch (const parse_error&)
+ {
+ // This is expected.
+ }
+ }
+
+ assert(file_count > 0);
+}
+
+void test_yaml_parse_basic1()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/basic1/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+
+ // Document root is a map node with 4 elements.
+ yaml::const_node root = doc.get_document_root(0);
+ uintptr_t root_id = root.identity();
+ assert(root.type() == yaml::node_t::map);
+ assert(root.child_count() == 4);
+
+ std::vector<yaml::const_node> keys = root.keys();
+ assert(keys.size() == 4);
+
+ yaml::const_node key = keys[0];
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "dict");
+
+ key = keys[1];
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "list");
+
+ key = keys[2];
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "number");
+
+ key = keys[3];
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "string");
+
+ // first child is a map.
+ yaml::const_node node = root.child(keys[0]);
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 3);
+
+ key = node.key(0);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "a");
+
+ key = node.key(1);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "b");
+
+ key = node.key(2);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "c");
+
+ node = node.child(0);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 1.0);
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 2.0);
+ node = node.parent();
+
+ node = node.child(2);
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == 2);
+ yaml::const_node child = node.child(0);
+ assert(child.type() == yaml::node_t::string);
+ assert(child.string_value() == "foo");
+ child = node.child(1);
+ assert(child.type() == yaml::node_t::string);
+ assert(child.string_value() == "bar");
+
+ // Go up to the root node.
+ node = node.parent().parent();
+ assert(node.type() == yaml::node_t::map);
+ assert(node.identity() == root_id);
+
+ node = node.child(keys[1]);
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == 3);
+
+ node = node.child(0);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 1.0);
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 2.0);
+ node = node.parent();
+
+ node = node.child(2);
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 3);
+
+ key = node.key(0);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "a");
+
+ key = node.key(1);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "b");
+
+ key = node.key(2);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "c");
+
+ node = node.child(0);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 1.1);
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 1.2);
+ node = node.parent();
+
+ node = node.child(2);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 1.3);
+ node = node.parent();
+
+ node = node.parent().parent(); // back to the root.
+ assert(node.identity() == root_id);
+
+ key = node.key(2);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "number");
+
+ key = node.key(3);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "string");
+
+ node = node.child(2);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 12.3);
+ node = node.parent();
+
+ node = node.child(3);
+ assert(node.type() == yaml::node_t::string);
+ assert(node.string_value() == "foo");
+ node = node.parent();
+}
+
+void test_yaml_parse_basic2()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/basic2/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == 3);
+
+ node = node.child(0);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 1);
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 2);
+ node = node.parent();
+
+ node = node.child(2);
+ assert(node.type() == yaml::node_t::number);
+ assert(node.numeric_value() == 3);
+ node = node.parent();
+}
+
+void test_yaml_parse_basic3()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/basic3/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == 2);
+
+ node = node.child(0);
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 3);
+
+ assert(string_expected(node.key(0), "a"));
+ assert(string_expected(node.key(1), "b"));
+ assert(string_expected(node.key(2), "c"));
+
+ assert(number_expected(node.child(0), 1));
+ assert(number_expected(node.child(1), 2));
+ assert(number_expected(node.child(2), 3));
+
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 3);
+
+ assert(string_expected(node.key(0), "d"));
+ assert(string_expected(node.key(1), "e"));
+ assert(string_expected(node.key(2), "f"));
+
+ assert(number_expected(node.child(0), 4));
+ assert(number_expected(node.child(1), 5));
+ assert(number_expected(node.child(2), 6));
+}
+
+void test_yaml_parse_null()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/null/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == 6);
+
+ node = node.child(0);
+ assert(node.type() == yaml::node_t::null);
+ node = node.parent();
+
+ node = node.child(1);
+ assert(node.type() == yaml::node_t::null);
+ node = node.parent();
+
+ node = node.child(2);
+ assert(node.type() == yaml::node_t::null);
+ node = node.parent();
+
+ node = node.child(3);
+ assert(node.type() == yaml::node_t::null);
+ node = node.parent();
+
+ node = node.child(4);
+ assert(node.type() == yaml::node_t::string);
+ assert(node.string_value() == "nULL");
+ node = node.parent();
+
+ node = node.child(5);
+ assert(node.type() == yaml::node_t::string);
+ assert(node.string_value() == "NUll");
+ node = node.parent();
+}
+
+void test_yaml_parse_boolean()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/boolean/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 3);
+
+ yaml::const_node key = node.key(0);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "positive");
+
+ key = node.key(1);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "negative");
+
+ key = node.key(2);
+ assert(key.type() == yaml::node_t::string);
+ assert(key.string_value() == "non boolean");
+
+ // list of boolean true's.
+ node = node.child(0);
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == 11);
+ for (size_t i = 0; i < node.child_count(); ++i)
+ {
+ yaml::const_node child = node.child(i);
+ assert(child.type() == yaml::node_t::boolean_true);
+ }
+ node = node.parent();
+
+ // list of boolean false's.
+ node = node.child(1);
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == 11);
+ for (size_t i = 0; i < node.child_count(); ++i)
+ {
+ yaml::const_node child = node.child(i);
+ assert(child.type() == yaml::node_t::boolean_false);
+ }
+ node = node.parent();
+
+ // list of strings.
+ const char* values[] = {
+ "yES",
+ "nO",
+ "tRUE",
+ "faLSE",
+ "oN",
+ "oFF"
+ };
+
+ node = node.child(2);
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == std::size(values));
+
+ for (size_t i = 0; i < std::size(values); ++i)
+ {
+ node = node.child(i);
+ assert(node.type() == yaml::node_t::string);
+ assert(node.string_value() == values[i]);
+ node = node.parent();
+ }
+}
+
+void test_yaml_parse_quoted_string()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/quoted-string/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 3);
+
+ assert(string_expected(node.key(0), "I am quoted: ~ "));
+ assert(string_expected(node.key(1), "list with quoted string values"));
+ assert(string_expected(node.key(2), "single quoted string values"));
+ assert(string_expected(node.child(0), "Here is another quote."));
+
+ node = node.child(1);
+
+ {
+ // list of strings.
+ const char* values[] = {
+ "1 2 3",
+ "null",
+ "true",
+ "false",
+ "#hashtag",
+ "\"quoted inside\"",
+ "'single quote inside'",
+ "Japan's finest beer"
+ };
+
+ size_t n = std::size(values);
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == n);
+
+ for (size_t i = 0; i < n; ++i)
+ assert(string_expected(node.child(i), values[i]));
+ }
+
+ node = node.parent().child(2);
+
+ {
+ // list of strings.
+ const char* values[] = {
+ "8.8.8.8",
+ "'single quote inside'",
+ "prefix 'quoted' suffix",
+ "\"double quote\"",
+ "before \"quote\" after",
+ "http://www.google.com",
+ "'''",
+ " ' ' ' ",
+ "#hashtag"
+ };
+
+ size_t n = std::size(values);
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == n);
+
+ for (size_t i = 0; i < n; ++i)
+ assert(string_expected(node.child(i), values[i]));
+ }
+}
+
+void test_yaml_parse_multi_line_1()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/multi-line-1/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+ assert(string_expected(node, "1 2 3"));
+ assert(node.child_count() == 0);
+}
+
+void test_yaml_parse_multi_line_2()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/multi-line-2/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+ assert(string_expected(node, "1 - 2 - 3"));
+ assert(node.child_count() == 0);
+}
+
+void test_yaml_parse_literal_block_1()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/literal-block-1/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(string_expected(node, "line 1\n line 2\nline 3\n2 blanks follow "));
+ assert(node.child_count() == 0);
+}
+
+void test_yaml_parse_literal_block_2()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/literal-block-2/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 2);
+
+ assert(string_expected(node.key(0), "literal block"));
+ assert(string_expected(node.child(0), "line 1\n line 2\n line 3"));
+ assert(string_expected(node.key(1), "multi line"));
+ assert(string_expected(node.child(1), "line 1 line 2 line 3"));
+}
+
+void test_yaml_parse_url()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/url/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == 3);
+
+ assert(string_expected(node.child(0), "http://www.google.com/"));
+ assert(string_expected(node.child(1), "mailto:joe@joe-me.com"));
+
+ node = node.child(2);
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 2);
+
+ assert(string_expected(node.key(0), "orcus-url"));
+ assert(string_expected(node.key(1), "debian-bugs"));
+ assert(string_expected(node.child(0), "http://gitlab.com/orcus/orcus"));
+ assert(string_expected(node.child(1), "mailto:submit@bugs.debian.org"));
+}
+
+void test_yaml_parse_empty_value_map_1()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/empty-value-map-1/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 1);
+
+ assert(string_expected(node.key(0), "key"));
+ assert(node.child(0).type() == yaml::node_t::null);
+}
+
+void test_yaml_parse_empty_value_map_2()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/empty-value-map-2/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 2);
+
+ assert(string_expected(node.key(0), "key1"));
+ assert(node.child(0).type() == yaml::node_t::null);
+ assert(string_expected(node.key(1), "key2"));
+ assert(node.child(1).type() == yaml::node_t::null);
+}
+
+void test_yaml_parse_empty_value_sequence_1()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/empty-value-sequence-1/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == 1);
+
+ assert(node.child(0).type() == yaml::node_t::null);
+}
+
+void test_yaml_parse_empty_value_sequence_2()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/empty-value-sequence-2/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::sequence);
+ assert(node.child_count() == 2);
+
+ assert(node.child(0).type() == yaml::node_t::null);
+ assert(node.child(1).type() == yaml::node_t::null);
+}
+
+void test_yaml_map_key_1()
+{
+ yaml::document_tree doc = load_doc(SRCDIR"/test/yaml/map-key-1/input.yaml");
+
+ assert(doc.get_document_count() == 1);
+ yaml::const_node node = doc.get_document_root(0);
+
+ assert(node.type() == yaml::node_t::map);
+ assert(node.child_count() == 2);
+
+ assert(string_expected(node.key(0), "-key"));
+ assert(string_expected(node.child(0), "value"));
+ assert(string_expected(node.key(1), "key"));
+ assert(string_expected(node.child(1), "value"));
+}
+
+int main()
+{
+ test_yaml_invalids();
+ test_yaml_parse_basic1();
+ test_yaml_parse_basic2();
+ test_yaml_parse_basic3();
+ test_yaml_parse_null();
+ test_yaml_parse_boolean();
+ test_yaml_parse_quoted_string();
+ test_yaml_parse_multi_line_1();
+ test_yaml_parse_multi_line_2();
+ test_yaml_parse_literal_block_1();
+ test_yaml_parse_literal_block_2();
+ test_yaml_parse_url();
+ test_yaml_parse_empty_value_map_1();
+ test_yaml_parse_empty_value_map_2();
+ test_yaml_parse_empty_value_sequence_1();
+ test_yaml_parse_empty_value_sequence_2();
+ test_yaml_map_key_1();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/mso/Makefile.am b/src/mso/Makefile.am
new file mode 100644
index 0000000..b21e225
--- /dev/null
+++ b/src/mso/Makefile.am
@@ -0,0 +1,13 @@
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include \
+ -D__ORCUS_MSO_BUILDING_DLL
+
+lib_LTLIBRARIES = liborcus-mso-@ORCUS_API_VERSION@.la
+liborcus_mso_@ORCUS_API_VERSION@_la_SOURCES = \
+ encryption_info.cpp
+
+liborcus_mso_@ORCUS_API_VERSION@_la_LDFLAGS = -no-undefined
+liborcus_mso_@ORCUS_API_VERSION@_la_LIBADD = \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
diff --git a/src/mso/Makefile.in b/src/mso/Makefile.in
new file mode 100644
index 0000000..783cdcc
--- /dev/null
+++ b/src/mso/Makefile.in
@@ -0,0 +1,702 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/mso
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+liborcus_mso_@ORCUS_API_VERSION@_la_DEPENDENCIES = \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+am_liborcus_mso_@ORCUS_API_VERSION@_la_OBJECTS = encryption_info.lo
+liborcus_mso_@ORCUS_API_VERSION@_la_OBJECTS = \
+ $(am_liborcus_mso_@ORCUS_API_VERSION@_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+liborcus_mso_@ORCUS_API_VERSION@_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(liborcus_mso_@ORCUS_API_VERSION@_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/encryption_info.Plo
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(liborcus_mso_@ORCUS_API_VERSION@_la_SOURCES)
+DIST_SOURCES = $(liborcus_mso_@ORCUS_API_VERSION@_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include \
+ -D__ORCUS_MSO_BUILDING_DLL
+
+lib_LTLIBRARIES = liborcus-mso-@ORCUS_API_VERSION@.la
+liborcus_mso_@ORCUS_API_VERSION@_la_SOURCES = \
+ encryption_info.cpp
+
+liborcus_mso_@ORCUS_API_VERSION@_la_LDFLAGS = -no-undefined
+liborcus_mso_@ORCUS_API_VERSION@_la_LIBADD = \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/mso/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/mso/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+liborcus-mso-@ORCUS_API_VERSION@.la: $(liborcus_mso_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_mso_@ORCUS_API_VERSION@_la_DEPENDENCIES) $(EXTRA_liborcus_mso_@ORCUS_API_VERSION@_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(liborcus_mso_@ORCUS_API_VERSION@_la_LINK) -rpath $(libdir) $(liborcus_mso_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_mso_@ORCUS_API_VERSION@_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encryption_info.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-am
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-am
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-am
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-am
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-am
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/encryption_info.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/encryption_info.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am am--depfiles check check-am check-valgrind-am \
+ check-valgrind-drd-am check-valgrind-drd-local \
+ check-valgrind-helgrind-am check-valgrind-helgrind-local \
+ check-valgrind-local check-valgrind-memcheck-am \
+ check-valgrind-memcheck-local check-valgrind-sgcheck-am \
+ check-valgrind-sgcheck-local clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/mso/encryption_info.cpp b/src/mso/encryption_info.cpp
new file mode 100644
index 0000000..bca2bcd
--- /dev/null
+++ b/src/mso/encryption_info.cpp
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/sax_ns_parser.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <orcus/base64.hpp>
+
+#include "mso/encryption_info.hpp"
+
+#define ORCUS_DEBUG_MSO_ENCRYPTION_INFO 1
+
+#if ORCUS_DEBUG_MSO_ENCRYPTION_INFO
+#include <iostream>
+#endif
+
+#include <vector>
+#include <ostream>
+
+using namespace std;
+
+namespace orcus { namespace mso {
+
+namespace {
+
+const xmlns_id_t NS_mso_encryption = "http://schemas.microsoft.com/office/2006/encryption";
+const xmlns_id_t NS_mso_password = "http://schemas.microsoft.com/office/2006/keyEncryptor/password";
+
+const xmlns_id_t NS_mso_all[] = {
+ NS_mso_encryption,
+ NS_mso_password,
+ nullptr
+};
+
+class char_printer
+{
+ ostream& m_os;
+public:
+ char_printer(ostream& os) : m_os(os) {}
+ void operator() (const char c) const
+ {
+ short v = c;
+ v &= 0x00FF;
+ m_os << hex << uppercase;
+ if (v < 16)
+ m_os << '0';
+ m_os << v << ' ';
+ }
+};
+
+void print_base64(const char* caption, std::string_view base64)
+{
+ cout << caption << " (base64): " << base64 << endl;
+ vector<uint8_t> value = orcus::decode_from_base64(base64);
+ cout << caption << " (binary): ";
+ for_each(value.begin(), value.end(), char_printer(cout));
+ cout << endl;
+}
+
+class key_data_attr_handler
+{
+public:
+ void operator() (const sax_ns_parser_attribute& attr)
+ {
+ if (attr.ns != NS_mso_encryption)
+ // wrong namespace
+ return;
+
+ if (attr.name == "saltSize")
+ cout << "salt size: " << attr.value << endl;
+ else if (attr.name == "blockSize")
+ cout << "block size: " << attr.value << endl;
+ else if (attr.name == "keyBits")
+ cout << "key bits: " << attr.value << endl;
+ else if (attr.name == "hashSize")
+ cout << "hash size: " << attr.value << endl;
+ else if (attr.name == "cipherAlgorithm")
+ cout << "cipher algorithm: " << attr.value << endl;
+ else if (attr.name == "cipherChaining")
+ cout << "cipher chaining: " << attr.value << endl;
+ else if (attr.name == "hashAlgorithm")
+ cout << "hash algorithm: " << attr.value << endl;
+ else if (attr.name == "saltValue")
+ print_base64("salt value", attr.value);
+ }
+};
+
+class data_integrity_attr_handler
+{
+public:
+ void operator() (const sax_ns_parser_attribute& attr)
+ {
+ if (attr.ns != NS_mso_encryption)
+ // wrong namespace
+ return;
+
+ if (attr.name == "encryptedHmacKey")
+ print_base64("encrypted HMAC key", attr.value);
+ else if (attr.name == "encryptedHmacValue")
+ print_base64("encrypted HMAC value", attr.value);
+ }
+};
+
+class password_encrypted_key_attr_handler
+{
+public:
+ void operator() (const sax_ns_parser_attribute& attr)
+ {
+ if (attr.ns != NS_mso_encryption)
+ // wrong namespace
+ return;
+
+ if (attr.name == "spinCount")
+ cout << "spin count: " << attr.value << endl;
+ else if (attr.name == "saltSize")
+ cout << "salt size: " << attr.value << endl;
+ else if (attr.name == "blockSize")
+ cout << "block size: " << attr.value << endl;
+ else if (attr.name == "keyBits")
+ cout << "key bits: " << attr.value << endl;
+ else if (attr.name == "hashSize")
+ cout << "hash size: " << attr.value << endl;
+ else if (attr.name == "cipherAlgorithm")
+ cout << "cipher algorithm: " << attr.value << endl;
+ else if (attr.name == "cipherChaining")
+ cout << "cipher chaining: " << attr.value << endl;
+ else if (attr.name == "hashAlgorithm")
+ cout << "hash algorithm: " << attr.value << endl;
+ else if (attr.name == "saltValue")
+ print_base64("salt value", attr.value);
+ else if (attr.name == "encryptedVerifierHashInput")
+ print_base64("encrypted verifier hash input", attr.value);
+ else if (attr.name == "encryptedVerifierHashValue")
+ print_base64("encrypted verifier hash value", attr.value);
+ else if (attr.name == "encryptedKeyValue")
+ print_base64("encrypted key value", attr.value);
+
+ }
+};
+
+class sax_handler
+{
+ vector<sax_ns_parser_attribute> m_attrs;
+
+public:
+ sax_handler(xmlns_context& /*ns_cxt*/) {}
+ void doctype(const sax::doctype_declaration&) {}
+ void start_declaration(std::string_view) {}
+ void end_declaration(std::string_view) {}
+ void attribute(std::string_view, std::string_view) {}
+
+ void attribute(const sax_ns_parser_attribute& attr)
+ {
+ m_attrs.push_back(attr);
+ }
+
+ void characters(std::string_view, bool) {}
+
+ void start_element(const sax_ns_parser_element& elem)
+ {
+ if (elem.ns == NS_mso_encryption)
+ {
+ if (elem.name == "keyData")
+ {
+ cout << "--- key data" << endl;
+ key_data_attr_handler func;
+ for_each(m_attrs.begin(), m_attrs.end(), func);
+ }
+ else if (elem.name == "dataIntegrity")
+ {
+ cout << "--- data integrity" << endl;
+ data_integrity_attr_handler func;
+ for_each(m_attrs.begin(), m_attrs.end(), func);
+ }
+ }
+ else if (elem.ns == NS_mso_password)
+ {
+ if (elem.name == "encryptedKey")
+ {
+ cout << "--- encrypted key" << endl;
+ password_encrypted_key_attr_handler func;
+ for_each(m_attrs.begin(), m_attrs.end(), func);
+ }
+ }
+
+ m_attrs.clear();
+ }
+
+ void end_element(const sax_ns_parser_element&) {}
+};
+
+}
+
+struct encryption_info_reader_impl
+{
+ orcus::xmlns_repository m_ns_repo;
+
+ encryption_info_reader_impl()
+ {
+ m_ns_repo.add_predefined_values(NS_mso_all);
+ }
+};
+
+encryption_info_reader::encryption_info_reader() :
+ mp_impl(new encryption_info_reader_impl) {}
+
+encryption_info_reader::~encryption_info_reader()
+{
+ delete mp_impl;
+}
+
+void encryption_info_reader::read(const char* p, size_t n)
+{
+#if ORCUS_DEBUG_MSO_ENCRYPTION_INFO
+ cout << "encryption_info_reader::read: stream size=" << n << endl;
+#endif
+ orcus::xmlns_context cxt = mp_impl->m_ns_repo.create_context();
+ sax_handler hdl(cxt);
+ orcus::sax_ns_parser<sax_handler> parser({p, n}, cxt, hdl);
+ parser.parse();
+}
+
+}}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_css_dump.cpp b/src/orcus_css_dump.cpp
new file mode 100644
index 0000000..f02ba77
--- /dev/null
+++ b/src/orcus_css_dump.cpp
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/css_document_tree.hpp"
+#include "orcus/stream.hpp"
+
+#include <iostream>
+
+int main(int argc, char** argv)
+{
+ if (argc < 2)
+ return EXIT_FAILURE;
+
+ const char* filepath = argv[1];
+ try
+ {
+ orcus::file_content content(filepath);
+ orcus::css_document_tree doc;
+ doc.load(content.str());
+ doc.dump();
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_csv_main.cpp b/src/orcus_csv_main.cpp
new file mode 100644
index 0000000..718fa28
--- /dev/null
+++ b/src/orcus_csv_main.cpp
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_csv.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#include "orcus/config.hpp"
+
+#include "orcus_filter_global.hpp"
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace std;
+using namespace orcus;
+namespace po = boost::program_options;
+
+class csv_args_handler : public extra_args_handler
+{
+ constexpr static const char* help_row_header =
+ "Specify the number of header rows to repeat if the source content gets split into multiple sheets.";
+
+ constexpr static const char* help_row_size =
+ "Specify the number of maximum rows in each sheet.";
+
+ constexpr static const char* help_split =
+ "Specify whether or not to split the data into multiple sheets in case it won't fit in a single sheet.";
+
+ spreadsheet::import_factory& m_fact;
+
+public:
+ csv_args_handler(spreadsheet::import_factory& fact) : m_fact(fact) {}
+ virtual ~csv_args_handler() override {}
+
+ virtual void add_options(po::options_description& desc) override
+ {
+ desc.add_options()
+ ("row-header", po::value<size_t>(), help_row_header)
+ ("split", help_split);
+ }
+
+ virtual void map_to_config(config& opt, const po::variables_map& vm) override
+ {
+ auto csv = std::get<config::csv_config>(opt.data);
+
+ if (vm.count("row-header"))
+ csv.header_row_size = vm["row-header"].as<size_t>();
+
+ csv.split_to_multiple_sheets = vm.count("split") > 0;
+
+ opt.data = csv;
+ }
+};
+
+int main(int argc, char** argv)
+{
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory fact(doc);
+ orcus_csv app(&fact);
+ csv_args_handler hdl(fact);
+
+ try
+ {
+ if (!parse_import_filter_args(argc, argv, fact, app, doc, &hdl))
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception& e)
+ {
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_detect_main.cpp b/src/orcus_detect_main.cpp
new file mode 100644
index 0000000..8dc89c6
--- /dev/null
+++ b/src/orcus_detect_main.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/format_detection.hpp"
+#include "orcus/exception.hpp"
+#include "orcus/stream.hpp"
+
+#include <cstdlib>
+#include <iostream>
+#include <string>
+
+using namespace orcus;
+using namespace std;
+
+int main(int argc, char** argv) try
+{
+ if (argc != 2)
+ return EXIT_FAILURE;
+
+ const char* filepath = argv[1];
+ file_content content(filepath);
+
+ if (content.empty())
+ {
+ cerr << "file is empty" << endl;
+ return EXIT_FAILURE;
+ }
+
+ format_t detected_type = detect(content.str());
+
+ cout << "type: ";
+ switch (detected_type)
+ {
+ case format_t::csv:
+ cout << "plain text format";
+ break;
+ case format_t::gnumeric:
+ cout << "Gnumeric";
+ break;
+ case format_t::ods:
+ cout << "OpenDocument Spreadsheet";
+ break;
+ case format_t::xls_xml:
+ cout << "Microsoft Excel XML";
+ break;
+ case format_t::xlsx:
+ cout << "Microsoft Office Open XML Excel 2007+";
+ break;
+ case format_t::parquet:
+ cout << "Apache Parquet";
+ break;
+ case format_t::unknown:
+ default:
+ cout << "unknown";
+ }
+ cout << endl;
+
+ return EXIT_SUCCESS;
+}
+catch (const std::exception& e)
+{
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_env_dump.cpp b/src/orcus_env_dump.cpp
new file mode 100644
index 0000000..2a60fb7
--- /dev/null
+++ b/src/orcus_env_dump.cpp
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "cpu_features.hpp"
+
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+int main()
+{
+ cout << "CPU flags:" << endl;
+ cout << " SSE 4.2: " << orcus::detail::cpu::has_sse42() << endl;
+ cout << " AVX2: " << orcus::detail::cpu::has_avx2() << endl;
+
+#if defined(_MSC_VER)
+ cout << "MSVC macros:" << endl;
+ #ifdef _M_IX86_FP
+ cout << " _M_IX86_FP: " << _M_IX86_FP << endl;
+ #else
+ cout << " _M_IX86_FP: not defined" << endl;
+ #endif
+#endif
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_filter_global.cpp b/src/orcus_filter_global.cpp
new file mode 100644
index 0000000..6df8563
--- /dev/null
+++ b/src/orcus_filter_global.cpp
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus_filter_global.hpp"
+#include "orcus/config.hpp"
+#include "orcus/interface.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+
+#include <mdds/sorted_string_map.hpp>
+#include <vector>
+#include <iostream>
+#include <fstream>
+
+#include "filesystem_env.hpp"
+
+using namespace std;
+using namespace orcus;
+
+namespace po = boost::program_options;
+
+namespace orcus {
+
+extra_args_handler::~extra_args_handler() {}
+
+namespace {
+
+const std::map<dump_format_t, std::string_view> descriptions =
+{
+ std::make_pair(dump_format_t::check, "Flat format that fully encodes document content. Suitable for automated testing."),
+ std::make_pair(dump_format_t::csv, "CSV format."),
+ std::make_pair(dump_format_t::flat, "Flat text format that displays document content in grid."),
+ std::make_pair(dump_format_t::html, "HTML format."),
+ std::make_pair(dump_format_t::json, "JSON format."),
+ std::make_pair(dump_format_t::xml, "This format is currently unsupported."),
+ std::make_pair(dump_format_t::yaml, "This format is currently unsupported."),
+ std::make_pair(dump_format_t::debug_state, "This format dumps the internal state of the document in detail, useful for debugging."),
+ std::make_pair(dump_format_t::none, "No output to be generated. Maybe useful during development."),
+};
+
+const char* help_program =
+"The FILE must specify a path to an existing file.";
+
+const char* help_output =
+"Output directory path, or output file when --dump-check option is used.";
+
+const char* help_dump_check =
+"Dump the content to stdout in a special format used for content verification "
+"in automated tests.";
+
+const char* help_debug =
+"Turn on a debug mode and optionally specify a debug level in order to generate run-time debug outputs.";
+
+const char* help_recalc =
+"Re-calculate all formula cells after the documetn is loaded.";
+
+const char* help_formula_error_policy =
+"Specify whether to abort immediately when the loader fails to parse the first "
+"formula cell ('fail'), or skip the offending cells and continue ('skip').";
+
+const char* help_row_size =
+"Specify the number of maximum rows in each sheet.";
+
+const char* err_no_input_file = "No input file.";
+
+}
+
+std::string gen_help_output_format()
+{
+ std::ostringstream os;
+ os << "Specify the output format. Supported format types are:" << endl;
+
+ for (std::pair<std::string_view, dump_format_t> entry : get_dump_format_entries())
+ {
+ std::string_view desc;
+ auto it_desc = descriptions.find(entry.second);
+ if (it_desc != descriptions.end())
+ desc = it_desc->second;
+
+ os << std::endl << "* " << entry.first << " - " << desc;
+ }
+
+ return os.str();
+}
+
+bool handle_dump_check(
+ iface::import_filter& app, iface::document_dumper& doc, const string& infile, const string& outfile)
+{
+ if (outfile.empty())
+ {
+ // Dump to stdout when no output file is specified.
+ app.read_file(infile);
+ doc.dump_check(cout);
+ return true;
+ }
+
+ if (fs::exists(outfile) && fs::is_directory(outfile))
+ {
+ cerr << "A directory named '" << outfile << "' already exists." << endl;
+ return false;
+ }
+
+ ofstream file(outfile.c_str());
+ app.read_file(infile);
+ doc.dump_check(file);
+ return true;
+}
+
+bool parse_import_filter_args(
+ int argc, char** argv, spreadsheet::import_factory& fact,
+ iface::import_filter& app, iface::document_dumper& doc,
+ extra_args_handler* args_handler)
+{
+ bool debug = false;
+ bool recalc_formula_cells = false;
+
+ po::options_description desc("Options");
+ desc.add_options()
+ ("help,h", "Print this help.")
+ ("debug,d", po::bool_switch(&debug), help_debug)
+ ("recalc,r", po::bool_switch(&recalc_formula_cells), help_recalc)
+ ("error-policy,e", po::value<string>()->default_value("fail"), help_formula_error_policy)
+ ("dump-check", help_dump_check)
+ ("output,o", po::value<string>(), help_output)
+ ("output-format,f", po::value<string>(), gen_help_output_format().data())
+ ("row-size", po::value<spreadsheet::row_t>(), help_row_size);
+
+ if (args_handler)
+ args_handler->add_options(desc);
+
+ po::options_description hidden("Hidden options");
+ hidden.add_options()
+ ("input", po::value<string>(), "input file");
+
+ po::options_description cmd_opt;
+ cmd_opt.add(desc).add(hidden);
+
+ po::positional_options_description po_desc;
+ po_desc.add("input", -1);
+
+ po::variables_map vm;
+ try
+ {
+ po::store(
+ po::command_line_parser(argc, argv).options(cmd_opt).positional(po_desc).run(), vm);
+ po::notify(vm);
+ }
+ catch (const exception& e)
+ {
+ // Unknown options.
+ cout << e.what() << endl;
+ cout << desc;
+ return false;
+ }
+
+ if (vm.count("help"))
+ {
+ cout << "Usage: orcus-" << app.get_name() << " [options] FILE" << endl << endl;
+ cout << help_program << endl << endl << desc;
+ return true;
+ }
+
+ std::string infile, outdir;
+ dump_format_t outformat = dump_format_t::unknown;
+
+ if (vm.count("input"))
+ infile = vm["input"].as<string>();
+
+ if (vm.count("output"))
+ outdir = vm["output"].as<string>();
+
+ if (vm.count("output-format"))
+ {
+ std::string outformat_s = vm["output-format"].as<string>();
+ outformat = to_dump_format_enum(outformat_s);
+ }
+
+ if (vm.count("row-size"))
+ fact.set_default_row_size(vm["row-size"].as<spreadsheet::row_t>());
+
+ std::string error_policy_s = vm["error-policy"].as<std::string>();
+ spreadsheet::formula_error_policy_t error_policy =
+ spreadsheet::to_formula_error_policy(error_policy_s);
+
+ if (error_policy == spreadsheet::formula_error_policy_t::unknown)
+ {
+ cerr << "Unrecognized error policy: " << error_policy_s << endl;
+ return false;
+ }
+
+ fact.set_formula_error_policy(error_policy);
+
+ if (infile.empty())
+ {
+ cerr << err_no_input_file << endl;
+ return false;
+ }
+
+ config opt = app.get_config();
+ opt.debug = debug;
+
+ if (args_handler)
+ args_handler->map_to_config(opt, vm);
+
+ app.set_config(opt);
+
+ fact.set_recalc_formula_cells(recalc_formula_cells);
+
+ if (vm.count("dump-check"))
+ {
+ // 'outdir' is used as the output file path in this mode.
+ return handle_dump_check(app, doc, infile, outdir);
+ }
+
+ if (outformat == dump_format_t::unknown)
+ {
+ std::cerr << "You must specify one of the supported output formats." << endl;
+ return false;
+ }
+
+ try
+ {
+ app.read_file(infile);
+ doc.dump(outformat, outdir);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_filter_global.hpp b/src/orcus_filter_global.hpp
new file mode 100644
index 0000000..6fdf344
--- /dev/null
+++ b/src/orcus_filter_global.hpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef ORCUS_ORCUS_FILTER_GLOBAL_HPP
+#define ORCUS_ORCUS_FILTER_GLOBAL_HPP
+
+#include <boost/program_options.hpp>
+
+namespace orcus {
+
+struct config;
+
+namespace spreadsheet {
+
+class import_factory;
+
+}
+
+namespace iface {
+
+class import_filter;
+class document_dumper;
+
+}
+
+/**
+ * Interface for supporting additional command-line options.
+ */
+class extra_args_handler
+{
+public:
+ virtual ~extra_args_handler();
+
+ virtual void add_options(boost::program_options::options_description& desc) = 0;
+ virtual void map_to_config(
+ config& opt, const boost::program_options::variables_map& vm) = 0;
+};
+
+bool parse_import_filter_args(
+ int argc, char** argv, spreadsheet::import_factory& fact,
+ iface::import_filter& app, iface::document_dumper& doc,
+ extra_args_handler* args_handler = nullptr);
+
+std::string gen_help_output_format();
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_gnumeric_main.cpp b/src/orcus_gnumeric_main.cpp
new file mode 100644
index 0000000..5eda3dc
--- /dev/null
+++ b/src/orcus_gnumeric_main.cpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_gnumeric.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include "orcus_filter_global.hpp"
+
+#include <iostream>
+
+using namespace orcus;
+
+int main(int argc, char** argv) try
+{
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory fact(doc);
+ orcus_gnumeric app(&fact);
+
+ if (!parse_import_filter_args(argc, argv, fact, app, doc))
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
+catch (const std::exception& e)
+{
+ std::cerr << e.what() << std::endl;
+ return EXIT_FAILURE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_json_cli.cpp b/src/orcus_json_cli.cpp
new file mode 100644
index 0000000..98a4f39
--- /dev/null
+++ b/src/orcus_json_cli.cpp
@@ -0,0 +1,443 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus_json_cli.hpp"
+#include "orcus/json_document_tree.hpp"
+#include "orcus/json_parser_base.hpp"
+#include "orcus/json_structure_tree.hpp"
+#include "orcus/config.hpp"
+#include "orcus/stream.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/dom_tree.hpp"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <memory>
+#include <sstream>
+
+#include <mdds/sorted_string_map.hpp>
+#include <boost/program_options.hpp>
+
+#include "filesystem_env.hpp"
+
+using namespace std;
+using namespace orcus;
+namespace po = boost::program_options;
+
+namespace orcus { namespace detail {
+
+cmd_params::cmd_params() {}
+
+cmd_params::cmd_params(cmd_params&& other) :
+ config(std::move(other.config)),
+ os(std::move(other.os)),
+ mode(other.mode),
+ map_file(std::move(other.map_file))
+{
+}
+
+cmd_params::~cmd_params() {}
+
+}}
+
+namespace {
+
+namespace mode {
+
+using map_type = mdds::sorted_string_map<detail::mode_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] =
+{
+ { "convert", detail::mode_t::convert },
+ { "map", detail::mode_t::map },
+ { "map-gen", detail::mode_t::map_gen },
+ { "structure", detail::mode_t::structure },
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), detail::mode_t::unknown);
+ return mt;
+}
+
+} // namespace mode
+
+const char* help_program =
+"The FILE must specify the path to an existing file.";
+
+const char* help_json_output =
+"Output file path.";
+
+const char* help_json_output_format =
+"Specify the format of output file. Supported format types are:\n"
+"\n"
+" * XML (xml)\n"
+" * JSON (json)\n"
+" * YAML (yaml)\n"
+" * flat tree dump (check)\n"
+" * no output (none)";
+
+const char* help_json_map =
+"Path to a map file. This parameter is only used for map mode, and it is "
+"required for map mode."
+;
+
+const char* err_no_input_file = "No input file.";
+
+void print_json_usage(std::ostream& os, const po::options_description& desc)
+{
+ os << "Usage: orcus-json [options] FILE" << endl << endl;
+ os << help_program << endl << endl << desc;
+}
+
+std::string build_mode_help_text()
+{
+ std::ostringstream os;
+ os << "Mode of operation. Select one of the following options: ";
+ auto it = mode::entries, ite = mode::entries + std::size(mode::entries);
+ --ite;
+
+ for (; it != ite; ++it)
+ os << it->key << ", ";
+
+ os << "or " << it->key << ".";
+ return os.str();
+}
+
+/**
+ * Reset params.config in case of failure.
+ */
+void parse_args_for_convert(
+ detail::cmd_params& params, const po::options_description& desc, const po::variables_map& vm)
+{
+ if (vm.count("resolve-refs"))
+ params.config->resolve_references = true;
+
+ if (vm.count("output-format"))
+ {
+ std::string s = vm["output-format"].as<string>();
+ params.config->output_format = to_dump_format_enum(s);
+
+ if (params.config->output_format == dump_format_t::unknown)
+ {
+ cerr << "Unknown output format type '" << s << "'." << endl;
+ params.config.reset();
+ return;
+ }
+ }
+ else
+ {
+ cerr << "Output format is not specified." << endl;
+ print_json_usage(cerr, desc);
+ params.config.reset();
+ return;
+ }
+}
+
+/**
+ * Reset params.config in case of failure.
+ */
+void parse_args_for_map(
+ detail::cmd_params& params, const po::options_description& desc, const po::variables_map& vm)
+{
+ if (vm.count("map"))
+ {
+ fs::path map_path = vm["map"].as<std::string>();
+ if (!fs::is_regular_file(map_path))
+ {
+ cerr << map_path.string() << " is not a valid file." << endl;
+ params.config.reset();
+ return;
+ }
+
+ params.map_file.load(map_path.string().data());
+ }
+ else
+ {
+ // Auto-mapping mode
+ }
+
+ parse_args_for_convert(params, desc, vm);
+}
+
+/**
+ * Parse the command-line options, populate the json_config object, and
+ * return that to the caller.
+ */
+detail::cmd_params parse_json_args(int argc, char** argv)
+{
+ detail::cmd_params params;
+
+ po::options_description desc("Options");
+ desc.add_options()
+ ("help,h", "Print this help.")
+ ("mode", po::value<std::string>(), build_mode_help_text().data())
+ ("resolve-refs", "Resolve JSON references to external files.")
+ ("output,o", po::value<string>(), help_json_output)
+ ("output-format,f", po::value<string>(), help_json_output_format)
+ ("map,m", po::value<string>(), help_json_map)
+ ;
+
+ po::options_description hidden("Hidden options");
+ hidden.add_options()
+ ("input", po::value<string>(), "input file");
+
+ po::options_description cmd_opt;
+ cmd_opt.add(desc).add(hidden);
+
+ po::positional_options_description po_desc;
+ po_desc.add("input", -1);
+
+ po::variables_map vm;
+ try
+ {
+ po::store(
+ po::command_line_parser(argc, argv).options(cmd_opt).positional(po_desc).run(), vm);
+ po::notify(vm);
+ }
+ catch (const exception& e)
+ {
+ // Unknown options.
+ cerr << e.what() << endl;
+ print_json_usage(cerr, desc);
+ return params;
+ }
+
+ if (vm.count("help"))
+ {
+ print_json_usage(cout, desc);
+ return params;
+ }
+
+ if (vm.count("mode"))
+ {
+ std::string s = vm["mode"].as<std::string>();
+ params.mode = mode::get().find(s);
+ if (params.mode == detail::mode_t::unknown)
+ {
+ cerr << "Unknown mode string '" << s << "'." << endl;
+ return params;
+ }
+ }
+
+ params.config = std::make_unique<json_config>();
+
+ if (vm.count("input"))
+ params.config->input_path = vm["input"].as<string>();
+
+ if (params.config->input_path.empty())
+ {
+ // No input file is given.
+ cerr << err_no_input_file << endl;
+ print_json_usage(cerr, desc);
+ params.config.reset();
+ return params;
+ }
+
+ if (!fs::exists(params.config->input_path))
+ {
+ cerr << "Input file does not exist: " << params.config->input_path << endl;
+ params.config.reset();
+ return params;
+ }
+
+ if (vm.count("output"))
+ params.config->output_path = vm["output"].as<string>();
+
+ switch (params.mode)
+ {
+ case detail::mode_t::map_gen:
+ case detail::mode_t::structure:
+ // Structure and map-gen modes only need input and output parameters.
+ params.os = std::make_unique<output_stream>(vm);
+ break;
+ case detail::mode_t::convert:
+ params.os = std::make_unique<output_stream>(vm);
+ parse_args_for_convert(params, desc, vm);
+ break;
+ case detail::mode_t::map:
+ parse_args_for_map(params, desc, vm);
+ break;
+ default:
+ assert(!"This should not happen since the mode check is done way earlier.");
+ }
+
+ return params;
+}
+
+std::unique_ptr<json::document_tree> load_doc(const orcus::file_content& content, const json_config& config)
+{
+ std::unique_ptr<json::document_tree> doc(std::make_unique<json::document_tree>());
+ doc->load(content.str(), config);
+ return doc;
+}
+
+void build_doc_and_dump(const orcus::file_content& content, detail::cmd_params& params)
+{
+ std::unique_ptr<json::document_tree> doc = load_doc(content, *params.config);
+ std::ostream& os = params.os->get();
+
+ switch (params.config->output_format)
+ {
+ case dump_format_t::xml:
+ {
+ os << doc->dump_xml();
+ break;
+ }
+ case dump_format_t::json:
+ {
+ os << doc->dump();
+ break;
+ }
+ case dump_format_t::yaml:
+ {
+ os << doc->dump_yaml();
+ break;
+ }
+ case dump_format_t::check:
+ {
+ string xml_strm = doc->dump_xml();
+ xmlns_repository repo;
+ xmlns_context ns_cxt = repo.create_context();
+ dom::document_tree dom(ns_cxt);
+ dom.load(xml_strm);
+
+ dom.dump_compact(os);
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+void parse_and_write_map_file(const orcus::file_content& content, detail::cmd_params& params)
+{
+ std::vector<json::table_range_t> ranges;
+
+ json::structure_tree::range_handler_type rh = [&ranges](json::table_range_t&& range)
+ {
+ ranges.push_back(std::move(range));
+ };
+
+ json::structure_tree tree;
+ tree.parse(content.str());
+
+ tree.process_ranges(rh);
+
+ json::document_tree map_doc = {
+ {"sheets", json::array()},
+ {"ranges", json::array()}
+ };
+
+ json::node root = map_doc.get_document_root();
+ json::node sheets_node = root["sheets"];
+ json::node ranges_node = root["ranges"];
+
+ size_t range_count = 0;
+ for (const json::table_range_t& range : ranges)
+ {
+ std::ostringstream os;
+ os << "range-" << range_count++;
+ std::string sheet = os.str();
+ sheets_node.push_back(sheet);
+
+ ranges_node.push_back({
+ {"sheet", sheet},
+ {"row", 0},
+ {"column", 0},
+ {"row-header", true},
+ {"fields", json::array()},
+ {"row-groups", json::array()},
+ });
+
+ json::node range_node = ranges_node.back();
+ json::node fields_node = range_node["fields"];
+ json::node row_groups_node = range_node["row-groups"];
+
+ for (const std::string& path : range.paths)
+ {
+ fields_node.push_back(json::object());
+ json::node path_node = fields_node.back();
+ path_node["path"] = path;
+ }
+
+ for (const std::string& row_group : range.row_groups)
+ {
+ row_groups_node.push_back(json::object());
+ json::node path_node = row_groups_node.back();
+ path_node["path"] = row_group;
+ }
+ }
+
+ std::ostream& os = params.os->get();
+ os << map_doc.dump();
+}
+
+} // anonymous namespace
+
+int main(int argc, char** argv)
+{
+ file_content content;
+
+ try
+ {
+ detail::cmd_params params = parse_json_args(argc, argv);
+
+ if (!params.config || params.mode == detail::mode_t::unknown)
+ return EXIT_FAILURE;
+
+ assert(!params.config->input_path.empty());
+ content.load(params.config->input_path.data());
+
+ switch (params.mode)
+ {
+ case detail::mode_t::structure:
+ {
+ json::structure_tree tree;
+ tree.parse(content.str());
+ tree.normalize_tree();
+ tree.dump_compact(params.os->get());
+ break;
+ }
+ case detail::mode_t::map:
+ {
+ map_to_sheets_and_dump(content, params);
+ break;
+ }
+ case detail::mode_t::map_gen:
+ {
+ parse_and_write_map_file(content, params);
+ break;
+ }
+ case detail::mode_t::convert:
+ {
+ build_doc_and_dump(content, params);
+ break;
+ }
+ default:
+ cerr << "Unkonwn mode has been given." << endl;
+ return EXIT_FAILURE;
+ }
+ }
+ catch (const parse_error& e)
+ {
+ cerr << create_parse_error_output(content.str(), e.offset()) << endl;
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception& e)
+ {
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_json_cli.hpp b/src/orcus_json_cli.hpp
new file mode 100644
index 0000000..2f8db9f
--- /dev/null
+++ b/src/orcus_json_cli.hpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_ORCUS_JSON_CLI_HPP
+#define INCLUDED_ORCUS_ORCUS_JSON_CLI_HPP
+
+#include "orcus/stream.hpp"
+#include "cli_global.hpp"
+
+#include <ostream>
+
+namespace orcus {
+
+struct json_config;
+
+namespace detail {
+
+enum class mode_t
+{
+ unknown,
+ convert,
+ map,
+ map_gen,
+ structure
+};
+
+struct cmd_params
+{
+ std::unique_ptr<json_config> config; //< json parser configuration.
+ std::unique_ptr<output_stream> os;
+ mode_t mode = mode_t::convert;
+ file_content map_file;
+
+ cmd_params(const cmd_params&) = delete;
+ cmd_params& operator= (const cmd_params&) = delete;
+
+ cmd_params();
+ cmd_params(cmd_params&& other);
+ ~cmd_params();
+};
+
+void map_to_sheets_and_dump(const file_content& content, cmd_params& params);
+
+}
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_json_cli_map.cpp b/src/orcus_json_cli_map.cpp
new file mode 100644
index 0000000..563b7e3
--- /dev/null
+++ b/src/orcus_json_cli_map.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus_json_cli.hpp"
+#include "orcus/config.hpp"
+
+#ifdef __ORCUS_SPREADSHEET_MODEL
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#include "orcus/orcus_json.hpp"
+#endif
+
+#include <iostream>
+#include <cassert>
+#include <vector>
+#include <sstream>
+
+using namespace std;
+
+namespace orcus { namespace detail {
+
+#ifdef __ORCUS_SPREADSHEET_MODEL
+
+void map_to_sheets_and_dump(const file_content& content, cmd_params& params)
+{
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory factory(doc);
+ orcus_json app(&factory);
+
+ if (params.map_file.empty())
+ // Automatic mapping of JSON to table.
+ app.detect_map_definition(content.str());
+ else
+ app.read_map_definition(params.map_file.str());
+
+ app.read_stream(content.str());
+ doc.dump(params.config->output_format, params.config->output_path);
+}
+
+#else
+
+void map_to_sheets_and_dump(const file_content& /*content*/, cmd_params& /*params*/)
+{
+ throw std::runtime_error(
+ "map mode disabled as the spreadsheet model backend is not available.");
+}
+
+#endif
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_mso_encryption.cpp b/src/orcus_mso_encryption.cpp
new file mode 100644
index 0000000..30eb4b3
--- /dev/null
+++ b/src/orcus_mso_encryption.cpp
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/stream.hpp>
+
+#include "mso/encryption_info.hpp"
+
+using namespace orcus;
+using namespace std;
+
+int main(int argc, char** argv) try
+{
+ if (argc != 2)
+ return EXIT_FAILURE;
+
+ mso::encryption_info_reader reader;
+ file_content content(argv[1]);
+
+ if (content.empty())
+ return EXIT_FAILURE;
+
+ reader.read(content.data(), content.size());
+
+ return EXIT_SUCCESS;
+}
+catch (...)
+{
+ return EXIT_FAILURE;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_ods_main.cpp b/src/orcus_ods_main.cpp
new file mode 100644
index 0000000..16c24f0
--- /dev/null
+++ b/src/orcus_ods_main.cpp
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_ods.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+
+#include "orcus_filter_global.hpp"
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace std;
+using namespace orcus;
+
+int main(int argc, char** argv) try
+{
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory fact(doc);
+ orcus_ods app(&fact);
+
+ if (!parse_import_filter_args(argc, argv, fact, app, doc))
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
+catch (const std::exception& e)
+{
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_ods_styles.cpp b/src/orcus_ods_styles.cpp
new file mode 100644
index 0000000..443d4ab
--- /dev/null
+++ b/src/orcus_ods_styles.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_import_ods.hpp"
+#include "orcus/spreadsheet/styles.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#include "orcus/string_pool.hpp"
+#include "orcus/stream.hpp"
+
+#include "orcus_filter_global.hpp"
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace std;
+using namespace orcus;
+
+int main(int argc, char** argv)
+{
+ if (argc != 2)
+ return EXIT_FAILURE;
+
+ string_pool sp;
+ spreadsheet::styles styles_store;
+ spreadsheet::import_styles istyles(styles_store, sp);
+
+ try
+ {
+ file_content content(argv[1]);
+ import_ods::read_styles(content.str(), &istyles);
+ }
+ catch(std::exception& ex)
+ {
+ std::cerr << ex.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_parquet_main.cpp b/src/orcus_parquet_main.cpp
new file mode 100644
index 0000000..a4730a0
--- /dev/null
+++ b/src/orcus_parquet_main.cpp
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_parquet.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+
+#include "orcus_filter_global.hpp"
+
+#include <iostream>
+
+int main(int argc, char** argv) try
+{
+ orcus::spreadsheet::range_size_t ss{1048576, 16384};
+ orcus::spreadsheet::document doc{ss};
+ orcus::spreadsheet::import_factory fact(doc);
+ orcus::orcus_parquet app(&fact);
+
+ if (!parse_import_filter_args(argc, argv, fact, app, doc))
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
+catch (const std::exception& e)
+{
+ std::cerr << e.what() << std::endl;
+ return EXIT_FAILURE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/orcus_test_csv.cpp b/src/orcus_test_csv.cpp
new file mode 100644
index 0000000..438f9a7
--- /dev/null
+++ b/src/orcus_test_csv.cpp
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus_test_global.hpp"
+#include "orcus/orcus_csv.hpp"
+#include <orcus/format_detection.hpp>
+#include "orcus/config.hpp"
+#include "orcus/stream.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/sheet.hpp"
+
+#include <cstdlib>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+using namespace orcus;
+namespace ss = orcus::spreadsheet;
+
+namespace {
+
+std::vector<const char*> dirs = {
+ SRCDIR"/test/csv/simple-numbers/",
+ SRCDIR"/test/csv/normal-quotes/",
+ SRCDIR"/test/csv/double-quotes/",
+ SRCDIR"/test/csv/quoted-with-delim/",
+};
+
+void test_csv_create_filter()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ ss::range_size_t ssize{1048576, 16384};
+ std::unique_ptr<ss::document> doc = std::make_unique<ss::document>(ssize);
+ ss::import_factory factory(*doc);
+
+ auto f = create_filter(format_t::csv, &factory);
+ assert(f);
+ assert(f->get_name() == "csv");
+}
+
+void test_csv_import()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ for (const char* dir : dirs)
+ {
+ std::string path(dir);
+
+ // Read the input.csv document.
+ path.append("input.csv");
+
+ std::cout << "checking " << path << "..." << std::endl;
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ {
+ spreadsheet::import_factory factory(doc);
+ orcus_csv app(&factory);
+ app.read_file(path.c_str());
+ }
+
+ // Dump the content of the model.
+ std::string check = test::get_content_check(doc);
+
+ // Check that against known control.
+ path = dir;
+ path.append("check.txt");
+ file_content control(path.c_str());
+
+ assert(!check.empty());
+ assert(!control.empty());
+
+ test::verify_content(__FILE__, __LINE__, control.str(), check);
+
+ // Dump the first sheet as csv.
+ std::string stream = test::get_content_as_csv(doc, 0);
+ assert(!stream.empty());
+
+ // Re-import the dumped csv.
+ doc.clear();
+ {
+ spreadsheet::import_factory factory(doc);
+ orcus_csv app(&factory);
+ app.read_stream(stream);
+ }
+
+ // Dump the content of the re-imported model, and make sure it's still
+ // identical to the control.
+ check = test::get_content_check(doc);
+ assert(!check.empty());
+
+ test::verify_content(__FILE__, __LINE__, control.str(), check);
+ }
+}
+
+void test_csv_import_split_sheet()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ const char* dir = SRCDIR"/test/csv/split-sheet/";
+
+ std::string path(dir);
+ path.append("input.csv");
+
+ std::cout << "checking " << path << "..." << std::endl;
+
+ config conf(format_t::csv);
+ std::get<config::csv_config>(conf.data).header_row_size = 0;
+ std::get<config::csv_config>(conf.data).split_to_multiple_sheets = true;
+
+ // Set the row size to 11 to make sure the split occurs.
+ spreadsheet::range_size_t ss{11, 4};
+ spreadsheet::document doc{ss};
+ {
+ spreadsheet::import_factory factory(doc);
+ orcus_csv app(&factory);
+ app.set_config(conf);
+
+ app.read_file(path.c_str());
+ }
+
+ assert(doc.get_sheet_count() == 2);
+
+ // Dump the content of the model.
+ std::string check = test::get_content_check(doc);
+
+ // Check that against known control.
+ path = dir;
+ path.append("check-1.txt");
+ file_content control(path.data());
+
+ test::verify_content(__FILE__, __LINE__, control.str(), check);
+
+ // Re-import the same input file, but have the first row repeated on every
+ // sheet.
+ path = dir;
+ path.append("input.csv");
+ doc.clear();
+ std::get<config::csv_config>(conf.data).header_row_size = 1;
+ {
+ spreadsheet::import_factory factory(doc);
+ orcus_csv app(&factory);
+ app.set_config(conf);
+
+ app.read_file(path.c_str());
+ }
+
+ assert(doc.get_sheet_count() == 2);
+
+ // Dump the content of the model.
+ check = test::get_content_check(doc);
+
+ // Check that against known control.
+ path = dir;
+ path.append("check-2.txt");
+ control.load(path.data());
+
+ test::verify_content(__FILE__, __LINE__, control.str(), check);
+
+ // Re-import it again, but this time disable the splitting. The data should
+ // get trucated on the first sheet.
+ std::get<config::csv_config>(conf.data).split_to_multiple_sheets = false;
+
+ path = dir;
+ path.append("input.csv");
+ doc.clear();
+
+ {
+ spreadsheet::import_factory factory(doc);
+ orcus_csv app(&factory);
+ app.set_config(conf);
+
+ app.read_file(path.c_str());
+ }
+
+ assert(doc.get_sheet_count() == 1);
+
+ // Dump the content of the model.
+ check = test::get_content_check(doc);
+
+ // Check that against known control.
+ path = dir;
+ path.append("check-3.txt");
+ control.load(path.data());
+
+ test::verify_content(__FILE__, __LINE__, control.str(), check);
+}
+
+void test_csv_dump_flat_utf8()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ constexpr std::string_view src =
+ "New York,fabriqué\n"
+ "garçon,вход\n"
+ "выход,помогите\n"
+ "Nähe,San Diego";
+
+ constexpr std::string_view expected =
+ "rows: 4 cols: 2\n"
+ "+----------+-----------+\n"
+ "| New York | fabriqué |\n"
+ "+----------+-----------+\n"
+ "| garçon | вход |\n"
+ "+----------+-----------+\n"
+ "| выход | помогите |\n"
+ "+----------+-----------+\n"
+ "| Nähe | San Diego |\n"
+ "+----------+-----------+\n";
+
+ ss::range_size_t ss{1048576, 16384};
+ ss::document doc{ss};
+ ss::import_factory factory(doc);
+ orcus_csv app(&factory);
+ app.read_stream(src);
+
+ const ss::sheet* sh = doc.get_sheet(0);
+ assert(sh);
+ std::ostringstream os;
+ sh->dump_flat(os);
+ std::string flat_dump = os.str();
+
+ test::verify_content(__FILE__, __LINE__, expected, flat_dump);
+}
+
+} // anonymous namespace
+
+int main()
+{
+ try
+ {
+ test_csv_create_filter();
+ test_csv_import();
+ test_csv_import_split_sheet();
+ test_csv_dump_flat_utf8();
+ }
+ catch (const std::exception& e)
+ {
+ std::cout << e.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_test_global.cpp b/src/orcus_test_global.cpp
new file mode 100644
index 0000000..78de0f2
--- /dev/null
+++ b/src/orcus_test_global.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus_test_global.hpp"
+
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/spreadsheet/sheet.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/parser_global.hpp>
+
+#include <sstream>
+#include <cmath>
+#include <iostream>
+#include <chrono>
+
+namespace orcus { namespace test {
+
+std::string get_content_check(const spreadsheet::document& doc)
+{
+ std::ostringstream os;
+ doc.dump_check(os);
+ return os.str();
+}
+
+std::string get_content_as_csv(const spreadsheet::document& doc, spreadsheet::sheet_t sheet_index)
+{
+ const spreadsheet::sheet* sh = doc.get_sheet(sheet_index);
+ if (!sh)
+ return std::string();
+
+ std::ostringstream os;
+ sh->dump_csv(os);
+ return os.str();
+}
+
+void verify_content(
+ const char* filename, size_t line_no, const spreadsheet::document& doc, std::string_view expected)
+{
+ std::string actual = get_content_check(doc);
+ verify_content(filename, line_no, expected, actual);
+}
+
+void verify_value_to_decimals(
+ const char* filename, size_t line_no, double expected, double actual, int decimals)
+{
+ double expected_f = expected;
+ double actual_f = actual;
+
+ for (int i = 0; i < decimals; ++i)
+ {
+ expected_f *= 10.0;
+ actual_f *= 10.0;
+ }
+
+ long expected_i = std::lround(expected_f);
+ long actual_i = std::lround(actual_f);
+
+ if (expected_i == actual_i)
+ return;
+
+ std::ostringstream os;
+ os << "value is not as expected: (expected: " << expected << "; actual: " << actual << ")";
+ throw assert_error(filename, line_no, os.str().data());
+}
+
+std::string prefix_multiline_string(std::string_view str, std::string_view prefix)
+{
+ std::ostringstream os;
+
+ const char* p = str.data();
+ const char* p_end = p + str.size();
+
+ const char* p0 = nullptr;
+ for (; p != p_end; ++p)
+ {
+ if (!p0)
+ p0 = p;
+
+ if (*p == '\n')
+ {
+ os << prefix << std::string_view(p0, std::distance(p0, p)) << '\n';
+ p0 = nullptr;
+ }
+ }
+
+ if (p0)
+ os << prefix << std::string_view(p0, std::distance(p0, p));
+
+ return os.str();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_test_global.hpp b/src/orcus_test_global.hpp
new file mode 100644
index 0000000..dc3e314
--- /dev/null
+++ b/src/orcus_test_global.hpp
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_ORCUS_TEST_GLOBAL_HPP
+#define INCLUDED_ORCUS_ORCUS_TEST_GLOBAL_HPP
+
+#include "test_global.hpp"
+#include <orcus/spreadsheet/types.hpp>
+
+#include <string>
+
+namespace orcus {
+
+namespace spreadsheet {
+
+class document;
+
+}
+
+namespace test {
+
+std::string get_content_check(const spreadsheet::document& doc);
+
+std::string get_content_as_csv(const spreadsheet::document& doc, spreadsheet::sheet_t sheet_index);
+
+void verify_content(
+ const char* filename, size_t line_no, const spreadsheet::document& doc, std::string_view expected);
+
+void verify_value_to_decimals(
+ const char* filename, size_t line_no, double expected, double actual, int decimals);
+
+std::string prefix_multiline_string(std::string_view str, std::string_view prefix);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_test_gnumeric.cpp b/src/orcus_test_gnumeric.cpp
new file mode 100644
index 0000000..f2ba3b6
--- /dev/null
+++ b/src/orcus_test_gnumeric.cpp
@@ -0,0 +1,1386 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus_test_global.hpp"
+#include "filesystem_env.hpp"
+
+#include <orcus/orcus_gnumeric.hpp>
+#include <orcus/format_detection.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/spreadsheet/factory.hpp>
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/spreadsheet/sheet.hpp>
+#include <orcus/spreadsheet/auto_filter.hpp>
+#include <orcus/spreadsheet/shared_strings.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+#include <orcus/types.hpp>
+
+#include <ixion/address.hpp>
+#include <ixion/model_context.hpp>
+#include <iostream>
+#include <sstream>
+
+using namespace orcus;
+namespace ss = orcus::spreadsheet;
+
+namespace {
+
+std::vector<fs::path> dirs = {
+ SRCDIR"/test/gnumeric/raw-values-1/",
+ SRCDIR"/test/gnumeric/cell-value-types/",
+ SRCDIR"/test/gnumeric/formula-cells/",
+ SRCDIR"/test/gnumeric/named-expression/",
+ SRCDIR"/test/gnumeric/named-expression-sheet-local/",
+};
+
+std::unique_ptr<ss::document> load_doc(const fs::path& filepath)
+{
+ ss::range_size_t ss{1048576, 16384};
+ auto doc = std::make_unique<ss::document>(ss);
+ ss::import_factory factory(*doc);
+ orcus_gnumeric app(&factory);
+ app.read_file(filepath.string());
+
+ // Gnumeric doc doesn't cache formula results.
+ doc->recalc_formula_cells();
+
+ return doc;
+}
+
+void test_gnumeric_detection()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ for (const auto& dir : dirs)
+ {
+ fs::path filepath = dir / "input.gnumeric";
+ file_content fc(filepath.string());
+ assert(!fc.empty());
+
+ format_t detected = detect(fc.str());
+ assert(detected == format_t::gnumeric);
+ }
+}
+
+void test_gnumeric_create_filter()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ ss::range_size_t ssize{1048576, 16384};
+ std::unique_ptr<ss::document> doc = std::make_unique<ss::document>(ssize);
+ ss::import_factory factory(*doc);
+
+ auto f = create_filter(format_t::gnumeric, &factory);
+ assert(f);
+ assert(f->get_name() == "gnumeric");
+}
+
+void test_gnumeric_import()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ for (const auto& dir : dirs)
+ {
+ std::cout << "checking " << dir << "..." << std::endl;
+
+ // Read the input.gnumeric document.
+ fs::path filepath = dir / "input.gnumeric";
+ auto doc = load_doc(filepath);
+
+ // Dump the content of the model.
+ std::ostringstream os;
+ doc->dump_check(os);
+ std::string check = os.str();
+
+ // Check that against known control.
+ filepath = dir / "check.txt";
+ file_content control(filepath.string());
+
+ assert(!check.empty());
+ assert(!control.empty());
+
+ test::verify_content(__FILE__, __LINE__, control.str(), check);
+ }
+}
+
+void test_gnumeric_column_widths_row_heights()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/column-width-row-height/input.gnumeric";
+ auto doc = load_doc(filepath);
+
+ assert(doc->get_sheet_count() == 1);
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ {
+ // column, column width (twips), column span
+ const std::tuple<ss::col_t, ss::col_width_t, ss::col_t> expected[] = {
+ { 0, 99 * 20, 1 },
+ { 1, 57 * 20, 1 },
+ { 2, 84 * 20, 1 },
+ { 3, 111 * 20, 1 },
+ { 4, ss::get_default_column_width(), 1 },
+ { 5, 69 * 20, 3 },
+ { 10, 120 * 20, 2 },
+ };
+
+ for (const auto& [col, cw_expected, span_expected] : expected)
+ {
+ ss::col_t col_start, col_end;
+ ss::col_width_t cw = sh->get_col_width(col, &col_start, &col_end);
+ ss::col_t span = col_end - col_start;
+
+ std::cout << "column: " << col << "; expected=" << cw_expected << "; actual=" << cw
+ << "; span-expected=" << span_expected << "; span-actual=" << span << std::endl;
+
+ assert(cw == cw_expected);
+ assert(span == span_expected);
+ }
+ }
+
+ {
+ // row, row height (twips), row span
+ const std::tuple<ss::row_t, ss::row_height_t, ss::row_t> expected[] = {
+ { 0, 18 * 20, 3 },
+ { 3, 30 * 20, 1 },
+ { 4, 42 * 20, 1 },
+ { 5, 51 * 20, 1 },
+ { 6, ss::get_default_row_height(), 1 },
+ { 7, 27 * 20, 3 },
+ { 10, ss::get_default_row_height(), 2 },
+ { 12, 36 * 20, 2 },
+ };
+
+ for (const auto& [row, rh_expected, span_expected] : expected)
+ {
+ ss::row_t row_start, row_end;
+ ss::row_height_t rh = sh->get_row_height(row, &row_start, &row_end);
+ ss::row_t span = row_end - row_start;
+
+ std::cout << "row: " << row << "; expected=" << rh_expected << "; actual=" << rh
+ << "; span-expected=" << span_expected << "; span-actual=" << span << std::endl;
+
+ assert(rh == rh_expected);
+ assert(span == span_expected);
+ }
+ }
+}
+
+void test_gnumeric_auto_filter()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/table/autofilter.gnumeric";
+ auto doc = load_doc(filepath);
+
+ assert(doc->get_sheet_count() == 1);
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ const ss::auto_filter_t* af = sh->get_auto_filter_data();
+ assert(af);
+ ixion::abs_range_t b2_c11{0, 1, 1, 10, 2};
+ assert(af->range == b2_c11);
+ assert(af->columns.size() == 2);
+
+ auto it = af->columns.begin();
+ assert(it->first == 0);
+ {
+ const ss::auto_filter_column_t& afc = it->second;
+ assert(afc.match_values.size() == 1);
+ assert(*afc.match_values.begin() == "A");
+ }
+
+ ++it;
+ assert(it->first == 1);
+ {
+ const ss::auto_filter_column_t& afc = it->second;
+ assert(afc.match_values.size() == 1);
+ assert(*afc.match_values.begin() == "1");
+ }
+}
+
+void test_gnumeric_hidden_rows_columns()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/hidden-rows-columns/input.gnumeric";
+ auto doc = load_doc(filepath);
+
+ ss::sheet* sh = doc->get_sheet("Hidden Rows");
+ assert(sh);
+
+ ss::row_t row_start = -1, row_end = -1;
+
+ // Row 1 is visible.
+ assert(!sh->is_row_hidden(0, &row_start, &row_end));
+ assert(row_start == 0);
+ assert(row_end == 1); // the end position is non-inclusive.
+
+ // Rows 2-3 are hidden.
+ assert(sh->is_row_hidden(1, &row_start, &row_end));
+ assert(row_start == 1);
+ assert(row_end == 3); // the end position is non-inclusive.
+
+ // Row 4 is visible.
+ assert(!sh->is_row_hidden(3, &row_start, &row_end));
+ assert(row_start == 3);
+ assert(row_end == 4); // the end position is non-inclusive.
+
+ // Row 5 is hidden.
+ assert(sh->is_row_hidden(4, &row_start, &row_end));
+ assert(row_start == 4);
+ assert(row_end == 5); // the end position is non-inclusive.
+
+ // Rows 6-8 are visible.
+ assert(!sh->is_row_hidden(5, &row_start, &row_end));
+ assert(row_start == 5);
+ assert(row_end == 8); // the end position is non-inclusive.
+
+ // Row 9 is hidden.
+ assert(sh->is_row_hidden(8, &row_start, &row_end));
+ assert(row_start == 8);
+ assert(row_end == 9); // the end position is non-inclusive.
+
+ // The rest of the rows are visible.
+ assert(!sh->is_row_hidden(9, &row_start, &row_end));
+ assert(row_start == 9);
+ assert(row_end == doc->get_sheet_size().rows); // the end position is non-inclusive.
+
+ sh = doc->get_sheet("Hidden Columns");
+ assert(sh);
+
+ ss::col_t col_start = -1, col_end = -1;
+
+ // Columns A-B are visible.
+ assert(!sh->is_col_hidden(0, &col_start, &col_end));
+ assert(col_start == 0);
+ assert(col_end == 2); // non-inclusive
+
+ // Columns C-E are hidden.
+ assert(sh->is_col_hidden(2, &col_start, &col_end));
+ assert(col_start == 2);
+ assert(col_end == 6); // non-inclusive
+
+ // Columns G-J are visible.
+ assert(!sh->is_col_hidden(6, &col_start, &col_end));
+ assert(col_start == 6);
+ assert(col_end == 10); // non-inclusive
+
+ // Column K is hidden.
+ assert(sh->is_col_hidden(10, &col_start, &col_end));
+ assert(col_start == 10);
+ assert(col_end == 11); // non-inclusive
+
+ // The rest of the columns are all visible.
+ assert(!sh->is_col_hidden(11, &col_start, &col_end));
+ assert(col_start == 11);
+ assert(col_end == doc->get_sheet_size().columns); // non-inclusive
+}
+
+void test_gnumeric_merged_cells()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/merged-cells/input.gnumeric";
+ auto doc = load_doc(filepath);
+
+ const ss::sheet* sheet1 = doc->get_sheet("Sheet1");
+ assert(sheet1);
+
+ ss::range_t merge_range = sheet1->get_merge_cell_range(0, 1);
+ assert(merge_range.first.column == 1);
+ assert(merge_range.last.column == 2);
+ assert(merge_range.first.row == 0);
+ assert(merge_range.last.row == 0);
+
+ merge_range = sheet1->get_merge_cell_range(0, 3);
+ assert(merge_range.first.column == 3);
+ assert(merge_range.last.column == 5);
+ assert(merge_range.first.row == 0);
+ assert(merge_range.last.row == 0);
+
+ merge_range = sheet1->get_merge_cell_range(1, 0);
+ assert(merge_range.first.column == 0);
+ assert(merge_range.last.column == 0);
+ assert(merge_range.first.row == 1);
+ assert(merge_range.last.row == 2);
+
+ merge_range = sheet1->get_merge_cell_range(3, 0);
+ assert(merge_range.first.column == 0);
+ assert(merge_range.last.column == 0);
+ assert(merge_range.first.row == 3);
+ assert(merge_range.last.row == 5);
+
+ merge_range = sheet1->get_merge_cell_range(2, 2);
+ assert(merge_range.first.column == 2);
+ assert(merge_range.last.column == 5);
+ assert(merge_range.first.row == 2);
+ assert(merge_range.last.row == 5);
+}
+
+void test_gnumeric_text_alignment()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/text-alignment/input.gnumeric";
+ auto doc = load_doc(filepath);
+
+ ss::styles& styles = doc->get_styles();
+
+ ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ ss::row_t row;
+ ss::col_t col;
+ bool apply_align;
+ ss::hor_alignment_t hor_align;
+ ss::ver_alignment_t ver_align;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 2, true, ss::hor_alignment_t::unknown, ss::ver_alignment_t::bottom }, // C2
+ { 2, 2, true, ss::hor_alignment_t::left, ss::ver_alignment_t::bottom }, // C3
+ { 3, 2, true, ss::hor_alignment_t::center, ss::ver_alignment_t::bottom }, // C4
+ { 4, 2, true, ss::hor_alignment_t::right, ss::ver_alignment_t::bottom }, // C5
+ { 5, 2, true, ss::hor_alignment_t::left, ss::ver_alignment_t::bottom }, // C6
+ { 6, 2, true, ss::hor_alignment_t::left, ss::ver_alignment_t::bottom }, // C7
+ { 7, 2, true, ss::hor_alignment_t::right, ss::ver_alignment_t::bottom }, // C8
+ { 8, 2, true, ss::hor_alignment_t::right, ss::ver_alignment_t::bottom }, // C9
+ { 9, 2, true, ss::hor_alignment_t::unknown, ss::ver_alignment_t::middle }, // C10
+ { 10, 2, true, ss::hor_alignment_t::left, ss::ver_alignment_t::middle }, // C11
+ { 11, 2, true, ss::hor_alignment_t::center, ss::ver_alignment_t::middle }, // C12
+ { 12, 2, true, ss::hor_alignment_t::right, ss::ver_alignment_t::middle }, // C13
+ { 13, 2, true, ss::hor_alignment_t::left, ss::ver_alignment_t::middle }, // C14
+ { 14, 2, true, ss::hor_alignment_t::left, ss::ver_alignment_t::middle }, // C15
+ { 15, 2, true, ss::hor_alignment_t::right, ss::ver_alignment_t::middle }, // C16
+ { 16, 2, true, ss::hor_alignment_t::right, ss::ver_alignment_t::middle }, // C17
+ { 17, 2, true, ss::hor_alignment_t::unknown, ss::ver_alignment_t::top }, // C18
+ { 18, 2, true, ss::hor_alignment_t::left, ss::ver_alignment_t::top }, // C19
+ { 19, 2, true, ss::hor_alignment_t::center, ss::ver_alignment_t::top }, // C20
+ { 20, 2, true, ss::hor_alignment_t::right, ss::ver_alignment_t::top }, // C21
+ { 21, 2, true, ss::hor_alignment_t::left, ss::ver_alignment_t::top }, // C22
+ { 22, 2, true, ss::hor_alignment_t::left, ss::ver_alignment_t::top }, // C23
+ { 23, 2, true, ss::hor_alignment_t::right, ss::ver_alignment_t::top }, // C24
+ { 24, 2, true, ss::hor_alignment_t::right, ss::ver_alignment_t::top }, // C25
+ { 25, 2, true, ss::hor_alignment_t::unknown, ss::ver_alignment_t::justified }, // C26
+ { 26, 2, true, ss::hor_alignment_t::justified, ss::ver_alignment_t::bottom }, // C27
+ { 27, 2, true, ss::hor_alignment_t::distributed, ss::ver_alignment_t::distributed }, // C28
+ };
+
+ for (const check& c : checks)
+ {
+ std::cout << "row=" << c.row << "; col=" << c.col << std::endl;
+ size_t xf = sh->get_cell_format(c.row, c.col);
+
+ const ss::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(c.apply_align == cf->apply_alignment);
+
+ if (!cf->apply_alignment)
+ continue;
+
+ assert(c.hor_align == cf->hor_align);
+ assert(c.ver_align == cf->ver_align);
+ }
+}
+
+void test_gnumeric_cell_properties_wrap_and_shrink()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ // NB : Gnumeric doesn't appear to support shrink-to-fit, so we only check
+ // wrap-text for now. When Gnumeric supports shrink-to-fit, re-generate the
+ // test file from test/xls-xml/cell-properties/wrap-and-shrink.xml.
+
+ fs::path filepath = SRCDIR"/test/gnumeric/cell-properties/wrap-and-shrink.gnumeric";
+ auto doc = load_doc(filepath);
+
+ const ss::styles& styles = doc->get_styles();
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ std::size_t xfid = sh->get_cell_format(0, 1); // B1
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->wrap_text);
+ assert(!*xf->wrap_text);
+// assert(xf->shrink_to_fit);
+// assert(!*xf->shrink_to_fit);
+
+ xfid = sh->get_cell_format(1, 1); // B2
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->wrap_text);
+ assert(*xf->wrap_text);
+// assert(xf->shrink_to_fit);
+// assert(!*xf->shrink_to_fit);
+
+ xfid = sh->get_cell_format(2, 1); // B3
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->wrap_text);
+ assert(!*xf->wrap_text);
+// assert(xf->shrink_to_fit);
+// assert(*xf->shrink_to_fit);
+}
+
+void test_gnumeric_background_fill()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/background-color/standard.gnumeric";
+ auto doc = load_doc(filepath);
+
+ ss::styles& styles = doc->get_styles();
+
+ ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ ss::row_t row;
+ ss::col_t col;
+ ss::fill_pattern_t pattern_type;
+ ss::color_t fg_color;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 0, ss::fill_pattern_t::solid, { 255, 192, 0, 0 } }, // A2 - dark red
+ { 2, 0, ss::fill_pattern_t::solid, { 255, 255, 0, 0 } }, // A3 - red
+ { 3, 0, ss::fill_pattern_t::solid, { 255, 255, 192, 0 } }, // A4 - orange
+ { 4, 0, ss::fill_pattern_t::solid, { 255, 255, 255, 0 } }, // A5 - yellow
+ { 5, 0, ss::fill_pattern_t::solid, { 255, 146, 208, 80 } }, // A6 - light green
+ { 6, 0, ss::fill_pattern_t::solid, { 255, 0, 176, 80 } }, // A7 - green
+ { 7, 0, ss::fill_pattern_t::solid, { 255, 0, 176, 240 } }, // A8 - light blue
+ { 8, 0, ss::fill_pattern_t::solid, { 255, 0, 112, 192 } }, // A9 - blue
+ { 9, 0, ss::fill_pattern_t::solid, { 255, 0, 32, 96 } }, // A10 - dark blue
+ { 10, 0, ss::fill_pattern_t::solid, { 255, 112, 48, 160 } }, // A11 - purple
+ };
+
+ ss::color_t color_white(255, 255, 255, 255);
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+
+ const ss::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+
+ const ss::fill_t* fill_data = styles.get_fill(cf->fill);
+ assert(fill_data);
+ assert(fill_data->pattern_type == c.pattern_type);
+ assert(fill_data->fg_color == c.fg_color);
+
+ // The font colors are all white in the colored cells.
+ const ss::font_t* font_data = styles.get_font(cf->font);
+ assert(font_data);
+
+ assert(font_data->color == color_white);
+ }
+}
+
+void test_gnumeric_colored_text()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/colored-text/input.gnumeric";
+ auto doc = load_doc(filepath);
+
+ const ss::sheet* sheet1 = doc->get_sheet("ColoredText");
+ assert(sheet1);
+
+ const ss::shared_strings& ss = doc->get_shared_strings();
+
+ const ss::styles& styles = doc->get_styles();
+
+ // Column A contains colored cells.
+
+ struct check
+ {
+ ss::row_t row;
+ ss::color_elem_t red;
+ ss::color_elem_t green;
+ ss::color_elem_t blue;
+ std::string text;
+ };
+
+ std::vector<check> checks = {
+ { 1, 0xC0, 0x00, 0x00, "Dark Red" },
+ { 2, 0xFF, 0x00, 0x00, "Red" },
+ { 3, 0xFF, 0xC0, 0x00, "Orange" },
+ { 4, 0xFF, 0xFF, 0x00, "Yellow" },
+ { 5, 0x92, 0xD0, 0x50, "Light Green" },
+ { 6, 0x00, 0xB0, 0x50, "Green" },
+ { 7, 0x00, 0xB0, 0xF0, "Light Blue" },
+ { 8, 0x00, 0x70, 0xC0, "Blue" },
+ { 9, 0x00, 0x20, 0x60, "Dark Blue" },
+ { 10, 0x70, 0x30, 0xA0, "Purple" },
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xfi = sheet1->get_cell_format(c.row, 0);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfi);
+ assert(xf);
+
+ const ss::font_t* font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->color);
+ assert(font->color.value().red == c.red);
+ assert(font->color.value().green == c.green);
+ assert(font->color.value().blue == c.blue);
+
+ size_t si = sheet1->get_string_identifier(c.row, 0);
+ const std::string* s = ss.get_string(si);
+ assert(s);
+ assert(*s == c.text);
+ }
+
+ {
+ // Cell B2 contains mix-colored text.
+ size_t si = sheet1->get_string_identifier(1, 1);
+ const std::string* s = ss.get_string(si);
+ assert(s);
+ assert(*s == "Red and Blue");
+ const spreadsheet::format_runs_t* fmt_runs = ss.get_format_runs(si);
+ assert(fmt_runs);
+
+ // There should be 2 segments that are color-formatted.
+ assert(fmt_runs->size() == 2);
+
+ // The 'Red' segment should be in red color.
+ const spreadsheet::format_run* fmt = &fmt_runs->at(0);
+ assert(fmt->color.alpha == 0xFF);
+ assert(fmt->color.red == 0xFF);
+ assert(fmt->color.green == 0);
+ assert(fmt->color.blue == 0);
+ assert(fmt->pos == 0);
+ assert(fmt->size == 3);
+
+ // The 'Blue' segment should be in blue color.
+ fmt = &fmt_runs->at(1);
+ assert(fmt->color.alpha == 0xFF);
+ assert(fmt->color.red == 0);
+ assert(fmt->color.green == 0x00);
+ assert(fmt->color.blue == 0xFF);
+ assert(fmt->pos == 8);
+ assert(fmt->size == 4);
+ }
+
+ {
+ // Cell B3 too
+ size_t si = sheet1->get_string_identifier(2, 1);
+ const std::string* s = ss.get_string(si);
+ assert(s);
+ assert(*s == "Green and Orange");
+ const spreadsheet::format_runs_t* fmt_runs = ss.get_format_runs(si);
+ assert(fmt_runs);
+
+ assert(fmt_runs->size() == 2);
+
+ // 'Green' segment
+ const spreadsheet::format_run* fmt = &fmt_runs->at(0);
+ assert(fmt->color.alpha == 0xFF);
+ assert(fmt->color.red == 0);
+ assert(fmt->color.green == 0xFF);
+ assert(fmt->color.blue == 0);
+ assert(fmt->pos == 0);
+ assert(fmt->size == 5);
+
+ // 'Orange' segment
+ fmt = &fmt_runs->at(1);
+ assert(fmt->color.alpha == 0xFF);
+ assert(fmt->color.red == 0xFF);
+ assert(fmt->color.green == 0x99);
+ assert(fmt->color.blue == 0);
+ assert(fmt->pos == 10);
+ assert(fmt->size == 6);
+ }
+}
+
+void test_gnumeric_text_formats()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/text-formats/input.gnumeric";
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ const auto& styles_pool = doc->get_styles();
+
+ auto get_font = [&styles_pool](const ss::sheet& sh, ss::row_t row, ss::col_t col)
+ {
+ std::size_t xf = sh.get_cell_format(row, col);
+
+ const ss::cell_format_t* cell_format = styles_pool.get_cell_format(xf);
+ assert(cell_format);
+
+ const ss::font_t* font = styles_pool.get_font(cell_format->font);
+ assert(font);
+
+ return font;
+ };
+
+ auto check_cell_bold = [&get_font](const ss::sheet& sh, ss::row_t row, ss::col_t col, bool expected)
+ {
+ const ss::font_t* font = get_font(sh, row, col);
+
+ if (expected)
+ {
+ if (font->bold && *font->bold)
+ return true;
+
+ std::cerr << "expected to be bold but it is not "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ else
+ {
+ if (!font->bold || !*font->bold)
+ return true;
+
+ std::cerr << "expected to be non-bold but it is bold "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ };
+
+ auto check_cell_italic = [&get_font](const ss::sheet& sh, ss::row_t row, ss::col_t col, bool expected)
+ {
+ const ss::font_t* font = get_font(sh, row, col);
+
+ if (expected)
+ {
+ if (font->italic && *font->italic)
+ return true;
+
+ std::cerr << "expected to be italic but it is not "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ else
+ {
+ if (!font->italic || !*font->italic)
+ return true;
+
+ std::cerr << "expected to be non-italic but it is italic "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ };
+
+ auto check_cell_text = [&doc](const ss::sheet& sh, ss::row_t row, ss::col_t col, std::string_view expected)
+ {
+ const auto& sstrings = doc->get_shared_strings();
+
+ std::size_t si = sh.get_string_identifier(row, col);
+ const std::string* s = sstrings.get_string(si);
+ if (!s)
+ {
+ std::cerr << "expected='" << expected << "'; actual=<none> "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+
+ if (*s == expected)
+ return true;
+
+ std::cerr << "expected='" << expected << "'; actual='" << *s << "' "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ };
+
+ const ss::sheet* sheet1 = doc->get_sheet("Text Properties");
+ assert(sheet1);
+
+ ss::row_t row = 0;
+ ss::col_t col = 0;
+
+ // A1 - unformatted
+ assert(check_cell_text(*sheet1, row, col, "Normal Text"));
+ assert(check_cell_bold(*sheet1, row, col, false));
+ assert(check_cell_italic(*sheet1, row, col, false));
+
+ // A2 - bold
+ row = 1;
+ assert(check_cell_text(*sheet1, row, col, "Bold Text"));
+ assert(check_cell_bold(*sheet1, row, col, true));
+ assert(check_cell_italic(*sheet1, row, col, false));
+
+ // A3 - italic
+ row = 2;
+ assert(check_cell_text(*sheet1, row, col, "Italic Text"));
+ assert(check_cell_bold(*sheet1, row, col, false));
+ assert(check_cell_italic(*sheet1, row, col, true));
+
+ // A4 - bold and italic
+ row = 3;
+ assert(check_cell_text(*sheet1, row, col, "Bold and Italic Text"));
+ assert(check_cell_bold(*sheet1, row, col, true));
+ assert(check_cell_italic(*sheet1, row, col, true));
+
+ // A5 - bold and italic mixed - base cell is unformatted and text contains
+ // format runs.
+ row = 4;
+ assert(check_cell_text(*sheet1, row, col, "Bold and Italic mixed"));
+ assert(check_cell_bold(*sheet1, row, col, false));
+ assert(check_cell_italic(*sheet1, row, col, false));
+
+ std::size_t si = sheet1->get_string_identifier(row, col);
+ const ss::format_runs_t* runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 2u);
+
+ // Bold and ...
+ // ^^^^
+ assert(runs->at(0).pos == 0);
+ assert(runs->at(0).size == 4);
+ assert(runs->at(0).bold);
+ assert(!runs->at(0).italic);
+
+ // Bold and Italic
+ // ^^^^^^
+ assert(runs->at(1).pos == 9);
+ assert(runs->at(1).size == 6);
+ assert(!runs->at(1).bold);
+ assert(runs->at(1).italic);
+
+ // A6
+ row = 5;
+ assert(check_cell_text(*sheet1, row, col, "Bold base with non-bold part"));
+ assert(check_cell_bold(*sheet1, row, col, true));
+ assert(check_cell_italic(*sheet1, row, col, false));
+#if 0 // FIXME: see #183
+ si = sheet1->get_string_identifier(row, col);
+ runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 1u);
+#endif
+
+ // Rest of the cells are imported as unformatted for now, until we support
+ // more format properties. See #182.
+ row = 6;
+ assert(check_cell_text(*sheet1, row, col, "Only partially underlined"));
+
+ {
+ row = 7;
+ assert(check_cell_text(*sheet1, row, col, "All Underlined"));
+ const ss::font_t* font = get_font(*sheet1, row, col);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line);
+ }
+
+ {
+ row = 8;
+ assert(check_cell_text(*sheet1, row, col, "Bold and Underlined"));
+ const ss::font_t* font = get_font(*sheet1, row, col);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line);
+ assert(font->bold);
+ assert(*font->bold);
+ }
+
+ {
+ row = 9;
+ assert(check_cell_text(*sheet1, row, col, "All Strikethrough"));
+ const ss::font_t* font = get_font(*sheet1, row, col);
+ assert(font->strikethrough_style);
+ assert(*font->strikethrough_style == ss::strikethrough_style_t::solid);
+
+ assert(font->strikethrough_type);
+ assert(*font->strikethrough_type == ss::strikethrough_type_t::single_type);
+
+ assert(font->strikethrough_width);
+ assert(*font->strikethrough_width == ss::strikethrough_width_t::width_auto);
+ }
+
+ row = 10;
+ assert(check_cell_text(*sheet1, row, col, "Partial strikethrough"));
+ row = 11;
+ assert(check_cell_text(*sheet1, row, col, "Superscript"));
+ row = 12;
+ assert(check_cell_text(*sheet1, row, col, "Subscript"));
+ row = 13;
+ assert(check_cell_text(*sheet1, row, col, "x2 + y2 = 102"));
+ row = 14;
+ assert(check_cell_text(*sheet1, row, col, "xi = yi + zi"));
+
+ {
+ const ss::sheet* sheet2 = doc->get_sheet("Fonts");
+ assert(sheet2);
+
+ struct check
+ {
+ ss::row_t row;
+ std::string_view font_name;
+ double font_unit;
+ };
+
+ check checks[] = {
+ { 0, "Sans", 12.0 },
+ { 1, "FreeSans", 18.0 },
+ { 2, "Serif", 14.0 },
+ { 3, "Monospace", 9.0 },
+ { 4, "DejaVu Sans Mono", 11.0 },
+ };
+
+ for (const auto& c : checks)
+ {
+ std::size_t xf = sheet2->get_cell_format(c.row, 0);
+ const ss::cell_format_t* cell_format = styles_pool.get_cell_format(xf);
+ assert(cell_format);
+ const ss::font_t* font = styles_pool.get_font(cell_format->font);
+ assert(font);
+ assert(font->name == c.font_name);
+ assert(font->size == c.font_unit);
+
+ // Columns A and B should have the same font.
+ xf = sheet2->get_cell_format(c.row, 1);
+ cell_format = styles_pool.get_cell_format(xf);
+ assert(cell_format);
+ font = styles_pool.get_font(cell_format->font);
+ assert(font);
+ assert(font->name == c.font_name);
+ assert(font->size == c.font_unit);
+ }
+ }
+
+ {
+ const ss::sheet* sheet3 = doc->get_sheet("Mixed Fonts");
+ assert(sheet3);
+
+ // A1
+ row = 0;
+ col = 0;
+ assert(check_cell_text(*sheet3, row, col, "C++ has class and struct as keywords."));
+
+ // Base cell has Serif 12-pt font applied
+ auto xf = sheet3->get_cell_format(row, col);
+ const ss::cell_format_t* fmt = styles_pool.get_cell_format(xf);
+ assert(fmt);
+ const ss::font_t* font = styles_pool.get_font(fmt->font);
+ assert(font);
+ assert(font->name == "Serif");
+ assert(font->size == 12.0f);
+
+ // two segments where Monospace font is applied
+ si = sheet3->get_string_identifier(row, col);
+ runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 2u);
+
+ // C++ has class ...
+ // ^^^^^
+ assert(runs->at(0).pos == 8);
+ assert(runs->at(0).size == 5);
+ assert(runs->at(0).font == "Monospace");
+
+ // ... and struct as ...
+ // ^^^^^^
+ assert(runs->at(1).pos == 18);
+ assert(runs->at(1).size == 6);
+ assert(runs->at(1).font == "Monospace");
+
+ // A2
+ row = 1;
+ assert(check_cell_text(*sheet3, row, col, "Text with 12-point font, 24-point font, and 36-point font mixed."));
+ si = sheet3->get_string_identifier(row, col);
+ runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 6u);
+
+ // with 12-point font, ...
+ // ^^
+ assert(runs->at(0).pos == 10);
+ assert(runs->at(0).size == 2);
+ assert(runs->at(0).font_size == 12.0f);
+ assert(runs->at(0).color == ss::color_t(0xFF, 0xFF, 0, 0)); // red
+
+ // with 12-point font, ...
+ // ^^^^^^
+ assert(runs->at(1).pos == 12);
+ assert(runs->at(1).size == 6);
+ assert(runs->at(1).font_size == 12.0f);
+
+ // 24-point font,
+ // ^^
+ assert(runs->at(2).pos == 25);
+ assert(runs->at(2).size == 2);
+ assert(runs->at(2).font_size == 24.0f);
+ assert(runs->at(2).color == ss::color_t(0xFF, 0xFF, 0, 0)); // red
+
+ // 24-point font,
+ // ^^^^^^
+ assert(runs->at(3).pos == 27);
+ assert(runs->at(3).size == 6);
+ assert(runs->at(3).font_size == 24.0f);
+
+ // and 36-point font
+ // ^^
+ assert(runs->at(4).pos == 44);
+ assert(runs->at(4).size == 2);
+ assert(runs->at(4).font_size == 36.0f);
+ assert(runs->at(4).color == ss::color_t(0xFF, 0xFF, 0, 0)); // red
+
+ // and 36-point font
+ // ^^^^^^
+ assert(runs->at(5).pos == 46);
+ assert(runs->at(5).size == 6);
+ assert(runs->at(5).font_size == 36.0f);
+ }
+}
+
+void test_gnumeric_cell_borders_single_cells()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/borders/single-cells.gnumeric";
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ ss::styles& styles = doc->get_styles();
+
+ ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ ss::row_t row;
+ ss::col_t col;
+ ss::border_style_t style;
+ };
+
+ std::vector<check> checks =
+ {
+ { 3, 1, ss::border_style_t::hair },
+ { 5, 1, ss::border_style_t::dotted },
+ { 7, 1, ss::border_style_t::dash_dot_dot },
+ { 9, 1, ss::border_style_t::dash_dot },
+ { 11, 1, ss::border_style_t::dashed },
+ { 13, 1, ss::border_style_t::thin },
+ { 1, 3, ss::border_style_t::medium_dash_dot_dot },
+ { 3, 3, ss::border_style_t::slant_dash_dot },
+ { 5, 3, ss::border_style_t::medium_dash_dot },
+ { 7, 3, ss::border_style_t::medium_dashed },
+ { 9, 3, ss::border_style_t::medium },
+ { 11, 3, ss::border_style_t::thick },
+ { 13, 3, ss::border_style_t::double_border },
+ };
+
+ for (const check& c : checks)
+ {
+ std::cout << "(row: " << c.row << "; col: " << c.col << "; expected: " << int(c.style) << ")" << std::endl;
+ size_t xf = sh->get_cell_format(c.row, c.col);
+ const ss::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const ss::border_t* border = styles.get_border(cf->border);
+ assert(border);
+ assert(border->top.style == c.style);
+ assert(border->bottom.style == c.style);
+ assert(border->left.style == c.style);
+ assert(border->right.style == c.style);
+ }
+}
+
+void test_gnumeric_cell_borders_directions()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/borders/directions.gnumeric";
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ ss::styles& styles = doc->get_styles();
+
+ ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ ss::row_t row;
+ ss::col_t col;
+ ss::border_direction_t dir;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 1, ss::border_direction_t::top },
+ { 3, 1, ss::border_direction_t::left },
+ { 5, 1, ss::border_direction_t::right },
+ { 7, 1, ss::border_direction_t::bottom },
+ { 9, 1, ss::border_direction_t::diagonal_tl_br },
+ { 11, 1, ss::border_direction_t::diagonal_bl_tr },
+ { 13, 1, ss::border_direction_t::diagonal },
+ };
+
+ const ss::color_t black{255, 0, 0, 0};
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+ const ss::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const ss::border_t* border = styles.get_border(cf->border);
+ assert(border);
+
+ switch (c.dir)
+ {
+ case ss::border_direction_t::top:
+ assert(border->top.style);
+ assert(*border->top.style == ss::border_style_t::thin);
+ assert(border->top.border_color);
+ assert(*border->top.border_color == black);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(!border->diagonal_tl_br.style);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case ss::border_direction_t::left:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(border->left.style);
+ assert(*border->left.style == ss::border_style_t::thin);
+ assert(border->left.border_color);
+ assert(*border->left.border_color == black);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(!border->diagonal_tl_br.style);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case ss::border_direction_t::right:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(border->right.style);
+ assert(*border->right.style == ss::border_style_t::thin);
+ assert(border->right.border_color);
+ assert(*border->right.border_color == black);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(!border->diagonal_tl_br.style);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case ss::border_direction_t::bottom:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(border->bottom.style);
+ assert(*border->bottom.style == ss::border_style_t::thin);
+ assert(border->bottom.border_color);
+ assert(*border->bottom.border_color == black);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(!border->diagonal_tl_br.style);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case ss::border_direction_t::diagonal:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(border->diagonal_bl_tr.style);
+ assert(*border->diagonal_bl_tr.style == ss::border_style_t::thin);
+ assert(border->diagonal_bl_tr.border_color);
+ assert(*border->diagonal_bl_tr.border_color == black);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(border->diagonal_tl_br.style);
+ assert(*border->diagonal_tl_br.style == ss::border_style_t::thin);
+ assert(border->diagonal_tl_br.border_color);
+ assert(*border->diagonal_tl_br.border_color == black);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case ss::border_direction_t::diagonal_tl_br:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(border->diagonal_tl_br.style);
+ assert(*border->diagonal_tl_br.style == ss::border_style_t::thin);
+ assert(border->diagonal_tl_br.border_color);
+ assert(*border->diagonal_tl_br.border_color == black);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case ss::border_direction_t::diagonal_bl_tr:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(border->diagonal_bl_tr.style);
+ assert(*border->diagonal_bl_tr.style == ss::border_style_t::thin);
+ assert(border->diagonal_bl_tr.border_color);
+ assert(*border->diagonal_bl_tr.border_color == black);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(!border->diagonal_tl_br.style);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ default:
+ assert(!"unhandled direction!");
+ }
+ }
+}
+
+void test_gnumeric_cell_borders_colors()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ using ss::color_t;
+ using ss::border_style_t;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/borders/colors.gnumeric";
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ ss::styles& styles = doc->get_styles();
+
+ ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ ss::row_t row;
+ ss::col_t col;
+ color_t color;
+ };
+
+ std::vector<check> checks =
+ {
+ { 2, 1, color_t(0xFF, 0xFF, 0, 0) }, // B3 - red
+ { 3, 1, color_t(0xFF, 0, 0x70, 0xC0) }, // B4 - blue
+ { 4, 1, color_t(0xFF, 0, 0xB0, 0x50) }, // B5 - green
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col); // B3
+
+ const ss::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const ss::border_t* border = styles.get_border(cf->border);
+ assert(border);
+
+ assert(!border->left.style);
+ assert(border->right.style);
+ assert(*border->right.style == border_style_t::thick);
+ assert(!border->top.style);
+ assert(!border->bottom.style);
+
+ assert(border->right.border_color == c.color);
+ }
+
+ // B7 contains yellow left border, purple right border, and light blue
+ // diagonal borders.
+
+ size_t xf = sh->get_cell_format(6, 1); // B7
+
+ const ss::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const ss::border_t* border = styles.get_border(cf->border);
+ assert(border);
+
+ assert(border->left.style == border_style_t::thick);
+ assert(border->left.border_color == color_t(0xFF, 0xFF, 0xFF, 0)); // yellow
+
+ assert(border->right.style == border_style_t::thick);
+ assert(border->right.border_color == color_t(0xFF, 0x70, 0x30, 0xA0)); // purple
+
+ assert(border->diagonal_bl_tr.style == border_style_t::thick);
+ assert(border->diagonal_bl_tr.border_color == color_t(0xFF, 0x00, 0xB0, 0xF0)); // light blue
+
+ assert(border->diagonal_tl_br.style == border_style_t::thick);
+ assert(border->diagonal_tl_br.border_color == color_t(0xFF, 0x00, 0xB0, 0xF0)); // light blue
+
+ // B7 also contains multi-line string. Test that as well.
+ ixion::model_context& model = doc->get_model_context();
+ ixion::string_id_t sid = model.get_string_identifier(ixion::abs_address_t(0,6,1));
+ const std::string* s = model.get_string(sid);
+ assert(s);
+ assert(*s == "<- Yellow\nPurple ->\nLight Blue \\");
+}
+
+void test_gnumeric_number_format()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath = SRCDIR"/test/gnumeric/number-formats/input.gnumeric";
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ const spreadsheet::styles& styles = doc->get_styles();
+
+ const spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ ss::row_t row;
+ ss::col_t col;
+ std::string_view expected;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 1, "[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy" },
+ { 2, 1, "[$-409]mmmm\\ d\\,\\ yyyy;@" },
+ { 3, 1, "m/d/yy;@" },
+ { 4, 1, "m/d/yy h:mm" }, // General Date
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+
+ const spreadsheet::number_format_t* nf = styles.get_number_format(cf->number_format);
+ assert(nf);
+ std::cout << "row=" << c.row << "; col=" << c.col << "; expected='"
+ << c.expected << "'; actual='" << (nf->format_string ? *nf->format_string : "") << "'" << std::endl;
+ assert(nf->format_string == c.expected);
+ }
+}
+
+} // anonymous namespace
+
+int main()
+{
+ test_gnumeric_detection();
+ test_gnumeric_create_filter();
+ test_gnumeric_import();
+ test_gnumeric_column_widths_row_heights();
+ test_gnumeric_auto_filter();
+ test_gnumeric_hidden_rows_columns();
+ test_gnumeric_merged_cells();
+ test_gnumeric_text_alignment();
+ test_gnumeric_cell_properties_wrap_and_shrink();
+ test_gnumeric_background_fill();
+ test_gnumeric_colored_text();
+ test_gnumeric_text_formats();
+ test_gnumeric_cell_borders_single_cells();
+ test_gnumeric_cell_borders_directions();
+ test_gnumeric_cell_borders_colors();
+ test_gnumeric_number_format();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_test_import_ods.cpp b/src/orcus_test_import_ods.cpp
new file mode 100644
index 0000000..05ae657
--- /dev/null
+++ b/src/orcus_test_import_ods.cpp
@@ -0,0 +1,1065 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/orcus_import_ods.hpp>
+
+#include <orcus/measurement.hpp>
+#include <orcus/spreadsheet/factory.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+#include <orcus/spreadsheet/types.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/string_pool.hpp>
+
+#include <cassert>
+#include <iostream>
+#include <sstream>
+
+#include "filesystem_env.hpp"
+
+namespace ss = orcus::spreadsheet;
+
+using orcus::test::stack_printer;
+
+namespace {
+
+struct test_model
+{
+ orcus::string_pool pool;
+ orcus::file_content content;
+ ss::styles styles;
+ ss::import_styles istyles;
+
+ test_model() : styles(), istyles(styles, pool) {}
+
+ void load(const fs::path& input_path)
+ {
+ if (!fs::is_regular_file(input_path))
+ {
+ std::ostringstream os;
+ os << input_path << " is not a regular file.";
+ throw std::runtime_error(os.str());
+ }
+
+ styles.clear();
+ content.load(input_path.string());
+ orcus::import_ods::read_styles(content.str(), &istyles);
+ }
+};
+
+bool verify_font_attrs(const ss::font_t& expected, const ss::font_t& actual)
+{
+ if (expected.name != actual.name)
+ {
+ std::cerr << "font name states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.name && *expected.name != *actual.name)
+ {
+ std::cerr << "font names differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.size != actual.size)
+ {
+ std::cerr << "font size states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.size && *expected.size != *actual.size)
+ {
+ std::cerr << "font sizes differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.bold != actual.bold)
+ {
+ std::cerr << "font bold states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.bold && *expected.bold != *actual.bold)
+ {
+ std::cerr << "font bold values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.italic != actual.italic)
+ {
+ std::cerr << "font italic states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.italic && *expected.italic != *actual.italic)
+ {
+ std::cerr << "font italic values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.underline_style != actual.underline_style)
+ {
+ std::cerr << "underline_style states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.underline_style && *expected.underline_style != *actual.underline_style)
+ {
+ std::cerr << "underline_style values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.underline_width != actual.underline_width)
+ {
+ std::cerr << "underline_width states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.underline_width && *expected.underline_width != *actual.underline_width)
+ {
+ std::cerr << "underline_width values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.underline_mode != actual.underline_mode)
+ {
+ std::cerr << "underline_mode states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.underline_mode && *expected.underline_mode != *actual.underline_mode)
+ {
+ std::cerr << "underline_mode values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.underline_type != actual.underline_type)
+ {
+ std::cerr << "underline_type states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.underline_type && *expected.underline_type != *actual.underline_type)
+ {
+ std::cerr << "underline_type values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.underline_color != actual.underline_color)
+ {
+ std::cerr << "underline_color states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.underline_color && *expected.underline_color != *actual.underline_color)
+ {
+ std::cerr << "underline_color values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.color != actual.color)
+ {
+ std::cerr << "font color states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.color && *expected.color != *actual.color)
+ {
+ std::cerr << "font color values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.strikethrough_style != actual.strikethrough_style)
+ {
+ std::cerr << "strikethrough_style states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.strikethrough_style && *expected.strikethrough_style != *actual.strikethrough_style)
+ {
+ std::cerr << "strikethrough_style values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.strikethrough_width != actual.strikethrough_width)
+ {
+ std::cerr << "strikethrough_width states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.strikethrough_width && *expected.strikethrough_width != *actual.strikethrough_width)
+ {
+ std::cerr << "strikethrough_width values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.strikethrough_type != actual.strikethrough_type)
+ {
+ std::cerr << "strikethrough_type states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.strikethrough_type && *expected.strikethrough_type != *actual.strikethrough_type)
+ {
+ std::cerr << "strikethrough_type values differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.strikethrough_text != actual.strikethrough_text)
+ {
+ std::cerr << "strikethrough_text states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.strikethrough_text && *expected.strikethrough_text != *actual.strikethrough_text)
+ {
+ std::cerr << "strikethrough_text values differ!" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool verify_fill_attrs(const ss::fill_t& expected, const ss::fill_t& actual)
+{
+ if (expected.pattern_type != actual.pattern_type)
+ {
+ std::cerr << "pattern_type states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.pattern_type && *expected.pattern_type != *actual.pattern_type)
+ {
+ std::cerr << "pattern types differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.fg_color != actual.fg_color)
+ {
+ std::cerr << "fg_color states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.fg_color && *expected.fg_color != *actual.fg_color)
+ {
+ std::cerr << "foreground colors differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.bg_color != actual.bg_color)
+ {
+ std::cerr << "bg_color states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.bg_color && *expected.bg_color != *actual.bg_color)
+ {
+ std::cerr << "background colors differ!" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool verify_protection_attrs(const ss::protection_t& expected, const ss::protection_t& actual)
+{
+ if (expected.locked != actual.locked)
+ {
+ std::cerr << "locked states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.hidden != actual.hidden)
+ {
+ std::cerr << "hidden states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.print_content != actual.print_content)
+ {
+ std::cerr << "'print content' states differ!" << std::endl;
+ return false;
+ }
+
+ if (expected.formula_hidden != actual.formula_hidden)
+ {
+ std::cerr << "'formula hidden' states differ!" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool verify_border_attrs(const ss::border_t& expected, const ss::border_t& actual)
+{
+ auto verify_single = [](std::string_view name, const ss::border_attrs_t& _expected, const ss::border_attrs_t& _actual)
+ {
+ if (_expected.style != _actual.style)
+ {
+ std::cerr << name << " border style states differ!" << std::endl;
+ return false;
+ }
+
+ if (_expected.style && *_expected.style != *_actual.style)
+ {
+ std::cerr << name << " border styles differ!" << std::endl;
+ return false;
+ }
+
+ if (_expected.border_color != _actual.border_color)
+ {
+ std::cerr << name << " border color states differ!" << std::endl;
+ return false;
+ }
+
+ if (_expected.border_color && *_expected.border_color != *_actual.border_color)
+ {
+ std::cerr << name << " border colors differ!" << std::endl;
+ return false;
+ }
+
+ if (_expected.border_width != _actual.border_width)
+ {
+ std::cerr << name << " border width states differ!" << std::endl;
+ return false;
+ }
+
+ if (_expected.border_width && *_expected.border_width != *_actual.border_width)
+ {
+ std::cerr << name << " border widths differ!" << std::endl;
+ return false;
+ }
+
+ return true;
+ };
+
+ if (!verify_single("top", expected.top, actual.top))
+ return false;
+
+ if (!verify_single("bottom", expected.bottom, actual.bottom))
+ return false;
+
+ if (!verify_single("left", expected.left, actual.left))
+ return false;
+
+ if (!verify_single("right", expected.right, actual.right))
+ return false;
+
+ if (!verify_single("diagonal", expected.diagonal, actual.diagonal))
+ return false;
+
+ if (!verify_single("diagonal_bl_tr", expected.diagonal_bl_tr, actual.diagonal_bl_tr))
+ return false;
+
+ if (!verify_single("diagonal_tl_br", expected.diagonal_tl_br, actual.diagonal_tl_br))
+ return false;
+
+ return true;
+}
+
+const ss::cell_style_t* find_cell_style_by_name(
+ std::string_view name, const ss::styles& styles)
+{
+ size_t n = styles.get_cell_styles_count();
+ for (size_t i = 0; i < n; ++i)
+ {
+ const ss::cell_style_t* cur_style = styles.get_cell_style(i);
+ if (cur_style->name == name)
+ return cur_style;
+ }
+
+ std::cerr << "No styles named '" << name << "' found!" << std::endl;
+ return nullptr;
+}
+
+const ss::cell_format_t* find_cell_format(const ss::styles& styles, std::string_view name, std::string_view parent_name)
+{
+ const ss::cell_style_t* style = find_cell_style_by_name(name, styles);
+ if (!style)
+ return nullptr;
+
+ if (style->parent_name != parent_name)
+ {
+ std::cerr << "Parent name is not as expected: expected='" << parent_name << "'; actual='" << style->parent_name << "'" << std::endl;
+ return nullptr;
+ }
+
+ return styles.get_cell_style_format(style->xf);
+}
+
+void test_odf_fill(const ss::styles& styles)
+{
+ const ss::cell_style_t* style = find_cell_style_by_name("Name1", styles);
+ assert(style);
+ assert(style->parent_name == "Text");
+ size_t xf = style->xf;
+ const ss::cell_format_t* cell_format = styles.get_cell_style_format(xf);
+ assert(cell_format);
+
+ size_t fill = cell_format->fill;
+ const ss::fill_t* cell_fill = styles.get_fill(fill);
+ assert(cell_fill);
+ assert(cell_fill->fg_color);
+ assert(*cell_fill->fg_color == ss::color_t(0xFF, 0xFE, 0xFF, 0xCC));
+ assert(cell_fill->pattern_type);
+ assert(*cell_fill->pattern_type == ss::fill_pattern_t::solid);
+}
+
+void test_odf_border(const ss::styles &styles)
+{
+ /* Test that border style applies to all the sides when not specified */
+ const ss::cell_style_t* style = find_cell_style_by_name("Name1", styles);
+ assert(style);
+ const ss::cell_format_t* cell_format = styles.get_cell_style_format(style->xf);
+ assert(cell_format);
+
+ const ss::border_t* cell_border = styles.get_border(cell_format->border);
+ assert(cell_border->top.style);
+ assert(*cell_border->top.style == ss::border_style_t::dotted);
+ assert(cell_border->bottom.style);
+ assert(*cell_border->bottom.style == ss::border_style_t::dotted);
+ assert(cell_border->left.style);
+ assert(*cell_border->left.style == ss::border_style_t::dotted);
+ assert(cell_border->right.style);
+ assert(*cell_border->right.style == ss::border_style_t::dotted);
+
+ ss::color_t expected_color{0xFF, 0xFF, 0xCC, 0x12};
+ assert(cell_border->top.border_color);
+ assert(*cell_border->top.border_color == expected_color);
+ assert(cell_border->bottom.border_color);
+ assert(*cell_border->bottom.border_color == expected_color);
+ assert(cell_border->left.border_color);
+ assert(*cell_border->left.border_color == expected_color);
+ assert(cell_border->right.border_color);
+ assert(*cell_border->right.border_color == expected_color);
+
+ orcus::length_t expected_width{orcus::length_unit_t::point, 0.06};
+ assert(cell_border->top.border_width);
+ assert(*cell_border->top.border_width == expected_width);
+ assert(cell_border->bottom.border_width);
+ assert(*cell_border->bottom.border_width == expected_width);
+ assert(cell_border->left.border_width);
+ assert(*cell_border->left.border_width == expected_width);
+ assert(cell_border->right.border_width);
+ assert(*cell_border->right.border_width == expected_width);
+
+ style = find_cell_style_by_name("Name2", styles);
+ assert(style);
+ cell_format = styles.get_cell_style_format(style->xf);
+ assert(cell_format);
+
+ cell_border = styles.get_border(cell_format->border);
+ assert(cell_border);
+ assert(cell_border->top.style);
+ assert(*cell_border->top.style == ss::border_style_t::fine_dashed);
+ assert(cell_border->bottom.style);
+ assert(*cell_border->bottom.style == ss::border_style_t::double_thin);
+ assert(cell_border->left.style);
+ assert(*cell_border->left.style == ss::border_style_t::none);
+ assert(cell_border->right.style);
+ assert(*cell_border->right.style == ss::border_style_t::dash_dot_dot);
+
+ assert(cell_border->top.border_color);
+ assert(*cell_border->top.border_color == ss::color_t(0xFF, 0xFF, 0xEE, 0x11));
+ assert(cell_border->bottom.border_color);
+ assert(*cell_border->bottom.border_color == ss::color_t(0xFF, 0xAE, 0xEE, 0x11));
+ assert(cell_border->left.border_color);
+ assert(*cell_border->left.border_color == ss::color_t(0xFF, 0x11, 0xEE, 0x11));
+ assert(cell_border->right.border_color);
+ assert(*cell_border->right.border_color == ss::color_t(0xFF, 0x05, 0xEE, 0x11));
+
+ expected_width.value = 0.74; // point
+ assert(cell_border->top.border_width);
+ assert(*cell_border->top.border_width == expected_width);
+ expected_width.value = 1.74;
+ assert(cell_border->bottom.border_width);
+ assert(*cell_border->bottom.border_width == expected_width);
+ expected_width.value = 0.74;
+ assert(cell_border->left.border_width);
+ assert(*cell_border->left.border_width == expected_width);
+ expected_width.value = 0.22;
+ assert(cell_border->right.border_width);
+ assert(*cell_border->right.border_width == expected_width);
+
+ /*Test that border applies to the diagonal*/
+ style = find_cell_style_by_name("Name3", styles);
+ assert(style);
+ cell_format = styles.get_cell_style_format(style->xf);
+ assert(cell_format);
+
+ cell_border = styles.get_border(cell_format->border);
+ assert(cell_border);
+
+ // 1.74pt dashed #ffccee
+ assert(cell_border->diagonal_bl_tr.style);
+ assert(*cell_border->diagonal_bl_tr.style == ss::border_style_t::dashed);
+ assert(cell_border->diagonal_bl_tr.border_color);
+ assert(*cell_border->diagonal_bl_tr.border_color == ss::color_t(0xFF, 0xFF, 0xCC, 0xEE));
+ expected_width.value = 1.74;
+ assert(cell_border->diagonal_bl_tr.border_width);
+ assert(*cell_border->diagonal_bl_tr.border_width == expected_width);
+
+ // 0.74pt dash-dot #120000
+ assert(cell_border->diagonal_tl_br.style);
+ assert(*cell_border->diagonal_tl_br.style == ss::border_style_t::dash_dot);
+ assert(cell_border->diagonal_tl_br.border_color);
+ assert(*cell_border->diagonal_tl_br.border_color == ss::color_t(0xFF, 0x12, 0x00, 0x00));
+ expected_width.value = 0.74;
+ assert(cell_border->diagonal_tl_br.border_width);
+ assert(*cell_border->diagonal_tl_br.border_width == expected_width);
+}
+
+void test_odf_cell_protection(const ss::styles& styles)
+{
+ /* Test that Cell is only protected and not hidden , Print Content is true */
+ const ss::cell_style_t* style = find_cell_style_by_name("Name5", styles);
+ assert(style);
+ size_t xf = style->xf;
+ const ss::cell_format_t* cell_format = styles.get_cell_style_format(xf);
+ size_t protection = cell_format->protection;
+ assert(cell_format);
+
+ const ss::protection_t* cell_protection = styles.get_protection(protection);
+ assert(*cell_protection->locked == true);
+ assert(*cell_protection->hidden == true);
+ assert(*cell_protection->print_content == true);
+ assert(!cell_protection->formula_hidden);
+
+ /* Test that Cell is protected and formula is hidden , Print Content is false */
+ style = find_cell_style_by_name("Name6", styles);
+ assert(style);
+ xf = style->xf;
+ cell_format = styles.get_cell_style_format(xf);
+ protection = cell_format->protection;
+ assert(cell_format);
+
+ cell_protection = styles.get_protection(protection);
+ assert(*cell_protection->locked == true);
+ assert(!cell_protection->hidden); // not set
+ assert(*cell_protection->print_content == false);
+ assert(*cell_protection->formula_hidden == true);
+
+ /* Test that Cell is not protected by any way, Print Content is false */
+ style = find_cell_style_by_name("Name7", styles);
+ assert(style);
+ xf = style->xf;
+ cell_format = styles.get_cell_style_format(xf);
+ protection = cell_format->protection;
+ assert(cell_format);
+
+ cell_protection = styles.get_protection(protection);
+ assert(*cell_protection->locked == false);
+ assert(*cell_protection->hidden == false);
+ assert(*cell_protection->print_content == true);
+ assert(*cell_protection->formula_hidden == false);
+}
+
+void test_odf_font(const ss::styles& styles)
+{
+ const ss::cell_style_t* style = find_cell_style_by_name("Name8", styles);
+ assert(style);
+ size_t xf = style->xf;
+ const ss::cell_format_t* cell_format = styles.get_cell_style_format(xf);
+ size_t font = cell_format->font;
+ assert(cell_format);
+
+ const ss::font_t* cell_font = styles.get_font(font);
+ assert(*cell_font->name == "Liberation Sans");
+ assert(*cell_font->size == 24);
+ assert(*cell_font->bold == true);
+ assert(*cell_font->italic == true);
+ assert(*cell_font->underline_style == ss::underline_t::single_line);
+ assert(*cell_font->underline_width == ss::underline_width_t::thick);
+ assert(!cell_font->underline_mode); // not set
+ assert(!cell_font->underline_type); // not set
+ assert(cell_font->color->red == (int)0x80);
+ assert(cell_font->color->green == (int)0x80);
+ assert(cell_font->color->blue == (int)0x80);
+
+ style = find_cell_style_by_name("Name9", styles);
+ assert(style);
+ xf = style->xf;
+ cell_format = styles.get_cell_style_format(xf);
+ font = cell_format->font;
+ assert(cell_format);
+
+ cell_font = styles.get_font(font);
+ assert(*cell_font->name == "Tahoma");
+ assert(*cell_font->size == 00);
+ assert(*cell_font->bold == true);
+ assert(!cell_font->italic);
+ assert(*cell_font->underline_style == ss::underline_t::dash);
+ assert(*cell_font->underline_width == ss::underline_width_t::bold);
+ assert(!cell_font->underline_mode); // not set
+ assert(!cell_font->underline_type); // not set
+ assert(cell_font->underline_color->red == (int)0x18);
+ assert(cell_font->underline_color->green == (int)0x56);
+ assert(cell_font->underline_color->blue == (int)0xff);
+}
+
+void test_odf_text_strikethrough(const ss::styles& styles)
+{
+ const ss::cell_style_t* style = find_cell_style_by_name("Name20", styles);
+ assert(style);
+ size_t xf = style->xf;
+ const ss::cell_format_t* cell_format = styles.get_cell_style_format(xf);
+ size_t font = cell_format->font;
+ assert(cell_format);
+
+ const ss::font_t* cell_font = styles.get_font(font);
+ assert(*cell_font->strikethrough_style == ss::strikethrough_style_t::solid);
+ assert(!cell_font->strikethrough_width); // not set
+ assert(*cell_font->strikethrough_type == ss::strikethrough_type_t::single_type);
+ assert(!cell_font->strikethrough_text); // not set
+
+ style = find_cell_style_by_name("Name21", styles);
+ assert(style);
+ xf = style->xf;
+ cell_format = styles.get_cell_style_format(xf);
+ font = cell_format->font;
+ assert(cell_format);
+
+ cell_font = styles.get_font(font);
+ assert(*cell_font->strikethrough_style == ss::strikethrough_style_t::solid);
+ assert(*cell_font->strikethrough_width == ss::strikethrough_width_t::bold);
+ assert(*cell_font->strikethrough_type == ss::strikethrough_type_t::single_type);
+ assert(!cell_font->strikethrough_text); // not set
+
+ style = find_cell_style_by_name("Name22", styles);
+ assert(style);
+ xf = style->xf;
+ cell_format = styles.get_cell_style_format(xf);
+ font = cell_format->font;
+ assert(cell_format);
+
+ cell_font = styles.get_font(font);
+ assert(*cell_font->strikethrough_style == ss::strikethrough_style_t::solid);
+ assert(!cell_font->strikethrough_width); // not set
+ assert(*cell_font->strikethrough_type == ss::strikethrough_type_t::single_type);
+ assert(*cell_font->strikethrough_text == ss::strikethrough_text_t::slash);
+}
+
+void test_odf_text_alignment(const ss::styles& styles)
+{
+ const ss::cell_style_t* style = find_cell_style_by_name("Name23", styles);
+ assert(style);
+ size_t xf = style->xf;
+ const ss::cell_format_t* cell_format = styles.get_cell_style_format(xf);
+ assert(cell_format);
+
+ assert(cell_format->hor_align == ss::hor_alignment_t::right);
+ assert(cell_format->ver_align == ss::ver_alignment_t::middle);
+}
+
+void test_cell_styles()
+{
+ stack_printer __sp__(__func__);
+
+ test_model model;
+
+ model.load(SRCDIR"/test/ods/import-styles/cell-styles.xml");
+ test_odf_fill(model.styles);
+ test_odf_border(model.styles);
+ test_odf_cell_protection(model.styles);
+ test_odf_font(model.styles);
+ test_odf_text_strikethrough(model.styles);
+ test_odf_text_alignment(model.styles);
+}
+
+void test_standard_styles()
+{
+ stack_printer __sp__(__func__);
+
+ test_model model;
+ model.load(SRCDIR"/test/ods/import-styles/standard-styles.xml");
+
+ {
+ // Heading only specifies color, font size, font style and font weight.
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Heading", "Default");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.size = 24;
+ expected.bold = true;
+ expected.italic = false;
+ expected.color = ss::color_t(0, 0, 0);
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+ }
+
+ {
+ // Heading 1 only overwrites font size.
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Heading 1", "Heading");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.size = 18;
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+ }
+
+ {
+ // Heading 2 also only overwrites font size but with a different size.
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Heading 2", "Heading");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.size = 12;
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+ }
+
+ {
+ // Text simply inherits from Default.
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Text", "Default");
+ assert(cell_format);
+
+ ss::font_t expected; // nothing is active
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Note", "Text");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.color = ss::color_t(0x33, 0x33, 0x33);
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+
+ ss::fill_t expected_fill;
+ expected_fill.pattern_type = ss::fill_pattern_t::solid;
+ expected_fill.fg_color = ss::color_t(0xff, 0xff, 0xcc);
+
+ const ss::fill_t* actual_fill = model.styles.get_fill(cell_format->fill);
+ assert(actual_fill);
+ assert(verify_fill_attrs(expected_fill, *actual_fill));
+
+ // fo:border="0.75pt solid #808080" -> same border attributes applied to top, bottom, left and right borders.
+ ss::border_t expected_border;
+ expected_border.top.style = ss::border_style_t::solid;
+ expected_border.top.border_width = orcus::length_t{orcus::length_unit_t::point, 0.75};
+ expected_border.top.border_color = ss::color_t(0xFF, 0x80, 0x80, 0x80);
+
+ expected_border.bottom = expected_border.top;
+ expected_border.left = expected_border.top;
+ expected_border.right = expected_border.top;
+
+ const auto* actual_border = model.styles.get_border(cell_format->border);
+ assert(actual_border);
+ assert(verify_border_attrs(expected_border, *actual_border));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Footnote", "Text");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.color = ss::color_t(0x80, 0x80, 0x80);
+ expected.italic = true;
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Hyperlink", "Text");
+ assert(cell_format);
+
+ // TODO: Since we currently handle text-underline-width and
+ // text-underline-color incorrectly, we cannot perform exhaustive check.
+ // We can only check the attributes individually.
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+
+ // fo:color="#0000ee"
+ assert(actual->color);
+ assert(*actual->color == ss::color_t(0x00, 0x00, 0xee));
+
+ // style:text-underline-style="solid"
+ assert(actual->underline_style);
+ assert(*actual->underline_style == ss::underline_t::single_line); // solid
+
+ // style:text-underline-width="auto"
+ assert(actual->underline_width);
+ assert(*actual->underline_width == ss::underline_width_t::automatic);
+
+ // style:text-underline-color="font-color" (use the same color as the font)
+ assert(!actual->underline_color); // this implies the same color as the font
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Status", "Default");
+ assert(cell_format);
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Good", "Status");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.color = ss::color_t(0x00, 0x66, 0x00);
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+
+ ss::fill_t expected_fill;
+ expected_fill.pattern_type = ss::fill_pattern_t::solid;
+ expected_fill.fg_color = ss::color_t(0xcc, 0xff, 0xcc);
+
+ const ss::fill_t* actual_fill = model.styles.get_fill(cell_format->fill);
+ assert(actual_fill);
+ assert(verify_fill_attrs(expected_fill, *actual_fill));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Neutral", "Status");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.color = ss::color_t(0x99, 0x66, 0x00);
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+
+ ss::fill_t expected_fill;
+ expected_fill.pattern_type = ss::fill_pattern_t::solid;
+ expected_fill.fg_color = ss::color_t(0xff, 0xff, 0xcc);
+
+ const ss::fill_t* actual_fill = model.styles.get_fill(cell_format->fill);
+ assert(actual_fill);
+ assert(verify_fill_attrs(expected_fill, *actual_fill));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Bad", "Status");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.color = ss::color_t(0xcc, 0x00, 0x00);
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+
+ ss::fill_t expected_fill;
+ expected_fill.pattern_type = ss::fill_pattern_t::solid;
+ expected_fill.fg_color = ss::color_t(0xff, 0xcc, 0xcc);
+
+ const ss::fill_t* actual_fill = model.styles.get_fill(cell_format->fill);
+ assert(actual_fill);
+ assert(verify_fill_attrs(expected_fill, *actual_fill));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Warning", "Status");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.color = ss::color_t(0xcc, 0x00, 0x00);
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Error", "Status");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.color = ss::color_t(0xff, 0xff, 0xff);
+ expected.bold = true;
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+
+ ss::fill_t expected_fill;
+ expected_fill.pattern_type = ss::fill_pattern_t::solid;
+ expected_fill.fg_color = ss::color_t(0xcc, 0x00, 0x00);
+
+ const ss::fill_t* actual_fill = model.styles.get_fill(cell_format->fill);
+ assert(actual_fill);
+ assert(verify_fill_attrs(expected_fill, *actual_fill));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Accent", "Default");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.bold = true;
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Accent 1", "Accent");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.color = ss::color_t(0xff, 0xff, 0xff);
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+
+ ss::fill_t expected_fill;
+ expected_fill.pattern_type = ss::fill_pattern_t::solid;
+ expected_fill.fg_color = ss::color_t(0x00, 0x00, 0x00);
+
+ const ss::fill_t* actual_fill = model.styles.get_fill(cell_format->fill);
+ assert(actual_fill);
+ assert(verify_fill_attrs(expected_fill, *actual_fill));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Accent 2", "Accent");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.color = ss::color_t(0xff, 0xff, 0xff);
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+
+ ss::fill_t expected_fill;
+ expected_fill.pattern_type = ss::fill_pattern_t::solid;
+ expected_fill.fg_color = ss::color_t(0x80, 0x80, 0x80);
+
+ const ss::fill_t* actual_fill = model.styles.get_fill(cell_format->fill);
+ assert(actual_fill);
+ assert(verify_fill_attrs(expected_fill, *actual_fill));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Accent 3", "Accent");
+ assert(cell_format);
+
+ ss::fill_t expected_fill;
+ expected_fill.pattern_type = ss::fill_pattern_t::solid;
+ expected_fill.fg_color = ss::color_t(0xdd, 0xdd, 0xdd);
+
+ const ss::fill_t* actual_fill = model.styles.get_fill(cell_format->fill);
+ assert(actual_fill);
+ assert(verify_fill_attrs(expected_fill, *actual_fill));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Result", "Default");
+ assert(cell_format);
+
+ ss::font_t expected;
+ expected.bold = true;
+ expected.italic = true;
+ expected.underline_style = ss::underline_t::single_line;
+
+ const ss::font_t* actual = model.styles.get_font(cell_format->font);
+ assert(actual);
+ assert(verify_font_attrs(expected, *actual));
+ }
+}
+
+void test_cell_protection_styles()
+{
+ stack_printer __sp__(__func__);
+
+ test_model model;
+ model.load(SRCDIR"/test/ods/import-styles/cell-protection.xml");
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Hide_20_Formula", "Protected");
+ assert(cell_format);
+
+ const auto* protection = model.styles.get_protection(cell_format->protection);
+ assert(protection);
+
+ ss::protection_t expected;
+ expected.locked = true;
+ expected.formula_hidden = true;
+ expected.print_content = true;
+
+ assert(verify_protection_attrs(expected, *protection));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Hide_20_When_20_Printing", "Protected");
+ assert(cell_format);
+
+ const auto* protection = model.styles.get_protection(cell_format->protection);
+ assert(protection);
+
+ ss::protection_t expected;
+ expected.locked = true;
+ expected.print_content = false;
+
+ assert(verify_protection_attrs(expected, *protection));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Hide_20_All", "Protected");
+ assert(cell_format);
+
+ const auto* protection = model.styles.get_protection(cell_format->protection);
+ assert(protection);
+
+ ss::protection_t expected;
+ expected.locked = true;
+ expected.hidden = true;
+ expected.print_content = true;
+
+ assert(verify_protection_attrs(expected, *protection));
+ }
+
+ {
+ const ss::cell_format_t* cell_format = find_cell_format(model.styles, "Not_20_Protected", "Default");
+ assert(cell_format);
+
+ const auto* protection = model.styles.get_protection(cell_format->protection);
+ assert(protection);
+
+ ss::protection_t expected;
+ expected.locked = false;
+ expected.hidden = false;
+ expected.print_content = true;
+ expected.formula_hidden = false;
+
+ assert(verify_protection_attrs(expected, *protection));
+ }
+}
+
+} // anonymous namespace
+
+int main()
+{
+ test_cell_styles();
+ test_standard_styles();
+ test_cell_protection_styles();
+
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_test_json_mapped.cpp b/src/orcus_test_json_mapped.cpp
new file mode 100644
index 0000000..dbe3561
--- /dev/null
+++ b/src/orcus_test_json_mapped.cpp
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/orcus_json.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/spreadsheet/factory.hpp>
+#include <orcus/exception.hpp>
+#include <orcus/parser_global.hpp>
+
+#include <iostream>
+#include <vector>
+#include <cassert>
+#include <sstream>
+
+#include "filesystem_env.hpp"
+
+using namespace std;
+using namespace orcus;
+
+namespace {
+
+const std::vector<const char*> tests =
+{
+ SRCDIR"/test/json-mapped/array-of-arrays-basic",
+ SRCDIR"/test/json-mapped/array-of-arrays-header",
+ SRCDIR"/test/json-mapped/array-of-objects-basic",
+ SRCDIR"/test/json-mapped/array-of-objects-header",
+ SRCDIR"/test/json-mapped/nested-repeats",
+ SRCDIR"/test/json-mapped/nested-repeats-2",
+};
+
+} // anonymous namespace
+
+void test_mapped_json_import()
+{
+ for (fs::path base_dir : tests)
+ {
+ fs::path data_file = base_dir / "input.json";
+ fs::path map_file = base_dir / "map.json";
+ fs::path check_file = base_dir / "check.txt";
+
+ cout << "reading " << data_file.string() << endl;
+ file_content content(data_file.string().data());
+ file_content map_content(map_file.string().data());
+ file_content check_content(check_file.string().data());
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory import_fact(doc);
+
+ orcus_json app(&import_fact);
+ app.read_map_definition(map_content.str());
+ app.read_stream(content.str());
+
+ std::ostringstream os;
+ doc.dump_check(os);
+
+ std::string actual_strm = os.str();
+ std::string_view actual(actual_strm);
+ std::string_view expected = check_content.str();
+ actual = trim(actual);
+ expected = trim(expected);
+ assert(actual == expected);
+ }
+}
+
+void test_invalid_map_definition()
+{
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory import_fact(doc);
+
+ orcus_json app(&import_fact);
+ try
+ {
+ app.read_map_definition("asdfdasf");
+ assert(false); // We were expecting an exception, but didn't get one.
+ }
+ catch (const invalid_map_error&)
+ {
+ // Success!
+ }
+}
+
+int main()
+{
+ test_mapped_json_import();
+ test_invalid_map_definition();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/orcus_test_ods.cpp b/src/orcus_test_ods.cpp
new file mode 100644
index 0000000..377c35b
--- /dev/null
+++ b/src/orcus_test_ods.cpp
@@ -0,0 +1,958 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/orcus_ods.hpp>
+#include <orcus/format_detection.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/parser_global.hpp>
+#include <orcus/spreadsheet/factory.hpp>
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/spreadsheet/sheet.hpp>
+#include <orcus/spreadsheet/shared_strings.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+
+#include <cstdlib>
+#include <cassert>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include "filesystem_env.hpp"
+
+#include <mdds/flat_segment_tree.hpp>
+
+using namespace orcus;
+using namespace orcus::spreadsheet;
+
+namespace ss = orcus::spreadsheet;
+
+
+typedef mdds::flat_segment_tree<std::size_t, bool> bool_segment_type;
+
+namespace {
+
+std::unique_ptr<ss::document> load_doc(const fs::path& filepath)
+{
+ spreadsheet::range_size_t ss{1048576, 16384};
+ std::unique_ptr<ss::document> doc = std::make_unique<ss::document>(ss);
+ import_factory factory(*doc);
+ orcus_ods app(&factory);
+ app.read_file(filepath.string());
+
+ return doc;
+}
+
+std::vector<fs::path> dirs = {
+ SRCDIR"/test/ods/raw-values-1/",
+ SRCDIR"/test/ods/formula-1/",
+ SRCDIR"/test/ods/formula-2/",
+ SRCDIR"/test/ods/named-range/",
+ SRCDIR"/test/ods/named-expression/",
+ SRCDIR"/test/ods/named-expression-sheet-local/",
+};
+
+void test_ods_detection()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ for (const auto& dir : dirs)
+ {
+ fs::path filepath = dir / "input.ods";
+ file_content fc(filepath.string());
+ assert(!fc.empty());
+
+ format_t detected = detect(fc.str());
+ assert(detected == format_t::ods);
+ }
+}
+
+void test_ods_create_filter()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ ss::range_size_t ssize{1048576, 16384};
+ std::unique_ptr<ss::document> doc = std::make_unique<ss::document>(ssize);
+ ss::import_factory factory(*doc);
+
+ auto f = create_filter(format_t::ods, &factory);
+ assert(f);
+ assert(f->get_name() == "ods");
+}
+
+void test_ods_import_cell_values()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ for (const auto& dir : dirs)
+ {
+ fs::path filepath{dir};
+ filepath /= "input.ods";
+ std::cout << filepath << std::endl;
+
+ auto doc = load_doc(filepath);
+ assert(doc);
+ doc->recalc_formula_cells();
+
+ // Dump the content of the model.
+ std::ostringstream os;
+ doc->dump_check(os);
+ std::string check = os.str();
+
+ // Check that against known control.
+ filepath = dir;
+ filepath /= "check.txt";
+ file_content control{filepath.string()};
+
+ assert(!check.empty());
+ assert(!control.empty());
+
+ assert(trim(check) == trim(control.str()));
+ }
+}
+
+void test_ods_import_column_widths_row_heights()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath{SRCDIR"/test/ods/column-width-row-height/input.ods"};
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ assert(doc->get_sheet_count() > 0);
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ // Column widths are in twips.
+ col_width_t cw = sh->get_col_width(1, nullptr, nullptr);
+ assert(cw == 1440); // 1 in
+ cw = sh->get_col_width(2, nullptr, nullptr);
+ assert(cw == 2160); // 1.5 in
+ cw = sh->get_col_width(3, nullptr, nullptr);
+ assert(cw == 2592); // 1.8 in
+
+ // Row heights are in twips too.
+ row_height_t rh = sh->get_row_height(3, nullptr, nullptr);
+ assert(rh == 720); // 0.5 in
+ rh = sh->get_row_height(4, nullptr, nullptr);
+ assert(rh == 1440); // 1 in
+ rh = sh->get_row_height(5, nullptr, nullptr);
+ assert(rh == 2160); // 1.5 in
+ rh = sh->get_row_height(6, nullptr, nullptr);
+ assert(rh == 2592); // 1.8 in
+}
+
+void test_ods_import_formatted_text()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath{SRCDIR"/test/ods/formatted-text/bold-and-italic.ods"};
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ assert(doc->get_sheet_count() > 0);
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ const shared_strings& ss = doc->get_shared_strings();
+
+ const styles& styles = doc->get_styles();
+
+ // A1 is unformatted
+ size_t str_id = sh->get_string_identifier(0,0);
+ const std::string* str = ss.get_string(str_id);
+ assert(str && *str == "Normal Text");
+ std::size_t xfid = sh->get_cell_format(0, 0);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+ const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Default");
+ const format_runs_t* fmt = ss.get_format_runs(str_id);
+ assert(!fmt); // The string should be unformatted.
+
+ // A2 is all bold via cell format.
+ str_id = sh->get_string_identifier(1,0);
+ str = ss.get_string(str_id);
+ assert(str && *str == "Bold Text");
+ xfid = sh->get_cell_format(1,0);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ const font_t* font_data = styles.get_font(xf->font);
+ assert(font_data);
+ assert(font_data->bold);
+ assert(*font_data->bold);
+ assert(font_data->italic);
+ assert(!*font_data->italic);
+ fmt = ss.get_format_runs(str_id);
+ assert(!fmt); // This string should be unformatted.
+
+ // A3 is all italic.
+ str_id = sh->get_string_identifier(2,0);
+ str = ss.get_string(str_id);
+ assert(str && *str == "Italic Text");
+ xfid = sh->get_cell_format(2,0);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ font_data = styles.get_font(xf->font);
+ assert(font_data);
+ assert(font_data->bold);
+ assert(!*font_data->bold);
+ assert(font_data->italic);
+ assert(*font_data->italic);
+ fmt = ss.get_format_runs(str_id);
+ assert(!fmt); // This string should be unformatted.
+
+ // A4 is all bold and italic.
+ str_id = sh->get_string_identifier(3,0);
+ str = ss.get_string(str_id);
+ assert(str && *str == "Bold and Italic Text");
+ xfid = sh->get_cell_format(3,0);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ font_data = styles.get_font(xf->font);
+ assert(font_data);
+ assert(font_data->bold);
+ assert(*font_data->bold);
+ assert(font_data->italic);
+ assert(*font_data->italic);
+ fmt = ss.get_format_runs(str_id);
+ assert(!fmt); // This string should be unformatted.
+
+ // A5 has mixed format runs.
+ str_id = sh->get_string_identifier(4,0);
+ str = ss.get_string(str_id);
+ assert(str && *str == "Bold and Italic mixed");
+ xfid = sh->get_cell_format(4,0);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ font_data = styles.get_font(xf->font);
+ fmt = ss.get_format_runs(str_id);
+ assert(fmt); // This string should be formatted.
+
+ {
+ // Check the bold format segment.
+ bool_segment_type bold_runs(0, str->size(), font_data->bold ? *font_data->bold : false);
+
+ for (size_t i = 0, n = fmt->size(); i < n; ++i)
+ {
+ format_run run = fmt->at(i);
+ bold_runs.insert_back(run.pos, run.pos+run.size, run.bold);
+ }
+
+ bold_runs.build_tree();
+ bool is_bold = false;
+ size_t start_pos, end_pos;
+
+ // The first four letters 'Bold' should be bold.
+ bool good = bold_runs.search_tree(0, is_bold, &start_pos, &end_pos).second;
+ assert(good);
+ assert(is_bold);
+ assert(start_pos == 0);
+ assert(end_pos == 4);
+
+ // The rest should be non-bold.
+ good = bold_runs.search_tree(4, is_bold, &start_pos, &end_pos).second;
+ assert(good);
+ assert(!is_bold);
+ assert(start_pos == 4);
+ assert(end_pos == str->size());
+ }
+
+ {
+ // Check the italic format segment.
+ bool_segment_type italic_runs(0, str->size(), font_data->italic ? *font_data->italic : false);
+
+ for (size_t i = 0, n = fmt->size(); i < n; ++i)
+ {
+ format_run run = fmt->at(i);
+ italic_runs.insert_back(run.pos, run.pos+run.size, run.italic);
+ }
+
+ italic_runs.build_tree();
+ bool it_italic = false;
+ size_t start_pos, end_pos;
+
+ // The first 9 letters 'Bold and ' should not be italic.
+ bool good = italic_runs.search_tree(0, it_italic, &start_pos, &end_pos).second;
+ assert(good);
+ assert(!it_italic);
+ assert(start_pos == 0);
+ assert(end_pos == 9);
+
+ // The next 6 letters 'Italic' should be italic.
+ good = italic_runs.search_tree(9, it_italic, &start_pos, &end_pos).second;
+ assert(good);
+ assert(it_italic);
+ assert(start_pos == 9);
+ assert(end_pos == 15);
+
+ // The rest should be non-italic.
+ good = italic_runs.search_tree(15, it_italic, &start_pos, &end_pos).second;
+ assert(good);
+ assert(!it_italic);
+ assert(start_pos == 15);
+ assert(end_pos == str->size());
+ }
+}
+
+void test_ods_import_number_formats()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath{SRCDIR"/test/ods/number-format/basic-set.ods"};
+
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ assert(doc->get_sheet_count() > 0);
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ const styles& styles = doc->get_styles();
+
+ struct check
+ {
+ row_t row;
+ col_t col;
+ std::string_view format;
+ };
+
+ const check checks[] = {
+ { 1, 1, "#.000000" }, // B2
+ { 2, 1, "[>=0][$₹]#,##0.00;[RED]-[$₹]#,##0.00" }, // B3
+ { 3, 1, "0.00%" }, // B4
+ { 4, 1, "#.00E+00" }, // B5
+ { 5, 1, "BOOLEAN" }, // B6
+ { 6, 1, "?/11" }, // B7
+ { 7, 1, "MM/DD/YY" }, // B8
+ { 8, 1, "HH:MM:SS AM/PM" }, // B9
+ { 9, 1, "[>=0]0.00;[RED]-0.00" }, // B9
+ { 10, 1, "#,##0.00" }, // B10
+ { 11, 1, "Head @ Tail" }, // B11
+ };
+
+ for (const auto& c : checks)
+ {
+ std::size_t xfid = sh->get_cell_format(c.row, c.col);
+ const cell_format_t* xf = styles.get_cell_format(xfid);
+ if (!xf)
+ {
+ std::cerr << "No cell format entry for (row=" << c.row << "; col=" << c.col << ")" << std::endl;
+ assert(false);
+ }
+
+ const number_format_t* numfmt = styles.get_number_format(xf->number_format);
+ if (!numfmt)
+ {
+ std::cerr << "No number-format entry for (row=" << c.row << "; col=" << c.col << ")" << std::endl;
+ assert(false);
+ }
+
+ if (numfmt->format_string && *numfmt->format_string != c.format)
+ {
+ std::cerr << "Number format strings differ: (expected='" << c.format << "'; actual='"
+ << *numfmt->format_string << "')" << std::endl;
+
+ assert(false);
+ }
+ }
+}
+
+void test_ods_import_cell_properties()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath{SRCDIR"/test/ods/cell-properties/wrap-and-shrink.ods"};
+
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ const ss::styles& styles = doc->get_styles();
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ std::size_t xfid = sh->get_cell_format(0, 1); // B1
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(!xf->wrap_text);
+ assert(!xf->shrink_to_fit);
+
+ xfid = sh->get_cell_format(1, 1); // B2
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->wrap_text);
+ assert(*xf->wrap_text);
+ assert(!xf->shrink_to_fit);
+
+ xfid = sh->get_cell_format(2, 1); // B3
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(!xf->wrap_text);
+ assert(xf->shrink_to_fit);
+ assert(*xf->shrink_to_fit);
+}
+
+void test_ods_import_styles_direct_format()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath{SRCDIR"/test/ods/styles/direct-format.ods"};
+
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ const ss::styles& styles = doc->get_styles();
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ // B2 - horizontally center, bold and underlined
+ std::size_t xfid = sh->get_cell_format(1, 1);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->hor_align == ss::hor_alignment_t::center);
+
+ const ss::font_t* font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->bold);
+ assert(*font->bold);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line);
+
+ // B4 - yellow background and right-aligned
+ xfid = sh->get_cell_format(3, 1);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->hor_align == ss::hor_alignment_t::right);
+
+ const ss::fill_t* fill = styles.get_fill(xf->fill);
+ assert(fill);
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(*fill->fg_color == ss::color_t(0xFF, 0xFF, 0xFF, 0x00));
+
+ // D4 - named style "Good" applied with no direct formatting on top
+ xfid = sh->get_cell_format(3, 3);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Good");
+
+ // D6 - named style "Good" plus wrap-text, center and middle aligned and bold text
+ xfid = sh->get_cell_format(5, 3);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->hor_align == ss::hor_alignment_t::center);
+ assert(xf->ver_align == ss::ver_alignment_t::middle);
+ assert(xf->wrap_text);
+ assert(*xf->wrap_text);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->bold);
+ assert(*font->bold);
+
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Good");
+}
+
+void test_ods_import_styles_column_styles()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath{SRCDIR"/test/ods/styles/column-styles.ods"};
+
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ const ss::styles& styles = doc->get_styles();
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ // A1 should have the Default style applied.
+ std::size_t xfid = sh->get_cell_format(0, 0);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Default");
+
+ // This Default style has some custom properties.
+ xf = styles.get_cell_style_format(xf->style_xf);
+ assert(xf);
+
+ // Default style has a solid fill with light green color.
+ const ss::fill_t* fill = styles.get_fill(xf->fill);
+ assert(fill);
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(*fill->fg_color == ss::color_t(0xFF, 0xF6, 0xF9, 0xD4));
+ assert(!fill->bg_color);
+
+ // Default style has a 14pt DejaVu Sans font with normal weight
+ const ss::font_t* font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->name);
+ assert(*font->name == "DejaVu Sans");
+ assert(font->size);
+ assert(*font->size == 14.0);
+ assert(font->bold);
+ assert(!*font->bold);
+
+ assert(xf->hor_align == ss::hor_alignment_t::center);
+
+ // Columns B, E, G and rest all should have the "Default" style applied.
+ std::size_t xfid_default = xfid;
+ for (ss::col_t col : {1, 4, 6, 7, 8})
+ {
+ std::cout << "column " << col << std::endl;
+ xfid = sh->get_cell_format(0, col); // top cell
+ assert(xfid == xfid_default);
+ xfid = sh->get_cell_format(doc->get_sheet_size().rows-1, col); // bottom cell
+ assert(xfid == xfid_default);
+ }
+
+ // Column C should have "Gray With Lime" style applied
+ xfid = sh->get_cell_format(0, 2);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Gray With Lime" || xstyle->display_name == "Gray With Lime");
+
+ // Its parent style should be "Default".
+ xf = styles.get_cell_style_format(xf->style_xf);
+ assert(xf);
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Default");
+
+ // solid gray background
+ fill = styles.get_fill(xf->fill);
+ assert(fill);
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(fill->fg_color == ss::color_t(0xFF, 0xCC, 0xCC, 0xCC));
+ assert(!fill->bg_color);
+
+ // bold, 16pt font, name not set
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(!font->name);
+ assert(font->size);
+ assert(*font->size == 16.0);
+ assert(font->bold);
+ assert(*font->bold);
+
+ // left and right borders are solid light green
+ const ss::border_t* border = styles.get_border(xf->border);
+ assert(border);
+
+ assert(border->left.style);
+ assert(*border->left.style == ss::border_style_t::solid);
+ assert(border->left.border_width);
+ assert(*border->left.border_width == length_t(length_unit_t::point, 2.01));
+ assert(border->left.border_color);
+ assert(*border->left.border_color == ss::color_t(0xFF, 0x81, 0xD4, 0x1A));
+
+ assert(border->right.style);
+ assert(*border->right.style == ss::border_style_t::solid);
+ assert(border->right.border_width);
+ assert(*border->right.border_width == length_t(length_unit_t::point, 2.01));
+ assert(border->right.border_color);
+ assert(*border->right.border_color == ss::color_t(0xFF, 0x81, 0xD4, 0x1A));
+
+ // Column D should have "Emphasis" style applied
+ xfid = sh->get_cell_format(0, 3);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Emphasis" || xstyle->display_name == "Emphasis");
+
+ // Its parent style should be "Default".
+ xf = styles.get_cell_style_format(xf->style_xf);
+ assert(xf);
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Default");
+
+ // solid pink background
+ fill = styles.get_fill(xf->fill);
+ assert(fill);
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(*fill->fg_color == ss::color_t(0xFF, 0xFF, 0xd7, 0xd7));
+ assert(!fill->bg_color);
+
+ // font name 'Rasa Light', 18pt, underlined (solid double), red, not bold
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->name);
+ assert(*font->name == "Rasa Light");
+ assert(font->size);
+ assert(*font->size == 18.0);
+ assert(font->bold);
+ assert(!*font->bold); // in the file, it is given as a font weight of 250
+ assert(font->color);
+ assert(*font->color == ss::color_t(0xFF, 0xFF, 0x00, 0x00));
+ // double underline is stored as single-line double-type?
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line);
+ assert(font->underline_type);
+ assert(*font->underline_type == ss::underline_type_t::double_type);
+ assert(!font->underline_color); // implies the same as font color
+
+ // Column F has "Default" style plus solid light purple background and bold font on top
+ xfid = sh->get_cell_format(0, 5);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Default");
+
+ // light purple solid background
+ fill = styles.get_fill(xf->fill);
+ assert(fill);
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(*fill->fg_color == ss::color_t(0xFF, 0xE0, 0xC2, 0xCD));
+
+ // bold font
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->bold);
+ assert(*font->bold);
+
+ // Check on row 10 cell format from column A to column G
+ for (ss::col_t col = 0; col <= 100; ++col)
+ {
+ std::cout << "(row=9; column=" << col << ")" << std::endl;
+ xfid = sh->get_cell_format(9, col);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->ver_align == ss::ver_alignment_t::top);
+
+ fill = styles.get_fill(xf->fill);
+ assert(fill);
+
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(*fill->fg_color == ss::color_t(0xFF, 0x00, 0xA9, 0x33));
+ }
+
+ // Move on to the next sheet...
+ sh = doc->get_sheet(1);
+ assert(sh);
+
+ // Column A uses "Default"
+ xfid = sh->get_cell_format(0, 0);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Default");
+
+ // Columns B:D use "Gray With Lime" with direct background color
+ for (ss::col_t col : {1, 2, 3})
+ {
+ std::cout << "column " << col << std::endl;
+ xfid = sh->get_cell_format(0, col);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Gray With Lime" || xstyle->display_name == "Gray With Lime");
+
+ fill = styles.get_fill(xf->fill);
+ assert(fill);
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(*fill->fg_color == ss::color_t(0xFF, 0xFF, 0xDE, 0x59));
+ }
+
+ // Column E and the rest all use "Default"
+ xfid = sh->get_cell_format(0, 4);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Default");
+
+ // Columns F:I have narrower width of 0.5 inch.
+ {
+ ss::col_t col_start = -1, col_end = -1;
+ // column widths are stored in twips
+ ss::col_width_t cw = sh->get_col_width(5, &col_start, &col_end);
+ assert(col_start == 5);
+ assert(col_end == 9); // column I has an id = 8, plus 1 for the end position
+ length_t v{length_unit_t::inch, 0.5};
+ ss::col_width_t cw_expected = convert(0.5, length_unit_t::inch, length_unit_t::twip);
+ assert(cw == cw_expected);
+ }
+}
+
+void test_ods_import_styles_asian_complex()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath{SRCDIR"/test/ods/styles/asian-complex.ods"};
+
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ const ss::styles& styles = doc->get_styles();
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ std::size_t xfid = sh->get_cell_format(0, 0); // A1
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::font_t* font = styles.get_font(xf->font);
+ assert(font);
+
+ assert(font->name);
+ assert(*font->name == "FreeMono");
+ assert(font->size);
+ assert(*font->size == 12.0);
+ assert(!font->bold); // bold not set
+ assert(font->italic);
+ assert(*font->italic);
+
+ xfid = sh->get_cell_format(1, 0); // A2
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+
+ assert(font->name_asian);
+ assert(*font->name_asian == "Noto Sans CJK SC");
+ assert(font->size_asian);
+ assert(*font->size_asian == 16.0);
+ assert(font->bold_asian);
+ assert(*font->bold_asian);
+ assert(font->italic_asian);
+ assert(*font->italic_asian);
+
+ xfid = sh->get_cell_format(2, 0); // A3
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+
+ assert(font->name_complex);
+ assert(*font->name_complex == "Gubbi");
+ assert(font->size_complex);
+ assert(*font->size_complex == 24.0);
+ assert(font->bold_complex);
+ assert(*font->bold_complex);
+ assert(font->italic_complex);
+ assert(*font->italic_complex);
+}
+
+void test_ods_import_styles_text_underlines()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath{SRCDIR"/test/ods/styles/text-underlines.ods"};
+
+ auto doc = load_doc(filepath);
+ assert(doc);
+
+ const ss::styles& styles = doc->get_styles();
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ std::size_t xfid = sh->get_cell_format(1, 0); // A2
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::font_t* font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line); // solid
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::automatic);
+ assert(!font->underline_color); // same as the font color
+
+ xfid = sh->get_cell_format(2, 0); // A3
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line); // solid
+ assert(font->underline_type);
+ assert(*font->underline_type == ss::underline_type_t::double_type);
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::automatic);
+ assert(!font->underline_color); // same as the font color
+
+ xfid = sh->get_cell_format(3, 0); // A4
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line); // solid
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::bold);
+ assert(!font->underline_color); // same as the font color
+
+ xfid = sh->get_cell_format(4, 0); // A5
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::dotted);
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::automatic);
+ assert(!font->underline_color); // same as the font color
+
+ xfid = sh->get_cell_format(5, 0); // A6
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::dotted);
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::bold);
+ assert(!font->underline_color); // same as the font color
+
+ xfid = sh->get_cell_format(6, 0); // A7
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::dash);
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::automatic);
+ assert(font->underline_color);
+ assert(*font->underline_color == ss::color_t(0x5E, 0xB9, 0x1E));
+
+ xfid = sh->get_cell_format(7, 0); // A8
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::long_dash);
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::automatic);
+ assert(!font->underline_color); // same as the font color
+
+ xfid = sh->get_cell_format(8, 0); // A9
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::dot_dash);
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::automatic);
+ assert(!font->underline_color); // same as the font color
+
+ xfid = sh->get_cell_format(9, 0); // A10
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::dot_dot_dash);
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::automatic);
+ assert(!font->underline_color); // same as the font color
+
+ xfid = sh->get_cell_format(10, 0); // A11
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::wave);
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::automatic);
+ assert(!font->underline_color); // same as the font color
+
+ xfid = sh->get_cell_format(11, 0); // A12
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::wave);
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::automatic);
+ assert(font->underline_color);
+ assert(*font->underline_color == ss::color_t(0xFF, 0x00, 0x00));
+
+ xfid = sh->get_cell_format(12, 0); // A13
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::wave);
+ assert(font->underline_type);
+ assert(*font->underline_type == ss::underline_type_t::double_type);
+ assert(font->underline_width);
+ assert(*font->underline_width == ss::underline_width_t::automatic);
+ assert(!font->underline_color); // same as the font color
+ assert(font->underline_mode);
+ assert(*font->underline_mode == ss::underline_mode_t::skip_white_space);
+}
+
+} // anonymous namespace
+
+int main()
+{
+ test_ods_detection();
+ test_ods_create_filter();
+ test_ods_import_cell_values();
+ test_ods_import_column_widths_row_heights();
+ test_ods_import_formatted_text();
+ test_ods_import_number_formats();
+ test_ods_import_cell_properties();
+ test_ods_import_styles_direct_format();
+ test_ods_import_styles_column_styles();
+ test_ods_import_styles_asian_complex();
+ test_ods_import_styles_text_underlines();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_test_parquet.cpp b/src/orcus_test_parquet.cpp
new file mode 100644
index 0000000..d8a0699
--- /dev/null
+++ b/src/orcus_test_parquet.cpp
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus_test_global.hpp"
+
+#include <orcus/stream.hpp>
+#include <orcus/orcus_parquet.hpp>
+#include <orcus/format_detection.hpp>
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/spreadsheet/factory.hpp>
+
+#include <iostream>
+#include <sstream>
+
+#include "filesystem_env.hpp"
+
+using namespace orcus;
+namespace ss = orcus::spreadsheet;
+
+const fs::path BASIC_TEST_DOC_DIR = SRCDIR"/test/parquet/basic";
+
+constexpr std::string_view BASIC_TEST_DOCS[] = {
+ "basic-gzip.parquet",
+ "basic-nocomp.parquet",
+ "basic-snappy.parquet",
+ "basic-zstd.parquet",
+ "float-with-nan.parquet",
+};
+
+struct doc_context
+{
+ ss::document doc;
+ ss::import_factory factory;
+ orcus_parquet app;
+
+ doc_context() :
+ doc{ss::range_size_t{1048576, 16384}}, factory{doc}, app{&factory}
+ {
+ }
+
+ std::string get_check_string() const
+ {
+ std::ostringstream os;
+ doc.dump_check(os);
+ return os.str();
+ }
+};
+
+void test_parquet_create_filter()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ ss::range_size_t ssize{1048576, 16384};
+ std::unique_ptr<ss::document> doc = std::make_unique<ss::document>(ssize);
+ ss::import_factory factory(*doc);
+
+ auto f = create_filter(format_t::parquet, &factory);
+ assert(f);
+ assert(f->get_name() == "parquet");
+}
+
+void test_parquet_basic()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ for (auto test_doc : BASIC_TEST_DOCS)
+ {
+ const auto docpath = BASIC_TEST_DOC_DIR / std::string{test_doc};
+ std::cout << docpath << std::endl;
+ assert(fs::is_regular_file(docpath));
+
+ // Test the file import.
+ auto cxt = std::make_unique<doc_context>();
+ cxt->app.read_file(docpath.string());
+ assert(cxt->doc.get_sheet_count() == 1);
+
+ // Check the content vs control
+ const fs::path check_path = BASIC_TEST_DOC_DIR / (docpath.filename().string() + ".check");
+ file_content control{check_path.string()};
+
+ test::verify_content(__FILE__, __LINE__, control.str(), cxt->get_check_string());
+
+ // Test the stream import. Manually change the sheet name to the stem
+ // of the input file since the sheet name is set to 'Data' for stream
+ // imports.
+ cxt = std::make_unique<doc_context>();
+ file_content fc(docpath.string());
+ cxt->app.read_stream(fc.str());
+ cxt->doc.set_sheet_name(0, docpath.stem().string());
+
+ // Check the content vs control
+ test::verify_content(__FILE__, __LINE__, control.str(), cxt->get_check_string());
+ }
+}
+
+void test_parquet_detection()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ for (auto test_doc : BASIC_TEST_DOCS)
+ {
+ const auto docpath = BASIC_TEST_DOC_DIR / std::string{test_doc};
+ assert(fs::is_regular_file(docpath));
+
+ file_content content{docpath.string()};
+ auto strm = content.str();
+ bool res = orcus_parquet::detect(reinterpret_cast<const unsigned char*>(strm.data()), strm.size());
+ assert(res);
+ }
+}
+
+int main()
+{
+ try
+ {
+ test_parquet_create_filter();
+ test_parquet_basic();
+ test_parquet_detection();
+ }
+ catch (const std::exception& e)
+ {
+ std::cout << e.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/orcus_test_xls_xml.cpp b/src/orcus_test_xls_xml.cpp
new file mode 100644
index 0000000..71bbb17
--- /dev/null
+++ b/src/orcus_test_xls_xml.cpp
@@ -0,0 +1,2455 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus_test_global.hpp"
+#include "filesystem_env.hpp"
+
+#include "orcus/orcus_xls_xml.hpp"
+#include <orcus/format_detection.hpp>
+#include "orcus/stream.hpp"
+#include "orcus/config.hpp"
+#include <orcus/parser_global.hpp>
+#include "orcus/yaml_document_tree.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/view.hpp"
+#include "orcus/spreadsheet/sheet.hpp"
+#include "orcus/spreadsheet/shared_strings.hpp"
+#include "orcus/spreadsheet/styles.hpp"
+#include "orcus/spreadsheet/config.hpp"
+
+#include <ixion/model_context.hpp>
+#include <ixion/address.hpp>
+#include <ixion/cell.hpp>
+
+#include <string>
+#include <sstream>
+#include <vector>
+#include <cmath>
+#include <iostream>
+#include <fstream>
+
+using namespace orcus;
+namespace ss = orcus::spreadsheet;
+
+namespace {
+
+config test_config(format_t::xls_xml);
+
+const std::vector<fs::path> dirs = {
+ SRCDIR"/test/xls-xml/basic/",
+ SRCDIR"/test/xls-xml/basic-utf-16-be/",
+ SRCDIR"/test/xls-xml/basic-utf-16-le/",
+ SRCDIR"/test/xls-xml/bold-and-italic/",
+ SRCDIR"/test/xls-xml/colored-text/",
+ SRCDIR"/test/xls-xml/empty-rows/",
+ SRCDIR"/test/xls-xml/formula-array-1/",
+ SRCDIR"/test/xls-xml/formula-cells-1/",
+ SRCDIR"/test/xls-xml/formula-cells-2/",
+ SRCDIR"/test/xls-xml/formula-cells-3/",
+ SRCDIR"/test/xls-xml/invalid-sub-structure/",
+ SRCDIR"/test/xls-xml/leading-whitespace/",
+ SRCDIR"/test/xls-xml/merged-cells/",
+ SRCDIR"/test/xls-xml/named-colors/",
+ SRCDIR"/test/xls-xml/named-expression/",
+ SRCDIR"/test/xls-xml/named-expression-sheet-local/",
+ SRCDIR"/test/xls-xml/raw-values-1/",
+ SRCDIR"/test/xls-xml/table-offset/",
+ SRCDIR"/test/xls-xml/unnamed-parent-styles/",
+};
+
+std::unique_ptr<spreadsheet::document> load_doc_from_filepath(
+ const std::string& path,
+ bool recalc=true,
+ ss::formula_error_policy_t error_policy=ss::formula_error_policy_t::fail)
+{
+ std::cout << path << std::endl;
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ std::unique_ptr<spreadsheet::document> doc = std::make_unique<spreadsheet::document>(ss);
+ spreadsheet::import_factory factory(*doc);
+ factory.set_recalc_formula_cells(recalc);
+ factory.set_formula_error_policy(error_policy);
+ orcus_xls_xml app(&factory);
+ app.set_config(test_config);
+ app.read_file(path.c_str());
+
+ return doc;
+}
+
+std::unique_ptr<spreadsheet::document> load_doc_from_stream(const std::string& path)
+{
+ spreadsheet::range_size_t ss{1048576, 16384};
+ std::unique_ptr<spreadsheet::document> doc = std::make_unique<spreadsheet::document>(ss);
+ spreadsheet::import_factory factory(*doc);
+ orcus_xls_xml app(&factory);
+
+ std::ifstream ifs(path, std::ios::binary | std::ios::ate);
+ std::streamsize n = ifs.tellg();
+ ifs.seekg(0);
+ std::string content(n, '\0');
+ if (ifs.read(content.data(), n))
+ {
+ app.read_stream(content);
+ doc->recalc_formula_cells();
+ }
+
+ return doc;
+}
+
+class doc_loader
+{
+ spreadsheet::document m_doc;
+ spreadsheet::import_factory m_factory;
+
+public:
+ doc_loader(std::string_view path) :
+ m_doc({1048576, 16384}), m_factory(m_doc)
+ {
+ std::cout << path << std::endl;
+ orcus_xls_xml app(&m_factory);
+ app.read_file(path.data());
+ }
+
+ spreadsheet::document& get_doc()
+ {
+ return m_doc;
+ }
+
+ spreadsheet::import_factory& get_factory()
+ {
+ return m_factory;
+ }
+};
+
+void update_config(spreadsheet::document& doc, const std::string& path)
+{
+ try
+ {
+ spreadsheet::document_config cfg = doc.get_config();
+
+ yaml::document_tree config;
+ file_content content(path.data());
+ config.load(content.str());
+ yaml::const_node root = config.get_document_root(0);
+ std::vector<yaml::const_node> keys = root.keys();
+ for (size_t i = 0; i < keys.size(); ++i)
+ {
+ const yaml::const_node& key = keys[i];
+ if (key.type() == yaml::node_t::string && key.string_value() == "output-precision")
+ {
+ yaml::const_node child = root.child(i);
+ if (child.type() == yaml::node_t::number)
+ cfg.output_precision = child.numeric_value();
+ }
+ }
+
+ doc.set_config(cfg);
+ }
+ catch (const std::exception&)
+ {
+ // Do nothing.
+ }
+}
+
+void test_xls_xml_detection()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ for (const auto& dir : dirs)
+ {
+ fs::path filepath = dir / "input.xml";
+ file_content fc(filepath.string());
+ assert(!fc.empty());
+
+ format_t detected = detect(fc.str());
+ assert(detected == format_t::xls_xml);
+ }
+}
+
+void test_xls_xml_create_filter()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ ss::range_size_t ssize{1048576, 16384};
+ std::unique_ptr<ss::document> doc = std::make_unique<ss::document>(ssize);
+ ss::import_factory factory(*doc);
+
+ auto f = create_filter(format_t::xls_xml, &factory);
+ assert(f);
+ assert(f->get_name() == "xls-xml");
+}
+
+void test_xls_xml_import()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto verify = [](spreadsheet::document& doc, const fs::path& dir)
+ {
+ auto path = dir / "config.yaml";
+ update_config(doc, path.string());
+
+ // Dump the content of the model.
+ std::ostringstream os;
+ doc.dump_check(os);
+ std::string check = os.str();
+
+ // Check that against known control.
+ path = dir / "check.txt";
+ file_content control(path.string());
+
+ assert(!check.empty());
+ assert(!control.empty());
+
+ std::string_view s1(check.data(), check.size());
+ std::string_view s2 = control.str();
+ s1 = orcus::trim(s1);
+ s2 = orcus::trim(s2);
+
+ if (s1 != s2)
+ {
+ size_t offset = locate_first_different_char(s1, s2);
+ auto line1 = locate_line_with_offset(s1, offset);
+ auto line2 = locate_line_with_offset(s2, offset);
+ std::cout << "expected: " << line2.line << std::endl;
+ std::cout << "observed: " << line1.line << std::endl;
+ assert(!"content verification failed");
+ }
+ };
+
+ for (const auto& dir : dirs)
+ {
+ std::cout << dir << std::endl;
+
+ // Read the input.xml document.
+ fs::path filepath = dir / "input.xml";
+ std::unique_ptr<spreadsheet::document> doc = load_doc_from_filepath(filepath.string());
+ verify(*doc, dir);
+
+ doc = load_doc_from_stream(filepath.string());
+ verify(*doc, dir);
+ }
+}
+
+void test_xls_xml_merged_cells()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/merged-cells/input.xml");
+
+ const spreadsheet::sheet* sheet1 = doc->get_sheet("Sheet1");
+ assert(sheet1);
+
+ spreadsheet::range_t merge_range = sheet1->get_merge_cell_range(0, 1);
+ assert(merge_range.first.column == 1);
+ assert(merge_range.last.column == 2);
+ assert(merge_range.first.row == 0);
+ assert(merge_range.last.row == 0);
+
+ merge_range = sheet1->get_merge_cell_range(0, 3);
+ assert(merge_range.first.column == 3);
+ assert(merge_range.last.column == 5);
+ assert(merge_range.first.row == 0);
+ assert(merge_range.last.row == 0);
+
+ merge_range = sheet1->get_merge_cell_range(1, 0);
+ assert(merge_range.first.column == 0);
+ assert(merge_range.last.column == 0);
+ assert(merge_range.first.row == 1);
+ assert(merge_range.last.row == 2);
+
+ merge_range = sheet1->get_merge_cell_range(3, 0);
+ assert(merge_range.first.column == 0);
+ assert(merge_range.last.column == 0);
+ assert(merge_range.first.row == 3);
+ assert(merge_range.last.row == 5);
+
+ merge_range = sheet1->get_merge_cell_range(2, 2);
+ assert(merge_range.first.column == 2);
+ assert(merge_range.last.column == 5);
+ assert(merge_range.first.row == 2);
+ assert(merge_range.last.row == 5);
+}
+
+void test_xls_xml_date_time()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/date-time/input.xml");
+
+ const spreadsheet::sheet* sheet1 = doc->get_sheet("Sheet1");
+ assert(sheet1);
+
+ // B1 contains date-only value.
+ date_time_t dt = sheet1->get_date_time(0, 1);
+ assert(dt == date_time_t(2016, 12, 14));
+
+ // B2 contains date-time value with no fraction seconds.
+ dt = sheet1->get_date_time(1, 1);
+ assert(dt == date_time_t(2002, 2, 3, 12, 34, 45));
+
+ // B3 contains date-time value with fraction second (1992-03-04 08:34:33.555)
+ dt = sheet1->get_date_time(2, 1);
+ assert(dt.year == 1992);
+ assert(dt.month == 3);
+ assert(dt.day == 4);
+ assert(dt.hour == 8);
+ assert(dt.minute == 34);
+ assert(std::floor(dt.second) == 33.0);
+
+ // Evalutate the fraction second as milliseconds.
+ double ms = dt.second * 1000.0;
+ ms -= std::floor(dt.second) * 1000.0;
+ ms = std::round(ms);
+ assert(ms == 555.0);
+}
+
+void test_xls_xml_bold_and_italic()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/bold-and-italic/input.xml");
+
+ const spreadsheet::sheet* sheet1 = doc->get_sheet("Sheet1");
+ assert(sheet1);
+
+ const spreadsheet::shared_strings& ss = doc->get_shared_strings();
+
+ const spreadsheet::styles& styles = doc->get_styles();
+
+ // A1 contains unformatted text.
+ size_t si = sheet1->get_string_identifier(0, 0);
+ const std::string* sp = ss.get_string(si);
+ assert(sp);
+ assert(*sp == "Normal Text");
+
+ // A2 contains bold text.
+ si = sheet1->get_string_identifier(1, 0);
+ sp = ss.get_string(si);
+ assert(sp);
+ assert(*sp == "Bold Text");
+
+ size_t xfi = sheet1->get_cell_format(1, 0);
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xfi);
+ assert(cf);
+ const spreadsheet::font_t* font = styles.get_font(cf->font);
+ assert(font);
+ assert(*font->bold);
+ assert(!*font->italic);
+
+ // A3 contains italic text.
+ si = sheet1->get_string_identifier(2, 0);
+ sp = ss.get_string(si);
+ assert(sp);
+ assert(*sp == "Italic Text");
+
+ xfi = sheet1->get_cell_format(2, 0);
+ cf = styles.get_cell_format(xfi);
+ assert(cf);
+ font = styles.get_font(cf->font);
+ assert(font);
+ assert(!*font->bold);
+ assert(*font->italic);
+
+ // A4 contains bold and italic text.
+ si = sheet1->get_string_identifier(3, 0);
+ sp = ss.get_string(si);
+ assert(sp);
+ assert(*sp == "Bold and Italic Text");
+
+ xfi = sheet1->get_cell_format(3, 0);
+ cf = styles.get_cell_format(xfi);
+ assert(cf);
+ font = styles.get_font(cf->font);
+ assert(font);
+ assert(font->bold);
+ assert(font->italic);
+
+ // A5 contains a mixed format text.
+ si = sheet1->get_string_identifier(4, 0);
+ sp = ss.get_string(si);
+ assert(sp);
+ assert(*sp == "Bold and Italic mixed");
+
+ // The string contains 4 formatted segments.
+ const spreadsheet::format_runs_t* fmt_runs = ss.get_format_runs(si);
+ assert(fmt_runs);
+ assert(fmt_runs->size() == 4);
+
+ // First formatted segment is bold.
+ const spreadsheet::format_run* fmt_run = &fmt_runs->at(0);
+ assert(fmt_run->pos == 0);
+ assert(fmt_run->size == 4);
+ assert(fmt_run->bold);
+ assert(!fmt_run->italic);
+
+ // Third formatted segment is italic.
+ fmt_run = &fmt_runs->at(2);
+ assert(fmt_run->pos == 9);
+ assert(fmt_run->size == 6);
+ assert(!fmt_run->bold);
+ assert(fmt_run->italic);
+}
+
+void test_xls_xml_colored_text()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/colored-text/input.xml");
+
+ const spreadsheet::sheet* sheet1 = doc->get_sheet("ColoredText");
+ assert(sheet1);
+
+ const spreadsheet::shared_strings& ss = doc->get_shared_strings();
+
+ const spreadsheet::styles& styles = doc->get_styles();
+
+ // Column A contains colored cells.
+
+ struct check
+ {
+ spreadsheet::row_t row;
+ spreadsheet::color_elem_t red;
+ spreadsheet::color_elem_t green;
+ spreadsheet::color_elem_t blue;
+ std::string text;
+ };
+
+ std::vector<check> checks = {
+ { 1, 0xC0, 0x00, 0x00, "Dark Red" },
+ { 2, 0xFF, 0x00, 0x00, "Red" },
+ { 3, 0xFF, 0xC0, 0x00, "Orange" },
+ { 4, 0xFF, 0xFF, 0x00, "Yellow" },
+ { 5, 0x92, 0xD0, 0x50, "Light Green" },
+ { 6, 0x00, 0xB0, 0x50, "Green" },
+ { 7, 0x00, 0xB0, 0xF0, "Light Blue" },
+ { 8, 0x00, 0x70, 0xC0, "Blue" },
+ { 9, 0x00, 0x20, 0x60, "Dark Blue" },
+ { 10, 0x70, 0x30, 0xA0, "Purple" },
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xfi = sheet1->get_cell_format(c.row, 0);
+ const spreadsheet::cell_format_t* xf = styles.get_cell_format(xfi);
+ assert(xf);
+
+ const spreadsheet::font_t* font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->color);
+ assert(font->color.value().red == c.red);
+ assert(font->color.value().green == c.green);
+ assert(font->color.value().blue == c.blue);
+
+ size_t si = sheet1->get_string_identifier(c.row, 0);
+ const std::string* s = ss.get_string(si);
+ assert(s);
+ assert(*s == c.text);
+ }
+
+ // Cell B2 contains mix-colored text.
+ size_t si = sheet1->get_string_identifier(1, 1);
+ const std::string* s = ss.get_string(si);
+ assert(s);
+ assert(*s == "Red and Blue");
+ const spreadsheet::format_runs_t* fmt_runs = ss.get_format_runs(si);
+ assert(fmt_runs);
+
+ // There should be 2 segments that are color-formatted and one that is not.
+ assert(fmt_runs->size() == 3);
+
+ // The 'Red' segment should be in red color.
+ const spreadsheet::format_run* fmt = &fmt_runs->at(0);
+ assert(fmt->color.alpha == 0xFF);
+ assert(fmt->color.red == 0xFF);
+ assert(fmt->color.green == 0);
+ assert(fmt->color.blue == 0);
+ assert(fmt->pos == 0);
+ assert(fmt->size == 3);
+
+ // The 'Blue' segment should be in blue color.
+ fmt = &fmt_runs->at(2);
+ assert(fmt->color.alpha == 0xFF);
+ assert(fmt->color.red == 0);
+ assert(fmt->color.green == 0x70);
+ assert(fmt->color.blue == 0xC0);
+ assert(fmt->pos == 8);
+ assert(fmt->size == 4);
+}
+
+void test_xls_xml_formatted_text_basic()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/formatted-text/basic.xml");
+ const auto& styles_pool = doc->get_styles();
+
+ auto get_font = [&styles_pool](const ss::sheet& sh, ss::row_t row, ss::col_t col)
+ {
+ std::size_t xf = sh.get_cell_format(row, col);
+
+ const ss::cell_format_t* cell_format = styles_pool.get_cell_format(xf);
+ assert(cell_format);
+
+ const ss::font_t* font = styles_pool.get_font(cell_format->font);
+ assert(font);
+
+ return font;
+ };
+
+ auto check_cell_bold = [&get_font](const ss::sheet& sh, ss::row_t row, ss::col_t col, bool expected)
+ {
+ const ss::font_t* font = get_font(sh, row, col);
+
+ if (expected)
+ {
+ if (font->bold && *font->bold)
+ return true;
+
+ std::cerr << "expected to be bold but it is not "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ else
+ {
+ if (!font->bold || !*font->bold)
+ return true;
+
+ std::cerr << "expected to be non-bold but it is bold "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ };
+
+ auto check_cell_italic = [&get_font](const ss::sheet& sh, ss::row_t row, ss::col_t col, bool expected)
+ {
+ const ss::font_t* font = get_font(sh, row, col);
+
+ if (expected)
+ {
+ if (font->italic && *font->italic)
+ return true;
+
+ std::cerr << "expected to be italic but it is not "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ else
+ {
+ if (!font->italic || !*font->italic)
+ return true;
+
+ std::cerr << "expected to be non-italic but it is italic "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ };
+
+ auto check_cell_text = [&doc](const ss::sheet& sh, ss::row_t row, ss::col_t col, std::string_view expected)
+ {
+ const auto& sstrings = doc->get_shared_strings();
+
+ std::size_t si = sh.get_string_identifier(row, col);
+ const std::string* s = sstrings.get_string(si);
+ if (!s)
+ {
+ std::cerr << "expected='" << expected << "'; actual=<none> "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+
+ if (*s == expected)
+ return true;
+
+ std::cerr << "expected='" << expected << "'; actual='" << *s << "' "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ };
+
+ {
+ const spreadsheet::sheet* sheet = doc->get_sheet("Text Properties");
+ assert(sheet);
+
+ ss::row_t row = 0;
+ ss::col_t col = 0;
+
+ // A1 - unformatted
+ assert(check_cell_text(*sheet, row, col, "Normal Text"));
+ assert(check_cell_bold(*sheet, row, col, false));
+ assert(check_cell_italic(*sheet, row, col, false));
+
+ // A2 - bold
+ row = 1;
+ assert(check_cell_text(*sheet, row, col, "Bold Text"));
+ assert(check_cell_bold(*sheet, row, col, true));
+ assert(check_cell_italic(*sheet, row, col, false));
+
+ // A3 - italic
+ row = 2;
+ assert(check_cell_text(*sheet, row, col, "Italic Text"));
+ assert(check_cell_bold(*sheet, row, col, false));
+ assert(check_cell_italic(*sheet, row, col, true));
+
+ // A4 - bold and italic
+ row = 3;
+ assert(check_cell_text(*sheet, row, col, "Bold and Italic Text"));
+ assert(check_cell_bold(*sheet, row, col, true));
+ assert(check_cell_italic(*sheet, row, col, true));
+
+ // A5 - bold and italic mixed. Excel creates format runs even for
+ // non-formatted segments.
+ row = 4;
+ assert(check_cell_text(*sheet, row, col, "Bold and Italic mixed"));
+
+ std::size_t si = sheet->get_string_identifier(row, col);
+ const ss::format_runs_t* runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 4u); // only 0 and 2 are formatted
+
+ // Bold and ...
+ // ^^^^
+ assert(runs->at(0).pos == 0);
+ assert(runs->at(0).size == 4);
+ assert(runs->at(0).bold);
+ assert(!runs->at(0).italic);
+
+ // Bold and Italic
+ // ^^^^^^
+ assert(runs->at(2).pos == 9);
+ assert(runs->at(2).size == 6);
+ assert(!runs->at(2).bold);
+ assert(runs->at(2).italic);
+
+ // A6
+ row = 5;
+ assert(check_cell_text(*sheet, row, col, "Bold base with non-bold part"));
+ assert(check_cell_bold(*sheet, row, col, true));
+ assert(check_cell_italic(*sheet, row, col, false));
+
+ si = sheet->get_string_identifier(row, col);
+ runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 3u);
+
+ assert(runs->at(0).pos == 0);
+ assert(runs->at(0).size == 15);
+ assert(runs->at(0).bold);
+
+ assert(runs->at(1).pos == 15);
+ assert(runs->at(1).size == 8);
+ assert(!runs->at(1).bold);
+
+ assert(runs->at(2).pos == 23);
+ assert(runs->at(2).size == 5);
+ assert(runs->at(2).bold);
+
+ // A7 - TODO: check format
+ row = 6;
+ assert(check_cell_text(*sheet, row, col, "Only partially underlined"));
+
+ // A8
+ row = 7;
+ assert(check_cell_text(*sheet, row, col, "All Underlined"));
+ const ss::font_t* font = get_font(*sheet, row, col);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line);
+
+ // A9
+ row = 8;
+ assert(check_cell_text(*sheet, row, col, "Bold and underlined"));
+ assert(check_cell_bold(*sheet, row, col, true));
+ font = get_font(*sheet, row, col);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line);
+
+ row = 9;
+ assert(check_cell_text(*sheet, row, col, "All Strikethrough"));
+ // TODO: check for strikethrough in cell
+
+ // A11:A15 - TODO: check format
+ row = 10;
+ assert(check_cell_text(*sheet, row, col, "Partial strikethrough"));
+ row = 11;
+ assert(check_cell_text(*sheet, row, col, "Superscript"));
+ row = 12;
+ assert(check_cell_text(*sheet, row, col, "Subscript"));
+ row = 13;
+ assert(check_cell_text(*sheet, row, col, "x2 + y2 = 102"));
+ row = 14;
+ assert(check_cell_text(*sheet, row, col, "xi = yi + zi"));
+ }
+
+ {
+ const spreadsheet::sheet* sheet = doc->get_sheet("Fonts");
+ assert(sheet);
+
+ struct check
+ {
+ ss::row_t row;
+ std::string_view font_name;
+ double font_unit;
+ };
+
+ check checks[] = {
+ { 0, "Calibri Light", 12.0 },
+ { 1, "Arial", 18.0 },
+ { 2, "Times New Roman", 14.0 },
+ { 3, "Consolas", 9.0 },
+ { 4, "Bookman Old Style", 20.0 },
+ };
+
+ for (const auto& c : checks)
+ {
+ std::size_t xf = sheet->get_cell_format(c.row, 0);
+ const ss::cell_format_t* cell_format = styles_pool.get_cell_format(xf);
+ assert(cell_format);
+ const ss::font_t* font = styles_pool.get_font(cell_format->font);
+ assert(font);
+ assert(font->name == c.font_name);
+ assert(font->size == c.font_unit);
+
+ // Columns A and B should have the same font.
+ xf = sheet->get_cell_format(c.row, 1);
+ cell_format = styles_pool.get_cell_format(xf);
+ assert(cell_format);
+ font = styles_pool.get_font(cell_format->font);
+ assert(font);
+ assert(font->name == c.font_name);
+ assert(font->size == c.font_unit);
+ }
+ }
+
+ {
+ const spreadsheet::sheet* sheet = doc->get_sheet("Mixed Fonts");
+ assert(sheet);
+
+ // A1
+ ss::row_t row = 0;
+ ss::col_t col = 0;
+ assert(check_cell_text(*sheet, row, col, "C++ has class and struct as keywords."));
+
+ // Base cell has Serif 12-pt font applied
+ auto xf = sheet->get_cell_format(row, col);
+ const ss::cell_format_t* fmt = styles_pool.get_cell_format(xf);
+ assert(fmt);
+ const ss::font_t* font = styles_pool.get_font(fmt->font);
+ assert(font);
+ assert(font->name == "Calibri");
+ assert(font->size == 11.0);
+
+ // Two segments has Liberation Mono font applied (runs 1 and 3) whereas
+ // runs 0, 2 and 4 are unformatted.
+ std::size_t si = sheet->get_string_identifier(row, col);
+ const ss::format_runs_t* runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 5u);
+
+ // C++ has class ...
+ // ^^^^^
+ assert(runs->at(1).pos == 8);
+ assert(runs->at(1).size == 5);
+ assert(runs->at(1).font == "Liberation Mono");
+
+ // ... and struct as ...
+ // ^^^^^^
+ assert(runs->at(3).pos == 18);
+ assert(runs->at(3).size == 6);
+ assert(runs->at(3).font == "Liberation Mono");
+
+ // A2
+ row = 1;
+ assert(check_cell_text(*sheet, row, col, "Text with 12-point font, 24-point font, and 36-point font mixed."));
+ si = sheet->get_string_identifier(row, col);
+ runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 10u);
+
+ // with 12-point font, ...
+ // ^^
+ assert(runs->at(1).pos == 10);
+ assert(runs->at(1).size == 2);
+ assert(runs->at(1).font_size == 12.0f);
+ assert(runs->at(1).color == ss::color_t(0xFF, 0xFF, 0, 0)); // red
+
+ // with 12-point font, ...
+ // ^^^^^^
+ assert(runs->at(2).pos == 12);
+ assert(runs->at(2).size == 6);
+ assert(runs->at(2).font_size == 12.0f);
+
+ // 24-point font,
+ // ^^
+ assert(runs->at(4).pos == 25);
+ assert(runs->at(4).size == 2);
+ assert(runs->at(4).font_size == 24.0f);
+ assert(runs->at(4).color == ss::color_t(0xFF, 0xFF, 0, 0)); // red
+
+ // 24-point font,
+ // ^^^^^^
+ assert(runs->at(5).pos == 27);
+ assert(runs->at(5).size == 6);
+ assert(runs->at(5).font_size == 24.0f);
+
+ // and 36-point font
+ // ^^
+ assert(runs->at(7).pos == 44);
+ assert(runs->at(7).size == 2);
+ assert(runs->at(7).font_size == 36.0f);
+ assert(runs->at(7).color == ss::color_t(0xFF, 0xFF, 0, 0)); // red
+
+ // and 36-point font
+ // ^^^^^^
+ assert(runs->at(8).pos == 46);
+ assert(runs->at(8).size == 6);
+ assert(runs->at(8).font_size == 36.0f);
+ }
+}
+
+void test_xls_xml_column_width_row_height()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ struct cw_check
+ {
+ spreadsheet::col_t col;
+ double width;
+ int decimals;
+ };
+
+ struct rh_check
+ {
+ spreadsheet::row_t row;
+ double height;
+ int decimals;
+ };
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/column-width-row-height/input.xml");
+
+ // Column widths and row heights are stored in twips. Convert them to
+ // points so that we can compare them with the values stored in the source
+ // file.
+
+ {
+ // Sheet1
+ const spreadsheet::sheet* sheet = doc->get_sheet(0);
+ assert(sheet);
+
+ std::vector<cw_check> cw_checks =
+ {
+ { 1, 56.25, 2 },
+ { 2, 82.50, 2 },
+ { 3, 108.75, 2 },
+ { 5, 66.75, 2 },
+ { 6, 66.75, 2 },
+ { 7, 66.75, 2 },
+ { 10, 119.25, 2 },
+ { 11, 119.25, 2 },
+ };
+
+ for (const cw_check& check : cw_checks)
+ {
+ spreadsheet::col_width_t cw = sheet->get_col_width(check.col, nullptr, nullptr);
+ double pt = convert(cw, length_unit_t::twip, length_unit_t::point);
+ test::verify_value_to_decimals(__FILE__, __LINE__, check.width, pt, check.decimals);
+ }
+
+ std::vector<rh_check> rh_checks =
+ {
+ { 2, 20.0, 0 },
+ { 3, 30.0, 0 },
+ { 4, 40.0, 0 },
+ { 5, 50.0, 0 },
+ { 7, 25.0, 0 },
+ { 8, 25.0, 0 },
+ { 9, 25.0, 0 },
+ { 12, 35.0, 0 },
+ { 13, 35.0, 0 },
+ };
+
+ for (const rh_check& check : rh_checks)
+ {
+ spreadsheet::row_height_t rh = sheet->get_row_height(check.row, nullptr, nullptr);
+ double pt = convert(rh, length_unit_t::twip, length_unit_t::point);
+ test::verify_value_to_decimals(__FILE__, __LINE__, check.height, pt, check.decimals);
+ }
+ }
+
+ {
+ // Sheet2
+ const spreadsheet::sheet* sheet = doc->get_sheet(1);
+ assert(sheet);
+
+ std::vector<cw_check> cw_checks =
+ {
+ { 1, 119.25, 2 },
+ { 3, 234.75, 2 },
+ };
+
+ for (const cw_check& check : cw_checks)
+ {
+ spreadsheet::col_width_t cw = sheet->get_col_width(check.col, nullptr, nullptr);
+ double pt = convert(cw, length_unit_t::twip, length_unit_t::point);
+ test::verify_value_to_decimals(__FILE__, __LINE__, check.width, pt, check.decimals);
+ }
+
+ std::vector<rh_check> rh_checks =
+ {
+ { 2, 40.0, 0 },
+ { 4, 60.0, 0 },
+ };
+
+ for (const rh_check& check : rh_checks)
+ {
+ spreadsheet::row_height_t rh = sheet->get_row_height(check.row, nullptr, nullptr);
+ double pt = convert(rh, length_unit_t::twip, length_unit_t::point);
+ test::verify_value_to_decimals(__FILE__, __LINE__, check.height, pt, check.decimals);
+ }
+ }
+}
+
+void test_xls_xml_background_fill()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/background-color/standard.xml");
+
+ spreadsheet::styles& styles = doc->get_styles();
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ spreadsheet::row_t row;
+ spreadsheet::col_t col;
+ spreadsheet::fill_pattern_t pattern_type;
+ spreadsheet::color_t fg_color;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 0, spreadsheet::fill_pattern_t::solid, { 255, 192, 0, 0 } }, // A2 - dark red
+ { 2, 0, spreadsheet::fill_pattern_t::solid, { 255, 255, 0, 0 } }, // A3 - red
+ { 3, 0, spreadsheet::fill_pattern_t::solid, { 255, 255, 192, 0 } }, // A4 - orange
+ { 4, 0, spreadsheet::fill_pattern_t::solid, { 255, 255, 255, 0 } }, // A5 - yellow
+ { 5, 0, spreadsheet::fill_pattern_t::solid, { 255, 146, 208, 80 } }, // A6 - light green
+ { 6, 0, spreadsheet::fill_pattern_t::solid, { 255, 0, 176, 80 } }, // A7 - green
+ { 7, 0, spreadsheet::fill_pattern_t::solid, { 255, 0, 176, 240 } }, // A8 - light blue
+ { 8, 0, spreadsheet::fill_pattern_t::solid, { 255, 0, 112, 192 } }, // A9 - blue
+ { 9, 0, spreadsheet::fill_pattern_t::solid, { 255, 0, 32, 96 } }, // A10 - dark blue
+ { 10, 0, spreadsheet::fill_pattern_t::solid, { 255, 112, 48, 160 } }, // A11 - purple
+ };
+
+ spreadsheet::color_t color_white(255, 255, 255, 255);
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+
+ const spreadsheet::fill_t* fill_data = styles.get_fill(cf->fill);
+ assert(fill_data);
+ assert(fill_data->pattern_type == c.pattern_type);
+ assert(fill_data->fg_color == c.fg_color);
+
+ // The font colors are all white in the colored cells.
+ const spreadsheet::font_t* font_data = styles.get_font(cf->font);
+ assert(font_data);
+
+ assert(font_data->color == color_white);
+ }
+}
+
+void test_xls_xml_named_colors()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ constexpr std::string_view paths[] = {
+ SRCDIR"/test/xls-xml/named-colors/input.xml",
+ SRCDIR"/test/xls-xml/named-colors/input-upper.xml"
+ };
+
+ for (auto path : paths)
+ {
+ std::cout << path << std::endl;
+ std::unique_ptr<spreadsheet::document> doc = load_doc_from_filepath(std::string{path});
+
+ spreadsheet::styles& styles = doc->get_styles();
+ const ixion::model_context& model = doc->get_model_context();
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ for (ss::row_t row = 1; row < 141; ++row)
+ {
+ // Column B stores the expected RGB value in hex.
+ size_t sid = model.get_string_identifier(ixion::abs_address_t(sh->get_index(), row, 1));
+ const std::string* s = model.get_string(sid);
+ assert(s);
+ spreadsheet::color_rgb_t expected = spreadsheet::to_color_rgb(*s);
+
+ size_t xf = sh->get_cell_format(row, 0);
+ const ss::fill_t* fill_data = styles.get_fill(xf);
+ assert(fill_data->fg_color);
+ const ss::color_t& actual = *fill_data->fg_color;
+ assert(expected.red == actual.red);
+ assert(expected.green == actual.green);
+ assert(expected.blue == actual.blue);
+ }
+ }
+}
+
+void test_xls_xml_text_alignment()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/text-alignment/input.xml");
+
+ spreadsheet::styles& styles = doc->get_styles();
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ spreadsheet::row_t row;
+ spreadsheet::col_t col;
+ bool apply_align;
+ spreadsheet::hor_alignment_t hor_align;
+ spreadsheet::ver_alignment_t ver_align;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 2, true, spreadsheet::hor_alignment_t::unknown, spreadsheet::ver_alignment_t::bottom }, // C2
+ { 2, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::bottom }, // C3
+ { 3, 2, true, spreadsheet::hor_alignment_t::center, spreadsheet::ver_alignment_t::bottom }, // C4
+ { 4, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::bottom }, // C5
+ { 5, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::bottom }, // C6
+ { 6, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::bottom }, // C7
+ { 7, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::bottom }, // C8
+ { 8, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::bottom }, // C9
+ { 9, 2, true, spreadsheet::hor_alignment_t::unknown, spreadsheet::ver_alignment_t::middle }, // C10
+ { 10, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::middle }, // C11
+ { 11, 2, true, spreadsheet::hor_alignment_t::center, spreadsheet::ver_alignment_t::middle }, // C12
+ { 12, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::middle }, // C13
+ { 13, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::middle }, // C14
+ { 14, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::middle }, // C15
+ { 15, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::middle }, // C16
+ { 16, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::middle }, // C17
+ { 17, 2, true, spreadsheet::hor_alignment_t::unknown, spreadsheet::ver_alignment_t::top }, // C18
+ { 18, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::top }, // C19
+ { 19, 2, true, spreadsheet::hor_alignment_t::center, spreadsheet::ver_alignment_t::top }, // C20
+ { 20, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::top }, // C21
+ { 21, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::top }, // C22
+ { 22, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::top }, // C23
+ { 23, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::top }, // C24
+ { 24, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::top }, // C25
+ { 25, 2, true, spreadsheet::hor_alignment_t::unknown, spreadsheet::ver_alignment_t::justified }, // C26
+ { 26, 2, true, spreadsheet::hor_alignment_t::justified, spreadsheet::ver_alignment_t::bottom }, // C27
+ { 27, 2, true, spreadsheet::hor_alignment_t::distributed, spreadsheet::ver_alignment_t::distributed }, // C28
+ };
+
+ for (const check& c : checks)
+ {
+ std::cout << "row=" << c.row << "; col=" << c.col << std::endl;
+ size_t xf = sh->get_cell_format(c.row, c.col);
+
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(c.apply_align == cf->apply_alignment);
+
+ if (!cf->apply_alignment)
+ continue;
+
+ assert(c.hor_align == cf->hor_align);
+ assert(c.ver_align == cf->ver_align);
+ }
+}
+
+void test_xls_xml_cell_borders_single_cells()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/borders/single-cells.xml");
+
+ spreadsheet::styles& styles = doc->get_styles();
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ spreadsheet::row_t row;
+ spreadsheet::col_t col;
+ spreadsheet::border_style_t style;
+ };
+
+ std::vector<check> checks =
+ {
+ { 3, 1, spreadsheet::border_style_t::hair },
+ { 5, 1, spreadsheet::border_style_t::dotted },
+ { 7, 1, spreadsheet::border_style_t::dash_dot_dot },
+ { 9, 1, spreadsheet::border_style_t::dash_dot },
+ { 11, 1, spreadsheet::border_style_t::dashed },
+ { 13, 1, spreadsheet::border_style_t::thin },
+ { 1, 3, spreadsheet::border_style_t::medium_dash_dot_dot },
+ { 3, 3, spreadsheet::border_style_t::slant_dash_dot },
+ { 5, 3, spreadsheet::border_style_t::medium_dash_dot },
+ { 7, 3, spreadsheet::border_style_t::medium_dashed },
+ { 9, 3, spreadsheet::border_style_t::medium },
+ { 11, 3, spreadsheet::border_style_t::thick },
+ { 13, 3, spreadsheet::border_style_t::double_border },
+ };
+
+ for (const check& c : checks)
+ {
+ std::cout << "(row: " << c.row << "; col: " << c.col << "; expected: " << int(c.style) << ")" << std::endl;
+ size_t xf = sh->get_cell_format(c.row, c.col);
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const spreadsheet::border_t* border = styles.get_border(cf->border);
+ assert(border);
+ assert(border->top.style == c.style);
+ assert(border->bottom.style == c.style);
+ assert(border->left.style == c.style);
+ assert(border->right.style == c.style);
+ }
+}
+
+void test_xls_xml_cell_borders_directions()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/borders/directions.xml");
+
+ spreadsheet::styles& styles = doc->get_styles();
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ spreadsheet::row_t row;
+ spreadsheet::col_t col;
+ spreadsheet::border_direction_t dir;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 1, ss::border_direction_t::top },
+ { 3, 1, ss::border_direction_t::left },
+ { 5, 1, ss::border_direction_t::right },
+ { 7, 1, ss::border_direction_t::bottom },
+ { 9, 1, ss::border_direction_t::diagonal_tl_br },
+ { 11, 1, ss::border_direction_t::diagonal_bl_tr },
+ { 13, 1, ss::border_direction_t::diagonal },
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+ const ss::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const ss::border_t* border = styles.get_border(cf->border);
+ assert(border);
+
+ switch (c.dir)
+ {
+ case ss::border_direction_t::top:
+ assert(border->top.style);
+ assert(*border->top.style == ss::border_style_t::thin);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(!border->diagonal_tl_br.style);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case ss::border_direction_t::left:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(border->left.style);
+ assert(*border->left.style == ss::border_style_t::thin);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(!border->diagonal_tl_br.style);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case ss::border_direction_t::right:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(border->right.style);
+ assert(*border->right.style == ss::border_style_t::thin);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(!border->diagonal_tl_br.style);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case ss::border_direction_t::bottom:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(border->bottom.style);
+ assert(*border->bottom.style == ss::border_style_t::thin);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(!border->diagonal_tl_br.style);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case spreadsheet::border_direction_t::diagonal:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(border->diagonal_bl_tr.style);
+ assert(*border->diagonal_bl_tr.style == ss::border_style_t::thin);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(border->diagonal_tl_br.style);
+ assert(*border->diagonal_tl_br.style == ss::border_style_t::thin);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case spreadsheet::border_direction_t::diagonal_tl_br:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(border->diagonal_tl_br.style);
+ assert(*border->diagonal_tl_br.style == ss::border_style_t::thin);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ case spreadsheet::border_direction_t::diagonal_bl_tr:
+ assert(!border->top.style);
+ assert(!border->top.border_color);
+ assert(!border->top.border_width);
+ assert(!border->bottom.style);
+ assert(!border->bottom.border_color);
+ assert(!border->bottom.border_width);
+ assert(!border->left.style);
+ assert(!border->left.border_color);
+ assert(!border->left.border_width);
+ assert(!border->right.style);
+ assert(!border->right.border_color);
+ assert(!border->right.border_width);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal.border_color);
+ assert(!border->diagonal.border_width);
+ assert(border->diagonal_bl_tr.style);
+ assert(*border->diagonal_bl_tr.style == ss::border_style_t::thin);
+ assert(!border->diagonal_bl_tr.border_color);
+ assert(!border->diagonal_bl_tr.border_width);
+ assert(!border->diagonal_tl_br.style);
+ assert(!border->diagonal_tl_br.border_color);
+ assert(!border->diagonal_tl_br.border_width);
+ break;
+ default:
+ assert(!"unhandled direction!");
+ }
+ }
+}
+
+void test_xls_xml_cell_borders_colors()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ using spreadsheet::color_t;
+ using spreadsheet::border_style_t;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/borders/colors.xml");
+
+ spreadsheet::styles& styles = doc->get_styles();
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ spreadsheet::row_t row;
+ spreadsheet::col_t col;
+ color_t color;
+ };
+
+ std::vector<check> checks =
+ {
+ { 2, 1, color_t(0xFF, 0xFF, 0, 0) }, // B3 - red
+ { 3, 1, color_t(0xFF, 0, 0x70, 0xC0) }, // B4 - blue
+ { 4, 1, color_t(0xFF, 0, 0xB0, 0x50) }, // B5 - green
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col); // B3
+
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const spreadsheet::border_t* border = styles.get_border(cf->border);
+ assert(border);
+
+ assert(!border->left.style);
+ assert(border->right.style);
+ assert(*border->right.style == border_style_t::thick);
+ assert(!border->top.style);
+ assert(!border->bottom.style);
+
+ assert(border->right.border_color == c.color);
+ }
+
+ // B7 contains yellow left border, purple right border, and light blue
+ // diagonal borders.
+
+ size_t xf = sh->get_cell_format(6, 1); // B7
+
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const spreadsheet::border_t* border = styles.get_border(cf->border);
+ assert(border);
+
+ assert(border->left.style == border_style_t::thick);
+ assert(border->left.border_color == color_t(0xFF, 0xFF, 0xFF, 0)); // yellow
+
+ assert(border->right.style == border_style_t::thick);
+ assert(border->right.border_color == color_t(0xFF, 0x70, 0x30, 0xA0)); // purple
+
+ assert(border->diagonal_bl_tr.style == border_style_t::thick);
+ assert(border->diagonal_bl_tr.border_color == color_t(0xFF, 0x00, 0xB0, 0xF0)); // light blue
+
+ assert(border->diagonal_tl_br.style == border_style_t::thick);
+ assert(border->diagonal_tl_br.border_color == color_t(0xFF, 0x00, 0xB0, 0xF0)); // light blue
+
+ // B7 also contains multi-line string. Test that as well.
+ ixion::model_context& model = doc->get_model_context();
+ ixion::string_id_t sid = model.get_string_identifier(ixion::abs_address_t(0,6,1));
+ const std::string* s = model.get_string(sid);
+ assert(s);
+ assert(*s == "<- Yellow\nPurple ->\nLight Blue \\");
+}
+
+void test_xls_xml_hidden_rows_columns()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/hidden-rows-columns/input.xml");
+
+ spreadsheet::sheet* sh = doc->get_sheet("Hidden Rows");
+ assert(sh);
+
+ spreadsheet::row_t row_start = -1, row_end = -1;
+
+ // Row 1 is visible.
+ assert(!sh->is_row_hidden(0, &row_start, &row_end));
+ assert(row_start == 0);
+ assert(row_end == 1); // the end position is non-inclusive.
+
+ // Rows 2-3 are hidden.
+ assert(sh->is_row_hidden(1, &row_start, &row_end));
+ assert(row_start == 1);
+ assert(row_end == 3); // the end position is non-inclusive.
+
+ // Row 4 is visible.
+ assert(!sh->is_row_hidden(3, &row_start, &row_end));
+ assert(row_start == 3);
+ assert(row_end == 4); // the end position is non-inclusive.
+
+ // Row 5 is hidden.
+ assert(sh->is_row_hidden(4, &row_start, &row_end));
+ assert(row_start == 4);
+ assert(row_end == 5); // the end position is non-inclusive.
+
+ // Rows 6-8 are visible.
+ assert(!sh->is_row_hidden(5, &row_start, &row_end));
+ assert(row_start == 5);
+ assert(row_end == 8); // the end position is non-inclusive.
+
+ // Row 9 is hidden.
+ assert(sh->is_row_hidden(8, &row_start, &row_end));
+ assert(row_start == 8);
+ assert(row_end == 9); // the end position is non-inclusive.
+
+ // The rest of the rows are visible.
+ assert(!sh->is_row_hidden(9, &row_start, &row_end));
+ assert(row_start == 9);
+ assert(row_end == doc->get_sheet_size().rows); // the end position is non-inclusive.
+
+ sh = doc->get_sheet("Hidden Columns");
+ assert(sh);
+
+ spreadsheet::col_t col_start = -1, col_end = -1;
+
+ // Columns A-B are visible.
+ assert(!sh->is_col_hidden(0, &col_start, &col_end));
+ assert(col_start == 0);
+ assert(col_end == 2); // non-inclusive
+
+ // Columns C-E are hidden.
+ assert(sh->is_col_hidden(2, &col_start, &col_end));
+ assert(col_start == 2);
+ assert(col_end == 6); // non-inclusive
+
+ // Columns G-J are visible.
+ assert(!sh->is_col_hidden(6, &col_start, &col_end));
+ assert(col_start == 6);
+ assert(col_end == 10); // non-inclusive
+
+ // Column K is hidden.
+ assert(sh->is_col_hidden(10, &col_start, &col_end));
+ assert(col_start == 10);
+ assert(col_end == 11); // non-inclusive
+
+ // The rest of the columns are all visible.
+ assert(!sh->is_col_hidden(11, &col_start, &col_end));
+ assert(col_start == 11);
+ assert(col_end == doc->get_sheet_size().columns); // non-inclusive
+}
+
+void test_xls_xml_character_set()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ doc_loader loader(SRCDIR"/test/xls-xml/character-set/input.xml");
+ assert(loader.get_factory().get_character_set() == character_set_t::windows_1252);
+}
+
+void test_xls_xml_number_format()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ doc_loader loader(SRCDIR"/test/xls-xml/number-format/date-time.xml");
+
+ const spreadsheet::document& doc = loader.get_doc();
+ const spreadsheet::styles& styles = doc.get_styles();
+
+ const spreadsheet::sheet* sh = doc.get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ ss::row_t row;
+ ss::col_t col;
+ std::string_view expected;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 1, "[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy" },
+ { 2, 1, "[ENG][$-409]mmmm\\ d\\,\\ yyyy;@" },
+ { 3, 1, "m/d/yy;@" },
+ { 4, 1, "m/d/yyyy h:mm" }, // General Date
+ { 5, 1, "d-mmm-yy" }, // Medium Date
+ { 6, 1, "m/d/yyyy" }, // Short Date
+ { 7, 1, "h:mm:ss AM/PM" }, // Long Time
+ { 8, 1, "h:mm AM/PM" }, // Medium Time
+ { 9, 1, "h:mm" }, // Short Time
+ { 10, 1, "0.00" }, // Fixed
+ { 11, 1, "#,##0.00" }, // Standard
+ { 12, 1, "0.00%" }, // Percent
+ { 13, 1, "0.00E+00" }, // Scientific
+ { 14, 1, "\"Yes\";\"Yes\";\"No\"" }, // Yes/No
+ { 15, 1, "\"True\";\"True\";\"False\"" }, // True/False
+ { 16, 1, "\"On\";\"On\";\"Off\"" }, // On/Off
+ { 17, 1, "$#,##0.00_);[Red]($#,##0.00)" }, // Currency
+ { 18, 1, "[$\xe2\x82\xac-x-euro2] #,##0.00_);[Red]([$\xe2\x82\xac-x-euro2] #,##0.00)" }, // Euro Currency
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+
+ const spreadsheet::number_format_t* nf = styles.get_number_format(cf->number_format);
+ assert(nf);
+ assert(nf->format_string == c.expected);
+ }
+}
+
+void test_xls_xml_cell_properties_wrap_and_shrink()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/cell-properties/wrap-and-shrink.xml");
+
+ const ss::styles& styles = doc->get_styles();
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ std::size_t xfid = sh->get_cell_format(0, 1); // B1
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->wrap_text);
+ assert(!*xf->wrap_text);
+ assert(xf->shrink_to_fit);
+ assert(!*xf->shrink_to_fit);
+
+ xfid = sh->get_cell_format(1, 1); // B2
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->wrap_text);
+ assert(*xf->wrap_text);
+ assert(xf->shrink_to_fit);
+ assert(!*xf->shrink_to_fit);
+
+ xfid = sh->get_cell_format(2, 1); // B3
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->wrap_text);
+ assert(!*xf->wrap_text);
+ assert(xf->shrink_to_fit);
+ assert(*xf->shrink_to_fit);
+}
+
+void test_xls_xml_cell_properties_default_style()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/cell-properties/default-style.xml");
+
+ const ss::color_t black{255, 0, 0, 0};
+
+ const ss::styles& styles = doc->get_styles();
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ std::size_t xfid_default = sh->get_cell_format(0, 0); // A1
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid_default);
+ assert(xf);
+
+ // alignments
+ assert(xf->hor_align == ss::hor_alignment_t::center);
+ assert(xf->ver_align == ss::ver_alignment_t::bottom);
+
+ // font
+ const ss::font_t* font_style = styles.get_font(xf->font);
+ assert(font_style);
+ assert(font_style->name == "DejaVu Sans");
+ assert(font_style->size == 12.0);
+ assert(font_style->color == black);
+
+ // fill
+ const ss::fill_t* fill_style = styles.get_fill(xf->fill);
+ assert(fill_style);
+ assert(fill_style->pattern_type == ss::fill_pattern_t::solid);
+ const ss::color_t fill_color_fg{255, 0xE2, 0xEF, 0xDA};
+ assert(fill_style->fg_color == fill_color_fg);
+
+ // border
+ const ss::border_t* border_style = styles.get_border(xf->border);
+ assert(border_style);
+
+ assert(border_style->bottom.style == ss::border_style_t::dotted);
+
+ // number format
+ const ss::number_format_t* numfmt = styles.get_number_format(xf->number_format);
+ assert(numfmt);
+ assert(numfmt->format_string == "0.0000");
+
+ // protection
+ const ss::protection_t* prot = styles.get_protection(xf->protection);
+ assert(prot);
+ assert(prot->formula_hidden);
+
+ // A1:G6 should all use the default cell style.
+ for (ss::row_t row = 0; row <= 5; ++row)
+ {
+ for (ss::col_t col = 0; col <= 6; ++col)
+ {
+ assert(sh->get_cell_format(row, col) == xfid_default);
+ }
+ }
+}
+
+void test_xls_xml_cell_properties_locked_and_hidden()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto doc = load_doc_from_filepath(SRCDIR"/test/xls-xml/cell-properties/locked-and-hidden.xml");
+ const ixion::model_context& model = doc->get_model_context();
+
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ {
+ // Check cell string values first.
+
+ struct check_type
+ {
+ ixion::abs_address_t address;
+ std::string_view str;
+ };
+
+ const check_type checks[] = {
+ // sheet, row, column, expected cell string value
+ { { 0, 0, 0 }, "Default (Should be locked but not hidden)" },
+ { { 0, 0, 1 }, "Not Locked and not hidden" },
+ { { 0, 1, 0 }, "Locked and hidden" },
+ { { 0, 1, 1 }, "Not locked and hidden" },
+ };
+
+ for (const auto& c : checks)
+ {
+ ixion::string_id_t sid = model.get_string_identifier(c.address);
+ const std::string* s = model.get_string(sid);
+ assert(s);
+ assert(*s == c.str);
+ }
+ }
+
+ {
+ // Check the cell protection attributes.
+
+ struct check_type
+ {
+ ss::row_t row;
+ ss::col_t col;
+ bool locked;
+ bool formula_hidden;
+ };
+
+ const check_type checks[] = {
+ // row, column, locked, formula-hidden
+ { 0, 0, true, false },
+ { 0, 1, false, false },
+ { 1, 0, true, true },
+ { 1, 1, false, true },
+ };
+
+ const ss::styles& styles = doc->get_styles();
+
+ for (const auto& c : checks)
+ {
+ std::cout << "row=" << c.row << "; col=" << c.col << std::endl;
+
+ std::size_t xfid = sh->get_cell_format(c.row, c.col);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::protection_t* prot = styles.get_protection(xf->protection);
+ assert(prot);
+ assert(prot->locked);
+ assert(prot->formula_hidden);
+ std::cout << " * locked: expected=" << c.locked << "; actual=" << *prot->locked << std::endl;
+ assert(*prot->locked == c.locked);
+ std::cout << " * formula-hidden: expected=" << c.formula_hidden << "; actual=" << *prot->formula_hidden << std::endl;
+ assert(*prot->formula_hidden == c.formula_hidden);
+ }
+ }
+}
+
+void test_xls_xml_styles_direct_format()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path{SRCDIR"/test/xls-xml/styles/direct-format.xml"};
+ auto doc = load_doc_from_filepath(path, false, ss::formula_error_policy_t::fail);
+ assert(doc);
+
+ const auto& model = doc->get_model_context();
+
+ {
+ // Check cell string values first.
+
+ struct check_type
+ {
+ ixion::abs_address_t address;
+ std::string_view str;
+ };
+
+ const check_type checks[] = {
+ // sheet, row, column, expected cell string value
+ { { 0, 1, 1 }, "Bold and underlined" },
+ { { 0, 3, 1 }, "Yellow background\nand\nright aligned" },
+ { { 0, 5, 3 }, "Named Format (Good)" },
+ { { 0, 7, 3 }, "Named Format (Good) plus direct format on top" },
+ };
+
+ for (const auto& c : checks)
+ {
+ ixion::string_id_t sid = model.get_string_identifier(c.address);
+ const std::string* s = model.get_string(sid);
+ assert(s);
+ assert(*s == c.str);
+ }
+ }
+
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ const ss::styles& styles = doc->get_styles();
+
+ // Text in B2 is bold, underlined, and horizontally and vertically centered.
+ auto xfid = sh->get_cell_format(1, 1);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::font_t* font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->bold);
+ assert(*font->bold);
+
+ const auto* border = styles.get_border(xf->border);
+ assert(border);
+
+ // "Continuous" with a weight of 1 is mapped to 'thin' border style.
+ assert(border->bottom.style);
+ assert(*border->bottom.style == ss::border_style_t::thin);
+
+ assert(xf->hor_align == ss::hor_alignment_t::center);
+ assert(xf->ver_align == ss::ver_alignment_t::middle);
+
+ // B4 has yellow background, has "Calibri" font at 14 pt etc
+ xfid = sh->get_cell_format(3, 1);
+
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->name);
+ assert(*font->name == "Calibri");
+ assert(font->size);
+ assert(*font->size == 14.0);
+ assert(font->color);
+ assert(*font->color == ss::color_t(0xFF, 0x37, 0x56, 0x23));
+
+ // B4 has yellow background
+ const ss::fill_t* fill = styles.get_fill(xf->fill);
+ assert(fill);
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(*fill->fg_color == ss::color_t(0xFF, 0xFF, 0xFF, 0x00));
+
+ // B4 is horizontally right-aligned and vertically bottom-aligned
+ assert(xf->hor_align == ss::hor_alignment_t::right);
+ assert(xf->ver_align == ss::ver_alignment_t::bottom);
+
+ // B4 has wrap text on
+ assert(xf->wrap_text && *xf->wrap_text);
+
+ // D6 only uses "Good" named cell style with no direct formatting
+ xfid = sh->get_cell_format(5, 3);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const auto xfid_style_good = xf->style_xf;
+ const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Good");
+
+ // Check the format detail of the "Good" style
+ xf = styles.get_cell_style_format(xstyle->xf);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->name);
+ assert(*font->name == "Calibri");
+ assert(font->size);
+ assert(*font->size == 11.0);
+ assert(font->color);
+ assert(*font->color == ss::color_t(0xFF, 0x00, 0x61, 0x00));
+
+ fill = styles.get_fill(xf->fill);
+ assert(fill);
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(*fill->fg_color == ss::color_t(0xFF, 0xC6, 0xEF, 0xCE));
+
+ // D8 has some direct formats applied on top of "Good" named style
+ xfid = sh->get_cell_format(7, 3);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ // Make sure it has the "Good" style as its basis
+ assert(xf->style_xf == xfid_style_good);
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Good");
+
+ // Format directly applied to D8 on top of "Good" style
+ assert(xf->hor_align == ss::hor_alignment_t::center);
+ assert(xf->ver_align == ss::ver_alignment_t::bottom);
+ assert(xf->wrap_text);
+ assert(*xf->wrap_text);
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->bold);
+ assert(*font->bold);
+}
+
+void test_xls_xml_styles_column_styles()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path{SRCDIR"/test/xls-xml/styles/column-styles.xml"};
+ auto doc = load_doc_from_filepath(path, false, ss::formula_error_policy_t::fail);
+ assert(doc);
+ auto doc_size = doc->get_sheet_size();
+
+ const ss::styles& styles = doc->get_styles();
+
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ {
+ // On Sheet1, check the named styles applied on columns B:D and F.
+ // Columns A and E should have Normal style applied.
+ const std::tuple<ss::row_t, ss::col_t, std::string> checks[] = {
+ { 0, 0, "Normal" },
+ { 0, 1, "Bad" },
+ { 0, 2, "Good" },
+ { 0, 3, "Neutral" },
+ { 0, 4, "Normal" },
+ { 0, 5, "Note" },
+ { doc_size.rows - 1, 0, "Normal" },
+ { doc_size.rows - 1, 1, "Bad" },
+ { doc_size.rows - 1, 2, "Good" },
+ { doc_size.rows - 1, 3, "Neutral" },
+ { doc_size.rows - 1, 4, "Normal" },
+ { doc_size.rows - 1, 5, "Note" },
+ };
+
+ for (const auto& check : checks)
+ {
+ ss::row_t r = std::get<0>(check);
+ ss::col_t c = std::get<1>(check);
+ std::string_view name = std::get<2>(check);
+
+ std::size_t xfid = sh->get_cell_format(r, c);
+ std::cout << "row=" << r << "; column=" << c << "; xfid=" << xfid << std::endl;
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+ std::cout << "style xfid=" << xf->style_xf << std::endl;
+
+ const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ if (xstyle->name != name)
+ std::cout << "names differ! (expected=" << name << "; actual=" << xstyle->name << ")" << std::endl;
+
+ assert(xstyle->name == name);
+ }
+ }
+
+ {
+ // Row 10 has green background, and row 11 has orange background.
+ const std::tuple<ss::row_t, ss::color_t> checks[] = {
+ { 9, {0xFF, 0x92, 0xD0, 0x50} },
+ { 10, {0xFF, 0xFF, 0xC0, 0x00} },
+ };
+
+ for (const auto& check : checks)
+ {
+ const ss::row_t row = std::get<0>(check);
+ const ss::color_t color = std::get<1>(check);
+
+ for (ss::col_t col = 0; col <= 6; ++col)
+ {
+ std::size_t xfid = sh->get_cell_format(row, col);
+ std::cout << "row=" << row << "; column=" << col << "; xfid=" << xfid << std::endl;
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::fill_t* fill = styles.get_fill(xf->fill);
+ assert(fill);
+
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+
+ assert(fill->fg_color);
+ assert(*fill->fg_color == color);
+ }
+ }
+ }
+
+ sh = doc->get_sheet(1);
+ assert(sh);
+
+ // Columns B:D should have "Good" named style applied.
+ {
+ const std::pair<ss::row_t, ss::col_t> cells[] = {
+ { 0, 1 },
+ { 0, 3 },
+ { doc_size.rows - 1, 1 },
+ { doc_size.rows - 1, 3 },
+ };
+
+ for (const auto& cell : cells)
+ {
+ std::size_t xfid = sh->get_cell_format(cell.first, cell.second);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Good");
+ }
+ }
+}
+
+void test_xls_xml_styles_data_offset()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path{SRCDIR"/test/xls-xml/styles/data-offset.xml"};
+ auto doc = load_doc_from_filepath(path, false, ss::formula_error_policy_t::fail);
+ assert(doc);
+
+ const ss::styles& styles = doc->get_styles();
+
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ auto check_font_style1 = [sh, &styles](ss::row_t row, ss::col_t col)
+ {
+ std::size_t xfid = sh->get_cell_format(row, col);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::font_t* font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->bold);
+ assert(font->color);
+ assert(*font->color == ss::color_t(0xFF, 0x00, 0x80, 0x00));
+ const ss::number_format_t* numfmt = styles.get_number_format(xf->number_format);
+ assert(numfmt);
+ assert(numfmt->format_string);
+ assert(*numfmt->format_string == "0.00_ ;[Red]\\-0.00\\ ");
+ };
+
+ auto check_font_style2 = [sh, &styles](ss::row_t row, ss::col_t col)
+ {
+ const ss::color_t red{0xFF, 0xFF, 0x00, 0x00};
+
+ std::size_t xfid = sh->get_cell_format(row, col);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::font_t* font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->color);
+ assert(*font->color == red);
+ };
+
+ auto check_font_style3 = [sh, &styles](ss::row_t row, ss::col_t col)
+ {
+ const ss::color_t blue{0xFF, 0x00, 0x00, 0xFF};
+
+ std::size_t xfid = sh->get_cell_format(row, col);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::font_t* font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->color);
+ assert(*font->color == blue);
+
+ const ss::number_format_t* numfmt = styles.get_number_format(xf->number_format);
+ assert(numfmt);
+ assert(numfmt->format_string);
+ assert(*numfmt->format_string == "yyyy/mm\\-dd;@");
+ };
+
+ // Column B and row 2 should have font with bold, green-ish with number format applied
+ check_font_style1(0, 1);
+ check_font_style1(1, 1);
+ check_font_style1(2, 1);
+ check_font_style1(3, 1);
+
+ // row 2
+ check_font_style1(1, 0);
+ check_font_style1(1, 1);
+ check_font_style1(1, 2);
+ check_font_style1(1, 3);
+
+ // Column C should have red font (except for row 2)
+ check_font_style2(0, 2);
+ check_font_style2(2, 2);
+ check_font_style2(3, 2);
+
+ // Column D should have blue font with custom number format applied (except for row 2)
+ check_font_style3(0, 3);
+ check_font_style3(2, 3);
+ check_font_style3(3, 3);
+}
+
+void test_xls_xml_view_cursor_per_sheet()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xls-xml/view/cursor-per-sheet.xml");
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::view view(doc);
+ spreadsheet::import_factory factory(doc, view);
+ orcus_xls_xml app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ // Sheet3 should be active.
+ assert(view.get_active_sheet() == 2);
+
+ const spreadsheet::sheet_view* sv = view.get_sheet_view(0);
+ assert(sv);
+
+ // NB : the resolver type is set to R1C1 for Excel XML 2003.
+ spreadsheet::iface::import_reference_resolver* resolver =
+ factory.get_reference_resolver(spreadsheet::formula_ref_context_t::global);
+ assert(resolver);
+
+ // On Sheet1, the cursor should be set to C4.
+ spreadsheet::range_t expected = to_rc_range(resolver->resolve_range("R4C3"));
+ spreadsheet::range_t actual = sv->get_selection(spreadsheet::sheet_pane_t::top_left);
+ assert(expected == actual);
+
+ sv = view.get_sheet_view(1);
+ assert(sv);
+
+ // On Sheet2, the cursor should be set to D8.
+ expected = to_rc_range(resolver->resolve_range("R8C4"));
+ actual = sv->get_selection(spreadsheet::sheet_pane_t::top_left);
+ assert(expected == actual);
+
+ sv = view.get_sheet_view(2);
+ assert(sv);
+
+ // On Sheet3, the cursor should be set to D2.
+ expected = to_rc_range(resolver->resolve_range("R2C4"));
+ actual = sv->get_selection(spreadsheet::sheet_pane_t::top_left);
+ assert(expected == actual);
+
+ sv = view.get_sheet_view(3);
+ assert(sv);
+
+ // On Sheet4, the cursor should be set to C5:E8.
+ expected = to_rc_range(resolver->resolve_range("R5C3:R8C5"));
+ actual = sv->get_selection(spreadsheet::sheet_pane_t::top_left);
+ assert(expected == actual);
+}
+
+struct expected_selection
+{
+ spreadsheet::sheet_pane_t pane;
+ std::string_view sel;
+};
+
+void test_xls_xml_view_cursor_split_pane()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xls-xml/view/cursor-split-pane.xml");
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::view view(doc);
+ spreadsheet::import_factory factory(doc, view);
+ orcus_xls_xml app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ // NB : the resolver type is set to R1C1 for Excel XML 2003.
+ spreadsheet::iface::import_reference_resolver* resolver =
+ factory.get_reference_resolver(spreadsheet::formula_ref_context_t::global);
+ assert(resolver);
+
+ // Sheet4 should be active.
+ assert(view.get_active_sheet() == 3);
+
+ const spreadsheet::sheet_view* sv = view.get_sheet_view(0);
+ assert(sv);
+
+ // On Sheet1, the view is split into 4.
+ assert(sv->get_active_pane() == spreadsheet::sheet_pane_t::bottom_left);
+ assert(sv->get_split_pane().hor_split == 5190.0);
+ assert(sv->get_split_pane().ver_split == 1800.0);
+
+ {
+ spreadsheet::address_t expected = to_rc_address(resolver->resolve_address("R6C6"));
+ spreadsheet::address_t actual = sv->get_split_pane().top_left_cell;
+ assert(expected == actual);
+ }
+
+ std::vector<expected_selection> expected_selections =
+ {
+ { spreadsheet::sheet_pane_t::top_left, "R4C5" },
+ { spreadsheet::sheet_pane_t::top_right, "R2C10" },
+ { spreadsheet::sheet_pane_t::bottom_left, "R8C1" },
+ { spreadsheet::sheet_pane_t::bottom_right, "R17C10" },
+ };
+
+ for (const expected_selection& es : expected_selections)
+ {
+ // cursor in the top-left pane.
+ spreadsheet::range_t expected = to_rc_range(resolver->resolve_range(es.sel));
+ spreadsheet::range_t actual = sv->get_selection(es.pane);
+ assert(expected == actual);
+ }
+
+ sv = view.get_sheet_view(1);
+ assert(sv);
+
+ // Sheet2 is also split into 4 views.
+ assert(sv->get_active_pane() == spreadsheet::sheet_pane_t::top_right);
+ assert(sv->get_split_pane().hor_split == 5190.0);
+ assert(sv->get_split_pane().ver_split == 2400.0);
+
+ {
+ spreadsheet::address_t expected = to_rc_address(resolver->resolve_address("R8C6"));
+ spreadsheet::address_t actual = sv->get_split_pane().top_left_cell;
+ assert(expected == actual);
+ }
+
+ expected_selections =
+ {
+ { spreadsheet::sheet_pane_t::top_left, "R2C3:R6C3" },
+ { spreadsheet::sheet_pane_t::top_right, "R2C8:R2C12" },
+ { spreadsheet::sheet_pane_t::bottom_left, "R18C2:R23C3" },
+ { spreadsheet::sheet_pane_t::bottom_right, "R11C8:R13C10" },
+ };
+
+ for (const expected_selection& es : expected_selections)
+ {
+ // cursor in the top-left pane.
+ spreadsheet::range_t expected = to_rc_range(resolver->resolve_range(es.sel));
+ spreadsheet::range_t actual = sv->get_selection(es.pane);
+ assert(expected == actual);
+ }
+
+ sv = view.get_sheet_view(2);
+ assert(sv);
+
+ // Sheet3 is horizontally split into top and bottom views (top-left and bottom-left).
+ assert(sv->get_active_pane() == spreadsheet::sheet_pane_t::bottom_left);
+ assert(sv->get_split_pane().hor_split == 0.0);
+ assert(sv->get_split_pane().ver_split == 1500.0);
+
+ {
+ spreadsheet::address_t expected = to_rc_address(resolver->resolve_address("R5C1"));
+ spreadsheet::address_t actual = sv->get_split_pane().top_left_cell;
+ assert(expected == actual);
+ }
+
+ expected_selections =
+ {
+ { spreadsheet::sheet_pane_t::top_left, "R2C4" },
+ { spreadsheet::sheet_pane_t::bottom_left, "R9C3" },
+ };
+
+ for (const expected_selection& es : expected_selections)
+ {
+ // cursor in the top-left pane.
+ spreadsheet::range_t expected = to_rc_range(resolver->resolve_range(es.sel));
+ spreadsheet::range_t actual = sv->get_selection(es.pane);
+ assert(expected == actual);
+ }
+
+ sv = view.get_sheet_view(3);
+ assert(sv);
+
+ // Sheet4 is vertically split into left and right views (top-left and top-right).
+ assert(sv->get_active_pane() == spreadsheet::sheet_pane_t::top_left);
+ assert(sv->get_split_pane().hor_split == 4230.0);
+ assert(sv->get_split_pane().ver_split == 0.0);
+
+ {
+ spreadsheet::address_t expected = to_rc_address(resolver->resolve_address("R1C5"));
+ spreadsheet::address_t actual = sv->get_split_pane().top_left_cell;
+ assert(expected == actual);
+ }
+
+ expected_selections =
+ {
+ { spreadsheet::sheet_pane_t::top_left, "R18C2" },
+ { spreadsheet::sheet_pane_t::top_right, "R11C9" },
+ };
+
+ for (const expected_selection& es : expected_selections)
+ {
+ // cursor in the top-left pane.
+ spreadsheet::range_t expected = to_rc_range(resolver->resolve_range(es.sel));
+ spreadsheet::range_t actual = sv->get_selection(es.pane);
+ assert(expected == actual);
+ }
+}
+
+void test_xls_xml_view_frozen_pane()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xls-xml/view/frozen-pane.xml");
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::view view(doc);
+ spreadsheet::import_factory factory(doc, view);
+ orcus_xls_xml app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ // NB : the resolver type is set to R1C1 for Excel XML 2003.
+ spreadsheet::iface::import_reference_resolver* resolver =
+ factory.get_reference_resolver(spreadsheet::formula_ref_context_t::global);
+ assert(resolver);
+
+ // Sheet3 should be active.
+ assert(view.get_active_sheet() == 2);
+
+ const spreadsheet::sheet_view* sv = view.get_sheet_view(0);
+ assert(sv);
+
+ {
+ // Sheet1 is vertically frozen between columns A and B.
+ const spreadsheet::frozen_pane_t& fp = sv->get_frozen_pane();
+ assert(fp.top_left_cell == to_rc_address(resolver->resolve_address("R1C2")));
+ assert(fp.visible_columns == 1);
+ assert(fp.visible_rows == 0);
+ assert(sv->get_active_pane() == spreadsheet::sheet_pane_t::top_right);
+ }
+
+ sv = view.get_sheet_view(1);
+ assert(sv);
+
+ {
+ // Sheet2 is horizontally frozen between rows 1 and 2.
+ const spreadsheet::frozen_pane_t& fp = sv->get_frozen_pane();
+ assert(fp.top_left_cell == to_rc_address(resolver->resolve_address("R2C1")));
+ assert(fp.visible_columns == 0);
+ assert(fp.visible_rows == 1);
+ assert(sv->get_active_pane() == spreadsheet::sheet_pane_t::bottom_left);
+ }
+
+ sv = view.get_sheet_view(2);
+ assert(sv);
+
+ {
+ // Sheet3 is frozen both horizontally and vertically.
+ const spreadsheet::frozen_pane_t& fp = sv->get_frozen_pane();
+ assert(fp.top_left_cell == to_rc_address(resolver->resolve_address("R9C5")));
+ assert(fp.visible_columns == 4);
+ assert(fp.visible_rows == 8);
+ assert(sv->get_active_pane() == spreadsheet::sheet_pane_t::bottom_right);
+ }
+}
+
+void test_xls_xml_skip_error_cells()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xls-xml/formula-cells-parse-error/input.xml");
+
+ try
+ {
+ auto doc = load_doc_from_filepath(path, false, ss::formula_error_policy_t::fail);
+ (void)doc;
+ assert(!"exception was expected, but was not thrown.");
+ }
+ catch (const std::exception&)
+ {
+ // works as expected
+ }
+
+ auto doc = load_doc_from_filepath(path, false, ss::formula_error_policy_t::skip);
+ const ixion::model_context& cxt = doc->get_model_context();
+
+ auto is_formula_cell_with_error = [&cxt](const ixion::abs_address_t& pos) -> bool
+ {
+ const ixion::formula_cell* fc = cxt.get_formula_cell(pos);
+ if (!fc)
+ return false;
+
+ const ixion::formula_tokens_t& tokens = fc->get_tokens()->get();
+ if (tokens.empty())
+ return false;
+
+ return tokens[0].opcode == ixion::fop_error;
+ };
+
+ // Make sure these two cells have been imported as formula cells with error.
+ assert(is_formula_cell_with_error(ixion::abs_address_t(0, 1, 1)));
+ assert(is_formula_cell_with_error(ixion::abs_address_t(0, 4, 0)));
+}
+
+/**
+ * The test input file starts with double BOM's.
+ */
+void test_xls_xml_double_bom()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xls-xml/double-bom/input.xml");
+
+ // Make sure the test file does contain double BOM's.
+ orcus::file_content content{path};
+ auto content_s = content.str();
+
+ constexpr std::string_view BOM = "\xef\xbb\xbf";
+ assert(content_s.substr(0, 3) == BOM);
+ assert(content_s.substr(3, 3) == BOM);
+
+ auto doc = load_doc_from_filepath(path, false, ss::formula_error_policy_t::fail);
+
+ assert(doc->get_sheet_count() == 5u);
+ assert(doc->get_sheet_name(0) == "Holdings");
+ assert(doc->get_sheet_name(1) == "Overview");
+ assert(doc->get_sheet_name(2) == "Historical");
+ assert(doc->get_sheet_name(3) == "Performance");
+ assert(doc->get_sheet_name(4) == "Distributions");
+}
+
+} // anonymous namespace
+
+int main()
+{
+ test_config.debug = false;
+ test_config.structure_check = true;
+
+ test_xls_xml_detection();
+ test_xls_xml_create_filter();
+ test_xls_xml_import();
+ test_xls_xml_merged_cells();
+ test_xls_xml_date_time();
+ test_xls_xml_bold_and_italic();
+ test_xls_xml_colored_text();
+ test_xls_xml_formatted_text_basic();
+ test_xls_xml_column_width_row_height();
+ test_xls_xml_background_fill();
+ test_xls_xml_named_colors();
+ test_xls_xml_text_alignment();
+ test_xls_xml_cell_borders_single_cells();
+ test_xls_xml_cell_borders_directions();
+ test_xls_xml_cell_borders_colors();
+ test_xls_xml_hidden_rows_columns();
+ test_xls_xml_character_set();
+ test_xls_xml_number_format();
+ test_xls_xml_cell_properties_wrap_and_shrink();
+ test_xls_xml_cell_properties_default_style();
+ test_xls_xml_cell_properties_locked_and_hidden();
+ test_xls_xml_styles_direct_format();
+ test_xls_xml_styles_column_styles();
+ test_xls_xml_styles_data_offset();
+
+ // view import
+ test_xls_xml_view_cursor_per_sheet();
+ test_xls_xml_view_cursor_split_pane();
+ test_xls_xml_view_frozen_pane();
+
+ test_xls_xml_skip_error_cells();
+ test_xls_xml_double_bom();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/orcus_test_xlsx.cpp b/src/orcus_test_xlsx.cpp
new file mode 100644
index 0000000..c3c1600
--- /dev/null
+++ b/src/orcus_test_xlsx.cpp
@@ -0,0 +1,2401 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/orcus_xlsx.hpp>
+#include <orcus/format_detection.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/config.hpp>
+#include <orcus/spreadsheet/factory.hpp>
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/spreadsheet/view.hpp>
+#include <orcus/spreadsheet/sheet.hpp>
+#include <orcus/spreadsheet/auto_filter.hpp>
+#include <orcus/spreadsheet/pivot.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+#include <orcus/spreadsheet/shared_strings.hpp>
+#include <orcus/parser_global.hpp>
+
+#include <cstdlib>
+#include <cassert>
+#include <string>
+#include <sstream>
+#include <set>
+#include <cmath>
+#include <vector>
+#include <iostream>
+
+#include <ixion/model_context.hpp>
+#include <ixion/address.hpp>
+#include <ixion/formula_name_resolver.hpp>
+
+#include "filesystem_env.hpp"
+
+using namespace orcus;
+namespace ss = orcus::spreadsheet;
+
+namespace {
+
+config test_config(format_t::xlsx);
+
+std::unique_ptr<ss::document> load_doc(const std::string_view& path, bool recalc = true)
+{
+ ss::range_size_t sheet_size{1048576, 16384};
+ std::unique_ptr<ss::document> doc = std::make_unique<ss::document>(sheet_size);
+ ss::import_factory factory(*doc);
+
+ orcus_xlsx app(&factory);
+ app.read_file(std::string{path});
+ app.set_config(test_config);
+ if (recalc)
+ doc->recalc_formula_cells();
+
+ return doc;
+}
+
+/**
+ * Convenience function to retrieve a pivot cache instance from textural
+ * sheet name and range name.
+ */
+const ss::pivot_cache* get_pivot_cache(
+ const ss::pivot_collection& pc, const std::string_view& sheet_name, std::string_view range_name)
+{
+ std::unique_ptr<ixion::formula_name_resolver> resolver =
+ ixion::formula_name_resolver::get(
+ ixion::formula_name_resolver_t::excel_a1, nullptr);
+
+ if (!resolver)
+ return nullptr;
+
+ ixion::abs_address_t origin(0,0,0);
+
+ ixion::formula_name_t fn =
+ resolver->resolve(range_name, origin);
+
+ if (fn.type != ixion::formula_name_t::range_reference)
+ return nullptr;
+
+ ixion::abs_range_t range = std::get<ixion::range_t>(fn.value).to_abs(origin);
+ return pc.get_cache(sheet_name, range);
+}
+
+std::vector<fs::path> dirs_recalc = {
+ SRCDIR"/test/xlsx/raw-values-1",
+ SRCDIR"/test/xlsx/boolean-values",
+ SRCDIR"/test/xlsx/empty-shared-strings",
+ SRCDIR"/test/xlsx/formula-array-1",
+ SRCDIR"/test/xlsx/formula-cells",
+ SRCDIR"/test/xlsx/formula-shared",
+ SRCDIR"/test/xlsx/formula-with-string-results",
+ SRCDIR"/test/xlsx/named-expression",
+ SRCDIR"/test/xlsx/named-expression-sheet-local",
+};
+
+std::vector<fs::path> dirs_non_recalc = {
+ SRCDIR"/test/xlsx/formula-array-1",
+ SRCDIR"/test/xlsx/formula-cells",
+ SRCDIR"/test/xlsx/formula-shared",
+ SRCDIR"/test/xlsx/formula-with-string-results",
+};
+
+void test_xlsx_detection()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ for (const auto& dir : dirs_recalc)
+ {
+ fs::path filepath = dir / "input.xlsx";
+ file_content fc(filepath.string());
+ assert(!fc.empty());
+
+ format_t detected = detect(fc.str());
+ assert(detected == format_t::xlsx);
+ }
+}
+
+void test_xlsx_create_filter()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ ss::range_size_t ss{1048576, 16384};
+ std::unique_ptr<ss::document> doc = std::make_unique<ss::document>(ss);
+ ss::import_factory factory(*doc);
+
+ auto f = create_filter(format_t::xlsx, &factory);
+ assert(f);
+ assert(f->get_name() == "xlsx");
+}
+
+/**
+ * Semi-automated import test that goes through all specified directories,
+ * and in each directory, reads the input.xlsx file, dumps its output and
+ * checks it against the check.txt content.
+ */
+void test_xlsx_import()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ auto run_check = [](const fs::path& dir, bool recalc)
+ {
+ // Read the input.xlsx document.
+ fs::path filepath = dir / "input.xlsx";
+ auto doc = load_doc(filepath.string(), recalc);
+
+ // Dump the content of the model.
+ std::ostringstream os;
+ doc->dump_check(os);
+ std::string check = os.str();
+
+ // Check that against known control.
+ filepath = dir / "check.txt";
+ file_content control(filepath.string().data());
+
+ assert(!check.empty());
+ assert(!control.empty());
+
+ std::string_view s1(&check[0], check.size());
+ std::string_view s2 = control.str();
+ assert(orcus::trim(s1) == orcus::trim(s2));
+ };
+
+ for (const fs::path& dir : dirs_recalc)
+ {
+ run_check(dir, true);
+ }
+
+ for (const fs::path& dir : dirs_non_recalc)
+ {
+ run_check(dir, false);
+ }
+}
+
+void test_xlsx_table_autofilter()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/table/autofilter.xlsx");
+ spreadsheet::range_size_t ss{1048576, 16384};
+ ss::document doc{ss};
+ ss::import_factory factory(doc);
+ orcus_xlsx app(&factory);
+ app.read_file(path.c_str());
+
+ const ss::sheet* sh = doc.get_sheet(0);
+ assert(sh);
+ const ss::auto_filter_t* af = sh->get_auto_filter_data();
+ assert(af);
+
+ // Autofilter is over B2:C11.
+ assert(af->range.first.column == 1);
+ assert(af->range.first.row == 1);
+ assert(af->range.last.column == 2);
+ assert(af->range.last.row == 10);
+
+ // Check the match values of the 1st column filter criterion.
+ auto it = af->columns.find(0);
+ assert(it != af->columns.end());
+
+ const ss::auto_filter_column_t* afc = &it->second;
+ assert(afc->match_values.count("A") > 0);
+ assert(afc->match_values.count("C") > 0);
+
+ // And the 2nd column.
+ it = af->columns.find(1);
+ assert(it != af->columns.end());
+ afc = &it->second;
+ assert(afc->match_values.count("1") > 0);
+}
+
+void test_xlsx_table()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/table/table-1.xlsx");
+ ss::document doc{{1048576, 16384}};
+ ss::import_factory factory(doc);
+ orcus_xlsx app(&factory);
+ app.read_file(path.c_str());
+
+ std::string_view name("Table1");
+ const ss::table_t* p = doc.get_table(name);
+ assert(p);
+ assert(p->identifier == 1);
+ assert(p->name == name);
+ assert(p->display_name == name);
+ assert(p->totals_row_count == 1);
+
+ // Table range is C3:D9.
+ ixion::abs_range_t range;
+ range.first.column = 2;
+ range.first.row = 2;
+ range.first.sheet = 0;
+ range.last.column = 3;
+ range.last.row = 8;
+ range.last.sheet = 0;
+ assert(p->range == range);
+
+ // Table1 has 2 table columns.
+ assert(p->columns.size() == 2);
+
+ const ss::table_column_t* tcol = &p->columns[0];
+ assert(tcol);
+ assert(tcol->identifier == 1);
+ assert(tcol->name == "Category");
+ assert(tcol->totals_row_label == "Total");
+ assert(tcol->totals_row_function == ss::totals_row_function_t::none);
+
+ tcol = &p->columns[1];
+ assert(tcol);
+ assert(tcol->identifier == 2);
+ assert(tcol->name == "Value");
+ assert(tcol->totals_row_label.empty());
+ assert(tcol->totals_row_function == ss::totals_row_function_t::sum);
+
+ const auto& filter = p->filter;
+
+ // Auto filter range is C3:D8.
+ range.last.row = 7;
+ assert(filter.range == range);
+
+ assert(filter.columns.size() == 1);
+ const ss::auto_filter_column_t& afc = filter.columns.begin()->second;
+ assert(afc.match_values.size() == 4);
+ assert(afc.match_values.count("A") > 0);
+ assert(afc.match_values.count("C") > 0);
+ assert(afc.match_values.count("D") > 0);
+ assert(afc.match_values.count("E") > 0);
+
+ // Check table style.
+ const ss::table_style_t& style = p->style;
+ assert(style.name == "TableStyleLight9");
+ assert(style.show_first_column == false);
+ assert(style.show_last_column == false);
+ assert(style.show_row_stripes == true);
+ assert(style.show_column_stripes == false);
+}
+
+void test_xlsx_merged_cells()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/merged-cells/simple.xlsx");
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ ss::document doc{ss};
+ ss::import_factory factory(doc);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ const ss::sheet* sheet1 = doc.get_sheet("Sheet1");
+ assert(sheet1);
+
+ spreadsheet::range_t merge_range = sheet1->get_merge_cell_range(0, 1);
+ assert(merge_range.first.column == 1);
+ assert(merge_range.last.column == 2);
+ assert(merge_range.first.row == 0);
+ assert(merge_range.last.row == 0);
+
+ merge_range = sheet1->get_merge_cell_range(0, 3);
+ assert(merge_range.first.column == 3);
+ assert(merge_range.last.column == 5);
+ assert(merge_range.first.row == 0);
+ assert(merge_range.last.row == 0);
+
+ merge_range = sheet1->get_merge_cell_range(1, 0);
+ assert(merge_range.first.column == 0);
+ assert(merge_range.last.column == 0);
+ assert(merge_range.first.row == 1);
+ assert(merge_range.last.row == 2);
+
+ merge_range = sheet1->get_merge_cell_range(3, 0);
+ assert(merge_range.first.column == 0);
+ assert(merge_range.last.column == 0);
+ assert(merge_range.first.row == 3);
+ assert(merge_range.last.row == 5);
+
+ merge_range = sheet1->get_merge_cell_range(2, 2);
+ assert(merge_range.first.column == 2);
+ assert(merge_range.last.column == 5);
+ assert(merge_range.first.row == 2);
+ assert(merge_range.last.row == 5);
+}
+
+void test_xlsx_date_time()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/date-time/input.xlsx");
+
+ ss::document doc{{1048576, 16384}};
+ ss::import_factory factory(doc);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ const ss::sheet* sheet1 = doc.get_sheet("Sheet1");
+ assert(sheet1);
+
+ // B1 contains date-only value.
+ date_time_t dt = sheet1->get_date_time(0, 1);
+ assert(dt == date_time_t(2016, 12, 14));
+
+ // B2 contains date-time value with no fraction seconds.
+ dt = sheet1->get_date_time(1, 1);
+ assert(dt == date_time_t(2002, 2, 3, 12, 34, 45));
+
+ // B3 contains date-time value with fraction second (1992-03-04 08:34:33.555)
+ dt = sheet1->get_date_time(2, 1);
+ assert(dt.year == 1992);
+ assert(dt.month == 3);
+ assert(dt.day == 4);
+ assert(dt.hour == 8);
+ assert(dt.minute == 34);
+ assert(std::floor(dt.second) == 33.0);
+
+ // Evalutate the fraction second as milliseconds.
+ double ms = dt.second * 1000.0;
+ ms -= std::floor(dt.second) * 1000.0;
+ ms = std::round(ms);
+ assert(ms == 555.0);
+}
+
+void test_xlsx_background_fill()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view path(SRCDIR"/test/xlsx/background-color/standard.xlsx");
+ std::unique_ptr<spreadsheet::document> doc = load_doc(path);
+
+ spreadsheet::styles& styles = doc->get_styles();
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ spreadsheet::row_t row;
+ spreadsheet::col_t col;
+ spreadsheet::fill_pattern_t pattern_type;
+ spreadsheet::color_t fg_color;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 0, spreadsheet::fill_pattern_t::solid, { 255, 192, 0, 0 } }, // A2 - dark red
+ { 2, 0, spreadsheet::fill_pattern_t::solid, { 255, 255, 0, 0 } }, // A3 - red
+ { 3, 0, spreadsheet::fill_pattern_t::solid, { 255, 255, 192, 0 } }, // A4 - orange
+ { 4, 0, spreadsheet::fill_pattern_t::solid, { 255, 255, 255, 0 } }, // A5 - yellow
+ { 5, 0, spreadsheet::fill_pattern_t::solid, { 255, 146, 208, 80 } }, // A6 - light green
+ { 6, 0, spreadsheet::fill_pattern_t::solid, { 255, 0, 176, 80 } }, // A7 - green
+ { 7, 0, spreadsheet::fill_pattern_t::solid, { 255, 0, 176, 240 } }, // A8 - light blue
+ { 8, 0, spreadsheet::fill_pattern_t::solid, { 255, 0, 112, 192 } }, // A9 - blue
+ { 9, 0, spreadsheet::fill_pattern_t::solid, { 255, 0, 32, 96 } }, // A10 - dark blue
+ { 10, 0, spreadsheet::fill_pattern_t::solid, { 255, 112, 48, 160 } }, // A11 - purple
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+
+ const spreadsheet::fill_t* fill_data = styles.get_fill(cf->fill);
+ assert(fill_data);
+ assert(fill_data->pattern_type == c.pattern_type);
+ assert(fill_data->fg_color == c.fg_color);
+ }
+}
+
+void test_xlsx_number_format()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view path(SRCDIR"/test/xlsx/number-format/date-time.xlsx");
+ std::unique_ptr<spreadsheet::document> doc = load_doc(path);
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ ss::row_t row;
+ ss::col_t col;
+ std::string_view expected;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 1, "[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy" },
+ { 2, 1, "[ENG][$-409]mmmm\\ d\\,\\ yyyy;@" },
+ { 3, 1, "m/d/yy;@" },
+ };
+
+// TODO : We need to build our own internal number format code table for
+// xlsx. Firstly, xlsx uses numFmtId explicitly to link between the xf and
+// the format string and the ID's are not sequential. Secondly, there is a
+// set of built-in format strings for ID < 164, and that information is not
+// stored in the file.
+#if 0
+ spreadsheet::styles& styles = doc->get_styles();
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+
+ const spreadsheet::number_format_t* nf = styles.start_number_format(cf->number_format);
+ assert(nf);
+ assert(nf->format_string == c.expected);
+ }
+#endif
+}
+
+void test_xlsx_text_alignment()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view path(SRCDIR"/test/xlsx/text-alignment/input.xlsx");
+ std::unique_ptr<spreadsheet::document> doc = load_doc(path);
+
+ spreadsheet::styles& styles = doc->get_styles();
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ spreadsheet::row_t row;
+ spreadsheet::col_t col;
+ bool apply_align;
+ spreadsheet::hor_alignment_t hor_align;
+ spreadsheet::ver_alignment_t ver_align;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 2, false, spreadsheet::hor_alignment_t::unknown, spreadsheet::ver_alignment_t::unknown }, // C2
+ { 2, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::bottom }, // C3
+ { 3, 2, true, spreadsheet::hor_alignment_t::center, spreadsheet::ver_alignment_t::bottom }, // C4
+ { 4, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::bottom }, // C5
+ { 5, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::bottom }, // C6
+ { 6, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::bottom }, // C7
+ { 7, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::bottom }, // C8
+ { 8, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::bottom }, // C9
+ { 9, 2, true, spreadsheet::hor_alignment_t::unknown, spreadsheet::ver_alignment_t::middle }, // C10
+ { 10, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::middle }, // C11
+ { 11, 2, true, spreadsheet::hor_alignment_t::center, spreadsheet::ver_alignment_t::middle }, // C12
+ { 12, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::middle }, // C13
+ { 13, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::middle }, // C14
+ { 14, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::middle }, // C15
+ { 15, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::middle }, // C16
+ { 16, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::middle }, // C17
+ { 17, 2, true, spreadsheet::hor_alignment_t::unknown, spreadsheet::ver_alignment_t::top }, // C18
+ { 18, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::top }, // C19
+ { 19, 2, true, spreadsheet::hor_alignment_t::center, spreadsheet::ver_alignment_t::top }, // C20
+ { 20, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::top }, // C21
+ { 21, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::top }, // C22
+ { 22, 2, true, spreadsheet::hor_alignment_t::left, spreadsheet::ver_alignment_t::top }, // C23
+ { 23, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::top }, // C24
+ { 24, 2, true, spreadsheet::hor_alignment_t::right, spreadsheet::ver_alignment_t::top }, // C25
+ { 25, 2, true, spreadsheet::hor_alignment_t::unknown, spreadsheet::ver_alignment_t::justified }, // C26
+ { 26, 2, true, spreadsheet::hor_alignment_t::justified, spreadsheet::ver_alignment_t::bottom }, // C27
+ { 27, 2, true, spreadsheet::hor_alignment_t::distributed, spreadsheet::ver_alignment_t::distributed }, // C28
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(c.apply_align == cf->apply_alignment);
+
+ if (!cf->apply_alignment)
+ continue;
+
+ assert(c.hor_align == cf->hor_align);
+ assert(c.ver_align == cf->ver_align);
+ }
+}
+
+void test_xlsx_cell_borders_single_cells()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view path(SRCDIR"/test/xlsx/borders/single-cells.xlsx");
+ std::unique_ptr<spreadsheet::document> doc = load_doc(path);
+
+ spreadsheet::styles& styles = doc->get_styles();
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ spreadsheet::row_t row;
+ spreadsheet::col_t col;
+ spreadsheet::border_style_t style;
+ };
+
+ std::vector<check> checks =
+ {
+ { 3, 1, ss::border_style_t::hair },
+ { 5, 1, ss::border_style_t::dotted },
+ { 7, 1, ss::border_style_t::dash_dot_dot },
+ { 9, 1, ss::border_style_t::dash_dot },
+ { 11, 1, ss::border_style_t::dashed },
+ { 13, 1, ss::border_style_t::thin },
+ { 1, 3, ss::border_style_t::medium_dash_dot_dot },
+ { 3, 3, ss::border_style_t::slant_dash_dot },
+ { 5, 3, ss::border_style_t::medium_dash_dot },
+ { 7, 3, ss::border_style_t::medium_dashed },
+ { 9, 3, ss::border_style_t::medium },
+ { 11, 3, ss::border_style_t::thick },
+ { 13, 3, ss::border_style_t::double_border },
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const spreadsheet::border_t* border = styles.get_border(cf->border);
+ assert(border);
+ assert(border->top.style == c.style);
+ assert(border->bottom.style == c.style);
+ assert(border->left.style == c.style);
+ assert(border->right.style == c.style);
+ }
+}
+
+void test_xlsx_cell_borders_directions()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view path(SRCDIR"/test/xlsx/borders/directions.xlsx");
+ std::unique_ptr<ss::document> doc = load_doc(path);
+
+ ss::styles& styles = doc->get_styles();
+
+ ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ ss::row_t row;
+ ss::col_t col;
+ ss::border_direction_t dir;
+ };
+
+ std::vector<check> checks =
+ {
+ { 1, 1, ss::border_direction_t::top },
+ { 3, 1, ss::border_direction_t::left },
+ { 5, 1, ss::border_direction_t::right },
+ { 7, 1, ss::border_direction_t::bottom },
+ { 9, 1, ss::border_direction_t::diagonal_tl_br },
+ { 11, 1, ss::border_direction_t::diagonal_bl_tr },
+ { 13, 1, ss::border_direction_t::diagonal },
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col);
+ const ss::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const ss::border_t* border = styles.get_border(cf->border);
+ assert(border);
+
+ switch (c.dir)
+ {
+ case ss::border_direction_t::top:
+ assert(border->top.style);
+ assert(border->top.style == ss::border_style_t::thin);
+ assert(!border->bottom.style);
+ assert(!border->left.style);
+ assert(!border->right.style);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_tl_br.style);
+ break;
+ case ss::border_direction_t::left:
+ assert(!border->top.style);
+ assert(!border->bottom.style);
+ assert(border->left.style);
+ assert(*border->left.style == ss::border_style_t::thin);
+ assert(!border->right.style);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_tl_br.style);
+ break;
+ case ss::border_direction_t::right:
+ assert(!border->top.style);
+ assert(!border->bottom.style);
+ assert(!border->left.style);
+ assert(border->right.style);
+ assert(*border->right.style == ss::border_style_t::thin);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_tl_br.style);
+ break;
+ case ss::border_direction_t::bottom:
+ assert(!border->top.style);
+ assert(border->bottom.style);
+ assert(*border->bottom.style == ss::border_style_t::thin);
+ assert(!border->left.style);
+ assert(!border->right.style);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_tl_br.style);
+ break;
+ case ss::border_direction_t::diagonal:
+ assert(!border->top.style);
+ assert(!border->bottom.style);
+ assert(!border->left.style);
+ assert(!border->right.style);
+ assert(border->diagonal.style);
+ assert(*border->diagonal.style == ss::border_style_t::thin);
+ assert(!border->diagonal_bl_tr.style);
+ assert(!border->diagonal_tl_br.style);
+ break;
+ case ss::border_direction_t::diagonal_tl_br:
+ assert(!border->top.style);
+ assert(!border->bottom.style);
+ assert(!border->left.style);
+ assert(!border->right.style);
+ assert(!border->diagonal.style);
+ assert(!border->diagonal_bl_tr.style);
+ assert(border->diagonal_tl_br.style);
+ assert(border->diagonal_tl_br.style == ss::border_style_t::thin);
+ break;
+ case ss::border_direction_t::diagonal_bl_tr:
+ assert(!border->top.style);
+ assert(!border->bottom.style);
+ assert(!border->left.style);
+ assert(!border->right.style);
+ assert(!border->diagonal.style);
+ assert(border->diagonal_bl_tr.style);
+ assert(*border->diagonal_bl_tr.style == ss::border_style_t::thin);
+ assert(!border->diagonal_tl_br.style);
+ break;
+ default:
+ assert(!"unhandled direction!");
+ }
+ }
+}
+
+void test_xlsx_cell_borders_colors()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view path(SRCDIR"/test/xlsx/borders/colors.xlsx");
+ std::unique_ptr<spreadsheet::document> doc = load_doc(path);
+
+ spreadsheet::styles& styles = doc->get_styles();
+
+ spreadsheet::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ struct check
+ {
+ ss::row_t row;
+ ss::col_t col;
+ ss::color_t color;
+ };
+
+ std::vector<check> checks =
+ {
+ { 2, 1, ss::color_t(0xFF, 0xFF, 0, 0) }, // B3 - red
+ { 3, 1, ss::color_t(0xFF, 0, 0x70, 0xC0) }, // B4 - blue
+ { 4, 1, ss::color_t(0xFF, 0, 0xB0, 0x50) }, // B5 - green
+ };
+
+ for (const check& c : checks)
+ {
+ size_t xf = sh->get_cell_format(c.row, c.col); // B3
+
+ const spreadsheet::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const spreadsheet::border_t* border = styles.get_border(cf->border);
+ assert(border);
+
+ assert(!border->left.style);
+ assert(border->right.style);
+ assert(*border->right.style == ss::border_style_t::thick);
+ assert(!border->top.style);
+ assert(!border->bottom.style);
+
+ assert(border->right.border_color == c.color);
+ }
+
+ // B7 contains yellow left border, purple right border, and light blue
+ // diagonal borders.
+
+ size_t xf = sh->get_cell_format(6, 1); // B7
+
+ const ss::cell_format_t* cf = styles.get_cell_format(xf);
+ assert(cf);
+ assert(cf->apply_border);
+
+ const ss::border_t* border = styles.get_border(cf->border);
+ assert(border);
+
+ assert(border->left.style == ss::border_style_t::thick);
+ assert(border->left.border_color == ss::color_t(0xFF, 0xFF, 0xFF, 0)); // yellow
+
+ assert(border->right.style == ss::border_style_t::thick);
+ assert(border->right.border_color == ss::color_t(0xFF, 0x70, 0x30, 0xA0)); // purple
+
+ assert(border->diagonal.style == ss::border_style_t::thick);
+ assert(border->diagonal.border_color == ss::color_t(0xFF, 0x00, 0xB0, 0xF0)); // light blue
+
+ // B7 also contains multi-line string. Test that as well.
+ ixion::model_context& model = doc->get_model_context();
+ ixion::string_id_t sid = model.get_string_identifier(ixion::abs_address_t(0,6,1));
+ const std::string* s = model.get_string(sid);
+ assert(s);
+ assert(*s == "<- Yellow\nPurple ->\nLight Blue \\");
+}
+
+void test_xlsx_hidden_rows_columns()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view path(SRCDIR"/test/xlsx/hidden-rows-columns/input.xlsx");
+ std::unique_ptr<spreadsheet::document> doc = load_doc(path);
+
+ spreadsheet::sheet* sh = doc->get_sheet("Hidden Rows");
+ assert(sh);
+
+ spreadsheet::row_t row_start = -1, row_end = -1;
+
+ // Row 1 is visible.
+ assert(!sh->is_row_hidden(0, &row_start, &row_end));
+ assert(row_start == 0);
+ assert(row_end == 1); // the end position is non-inclusive.
+
+ // Rows 2-3 are hidden.
+ assert(sh->is_row_hidden(1, &row_start, &row_end));
+ assert(row_start == 1);
+ assert(row_end == 3); // the end position is non-inclusive.
+
+ // Row 4 is visible.
+ assert(!sh->is_row_hidden(3, &row_start, &row_end));
+ assert(row_start == 3);
+ assert(row_end == 4); // the end position is non-inclusive.
+
+ // Row 5 is hidden.
+ assert(sh->is_row_hidden(4, &row_start, &row_end));
+ assert(row_start == 4);
+ assert(row_end == 5); // the end position is non-inclusive.
+
+ // Rows 6-8 are visible.
+ assert(!sh->is_row_hidden(5, &row_start, &row_end));
+ assert(row_start == 5);
+ assert(row_end == 8); // the end position is non-inclusive.
+
+ // Row 9 is hidden.
+ assert(sh->is_row_hidden(8, &row_start, &row_end));
+ assert(row_start == 8);
+ assert(row_end == 9); // the end position is non-inclusive.
+
+ // The rest of the rows are visible.
+ assert(!sh->is_row_hidden(9, &row_start, &row_end));
+ assert(row_start == 9);
+ assert(row_end == doc->get_sheet_size().rows); // the end position is non-inclusive.
+
+ sh = doc->get_sheet("Hidden Columns");
+ assert(sh);
+
+ spreadsheet::col_t col_start = -1, col_end = -1;
+
+ // Columns A-B are visible.
+ assert(!sh->is_col_hidden(0, &col_start, &col_end));
+ assert(col_start == 0);
+ assert(col_end == 2); // non-inclusive
+
+ // Columns C-E are hidden.
+ assert(sh->is_col_hidden(2, &col_start, &col_end));
+ assert(col_start == 2);
+ assert(col_end == 6); // non-inclusive
+
+ // Columns G-J are visible.
+ assert(!sh->is_col_hidden(6, &col_start, &col_end));
+ assert(col_start == 6);
+ assert(col_end == 10); // non-inclusive
+
+ // Column K is hidden.
+ assert(sh->is_col_hidden(10, &col_start, &col_end));
+ assert(col_start == 10);
+ assert(col_end == 11); // non-inclusive
+
+ // The rest of the columns are all visible.
+ assert(!sh->is_col_hidden(11, &col_start, &col_end));
+ assert(col_start == 11);
+ assert(col_end == doc->get_sheet_size().columns); // non-inclusive
+}
+
+void test_xlsx_cell_properties()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path path{SRCDIR"/test/xlsx/cell-properties/wrap-and-shrink.xlsx"};
+ std::unique_ptr<spreadsheet::document> doc = load_doc(path.string());
+
+ const ss::styles& styles = doc->get_styles();
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ auto xfid = sh->get_cell_format(0, 1); // B1
+ const auto* xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(!xf->wrap_text);
+ assert(!xf->shrink_to_fit);
+
+ xfid = sh->get_cell_format(1, 1); // B2
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->wrap_text);
+ assert(*xf->wrap_text);
+ assert(xf->shrink_to_fit);
+ assert(!*xf->shrink_to_fit);
+
+ xfid = sh->get_cell_format(2, 1); // B3
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+ assert(xf->wrap_text);
+ assert(!*xf->wrap_text);
+ assert(xf->shrink_to_fit);
+ assert(*xf->shrink_to_fit);
+}
+
+void test_xlsx_styles_direct_format()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path path{SRCDIR"/test/xlsx/styles/direct-format.xlsx"};
+ std::unique_ptr<spreadsheet::document> doc = load_doc(path.string());
+ assert(doc);
+
+ const auto& model = doc->get_model_context();
+
+ {
+ // Check cell string values first.
+
+ struct check_type
+ {
+ ixion::abs_address_t address;
+ std::string_view str;
+ };
+
+ const check_type checks[] = {
+ // sheet, row, column, expected cell string value
+ { { 0, 1, 1 }, "Bold and underlined" },
+ { { 0, 3, 1 }, "Yellow background\nand\nright aligned" },
+ { { 0, 5, 3 }, "Named Format (Good)" },
+ { { 0, 7, 3 }, "Named Format (Good) plus direct format on top" },
+ };
+
+ for (const auto& c : checks)
+ {
+ ixion::string_id_t sid = model.get_string_identifier(c.address);
+ const std::string* s = model.get_string(sid);
+ assert(s);
+ assert(*s == c.str);
+ }
+ }
+
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ const ss::styles& styles = doc->get_styles();
+
+ // Text in B2 is bold, underlined, and horizontally and vertically centered.
+ auto xfid = sh->get_cell_format(1, 1);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::font_t* font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->bold);
+ assert(*font->bold);
+
+ const ss::border_t* border = styles.get_border(xf->border);
+ assert(border);
+
+ // "Continuous" with a weight of 1 is mapped to 'thin' border style.
+ assert(border->bottom.style);
+ assert(*border->bottom.style == ss::border_style_t::thin);
+
+ assert(xf->hor_align == ss::hor_alignment_t::center);
+ assert(xf->ver_align == ss::ver_alignment_t::middle);
+
+ // B4 has yellow background, has "Calibri" font at 14 pt etc
+ xfid = sh->get_cell_format(3, 1);
+
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->name);
+ assert(*font->name == "Calibri");
+ assert(font->size);
+ assert(*font->size == 14.0);
+#if 0
+ // TODO: xlsx stores this color as a theme index which we don't yet support
+ assert(font->first.color == ss::color_t(0xFF, 0x37, 0x56, 0x23));
+ assert(font->second.color);
+#endif
+
+ // B4 has yellow background
+ const ss::fill_t* fill = styles.get_fill(xf->fill);
+ assert(fill);
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(*fill->fg_color == ss::color_t(0xFF, 0xFF, 0xFF, 0x00));
+
+ // B4 is horizontally right-aligned and vertically bottom-aligned
+ assert(xf->hor_align == ss::hor_alignment_t::right);
+ assert(xf->ver_align == ss::ver_alignment_t::bottom);
+
+ // B4 has wrap text on
+ assert(xf->wrap_text && *xf->wrap_text);
+
+ // D6 only uses "Good" named cell style with no direct formatting
+ xfid = sh->get_cell_format(5, 3);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const auto xfid_style_good = xf->style_xf;
+ const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Good");
+
+ // Check the format detail of the "Good" style
+ xf = styles.get_cell_style_format(xstyle->xf);
+ assert(xf);
+
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->name);
+ assert(*font->name == "Calibri");
+ assert(font->size);
+ assert(*font->size == 11.0);
+ assert(font->color);
+ assert(*font->color == ss::color_t(0xFF, 0x00, 0x61, 0x00));
+
+ fill = styles.get_fill(xf->fill);
+ assert(fill);
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+ assert(fill->fg_color);
+ assert(*fill->fg_color == ss::color_t(0xFF, 0xC6, 0xEF, 0xCE));
+
+ // D8 has some direct formats applied on top of "Good" named style
+ xfid = sh->get_cell_format(7, 3);
+ xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ // Make sure it has the "Good" style as its basis
+ assert(xf->style_xf == xfid_style_good);
+ xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Good");
+
+ // Format directly applied to D8 on top of "Good" style
+ assert(xf->hor_align == ss::hor_alignment_t::center);
+ assert(xf->ver_align == ss::ver_alignment_t::bottom);
+ assert(xf->wrap_text);
+ assert(*xf->wrap_text);
+ font = styles.get_font(xf->font);
+ assert(font);
+ assert(font->bold);
+ assert(*font->bold);
+}
+
+void test_xlsx_styles_column_styles()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path path{SRCDIR"/test/xlsx/styles/column-styles.xlsx"};
+ std::unique_ptr<spreadsheet::document> doc = load_doc(path.string());
+ assert(doc);
+
+ auto doc_size = doc->get_sheet_size();
+
+ const ss::styles& styles = doc->get_styles();
+
+ const ss::sheet* sh = doc->get_sheet(0);
+ assert(sh);
+
+ {
+ // On Sheet1, check the named styles applied on columns B:D and F.
+ // Columns A and E should have Normal style applied.
+ const std::tuple<ss::row_t, ss::col_t, std::string> checks[] = {
+ { 0, 0, "Normal" },
+ { 0, 1, "Bad" },
+ { 0, 2, "Good" },
+ { 0, 3, "Neutral" },
+ { 0, 4, "Normal" },
+ { 0, 5, "Note" },
+ { doc_size.rows - 1, 0, "Normal" },
+ { doc_size.rows - 1, 1, "Bad" },
+ { doc_size.rows - 1, 2, "Good" },
+ { doc_size.rows - 1, 3, "Neutral" },
+ { doc_size.rows - 1, 4, "Normal" },
+ { doc_size.rows - 1, 5, "Note" },
+ };
+
+ for (const auto& check : checks)
+ {
+ ss::row_t r = std::get<0>(check);
+ ss::col_t c = std::get<1>(check);
+ std::string_view name = std::get<2>(check);
+
+ std::size_t xfid = sh->get_cell_format(r, c);
+ std::cout << "row=" << r << "; column=" << c << "; xfid=" << xfid << std::endl;
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+ std::cout << "style xfid=" << xf->style_xf << std::endl;
+
+ const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ if (xstyle->name != name)
+ std::cout << "names differ! (expected=" << name << "; actual=" << xstyle->name << ")" << std::endl;
+
+ assert(xstyle->name == name);
+ }
+ }
+
+ {
+ // Row 10 has green background, and row 11 has orange background.
+ const std::tuple<ss::row_t, ss::color_t> checks[] = {
+ { 9, {0xFF, 0x92, 0xD0, 0x50} },
+ { 10, {0xFF, 0xFF, 0xC0, 0x00} },
+ };
+
+ for (const auto& check : checks)
+ {
+ const ss::row_t row = std::get<0>(check);
+ const ss::color_t color = std::get<1>(check);
+
+ for (ss::col_t col = 0; col <= 6; ++col)
+ {
+ std::size_t xfid = sh->get_cell_format(row, col);
+ std::cout << "row=" << row << "; column=" << col << "; xfid=" << xfid << std::endl;
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::fill_t* fill = styles.get_fill(xf->fill);
+ assert(fill);
+
+ assert(fill->pattern_type);
+ assert(*fill->pattern_type == ss::fill_pattern_t::solid);
+
+ assert(fill->fg_color);
+ assert(*fill->fg_color == color);
+ }
+ }
+ }
+
+ sh = doc->get_sheet(1);
+ assert(sh);
+
+ // Columns B:D should have "Good" named style applied.
+ {
+ const std::pair<ss::row_t, ss::col_t> cells[] = {
+ { 0, 1 },
+ { 0, 3 },
+ { doc_size.rows - 1, 1 },
+ { doc_size.rows - 1, 3 },
+ };
+
+ for (const auto& cell : cells)
+ {
+ std::size_t xfid = sh->get_cell_format(cell.first, cell.second);
+ const ss::cell_format_t* xf = styles.get_cell_format(xfid);
+ assert(xf);
+
+ const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf);
+ assert(xstyle);
+ assert(xstyle->name == "Good");
+ }
+ }
+}
+
+void test_xlsx_formatted_text_basic()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path path{SRCDIR"/test/xlsx/formatted-text/basic.xlsx"};
+ std::unique_ptr<spreadsheet::document> doc = load_doc(path.string());
+ assert(doc);
+
+ const auto& styles_pool = doc->get_styles();
+
+ auto get_font = [&styles_pool](const ss::sheet& sh, ss::row_t row, ss::col_t col)
+ {
+ std::size_t xf = sh.get_cell_format(row, col);
+
+ const ss::cell_format_t* cell_format = styles_pool.get_cell_format(xf);
+ assert(cell_format);
+
+ const ss::font_t* font = styles_pool.get_font(cell_format->font);
+ assert(font);
+
+ return font;
+ };
+
+ auto check_cell_bold = [&get_font](const ss::sheet& sh, ss::row_t row, ss::col_t col, bool expected)
+ {
+ const ss::font_t* font = get_font(sh, row, col);
+
+ if (expected)
+ {
+ if (font->bold && *font->bold)
+ return true;
+
+ std::cerr << "expected to be bold but it is not "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ else
+ {
+ if (!font->bold || !*font->bold)
+ return true;
+
+ std::cerr << "expected to be non-bold but it is bold "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ };
+
+ auto check_cell_italic = [&get_font](const ss::sheet& sh, ss::row_t row, ss::col_t col, bool expected)
+ {
+ const ss::font_t* font = get_font(sh, row, col);
+
+ if (expected)
+ {
+ if (font->italic && *font->italic)
+ return true;
+
+ std::cerr << "expected to be italic but it is not "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ else
+ {
+ if (!font->italic || !*font->italic)
+ return true;
+
+ std::cerr << "expected to be non-italic but it is italic "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+ };
+
+ auto check_cell_text = [&doc](const ss::sheet& sh, ss::row_t row, ss::col_t col, std::string_view expected)
+ {
+ const auto& sstrings = doc->get_shared_strings();
+
+ std::size_t si = sh.get_string_identifier(row, col);
+ const std::string* s = sstrings.get_string(si);
+ if (!s)
+ {
+ std::cerr << "expected='" << expected << "'; actual=<none> "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ }
+
+ if (*s == expected)
+ return true;
+
+ std::cerr << "expected='" << expected << "'; actual='" << *s << "' "
+ << "(sheet=" << sh.get_index() << "; row=" << row << "; column=" << col << ")"
+ << std::endl;
+
+ return false;
+ };
+
+ {
+ const spreadsheet::sheet* sheet = doc->get_sheet("Text Properties");
+ assert(sheet);
+
+ ss::row_t row = 0;
+ ss::col_t col = 0;
+
+ // A1 - unformatted
+ assert(check_cell_text(*sheet, row, col, "Normal Text"));
+ assert(check_cell_bold(*sheet, row, col, false));
+ assert(check_cell_italic(*sheet, row, col, false));
+
+ // A2 - bold
+ row = 1;
+ assert(check_cell_text(*sheet, row, col, "Bold Text"));
+ assert(check_cell_bold(*sheet, row, col, true));
+ assert(check_cell_italic(*sheet, row, col, false));
+
+ // A3 - italic
+ row = 2;
+ assert(check_cell_text(*sheet, row, col, "Italic Text"));
+ assert(check_cell_bold(*sheet, row, col, false));
+ assert(check_cell_italic(*sheet, row, col, true));
+
+ // A4 - bold and italic
+ row = 3;
+ assert(check_cell_text(*sheet, row, col, "Bold and Italic Text"));
+ assert(check_cell_bold(*sheet, row, col, true));
+ assert(check_cell_italic(*sheet, row, col, true));
+
+ // A5 - bold and italic mixed. Excel creates format runs even for
+ // non-formatted segments.
+ row = 4;
+ assert(check_cell_text(*sheet, row, col, "Bold and Italic mixed"));
+
+ std::size_t si = sheet->get_string_identifier(row, col);
+ const ss::format_runs_t* runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 4u); // only 0 and 2 are formatted
+
+ // Bold and ...
+ // ^^^^
+ assert(runs->at(0).pos == 0);
+ assert(runs->at(0).size == 4);
+ assert(runs->at(0).bold);
+ assert(!runs->at(0).italic);
+
+ // Bold and Italic
+ // ^^^^^^
+ assert(runs->at(2).pos == 9);
+ assert(runs->at(2).size == 6);
+ assert(!runs->at(2).bold);
+ assert(runs->at(2).italic);
+
+ // A6 - xlsx stores 2 format runs; one for "non-bold" and one for " part"
+ row = 5;
+ assert(check_cell_text(*sheet, row, col, "Bold base with non-bold part"));
+ assert(check_cell_bold(*sheet, row, col, true));
+ assert(check_cell_italic(*sheet, row, col, false));
+
+ si = sheet->get_string_identifier(row, col);
+ runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 2u);
+
+ assert(runs->at(0).pos == 15);
+ assert(runs->at(0).size == 8);
+ assert(!runs->at(0).bold);
+
+ assert(runs->at(1).pos == 23);
+ assert(runs->at(1).size == 5);
+ assert(runs->at(1).bold);
+
+ // A7 - TODO: check format
+ row = 6;
+ assert(check_cell_text(*sheet, row, col, "Only partially underlined"));
+
+ // A8
+ row = 7;
+ assert(check_cell_text(*sheet, row, col, "All Underlined"));
+ const ss::font_t* font = get_font(*sheet, row, col);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line);
+
+ // A9
+ row = 8;
+ assert(check_cell_text(*sheet, row, col, "Bold and underlined"));
+ assert(check_cell_bold(*sheet, row, col, true));
+ font = get_font(*sheet, row, col);
+ assert(font->underline_style);
+ assert(*font->underline_style == ss::underline_t::single_line);
+
+ row = 9;
+ assert(check_cell_text(*sheet, row, col, "All Strikethrough"));
+ // TODO: check for strikethrough in cell
+
+ // A11:A15 - TODO: check format
+ row = 10;
+ assert(check_cell_text(*sheet, row, col, "Partial strikethrough"));
+ row = 11;
+ assert(check_cell_text(*sheet, row, col, "Superscript"));
+ row = 12;
+ assert(check_cell_text(*sheet, row, col, "Subscript"));
+ row = 13;
+ assert(check_cell_text(*sheet, row, col, "x2 + y2 = 102"));
+ row = 14;
+ assert(check_cell_text(*sheet, row, col, "xi = yi + zi"));
+ }
+
+ {
+ const spreadsheet::sheet* sheet = doc->get_sheet("Fonts");
+ assert(sheet);
+
+ struct check
+ {
+ ss::row_t row;
+ std::string_view font_name;
+ double font_unit;
+ };
+
+ check checks[] = {
+ { 0, "Calibri Light", 12.0 },
+ { 1, "Arial", 18.0 },
+ { 2, "Times New Roman", 14.0 },
+ { 3, "Consolas", 9.0 },
+ { 4, "Bookman Old Style", 20.0 },
+ };
+
+ for (const auto& c : checks)
+ {
+ std::size_t xf = sheet->get_cell_format(c.row, 0);
+ const ss::cell_format_t* cell_format = styles_pool.get_cell_format(xf);
+ assert(cell_format);
+ const ss::font_t* font = styles_pool.get_font(cell_format->font);
+ assert(font);
+ std::cout << "row: " << c.row << std::endl;
+ std::cout << " font-name: expected='" << c.font_name << "' vs actual='" << (font->name ? *font->name : "(not set)") << "'" << std::endl;
+ assert(font->name == c.font_name);
+ std:: cout << " font-size: expected=" << c.font_unit << " vs actual=" << (font->size ? *font->size : -1) << std::endl;
+ assert(font->size == c.font_unit);
+
+ // Columns A and B should have the same font.
+ xf = sheet->get_cell_format(c.row, 1);
+ cell_format = styles_pool.get_cell_format(xf);
+ assert(cell_format);
+ font = styles_pool.get_font(cell_format->font);
+ assert(font);
+ assert(font->name == c.font_name);
+ assert(font->size == c.font_unit);
+ }
+ }
+
+ {
+ const spreadsheet::sheet* sheet = doc->get_sheet("Mixed Fonts");
+ assert(sheet);
+
+ // A1
+ ss::row_t row = 0;
+ ss::col_t col = 0;
+ assert(check_cell_text(*sheet, row, col, "C++ has class and struct as keywords."));
+
+ // Base cell has Serif 12-pt font applied
+ auto xf = sheet->get_cell_format(row, col);
+ const ss::cell_format_t* fmt = styles_pool.get_cell_format(xf);
+ assert(fmt);
+ const ss::font_t* font = styles_pool.get_font(fmt->font);
+ assert(font);
+ assert(font->name == "Calibri");
+ assert(font->size == 11.0);
+
+ // Two segments has Liberation Mono font applied (runs 0 and 2).
+ std::size_t si = sheet->get_string_identifier(row, col);
+ const ss::format_runs_t* runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 4u);
+
+ // C++ has class ...
+ // ^^^^^
+ assert(runs->at(0).pos == 8);
+ assert(runs->at(0).size == 5);
+ assert(runs->at(0).font == "Liberation Mono");
+
+ // class and struct
+ // ^^^^^
+ assert(runs->at(1).pos == 13);
+ assert(runs->at(1).size == 5);
+ assert(runs->at(1).font == "Calibri");
+
+ // ... and struct as ...
+ // ^^^^^^
+ assert(runs->at(2).pos == 18);
+ assert(runs->at(2).size == 6);
+ assert(runs->at(2).font == "Liberation Mono");
+
+ // ... struct as keywords.
+ // ^^^^^^^^^^^^^
+ assert(runs->at(3).pos == 24);
+ assert(runs->at(3).size == 13);
+ assert(runs->at(3).font == "Calibri");
+
+ // A2
+ row = 1;
+ assert(check_cell_text(*sheet, row, col, "Text with 12-point font, 24-point font, and 36-point font mixed."));
+ si = sheet->get_string_identifier(row, col);
+ runs = doc->get_shared_strings().get_format_runs(si);
+ assert(runs);
+ assert(runs->size() == 9u);
+
+ // with 12-point font, ...
+ // ^^
+ assert(runs->at(0).pos == 10);
+ assert(runs->at(0).size == 2);
+ assert(runs->at(0).font_size == 12.0f);
+ assert(runs->at(0).color == ss::color_t(0xFF, 0xFF, 0, 0)); // red
+
+ // with 12-point font, ...
+ // ^^^^^^
+ assert(runs->at(1).pos == 12);
+ assert(runs->at(1).size == 6);
+ assert(runs->at(1).font_size == 12.0f);
+
+ // 24-point font,
+ // ^^
+ assert(runs->at(3).pos == 25);
+ assert(runs->at(3).size == 2);
+ assert(runs->at(3).font_size == 24.0f);
+ assert(runs->at(3).color == ss::color_t(0xFF, 0xFF, 0, 0)); // red
+
+ // 24-point font,
+ // ^^^^^^
+ assert(runs->at(4).pos == 27);
+ assert(runs->at(4).size == 6);
+ assert(runs->at(4).font_size == 24.0f);
+
+ // and 36-point font
+ // ^^
+ assert(runs->at(6).pos == 44);
+ assert(runs->at(6).size == 2);
+ assert(runs->at(6).font_size == 36.0f);
+ assert(runs->at(6).color == ss::color_t(0xFF, 0xFF, 0, 0)); // red
+
+ // and 36-point font
+ // ^^^^^^
+ assert(runs->at(7).pos == 46);
+ assert(runs->at(7).size == 6);
+ assert(runs->at(7).font_size == 36.0f);
+ }
+}
+
+void test_xlsx_pivot_two_pivot_caches()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/pivot-table/two-pivot-caches.xlsx");
+
+ ss::document doc{{1048576, 16384}};
+ ss::import_factory factory(doc);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ const ss::pivot_collection& pc = doc.get_pivot_collection();
+ assert(pc.get_cache_count() == 2);
+
+ // B2:C6 on sheet 'Data'.
+ const ss::pivot_cache* cache = get_pivot_cache(pc, "Data", "B2:C6");
+ assert(cache);
+ assert(cache->get_field_count() == 2);
+
+ // Test the content of this cache.
+ const ss::pivot_cache_field_t* fld = cache->get_field(0);
+ assert(fld);
+ assert(fld->name == "F1");
+
+ {
+ // This field should contain 4 string items 'A', 'B', 'C' and 'D'.
+ std::set<ss::pivot_cache_item_t> expected =
+ {
+ std::string_view{"A"},
+ std::string_view{"B"},
+ std::string_view{"C"},
+ std::string_view{"D"},
+ };
+
+ std::set<ss::pivot_cache_item_t> actual(fld->items.begin(), fld->items.end());
+ assert(actual == expected);
+ }
+
+ fld = cache->get_field(1);
+ assert(fld);
+ assert(fld->name == "D1");
+
+ // This is a pure numeric field with min and max values specified.
+ assert(fld->min_value && *fld->min_value == 1.0);
+ assert(fld->max_value && *fld->max_value == 4.0);
+ assert(fld->items.empty());
+
+ {
+ // Check the records.
+ ss::pivot_cache::records_type expected =
+ {
+ { std::size_t(0), 1.0 },
+ { std::size_t(1), 2.0 },
+ { std::size_t(2), 3.0 },
+ { std::size_t(3), 4.0 },
+ };
+
+ assert(expected == cache->get_all_records());
+ }
+
+ // F10:G14 on the same sheet.
+ cache = get_pivot_cache(pc, "Data", "F10:G14");
+ assert(cache);
+ assert(cache->get_field_count() == 2);
+
+ // This field should contain 4 string items 'W', 'X', 'Y' and 'Z' but not
+ // necessarily in this order.
+ fld = cache->get_field(0);
+ assert(fld);
+ assert(fld->name == "F2");
+
+ {
+ std::set<ss::pivot_cache_item_t> expected =
+ {
+ std::string_view{"W"},
+ std::string_view{"X"},
+ std::string_view{"Y"},
+ std::string_view{"Z"},
+ };
+
+ std::set<ss::pivot_cache_item_t> actual;
+ actual.insert(fld->items.begin(), fld->items.end());
+ assert(actual == expected);
+ }
+
+ fld = cache->get_field(1);
+ assert(fld);
+ assert(fld->name == "D2");
+
+ // This is a pure numeric field with min and max values specified.
+ assert(fld->min_value && *fld->min_value == 1.0);
+ assert(fld->max_value && *fld->max_value == 4.0);
+ assert(fld->items.empty());
+
+ {
+ // Check the records.
+ ss::pivot_cache::records_type expected =
+ {
+ { std::size_t(0), 4.0 },
+ { std::size_t(1), 3.0 },
+ { std::size_t(2), 2.0 },
+ { std::size_t(3), 1.0 },
+ };
+
+ assert(expected == cache->get_all_records());
+ }
+}
+
+void test_xlsx_pivot_mixed_type_field()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/pivot-table/mixed-type-field.xlsx");
+
+ ss::document doc{{1048576, 16384}};
+ ss::import_factory factory(doc);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ const ss::pivot_collection& pc = doc.get_pivot_collection();
+ assert(pc.get_cache_count() == 2);
+
+ // B2:C7 on sheet 'Data'.
+ const ss::pivot_cache* cache = get_pivot_cache(pc, "Data", "B2:C7");
+ assert(cache);
+ assert(cache->get_field_count() == 2);
+
+ // 1st field
+ const ss::pivot_cache_field_t* fld = cache->get_field(0);
+ assert(fld);
+ assert(fld->name == "F1");
+ assert(fld->min_value && fld->min_value == 1.0);
+ assert(fld->max_value && fld->max_value == 2.0);
+
+ {
+ // This field should contain 3 string items 'A', 'B', 'C' and 2 numeric
+ // items 1 and 2.
+ std::set<ss::pivot_cache_item_t> expected =
+ {
+ std::string_view{"A"},
+ std::string_view{"B"},
+ std::string_view{"C"},
+ 1.0,
+ 2.0,
+ };
+
+ std::set<ss::pivot_cache_item_t> actual(fld->items.begin(), fld->items.end());
+ assert(actual == expected);
+ }
+
+ // 2nd field should be a nuemric field between 1.1 and 1.5.
+ fld = cache->get_field(1);
+ assert(fld);
+ assert(fld->name == "V1");
+ assert(fld->items.empty());
+
+ assert(fld->min_value);
+ assert(std::round(*fld->min_value * 100.0) == 110.0); // min = 1.1
+ assert(fld->max_value);
+ assert(std::round(*fld->max_value * 100.0) == 150.0); // max = 1.5
+
+ {
+ // Check the records.
+ ss::pivot_cache::records_type expected =
+ {
+ { size_t(0), 1.1 },
+ { size_t(1), 1.2 },
+ { size_t(2), 1.3 },
+ { size_t(3), 1.4 },
+ { size_t(4), 1.5 },
+ };
+
+ assert(expected == cache->get_all_records());
+ }
+
+ // B10:C17 on sheet 'Data'.
+ cache = get_pivot_cache(pc, "Data", "B10:C17");
+ assert(cache);
+ assert(cache->get_field_count() == 2);
+
+ // 1st field
+ fld = cache->get_field(0);
+ assert(fld);
+ assert(fld->name == "F2");
+ assert(fld->min_value && fld->min_value == 1.0);
+ assert(fld->max_value && fld->max_value == 5.0);
+
+ {
+ // This field should contain 3 string items 'A', 'B', 'C' and 4 numeric
+ // items 1, 2, 3.5 and 5.
+ std::set<ss::pivot_cache_item_t> expected =
+ {
+ std::string_view{"A"},
+ std::string_view{"B"},
+ std::string_view{"C"},
+ 1.0,
+ 2.0,
+ 3.5,
+ 5.0,
+ };
+
+ std::set<ss::pivot_cache_item_t> actual;
+ actual.insert(fld->items.begin(), fld->items.end());
+ assert(actual == expected);
+ }
+
+ // 2nd field
+ fld = cache->get_field(1);
+ assert(fld);
+ assert(fld->name == "V2");
+ assert(fld->items.empty());
+
+ assert(fld->min_value);
+ assert(std::round(*fld->min_value * 100.0) == 110.0); // min = 1.1
+ assert(fld->max_value);
+ assert(std::round(*fld->max_value * 100.0) == 220.0); // max = 2.2
+
+ {
+ // Check the records.
+ ss::pivot_cache::records_type expected =
+ {
+ { std::size_t(0), 1.1 },
+ { std::size_t(1), 1.2 },
+ { std::size_t(2), 1.3 },
+ { std::size_t(3), 1.4 },
+ { std::size_t(4), 1.5 },
+ { std::size_t(5), 1.8 },
+ { std::size_t(6), 2.2 },
+ };
+
+ assert(expected == cache->get_all_records());
+ }
+}
+
+void test_xlsx_pivot_group_field()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/pivot-table/group-field.xlsx");
+
+ ss::document doc{{1048576, 16384}};
+ ss::import_factory factory(doc);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ const ss::pivot_collection& pc = doc.get_pivot_collection();
+ assert(pc.get_cache_count() == 1);
+
+ // B2:C6 on sheet 'Sheet1'.
+ const ss::pivot_cache* cache = get_pivot_cache(pc, "Sheet1", "B2:C6");
+ assert(cache);
+ assert(cache->get_field_count() == 3);
+
+ // First field is labeled 'Key'.
+ const ss::pivot_cache_field_t* fld = cache->get_field(0);
+ assert(fld);
+ assert(fld->name == "Key");
+
+ {
+ // This field should contain 4 string items 'A', 'B', 'C' and 'D'.
+ std::set<ss::pivot_cache_item_t> expected =
+ {
+ std::string_view{"A"},
+ std::string_view{"B"},
+ std::string_view{"C"},
+ std::string_view{"D"},
+ };
+
+ std::set<ss::pivot_cache_item_t> actual(fld->items.begin(), fld->items.end());
+ assert(actual == expected);
+ }
+
+ // 2nd field is 'Value' and is a numeric field.
+ fld = cache->get_field(1);
+ assert(fld);
+ assert(fld->name == "Value");
+ assert(fld->items.empty());
+
+ assert(fld->min_value);
+ assert(*fld->min_value == 1.0);
+ assert(fld->max_value);
+ assert(*fld->max_value == 4.0);
+
+ // 3rd field is a group field labeled 'Key2'.
+ fld = cache->get_field(2);
+ assert(fld);
+ assert(fld->name == "Key2");
+ assert(fld->items.empty());
+
+ const ss::pivot_cache_group_data_t* gd = fld->group_data.get();
+ assert(gd);
+ assert(gd->base_field == 0);
+ assert(gd->items.size() == 2);
+
+ {
+ // It should have two items - Group1 and Group2.
+ std::set<ss::pivot_cache_item_t> expected =
+ {
+ std::string_view{"Group1"},
+ std::string_view{"Group2"},
+ };
+
+ std::set<ss::pivot_cache_item_t> actual;
+ actual.insert(gd->items.begin(), gd->items.end());
+ assert(actual == expected);
+ }
+
+ // Group1 should group 'A' and 'B' from the 1st field, and Group2 should
+ // group 'C' and 'D'.
+
+ ss::pivot_cache_indices_t expected_group = { 0, 0, 1, 1 };
+ assert(gd->base_to_group_indices == expected_group);
+
+ {
+ // Check the records.
+ ss::pivot_cache::records_type expected =
+ {
+ { std::size_t(0), 1.0 },
+ { std::size_t(1), 2.0 },
+ { std::size_t(2), 3.0 },
+ { std::size_t(3), 4.0 },
+ };
+
+ assert(expected == cache->get_all_records());
+ }
+}
+
+void test_xlsx_pivot_group_by_numbers()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/pivot-table/group-by-numbers.xlsx");
+
+ ss::document doc{{1048576, 16384}};
+ ss::import_factory factory(doc);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ const ss::pivot_collection& pc = doc.get_pivot_collection();
+ assert(pc.get_cache_count() == 1);
+
+ // B2:C13 on sheet 'Sheet1'.
+ const ss::pivot_cache* cache = get_pivot_cache(pc, "Sheet1", "B2:C13");
+ assert(cache);
+ assert(cache->get_field_count() == 2);
+
+ // First field is a field with numeric grouping with intervals.
+ const ss::pivot_cache_field_t* fld = cache->get_field(0);
+ assert(fld);
+ assert(fld->name == "V1");
+
+ // There should be 11 raw values ranging from 9.78E-2 to 9.82.
+ assert(fld->items.size() == 11);
+ assert(fld->min_value);
+ assert(fld->max_value);
+ assert(std::round(*fld->min_value*10000.0) == 978.00); // 9.78E-2
+ assert(std::round(*fld->max_value*100.0) == 982.00); // 9.82
+
+ // We'll just make sure that all 11 items are of numeric type.
+
+ for (const auto& item : fld->items)
+ {
+ assert(item.type == ss::pivot_cache_item_t::item_type::numeric);
+ assert(*fld->min_value <= std::get<double>(item.value));
+ assert(std::get<double>(item.value) <= *fld->max_value);
+ }
+
+ // This field is also gruop field with 7 numeric intervals of width 2.
+ assert(fld->group_data);
+ const ss::pivot_cache_group_data_t& grp = *fld->group_data;
+ assert(grp.items.size() == 7);
+
+ ss::pivot_cache_items_t expected =
+ {
+ std::string_view{"<0"},
+ std::string_view{"0-2"},
+ std::string_view{"2-4"},
+ std::string_view{"4-6"},
+ std::string_view{"6-8"},
+ std::string_view{"8-10"},
+ std::string_view{">10"},
+ };
+
+ assert(grp.items == expected);
+
+ // Check the numeric range properties.
+ assert(grp.range_grouping);
+ assert(grp.range_grouping->group_by == ss::pivot_cache_group_by_t::range);
+ assert(!grp.range_grouping->auto_start);
+ assert(!grp.range_grouping->auto_end);
+ assert(grp.range_grouping->start == 0.0);
+ assert(grp.range_grouping->end == 10.0);
+ assert(grp.range_grouping->interval == 2.0);
+
+ // Test the 2nd field. This field is purely a numeric field with no
+ // discrete items.
+
+ fld = cache->get_field(1);
+ assert(fld);
+ assert(fld->name == "V2");
+ assert(!fld->group_data);
+ assert(fld->items.empty());
+ assert(fld->min_value);
+ assert(fld->min_value == 1.0);
+ assert(fld->max_value);
+ assert(fld->max_value == 11.0);
+}
+
+void test_xlsx_pivot_group_by_dates()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/pivot-table/group-by-dates.xlsx");
+
+ ss::document doc{{1048576, 16384}};
+ ss::import_factory factory(doc);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ const ss::pivot_collection& pc = doc.get_pivot_collection();
+ assert(pc.get_cache_count() == 1);
+
+ const ss::pivot_cache* cache = get_pivot_cache(pc, "Sheet1", "B2:C14");
+ assert(cache);
+
+ // First field is a date field.
+ const ss::pivot_cache_field_t* fld = cache->get_field(0);
+ assert(fld);
+ assert(fld->name == "Date");
+
+ // Minimum and maximum date values.
+ assert(fld->min_date);
+ assert(*fld->min_date == date_time_t(2014, 1, 1));
+ assert(fld->max_date);
+ assert(*fld->max_date == date_time_t(2014, 12, 2));
+
+ ss::pivot_cache_items_t expected =
+ {
+ date_time_t(2014, 1, 1),
+ date_time_t(2014, 2, 1),
+ date_time_t(2014, 3, 1),
+ date_time_t(2014, 4, 1),
+ date_time_t(2014, 5, 1),
+ date_time_t(2014, 6, 1),
+ date_time_t(2014, 7, 1),
+ date_time_t(2014, 8, 1),
+ date_time_t(2014, 9, 1),
+ date_time_t(2014, 10, 1),
+ date_time_t(2014, 11, 1),
+ date_time_t(2014, 12, 1),
+ };
+
+ ss::pivot_cache_items_t actual(fld->items.begin(), fld->items.end());
+ assert(actual == expected);
+
+ // This field is grouped by month.
+
+ assert(fld->group_data);
+ const ss::pivot_cache_group_data_t& gd = *fld->group_data;
+
+ expected =
+ {
+ std::string_view{"<1/1/2014"},
+ std::string_view{"Jan"},
+ std::string_view{"Feb"},
+ std::string_view{"Mar"},
+ std::string_view{"Apr"},
+ std::string_view{"May"},
+ std::string_view{"Jun"},
+ std::string_view{"Jul"},
+ std::string_view{"Aug"},
+ std::string_view{"Sep"},
+ std::string_view{"Oct"},
+ std::string_view{"Nov"},
+ std::string_view{"Dec"},
+ std::string_view{">12/2/2014"},
+ };
+
+ assert(gd.items == expected);
+
+ assert(gd.range_grouping);
+ assert(gd.range_grouping->group_by == ss::pivot_cache_group_by_t::months);
+
+ assert(gd.range_grouping->start_date == date_time_t(2014,1,1));
+ assert(gd.range_grouping->end_date == date_time_t(2014,12,2));
+
+ // The 2nd field is a simple numeric field.
+ fld = cache->get_field(1);
+ assert(fld);
+ assert(fld->name == "Value");
+ assert(fld->min_value == 1.0);
+ assert(fld->max_value == 12.0);
+
+ // The 3rd field is an extra group field.
+ fld = cache->get_field(2);
+ assert(fld);
+ assert(fld->name == "Quarters");
+ assert(fld->group_data);
+ const ss::pivot_cache_group_data_t& gd_qtrs = *fld->group_data;
+ assert(gd_qtrs.base_field == 0);
+
+ assert(gd_qtrs.range_grouping);
+ assert(gd_qtrs.range_grouping->group_by == ss::pivot_cache_group_by_t::quarters);
+ assert(gd_qtrs.range_grouping->start_date == date_time_t(2014,1,1));
+ assert(gd_qtrs.range_grouping->end_date == date_time_t(2014,12,2));
+
+ expected =
+ {
+ std::string_view{"<1/1/2014"},
+ std::string_view{"Qtr1"},
+ std::string_view{"Qtr2"},
+ std::string_view{"Qtr3"},
+ std::string_view{"Qtr4"},
+ std::string_view{">12/2/2014"},
+ };
+
+ assert(gd_qtrs.items == expected);
+}
+
+void test_xlsx_pivot_error_values()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/pivot-table/error-values.xlsx");
+
+ ss::document doc{{1048576, 16384}};
+ ss::import_factory factory(doc);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ const ss::pivot_collection& pc = doc.get_pivot_collection();
+ assert(pc.get_cache_count() == 1);
+
+ const ss::pivot_cache* cache = get_pivot_cache(pc, "Sheet1", "B2:C6");
+ assert(cache);
+
+ const ss::pivot_cache_field_t* fld = cache->get_field(0);
+
+ assert(fld);
+ assert(fld->name == "F1");
+
+ // This field should contain 4 string items 'A', 'B', 'C' and 'D'.
+ std::set<ss::pivot_cache_item_t> expected =
+ {
+ std::string_view{"A"},
+ std::string_view{"B"},
+ std::string_view{"C"},
+ std::string_view{"D"},
+ };
+
+ std::set<ss::pivot_cache_item_t> actual(fld->items.begin(), fld->items.end());
+ assert(actual == expected);
+
+ fld = cache->get_field(1);
+
+ assert(fld);
+ assert(fld->name == "F2");
+
+ expected =
+ {
+ spreadsheet::error_value_t::div0,
+ spreadsheet::error_value_t::name,
+ };
+
+ actual.clear();
+ actual.insert(fld->items.begin(), fld->items.end());
+
+ assert(actual == expected);
+}
+
+void test_xlsx_view_cursor_per_sheet()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/view/cursor-per-sheet.xlsx");
+
+ ss::document doc{{1048576, 16384}};
+ ss::view view(doc);
+ ss::import_factory factory(doc, view);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ // Sheet3 should be active.
+ assert(view.get_active_sheet() == 2);
+
+ const ss::sheet_view* sv = view.get_sheet_view(0);
+ assert(sv);
+
+ ss::iface::import_reference_resolver* resolver =
+ factory.get_reference_resolver(ss::formula_ref_context_t::global);
+ assert(resolver);
+
+ // On Sheet1, the cursor should be set to C4.
+ ss::range_t expected = to_rc_range(resolver->resolve_range("C4"));
+ ss::range_t actual = sv->get_selection(ss::sheet_pane_t::top_left);
+ assert(expected == actual);
+
+ sv = view.get_sheet_view(1);
+ assert(sv);
+
+ // On Sheet2, the cursor should be set to D8.
+ expected = to_rc_range(resolver->resolve_range("D8"));
+ actual = sv->get_selection(ss::sheet_pane_t::top_left);
+ assert(expected == actual);
+
+ sv = view.get_sheet_view(2);
+ assert(sv);
+
+ // On Sheet3, the cursor should be set to D2.
+ expected = to_rc_range(resolver->resolve_range("D2"));
+ actual = sv->get_selection(ss::sheet_pane_t::top_left);
+ assert(expected == actual);
+
+ sv = view.get_sheet_view(3);
+ assert(sv);
+
+ // On Sheet4, the cursor should be set to C5:E8.
+ expected = to_rc_range(resolver->resolve_range("C5:E8"));
+ actual = sv->get_selection(ss::sheet_pane_t::top_left);
+ assert(expected == actual);
+}
+
+struct expected_selection
+{
+ ss::sheet_pane_t pane;
+ std::string_view sel;
+};
+
+void test_xlsx_view_cursor_split_pane()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/view/cursor-split-pane.xlsx");
+
+ ss::document doc{{1048576, 16384}};
+ ss::view view(doc);
+ ss::import_factory factory(doc, view);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ ss::iface::import_reference_resolver* resolver =
+ factory.get_reference_resolver(ss::formula_ref_context_t::global);
+ assert(resolver);
+
+ // Sheet4 should be active.
+ assert(view.get_active_sheet() == 3);
+
+ const ss::sheet_view* sv = view.get_sheet_view(0);
+ assert(sv);
+
+ // On Sheet1, the view is split into 4.
+ assert(sv->get_active_pane() == ss::sheet_pane_t::bottom_left);
+ assert(sv->get_split_pane().hor_split == 5190.0);
+ assert(sv->get_split_pane().ver_split == 1800.0);
+
+ {
+ ss::address_t expected = to_rc_address(resolver->resolve_address("F6"));
+ ss::address_t actual = sv->get_split_pane().top_left_cell;
+ assert(expected == actual);
+ }
+
+ std::vector<expected_selection> expected_selections =
+ {
+ { ss::sheet_pane_t::top_left, "E4" },
+ { ss::sheet_pane_t::top_right, "J2" },
+ { ss::sheet_pane_t::bottom_left, "A8" },
+ { ss::sheet_pane_t::bottom_right, "J17" },
+ };
+
+ for (const expected_selection& es : expected_selections)
+ {
+ // cursor in the top-left pane.
+ ss::range_t expected = to_rc_range(resolver->resolve_range(es.sel));
+ ss::range_t actual = sv->get_selection(es.pane);
+ assert(expected == actual);
+ }
+
+ sv = view.get_sheet_view(1);
+ assert(sv);
+
+ // Sheet2 is also split into 4 views.
+ assert(sv->get_active_pane() == ss::sheet_pane_t::top_right);
+ assert(sv->get_split_pane().hor_split == 5190.0);
+ assert(sv->get_split_pane().ver_split == 2400.0);
+
+ {
+ ss::address_t expected = to_rc_address(resolver->resolve_address("F8"));
+ ss::address_t actual = sv->get_split_pane().top_left_cell;
+ assert(expected == actual);
+ }
+
+ expected_selections =
+ {
+ { ss::sheet_pane_t::top_left, "C2:C6" },
+ { ss::sheet_pane_t::top_right, "H2:L2" },
+ { ss::sheet_pane_t::bottom_left, "B18:C23" },
+ { ss::sheet_pane_t::bottom_right, "H11:J13" },
+ };
+
+ for (const expected_selection& es : expected_selections)
+ {
+ // cursor in the top-left pane.
+ ss::range_t expected = to_rc_range(resolver->resolve_range(es.sel));
+ ss::range_t actual = sv->get_selection(es.pane);
+ assert(expected == actual);
+ }
+
+ sv = view.get_sheet_view(2);
+ assert(sv);
+
+ // Sheet3 is horizontally split into top and bottom views (top-left and bottom-left).
+ assert(sv->get_active_pane() == ss::sheet_pane_t::bottom_left);
+ assert(sv->get_split_pane().hor_split == 0.0);
+ assert(sv->get_split_pane().ver_split == 1500.0);
+
+ {
+ ss::address_t expected = to_rc_address(resolver->resolve_address("A5"));
+ ss::address_t actual = sv->get_split_pane().top_left_cell;
+ assert(expected == actual);
+ }
+
+ expected_selections =
+ {
+ { ss::sheet_pane_t::top_left, "D2" },
+ { ss::sheet_pane_t::bottom_left, "C9" },
+ };
+
+ for (const expected_selection& es : expected_selections)
+ {
+ // cursor in the top-left pane.
+ ss::range_t expected = to_rc_range(resolver->resolve_range(es.sel));
+ ss::range_t actual = sv->get_selection(es.pane);
+ assert(expected == actual);
+ }
+
+ sv = view.get_sheet_view(3);
+ assert(sv);
+
+ // Sheet4 is vertically split into left and right views (top-left and top-right).
+ assert(sv->get_active_pane() == ss::sheet_pane_t::top_left);
+ assert(sv->get_split_pane().hor_split == 4230.0);
+ assert(sv->get_split_pane().ver_split == 0.0);
+
+ {
+ ss::address_t expected = to_rc_address(resolver->resolve_address("E1"));
+ ss::address_t actual = sv->get_split_pane().top_left_cell;
+ assert(expected == actual);
+ }
+
+ expected_selections =
+ {
+ { ss::sheet_pane_t::top_left, "B18" },
+ { ss::sheet_pane_t::top_right, "I11" },
+ };
+
+ for (const expected_selection& es : expected_selections)
+ {
+ // cursor in the top-left pane.
+ ss::range_t expected = to_rc_range(resolver->resolve_range(es.sel));
+ ss::range_t actual = sv->get_selection(es.pane);
+ assert(expected == actual);
+ }
+}
+
+void test_xlsx_view_frozen_pane()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string path(SRCDIR"/test/xlsx/view/frozen-pane.xlsx");
+
+ ss::document doc{{1048576, 16384}};
+ ss::view view(doc);
+ ss::import_factory factory(doc, view);
+ orcus_xlsx app(&factory);
+ app.set_config(test_config);
+
+ app.read_file(path.c_str());
+
+ ss::iface::import_reference_resolver* resolver =
+ factory.get_reference_resolver(ss::formula_ref_context_t::global);
+ assert(resolver);
+
+ // Sheet3 should be active.
+ assert(view.get_active_sheet() == 2);
+
+ const ss::sheet_view* sv = view.get_sheet_view(0);
+ assert(sv);
+
+ {
+ // Sheet1 is vertically frozen between columns A and B.
+ const ss::frozen_pane_t& fp = sv->get_frozen_pane();
+ assert(fp.top_left_cell == to_rc_address(resolver->resolve_address("B1")));
+ assert(fp.visible_columns == 1);
+ assert(fp.visible_rows == 0);
+ assert(sv->get_active_pane() == ss::sheet_pane_t::top_right);
+ }
+
+ sv = view.get_sheet_view(1);
+ assert(sv);
+
+ {
+ // Sheet2 is horizontally frozen between rows 1 and 2.
+ const ss::frozen_pane_t& fp = sv->get_frozen_pane();
+ assert(fp.top_left_cell == to_rc_address(resolver->resolve_address("A2")));
+ assert(fp.visible_columns == 0);
+ assert(fp.visible_rows == 1);
+ assert(sv->get_active_pane() == ss::sheet_pane_t::bottom_left);
+ }
+
+ sv = view.get_sheet_view(2);
+ assert(sv);
+
+ {
+ // Sheet3 is frozen both horizontally and vertically.
+ const ss::frozen_pane_t& fp = sv->get_frozen_pane();
+ assert(fp.top_left_cell == to_rc_address(resolver->resolve_address("E9")));
+ assert(fp.visible_columns == 4);
+ assert(fp.visible_rows == 8);
+ assert(sv->get_active_pane() == ss::sheet_pane_t::bottom_right);
+ }
+}
+
+void test_xlsx_doc_structure_unordered_sheet_positions()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view path(SRCDIR"/test/xlsx/doc-structure/unordered-sheet-positions.xlsx");
+ std::unique_ptr<ss::document> doc = load_doc(path);
+
+ // There should be 9 sheets named S1, S2, ..., S9.
+ std::vector<std::string_view> expected_sheet_names = {
+ "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9"
+ };
+
+ assert(doc->get_sheet_count() == expected_sheet_names.size());
+
+ ss::sheet_t n = expected_sheet_names.size();
+ for (ss::sheet_t i = 0; i < n; ++i)
+ {
+ std::string_view sheet_name = doc->get_sheet_name(i);
+ assert(sheet_name == expected_sheet_names[i]);
+ }
+}
+
+}
+
+int main()
+{
+ test_config.debug = false;
+ test_config.structure_check = true;
+
+ test_xlsx_detection();
+ test_xlsx_create_filter();
+ test_xlsx_import();
+ test_xlsx_table_autofilter();
+ test_xlsx_table();
+ test_xlsx_merged_cells();
+ test_xlsx_date_time();
+ test_xlsx_background_fill();
+ test_xlsx_number_format();
+ test_xlsx_text_alignment();
+ test_xlsx_cell_borders_single_cells();
+ test_xlsx_cell_borders_directions();
+ test_xlsx_cell_borders_colors();
+ test_xlsx_hidden_rows_columns();
+ test_xlsx_cell_properties();
+ test_xlsx_styles_direct_format();
+ test_xlsx_styles_column_styles();
+ test_xlsx_formatted_text_basic();
+
+ // pivot table
+ test_xlsx_pivot_two_pivot_caches();
+ test_xlsx_pivot_mixed_type_field();
+ test_xlsx_pivot_group_field();
+ test_xlsx_pivot_group_by_numbers();
+ test_xlsx_pivot_group_by_dates();
+ test_xlsx_pivot_error_values();
+
+ // view import
+ test_xlsx_view_cursor_per_sheet();
+ test_xlsx_view_cursor_split_pane();
+ test_xlsx_view_frozen_pane();
+
+ // document structure
+ test_xlsx_doc_structure_unordered_sheet_positions();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_test_xml.cpp b/src/orcus_test_xml.cpp
new file mode 100644
index 0000000..eb6bc95
--- /dev/null
+++ b/src/orcus_test_xml.cpp
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/sax_ns_parser.hpp"
+#include "orcus/dom_tree.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/stream.hpp"
+
+#include <cstdlib>
+#include <cassert>
+#include <iostream>
+#include <sstream>
+
+using namespace orcus;
+using namespace std;
+
+class sax_handler_encoded_attrs
+{
+ std::vector<sax::parser_attribute> m_attrs;
+
+public:
+ void doctype(const sax::doctype_declaration&) {}
+
+ void start_declaration(std::string_view) {}
+
+ void end_declaration(std::string_view)
+ {
+ m_attrs.clear();
+ }
+
+ void start_element(const sax::parser_element&) {}
+
+ void end_element(const sax::parser_element&) {}
+
+ void characters(std::string_view, bool) {}
+
+ void attribute(const sax::parser_attribute& attr)
+ {
+ m_attrs.push_back(attr);
+ }
+
+ bool check(const vector<string>& expected) const
+ {
+ if (m_attrs.size() != expected.size())
+ {
+ cerr << "unexpected attribute count." << endl;
+ return false;
+ }
+
+ for (size_t i = 0, n = m_attrs.size(); i < n; ++i)
+ {
+ if (m_attrs[i].value != expected[i].c_str())
+ {
+ cerr << "expected attribute value: " << expected[i] << " actual attribute value: " << m_attrs[i].value << endl;
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
+const char* sax_parser_test_dirs[] = {
+ SRCDIR"/test/xml/simple/",
+ SRCDIR"/test/xml/encoded-char/",
+ SRCDIR"/test/xml/default-ns/",
+ SRCDIR"/test/xml/ns-alias-1/",
+ SRCDIR"/test/xml/bom/",
+ SRCDIR"/test/xml/custom-decl-1/",
+ SRCDIR"/test/xml/cdata-1/",
+ SRCDIR"/test/xml/single-quote/",
+ SRCDIR"/test/xml/no-decl-1/",
+ SRCDIR"/test/xml/underscore-identifier/",
+ SRCDIR"/test/xml/self-closing-root/",
+ SRCDIR"/test/xml/utf8-1/",
+ SRCDIR"/test/xml/utf8-2/",
+};
+
+const char* sax_parser_parse_only_test_dirs[] = {
+ SRCDIR"/test/xml/parse-only/rss/"
+};
+
+void parse_file(dom::document_tree& tree, const char* filepath, std::string& /*strm*/)
+{
+ cout << "testing " << filepath << endl;
+ file_content content(filepath);
+ assert(!content.empty());
+
+ tree.load(content.str());
+}
+
+void test_xml_sax_parser()
+{
+ string strm;
+ size_t n = sizeof(sax_parser_test_dirs)/sizeof(sax_parser_test_dirs[0]);
+ for (size_t i = 0; i < n; ++i)
+ {
+ const char* dir = sax_parser_test_dirs[i];
+ string dir_path(dir);
+ string file = dir_path;
+ file.append("input.xml");
+
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+ dom::document_tree tree(cxt);
+ parse_file(tree, file.c_str(), strm);
+
+ // Get the compact form of the content.
+ ostringstream os;
+ tree.dump_compact(os);
+ string content = os.str();
+
+ // Load the check form.
+ file = dir_path;
+ file.append("check.txt");
+ file_content check(file.data());
+ std::string_view psource(content);
+ std::string_view pcheck = check.str();
+
+ // They must be equal, minus preceding or trailing spaces (if any).
+ assert(trim(psource) == trim(pcheck));
+ }
+}
+
+void test_xml_sax_parser_read_only()
+{
+ string strm;
+ size_t n = sizeof(sax_parser_parse_only_test_dirs)/sizeof(sax_parser_parse_only_test_dirs[0]);
+ for (size_t i = 0; i < n; ++i)
+ {
+ const char* dir = sax_parser_parse_only_test_dirs[i];
+ string dir_path(dir);
+ string file = dir_path;
+ file.append("input.xml");
+
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+ dom::document_tree tree(cxt);
+ parse_file(tree, file.c_str(), strm);
+ }
+}
+
+void test_xml_declarations()
+{
+ string strm;
+ const char* file_path = SRCDIR"/test/xml/custom-decl-1/input.xml";
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+ dom::document_tree dom(cxt);
+ parse_file(dom, file_path, strm);
+
+ // Make sure we parse the custom declaration correctly.
+ dom::const_node decl = dom.declaration("mso-application");
+ assert(decl.type() == dom::node_t::declaration);
+ assert(decl.attribute("progid") == "Excel.Sheet");
+}
+
+void test_xml_dtd()
+{
+ struct {
+ const char* file_path;
+ sax::doctype_declaration::keyword_type keyword;
+ const char* root_element;
+ const char* fpi;
+ const char* uri;
+ } tests[] = {
+ { SRCDIR"/test/xml/doctype/html.xml", sax::doctype_declaration::keyword_type::dtd_public,
+ "html", "-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" }
+ };
+
+ xmlns_repository repo;
+ size_t n = sizeof(tests)/sizeof(tests[0]);
+
+ for (size_t i = 0; i < n; ++i)
+ {
+ const char* file_path = tests[i].file_path;
+ string strm;
+ xmlns_context cxt = repo.create_context();
+ dom::document_tree dom(cxt);
+ parse_file(dom, file_path, strm);
+ const sax::doctype_declaration* dtd = dom.get_doctype();
+ assert(dtd);
+ assert(dtd->keyword == tests[i].keyword);
+ assert(dtd->root_element == tests[i].root_element);
+ assert(dtd->fpi == tests[i].fpi);
+ if (tests[i].uri)
+ {
+ assert(dtd->uri == tests[i].uri);
+ }
+ }
+}
+
+void test_xml_encoded_attrs()
+{
+ const char* filepath = SRCDIR"/test/xml/encoded-attrs/test1.xml";
+
+ cout << "testing " << filepath << endl;
+ file_content content(filepath);
+ assert(!content.empty());
+
+ sax_handler_encoded_attrs hdl;
+ sax_parser<sax_handler_encoded_attrs> parser(content.str(), hdl);
+ parser.parse();
+
+ vector<string> expected;
+ expected.push_back("1 & 2");
+ expected.push_back("3 & 4");
+ expected.push_back("5 & 6");
+ assert(hdl.check(expected));
+}
+
+int main()
+{
+ test_xml_sax_parser();
+ test_xml_sax_parser_read_only();
+ test_xml_declarations();
+ test_xml_dtd();
+ test_xml_encoded_attrs();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_test_xml_mapped.cpp b/src/orcus_test_xml_mapped.cpp
new file mode 100644
index 0000000..16d19ec
--- /dev/null
+++ b/src/orcus_test_xml_mapped.cpp
@@ -0,0 +1,321 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/orcus_xml.hpp>
+#include <orcus/sax_ns_parser.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <orcus/stream.hpp>
+#include <orcus/dom_tree.hpp>
+
+#include <orcus/spreadsheet/factory.hpp>
+#include <orcus/spreadsheet/document.hpp>
+
+#include "orcus_test_global.hpp"
+
+#include <cstdlib>
+#include <cassert>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <vector>
+
+#include "filesystem_env.hpp"
+
+using namespace orcus;
+
+const fs::path test_base_dir(SRCDIR"/test/xml-mapped");
+
+namespace {
+
+void test_mapped_xml_import()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ struct test_case
+ {
+ const char* base_dir;
+ bool output_equals_input;
+ };
+
+ const std::vector<test_case> tests =
+ {
+ { SRCDIR"/test/xml-mapped/attribute-basic", true },
+ { SRCDIR"/test/xml-mapped/attribute-namespace", true },
+ { SRCDIR"/test/xml-mapped/attribute-namespace-2", false },
+ { SRCDIR"/test/xml-mapped/attribute-range-self-close", true },
+ { SRCDIR"/test/xml-mapped/attribute-single-element", true },
+ { SRCDIR"/test/xml-mapped/attribute-single-element-2", true },
+ { SRCDIR"/test/xml-mapped/content-basic", true },
+ { SRCDIR"/test/xml-mapped/content-namespace", false },
+ { SRCDIR"/test/xml-mapped/content-namespace-2", true },
+ { SRCDIR"/test/xml-mapped/content-namespace-3", false },
+ { SRCDIR"/test/xml-mapped/custom-labels", true },
+ { SRCDIR"/test/xml-mapped/custom-labels-2", true },
+ { SRCDIR"/test/xml-mapped/fuel-economy", true },
+ { SRCDIR"/test/xml-mapped/nested-repeats", false },
+ { SRCDIR"/test/xml-mapped/nested-repeats-2", false },
+ { SRCDIR"/test/xml-mapped/nested-repeats-3", false },
+ { SRCDIR"/test/xml-mapped/nested-repeats-4", false },
+ };
+
+ auto dump_xml_structure = [](const file_content& content, xmlns_context& cxt)
+ {
+ dom::document_tree tree(cxt);
+ tree.load(content.str());
+ std::ostringstream os;
+ tree.dump_compact(os);
+ return os.str();
+ };
+
+ const fs::path temp_output_xml = fs::temp_directory_path() / "orcus-output.xml";
+
+ std::string strm;
+
+ for (const test_case& tc : tests)
+ {
+ fs::path base_dir(tc.base_dir);
+ fs::path data_file = base_dir / "input.xml";
+ fs::path map_file = base_dir / "map.xml";
+ fs::path check_file = base_dir / "check.txt";
+
+ // Load the data file content.
+ std::cout << "reading " << data_file.string() << std::endl;
+ file_content content(data_file.string().data());
+ std::string data_strm{content.str()};
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory import_fact(doc);
+ spreadsheet::export_factory export_fact(doc);
+
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+
+ // Parse the map file to define map rules, and parse the data file.
+ orcus_xml app(repo, &import_fact, &export_fact);
+ file_content map_content(map_file.string().data());
+ app.read_map_definition(map_content.str());
+ app.read_stream(data_strm);
+
+ // Zero the source data stream to make sure it's completely erased off
+ // memory.
+ std::for_each(data_strm.begin(), data_strm.end(), [](char& c) { c = '\0'; });
+ assert(data_strm[0] == '\0');
+ assert(data_strm[data_strm.size()-1] == '\0');
+
+ // Check the content of the document against static check file.
+ std::ostringstream os;
+ doc.dump_check(os);
+ std::string loaded = os.str();
+ content.load(check_file.string().data());
+ strm = content.str();
+
+ assert(!loaded.empty());
+ assert(!strm.empty());
+
+ std::string_view p1(loaded.data(), loaded.size()), p2(strm.data(), strm.size());
+
+ p1 = trim(p1);
+ p2 = trim(p2);
+ assert(p1 == p2);
+
+ if (tc.output_equals_input)
+ {
+ // Output to xml file with the linked values coming from the document.
+ std::cout << "writing to " << temp_output_xml << std::endl;
+ {
+ // Create a duplicate source XML stream.
+ content.load(data_file.string());
+ std::string data_strm_dup{content.str()};
+ std::ofstream file(temp_output_xml.string(), std::ios::out | std::ios::trunc);
+ assert(file);
+ app.write(data_strm_dup, file);
+ }
+
+ // Compare the logical xml content of the output xml with the
+ // input one. They should be identical.
+
+ // Hold the stream content in memory while the namespace context is being used.
+ file_content strm_data_file(data_file.string());
+ file_content strm_out_file(temp_output_xml.string());
+ std::string dump_input = dump_xml_structure(strm_data_file, cxt);
+ std::string dump_output = dump_xml_structure(strm_out_file, cxt);
+ assert(!dump_input.empty() && !dump_output.empty());
+
+ std::cout << dump_input << std::endl;
+ std::cout << "--" << std::endl;
+ std::cout << dump_output << std::endl;
+ assert(dump_input == dump_output);
+ }
+ }
+
+ // Delete the temporary xml output.
+ fs::remove(temp_output_xml);
+}
+
+void test_mapped_xml_import_no_map_definition()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ const std::vector<fs::path> tests = {
+ test_base_dir / "attribute-basic",
+ test_base_dir / "attribute-namespace",
+ test_base_dir / "attribute-namespace-2",
+ test_base_dir / "attribute-range-self-close",
+ test_base_dir / "content-basic",
+ test_base_dir / "content-one-column",
+ test_base_dir / "content-namespace",
+ test_base_dir / "content-namespace-2",
+ test_base_dir / "content-namespace-3",
+ test_base_dir / "fuel-economy",
+ test_base_dir / "nested-repeats",
+ test_base_dir / "nested-repeats-2",
+ test_base_dir / "nested-repeats-3",
+ test_base_dir / "nested-repeats-4",
+ };
+
+ for (const fs::path& base_dir : tests)
+ {
+ fs::path input_file = base_dir / "input.xml";
+ fs::path check_file = base_dir / "check-nomap.txt";
+
+ std::cout << "reading " << input_file.string() << std::endl;
+
+ file_content content(input_file.string().data());
+ file_content expected(check_file.string().data());
+
+ xmlns_repository repo;
+
+ {
+ // Automatically detect map definition without a map file.
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory import_fact(doc);
+
+ orcus_xml app(repo, &import_fact, nullptr);
+
+ app.detect_map_definition(content.str());
+ app.read_stream(content.str());
+
+ test::verify_content(__FILE__, __LINE__, doc, expected.str());
+ }
+
+ {
+ // Generate a map file and use it to import the XML document.
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory import_fact(doc);
+
+ orcus_xml app(repo, &import_fact, nullptr);
+
+ std::ostringstream os;
+ app.write_map_definition(content.str(), os);
+ std::string map_def = os.str();
+ app.read_map_definition(map_def);
+ app.read_stream(content.str());
+
+ test::verify_content(__FILE__, __LINE__, doc, expected.str());
+ }
+ }
+}
+
+void test_invalid_map_definition()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path invalids_dir = test_base_dir / "invalids" / "map-defs";
+
+ const std::vector<fs::path> tests = {
+ invalids_dir / "not-xml.xml",
+ invalids_dir / "non-leaf-element-linked.xml",
+ };
+
+ xmlns_repository repo;
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory import_fact(doc);
+ orcus_xml app(repo, &import_fact, nullptr);
+
+ for (const fs::path& test : tests)
+ {
+ std::cout << test.string() << std::endl;
+ file_content content(test.string().data());
+ doc.clear();
+
+ try
+ {
+ app.read_map_definition(content.str());
+ assert(!"We were expecting an exception, but didn't get one.");
+ }
+ catch (const invalid_map_error& e)
+ {
+ // Success!
+ std::cout << std::endl
+ << "Exception received as expected, with the following message:" << std::endl
+ << std::endl
+ << test::prefix_multiline_string(e.what(), " ") << std::endl
+ << std::endl;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ assert(!"Wrong exception thrown.");
+ }
+ }
+}
+
+void test_encoding()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ const fs::path test_dir = test_base_dir / "encoding";
+
+ struct test_case
+ {
+ const fs::path path;
+ character_set_t charset;
+ };
+
+ const test_case tests[] = {
+ { test_dir / "utf-8.xml", character_set_t::utf_8 },
+ { test_dir / "gbk.xml", character_set_t::gbk },
+ { test_dir / "euc-jp.xml", character_set_t::euc_jp },
+ };
+
+ for (const auto& test : tests)
+ {
+ std::cout << "reading " << test.path.string() << std::endl;
+
+ file_content content(test.path.string());
+
+ xmlns_repository repo;
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory import_fact(doc);
+ orcus_xml app(repo, &import_fact, nullptr);
+
+ app.read_stream(content.str());
+
+ assert(import_fact.get_character_set() == test.charset);
+ }
+}
+
+} // anonymous namespace
+
+int main()
+{
+ test_mapped_xml_import();
+ test_mapped_xml_import_no_map_definition();
+ test_invalid_map_definition();
+ test_encoding();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_xls_xml_main.cpp b/src/orcus_xls_xml_main.cpp
new file mode 100644
index 0000000..b54e1b7
--- /dev/null
+++ b/src/orcus_xls_xml_main.cpp
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_xls_xml.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/view.hpp"
+
+#include "orcus_filter_global.hpp"
+
+#include <iostream>
+
+using namespace orcus;
+
+int main(int argc, char** argv) try
+{
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::view view(doc);
+ spreadsheet::import_factory fact(doc, view);
+ orcus_xls_xml app(&fact);
+
+ if (!parse_import_filter_args(argc, argv, fact, app, doc))
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
+catch (const std::exception& e)
+{
+ std::cerr << e.what() << std::endl;
+ return EXIT_FAILURE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_xlsx_main.cpp b/src/orcus_xlsx_main.cpp
new file mode 100644
index 0000000..7c09bec
--- /dev/null
+++ b/src/orcus_xlsx_main.cpp
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_xlsx.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/view.hpp"
+
+#include "orcus_filter_global.hpp"
+
+#include <iostream>
+
+using namespace orcus;
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::view view(doc);
+ spreadsheet::import_factory fact(doc, view);
+
+ orcus_xlsx app(&fact);
+
+ if (!parse_import_filter_args(argc, argv, fact, app, doc))
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_xml_main.cpp b/src/orcus_xml_main.cpp
new file mode 100644
index 0000000..a1f38c5
--- /dev/null
+++ b/src/orcus_xml_main.cpp
@@ -0,0 +1,350 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/orcus_xml.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/xml_structure_tree.hpp"
+#include "orcus/dom_tree.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/stream.hpp"
+#include "orcus/sax_parser_base.hpp"
+
+#include "orcus_filter_global.hpp"
+#include "cli_global.hpp"
+
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <fstream>
+#include <boost/program_options.hpp>
+#include <mdds/sorted_string_map.hpp>
+
+#include "filesystem_env.hpp"
+
+using namespace orcus;
+using namespace std;
+namespace po = boost::program_options;
+
+namespace {
+
+namespace output_mode {
+
+enum class type {
+ unknown,
+ dump,
+ map,
+ map_gen,
+ transform_xml,
+ structure,
+};
+
+using map_type = mdds::sorted_string_map<type, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "dump", type::dump },
+ { "map", type::map },
+ { "map-gen", type::map_gen },
+ { "structure", type::structure },
+ { "transform", type::transform_xml },
+};
+
+const map_type& get()
+{
+ static const map_type mt(entries, std::size(entries), type::unknown);
+ return mt;
+}
+
+} // namespace output_mode
+
+std::string to_string(output_mode::type t)
+{
+ for (const output_mode::map_type::entry& e : output_mode::entries)
+ if (t == e.value)
+ return std::string(e.key);
+
+ return std::string();
+}
+
+void print_usage(ostream& os, const po::options_description& desc)
+{
+ os << "Usage: orcus-xml [OPTIONS] FILE" << endl << endl;
+ os << desc;
+}
+
+std::string build_output_help_text()
+{
+ std::ostringstream os;
+ os << "Path to either an output directory, or an output file.";
+ return os.str();
+}
+
+std::string build_mode_help_text()
+{
+ std::ostringstream os;
+ os << "Mode of operation. Select one of the following options: ";
+ auto it = output_mode::entries, ite = output_mode::entries + std::size(output_mode::entries);
+ --ite;
+
+ for (; it != ite; ++it)
+ os << std::string(it->key) << ", ";
+
+ os << "or " << std::string(it->key) << ".";
+ return os.str();
+}
+
+std::string build_map_help_text()
+{
+ std::ostringstream os;
+ os << "Path to the map file. A map file is required for all modes except for the "
+ << to_string(output_mode::type::structure) << " mode.";
+ return os.str();
+}
+
+bool parse_and_dump_structure(const file_content& content, const std::string& output)
+{
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+ xml_structure_tree tree(cxt);
+ tree.parse(content.str());
+
+ if (output.empty())
+ {
+ tree.dump_compact(cout);
+ return true;
+ }
+
+ ofstream file(output);
+ if (!file)
+ {
+ cerr << "failed to create output file: " << output << endl;
+ return false;
+ }
+
+ tree.dump_compact(file);
+
+ return true;
+}
+
+void dump_document_structure(const file_content& content, output_stream& os)
+{
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+ dom::document_tree tree(cxt);
+ tree.load(content.str());
+
+ tree.dump_compact(os.get());
+}
+
+} // anonymous namespace
+
+int main(int argc, char** argv) try
+{
+ po::options_description desc("Options");
+ desc.add_options()
+ ("help,h", "Print this help.")
+ ("mode", po::value<std::string>(), build_mode_help_text().data())
+ ("map,m", po::value<std::string>(), build_map_help_text().data())
+ ("output,o", po::value<std::string>(), build_output_help_text().data())
+ ("output-format,f", po::value<string>(), gen_help_output_format().data())
+ ;
+
+ po::options_description hidden("");
+ hidden.add_options()
+ ("input", po::value<string>(), "input file");
+
+ po::positional_options_description po_desc;
+ po_desc.add("input", 1);
+
+ po::options_description cmd_opt;
+ cmd_opt.add(desc).add(hidden);
+
+ po::variables_map vm;
+ try
+ {
+ po::store(
+ po::command_line_parser(argc, argv).options(cmd_opt).positional(po_desc).run(), vm);
+ po::notify(vm);
+ }
+ catch (const exception& e)
+ {
+ // Unknown options.
+ cerr << e.what() << endl;
+ print_usage(cout, desc);
+ return EXIT_FAILURE;
+ }
+
+ if (vm.count("help"))
+ {
+ print_usage(cout, desc);
+ return EXIT_FAILURE;
+ }
+
+ if (!vm.count("input"))
+ {
+ cerr << "No input file." << endl;
+ print_usage(cout, desc);
+ return EXIT_FAILURE;
+ }
+
+ if (!vm.count("mode"))
+ {
+ cerr << "Mode not specified." << endl;
+ print_usage(cout, desc);
+ return EXIT_FAILURE;
+ }
+
+ std::string s = vm["mode"].as<std::string>();
+ output_mode::type mode = output_mode::get().find(s);
+
+ if (mode == output_mode::type::unknown)
+ {
+ cerr << "Unknown output mode: " << s << endl;
+ print_usage(cout, desc);
+ return EXIT_FAILURE;
+ }
+
+ fs::path input_path = vm["input"].as<std::string>();
+
+ if (!fs::is_regular_file(input_path))
+ {
+ cerr << input_path << " is not a valid file." << endl;
+ return EXIT_FAILURE;
+ }
+
+ fs::path map_path;
+ if (vm.count("map"))
+ {
+ map_path = vm["map"].as<std::string>();
+
+ if (!fs::is_regular_file(map_path))
+ {
+ cerr << map_path << " is not a valid map file." << endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ std::string output;
+ if (vm.count("output"))
+ output = vm["output"].as<std::string>();
+
+ file_content content(input_path.string().data());
+
+ try
+ {
+ switch (mode)
+ {
+ case output_mode::type::structure:
+ {
+ bool success = parse_and_dump_structure(content, output);
+ return success ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+ case output_mode::type::dump:
+ {
+ output_stream os(vm);
+ dump_document_structure(content, os);
+ return EXIT_SUCCESS;
+ }
+ case output_mode::type::map_gen:
+ {
+ output_stream os(vm);
+ xmlns_repository repo;
+ orcus_xml app(repo, nullptr, nullptr);
+ app.write_map_definition(content.str(), os.get());
+ return EXIT_SUCCESS;
+ }
+ default:
+ ;
+ }
+
+ spreadsheet::range_size_t ss{1048576, 16384};
+ spreadsheet::document doc{ss};
+ spreadsheet::import_factory import_fact(doc);
+ spreadsheet::export_factory export_fact(doc);
+
+ xmlns_repository repo;
+ orcus_xml app(repo, &import_fact, &export_fact);
+
+ if (map_path.empty())
+ app.detect_map_definition(content.str());
+ else
+ {
+ file_content map_content(map_path.string().data());
+ app.read_map_definition(map_content.str());
+ }
+
+ app.read_stream(content.str());
+
+ switch (mode)
+ {
+ case output_mode::type::map:
+ {
+ dump_format_t format = dump_format_t::unknown;
+ s.clear();
+
+ if (vm.count("output-format"))
+ {
+ s = vm["output-format"].as<std::string>();
+ format = to_dump_format_enum(s);
+ }
+ else
+ {
+ cerr << "Output format is not specified." << endl;
+ print_usage(cout, desc);
+ return EXIT_FAILURE;
+ }
+
+ if (format == dump_format_t::unknown)
+ {
+ std::cerr << "Unsupported output format: '" << s << "'" << endl;
+ return EXIT_FAILURE;
+ }
+
+ doc.dump(format, output);
+ break;
+ }
+ case output_mode::type::transform_xml:
+ {
+ if (output.empty())
+ {
+ cout << "output xml file name not provided" << endl;
+ print_usage(cout, desc);
+ return EXIT_FAILURE;
+ }
+
+ ofstream file(output);
+ if (!file)
+ {
+ cerr << "failed to create output file: " << output << endl;
+ return EXIT_FAILURE;
+ }
+
+ // Write transformed xml content to file.
+ app.write(content.str(), file);
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ catch (const malformed_xml_error& e)
+ {
+ cerr << create_parse_error_output(content.str(), e.offset()) << endl;
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+catch (const std::exception& e)
+{
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_yaml_main.cpp b/src/orcus_yaml_main.cpp
new file mode 100644
index 0000000..bb1d43c
--- /dev/null
+++ b/src/orcus_yaml_main.cpp
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/yaml_document_tree.hpp"
+#include "orcus/yaml_parser_base.hpp"
+#include "orcus/config.hpp"
+#include "orcus/stream.hpp"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#include <boost/program_options.hpp>
+
+#include "filesystem_env.hpp"
+
+using namespace std;
+using namespace orcus;
+
+namespace po = boost::program_options;
+
+const char* help_program = "The FILE must specify a path to an existing file.";
+const char* err_no_input_file = "No input file.";
+const char* help_yaml_output = "Output file path.";
+const char* help_yaml_output_format =
+"Specify the format of output file. Supported format types are:\n"
+" 1) yaml\n"
+" 2) json";
+
+void print_yaml_usage(std::ostream& os, const po::options_description& desc)
+{
+ os << "Usage: orcus-yaml [options] FILE" << endl << endl;
+ os << help_program << endl << endl << desc;
+}
+
+std::unique_ptr<yaml_config> parse_yaml_args(int argc, char** argv)
+{
+ po::options_description desc("Options");
+ desc.add_options()
+ ("help,h", "Print this help.")
+ ("output,o", po::value<string>(), help_yaml_output)
+ ("output-format,f", po::value<string>(), help_yaml_output_format);
+
+ po::options_description hidden("Hidden options");
+ hidden.add_options()
+ ("input", po::value<string>(), "input file");
+
+ po::options_description cmd_opt;
+ cmd_opt.add(desc).add(hidden);
+
+ po::positional_options_description po_desc;
+ po_desc.add("input", -1);
+
+ po::variables_map vm;
+ try
+ {
+ po::store(
+ po::command_line_parser(argc, argv).options(cmd_opt).positional(po_desc).run(), vm);
+ po::notify(vm);
+ }
+ catch (const exception& e)
+ {
+ // Unknown options.
+ cerr << e.what() << endl;
+ print_yaml_usage(cerr, desc);
+ return nullptr;
+ }
+
+ if (vm.count("help"))
+ {
+ print_yaml_usage(cout, desc);
+ return nullptr;
+ }
+
+ std::unique_ptr<yaml_config> config = std::make_unique<yaml_config>();
+
+ if (vm.count("input"))
+ config->input_path = vm["input"].as<string>();
+
+ if (vm.count("output"))
+ config->output_path = vm["output"].as<string>();
+
+ if (vm.count("output-format"))
+ {
+ std::string outformat = vm["output-format"].as<string>();
+ if (outformat == "none")
+ config->output_format = yaml_config::output_format_type::none;
+ else if (outformat == "yaml")
+ config->output_format = yaml_config::output_format_type::yaml;
+ else if (outformat == "json")
+ config->output_format = yaml_config::output_format_type::json;
+ else
+ {
+ cerr << "Unknown output format type '" << outformat << "'." << endl;
+ return nullptr;
+ }
+ }
+ else
+ {
+ cerr << "Output format is not specified." << endl;
+ print_yaml_usage(cerr, desc);
+ return nullptr;
+ }
+
+ if (config->input_path.empty())
+ {
+ cerr << err_no_input_file << endl;
+ print_yaml_usage(cerr, desc);
+ return nullptr;
+ }
+
+ if (!fs::exists(config->input_path))
+ {
+ cerr << "Input file does not exist: " << config->input_path << endl;
+ return nullptr;
+ }
+
+ if (config->output_format != yaml_config::output_format_type::none)
+ {
+ if (config->output_path.empty())
+ {
+ cerr << "Output file not given." << endl;
+ return nullptr;
+ }
+
+ // Check to make sure the output path doesn't point to an existing
+ // directory.
+ if (fs::is_directory(config->output_path))
+ {
+ cerr << "Output file path points to an existing directory. Aborting." << endl;
+ return nullptr;
+ }
+ }
+
+ return config;
+}
+
+std::unique_ptr<yaml::document_tree> load_doc(const char* p, size_t n)
+{
+ std::unique_ptr<yaml::document_tree> doc(std::make_unique<yaml::document_tree>());
+ try
+ {
+ doc->load({p, n});
+ }
+ catch (const parse_error& e)
+ {
+ cerr << create_parse_error_output(std::string_view(p, n), e.offset()) << endl;
+ throw;
+ }
+ return doc;
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ std::unique_ptr<yaml_config> config = parse_yaml_args(argc, argv);
+ if (!config)
+ return EXIT_FAILURE;
+
+ file_content content(config->input_path.data());
+ std::unique_ptr<yaml::document_tree> doc = load_doc(content.data(), content.size());
+
+ switch (config->output_format)
+ {
+ case yaml_config::output_format_type::yaml:
+ {
+ ofstream fs(config->output_path.c_str());
+ fs << doc->dump_yaml();
+ }
+ break;
+ case yaml_config::output_format_type::json:
+ {
+ ofstream fs(config->output_path.c_str());
+ fs << doc->dump_json();
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ catch (const std::exception& e)
+ {
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/orcus_zip_dump.cpp b/src/orcus_zip_dump.cpp
new file mode 100644
index 0000000..1cf81e7
--- /dev/null
+++ b/src/orcus_zip_dump.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/zip_archive.hpp"
+#include "orcus/zip_archive_stream.hpp"
+
+#include <cstdlib>
+#include <vector>
+#include <iostream>
+
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ if (argc < 2)
+ return EXIT_FAILURE;
+
+ try
+ {
+ orcus::zip_archive_stream_fd stream(argv[1]);
+ orcus::zip_archive archive(&stream);
+ archive.load();
+ size_t n = archive.get_file_entry_count();
+
+ if (argc < 3)
+ {
+ for (size_t i = 0; i < n; ++i)
+ {
+ auto header = archive.get_file_entry_header(i);
+ std::cout << "--" << std::endl;
+ std::cout << header << std::endl;
+ }
+ return EXIT_SUCCESS;
+ }
+
+ auto header = archive.get_file_entry_header(argv[2]);
+ std::cout << header << std::endl;
+ }
+ catch (const std::exception& e)
+ {
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/Makefile.am b/src/parser/Makefile.am
new file mode 100644
index 0000000..c5c534c
--- /dev/null
+++ b/src/parser/Makefile.am
@@ -0,0 +1,338 @@
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include \
+ -DSRCDIR=\""$(top_srcdir)"\" \
+ $(BOOST_CPPFLAGS) \
+ -D__ORCUS_PSR_BUILDING_DLL
+
+if HAVE_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_FILESYSTEM=1"
+endif
+
+if HAVE_EXPERIMENTAL_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+endif
+
+lib_LTLIBRARIES = liborcus-parser-@ORCUS_API_VERSION@.la
+liborcus_parser_@ORCUS_API_VERSION@_la_SOURCES = \
+ win_stdint.h \
+ base64.cpp \
+ cell_buffer.cpp \
+ css_parser_base.cpp \
+ css_types.cpp \
+ csv_parser_base.cpp \
+ exception.cpp \
+ json_global.cpp \
+ json_parser_base.cpp \
+ json_parser_thread.cpp \
+ parser_base.cpp \
+ parser_global.cpp \
+ sax_parser_base.cpp \
+ sax_token_parser.cpp \
+ sax_token_parser_thread.cpp \
+ stream.cpp \
+ string_pool.cpp \
+ tokens.cpp \
+ types.cpp \
+ utf8.hpp \
+ utf8.cpp \
+ xml_namespace.cpp \
+ xml_writer.cpp \
+ yaml_parser_base.cpp \
+ zip_archive.cpp \
+ zip_archive_stream.cpp
+
+
+liborcus_parser_@ORCUS_API_VERSION@_la_LDFLAGS = \
+ -no-undefined \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+liborcus_parser_@ORCUS_API_VERSION@_la_LIBADD = \
+ $(BOOST_SYSTEM_LIBS) \
+ $(ZLIB_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+liborcus_parser_@ORCUS_API_VERSION@_la_LDFLAGS += -lstdc++fs
+else
+liborcus_parser_@ORCUS_API_VERSION@_la_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+liborcus_parser_@ORCUS_API_VERSION@_la_LIBADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+EXTRA_PROGRAMS = \
+ css-parser-test \
+ csv-parser-test \
+ json-parser-test \
+ parser-global-test \
+ parser-test-base \
+ parser-test-base64 \
+ parser-test-json-validation \
+ parser-test-numeric \
+ parser-test-stream \
+ parser-test-string-pool \
+ parser-test-threaded-json-parser \
+ parser-test-threaded-sax-token-parser \
+ parser-test-xml-namespace \
+ parser-test-xml-validation \
+ parser-test-zip-archive \
+ sax-ns-parser-test \
+ sax-parser-test \
+ sax-token-parser-test \
+ types-test \
+ utf8-test \
+ yaml-parser-test \
+ xml-writer-test
+
+# parser-test-string-pool
+
+parser_test_string_pool_SOURCES = \
+ string_pool.cpp \
+ string_pool_test.cpp
+
+parser_test_string_pool_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+parser_test_string_pool_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-xml-namespace
+
+parser_test_xml_namespace_SOURCES = \
+ xml_namespace.cpp \
+ xml_namespace_test.cpp
+
+parser_test_xml_namespace_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+
+parser_test_xml_namespace_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-xml-validation
+
+parser_test_xml_validation_SOURCES = \
+ parser_test_xml_validation.cpp
+
+parser_test_xml_validation_CPPFLAGS = $(AM_CPPFLAGS)
+parser_test_xml_validation_LDFLAGS = \
+ $(BOOST_SYSTEM_LDFLAGS)
+parser_test_xml_validation_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+parser_test_xml_validation_LDFLAGS += -lstdc++fs
+else
+parser_test_xml_validation_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+parser_test_xml_validation_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+# parser-test-base64
+
+parser_test_base64_SOURCES = \
+ base64.cpp \
+ base64_test.cpp
+
+parser_test_base64_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_base64_CPPFLAGS = $(AM_CPPFLAGS)
+
+# css-parser-test
+
+css_parser_test_SOURCES = \
+ css_parser_test.cpp
+
+css_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+css_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# csv-parser-test
+
+csv_parser_test_SOURCES = \
+ csv_parser_test.cpp
+
+csv_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+csv_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# json-parser-test
+
+json_parser_test_SOURCES = \
+ json_parser_test.cpp
+
+json_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+json_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# yaml-parser-test
+
+yaml_parser_test_SOURCES = \
+ yaml_parser_test.cpp
+
+yaml_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+yaml_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-parser-test
+
+sax_parser_test_SOURCES = \
+ sax_parser_test.cpp
+
+sax_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-ns-parser-test
+
+sax_ns_parser_test_SOURCES = \
+ sax_ns_parser_test.cpp
+
+sax_ns_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_ns_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-token-parser-test
+
+sax_token_parser_test_SOURCES = \
+ sax_token_parser_test.cpp
+
+sax_token_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_token_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-threaded-sax-token-parser
+
+parser_test_threaded_sax_token_parser_SOURCES = \
+ threaded_sax_token_parser_test.cpp
+
+parser_test_threaded_sax_token_parser_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_threaded_sax_token_parser_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-threaded-json-parser
+
+parser_test_threaded_json_parser_SOURCES = \
+ threaded_json_parser_test.cpp
+
+parser_test_threaded_json_parser_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_threaded_json_parser_LDFLAGS = -pthread
+parser_test_threaded_json_parser_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-stream
+
+parser_test_stream_SOURCES = \
+ stream_test.cpp
+
+parser_test_stream_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+parser_test_stream_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-zip-archive
+
+parser_test_zip_archive_SOURCES = \
+ zip_archive_test.cpp
+
+parser_test_zip_archive_CPPFLAGS = $(AM_CPPFLAGS)
+parser_test_zip_archive_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+parser_test_zip_archive_LDFLAGS = \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+parser_test_zip_archive_LDFLAGS += -lstdc++fs
+else
+parser_test_zip_archive_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+parser_test_zip_archive_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+
+
+# parser-test-base
+
+parser_test_base_SOURCES = \
+ parser_base_test.cpp
+
+parser_test_base_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_base_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-global-test
+
+parser_global_test_SOURCES = \
+ parser_global_test.cpp
+
+parser_global_test_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+parser_global_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-json-validation
+
+parser_test_json_validation_SOURCES = \
+ parser_test_json_validation.cpp
+
+parser_test_json_validation_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_json_validation_CPPFLAGS = $(AM_CPPFLAGS)
+
+# types-test
+
+types_test_SOURCES = types_test.cpp
+
+types_test_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+types_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# utf8-test
+
+utf8_test_SOURCES = \
+ utf8.cpp \
+ utf8_test.cpp
+
+utf8_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+utf8_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# xml-writer-test
+
+xml_writer_test_SOURCES = xml_writer_test.cpp
+
+xml_writer_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+xml_writer_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-numeric
+
+parser_test_numeric_SOURCES = \
+ parser_test_numeric.cpp
+
+parser_test_numeric = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_numeric_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_numeric_CPPFLAGS = $(AM_CPPFLAGS)
+
+TESTS = \
+ css-parser-test \
+ csv-parser-test \
+ json-parser-test \
+ parser-global-test \
+ parser-test-base \
+ parser-test-base64 \
+ parser-test-json-validation \
+ parser-test-numeric \
+ parser-test-stream \
+ parser-test-string-pool \
+ parser-test-threaded-json-parser \
+ parser-test-threaded-sax-token-parser \
+ parser-test-xml-namespace \
+ parser-test-xml-validation \
+ parser-test-zip-archive \
+ sax-ns-parser-test \
+ sax-parser-test \
+ sax-token-parser-test \
+ types-test \
+ utf8-test \
+ yaml-parser-test \
+ xml-writer-test
+
+distclean-local:
+ rm -rf $(TESTS)
+
+@VALGRIND_CHECK_RULES@
diff --git a/src/parser/Makefile.in b/src/parser/Makefile.in
new file mode 100644
index 0000000..8ac6054
--- /dev/null
+++ b/src/parser/Makefile.in
@@ -0,0 +1,2328 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_FILESYSTEM_TRUE@am__append_1 = "-DHAVE_FILESYSTEM=1"
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@am__append_2 = "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_3 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_4 = $(BOOST_FILESYSTEM_LDFLAGS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_5 = $(BOOST_FILESYSTEM_LIBS)
+EXTRA_PROGRAMS = css-parser-test$(EXEEXT) csv-parser-test$(EXEEXT) \
+ json-parser-test$(EXEEXT) parser-global-test$(EXEEXT) \
+ parser-test-base$(EXEEXT) parser-test-base64$(EXEEXT) \
+ parser-test-json-validation$(EXEEXT) \
+ parser-test-numeric$(EXEEXT) parser-test-stream$(EXEEXT) \
+ parser-test-string-pool$(EXEEXT) \
+ parser-test-threaded-json-parser$(EXEEXT) \
+ parser-test-threaded-sax-token-parser$(EXEEXT) \
+ parser-test-xml-namespace$(EXEEXT) \
+ parser-test-xml-validation$(EXEEXT) \
+ parser-test-zip-archive$(EXEEXT) sax-ns-parser-test$(EXEEXT) \
+ sax-parser-test$(EXEEXT) sax-token-parser-test$(EXEEXT) \
+ types-test$(EXEEXT) utf8-test$(EXEEXT) \
+ yaml-parser-test$(EXEEXT) xml-writer-test$(EXEEXT)
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_6 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_7 = $(BOOST_FILESYSTEM_LDFLAGS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_8 = $(BOOST_FILESYSTEM_LIBS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_9 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_10 = $(BOOST_FILESYSTEM_LDFLAGS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_11 = $(BOOST_FILESYSTEM_LIBS)
+TESTS = css-parser-test$(EXEEXT) csv-parser-test$(EXEEXT) \
+ json-parser-test$(EXEEXT) parser-global-test$(EXEEXT) \
+ parser-test-base$(EXEEXT) parser-test-base64$(EXEEXT) \
+ parser-test-json-validation$(EXEEXT) \
+ parser-test-numeric$(EXEEXT) parser-test-stream$(EXEEXT) \
+ parser-test-string-pool$(EXEEXT) \
+ parser-test-threaded-json-parser$(EXEEXT) \
+ parser-test-threaded-sax-token-parser$(EXEEXT) \
+ parser-test-xml-namespace$(EXEEXT) \
+ parser-test-xml-validation$(EXEEXT) \
+ parser-test-zip-archive$(EXEEXT) sax-ns-parser-test$(EXEEXT) \
+ sax-parser-test$(EXEEXT) sax-token-parser-test$(EXEEXT) \
+ types-test$(EXEEXT) utf8-test$(EXEEXT) \
+ yaml-parser-test$(EXEEXT) xml-writer-test$(EXEEXT)
+subdir = src/parser
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+liborcus_parser_@ORCUS_API_VERSION@_la_DEPENDENCIES = \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+am_liborcus_parser_@ORCUS_API_VERSION@_la_OBJECTS = base64.lo \
+ cell_buffer.lo css_parser_base.lo css_types.lo \
+ csv_parser_base.lo exception.lo json_global.lo \
+ json_parser_base.lo json_parser_thread.lo parser_base.lo \
+ parser_global.lo sax_parser_base.lo sax_token_parser.lo \
+ sax_token_parser_thread.lo stream.lo string_pool.lo tokens.lo \
+ types.lo utf8.lo xml_namespace.lo xml_writer.lo \
+ yaml_parser_base.lo zip_archive.lo zip_archive_stream.lo
+liborcus_parser_@ORCUS_API_VERSION@_la_OBJECTS = \
+ $(am_liborcus_parser_@ORCUS_API_VERSION@_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+liborcus_parser_@ORCUS_API_VERSION@_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(liborcus_parser_@ORCUS_API_VERSION@_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+am_css_parser_test_OBJECTS = \
+ css_parser_test-css_parser_test.$(OBJEXT)
+css_parser_test_OBJECTS = $(am_css_parser_test_OBJECTS)
+css_parser_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la
+am_csv_parser_test_OBJECTS = \
+ csv_parser_test-csv_parser_test.$(OBJEXT)
+csv_parser_test_OBJECTS = $(am_csv_parser_test_OBJECTS)
+csv_parser_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la
+am_json_parser_test_OBJECTS = \
+ json_parser_test-json_parser_test.$(OBJEXT)
+json_parser_test_OBJECTS = $(am_json_parser_test_OBJECTS)
+json_parser_test_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_global_test_OBJECTS = \
+ parser_global_test-parser_global_test.$(OBJEXT)
+parser_global_test_OBJECTS = $(am_parser_global_test_OBJECTS)
+parser_global_test_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a
+am_parser_test_base_OBJECTS = \
+ parser_test_base-parser_base_test.$(OBJEXT)
+parser_test_base_OBJECTS = $(am_parser_test_base_OBJECTS)
+parser_test_base_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_test_base64_OBJECTS = parser_test_base64-base64.$(OBJEXT) \
+ parser_test_base64-base64_test.$(OBJEXT)
+parser_test_base64_OBJECTS = $(am_parser_test_base64_OBJECTS)
+parser_test_base64_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_test_json_validation_OBJECTS = parser_test_json_validation-parser_test_json_validation.$(OBJEXT)
+parser_test_json_validation_OBJECTS = \
+ $(am_parser_test_json_validation_OBJECTS)
+parser_test_json_validation_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_test_numeric_OBJECTS = \
+ parser_test_numeric-parser_test_numeric.$(OBJEXT)
+parser_test_numeric_OBJECTS = $(am_parser_test_numeric_OBJECTS)
+parser_test_numeric_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_test_stream_OBJECTS = \
+ parser_test_stream-stream_test.$(OBJEXT)
+parser_test_stream_OBJECTS = $(am_parser_test_stream_OBJECTS)
+parser_test_stream_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a
+am_parser_test_string_pool_OBJECTS = \
+ parser_test_string_pool-string_pool.$(OBJEXT) \
+ parser_test_string_pool-string_pool_test.$(OBJEXT)
+parser_test_string_pool_OBJECTS = \
+ $(am_parser_test_string_pool_OBJECTS)
+parser_test_string_pool_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la $(am__DEPENDENCIES_1)
+am_parser_test_threaded_json_parser_OBJECTS = parser_test_threaded_json_parser-threaded_json_parser_test.$(OBJEXT)
+parser_test_threaded_json_parser_OBJECTS = \
+ $(am_parser_test_threaded_json_parser_OBJECTS)
+parser_test_threaded_json_parser_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_threaded_json_parser_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(parser_test_threaded_json_parser_LDFLAGS) $(LDFLAGS) -o $@
+am_parser_test_threaded_sax_token_parser_OBJECTS = parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.$(OBJEXT)
+parser_test_threaded_sax_token_parser_OBJECTS = \
+ $(am_parser_test_threaded_sax_token_parser_OBJECTS)
+parser_test_threaded_sax_token_parser_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_test_xml_namespace_OBJECTS = \
+ parser_test_xml_namespace-xml_namespace.$(OBJEXT) \
+ parser_test_xml_namespace-xml_namespace_test.$(OBJEXT)
+parser_test_xml_namespace_OBJECTS = \
+ $(am_parser_test_xml_namespace_OBJECTS)
+parser_test_xml_namespace_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a \
+ $(am__DEPENDENCIES_1)
+am_parser_test_xml_validation_OBJECTS = parser_test_xml_validation-parser_test_xml_validation.$(OBJEXT)
+parser_test_xml_validation_OBJECTS = \
+ $(am_parser_test_xml_validation_OBJECTS)
+parser_test_xml_validation_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+parser_test_xml_validation_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(parser_test_xml_validation_LDFLAGS) $(LDFLAGS) -o $@
+am_parser_test_zip_archive_OBJECTS = \
+ parser_test_zip_archive-zip_archive_test.$(OBJEXT)
+parser_test_zip_archive_OBJECTS = \
+ $(am_parser_test_zip_archive_OBJECTS)
+parser_test_zip_archive_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+parser_test_zip_archive_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(parser_test_zip_archive_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am_sax_ns_parser_test_OBJECTS = \
+ sax_ns_parser_test-sax_ns_parser_test.$(OBJEXT)
+sax_ns_parser_test_OBJECTS = $(am_sax_ns_parser_test_OBJECTS)
+sax_ns_parser_test_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_sax_parser_test_OBJECTS = \
+ sax_parser_test-sax_parser_test.$(OBJEXT)
+sax_parser_test_OBJECTS = $(am_sax_parser_test_OBJECTS)
+sax_parser_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la
+am_sax_token_parser_test_OBJECTS = \
+ sax_token_parser_test-sax_token_parser_test.$(OBJEXT)
+sax_token_parser_test_OBJECTS = $(am_sax_token_parser_test_OBJECTS)
+sax_token_parser_test_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_types_test_OBJECTS = types_test-types_test.$(OBJEXT)
+types_test_OBJECTS = $(am_types_test_OBJECTS)
+types_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+am_utf8_test_OBJECTS = utf8_test-utf8.$(OBJEXT) \
+ utf8_test-utf8_test.$(OBJEXT)
+utf8_test_OBJECTS = $(am_utf8_test_OBJECTS)
+utf8_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la
+am_xml_writer_test_OBJECTS = \
+ xml_writer_test-xml_writer_test.$(OBJEXT)
+xml_writer_test_OBJECTS = $(am_xml_writer_test_OBJECTS)
+xml_writer_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la
+am_yaml_parser_test_OBJECTS = \
+ yaml_parser_test-yaml_parser_test.$(OBJEXT)
+yaml_parser_test_OBJECTS = $(am_yaml_parser_test_OBJECTS)
+yaml_parser_test_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/base64.Plo \
+ ./$(DEPDIR)/cell_buffer.Plo ./$(DEPDIR)/css_parser_base.Plo \
+ ./$(DEPDIR)/css_parser_test-css_parser_test.Po \
+ ./$(DEPDIR)/css_types.Plo ./$(DEPDIR)/csv_parser_base.Plo \
+ ./$(DEPDIR)/csv_parser_test-csv_parser_test.Po \
+ ./$(DEPDIR)/exception.Plo ./$(DEPDIR)/json_global.Plo \
+ ./$(DEPDIR)/json_parser_base.Plo \
+ ./$(DEPDIR)/json_parser_test-json_parser_test.Po \
+ ./$(DEPDIR)/json_parser_thread.Plo ./$(DEPDIR)/parser_base.Plo \
+ ./$(DEPDIR)/parser_global.Plo \
+ ./$(DEPDIR)/parser_global_test-parser_global_test.Po \
+ ./$(DEPDIR)/parser_test_base-parser_base_test.Po \
+ ./$(DEPDIR)/parser_test_base64-base64.Po \
+ ./$(DEPDIR)/parser_test_base64-base64_test.Po \
+ ./$(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po \
+ ./$(DEPDIR)/parser_test_numeric-parser_test_numeric.Po \
+ ./$(DEPDIR)/parser_test_stream-stream_test.Po \
+ ./$(DEPDIR)/parser_test_string_pool-string_pool.Po \
+ ./$(DEPDIR)/parser_test_string_pool-string_pool_test.Po \
+ ./$(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po \
+ ./$(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po \
+ ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po \
+ ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po \
+ ./$(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po \
+ ./$(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po \
+ ./$(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po \
+ ./$(DEPDIR)/sax_parser_base.Plo \
+ ./$(DEPDIR)/sax_parser_test-sax_parser_test.Po \
+ ./$(DEPDIR)/sax_token_parser.Plo \
+ ./$(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po \
+ ./$(DEPDIR)/sax_token_parser_thread.Plo ./$(DEPDIR)/stream.Plo \
+ ./$(DEPDIR)/string_pool.Plo ./$(DEPDIR)/tokens.Plo \
+ ./$(DEPDIR)/types.Plo ./$(DEPDIR)/types_test-types_test.Po \
+ ./$(DEPDIR)/utf8.Plo ./$(DEPDIR)/utf8_test-utf8.Po \
+ ./$(DEPDIR)/utf8_test-utf8_test.Po \
+ ./$(DEPDIR)/xml_namespace.Plo ./$(DEPDIR)/xml_writer.Plo \
+ ./$(DEPDIR)/xml_writer_test-xml_writer_test.Po \
+ ./$(DEPDIR)/yaml_parser_base.Plo \
+ ./$(DEPDIR)/yaml_parser_test-yaml_parser_test.Po \
+ ./$(DEPDIR)/zip_archive.Plo ./$(DEPDIR)/zip_archive_stream.Plo
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(liborcus_parser_@ORCUS_API_VERSION@_la_SOURCES) \
+ $(css_parser_test_SOURCES) $(csv_parser_test_SOURCES) \
+ $(json_parser_test_SOURCES) $(parser_global_test_SOURCES) \
+ $(parser_test_base_SOURCES) $(parser_test_base64_SOURCES) \
+ $(parser_test_json_validation_SOURCES) \
+ $(parser_test_numeric_SOURCES) $(parser_test_stream_SOURCES) \
+ $(parser_test_string_pool_SOURCES) \
+ $(parser_test_threaded_json_parser_SOURCES) \
+ $(parser_test_threaded_sax_token_parser_SOURCES) \
+ $(parser_test_xml_namespace_SOURCES) \
+ $(parser_test_xml_validation_SOURCES) \
+ $(parser_test_zip_archive_SOURCES) \
+ $(sax_ns_parser_test_SOURCES) $(sax_parser_test_SOURCES) \
+ $(sax_token_parser_test_SOURCES) $(types_test_SOURCES) \
+ $(utf8_test_SOURCES) $(xml_writer_test_SOURCES) \
+ $(yaml_parser_test_SOURCES)
+DIST_SOURCES = $(liborcus_parser_@ORCUS_API_VERSION@_la_SOURCES) \
+ $(css_parser_test_SOURCES) $(csv_parser_test_SOURCES) \
+ $(json_parser_test_SOURCES) $(parser_global_test_SOURCES) \
+ $(parser_test_base_SOURCES) $(parser_test_base64_SOURCES) \
+ $(parser_test_json_validation_SOURCES) \
+ $(parser_test_numeric_SOURCES) $(parser_test_stream_SOURCES) \
+ $(parser_test_string_pool_SOURCES) \
+ $(parser_test_threaded_json_parser_SOURCES) \
+ $(parser_test_threaded_sax_token_parser_SOURCES) \
+ $(parser_test_xml_namespace_SOURCES) \
+ $(parser_test_xml_validation_SOURCES) \
+ $(parser_test_zip_archive_SOURCES) \
+ $(sax_ns_parser_test_SOURCES) $(sax_parser_test_SOURCES) \
+ $(sax_token_parser_test_SOURCES) $(types_test_SOURCES) \
+ $(utf8_test_SOURCES) $(xml_writer_test_SOURCES) \
+ $(yaml_parser_test_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/include \
+ -DSRCDIR=\""$(top_srcdir)"\" $(BOOST_CPPFLAGS) \
+ -D__ORCUS_PSR_BUILDING_DLL $(am__append_1) $(am__append_2)
+lib_LTLIBRARIES = liborcus-parser-@ORCUS_API_VERSION@.la
+liborcus_parser_@ORCUS_API_VERSION@_la_SOURCES = \
+ win_stdint.h \
+ base64.cpp \
+ cell_buffer.cpp \
+ css_parser_base.cpp \
+ css_types.cpp \
+ csv_parser_base.cpp \
+ exception.cpp \
+ json_global.cpp \
+ json_parser_base.cpp \
+ json_parser_thread.cpp \
+ parser_base.cpp \
+ parser_global.cpp \
+ sax_parser_base.cpp \
+ sax_token_parser.cpp \
+ sax_token_parser_thread.cpp \
+ stream.cpp \
+ string_pool.cpp \
+ tokens.cpp \
+ types.cpp \
+ utf8.hpp \
+ utf8.cpp \
+ xml_namespace.cpp \
+ xml_writer.cpp \
+ yaml_parser_base.cpp \
+ zip_archive.cpp \
+ zip_archive_stream.cpp
+
+liborcus_parser_@ORCUS_API_VERSION@_la_LDFLAGS = -no-undefined \
+ $(BOOST_SYSTEM_LDFLAGS) $(am__append_3) $(am__append_4)
+liborcus_parser_@ORCUS_API_VERSION@_la_LIBADD = $(BOOST_SYSTEM_LIBS) \
+ $(ZLIB_LIBS) $(am__append_5)
+
+# parser-test-string-pool
+parser_test_string_pool_SOURCES = \
+ string_pool.cpp \
+ string_pool_test.cpp
+
+parser_test_string_pool_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+parser_test_string_pool_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-xml-namespace
+parser_test_xml_namespace_SOURCES = \
+ xml_namespace.cpp \
+ xml_namespace_test.cpp
+
+parser_test_xml_namespace_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+
+parser_test_xml_namespace_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-xml-validation
+parser_test_xml_validation_SOURCES = \
+ parser_test_xml_validation.cpp
+
+parser_test_xml_validation_CPPFLAGS = $(AM_CPPFLAGS)
+parser_test_xml_validation_LDFLAGS = $(BOOST_SYSTEM_LDFLAGS) \
+ $(am__append_6) $(am__append_7)
+parser_test_xml_validation_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS) $(am__append_8)
+
+# parser-test-base64
+parser_test_base64_SOURCES = \
+ base64.cpp \
+ base64_test.cpp
+
+parser_test_base64_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_base64_CPPFLAGS = $(AM_CPPFLAGS)
+
+# css-parser-test
+css_parser_test_SOURCES = \
+ css_parser_test.cpp
+
+css_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+css_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# csv-parser-test
+csv_parser_test_SOURCES = \
+ csv_parser_test.cpp
+
+csv_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+csv_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# json-parser-test
+json_parser_test_SOURCES = \
+ json_parser_test.cpp
+
+json_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+json_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# yaml-parser-test
+yaml_parser_test_SOURCES = \
+ yaml_parser_test.cpp
+
+yaml_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+yaml_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-parser-test
+sax_parser_test_SOURCES = \
+ sax_parser_test.cpp
+
+sax_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-ns-parser-test
+sax_ns_parser_test_SOURCES = \
+ sax_ns_parser_test.cpp
+
+sax_ns_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_ns_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-token-parser-test
+sax_token_parser_test_SOURCES = \
+ sax_token_parser_test.cpp
+
+sax_token_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_token_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-threaded-sax-token-parser
+parser_test_threaded_sax_token_parser_SOURCES = \
+ threaded_sax_token_parser_test.cpp
+
+parser_test_threaded_sax_token_parser_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_threaded_sax_token_parser_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-threaded-json-parser
+parser_test_threaded_json_parser_SOURCES = \
+ threaded_json_parser_test.cpp
+
+parser_test_threaded_json_parser_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_threaded_json_parser_LDFLAGS = -pthread
+parser_test_threaded_json_parser_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-stream
+parser_test_stream_SOURCES = \
+ stream_test.cpp
+
+parser_test_stream_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+
+parser_test_stream_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-zip-archive
+parser_test_zip_archive_SOURCES = \
+ zip_archive_test.cpp
+
+parser_test_zip_archive_CPPFLAGS = $(AM_CPPFLAGS)
+parser_test_zip_archive_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS) $(am__append_11)
+parser_test_zip_archive_LDFLAGS = $(BOOST_SYSTEM_LDFLAGS) \
+ $(am__append_9) $(am__append_10)
+
+# parser-test-base
+parser_test_base_SOURCES = \
+ parser_base_test.cpp
+
+parser_test_base_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_base_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-global-test
+parser_global_test_SOURCES = \
+ parser_global_test.cpp
+
+parser_global_test_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+
+parser_global_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-json-validation
+parser_test_json_validation_SOURCES = \
+ parser_test_json_validation.cpp
+
+parser_test_json_validation_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_json_validation_CPPFLAGS = $(AM_CPPFLAGS)
+
+# types-test
+types_test_SOURCES = types_test.cpp
+types_test_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+
+types_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# utf8-test
+utf8_test_SOURCES = \
+ utf8.cpp \
+ utf8_test.cpp
+
+utf8_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+utf8_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# xml-writer-test
+xml_writer_test_SOURCES = xml_writer_test.cpp
+xml_writer_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+xml_writer_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-numeric
+parser_test_numeric_SOURCES = \
+ parser_test_numeric.cpp
+
+parser_test_numeric = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_numeric_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_numeric_CPPFLAGS = $(AM_CPPFLAGS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/parser/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/parser/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+liborcus-parser-@ORCUS_API_VERSION@.la: $(liborcus_parser_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_parser_@ORCUS_API_VERSION@_la_DEPENDENCIES) $(EXTRA_liborcus_parser_@ORCUS_API_VERSION@_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(liborcus_parser_@ORCUS_API_VERSION@_la_LINK) -rpath $(libdir) $(liborcus_parser_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_parser_@ORCUS_API_VERSION@_la_LIBADD) $(LIBS)
+
+css-parser-test$(EXEEXT): $(css_parser_test_OBJECTS) $(css_parser_test_DEPENDENCIES) $(EXTRA_css_parser_test_DEPENDENCIES)
+ @rm -f css-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(css_parser_test_OBJECTS) $(css_parser_test_LDADD) $(LIBS)
+
+csv-parser-test$(EXEEXT): $(csv_parser_test_OBJECTS) $(csv_parser_test_DEPENDENCIES) $(EXTRA_csv_parser_test_DEPENDENCIES)
+ @rm -f csv-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(csv_parser_test_OBJECTS) $(csv_parser_test_LDADD) $(LIBS)
+
+json-parser-test$(EXEEXT): $(json_parser_test_OBJECTS) $(json_parser_test_DEPENDENCIES) $(EXTRA_json_parser_test_DEPENDENCIES)
+ @rm -f json-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(json_parser_test_OBJECTS) $(json_parser_test_LDADD) $(LIBS)
+
+parser-global-test$(EXEEXT): $(parser_global_test_OBJECTS) $(parser_global_test_DEPENDENCIES) $(EXTRA_parser_global_test_DEPENDENCIES)
+ @rm -f parser-global-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_global_test_OBJECTS) $(parser_global_test_LDADD) $(LIBS)
+
+parser-test-base$(EXEEXT): $(parser_test_base_OBJECTS) $(parser_test_base_DEPENDENCIES) $(EXTRA_parser_test_base_DEPENDENCIES)
+ @rm -f parser-test-base$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_base_OBJECTS) $(parser_test_base_LDADD) $(LIBS)
+
+parser-test-base64$(EXEEXT): $(parser_test_base64_OBJECTS) $(parser_test_base64_DEPENDENCIES) $(EXTRA_parser_test_base64_DEPENDENCIES)
+ @rm -f parser-test-base64$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_base64_OBJECTS) $(parser_test_base64_LDADD) $(LIBS)
+
+parser-test-json-validation$(EXEEXT): $(parser_test_json_validation_OBJECTS) $(parser_test_json_validation_DEPENDENCIES) $(EXTRA_parser_test_json_validation_DEPENDENCIES)
+ @rm -f parser-test-json-validation$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_json_validation_OBJECTS) $(parser_test_json_validation_LDADD) $(LIBS)
+
+parser-test-numeric$(EXEEXT): $(parser_test_numeric_OBJECTS) $(parser_test_numeric_DEPENDENCIES) $(EXTRA_parser_test_numeric_DEPENDENCIES)
+ @rm -f parser-test-numeric$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_numeric_OBJECTS) $(parser_test_numeric_LDADD) $(LIBS)
+
+parser-test-stream$(EXEEXT): $(parser_test_stream_OBJECTS) $(parser_test_stream_DEPENDENCIES) $(EXTRA_parser_test_stream_DEPENDENCIES)
+ @rm -f parser-test-stream$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_stream_OBJECTS) $(parser_test_stream_LDADD) $(LIBS)
+
+parser-test-string-pool$(EXEEXT): $(parser_test_string_pool_OBJECTS) $(parser_test_string_pool_DEPENDENCIES) $(EXTRA_parser_test_string_pool_DEPENDENCIES)
+ @rm -f parser-test-string-pool$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_string_pool_OBJECTS) $(parser_test_string_pool_LDADD) $(LIBS)
+
+parser-test-threaded-json-parser$(EXEEXT): $(parser_test_threaded_json_parser_OBJECTS) $(parser_test_threaded_json_parser_DEPENDENCIES) $(EXTRA_parser_test_threaded_json_parser_DEPENDENCIES)
+ @rm -f parser-test-threaded-json-parser$(EXEEXT)
+ $(AM_V_CXXLD)$(parser_test_threaded_json_parser_LINK) $(parser_test_threaded_json_parser_OBJECTS) $(parser_test_threaded_json_parser_LDADD) $(LIBS)
+
+parser-test-threaded-sax-token-parser$(EXEEXT): $(parser_test_threaded_sax_token_parser_OBJECTS) $(parser_test_threaded_sax_token_parser_DEPENDENCIES) $(EXTRA_parser_test_threaded_sax_token_parser_DEPENDENCIES)
+ @rm -f parser-test-threaded-sax-token-parser$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_threaded_sax_token_parser_OBJECTS) $(parser_test_threaded_sax_token_parser_LDADD) $(LIBS)
+
+parser-test-xml-namespace$(EXEEXT): $(parser_test_xml_namespace_OBJECTS) $(parser_test_xml_namespace_DEPENDENCIES) $(EXTRA_parser_test_xml_namespace_DEPENDENCIES)
+ @rm -f parser-test-xml-namespace$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_xml_namespace_OBJECTS) $(parser_test_xml_namespace_LDADD) $(LIBS)
+
+parser-test-xml-validation$(EXEEXT): $(parser_test_xml_validation_OBJECTS) $(parser_test_xml_validation_DEPENDENCIES) $(EXTRA_parser_test_xml_validation_DEPENDENCIES)
+ @rm -f parser-test-xml-validation$(EXEEXT)
+ $(AM_V_CXXLD)$(parser_test_xml_validation_LINK) $(parser_test_xml_validation_OBJECTS) $(parser_test_xml_validation_LDADD) $(LIBS)
+
+parser-test-zip-archive$(EXEEXT): $(parser_test_zip_archive_OBJECTS) $(parser_test_zip_archive_DEPENDENCIES) $(EXTRA_parser_test_zip_archive_DEPENDENCIES)
+ @rm -f parser-test-zip-archive$(EXEEXT)
+ $(AM_V_CXXLD)$(parser_test_zip_archive_LINK) $(parser_test_zip_archive_OBJECTS) $(parser_test_zip_archive_LDADD) $(LIBS)
+
+sax-ns-parser-test$(EXEEXT): $(sax_ns_parser_test_OBJECTS) $(sax_ns_parser_test_DEPENDENCIES) $(EXTRA_sax_ns_parser_test_DEPENDENCIES)
+ @rm -f sax-ns-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(sax_ns_parser_test_OBJECTS) $(sax_ns_parser_test_LDADD) $(LIBS)
+
+sax-parser-test$(EXEEXT): $(sax_parser_test_OBJECTS) $(sax_parser_test_DEPENDENCIES) $(EXTRA_sax_parser_test_DEPENDENCIES)
+ @rm -f sax-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(sax_parser_test_OBJECTS) $(sax_parser_test_LDADD) $(LIBS)
+
+sax-token-parser-test$(EXEEXT): $(sax_token_parser_test_OBJECTS) $(sax_token_parser_test_DEPENDENCIES) $(EXTRA_sax_token_parser_test_DEPENDENCIES)
+ @rm -f sax-token-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(sax_token_parser_test_OBJECTS) $(sax_token_parser_test_LDADD) $(LIBS)
+
+types-test$(EXEEXT): $(types_test_OBJECTS) $(types_test_DEPENDENCIES) $(EXTRA_types_test_DEPENDENCIES)
+ @rm -f types-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(types_test_OBJECTS) $(types_test_LDADD) $(LIBS)
+
+utf8-test$(EXEEXT): $(utf8_test_OBJECTS) $(utf8_test_DEPENDENCIES) $(EXTRA_utf8_test_DEPENDENCIES)
+ @rm -f utf8-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(utf8_test_OBJECTS) $(utf8_test_LDADD) $(LIBS)
+
+xml-writer-test$(EXEEXT): $(xml_writer_test_OBJECTS) $(xml_writer_test_DEPENDENCIES) $(EXTRA_xml_writer_test_DEPENDENCIES)
+ @rm -f xml-writer-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(xml_writer_test_OBJECTS) $(xml_writer_test_LDADD) $(LIBS)
+
+yaml-parser-test$(EXEEXT): $(yaml_parser_test_OBJECTS) $(yaml_parser_test_DEPENDENCIES) $(EXTRA_yaml_parser_test_DEPENDENCIES)
+ @rm -f yaml-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(yaml_parser_test_OBJECTS) $(yaml_parser_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cell_buffer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/css_parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/css_parser_test-css_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/css_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csv_parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csv_parser_test-csv_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_parser_test-json_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_parser_thread.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_global_test-parser_global_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_base-parser_base_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_base64-base64.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_base64-base64_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_numeric-parser_test_numeric.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_stream-stream_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_string_pool-string_pool.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_string_pool-string_pool_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_parser_test-sax_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_token_parser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_token_parser_thread.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string_pool.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tokens.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/types_test-types_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utf8.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utf8_test-utf8.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utf8_test-utf8_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_namespace.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_writer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_writer_test-xml_writer_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yaml_parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yaml_parser_test-yaml_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zip_archive.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zip_archive_stream.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+css_parser_test-css_parser_test.o: css_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(css_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT css_parser_test-css_parser_test.o -MD -MP -MF $(DEPDIR)/css_parser_test-css_parser_test.Tpo -c -o css_parser_test-css_parser_test.o `test -f 'css_parser_test.cpp' || echo '$(srcdir)/'`css_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/css_parser_test-css_parser_test.Tpo $(DEPDIR)/css_parser_test-css_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='css_parser_test.cpp' object='css_parser_test-css_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(css_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o css_parser_test-css_parser_test.o `test -f 'css_parser_test.cpp' || echo '$(srcdir)/'`css_parser_test.cpp
+
+css_parser_test-css_parser_test.obj: css_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(css_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT css_parser_test-css_parser_test.obj -MD -MP -MF $(DEPDIR)/css_parser_test-css_parser_test.Tpo -c -o css_parser_test-css_parser_test.obj `if test -f 'css_parser_test.cpp'; then $(CYGPATH_W) 'css_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/css_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/css_parser_test-css_parser_test.Tpo $(DEPDIR)/css_parser_test-css_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='css_parser_test.cpp' object='css_parser_test-css_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(css_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o css_parser_test-css_parser_test.obj `if test -f 'css_parser_test.cpp'; then $(CYGPATH_W) 'css_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/css_parser_test.cpp'; fi`
+
+csv_parser_test-csv_parser_test.o: csv_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(csv_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT csv_parser_test-csv_parser_test.o -MD -MP -MF $(DEPDIR)/csv_parser_test-csv_parser_test.Tpo -c -o csv_parser_test-csv_parser_test.o `test -f 'csv_parser_test.cpp' || echo '$(srcdir)/'`csv_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/csv_parser_test-csv_parser_test.Tpo $(DEPDIR)/csv_parser_test-csv_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csv_parser_test.cpp' object='csv_parser_test-csv_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(csv_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o csv_parser_test-csv_parser_test.o `test -f 'csv_parser_test.cpp' || echo '$(srcdir)/'`csv_parser_test.cpp
+
+csv_parser_test-csv_parser_test.obj: csv_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(csv_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT csv_parser_test-csv_parser_test.obj -MD -MP -MF $(DEPDIR)/csv_parser_test-csv_parser_test.Tpo -c -o csv_parser_test-csv_parser_test.obj `if test -f 'csv_parser_test.cpp'; then $(CYGPATH_W) 'csv_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/csv_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/csv_parser_test-csv_parser_test.Tpo $(DEPDIR)/csv_parser_test-csv_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csv_parser_test.cpp' object='csv_parser_test-csv_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(csv_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o csv_parser_test-csv_parser_test.obj `if test -f 'csv_parser_test.cpp'; then $(CYGPATH_W) 'csv_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/csv_parser_test.cpp'; fi`
+
+json_parser_test-json_parser_test.o: json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT json_parser_test-json_parser_test.o -MD -MP -MF $(DEPDIR)/json_parser_test-json_parser_test.Tpo -c -o json_parser_test-json_parser_test.o `test -f 'json_parser_test.cpp' || echo '$(srcdir)/'`json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/json_parser_test-json_parser_test.Tpo $(DEPDIR)/json_parser_test-json_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_parser_test.cpp' object='json_parser_test-json_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o json_parser_test-json_parser_test.o `test -f 'json_parser_test.cpp' || echo '$(srcdir)/'`json_parser_test.cpp
+
+json_parser_test-json_parser_test.obj: json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT json_parser_test-json_parser_test.obj -MD -MP -MF $(DEPDIR)/json_parser_test-json_parser_test.Tpo -c -o json_parser_test-json_parser_test.obj `if test -f 'json_parser_test.cpp'; then $(CYGPATH_W) 'json_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/json_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/json_parser_test-json_parser_test.Tpo $(DEPDIR)/json_parser_test-json_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_parser_test.cpp' object='json_parser_test-json_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o json_parser_test-json_parser_test.obj `if test -f 'json_parser_test.cpp'; then $(CYGPATH_W) 'json_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/json_parser_test.cpp'; fi`
+
+parser_global_test-parser_global_test.o: parser_global_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_global_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_global_test-parser_global_test.o -MD -MP -MF $(DEPDIR)/parser_global_test-parser_global_test.Tpo -c -o parser_global_test-parser_global_test.o `test -f 'parser_global_test.cpp' || echo '$(srcdir)/'`parser_global_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_global_test-parser_global_test.Tpo $(DEPDIR)/parser_global_test-parser_global_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_global_test.cpp' object='parser_global_test-parser_global_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_global_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_global_test-parser_global_test.o `test -f 'parser_global_test.cpp' || echo '$(srcdir)/'`parser_global_test.cpp
+
+parser_global_test-parser_global_test.obj: parser_global_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_global_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_global_test-parser_global_test.obj -MD -MP -MF $(DEPDIR)/parser_global_test-parser_global_test.Tpo -c -o parser_global_test-parser_global_test.obj `if test -f 'parser_global_test.cpp'; then $(CYGPATH_W) 'parser_global_test.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_global_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_global_test-parser_global_test.Tpo $(DEPDIR)/parser_global_test-parser_global_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_global_test.cpp' object='parser_global_test-parser_global_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_global_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_global_test-parser_global_test.obj `if test -f 'parser_global_test.cpp'; then $(CYGPATH_W) 'parser_global_test.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_global_test.cpp'; fi`
+
+parser_test_base-parser_base_test.o: parser_base_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base-parser_base_test.o -MD -MP -MF $(DEPDIR)/parser_test_base-parser_base_test.Tpo -c -o parser_test_base-parser_base_test.o `test -f 'parser_base_test.cpp' || echo '$(srcdir)/'`parser_base_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base-parser_base_test.Tpo $(DEPDIR)/parser_test_base-parser_base_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_base_test.cpp' object='parser_test_base-parser_base_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base-parser_base_test.o `test -f 'parser_base_test.cpp' || echo '$(srcdir)/'`parser_base_test.cpp
+
+parser_test_base-parser_base_test.obj: parser_base_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base-parser_base_test.obj -MD -MP -MF $(DEPDIR)/parser_test_base-parser_base_test.Tpo -c -o parser_test_base-parser_base_test.obj `if test -f 'parser_base_test.cpp'; then $(CYGPATH_W) 'parser_base_test.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_base_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base-parser_base_test.Tpo $(DEPDIR)/parser_test_base-parser_base_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_base_test.cpp' object='parser_test_base-parser_base_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base-parser_base_test.obj `if test -f 'parser_base_test.cpp'; then $(CYGPATH_W) 'parser_base_test.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_base_test.cpp'; fi`
+
+parser_test_base64-base64.o: base64.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base64-base64.o -MD -MP -MF $(DEPDIR)/parser_test_base64-base64.Tpo -c -o parser_test_base64-base64.o `test -f 'base64.cpp' || echo '$(srcdir)/'`base64.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base64-base64.Tpo $(DEPDIR)/parser_test_base64-base64.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base64.cpp' object='parser_test_base64-base64.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base64-base64.o `test -f 'base64.cpp' || echo '$(srcdir)/'`base64.cpp
+
+parser_test_base64-base64.obj: base64.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base64-base64.obj -MD -MP -MF $(DEPDIR)/parser_test_base64-base64.Tpo -c -o parser_test_base64-base64.obj `if test -f 'base64.cpp'; then $(CYGPATH_W) 'base64.cpp'; else $(CYGPATH_W) '$(srcdir)/base64.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base64-base64.Tpo $(DEPDIR)/parser_test_base64-base64.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base64.cpp' object='parser_test_base64-base64.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base64-base64.obj `if test -f 'base64.cpp'; then $(CYGPATH_W) 'base64.cpp'; else $(CYGPATH_W) '$(srcdir)/base64.cpp'; fi`
+
+parser_test_base64-base64_test.o: base64_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base64-base64_test.o -MD -MP -MF $(DEPDIR)/parser_test_base64-base64_test.Tpo -c -o parser_test_base64-base64_test.o `test -f 'base64_test.cpp' || echo '$(srcdir)/'`base64_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base64-base64_test.Tpo $(DEPDIR)/parser_test_base64-base64_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base64_test.cpp' object='parser_test_base64-base64_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base64-base64_test.o `test -f 'base64_test.cpp' || echo '$(srcdir)/'`base64_test.cpp
+
+parser_test_base64-base64_test.obj: base64_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base64-base64_test.obj -MD -MP -MF $(DEPDIR)/parser_test_base64-base64_test.Tpo -c -o parser_test_base64-base64_test.obj `if test -f 'base64_test.cpp'; then $(CYGPATH_W) 'base64_test.cpp'; else $(CYGPATH_W) '$(srcdir)/base64_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base64-base64_test.Tpo $(DEPDIR)/parser_test_base64-base64_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base64_test.cpp' object='parser_test_base64-base64_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base64-base64_test.obj `if test -f 'base64_test.cpp'; then $(CYGPATH_W) 'base64_test.cpp'; else $(CYGPATH_W) '$(srcdir)/base64_test.cpp'; fi`
+
+parser_test_json_validation-parser_test_json_validation.o: parser_test_json_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_json_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_json_validation-parser_test_json_validation.o -MD -MP -MF $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Tpo -c -o parser_test_json_validation-parser_test_json_validation.o `test -f 'parser_test_json_validation.cpp' || echo '$(srcdir)/'`parser_test_json_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Tpo $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_json_validation.cpp' object='parser_test_json_validation-parser_test_json_validation.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_json_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_json_validation-parser_test_json_validation.o `test -f 'parser_test_json_validation.cpp' || echo '$(srcdir)/'`parser_test_json_validation.cpp
+
+parser_test_json_validation-parser_test_json_validation.obj: parser_test_json_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_json_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_json_validation-parser_test_json_validation.obj -MD -MP -MF $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Tpo -c -o parser_test_json_validation-parser_test_json_validation.obj `if test -f 'parser_test_json_validation.cpp'; then $(CYGPATH_W) 'parser_test_json_validation.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_json_validation.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Tpo $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_json_validation.cpp' object='parser_test_json_validation-parser_test_json_validation.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_json_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_json_validation-parser_test_json_validation.obj `if test -f 'parser_test_json_validation.cpp'; then $(CYGPATH_W) 'parser_test_json_validation.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_json_validation.cpp'; fi`
+
+parser_test_numeric-parser_test_numeric.o: parser_test_numeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_numeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_numeric-parser_test_numeric.o -MD -MP -MF $(DEPDIR)/parser_test_numeric-parser_test_numeric.Tpo -c -o parser_test_numeric-parser_test_numeric.o `test -f 'parser_test_numeric.cpp' || echo '$(srcdir)/'`parser_test_numeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_numeric-parser_test_numeric.Tpo $(DEPDIR)/parser_test_numeric-parser_test_numeric.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_numeric.cpp' object='parser_test_numeric-parser_test_numeric.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_numeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_numeric-parser_test_numeric.o `test -f 'parser_test_numeric.cpp' || echo '$(srcdir)/'`parser_test_numeric.cpp
+
+parser_test_numeric-parser_test_numeric.obj: parser_test_numeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_numeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_numeric-parser_test_numeric.obj -MD -MP -MF $(DEPDIR)/parser_test_numeric-parser_test_numeric.Tpo -c -o parser_test_numeric-parser_test_numeric.obj `if test -f 'parser_test_numeric.cpp'; then $(CYGPATH_W) 'parser_test_numeric.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_numeric.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_numeric-parser_test_numeric.Tpo $(DEPDIR)/parser_test_numeric-parser_test_numeric.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_numeric.cpp' object='parser_test_numeric-parser_test_numeric.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_numeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_numeric-parser_test_numeric.obj `if test -f 'parser_test_numeric.cpp'; then $(CYGPATH_W) 'parser_test_numeric.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_numeric.cpp'; fi`
+
+parser_test_stream-stream_test.o: stream_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_stream_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_stream-stream_test.o -MD -MP -MF $(DEPDIR)/parser_test_stream-stream_test.Tpo -c -o parser_test_stream-stream_test.o `test -f 'stream_test.cpp' || echo '$(srcdir)/'`stream_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_stream-stream_test.Tpo $(DEPDIR)/parser_test_stream-stream_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stream_test.cpp' object='parser_test_stream-stream_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_stream_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_stream-stream_test.o `test -f 'stream_test.cpp' || echo '$(srcdir)/'`stream_test.cpp
+
+parser_test_stream-stream_test.obj: stream_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_stream_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_stream-stream_test.obj -MD -MP -MF $(DEPDIR)/parser_test_stream-stream_test.Tpo -c -o parser_test_stream-stream_test.obj `if test -f 'stream_test.cpp'; then $(CYGPATH_W) 'stream_test.cpp'; else $(CYGPATH_W) '$(srcdir)/stream_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_stream-stream_test.Tpo $(DEPDIR)/parser_test_stream-stream_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stream_test.cpp' object='parser_test_stream-stream_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_stream_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_stream-stream_test.obj `if test -f 'stream_test.cpp'; then $(CYGPATH_W) 'stream_test.cpp'; else $(CYGPATH_W) '$(srcdir)/stream_test.cpp'; fi`
+
+parser_test_string_pool-string_pool.o: string_pool.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_string_pool-string_pool.o -MD -MP -MF $(DEPDIR)/parser_test_string_pool-string_pool.Tpo -c -o parser_test_string_pool-string_pool.o `test -f 'string_pool.cpp' || echo '$(srcdir)/'`string_pool.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_string_pool-string_pool.Tpo $(DEPDIR)/parser_test_string_pool-string_pool.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_pool.cpp' object='parser_test_string_pool-string_pool.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_string_pool-string_pool.o `test -f 'string_pool.cpp' || echo '$(srcdir)/'`string_pool.cpp
+
+parser_test_string_pool-string_pool.obj: string_pool.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_string_pool-string_pool.obj -MD -MP -MF $(DEPDIR)/parser_test_string_pool-string_pool.Tpo -c -o parser_test_string_pool-string_pool.obj `if test -f 'string_pool.cpp'; then $(CYGPATH_W) 'string_pool.cpp'; else $(CYGPATH_W) '$(srcdir)/string_pool.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_string_pool-string_pool.Tpo $(DEPDIR)/parser_test_string_pool-string_pool.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_pool.cpp' object='parser_test_string_pool-string_pool.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_string_pool-string_pool.obj `if test -f 'string_pool.cpp'; then $(CYGPATH_W) 'string_pool.cpp'; else $(CYGPATH_W) '$(srcdir)/string_pool.cpp'; fi`
+
+parser_test_string_pool-string_pool_test.o: string_pool_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_string_pool-string_pool_test.o -MD -MP -MF $(DEPDIR)/parser_test_string_pool-string_pool_test.Tpo -c -o parser_test_string_pool-string_pool_test.o `test -f 'string_pool_test.cpp' || echo '$(srcdir)/'`string_pool_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_string_pool-string_pool_test.Tpo $(DEPDIR)/parser_test_string_pool-string_pool_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_pool_test.cpp' object='parser_test_string_pool-string_pool_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_string_pool-string_pool_test.o `test -f 'string_pool_test.cpp' || echo '$(srcdir)/'`string_pool_test.cpp
+
+parser_test_string_pool-string_pool_test.obj: string_pool_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_string_pool-string_pool_test.obj -MD -MP -MF $(DEPDIR)/parser_test_string_pool-string_pool_test.Tpo -c -o parser_test_string_pool-string_pool_test.obj `if test -f 'string_pool_test.cpp'; then $(CYGPATH_W) 'string_pool_test.cpp'; else $(CYGPATH_W) '$(srcdir)/string_pool_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_string_pool-string_pool_test.Tpo $(DEPDIR)/parser_test_string_pool-string_pool_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_pool_test.cpp' object='parser_test_string_pool-string_pool_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_string_pool-string_pool_test.obj `if test -f 'string_pool_test.cpp'; then $(CYGPATH_W) 'string_pool_test.cpp'; else $(CYGPATH_W) '$(srcdir)/string_pool_test.cpp'; fi`
+
+parser_test_threaded_json_parser-threaded_json_parser_test.o: threaded_json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_json_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_threaded_json_parser-threaded_json_parser_test.o -MD -MP -MF $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Tpo -c -o parser_test_threaded_json_parser-threaded_json_parser_test.o `test -f 'threaded_json_parser_test.cpp' || echo '$(srcdir)/'`threaded_json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Tpo $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='threaded_json_parser_test.cpp' object='parser_test_threaded_json_parser-threaded_json_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_json_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_threaded_json_parser-threaded_json_parser_test.o `test -f 'threaded_json_parser_test.cpp' || echo '$(srcdir)/'`threaded_json_parser_test.cpp
+
+parser_test_threaded_json_parser-threaded_json_parser_test.obj: threaded_json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_json_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_threaded_json_parser-threaded_json_parser_test.obj -MD -MP -MF $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Tpo -c -o parser_test_threaded_json_parser-threaded_json_parser_test.obj `if test -f 'threaded_json_parser_test.cpp'; then $(CYGPATH_W) 'threaded_json_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/threaded_json_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Tpo $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='threaded_json_parser_test.cpp' object='parser_test_threaded_json_parser-threaded_json_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_json_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_threaded_json_parser-threaded_json_parser_test.obj `if test -f 'threaded_json_parser_test.cpp'; then $(CYGPATH_W) 'threaded_json_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/threaded_json_parser_test.cpp'; fi`
+
+parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.o: threaded_sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_sax_token_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.o -MD -MP -MF $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Tpo -c -o parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.o `test -f 'threaded_sax_token_parser_test.cpp' || echo '$(srcdir)/'`threaded_sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Tpo $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='threaded_sax_token_parser_test.cpp' object='parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_sax_token_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.o `test -f 'threaded_sax_token_parser_test.cpp' || echo '$(srcdir)/'`threaded_sax_token_parser_test.cpp
+
+parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.obj: threaded_sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_sax_token_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.obj -MD -MP -MF $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Tpo -c -o parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.obj `if test -f 'threaded_sax_token_parser_test.cpp'; then $(CYGPATH_W) 'threaded_sax_token_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/threaded_sax_token_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Tpo $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='threaded_sax_token_parser_test.cpp' object='parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_sax_token_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.obj `if test -f 'threaded_sax_token_parser_test.cpp'; then $(CYGPATH_W) 'threaded_sax_token_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/threaded_sax_token_parser_test.cpp'; fi`
+
+parser_test_xml_namespace-xml_namespace.o: xml_namespace.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_namespace-xml_namespace.o -MD -MP -MF $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Tpo -c -o parser_test_xml_namespace-xml_namespace.o `test -f 'xml_namespace.cpp' || echo '$(srcdir)/'`xml_namespace.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Tpo $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_namespace.cpp' object='parser_test_xml_namespace-xml_namespace.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_namespace-xml_namespace.o `test -f 'xml_namespace.cpp' || echo '$(srcdir)/'`xml_namespace.cpp
+
+parser_test_xml_namespace-xml_namespace.obj: xml_namespace.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_namespace-xml_namespace.obj -MD -MP -MF $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Tpo -c -o parser_test_xml_namespace-xml_namespace.obj `if test -f 'xml_namespace.cpp'; then $(CYGPATH_W) 'xml_namespace.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_namespace.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Tpo $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_namespace.cpp' object='parser_test_xml_namespace-xml_namespace.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_namespace-xml_namespace.obj `if test -f 'xml_namespace.cpp'; then $(CYGPATH_W) 'xml_namespace.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_namespace.cpp'; fi`
+
+parser_test_xml_namespace-xml_namespace_test.o: xml_namespace_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_namespace-xml_namespace_test.o -MD -MP -MF $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Tpo -c -o parser_test_xml_namespace-xml_namespace_test.o `test -f 'xml_namespace_test.cpp' || echo '$(srcdir)/'`xml_namespace_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Tpo $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_namespace_test.cpp' object='parser_test_xml_namespace-xml_namespace_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_namespace-xml_namespace_test.o `test -f 'xml_namespace_test.cpp' || echo '$(srcdir)/'`xml_namespace_test.cpp
+
+parser_test_xml_namespace-xml_namespace_test.obj: xml_namespace_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_namespace-xml_namespace_test.obj -MD -MP -MF $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Tpo -c -o parser_test_xml_namespace-xml_namespace_test.obj `if test -f 'xml_namespace_test.cpp'; then $(CYGPATH_W) 'xml_namespace_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_namespace_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Tpo $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_namespace_test.cpp' object='parser_test_xml_namespace-xml_namespace_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_namespace-xml_namespace_test.obj `if test -f 'xml_namespace_test.cpp'; then $(CYGPATH_W) 'xml_namespace_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_namespace_test.cpp'; fi`
+
+parser_test_xml_validation-parser_test_xml_validation.o: parser_test_xml_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_validation-parser_test_xml_validation.o -MD -MP -MF $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Tpo -c -o parser_test_xml_validation-parser_test_xml_validation.o `test -f 'parser_test_xml_validation.cpp' || echo '$(srcdir)/'`parser_test_xml_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Tpo $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_xml_validation.cpp' object='parser_test_xml_validation-parser_test_xml_validation.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_validation-parser_test_xml_validation.o `test -f 'parser_test_xml_validation.cpp' || echo '$(srcdir)/'`parser_test_xml_validation.cpp
+
+parser_test_xml_validation-parser_test_xml_validation.obj: parser_test_xml_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_validation-parser_test_xml_validation.obj -MD -MP -MF $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Tpo -c -o parser_test_xml_validation-parser_test_xml_validation.obj `if test -f 'parser_test_xml_validation.cpp'; then $(CYGPATH_W) 'parser_test_xml_validation.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_xml_validation.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Tpo $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_xml_validation.cpp' object='parser_test_xml_validation-parser_test_xml_validation.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_validation-parser_test_xml_validation.obj `if test -f 'parser_test_xml_validation.cpp'; then $(CYGPATH_W) 'parser_test_xml_validation.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_xml_validation.cpp'; fi`
+
+parser_test_zip_archive-zip_archive_test.o: zip_archive_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_zip_archive_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_zip_archive-zip_archive_test.o -MD -MP -MF $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Tpo -c -o parser_test_zip_archive-zip_archive_test.o `test -f 'zip_archive_test.cpp' || echo '$(srcdir)/'`zip_archive_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Tpo $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='zip_archive_test.cpp' object='parser_test_zip_archive-zip_archive_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_zip_archive_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_zip_archive-zip_archive_test.o `test -f 'zip_archive_test.cpp' || echo '$(srcdir)/'`zip_archive_test.cpp
+
+parser_test_zip_archive-zip_archive_test.obj: zip_archive_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_zip_archive_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_zip_archive-zip_archive_test.obj -MD -MP -MF $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Tpo -c -o parser_test_zip_archive-zip_archive_test.obj `if test -f 'zip_archive_test.cpp'; then $(CYGPATH_W) 'zip_archive_test.cpp'; else $(CYGPATH_W) '$(srcdir)/zip_archive_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Tpo $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='zip_archive_test.cpp' object='parser_test_zip_archive-zip_archive_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_zip_archive_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_zip_archive-zip_archive_test.obj `if test -f 'zip_archive_test.cpp'; then $(CYGPATH_W) 'zip_archive_test.cpp'; else $(CYGPATH_W) '$(srcdir)/zip_archive_test.cpp'; fi`
+
+sax_ns_parser_test-sax_ns_parser_test.o: sax_ns_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_ns_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_ns_parser_test-sax_ns_parser_test.o -MD -MP -MF $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Tpo -c -o sax_ns_parser_test-sax_ns_parser_test.o `test -f 'sax_ns_parser_test.cpp' || echo '$(srcdir)/'`sax_ns_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Tpo $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_ns_parser_test.cpp' object='sax_ns_parser_test-sax_ns_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_ns_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_ns_parser_test-sax_ns_parser_test.o `test -f 'sax_ns_parser_test.cpp' || echo '$(srcdir)/'`sax_ns_parser_test.cpp
+
+sax_ns_parser_test-sax_ns_parser_test.obj: sax_ns_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_ns_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_ns_parser_test-sax_ns_parser_test.obj -MD -MP -MF $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Tpo -c -o sax_ns_parser_test-sax_ns_parser_test.obj `if test -f 'sax_ns_parser_test.cpp'; then $(CYGPATH_W) 'sax_ns_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_ns_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Tpo $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_ns_parser_test.cpp' object='sax_ns_parser_test-sax_ns_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_ns_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_ns_parser_test-sax_ns_parser_test.obj `if test -f 'sax_ns_parser_test.cpp'; then $(CYGPATH_W) 'sax_ns_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_ns_parser_test.cpp'; fi`
+
+sax_parser_test-sax_parser_test.o: sax_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_parser_test-sax_parser_test.o -MD -MP -MF $(DEPDIR)/sax_parser_test-sax_parser_test.Tpo -c -o sax_parser_test-sax_parser_test.o `test -f 'sax_parser_test.cpp' || echo '$(srcdir)/'`sax_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_parser_test-sax_parser_test.Tpo $(DEPDIR)/sax_parser_test-sax_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_parser_test.cpp' object='sax_parser_test-sax_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_parser_test-sax_parser_test.o `test -f 'sax_parser_test.cpp' || echo '$(srcdir)/'`sax_parser_test.cpp
+
+sax_parser_test-sax_parser_test.obj: sax_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_parser_test-sax_parser_test.obj -MD -MP -MF $(DEPDIR)/sax_parser_test-sax_parser_test.Tpo -c -o sax_parser_test-sax_parser_test.obj `if test -f 'sax_parser_test.cpp'; then $(CYGPATH_W) 'sax_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_parser_test-sax_parser_test.Tpo $(DEPDIR)/sax_parser_test-sax_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_parser_test.cpp' object='sax_parser_test-sax_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_parser_test-sax_parser_test.obj `if test -f 'sax_parser_test.cpp'; then $(CYGPATH_W) 'sax_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_parser_test.cpp'; fi`
+
+sax_token_parser_test-sax_token_parser_test.o: sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_token_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_token_parser_test-sax_token_parser_test.o -MD -MP -MF $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Tpo -c -o sax_token_parser_test-sax_token_parser_test.o `test -f 'sax_token_parser_test.cpp' || echo '$(srcdir)/'`sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Tpo $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_token_parser_test.cpp' object='sax_token_parser_test-sax_token_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_token_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_token_parser_test-sax_token_parser_test.o `test -f 'sax_token_parser_test.cpp' || echo '$(srcdir)/'`sax_token_parser_test.cpp
+
+sax_token_parser_test-sax_token_parser_test.obj: sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_token_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_token_parser_test-sax_token_parser_test.obj -MD -MP -MF $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Tpo -c -o sax_token_parser_test-sax_token_parser_test.obj `if test -f 'sax_token_parser_test.cpp'; then $(CYGPATH_W) 'sax_token_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_token_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Tpo $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_token_parser_test.cpp' object='sax_token_parser_test-sax_token_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_token_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_token_parser_test-sax_token_parser_test.obj `if test -f 'sax_token_parser_test.cpp'; then $(CYGPATH_W) 'sax_token_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_token_parser_test.cpp'; fi`
+
+types_test-types_test.o: types_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(types_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT types_test-types_test.o -MD -MP -MF $(DEPDIR)/types_test-types_test.Tpo -c -o types_test-types_test.o `test -f 'types_test.cpp' || echo '$(srcdir)/'`types_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/types_test-types_test.Tpo $(DEPDIR)/types_test-types_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='types_test.cpp' object='types_test-types_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(types_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o types_test-types_test.o `test -f 'types_test.cpp' || echo '$(srcdir)/'`types_test.cpp
+
+types_test-types_test.obj: types_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(types_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT types_test-types_test.obj -MD -MP -MF $(DEPDIR)/types_test-types_test.Tpo -c -o types_test-types_test.obj `if test -f 'types_test.cpp'; then $(CYGPATH_W) 'types_test.cpp'; else $(CYGPATH_W) '$(srcdir)/types_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/types_test-types_test.Tpo $(DEPDIR)/types_test-types_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='types_test.cpp' object='types_test-types_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(types_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o types_test-types_test.obj `if test -f 'types_test.cpp'; then $(CYGPATH_W) 'types_test.cpp'; else $(CYGPATH_W) '$(srcdir)/types_test.cpp'; fi`
+
+utf8_test-utf8.o: utf8.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT utf8_test-utf8.o -MD -MP -MF $(DEPDIR)/utf8_test-utf8.Tpo -c -o utf8_test-utf8.o `test -f 'utf8.cpp' || echo '$(srcdir)/'`utf8.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/utf8_test-utf8.Tpo $(DEPDIR)/utf8_test-utf8.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='utf8.cpp' object='utf8_test-utf8.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o utf8_test-utf8.o `test -f 'utf8.cpp' || echo '$(srcdir)/'`utf8.cpp
+
+utf8_test-utf8.obj: utf8.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT utf8_test-utf8.obj -MD -MP -MF $(DEPDIR)/utf8_test-utf8.Tpo -c -o utf8_test-utf8.obj `if test -f 'utf8.cpp'; then $(CYGPATH_W) 'utf8.cpp'; else $(CYGPATH_W) '$(srcdir)/utf8.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/utf8_test-utf8.Tpo $(DEPDIR)/utf8_test-utf8.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='utf8.cpp' object='utf8_test-utf8.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o utf8_test-utf8.obj `if test -f 'utf8.cpp'; then $(CYGPATH_W) 'utf8.cpp'; else $(CYGPATH_W) '$(srcdir)/utf8.cpp'; fi`
+
+utf8_test-utf8_test.o: utf8_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT utf8_test-utf8_test.o -MD -MP -MF $(DEPDIR)/utf8_test-utf8_test.Tpo -c -o utf8_test-utf8_test.o `test -f 'utf8_test.cpp' || echo '$(srcdir)/'`utf8_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/utf8_test-utf8_test.Tpo $(DEPDIR)/utf8_test-utf8_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='utf8_test.cpp' object='utf8_test-utf8_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o utf8_test-utf8_test.o `test -f 'utf8_test.cpp' || echo '$(srcdir)/'`utf8_test.cpp
+
+utf8_test-utf8_test.obj: utf8_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT utf8_test-utf8_test.obj -MD -MP -MF $(DEPDIR)/utf8_test-utf8_test.Tpo -c -o utf8_test-utf8_test.obj `if test -f 'utf8_test.cpp'; then $(CYGPATH_W) 'utf8_test.cpp'; else $(CYGPATH_W) '$(srcdir)/utf8_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/utf8_test-utf8_test.Tpo $(DEPDIR)/utf8_test-utf8_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='utf8_test.cpp' object='utf8_test-utf8_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o utf8_test-utf8_test.obj `if test -f 'utf8_test.cpp'; then $(CYGPATH_W) 'utf8_test.cpp'; else $(CYGPATH_W) '$(srcdir)/utf8_test.cpp'; fi`
+
+xml_writer_test-xml_writer_test.o: xml_writer_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_writer_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_writer_test-xml_writer_test.o -MD -MP -MF $(DEPDIR)/xml_writer_test-xml_writer_test.Tpo -c -o xml_writer_test-xml_writer_test.o `test -f 'xml_writer_test.cpp' || echo '$(srcdir)/'`xml_writer_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_writer_test-xml_writer_test.Tpo $(DEPDIR)/xml_writer_test-xml_writer_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_writer_test.cpp' object='xml_writer_test-xml_writer_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_writer_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_writer_test-xml_writer_test.o `test -f 'xml_writer_test.cpp' || echo '$(srcdir)/'`xml_writer_test.cpp
+
+xml_writer_test-xml_writer_test.obj: xml_writer_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_writer_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_writer_test-xml_writer_test.obj -MD -MP -MF $(DEPDIR)/xml_writer_test-xml_writer_test.Tpo -c -o xml_writer_test-xml_writer_test.obj `if test -f 'xml_writer_test.cpp'; then $(CYGPATH_W) 'xml_writer_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_writer_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_writer_test-xml_writer_test.Tpo $(DEPDIR)/xml_writer_test-xml_writer_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_writer_test.cpp' object='xml_writer_test-xml_writer_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_writer_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_writer_test-xml_writer_test.obj `if test -f 'xml_writer_test.cpp'; then $(CYGPATH_W) 'xml_writer_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_writer_test.cpp'; fi`
+
+yaml_parser_test-yaml_parser_test.o: yaml_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT yaml_parser_test-yaml_parser_test.o -MD -MP -MF $(DEPDIR)/yaml_parser_test-yaml_parser_test.Tpo -c -o yaml_parser_test-yaml_parser_test.o `test -f 'yaml_parser_test.cpp' || echo '$(srcdir)/'`yaml_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/yaml_parser_test-yaml_parser_test.Tpo $(DEPDIR)/yaml_parser_test-yaml_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='yaml_parser_test.cpp' object='yaml_parser_test-yaml_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o yaml_parser_test-yaml_parser_test.o `test -f 'yaml_parser_test.cpp' || echo '$(srcdir)/'`yaml_parser_test.cpp
+
+yaml_parser_test-yaml_parser_test.obj: yaml_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT yaml_parser_test-yaml_parser_test.obj -MD -MP -MF $(DEPDIR)/yaml_parser_test-yaml_parser_test.Tpo -c -o yaml_parser_test-yaml_parser_test.obj `if test -f 'yaml_parser_test.cpp'; then $(CYGPATH_W) 'yaml_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/yaml_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/yaml_parser_test-yaml_parser_test.Tpo $(DEPDIR)/yaml_parser_test-yaml_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='yaml_parser_test.cpp' object='yaml_parser_test-yaml_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o yaml_parser_test-yaml_parser_test.obj `if test -f 'yaml_parser_test.cpp'; then $(CYGPATH_W) 'yaml_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/yaml_parser_test.cpp'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+css-parser-test.log: css-parser-test$(EXEEXT)
+ @p='css-parser-test$(EXEEXT)'; \
+ b='css-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+csv-parser-test.log: csv-parser-test$(EXEEXT)
+ @p='csv-parser-test$(EXEEXT)'; \
+ b='csv-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+json-parser-test.log: json-parser-test$(EXEEXT)
+ @p='json-parser-test$(EXEEXT)'; \
+ b='json-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-global-test.log: parser-global-test$(EXEEXT)
+ @p='parser-global-test$(EXEEXT)'; \
+ b='parser-global-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-base.log: parser-test-base$(EXEEXT)
+ @p='parser-test-base$(EXEEXT)'; \
+ b='parser-test-base'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-base64.log: parser-test-base64$(EXEEXT)
+ @p='parser-test-base64$(EXEEXT)'; \
+ b='parser-test-base64'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-json-validation.log: parser-test-json-validation$(EXEEXT)
+ @p='parser-test-json-validation$(EXEEXT)'; \
+ b='parser-test-json-validation'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-numeric.log: parser-test-numeric$(EXEEXT)
+ @p='parser-test-numeric$(EXEEXT)'; \
+ b='parser-test-numeric'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-stream.log: parser-test-stream$(EXEEXT)
+ @p='parser-test-stream$(EXEEXT)'; \
+ b='parser-test-stream'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-string-pool.log: parser-test-string-pool$(EXEEXT)
+ @p='parser-test-string-pool$(EXEEXT)'; \
+ b='parser-test-string-pool'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-threaded-json-parser.log: parser-test-threaded-json-parser$(EXEEXT)
+ @p='parser-test-threaded-json-parser$(EXEEXT)'; \
+ b='parser-test-threaded-json-parser'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-threaded-sax-token-parser.log: parser-test-threaded-sax-token-parser$(EXEEXT)
+ @p='parser-test-threaded-sax-token-parser$(EXEEXT)'; \
+ b='parser-test-threaded-sax-token-parser'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-xml-namespace.log: parser-test-xml-namespace$(EXEEXT)
+ @p='parser-test-xml-namespace$(EXEEXT)'; \
+ b='parser-test-xml-namespace'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-xml-validation.log: parser-test-xml-validation$(EXEEXT)
+ @p='parser-test-xml-validation$(EXEEXT)'; \
+ b='parser-test-xml-validation'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-zip-archive.log: parser-test-zip-archive$(EXEEXT)
+ @p='parser-test-zip-archive$(EXEEXT)'; \
+ b='parser-test-zip-archive'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+sax-ns-parser-test.log: sax-ns-parser-test$(EXEEXT)
+ @p='sax-ns-parser-test$(EXEEXT)'; \
+ b='sax-ns-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+sax-parser-test.log: sax-parser-test$(EXEEXT)
+ @p='sax-parser-test$(EXEEXT)'; \
+ b='sax-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+sax-token-parser-test.log: sax-token-parser-test$(EXEEXT)
+ @p='sax-token-parser-test$(EXEEXT)'; \
+ b='sax-token-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+types-test.log: types-test$(EXEEXT)
+ @p='types-test$(EXEEXT)'; \
+ b='types-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+utf8-test.log: utf8-test$(EXEEXT)
+ @p='utf8-test$(EXEEXT)'; \
+ b='utf8-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+yaml-parser-test.log: yaml-parser-test$(EXEEXT)
+ @p='yaml-parser-test$(EXEEXT)'; \
+ b='yaml-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+xml-writer-test.log: xml-writer-test$(EXEEXT)
+ @p='xml-writer-test$(EXEEXT)'; \
+ b='xml-writer-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+install-EXTRAPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-am
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-am
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-am
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-am
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-am
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/base64.Plo
+ -rm -f ./$(DEPDIR)/cell_buffer.Plo
+ -rm -f ./$(DEPDIR)/css_parser_base.Plo
+ -rm -f ./$(DEPDIR)/css_parser_test-css_parser_test.Po
+ -rm -f ./$(DEPDIR)/css_types.Plo
+ -rm -f ./$(DEPDIR)/csv_parser_base.Plo
+ -rm -f ./$(DEPDIR)/csv_parser_test-csv_parser_test.Po
+ -rm -f ./$(DEPDIR)/exception.Plo
+ -rm -f ./$(DEPDIR)/json_global.Plo
+ -rm -f ./$(DEPDIR)/json_parser_base.Plo
+ -rm -f ./$(DEPDIR)/json_parser_test-json_parser_test.Po
+ -rm -f ./$(DEPDIR)/json_parser_thread.Plo
+ -rm -f ./$(DEPDIR)/parser_base.Plo
+ -rm -f ./$(DEPDIR)/parser_global.Plo
+ -rm -f ./$(DEPDIR)/parser_global_test-parser_global_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_base-parser_base_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_base64-base64.Po
+ -rm -f ./$(DEPDIR)/parser_test_base64-base64_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po
+ -rm -f ./$(DEPDIR)/parser_test_numeric-parser_test_numeric.Po
+ -rm -f ./$(DEPDIR)/parser_test_stream-stream_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_string_pool-string_pool.Po
+ -rm -f ./$(DEPDIR)/parser_test_string_pool-string_pool_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po
+ -rm -f ./$(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po
+ -rm -f ./$(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_parser_base.Plo
+ -rm -f ./$(DEPDIR)/sax_parser_test-sax_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_token_parser.Plo
+ -rm -f ./$(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_token_parser_thread.Plo
+ -rm -f ./$(DEPDIR)/stream.Plo
+ -rm -f ./$(DEPDIR)/string_pool.Plo
+ -rm -f ./$(DEPDIR)/tokens.Plo
+ -rm -f ./$(DEPDIR)/types.Plo
+ -rm -f ./$(DEPDIR)/types_test-types_test.Po
+ -rm -f ./$(DEPDIR)/utf8.Plo
+ -rm -f ./$(DEPDIR)/utf8_test-utf8.Po
+ -rm -f ./$(DEPDIR)/utf8_test-utf8_test.Po
+ -rm -f ./$(DEPDIR)/xml_namespace.Plo
+ -rm -f ./$(DEPDIR)/xml_writer.Plo
+ -rm -f ./$(DEPDIR)/xml_writer_test-xml_writer_test.Po
+ -rm -f ./$(DEPDIR)/yaml_parser_base.Plo
+ -rm -f ./$(DEPDIR)/yaml_parser_test-yaml_parser_test.Po
+ -rm -f ./$(DEPDIR)/zip_archive.Plo
+ -rm -f ./$(DEPDIR)/zip_archive_stream.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-local distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/base64.Plo
+ -rm -f ./$(DEPDIR)/cell_buffer.Plo
+ -rm -f ./$(DEPDIR)/css_parser_base.Plo
+ -rm -f ./$(DEPDIR)/css_parser_test-css_parser_test.Po
+ -rm -f ./$(DEPDIR)/css_types.Plo
+ -rm -f ./$(DEPDIR)/csv_parser_base.Plo
+ -rm -f ./$(DEPDIR)/csv_parser_test-csv_parser_test.Po
+ -rm -f ./$(DEPDIR)/exception.Plo
+ -rm -f ./$(DEPDIR)/json_global.Plo
+ -rm -f ./$(DEPDIR)/json_parser_base.Plo
+ -rm -f ./$(DEPDIR)/json_parser_test-json_parser_test.Po
+ -rm -f ./$(DEPDIR)/json_parser_thread.Plo
+ -rm -f ./$(DEPDIR)/parser_base.Plo
+ -rm -f ./$(DEPDIR)/parser_global.Plo
+ -rm -f ./$(DEPDIR)/parser_global_test-parser_global_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_base-parser_base_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_base64-base64.Po
+ -rm -f ./$(DEPDIR)/parser_test_base64-base64_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po
+ -rm -f ./$(DEPDIR)/parser_test_numeric-parser_test_numeric.Po
+ -rm -f ./$(DEPDIR)/parser_test_stream-stream_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_string_pool-string_pool.Po
+ -rm -f ./$(DEPDIR)/parser_test_string_pool-string_pool_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po
+ -rm -f ./$(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po
+ -rm -f ./$(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_parser_base.Plo
+ -rm -f ./$(DEPDIR)/sax_parser_test-sax_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_token_parser.Plo
+ -rm -f ./$(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_token_parser_thread.Plo
+ -rm -f ./$(DEPDIR)/stream.Plo
+ -rm -f ./$(DEPDIR)/string_pool.Plo
+ -rm -f ./$(DEPDIR)/tokens.Plo
+ -rm -f ./$(DEPDIR)/types.Plo
+ -rm -f ./$(DEPDIR)/types_test-types_test.Po
+ -rm -f ./$(DEPDIR)/utf8.Plo
+ -rm -f ./$(DEPDIR)/utf8_test-utf8.Po
+ -rm -f ./$(DEPDIR)/utf8_test-utf8_test.Po
+ -rm -f ./$(DEPDIR)/xml_namespace.Plo
+ -rm -f ./$(DEPDIR)/xml_writer.Plo
+ -rm -f ./$(DEPDIR)/xml_writer_test-xml_writer_test.Po
+ -rm -f ./$(DEPDIR)/yaml_parser_base.Plo
+ -rm -f ./$(DEPDIR)/yaml_parser_test-yaml_parser_test.Po
+ -rm -f ./$(DEPDIR)/zip_archive.Plo
+ -rm -f ./$(DEPDIR)/zip_archive_stream.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am check-valgrind-am check-valgrind-drd-am \
+ check-valgrind-drd-local check-valgrind-helgrind-am \
+ check-valgrind-helgrind-local check-valgrind-local \
+ check-valgrind-memcheck-am check-valgrind-memcheck-local \
+ check-valgrind-sgcheck-am check-valgrind-sgcheck-local clean \
+ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-local distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-libLTLIBRARIES \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \
+ uninstall uninstall-am uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+distclean-local:
+ rm -rf $(TESTS)
+
+@VALGRIND_CHECK_RULES@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/parser/base64.cpp b/src/parser/base64.cpp
new file mode 100644
index 0000000..31b8267
--- /dev/null
+++ b/src/parser/base64.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/base64.hpp>
+
+#include <boost/archive/iterators/base64_from_binary.hpp>
+#include <boost/archive/iterators/binary_from_base64.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+
+using namespace boost::archive::iterators;
+
+namespace orcus {
+
+typedef transform_width<binary_from_base64<std::vector<char>::const_iterator>, 8, 6> to_binary;
+typedef base64_from_binary<transform_width<std::vector<uint8_t>::const_iterator, 6, 8> > to_base64;
+
+std::vector<uint8_t> decode_from_base64(std::string_view base64)
+{
+ if (base64.size() < 4)
+ // Minimum of 4 characters required.
+ return std::vector<uint8_t>{};
+
+ std::vector<char> base64_seq{base64.data(), base64.data() + base64.size()};
+
+ // Check the number of trailing '='s (up to 2).
+ std::size_t pad_size = 0;
+ auto it = base64_seq.rbegin();
+ for (; pad_size < 2; ++pad_size, ++it)
+ {
+ if (*it != '=')
+ break;
+
+ *it = 'A'; // replace it with 'A' which is a base64 encoding of '\0'.
+ }
+
+ std::vector<uint8_t> decoded{to_binary(base64_seq.begin()), to_binary(base64_seq.end())};
+ decoded.erase(decoded.end() - pad_size, decoded.end());
+
+ return decoded;
+}
+
+std::string encode_to_base64(const std::vector<uint8_t>& input)
+{
+ if (input.empty())
+ return std::string{};
+
+ std::vector<uint8_t> inp = input;
+ size_t pad_size = (3 - inp.size() % 3) % 3;
+ inp.resize(inp.size() + pad_size);
+
+ std::string encoded{to_base64(inp.begin()), to_base64(inp.end())};
+
+ auto it = encoded.rbegin();
+ for (size_t i = 0; i < pad_size; ++i, ++it)
+ {
+ // 'A' is a base64 encoding of '\0'
+ // replace them with padding charachters '='
+ if (*it == 'A')
+ *it = '=';
+ }
+
+ return encoded;
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/base64_test.cpp b/src/parser/base64_test.cpp
new file mode 100644
index 0000000..9608aef
--- /dev/null
+++ b/src/parser/base64_test.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/base64.hpp"
+
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include <string>
+#include <iterator>
+
+using namespace orcus;
+using namespace std;
+
+void test_base64_text_input(const char* p)
+{
+ cout << "input: '" << p << "'" << endl;
+ size_t n = strlen(p);
+ std::vector<uint8_t> input(p, p+n);
+ std::string encoded = encode_to_base64(input);
+ cout << "encoded: '" << encoded << "'" << endl;
+
+ std::vector<uint8_t> decoded = decode_from_base64(encoded);
+ cout << "decoded: '";
+ std::copy(decoded.begin(), decoded.end(), std::ostream_iterator<char>(cout, ""));
+ cout << "'" << endl;
+
+ assert(input == decoded);
+}
+
+int main()
+{
+ test_base64_text_input("Hello there");
+ test_base64_text_input("World domination!!!");
+ test_base64_text_input("World domination!!");
+ test_base64_text_input("World domination!");
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/cell_buffer.cpp b/src/parser/cell_buffer.cpp
new file mode 100644
index 0000000..6815d71
--- /dev/null
+++ b/src/parser/cell_buffer.cpp
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/cell_buffer.hpp"
+
+#include <cstring>
+
+#define ORCUS_DEBUG_CELL_BUFFER 0
+
+#if ORCUS_DEBUG_CELL_BUFFER
+#include <iostream>
+using std::cout;
+using std::endl;
+#endif
+
+namespace orcus {
+
+cell_buffer::cell_buffer() : m_buf_size(0) {}
+
+cell_buffer::~cell_buffer() = default;
+
+void cell_buffer::append(const char* p, size_t len)
+{
+ if (!len)
+ return;
+
+#if ORCUS_DEBUG_CELL_BUFFER
+ cout << "cell_buffer::append: '" << std::string(p, len) << "'" << endl;
+#endif
+
+ size_t size_needed = m_buf_size + len;
+ if (m_buffer.size() < size_needed)
+ m_buffer.resize(size_needed);
+
+ char* p_dest = &m_buffer[m_buf_size];
+ std::strncpy(p_dest, p, len);
+ m_buf_size += len;
+}
+
+void cell_buffer::reset()
+{
+ m_buf_size = 0;
+}
+
+std::string_view cell_buffer::str() const
+{
+ return std::string_view{m_buffer.data(), m_buf_size};
+}
+
+bool cell_buffer::empty() const
+{
+ return m_buf_size == 0;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/css_parser_base.cpp b/src/parser/css_parser_base.cpp
new file mode 100644
index 0000000..128e5d4
--- /dev/null
+++ b/src/parser/css_parser_base.cpp
@@ -0,0 +1,337 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/css_parser_base.hpp>
+#include <orcus/parser_global.hpp>
+
+#include "utf8.hpp"
+
+#include <cstring>
+#include <cassert>
+#include <cmath>
+#include <limits>
+
+namespace orcus { namespace css {
+
+parser_base::parser_base(std::string_view content) :
+ orcus::parser_base(content.data(), content.size()),
+ m_simple_selector_count(0),
+ m_combinator(combinator_t::descendant) {}
+
+void parser_base::identifier(const char*& p, size_t& len, std::string_view extra)
+{
+ p = mp_char;
+ len = 1;
+ for (next(); has_char(); next(), ++len)
+ {
+ char c = cur_char();
+ if (is_alpha(c) || is_numeric(c) || is_in(c, "-_"))
+ continue;
+
+ if (!extra.empty())
+ {
+ // See if the character is one of the extra allowed characters.
+ if (is_in(c, extra))
+ continue;
+ }
+ return;
+ }
+}
+
+uint8_t parser_base::parse_uint8()
+{
+ // 0 - 255
+ int val = 0;
+ size_t len = 0;
+ for (; has_char() && len <= 3; next())
+ {
+ char c = cur_char();
+ if (!is_numeric(c))
+ break;
+
+ ++len;
+ val *= 10;
+ val += c - '0';
+ }
+
+ if (!len)
+ throw parse_error("parse_uint8: no digit encountered.", offset());
+
+ int maxval = std::numeric_limits<uint8_t>::max();
+ if (val > maxval)
+ val = maxval;
+
+ return static_cast<uint8_t>(val);
+}
+
+std::string_view parser_base::parse_value()
+{
+ auto throw_invalid = [this](uint8_t n_bytes)
+ {
+ std::ostringstream os;
+ os << "parse_value: invalid utf-8 byte length (" << int(n_bytes) << ")";
+ throw parse_error(os.str(), offset());
+ };
+
+ auto check_byte_length_or_throw = [this](uint8_t n_bytes, std::size_t max_size)
+ {
+ if (std::size_t(n_bytes) > max_size)
+ {
+ std::ostringstream os;
+ os << "parse_value: utf-8 byte length is " << int(n_bytes) << " but only " << max_size << " bytes remaining.";
+ throw parse_error(os.str(), offset());
+ }
+ };
+
+ std::size_t max_size = available_size();
+ if (!max_size)
+ return {};
+
+ const char* p0 = mp_char;
+ std::size_t len = 0;
+
+ char c = cur_char();
+ uint8_t n_bytes = calc_utf8_byte_length(c);
+
+ // any of '-+.#' is allowed as first character, while any of '-_.%' is
+ // allowed as second characters.
+
+ switch (n_bytes)
+ {
+ case 1:
+ {
+ if (!is_alpha(c) && !is_numeric(c) && !is_in(c, "-+.#"))
+ parse_error::throw_with("parse_value: illegal first character of a value '", c, "'", offset());
+ break;
+ }
+ case 2:
+ case 3:
+ case 4:
+ {
+ check_byte_length_or_throw(n_bytes, max_size);
+ break;
+ }
+ default:
+ throw_invalid(n_bytes);
+ }
+
+ len += n_bytes;
+ next(n_bytes);
+
+ while (has_char())
+ {
+ c = cur_char();
+ max_size = available_size();
+ n_bytes = calc_utf8_byte_length(c);
+
+ switch (n_bytes)
+ {
+ case 1:
+ {
+ if (!is_alpha(c) && !is_numeric(c) && !is_in(c, "-_.%"))
+ return {p0, len};
+ break;
+ }
+ case 2:
+ case 3:
+ case 4:
+ {
+ check_byte_length_or_throw(n_bytes, max_size);
+ break;
+ }
+ default:
+ throw_invalid(n_bytes);
+ }
+
+ len += n_bytes;
+ next(n_bytes);
+ }
+
+ return {p0, len};
+}
+
+double parser_base::parse_percent()
+{
+ double v = parse_double_or_throw();
+
+ if (*mp_char != '%')
+ parse_error::throw_with(
+ "parse_percent: '%' expected after the numeric value, but '", *mp_char, "' found.", offset());
+
+ next(); // skip the '%'.
+ return v;
+}
+
+double parser_base::parse_double_or_throw()
+{
+ double v = parse_double();
+ if (std::isnan(v))
+ throw parse_error("parse_double: failed to parse double precision value.", offset());
+ return v;
+}
+
+void parser_base::literal(const char*& p, size_t& len, char quote)
+{
+ assert(cur_char() == quote);
+ next();
+ skip_to(p, len, quote);
+
+ if (cur_char() != quote)
+ throw parse_error("literal: end quote has never been reached.", offset());
+}
+
+void parser_base::skip_to(const char*&p, size_t& len, char c)
+{
+ p = mp_char;
+ len = 0;
+ for (; has_char(); next(), ++len)
+ {
+ if (cur_char() == c)
+ return;
+ }
+}
+
+void parser_base::skip_to_or_blank(const char*&p, size_t& len, std::string_view chars)
+{
+ p = mp_char;
+ len = 0;
+ for (; has_char(); next(), ++len)
+ {
+ if (is_blank(*mp_char) || is_in(*mp_char, chars))
+ return;
+ }
+}
+
+void parser_base::skip_blanks()
+{
+ skip(" \t\r\n");
+}
+
+void parser_base::skip_blanks_reverse()
+{
+ const char* p = mp_char + remaining_size();
+ for (; p != mp_char; --p, --mp_end)
+ {
+ if (!is_blank(*p))
+ break;
+ }
+}
+
+void parser_base::shrink_stream()
+{
+ // Skip any leading blanks.
+ skip_blanks();
+
+ if (!remaining_size())
+ return;
+
+ // Skip any trailing blanks.
+ skip_blanks_reverse();
+
+ // Skip leading <!-- if present.
+
+ const char* com_open = "<!--";
+ size_t com_open_len = std::strlen(com_open);
+ if (remaining_size() < com_open_len)
+ // Not enough stream left. Bail out.
+ return;
+
+ const char* p = mp_char;
+ for (size_t i = 0; i < com_open_len; ++i, ++p)
+ {
+ if (*p != com_open[i])
+ return;
+ next();
+ }
+ mp_char = p;
+
+ // Skip leading blanks once again.
+ skip_blanks();
+
+ // Skip trailing --> if present.
+ const char* com_close = "-->";
+ size_t com_close_len = std::strlen(com_close);
+ size_t n = remaining_size();
+ if (n < com_close_len)
+ // Not enough stream left. Bail out.
+ return;
+
+ p = mp_char + n; // move to the last char.
+ for (size_t i = com_close_len; i > 0; --i, --p)
+ {
+ if (*p != com_close[i-1])
+ return;
+ }
+ mp_end -= com_close_len;
+
+ skip_blanks_reverse();
+}
+
+bool parser_base::skip_comment()
+{
+ char c = cur_char();
+ if (c != '/')
+ return false;
+
+ if (remaining_size() > 2 && peek_char() == '*')
+ {
+ next();
+ comment();
+ skip_blanks();
+ return true;
+ }
+
+ return false;
+}
+
+void parser_base::comment()
+{
+ assert(cur_char() == '*');
+
+ // Parse until we reach either EOF or '*/'.
+ bool has_star = false;
+ for (next(); has_char(); next())
+ {
+ char c = cur_char();
+ if (has_star && c == '/')
+ {
+ next();
+ return;
+ }
+ has_star = (c == '*');
+ }
+
+ // EOF reached.
+}
+
+void parser_base::skip_comments_and_blanks()
+{
+ skip_blanks();
+ while (skip_comment())
+ ;
+}
+
+void parser_base::set_combinator(char c, css::combinator_t combinator)
+{
+ if (!m_simple_selector_count)
+ parse_error::throw_with(
+ "set_combinator: combinator '", c, "' encountered without parent element.", offset());
+
+ m_combinator = combinator;
+ next();
+ skip_comments_and_blanks();
+}
+
+void parser_base::reset_before_block()
+{
+ m_simple_selector_count = 0;
+ m_combinator = css::combinator_t::descendant;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/css_parser_test.cpp b/src/parser/css_parser_test.cpp
new file mode 100644
index 0000000..95f4b1c
--- /dev/null
+++ b/src/parser/css_parser_test.cpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/css_parser.hpp>
+
+#include <cstring>
+
+void test_handler()
+{
+ const char* test_code = "p { background-color: white; }";
+
+ orcus::css_handler hdl;
+ orcus::css_parser<orcus::css_handler> parser(test_code, hdl);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/css_types.cpp b/src/parser/css_types.cpp
new file mode 100644
index 0000000..9079159
--- /dev/null
+++ b/src/parser/css_types.cpp
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/css_types.hpp>
+#include <mdds/sorted_string_map.hpp>
+#include <mdds/global.hpp>
+
+#include <sstream>
+
+namespace orcus { namespace css {
+
+const pseudo_element_t pseudo_element_after = 0x0001;
+const pseudo_element_t pseudo_element_before = 0x0002;
+const pseudo_element_t pseudo_element_first_letter = 0x0004;
+const pseudo_element_t pseudo_element_first_line = 0x0008;
+const pseudo_element_t pseudo_element_selection = 0x0010;
+const pseudo_element_t pseudo_element_backdrop = 0x0020;
+
+namespace {
+
+namespace pseudo_elem {
+
+using map_type = mdds::sorted_string_map<pseudo_element_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "after", pseudo_element_after },
+ { "backdrop", pseudo_element_backdrop },
+ { "before", pseudo_element_before },
+ { "first-letter", pseudo_element_first_letter },
+ { "first-line", pseudo_element_first_line },
+ { "selection", pseudo_element_selection },
+};
+
+const map_type& get()
+{
+ static map_type map(entries, std::size(entries), 0);
+ return map;
+}
+
+} // namespace pseudo_elem
+
+}
+
+pseudo_element_t to_pseudo_element(std::string_view s)
+{
+ return pseudo_elem::get().find(s);
+}
+
+const pseudo_class_t pseudo_class_active = 0x0000000000000001;
+const pseudo_class_t pseudo_class_checked = 0x0000000000000002;
+const pseudo_class_t pseudo_class_default = 0x0000000000000004;
+const pseudo_class_t pseudo_class_dir = 0x0000000000000008;
+const pseudo_class_t pseudo_class_disabled = 0x0000000000000010;
+const pseudo_class_t pseudo_class_empty = 0x0000000000000020;
+const pseudo_class_t pseudo_class_enabled = 0x0000000000000040;
+const pseudo_class_t pseudo_class_first = 0x0000000000000080;
+const pseudo_class_t pseudo_class_first_child = 0x0000000000000100;
+const pseudo_class_t pseudo_class_first_of_type = 0x0000000000000200;
+const pseudo_class_t pseudo_class_fullscreen = 0x0000000000000400;
+const pseudo_class_t pseudo_class_focus = 0x0000000000000800;
+const pseudo_class_t pseudo_class_hover = 0x0000000000001000;
+const pseudo_class_t pseudo_class_indeterminate = 0x0000000000002000;
+const pseudo_class_t pseudo_class_in_range = 0x0000000000004000;
+const pseudo_class_t pseudo_class_invalid = 0x0000000000008000;
+const pseudo_class_t pseudo_class_lang = 0x0000000000010000;
+const pseudo_class_t pseudo_class_last_child = 0x0000000000020000;
+const pseudo_class_t pseudo_class_last_of_type = 0x0000000000040000;
+const pseudo_class_t pseudo_class_left = 0x0000000000080000;
+const pseudo_class_t pseudo_class_link = 0x0000000000100000;
+const pseudo_class_t pseudo_class_not = 0x0000000000200000;
+const pseudo_class_t pseudo_class_nth_child = 0x0000000000400000;
+const pseudo_class_t pseudo_class_nth_last_child = 0x0000000000800000;
+const pseudo_class_t pseudo_class_nth_last_of_type = 0x0000000001000000;
+const pseudo_class_t pseudo_class_nth_of_type = 0x0000000002000000;
+const pseudo_class_t pseudo_class_only_child = 0x0000000004000000;
+const pseudo_class_t pseudo_class_only_of_type = 0x0000000008000000;
+const pseudo_class_t pseudo_class_optional = 0x0000000010000000;
+const pseudo_class_t pseudo_class_out_of_range = 0x0000000020000000;
+const pseudo_class_t pseudo_class_read_only = 0x0000000040000000;
+const pseudo_class_t pseudo_class_read_write = 0x0000000080000000;
+const pseudo_class_t pseudo_class_required = 0x0000000100000000;
+const pseudo_class_t pseudo_class_right = 0x0000000200000000;
+const pseudo_class_t pseudo_class_root = 0x0000000400000000;
+const pseudo_class_t pseudo_class_scope = 0x0000000800000000;
+const pseudo_class_t pseudo_class_target = 0x0000001000000000;
+const pseudo_class_t pseudo_class_valid = 0x0000002000000000;
+const pseudo_class_t pseudo_class_visited = 0x0000004000000000;
+
+namespace {
+
+namespace pseudo_class {
+
+using map_type = mdds::sorted_string_map<pseudo_class_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "active", pseudo_class_active },
+ { "checked", pseudo_class_checked },
+ { "default", pseudo_class_default },
+ { "dir", pseudo_class_dir },
+ { "disabled", pseudo_class_disabled },
+ { "empty", pseudo_class_empty },
+ { "enabled", pseudo_class_enabled },
+ { "first", pseudo_class_first },
+ { "first-child", pseudo_class_first_child },
+ { "first-of-type", pseudo_class_first_of_type },
+ { "focus", pseudo_class_focus },
+ { "fullscreen", pseudo_class_fullscreen },
+ { "hover", pseudo_class_hover },
+ { "in-range", pseudo_class_in_range },
+ { "indeterminate", pseudo_class_indeterminate },
+ { "invalid", pseudo_class_invalid },
+ { "lang", pseudo_class_lang },
+ { "last-child", pseudo_class_last_child },
+ { "last-of-type", pseudo_class_last_of_type },
+ { "left", pseudo_class_left },
+ { "link", pseudo_class_link },
+ { "not", pseudo_class_not },
+ { "nth-child", pseudo_class_nth_child },
+ { "nth-last-child", pseudo_class_nth_last_child },
+ { "nth-last-of-type", pseudo_class_nth_last_of_type },
+ { "nth-of-type", pseudo_class_nth_of_type },
+ { "only-child", pseudo_class_only_child },
+ { "only-of-type", pseudo_class_only_of_type },
+ { "optional", pseudo_class_optional },
+ { "out-of-range", pseudo_class_out_of_range },
+ { "read-only", pseudo_class_read_only },
+ { "read-write", pseudo_class_read_write },
+ { "required", pseudo_class_required },
+ { "right", pseudo_class_right },
+ { "root", pseudo_class_root },
+ { "scope", pseudo_class_scope },
+ { "target", pseudo_class_target },
+ { "valid", pseudo_class_valid },
+ { "visited", pseudo_class_visited },
+};
+
+const map_type& get()
+{
+ static map_type map(entries, std::size(entries), 0);
+ return map;
+}
+
+} // namespace pseudo_class
+
+}
+
+pseudo_class_t to_pseudo_class(std::string_view s)
+{
+ return pseudo_class::get().find(s);
+}
+
+std::string pseudo_class_to_string(pseudo_class_t val)
+{
+ std::ostringstream os;
+ std::size_t n = std::size(pseudo_class::entries);
+ const pseudo_class::map_type::entry* p = pseudo_class::entries;
+ const pseudo_class::map_type::entry* p_end = p + n;
+ for (; p != p_end; ++p)
+ {
+ if (val & p->value)
+ os << ":" << p->key;
+ }
+
+ return os.str();
+}
+
+namespace {
+
+typedef mdds::sorted_string_map<property_function_t> propfunc_map_type;
+
+// Keys must be sorted.
+propfunc_map_type::entry propfunc_type_entries[] = {
+ { MDDS_ASCII("hsl"), property_function_t::hsl },
+ { MDDS_ASCII("hsla"), property_function_t::hsla },
+ { MDDS_ASCII("rgb"), property_function_t::rgb },
+ { MDDS_ASCII("rgba"), property_function_t::rgba },
+ { MDDS_ASCII("url"), property_function_t::url }
+};
+
+}
+
+property_function_t to_property_function(std::string_view s)
+{
+ static propfunc_map_type propfunc_map(
+ propfunc_type_entries, std::size(propfunc_type_entries), property_function_t::unknown);
+
+ return propfunc_map.find(s.data(), s.size());
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/csv_parser_base.cpp b/src/parser/csv_parser_base.cpp
new file mode 100644
index 0000000..1bf914c
--- /dev/null
+++ b/src/parser/csv_parser_base.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/csv_parser_base.hpp"
+
+#include <cstring>
+
+namespace orcus { namespace csv {
+
+parser_config::parser_config() :
+ text_qualifier('\0'),
+ trim_cell_value(false) {}
+
+parser_base::parser_base(
+ std::string_view content, const csv::parser_config& config) :
+ ::orcus::parser_base(content.data(), content.size()), m_config(config)
+{
+ skip_bom();
+}
+
+bool parser_base::is_blank(char c) const
+{
+ return is_in(c, " \t");
+}
+
+bool parser_base::is_delim(char c) const
+{
+ return m_config.delimiters.find(c) != std::string::npos;
+}
+
+bool parser_base::is_text_qualifier(char c) const
+{
+ return m_config.text_qualifier == c;
+}
+
+void parser_base::skip_blanks()
+{
+ skip(" \t");
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/csv_parser_test.cpp b/src/parser/csv_parser_test.cpp
new file mode 100644
index 0000000..18470f0
--- /dev/null
+++ b/src/parser/csv_parser_test.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/csv_parser.hpp>
+
+#include <cstring>
+
+void test_handler()
+{
+ const char* test_code = "1,2,3,4,5\n6,7,8,9,10\n";
+
+ orcus::csv_handler hdl;
+ orcus::csv::parser_config config;
+ orcus::csv_parser<orcus::csv_handler> parser(test_code, hdl, config);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/exception.cpp b/src/parser/exception.cpp
new file mode 100644
index 0000000..1d958fd
--- /dev/null
+++ b/src/parser/exception.cpp
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/exception.hpp"
+
+#include <sstream>
+
+using namespace std;
+
+namespace orcus {
+
+general_error::general_error(std::string msg) :
+ m_msg(std::move(msg))
+{
+}
+
+general_error::general_error(std::string_view cls, std::string_view msg)
+{
+ std::ostringstream os;
+ os << cls << ": " << msg;
+ m_msg = os.str();
+}
+
+general_error::~general_error() noexcept = default;
+
+const char* general_error::what() const noexcept
+{
+ return m_msg.c_str();
+}
+
+void general_error::append_msg(const std::string& s)
+{
+ m_msg += s;
+}
+
+invalid_arg_error::invalid_arg_error(const std::string& msg) :
+ std::invalid_argument(msg) {}
+
+invalid_arg_error::~invalid_arg_error() noexcept {}
+
+xml_structure_error::xml_structure_error(std::string msg) :
+ general_error(std::move(msg)) {}
+
+xml_structure_error::~xml_structure_error() noexcept = default;
+
+json_structure_error::json_structure_error(std::string msg) :
+ general_error(std::move(msg)) {}
+
+json_structure_error::~json_structure_error() noexcept = default;
+
+invalid_map_error::invalid_map_error(std::string msg) :
+ general_error(std::move(msg)) {}
+
+invalid_map_error::~invalid_map_error() noexcept = default;
+
+value_error::value_error(std::string msg) :
+ general_error(std::move(msg)) {}
+
+value_error::~value_error() noexcept = default;
+
+xpath_error::xpath_error(std::string msg) : general_error(std::move(msg)) {}
+
+xpath_error::~xpath_error() noexcept = default;
+
+interface_error::interface_error(std::string msg) : general_error(std::move(msg)) {}
+
+interface_error::~interface_error() noexcept = default;
+
+namespace {
+
+std::string build_offset_msg(std::ptrdiff_t offset)
+{
+ std::ostringstream os;
+ os << " (offset=" << offset << ')';
+ return os.str();
+}
+
+std::string build_message(std::string_view msg_before, char c, std::string_view msg_after)
+{
+ std::ostringstream os;
+ os << msg_before << c << msg_after;
+ return os.str();
+}
+
+std::string build_message(
+ std::string_view msg_before, std::string_view msg, std::string_view msg_after)
+{
+ std::ostringstream os;
+ os << msg_before << msg << msg_after;
+ return os.str();
+}
+
+}
+
+parse_error::parse_error(std::string_view cls, std::string_view msg, std::ptrdiff_t offset) :
+ general_error(cls, msg), m_offset(offset)
+{
+ append_msg(build_offset_msg(offset));
+}
+
+parse_error::parse_error(std::string msg, std::ptrdiff_t offset) :
+ general_error(std::move(msg)), m_offset(offset)
+{
+ append_msg(build_offset_msg(offset));
+}
+
+std::ptrdiff_t parse_error::offset() const
+{
+ return m_offset;
+}
+
+void parse_error::throw_with(
+ std::string_view msg_before, char c, std::string_view msg_after, std::ptrdiff_t offset)
+{
+ throw parse_error(build_message(msg_before, c, msg_after), offset);
+}
+
+void parse_error::throw_with(
+ std::string_view msg_before, std::string_view msg, std::string_view msg_after, std::ptrdiff_t offset)
+{
+ throw parse_error(build_message(msg_before, msg, msg_after), offset);
+}
+
+malformed_xml_error::malformed_xml_error(std::string_view msg, std::ptrdiff_t offset) :
+ orcus::parse_error("malformed_xml_error", msg, offset) {}
+
+malformed_xml_error::~malformed_xml_error() = default;
+
+zip_error::zip_error(std::string_view msg) : general_error("zip_error", msg)
+{
+}
+
+zip_error::~zip_error() = default;
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/json_global.cpp b/src/parser/json_global.cpp
new file mode 100644
index 0000000..f01f778
--- /dev/null
+++ b/src/parser/json_global.cpp
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/json_global.hpp"
+#include "orcus/parser_global.hpp"
+
+#include <sstream>
+
+namespace orcus { namespace json {
+
+namespace {
+
+const char backslash = '\\';
+
+}
+
+std::string escape_string(const std::string& input)
+{
+ std::ostringstream os;
+
+ for (auto it = input.begin(), ite = input.end(); it != ite; ++it)
+ {
+ char c = *it;
+ if (c == '"')
+ // Escape double quote, but not forward slash.
+ os << backslash;
+ else if (c == backslash)
+ {
+ // Escape a '\' if and only if the next character is not one of control characters.
+ auto itnext = it + 1;
+ if (itnext == ite || get_string_escape_char_type(*itnext) != string_escape_char_t::control_char)
+ os << backslash;
+ }
+ os << c;
+ }
+
+ return os.str();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/json_parser_base.cpp b/src/parser/json_parser_base.cpp
new file mode 100644
index 0000000..0dcdc3b
--- /dev/null
+++ b/src/parser/json_parser_base.cpp
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/json_parser_base.hpp"
+#include "orcus/cell_buffer.hpp"
+#include "numeric_parser.hpp"
+
+#include <cassert>
+#include <cmath>
+
+namespace orcus { namespace json {
+
+namespace {
+
+const char* parse_numeric_json(const char* p, const char* p_end, double& value)
+{
+ using numeric_parser_type = detail::numeric_parser<detail::json_parser_trait>;
+
+ numeric_parser_type parser(p, p_end);
+ double v = parser.parse();
+ if (!std::isnan(v))
+ p = parser.get_char_position();
+
+ value = v;
+ return p;
+};
+
+} // anonymous namespace
+
+struct parser_base::impl
+{
+ cell_buffer m_buffer;
+};
+
+parser_base::parser_base(std::string_view content) :
+ orcus::parser_base(content.data(), content.size()), mp_impl(std::make_unique<impl>())
+{
+
+ set_numeric_parser(parse_numeric_json);
+}
+
+parser_base::~parser_base() {}
+
+void parser_base::skip_ws()
+{
+ skip(" \n\r\t");
+}
+
+void parser_base::parse_true()
+{
+ if (!parse_expected("true"))
+ throw parse_error("parse_true: boolean 'true' expected.", offset());
+
+ skip_ws();
+}
+
+void parser_base::parse_false()
+{
+ if (!parse_expected("false"))
+ throw parse_error("parse_false: boolean 'false' expected.", offset());
+
+ skip_ws();
+}
+
+void parser_base::parse_null()
+{
+ if (!parse_expected("null"))
+ throw parse_error("parse_null: null expected.", offset());
+
+ skip_ws();
+}
+
+double parser_base::parse_double_or_throw()
+{
+ double v = parse_double();
+ if (std::isnan(v))
+ throw parse_error("parse_double_or_throw: failed to parse double precision value.", offset());
+ return v;
+}
+
+parse_quoted_string_state parser_base::parse_string()
+{
+ assert(cur_char() == '"');
+ size_t max_length = remaining_size();
+ const char* p = mp_char;
+ parse_quoted_string_state ret = parse_double_quoted_string(p, max_length, mp_impl->m_buffer);
+ if (ret.has_control_character)
+ throw parse_error("parse_string: string contains a control character.", offset());
+
+ mp_char = p;
+
+ if (ret.str)
+ skip_ws();
+
+ return ret;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/json_parser_test.cpp b/src/parser/json_parser_test.cpp
new file mode 100644
index 0000000..db64861
--- /dev/null
+++ b/src/parser/json_parser_test.cpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/json_parser.hpp>
+
+#include <cstring>
+
+void test_handler()
+{
+ const char* test_code = "{\"key1\": [1,2,3,4,5], \"key2\": 12.3}";
+
+ orcus::json_handler hdl;
+ orcus::json_parser<orcus::json_handler> parser(test_code, hdl);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/json_parser_thread.cpp b/src/parser/json_parser_thread.cpp
new file mode 100644
index 0000000..a07bb61
--- /dev/null
+++ b/src/parser/json_parser_thread.cpp
@@ -0,0 +1,294 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/json_parser_thread.hpp>
+#include <orcus/json_parser.hpp>
+#include <orcus/string_pool.hpp>
+#include <orcus/detail/parser_token_buffer.hpp>
+
+#include <sstream>
+#include <string_view>
+#include <algorithm>
+#include <limits>
+
+namespace orcus { namespace json {
+
+parse_token::parse_token() : type(parse_token_t::unknown), value(0.0) {}
+
+parse_token::parse_token(parse_token_t _type) : type(_type), value(0.0) {}
+
+parse_token::parse_token(parse_token_t _type, std::string_view s) :
+ type(_type), value(s)
+{
+}
+
+parse_token::parse_token(std::string_view s, std::ptrdiff_t offset) :
+ type(parse_token_t::parse_error), value(parse_error_value_t{s, offset})
+{
+ assert(type == parse_token_t::parse_error);
+}
+
+parse_token::parse_token(double v) :
+ type(parse_token_t::number), value(v)
+{
+}
+
+parse_token::parse_token(const parse_token& other) :
+ type(other.type), value(other.value)
+{
+}
+
+bool parse_token::operator== (const parse_token& other) const
+{
+ return type == other.type && value == other.value;
+}
+
+bool parse_token::operator!= (const parse_token& other) const
+{
+ return !operator== (other);
+}
+
+/**
+ * This impl class also acts as a handler for the parser.
+ *
+ */
+struct parser_thread::impl
+{
+ detail::thread::parser_token_buffer<parse_tokens_t> m_token_buffer;
+ string_pool m_pool;
+ parse_tokens_t m_parser_tokens; // token buffer for the parser thread.
+
+ const char* mp_char;
+ size_t m_size;
+
+ impl(const char* p, size_t n, size_t min_token_size, size_t max_token_size) :
+ m_token_buffer(min_token_size, max_token_size),
+ mp_char(p), m_size(n)
+ {
+ m_parser_tokens.reserve(min_token_size);
+ }
+
+ void start()
+ {
+ try
+ {
+ json_parser<parser_thread::impl> parser({mp_char, m_size}, *this);
+ parser.parse();
+ }
+ catch (const parse_error& e)
+ {
+ std::string_view s = m_pool.intern(e.what()).first;
+ m_parser_tokens.emplace_back(s, e.offset());
+ }
+
+ notify_and_finish();
+ }
+
+ void begin_parse()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::begin_parse);
+ check_and_notify();
+ }
+
+ void end_parse()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::end_parse);
+ check_and_notify();
+ }
+
+ void begin_array()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::begin_array);
+ check_and_notify();
+ }
+
+ void end_array()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::end_array);
+ check_and_notify();
+ }
+
+ void begin_object()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::begin_object);
+ check_and_notify();
+ }
+
+ void object_key(std::string_view s, bool transient)
+ {
+ if (transient)
+ s = m_pool.intern(s).first;
+
+ m_parser_tokens.emplace_back(parse_token_t::object_key, s);
+ check_and_notify();
+ }
+
+ void end_object()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::end_object);
+ check_and_notify();
+ }
+
+ void boolean_true()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::boolean_true);
+ check_and_notify();
+ }
+
+ void boolean_false()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::boolean_false);
+ check_and_notify();
+ }
+
+ void null()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::null);
+ check_and_notify();
+ }
+
+ void string(std::string_view s, bool transient)
+ {
+ if (transient)
+ s = m_pool.intern(s).first;
+
+ m_parser_tokens.emplace_back(parse_token_t::string, s);
+ check_and_notify();
+ }
+
+ void number(double val)
+ {
+ m_parser_tokens.emplace_back(val);
+ check_and_notify();
+ }
+
+ void check_and_notify()
+ {
+ m_token_buffer.check_and_notify(m_parser_tokens);
+ }
+
+ void notify_and_finish()
+ {
+ m_token_buffer.notify_and_finish(m_parser_tokens);
+ }
+
+ bool next_tokens(parse_tokens_t& tokens)
+ {
+ return m_token_buffer.next_tokens(tokens);
+ }
+
+ parser_stats get_stats() const
+ {
+ parser_stats stats;
+ stats.token_buffer_size_threshold = m_token_buffer.token_size_threshold();
+ return stats;
+ }
+
+ void swap_string_pool(string_pool& pool)
+ {
+ m_pool.swap(pool);
+ }
+};
+
+std::ostream& operator<< (std::ostream& os, const parse_tokens_t& tokens)
+{
+ using std::endl;
+
+ os << "token size: " << tokens.size() << endl;
+
+ std::for_each(tokens.begin(), tokens.end(),
+ [&](const parse_token& t)
+ {
+ switch (t.type)
+ {
+ case parse_token_t::begin_array:
+ os << "- begin_array" << endl;
+ break;
+ case parse_token_t::begin_object:
+ os << "- begin_object" << endl;
+ break;
+ case parse_token_t::begin_parse:
+ os << "- begin_parse" << endl;
+ break;
+ case parse_token_t::boolean_false:
+ os << "- boolean_false" << endl;
+ break;
+ case parse_token_t::boolean_true:
+ os << "- boolean_true" << endl;
+ break;
+ case parse_token_t::end_array:
+ os << "- end_array" << endl;
+ break;
+ case parse_token_t::end_object:
+ os << "- end_object" << endl;
+ break;
+ case parse_token_t::end_parse:
+ os << "- end_parse" << endl;
+ break;
+ case parse_token_t::null:
+ os << "- null" << endl;
+ break;
+ case parse_token_t::number:
+ os << "- number (v=" << std::get<double>(t.value) << ")" << endl;
+ break;
+ case parse_token_t::object_key:
+ os << "- object_key (v=" << std::get<std::string_view>(t.value) << ")" << endl;
+ break;
+ case parse_token_t::parse_error:
+ {
+ auto v = std::get<parse_error_value_t>(t.value);
+ os << "- parse_error (v=" << v.str << ", offset=" << v.offset << ")" << endl;
+ break;
+ }
+ case parse_token_t::string:
+ os << "- string (" << std::get<std::string_view>(t.value) << ")" << endl;
+ break;
+ case parse_token_t::unknown:
+ os << "- unknown" << endl;
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ return os;
+}
+
+parser_thread::parser_thread(const char* p, size_t n, size_t min_token_size) :
+ mp_impl(std::make_unique<parser_thread::impl>(
+ p, n, min_token_size, std::numeric_limits<size_t>::max()/2)) {}
+
+parser_thread::parser_thread(const char* p, size_t n, size_t min_token_size, size_t max_token_size) :
+ mp_impl(std::make_unique<parser_thread::impl>(
+ p, n, min_token_size, max_token_size)) {}
+
+parser_thread::~parser_thread() {}
+
+void parser_thread::start()
+{
+ mp_impl->start();
+}
+
+bool parser_thread::next_tokens(parse_tokens_t& tokens)
+{
+ return mp_impl->next_tokens(tokens);
+}
+
+parser_stats parser_thread::get_stats() const
+{
+ return mp_impl->get_stats();
+}
+
+void parser_thread::swap_string_pool(string_pool& pool)
+{
+ mp_impl->swap_string_pool(pool);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_base.cpp b/src/parser/parser_base.cpp
new file mode 100644
index 0000000..e49af71
--- /dev/null
+++ b/src/parser/parser_base.cpp
@@ -0,0 +1,222 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/parser_base.hpp"
+#include "orcus/parser_global.hpp"
+#include "cpu_features.hpp"
+
+#include <sstream>
+#include <cstring>
+#include <limits>
+#include <cassert>
+#include <algorithm>
+
+#ifdef __ORCUS_CPU_FEATURES
+#include <immintrin.h>
+#endif
+
+namespace orcus {
+
+parser_base::parser_base(const char* p, size_t n) :
+ mp_begin(p), mp_char(p), mp_end(p+n),
+ m_func_parse_numeric(parse_numeric)
+{
+}
+
+void parser_base::prev(size_t dec)
+{
+ mp_char -= dec;
+}
+
+char parser_base::peek_char(std::size_t offset) const
+{
+ return *(mp_char + offset);
+}
+
+std::string_view parser_base::peek_chars(std::size_t length) const
+{
+ return {mp_char, length};
+}
+
+void parser_base::skip_bom()
+{
+ // Skip one or more UTF-8 BOM's.
+ constexpr std::string_view BOM = "\xEF\xBB\xBF";
+
+ while (true)
+ {
+ if (available_size() < 3)
+ return;
+
+ if (peek_chars(3) != BOM)
+ return;
+
+ next(3);
+ }
+}
+
+void parser_base::skip(std::string_view chars_to_skip)
+{
+#if defined(__ORCUS_CPU_FEATURES) && defined(__SSE4_2__)
+ __m128i match = _mm_loadu_si128((const __m128i*)chars_to_skip.data());
+ const int mode = _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_EQUAL_ANY | _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY;
+
+ int n_total = available_size();
+
+ while (n_total)
+ {
+ __m128i char_block = _mm_loadu_si128((const __m128i*)mp_char);
+
+ // Find position of the first character that is NOT any of the
+ // characters to skip.
+ int n = std::min<int>(16, n_total);
+ int r = _mm_cmpestri(match, chars_to_skip.size(), char_block, n, mode);
+
+ if (!r)
+ // No characters to skip. Bail out.
+ break;
+
+ mp_char += r; // Move the current char position.
+
+ if (r < 16)
+ // No need to move to the next segment. Stop here.
+ break;
+
+ // Skip 16 chars to the next segment.
+ n_total -= 16;
+ }
+#else
+ for (; has_char(); next())
+ {
+ if (!is_in(*mp_char, chars_to_skip))
+ break;
+ }
+#endif
+}
+
+void parser_base::skip_space_and_control()
+{
+#if defined(__ORCUS_CPU_FEATURES) && defined(__AVX2__)
+ size_t n_total = available_size();
+ const __m256i ws = _mm256_set1_epi8(' '); // whitespaces
+ const __m256i sb = _mm256_set1_epi8(0x80); // signed bit on.
+
+ while (n_total)
+ {
+ // The 'results' stores (for each 8-bit int) 0x00 if the char is less
+ // than or equal to whitespace, or the char is "negative" i.e. the
+ // signed bit is on IOW greater than 127.
+ __m256i char_block = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(mp_char));
+ __m256i results = _mm256_cmpgt_epi8(char_block, ws); // NB: this is a signed comparison.
+ results = _mm256_or_si256(results, _mm256_and_si256(char_block, sb));
+ int r = _mm256_movemask_epi8(results);
+ r = _tzcnt_u32(r);
+ r = std::min<size_t>(r, n_total);
+
+ if (!r)
+ // No characters to skip. Bail out.
+ break;
+
+ mp_char += r; // Move the current char position.
+
+ if (r < 32)
+ // No need to move to the next segment. Stop here.
+ break;
+
+ n_total -= 32;
+ }
+
+#elif defined(__ORCUS_CPU_FEATURES) && defined(__SSE4_2__)
+ __m128i match = _mm_loadu_si128((const __m128i*)"\0 ");
+ const int mode = _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY;
+
+ size_t n_total = available_size();
+
+ while (n_total)
+ {
+ __m128i char_block = _mm_loadu_si128((const __m128i*)mp_char);
+
+ // Find position of the first character that is NOT any of the
+ // characters to skip.
+ int n = std::min<size_t>(16u, n_total);
+ int r = _mm_cmpestri(match, 2, char_block, n, mode);
+
+ if (!r)
+ // No characters to skip. Bail out.
+ break;
+
+ mp_char += r; // Move the current char position.
+
+ if (r < 16)
+ // No need to move to the next segment. Stop here.
+ break;
+
+ // Skip 16 chars to the next segment.
+ n_total -= 16;
+ }
+#else
+ for (; mp_char != mp_end && ((unsigned char)*mp_char) <= (unsigned char)' '; ++mp_char)
+ ;
+#endif
+}
+
+bool parser_base::parse_expected(std::string_view expected)
+{
+ if (expected.size() > available_size())
+ return false;
+
+#if defined(__ORCUS_CPU_FEATURES) && defined(__SSE4_2__)
+ __m128i v_expected = _mm_loadu_si128((const __m128i*)expected.data());
+ __m128i v_char_block = _mm_loadu_si128((const __m128i*)mp_char);
+
+ const int mode = _SIDD_CMP_EQUAL_ORDERED | _SIDD_UBYTE_OPS | _SIDD_BIT_MASK;
+ __m128i res = _mm_cmpestrm(v_expected, expected.size(), v_char_block, expected.size(), mode);
+ int mask = _mm_cvtsi128_si32(res);
+
+ if (mask)
+ mp_char += expected.size();
+
+ return mask;
+#else
+ const char* p = expected.data();
+ for (size_t i = 0; i < expected.size(); ++i, ++p, next())
+ {
+ if (cur_char() != *p)
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+double parser_base::parse_double()
+{
+ size_t max_length = available_size();
+ const char* p = mp_char;
+ double val;
+ p = m_func_parse_numeric(p, p + max_length, val);
+ if (p == mp_char)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ mp_char = p;
+ return val;
+}
+
+size_t parser_base::remaining_size() const
+{
+ size_t n = available_size();
+ return n ? (n - 1) : 0;
+}
+
+std::ptrdiff_t parser_base::offset() const
+{
+ return std::distance(mp_begin, mp_char);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_base_test.cpp b/src/parser/parser_base_test.cpp
new file mode 100644
index 0000000..74994da
--- /dev/null
+++ b/src/parser/parser_base_test.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/parser_base.hpp"
+
+using namespace std;
+using namespace orcus;
+
+void test_skip_space_and_control()
+{
+ class _test_type : public orcus::parser_base
+ {
+ public:
+ _test_type(const char* p, size_t n) : orcus::parser_base(p, n) {}
+
+ void run()
+ {
+ skip_space_and_control();
+ }
+
+ bool has_char() const
+ {
+ return orcus::parser_base::has_char();
+ }
+
+ size_t available_size() const
+ {
+ return orcus::parser_base::available_size();
+ }
+
+ char get_char() const
+ {
+ return *mp_char;
+ }
+ };
+
+ // Create a series of variable-legnth blank strings and make sure the
+ // function correctly skips all the empty characters.
+
+ for (size_t i = 0; i < 32; ++i)
+ {
+ std::string s(i, ' ');
+ assert(s.size() == i);
+
+ _test_type test(s.data(), s.size());
+ assert(test.available_size() == s.size());
+
+ test.run();
+ assert(!test.has_char()); // There should be no more characters to parse.
+
+ s.push_back('a');
+
+ _test_type test2(s.data(), s.size());
+ assert(test2.available_size() == s.size());
+
+ test2.run();
+ assert(test2.has_char()); // The current position should be on the 'a'.
+ assert(test2.get_char() == 'a');
+ }
+}
+
+int main()
+{
+ test_skip_space_and_control();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_global.cpp b/src/parser/parser_global.cpp
new file mode 100644
index 0000000..5489e21
--- /dev/null
+++ b/src/parser/parser_global.cpp
@@ -0,0 +1,515 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/parser_global.hpp>
+#include <orcus/cell_buffer.hpp>
+#include <orcus/exception.hpp>
+
+#include "numeric_parser.hpp"
+
+#include <cassert>
+#include <cmath>
+#include <iostream>
+#include <limits>
+#include <algorithm>
+#include <cctype>
+
+namespace orcus {
+
+const size_t parse_quoted_string_state::error_no_closing_quote = 1;
+const size_t parse_quoted_string_state::error_illegal_escape_char = 2;
+
+bool is_blank(char c)
+{
+ return is_in(c, " \t\n\r");
+}
+
+bool is_alpha(char c)
+{
+ return std::isalpha(static_cast<unsigned char>(c));
+}
+
+bool is_numeric(char c)
+{
+ return std::isdigit(static_cast<unsigned char>(c));
+}
+
+bool is_in(char c, std::string_view allowed)
+{
+#ifdef __ORCUS_DEBUG_UTILS
+ if (allowed.empty())
+ throw std::invalid_argument("'allowed' string should not be empty.");
+#endif
+ auto f = [c](char c_allowed) { return c == c_allowed; };
+ return std::any_of(allowed.begin(), allowed.end(), f);
+}
+
+const char* parse_numeric(const char* p, const char* p_end, double& value)
+{
+ using numeric_parser_type = detail::numeric_parser<detail::generic_parser_trait>;
+
+ numeric_parser_type parser(p, p_end);
+ double v = parser.parse();
+ if (!std::isnan(v))
+ p = parser.get_char_position();
+
+ value = v;
+ return p;
+}
+
+const char* parse_integer(const char* p, const char* p_end, long& value)
+{
+ if (p >= p_end)
+ return p;
+
+ long result = 0.0;
+ bool negative_sign = false;
+
+ // Check for presence of a sign.
+ if (p != p_end)
+ {
+ switch (*p)
+ {
+ case '+':
+ ++p;
+ break;
+ case '-':
+ negative_sign = true;
+ ++p;
+ break;
+ default:
+ ;
+ }
+ }
+
+ for (; p != p_end; ++p)
+ {
+ if (*p < '0' || '9' < *p)
+ {
+ value = negative_sign ? -result : result;
+ return p;
+ }
+
+ result *= 10;
+ result += *p - '0';
+ }
+
+ value = negative_sign ? -result : result;
+ return p;
+}
+
+string_escape_char_t get_string_escape_char_type(char c)
+{
+ switch (c)
+ {
+ case '"':
+ case '\\':
+ case '/':
+ return string_escape_char_t::valid;
+ case 'b': // backspace
+ case 'f': // formfeed
+ case 'n': // newline
+ case 'r': // carriage return
+ case 't': // horizontal tab
+ return string_escape_char_t::control_char;
+ default:
+ ;
+ }
+
+ return string_escape_char_t::invalid;
+}
+
+namespace {
+
+parse_quoted_string_state parse_string_with_escaped_char(
+ const char*& p, size_t max_length, const char* p_parsed, size_t n_parsed, char c,
+ cell_buffer& buffer)
+{
+ const char* p_end = p + max_length;
+
+ parse_quoted_string_state ret;
+ ret.str = nullptr;
+ ret.length = 0;
+ ret.transient = true;
+ ret.has_control_character = false;
+
+ // Start the buffer with the string we've parsed so far.
+ buffer.reset();
+ if (p_parsed && n_parsed)
+ buffer.append(p_parsed, n_parsed);
+ buffer.append(&c, 1);
+
+ ++p;
+ if (p == p_end)
+ {
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+ }
+
+ size_t len = 0;
+ const char* p_head = p;
+ bool escape = false;
+
+ for (; p != p_end; ++p, ++len)
+ {
+ c = *p;
+
+ if (escape)
+ {
+ escape = false;
+
+ switch (get_string_escape_char_type(c))
+ {
+ case string_escape_char_t::valid:
+ buffer.append(p_head, len-1);
+ buffer.append(&c, 1);
+ ++p;
+ len = 0;
+ p_head = p;
+ break;
+ case string_escape_char_t::control_char:
+ // do nothing on control characters.
+ break;
+ case string_escape_char_t::invalid:
+ default:
+ ret.length = parse_quoted_string_state::error_illegal_escape_char;
+ return ret;
+ }
+ }
+
+ switch (*p)
+ {
+ case '"':
+ {
+ // closing quote.
+ buffer.append(p_head, len);
+ ++p; // skip the quote.
+ std::string_view s = buffer.str();
+ ret.str = s.data();
+ ret.length = s.size();
+ return ret;
+ }
+ case '\\':
+ {
+ escape = true;
+ continue;
+ }
+ default:
+ ;
+ }
+ }
+
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+}
+
+parse_quoted_string_state parse_single_quoted_string_buffered(
+ const char*& p, const char* p_end, cell_buffer& buffer)
+{
+ const char* p0 = p;
+ size_t len = 0;
+ char last = 0;
+
+ parse_quoted_string_state ret;
+ ret.transient = true;
+ ret.has_control_character = false;
+
+ for (; p != p_end; ++p)
+ {
+ if (!p0)
+ p0 = p;
+
+ char c = *p;
+ switch (c)
+ {
+ case '\'':
+ {
+ if (last == c)
+ {
+ // Second "'" in series. This is an encoded single quote.
+ buffer.append(p0, len);
+ p0 = nullptr;
+ last = 0;
+ len = 0;
+ continue;
+ }
+ }
+ break;
+ default:
+ {
+ if (last == '\'')
+ {
+ buffer.append(p0, len-1);
+ auto s = buffer.str();
+ ret.str = s.data();
+ ret.length = s.size();
+ return ret;
+ }
+ }
+ }
+
+ last = c;
+ ++len;
+ }
+
+ if (last == '\'')
+ {
+ buffer.append(p0, len-1);
+ auto s = buffer.str();
+ ret.str = s.data();
+ ret.length = s.size();
+ return ret;
+ }
+
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+}
+
+}
+
+parse_quoted_string_state parse_single_quoted_string(
+ const char*& p, size_t max_length, cell_buffer& buffer)
+{
+ assert(*p == '\'');
+ const char* p_end = p + max_length;
+ ++p;
+
+ parse_quoted_string_state ret;
+ ret.str = p;
+ ret.length = 0;
+ ret.transient = false;
+ ret.has_control_character = false;
+
+ if (p == p_end)
+ {
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+ }
+
+ char last = 0;
+ char c = 0;
+ for (; p != p_end; last = c, ++p, ++ret.length)
+ {
+ c = *p;
+ switch (c)
+ {
+ case '\'':
+ {
+ if (last == c)
+ {
+ // Encoded single quote.
+ buffer.reset();
+ buffer.append(ret.str, ret.length);
+ ++p;
+ return parse_single_quoted_string_buffered(p, p_end, buffer);
+ }
+ }
+ break;
+ default:
+ {
+ if (last == '\'')
+ {
+ --ret.length;
+ return ret;
+ }
+ }
+
+ }
+ }
+
+ if (last == '\'')
+ {
+ --ret.length;
+ return ret;
+ }
+
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+}
+
+const char* parse_to_closing_single_quote(const char* p, size_t max_length)
+{
+ assert(*p == '\'');
+ const char* p_end = p + max_length;
+ ++p;
+
+ if (p == p_end)
+ return nullptr;
+
+ char last = 0;
+ for (; p != p_end; ++p)
+ {
+ char c = *p;
+ switch (c)
+ {
+ case '\'':
+ if (last == '\'')
+ {
+ last = 0;
+ continue;
+ }
+ break;
+ default:
+ {
+ if (last == '\'')
+ return p;
+ }
+ }
+
+ last = c;
+ }
+
+ if (last == '\'')
+ return p;
+
+ return nullptr;
+}
+
+parse_quoted_string_state parse_double_quoted_string(
+ const char*& p, size_t max_length, cell_buffer& buffer)
+{
+ if (max_length == 0 || !p || *p != '"')
+ throw invalid_arg_error("parse_double_quoted_string: invalid input string");
+
+ parse_quoted_string_state ret;
+ ret.str = nullptr;
+ ret.length = 0;
+ ret.transient = false;
+ ret.has_control_character = false;
+
+ const char* p_end = p + max_length;
+ ++p; // skip the opening quote.
+
+ ret.str = p;
+
+ if (p == p_end)
+ {
+ // The string contains only the opening quote.
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+ }
+
+ bool escape = false;
+
+ for (; p != p_end; ++p, ++ret.length)
+ {
+ char c = *p;
+
+ if (escape)
+ {
+ escape = false;
+
+ switch (get_string_escape_char_type(c))
+ {
+ case string_escape_char_t::valid:
+ return parse_string_with_escaped_char(p, max_length, ret.str, ret.length-1, c, buffer);
+ case string_escape_char_t::control_char:
+ // do nothing on control characters.
+ break;
+ case string_escape_char_t::invalid:
+ default:
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_illegal_escape_char;
+ return ret;
+ }
+ }
+
+ switch (*p)
+ {
+ case '"':
+ {
+ // closing quote.
+ ++p; // skip the quote.
+ return ret;
+ }
+ case '\\':
+ {
+ escape = true;
+ continue;
+ }
+ default:
+ ;
+ }
+
+ if (0x00 <= c && c <= 0x1F)
+ {
+ // This is an unescaped control character.
+ ret.has_control_character = true;
+ }
+ }
+
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+}
+
+const char* parse_to_closing_double_quote(const char* p, size_t max_length)
+{
+ assert(*p == '"');
+ const char* p_end = p + max_length;
+ ++p;
+
+ if (p == p_end)
+ return nullptr;
+
+ bool escape = false;
+
+ for (; p != p_end; ++p)
+ {
+ if (escape)
+ {
+ char c = *p;
+ escape = false;
+
+ if (get_string_escape_char_type(c) == string_escape_char_t::invalid)
+ return nullptr;
+ }
+
+ switch (*p)
+ {
+ case '"':
+ // closing quote.
+ ++p; // skip the quote.
+ return p;
+ case '\\':
+ escape = true;
+ break;
+ default:
+ ;
+ }
+ }
+
+ return nullptr;
+}
+
+std::string_view trim(std::string_view str)
+{
+ const char* p = str.data();
+ const char* p_end = p + str.size();
+
+ // Find the first non-space character.
+ p = std::find_if_not(p, p_end, is_blank);
+
+ if (p == p_end)
+ {
+ // This string is empty.
+ return std::string_view{};
+ }
+
+ // Find the last non-space character.
+ auto last = std::find_if_not(std::reverse_iterator(p_end), std::reverse_iterator(p), is_blank);
+ std::size_t n = std::distance(p, last.base());
+
+ return std::string_view{p, n};
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_global_test.cpp b/src/parser/parser_global_test.cpp
new file mode 100644
index 0000000..680a221
--- /dev/null
+++ b/src/parser/parser_global_test.cpp
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/parser_global.hpp>
+#include <orcus/cell_buffer.hpp>
+
+#include <vector>
+#include <cmath>
+#include <cstring>
+#include <limits>
+
+namespace {
+
+void test_parse_numbers()
+{
+ orcus::test::stack_printer __sp__(__func__);
+
+ struct test_case
+ {
+ const char* str;
+ double val;
+ };
+
+ std::vector<test_case> test_cases = {
+ {"1", 1.0},
+ {"1.0", 1.0},
+ {"-1.0", -1.0},
+ {"2e2", 200.0},
+ {"1.2", 1.2},
+ {"-0.0001", -0.0001},
+ {"-0.0", 0.0},
+ {"+.", std::numeric_limits<double>::signaling_NaN()},
+ {"+e", std::numeric_limits<double>::signaling_NaN()},
+ {"+e1", std::numeric_limits<double>::signaling_NaN()},
+ {"+ ", std::numeric_limits<double>::signaling_NaN()},
+ {"- ", std::numeric_limits<double>::signaling_NaN()}
+ };
+
+ for (const test_case& test_data : test_cases)
+ {
+ const char* str = test_data.str;
+ double val;
+ orcus::parse_numeric(str, str + std::strlen(test_data.str), val);
+ if (std::isnan(test_data.val))
+ {
+ assert(std::isnan(val));
+ }
+ else
+ {
+ assert(val == test_data.val);
+ }
+ }
+}
+
+void test_parse_integers()
+{
+ orcus::test::stack_printer __sp__(__func__);
+
+ std::string_view test_str = "-100";
+
+ long value;
+ const char* p = test_str.data();
+ const char* p_end = p + test_str.size();
+ const char* p_last = orcus::parse_integer(p, p_end, value);
+
+ assert(value == -100);
+ assert(p_last == p_end);
+
+ --p_end;
+ p_last = orcus::parse_integer(p, p_end, value);
+ assert(value == -10);
+ assert(p_last == p_end);
+
+ --p_end;
+ p_last = orcus::parse_integer(p, p_end, value);
+ assert(value == -1);
+ assert(p_last == p_end);
+
+ test_str = "13.4"; // the parsing should end on the '.'
+ p = test_str.data();
+ p_end = p + test_str.size();
+ p_last = orcus::parse_integer(p, p_end, value);
+ assert(value == 13);
+ assert(p_last == p + 2);
+
+ // What if the p_end points to an earlier address than the p ...
+ std::swap(p, p_end);
+ assert(p > p_end);
+ p_last = orcus::parse_integer(p, p_end, value);
+ assert(p == p_last);
+
+ // Empty char range
+ p = test_str.data();
+ p_end = p;
+ p_last = orcus::parse_integer(p, p_end, value);
+ assert(p_last == p);
+}
+
+void test_parse_double_quoted_strings()
+{
+ orcus::test::stack_printer __sp__(__func__);
+
+ struct test_case
+ {
+ std::string input;
+ const char* expected_p;
+ size_t expected_n;
+ };
+
+ std::vector<test_case> test_cases = {
+ { "\"", nullptr, orcus::parse_quoted_string_state::error_no_closing_quote },
+ { "\"\"", "", 0 },
+ { "\"a\"", "a", 1 },
+
+ };
+
+ for (const test_case& tc : test_cases)
+ {
+ orcus::cell_buffer buf;
+ const char* p = tc.input.data();
+ size_t n = tc.input.size();
+ orcus::parse_quoted_string_state ret = orcus::parse_double_quoted_string(p, n, buf);
+
+ if (tc.expected_p)
+ {
+ std::string expected(tc.expected_p, tc.expected_n);
+ std::string actual(ret.str, ret.length);
+ assert(expected == actual);
+ }
+ else
+ {
+ assert(ret.str == nullptr);
+ assert(ret.length == tc.expected_n);
+ }
+ }
+
+}
+
+void test_trim()
+{
+ // test for trimming.
+ std::string s1("test"), s2(" test"), s3(" test "), s4("test ");
+ std::string_view sv1(s1), sv2(s2), sv3(s3), sv4(s4);
+ assert(sv1 != sv2);
+ assert(sv1 != sv3);
+ assert(sv2 != sv3);
+ assert(sv1 != sv4);
+
+ std::string_view trimmed = orcus::trim(sv1);
+ assert(sv1 == trimmed); // nothing to trim.
+ assert(sv1 == orcus::trim(sv2));
+ assert(sv1 == orcus::trim(sv3));
+ assert(sv1 == orcus::trim(sv4));
+ assert(sv1.size() == orcus::trim(sv2).size());
+ assert(sv1.size() == orcus::trim(sv3).size());
+}
+
+}
+
+int main()
+{
+ test_parse_numbers();
+ test_parse_integers();
+ test_parse_double_quoted_strings();
+ test_trim();
+
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_test_json_validation.cpp b/src/parser/parser_test_json_validation.cpp
new file mode 100644
index 0000000..a001226
--- /dev/null
+++ b/src/parser/parser_test_json_validation.cpp
@@ -0,0 +1,439 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/json_parser.hpp"
+#include "orcus/stream.hpp"
+
+#include <vector>
+#include <iostream>
+#include <fstream>
+
+namespace {
+
+// These test cases originate from https://github.com/nst/JSONTestSuite
+//
+// The name of these files tell if their contents should be accepted or
+// rejected.
+//
+// * y_ content must be accepted by parsers
+// * n_ content must be rejected by parsers
+// * i_ parsers are free to accept or reject content
+
+std::vector<const char*> test_files_indeterminate = {
+ "i_number_double_huge_neg_exp.json",
+ "i_number_huge_exp.json",
+ "i_number_neg_int_huge_exp.json",
+ "i_number_pos_double_huge_exp.json",
+ "i_number_real_neg_overflow.json",
+ "i_number_real_pos_overflow.json",
+ "i_number_real_underflow.json",
+ "i_number_too_big_neg_int.json",
+ "i_number_too_big_pos_int.json",
+ "i_number_very_big_negative_int.json",
+ "i_object_key_lone_2nd_surrogate.json",
+ "i_string_1st_surrogate_but_2nd_missing.json",
+ "i_string_1st_valid_surrogate_2nd_invalid.json",
+ "i_string_incomplete_surrogate_and_escape_valid.json",
+ "i_string_incomplete_surrogate_pair.json",
+ "i_string_incomplete_surrogates_escape_valid.json",
+ "i_string_invalid_lonely_surrogate.json",
+ "i_string_invalid_surrogate.json",
+ "i_string_invalid_utf-8.json",
+ "i_string_inverted_surrogates_U+1D11E.json",
+ "i_string_iso_latin_1.json",
+ "i_string_lone_second_surrogate.json",
+ "i_string_lone_utf8_continuation_byte.json",
+ "i_string_not_in_unicode_range.json",
+ "i_string_overlong_sequence_2_bytes.json",
+ "i_string_overlong_sequence_6_bytes.json",
+ "i_string_overlong_sequence_6_bytes_null.json",
+ "i_string_truncated-utf-8.json",
+ "i_string_utf16BE_no_BOM.json",
+ "i_string_utf16LE_no_BOM.json",
+ "i_string_UTF-16LE_with_BOM.json",
+ "i_string_UTF-8_invalid_sequence.json",
+ "i_string_UTF8_surrogate_U+D800.json",
+ "i_structure_500_nested_arrays.json",
+ "i_structure_UTF-8_BOM_empty_object.json"
+};
+
+std::vector<const char*> test_files_failed = {
+ "n_array_1_true_without_comma.json",
+ "n_array_a_invalid_utf8.json",
+ "n_array_colon_instead_of_comma.json",
+ "n_array_comma_after_close.json",
+ "n_array_comma_and_number.json",
+ "n_array_double_comma.json",
+ "n_array_double_extra_comma.json",
+ "n_array_extra_close.json",
+ "n_array_extra_comma.json",
+ "n_array_incomplete_invalid_value.json",
+ "n_array_incomplete.json",
+ "n_array_inner_array_no_comma.json",
+ "n_array_invalid_utf8.json",
+ "n_array_items_separated_by_semicolon.json",
+ "n_array_just_comma.json",
+ "n_array_just_minus.json",
+ "n_array_missing_value.json",
+ "n_array_newlines_unclosed.json",
+ "n_array_number_and_comma.json",
+ "n_array_number_and_several_commas.json",
+ "n_array_spaces_vertical_tab_formfeed.json",
+ "n_array_star_inside.json",
+ "n_array_unclosed.json",
+ "n_array_unclosed_trailing_comma.json",
+ "n_array_unclosed_with_new_lines.json",
+ "n_array_unclosed_with_object_inside.json",
+ "n_incomplete_false.json",
+ "n_incomplete_null.json",
+ "n_incomplete_true.json",
+ "n_multidigit_number_then_00.json",
+ "n_number_0.1.2.json",
+ "n_number_-01.json",
+ "n_number_0.3e.json",
+ "n_number_0.3e+.json",
+ "n_number_0_capital_E.json",
+ "n_number_0_capital_E+.json",
+ "n_number_0.e1.json",
+ "n_number_0e.json",
+ "n_number_0e+.json",
+ "n_number_1_000.json",
+ "n_number_1.0e-.json",
+ "n_number_1.0e.json",
+ "n_number_1.0e+.json",
+ "n_number_-1.0..json",
+ "n_number_1eE2.json",
+ "n_number_.-1.json",
+ "n_number_+1.json",
+ "n_number_.2e-3.json",
+ "n_number_2.e-3.json",
+ "n_number_2.e+3.json",
+ "n_number_2.e3.json",
+ "n_number_-2..json",
+ "n_number_9.e+.json",
+ "n_number_expression.json",
+ "n_number_hex_1_digit.json",
+ "n_number_hex_2_digits.json",
+ "n_number_infinity.json",
+ "n_number_+Inf.json",
+ "n_number_Inf.json",
+ "n_number_invalid+-.json",
+ "n_number_invalid-negative-real.json",
+ "n_number_invalid-utf-8-in-bigger-int.json",
+ "n_number_invalid-utf-8-in-exponent.json",
+ "n_number_invalid-utf-8-in-int.json",
+ "n_number_++.json",
+ "n_number_minus_infinity.json",
+ "n_number_minus_sign_with_trailing_garbage.json",
+ "n_number_minus_space_1.json",
+ "n_number_-NaN.json",
+ "n_number_NaN.json",
+ "n_number_neg_int_starting_with_zero.json",
+ "n_number_neg_real_without_int_part.json",
+ "n_number_neg_with_garbage_at_end.json",
+ "n_number_real_garbage_after_e.json",
+ "n_number_real_with_invalid_utf8_after_e.json",
+ "n_number_real_without_fractional_part.json",
+ "n_number_starting_with_dot.json",
+ "n_number_U+FF11_fullwidth_digit_one.json",
+ "n_number_with_alpha_char.json",
+ "n_number_with_alpha.json",
+ "n_number_with_leading_zero.json",
+ "n_object_bad_value.json",
+ "n_object_bracket_key.json",
+ "n_object_comma_instead_of_colon.json",
+ "n_object_double_colon.json",
+ "n_object_emoji.json",
+ "n_object_garbage_at_end.json",
+ "n_object_key_with_single_quotes.json",
+ "n_object_lone_continuation_byte_in_key_and_trailing_comma.json",
+ "n_object_missing_colon.json",
+ "n_object_missing_key.json",
+ "n_object_missing_semicolon.json",
+ "n_object_missing_value.json",
+ "n_object_no-colon.json",
+ "n_object_non_string_key_but_huge_number_instead.json",
+ "n_object_non_string_key.json",
+ "n_object_repeated_null_null.json",
+ "n_object_several_trailing_commas.json",
+ "n_object_single_quote.json",
+ "n_object_trailing_comma.json",
+ "n_object_trailing_comment.json",
+ "n_object_trailing_comment_open.json",
+ "n_object_trailing_comment_slash_open_incomplete.json",
+ "n_object_trailing_comment_slash_open.json",
+ "n_object_two_commas_in_a_row.json",
+ "n_object_unquoted_key.json",
+ "n_object_unterminated-value.json",
+ "n_object_with_single_string.json",
+ "n_object_with_trailing_garbage.json",
+ "n_single_space.json",
+ "n_string_1_surrogate_then_escape.json",
+ "n_string_1_surrogate_then_escape_u1.json",
+ "n_string_1_surrogate_then_escape_u1x.json",
+ "n_string_1_surrogate_then_escape_u.json",
+ "n_string_accentuated_char_no_quotes.json",
+ "n_string_backslash_00.json",
+ "n_string_escaped_backslash_bad.json",
+ "n_string_escaped_ctrl_char_tab.json",
+ "n_string_escaped_emoji.json",
+ "n_string_escape_x.json",
+ "n_string_incomplete_escaped_character.json",
+ "n_string_incomplete_escape.json",
+ "n_string_incomplete_surrogate_escape_invalid.json",
+ "n_string_incomplete_surrogate.json",
+ "n_string_invalid_backslash_esc.json",
+ "n_string_invalid_unicode_escape.json",
+ "n_string_invalid_utf8_after_escape.json",
+ "n_string_invalid-utf-8-in-escape.json",
+ "n_string_leading_uescaped_thinspace.json",
+ "n_string_no_quotes_with_bad_escape.json",
+ "n_string_single_doublequote.json",
+ "n_string_single_quote.json",
+ "n_string_single_string_no_double_quotes.json",
+ "n_string_start_escape_unclosed.json",
+ "n_string_unescaped_crtl_char.json",
+ "n_string_unescaped_newline.json",
+ "n_string_unescaped_tab.json",
+ "n_string_unicode_CapitalU.json",
+ "n_string_with_trailing_garbage.json",
+ // "n_structure_100000_opening_arrays.json",
+ "n_structure_angle_bracket_..json",
+ "n_structure_angle_bracket_null.json",
+ "n_structure_array_trailing_garbage.json",
+ "n_structure_array_with_extra_array_close.json",
+ "n_structure_array_with_unclosed_string.json",
+ "n_structure_ascii-unicode-identifier.json",
+ "n_structure_capitalized_True.json",
+ "n_structure_close_unopened_array.json",
+ "n_structure_comma_instead_of_closing_brace.json",
+ "n_structure_double_array.json",
+ "n_structure_end_array.json",
+ "n_structure_incomplete_UTF8_BOM.json",
+ "n_structure_lone-invalid-utf-8.json",
+ "n_structure_lone-open-bracket.json",
+ "n_structure_no_data.json",
+ "n_structure_null-byte-outside-string.json",
+ "n_structure_number_with_trailing_garbage.json",
+ "n_structure_object_followed_by_closing_object.json",
+ "n_structure_object_unclosed_no_value.json",
+ "n_structure_object_with_comment.json",
+ "n_structure_object_with_trailing_garbage.json",
+ "n_structure_open_array_apostrophe.json",
+ "n_structure_open_array_comma.json",
+ // "n_structure_open_array_object.json",
+ "n_structure_open_array_open_object.json",
+ "n_structure_open_array_open_string.json",
+ "n_structure_open_array_string.json",
+ "n_structure_open_object_close_array.json",
+ "n_structure_open_object_comma.json",
+ "n_structure_open_object.json",
+ "n_structure_open_object_open_array.json",
+ "n_structure_open_object_open_string.json",
+ "n_structure_open_object_string_with_apostrophes.json",
+ "n_structure_open_open.json",
+ "n_structure_single_eacute.json",
+ "n_structure_single_star.json",
+ "n_structure_trailing_#.json",
+ "n_structure_U+2060_word_joined.json",
+ "n_structure_uescaped_LF_before_string.json",
+ "n_structure_unclosed_array.json",
+ "n_structure_unclosed_array_partial_null.json",
+ "n_structure_unclosed_array_unfinished_false.json",
+ "n_structure_unclosed_array_unfinished_true.json",
+ "n_structure_unclosed_object.json",
+ "n_structure_unicode-identifier.json",
+ "n_structure_UTF8_BOM_no_data.json",
+ "n_structure_whitespace_formfeed.json",
+ "n_structure_whitespace_U+2060_word_joiner.json"
+};
+
+std::vector<const char*> test_files_pass = {
+ "y_array_arraysWithSpaces.json",
+ "y_array_empty.json",
+ "y_array_empty-string.json",
+ "y_array_ending_with_newline.json",
+ "y_array_false.json",
+ "y_array_heterogeneous.json",
+ "y_array_null.json",
+ "y_array_with_1_and_newline.json",
+ "y_array_with_leading_space.json",
+ "y_array_with_several_null.json",
+ "y_array_with_trailing_space.json",
+ "y_number_0e+1.json",
+ "y_number_0e1.json",
+ "y_number_after_space.json",
+ "y_number_double_close_to_zero.json",
+ "y_number_int_with_exp.json",
+ "y_number.json",
+ "y_number_minus_zero.json",
+ "y_number_negative_int.json",
+ "y_number_negative_one.json",
+ "y_number_negative_zero.json",
+ "y_number_real_capital_e.json",
+ "y_number_real_capital_e_neg_exp.json",
+ "y_number_real_capital_e_pos_exp.json",
+ "y_number_real_exponent.json",
+ "y_number_real_fraction_exponent.json",
+ "y_number_real_neg_exp.json",
+ "y_number_real_pos_exponent.json",
+ "y_number_simple_int.json",
+ "y_number_simple_real.json",
+ "y_object_basic.json",
+ "y_object_duplicated_key_and_value.json",
+ "y_object_duplicated_key.json",
+ "y_object_empty.json",
+ "y_object_empty_key.json",
+ // "y_object_escaped_null_in_key.json",
+ "y_object_extreme_numbers.json",
+ "y_object.json",
+ "y_object_long_strings.json",
+ "y_object_simple.json",
+ // "y_object_string_unicode.json",
+ "y_object_with_newlines.json",
+ // "y_string_1_2_3_bytes_UTF-8_sequences.json",
+ // "y_string_accepted_surrogate_pair.json",
+ // "y_string_accepted_surrogate_pairs.json",
+ "y_string_allowed_escapes.json",
+ "y_string_backslash_and_u_escaped_zero.json",
+ "y_string_backslash_doublequotes.json",
+ "y_string_comments.json",
+ "y_string_double_escape_a.json",
+ "y_string_double_escape_n.json",
+ // "y_string_escaped_control_character.json",
+ // "y_string_escaped_noncharacter.json",
+ "y_string_in_array.json",
+ "y_string_in_array_with_leading_space.json",
+ // "y_string_last_surrogates_1_and_2.json",
+ // "y_string_nbsp_uescaped.json",
+ "y_string_nonCharacterInUTF-8_U+10FFFF.json",
+ "y_string_nonCharacterInUTF-8_U+FFFF.json",
+ // "y_string_null_escape.json",
+ // "y_string_one-byte-utf-8.json",
+ "y_string_pi.json",
+ "y_string_reservedCharacterInUTF-8_U+1BFFF.json",
+ "y_string_simple_ascii.json",
+ // "y_string_space.json",
+ // "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json",
+ // "y_string_three-byte-utf-8.json",
+ // "y_string_two-byte-utf-8.json",
+ "y_string_u+2028_line_sep.json",
+ "y_string_u+2029_par_sep.json",
+ // "y_string_uescaped_newline.json",
+ // "y_string_uEscape.json",
+ "y_string_unescaped_char_delete.json",
+ "y_string_unicode_2.json",
+ // "y_string_unicodeEscapedBackslash.json",
+ // "y_string_unicode_escaped_double_quote.json",
+ // "y_string_unicode.json",
+ // "y_string_unicode_U+10FFFE_nonchar.json",
+ // "y_string_unicode_U+1FFFE_nonchar.json",
+ // "y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json",
+ // "y_string_unicode_U+2064_invisible_plus.json",
+ // "y_string_unicode_U+FDD0_nonchar.json",
+ // "y_string_unicode_U+FFFE_nonchar.json",
+ "y_string_utf8.json",
+ "y_string_with_del_character.json",
+ // "y_structure_lonely_false.json",
+ // "y_structure_lonely_int.json",
+ // "y_structure_lonely_negative_real.json",
+ // "y_structure_lonely_null.json",
+ // "y_structure_lonely_string.json",
+ // "y_structure_lonely_true.json",
+ // "y_structure_string_empty.json",
+ "y_structure_trailing_newline.json",
+ "y_structure_true_in_array.json",
+ "y_structure_whitespace_array.json",
+};
+
+std::string load_file(const std::string& file_name)
+{
+ std::string file_path = std::string(SRCDIR) + "/test/json/validation/" + file_name;
+ std::ifstream f(file_path);
+ std::stringstream buffer;
+ buffer << f.rdbuf();
+ return buffer.str();
+}
+
+void test_pass()
+{
+ orcus::json_handler hdl;
+
+ for (const char* test_file_name : test_files_pass)
+ {
+ std::string content = load_file(test_file_name);
+ std::cout << test_file_name << std::endl;
+ try
+ {
+ orcus::json_parser<orcus::json_handler> parser(content, hdl);
+ parser.parse();
+ }
+ catch (const orcus::parse_error& e)
+ {
+ std::cout << e.what() << std::endl;
+ std::cout << orcus::create_parse_error_output(content, e.offset()) << std::endl;
+ assert(false);
+ }
+ }
+}
+
+void test_fail()
+{
+ orcus::json_handler hdl;
+
+ for (const char* test_file_name : test_files_failed)
+ {
+ std::string content = load_file(test_file_name);
+ std::cout << test_file_name << std::endl;
+ bool failed = false;
+ try {
+ orcus::json_parser<orcus::json_handler> parser(content, hdl);
+ parser.parse();
+ }
+ catch (const orcus::parse_error&)
+ {
+ failed = true;
+ }
+
+ if (!failed)
+ {
+ std::cout << "invalid json string has been parsed as valid: content='" << content << "'" << std::endl;
+ assert(false);
+ }
+ }
+}
+
+void test_indeterminate()
+{
+ orcus::json_handler hdl;
+
+ for (const char* test_file_name : test_files_indeterminate)
+ {
+ std::string content = load_file(test_file_name);
+ std::cout << test_file_name << std::endl;
+ try {
+ orcus::json_parser<orcus::json_handler> parser(content, hdl);
+ parser.parse();
+ }
+ catch (const orcus::parse_error&)
+ {
+ }
+
+ }
+}
+
+}
+
+int main()
+{
+ test_pass();
+ test_fail();
+ test_indeterminate();
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_test_numeric.cpp b/src/parser/parser_test_numeric.cpp
new file mode 100644
index 0000000..b16ed9a
--- /dev/null
+++ b/src/parser/parser_test_numeric.cpp
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "numeric_parser.hpp"
+
+#include <cassert>
+#include <iostream>
+#include <vector>
+#include <limits>
+
+using namespace orcus;
+using std::cout;
+using std::endl;
+
+namespace {
+
+struct check
+{
+ std::string_view str;
+ double expected;
+};
+
+const double invalid = std::numeric_limits<double>::quiet_NaN();
+
+template<typename ParserT>
+bool run_checks(const std::vector<check>& checks)
+{
+ for (const check& c : checks)
+ {
+ ParserT parser(c.str.data(), c.str.data() + c.str.size());
+ double v = parser.parse();
+
+ if (std::isnan(c.expected))
+ {
+ if (!std::isnan(v))
+ {
+ cout << "'" << c.str << "' was expected to be invalid, but parser parsed as if it was valid." << endl;
+ return false;
+ }
+ }
+ else
+ {
+ if (v != c.expected)
+ {
+ cout << "'" << c.str << "' was expected to be parsed as (" << c.expected << "), but the parser parsed it as (" << v << ")" << endl;
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+}
+
+void test_generic_number_parsing()
+{
+ using parser_type = detail::numeric_parser<detail::generic_parser_trait>;
+
+ std::vector<check> checks = {
+ { "-6.e3", -6e3 },
+ { "true", invalid },
+ { "1", 1.0 },
+ { "1.0", 1.0 },
+ { "-1.0", -1.0 },
+ { "-01", -1.0 },
+ { "2e2", 200.0 },
+ { "1.2", 1.2 },
+ { "-0.0001", -0.0001 },
+ { "-0.0", 0.0 },
+ { "+.", invalid },
+ { "+e", invalid },
+ { "+e1", invalid },
+ { "+ ", invalid },
+ { "- ", invalid }
+ };
+
+ assert(run_checks<parser_type>(checks));
+}
+
+void test_json_number_parsing()
+{
+ using parser_type = detail::numeric_parser<detail::json_parser_trait>;
+
+ std::vector<check> checks = {
+ { "-01", invalid }, // Leading zeros are invalid.
+ };
+
+ assert(run_checks<parser_type>(checks));
+}
+
+int main()
+{
+ test_generic_number_parsing();
+ test_json_number_parsing();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_test_xml_validation.cpp b/src/parser/parser_test_xml_validation.cpp
new file mode 100644
index 0000000..3be1804
--- /dev/null
+++ b/src/parser/parser_test_xml_validation.cpp
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/sax_parser.hpp>
+#include <orcus/stream.hpp>
+
+#include <iostream>
+#include <boost/range/iterator_range.hpp>
+
+#include "filesystem_env.hpp"
+
+void test_valid()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ struct _handler : public orcus::sax_handler {};
+
+ fs::path root_dir = fs::path{SRCDIR} / "test" / "xml" / "valids";
+
+ if (!fs::is_directory(root_dir))
+ return;
+
+ for (const fs::path& entry : boost::make_iterator_range(fs::directory_iterator{root_dir}, {}))
+ {
+ std::cout << "input file: " << entry << std::endl;
+
+ orcus::file_content content(entry.string());
+
+ _handler hdl;
+ orcus::sax_parser<_handler> parser(content.str(), hdl);
+
+ try
+ {
+ parser.parse();
+ }
+ catch (const orcus::malformed_xml_error& e)
+ {
+ std::cerr << orcus::create_parse_error_output(content.str(), e.offset()) << std::endl;
+ std::cerr << e.what() << std::endl;
+ assert(!"This was supposed to be a valid XML!");
+
+ }
+ }
+}
+
+void test_invalid()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ struct _handler : public orcus::sax_handler {};
+
+ fs::path root_dir = fs::path{SRCDIR} / "test" / "xml" / "invalids";
+
+ if (!fs::is_directory(root_dir))
+ return;
+
+ for (const fs::path& entry : boost::make_iterator_range(fs::directory_iterator{root_dir}, {}))
+ {
+ std::cout << "input file: " << entry << std::endl;
+
+ orcus::file_content content(entry.string());
+
+ _handler hdl;
+ orcus::sax_parser<_handler> parser(content.str(), hdl);
+
+ try
+ {
+ parser.parse();
+ assert(!"exception was expected, but one was not thrown.");
+ }
+ catch (const orcus::malformed_xml_error& e)
+ {
+ std::cerr << orcus::create_parse_error_output(content.str(), e.offset()) << std::endl;
+ std::cerr << e.what() << std::endl;
+ }
+ catch (...)
+ {
+ assert(!"wrong exception was thrown.");
+ }
+ }
+}
+
+int main()
+{
+ test_valid();
+ test_invalid();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_ns_parser_test.cpp b/src/parser/sax_ns_parser_test.cpp
new file mode 100644
index 0000000..eb7443f
--- /dev/null
+++ b/src/parser/sax_ns_parser_test.cpp
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/sax_ns_parser.hpp>
+#include <orcus/xml_namespace.hpp>
+
+#include <cstring>
+
+void test_handler()
+{
+ const char* test_code = "<?xml version=\"1.0\"?><root/>";
+ orcus::sax_ns_handler hdl;
+ orcus::xmlns_repository repo;
+ orcus::xmlns_context cxt = repo.create_context();
+
+ orcus::sax_ns_parser<orcus::sax_ns_handler> parser(test_code, cxt, hdl);
+ parser.parse();
+}
+
+/**
+ * Test for unqualified attribute NOT belonging to the default namespace,
+ * according to
+ * https://stackoverflow.com/questions/3312390/xml-default-namespaces-for-unqualified-attribute-names
+ */
+void test_default_attr_ns()
+{
+ const orcus::xmlns_id_t default_ns = "test:foo";
+
+ struct _handler : public orcus::sax_ns_handler
+ {
+ orcus::xmlns_id_t default_ns_expected;
+
+ void start_element(const orcus::sax_ns_parser_element& elem)
+ {
+ // All elements should belong to the default namespace.
+ assert(elem.ns == default_ns_expected);
+ }
+
+ void attribute(std::string_view /*name*/, std::string_view /*val*/) {}
+
+ void attribute(const orcus::sax_ns_parser_attribute& attr)
+ {
+ // Attribute's namespace should be empty.
+ assert(attr.ns == orcus::XMLNS_UNKNOWN_ID);
+ assert(attr.name == "attr");
+ assert(attr.value == "1");
+ }
+ };
+
+ const char* test_code = "<?xml version=\"1.0\"?><root xmlns='test:foo'><elem attr='1'/></root>";
+
+ const orcus::xmlns_id_t predefined[] = { default_ns, nullptr };
+
+ orcus::xmlns_repository repo;
+ repo.add_predefined_values(predefined);
+
+ orcus::xmlns_context cxt = repo.create_context();
+
+ _handler hdl;
+ hdl.default_ns_expected = default_ns;
+
+ orcus::sax_ns_parser<_handler> parser(test_code, cxt, hdl);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+ test_default_attr_ns();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_parser_base.cpp b/src/parser/sax_parser_base.cpp
new file mode 100644
index 0000000..58f750e
--- /dev/null
+++ b/src/parser/sax_parser_base.cpp
@@ -0,0 +1,421 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/sax_parser_base.hpp"
+
+#include "utf8.hpp"
+
+#include <cstring>
+#include <vector>
+#include <memory>
+
+#ifdef __ORCUS_CPU_FEATURES
+#include <immintrin.h>
+#endif
+
+namespace orcus { namespace sax {
+
+char decode_xml_encoded_char(const char* p, size_t n)
+{
+ if (n == 2)
+ {
+ if (!std::strncmp(p, "lt", n))
+ return '<';
+ else if (!std::strncmp(p, "gt", n))
+ return '>';
+ else
+ return '\0';
+ }
+ else if (n == 3)
+ {
+ if (!std::strncmp(p, "amp", n))
+ return '&';
+ else
+ return '\0';
+ }
+ else if (n == 4)
+ {
+ if (!std::strncmp(p, "apos", n))
+ return '\'';
+ else if (!std::strncmp(p, "quot", 4))
+ return '"';
+ else
+ return '\0';
+ }
+
+ return '\0';
+}
+
+std::string decode_xml_unicode_char(const char* p, size_t n)
+{
+ if (*p == '#' && n >= 2)
+ {
+ uint32_t point = 0;
+ if (p[1] == 'x')
+ {
+ if (n == 2)
+ throw orcus::xml_structure_error(
+ "invalid number of characters for hexadecimal unicode reference");
+
+ point = std::stoi(std::string(p + 2, n - 2), nullptr, 16);
+ }
+ else
+ point = std::stoi(std::string(p + 1, n - 1), nullptr, 10);
+
+ if (point < 0x80)
+ {
+ // is it really necessary to do the bit manipulation here?
+ std::string s(1, static_cast<char>(point & 0x7F));
+ return s;
+ }
+ else if (point < 0x0800)
+ {
+ std::string s(1, static_cast<char>((point >> 6 & 0x1F) | 0xC0));
+ s += static_cast<char>((point & 0x3F) | 0x80);
+ return s;
+ }
+ else if (point < 0x010000)
+ {
+ std::string s(1, static_cast<char>((point >> 12 & 0x0F) | 0xE0));
+ s += static_cast<char>((point >> 6 & 0x3F) | 0x80);
+ s += static_cast<char>((point & 0x3F) | 0x80);
+ return s;
+ }
+ else if (point < 0x110000)
+ {
+ std::string s(1, static_cast<char>((point >> 18 & 0x07) | 0xF0));
+ s += static_cast<char>((point >> 12 & 0x3F) | 0x80);
+ s += static_cast<char>((point >> 6 & 0x3F) | 0x80);
+ s += static_cast<char>((point & 0x3F) | 0x80);
+ return s;
+ }
+ else
+ {
+ // should not happen as that is not represented by utf-8
+ assert(false);
+ }
+ }
+
+ return std::string();
+}
+
+struct parser_base::impl
+{
+ std::vector<std::unique_ptr<cell_buffer>> m_cell_buffers;
+};
+
+parser_base::parser_base(const char* content, size_t size) :
+ ::orcus::parser_base(content, size),
+ mp_impl(std::make_unique<impl>()),
+ m_nest_level(0),
+ m_buffer_pos(0),
+ m_root_elem_open(true)
+{
+ mp_impl->m_cell_buffers.push_back(std::make_unique<cell_buffer>());
+}
+
+parser_base::~parser_base() {}
+
+void parser_base::inc_buffer_pos()
+{
+ ++m_buffer_pos;
+ if (m_buffer_pos == mp_impl->m_cell_buffers.size())
+ mp_impl->m_cell_buffers.push_back(std::make_unique<cell_buffer>());
+}
+
+cell_buffer& parser_base::get_cell_buffer()
+{
+ return *mp_impl->m_cell_buffers[m_buffer_pos];
+}
+
+void parser_base::comment()
+{
+ // Parse until we reach '-->'.
+ size_t len = available_size();
+ assert(len > 3);
+ char c = cur_char();
+ size_t i = 0;
+ bool hyphen = false;
+ for (; i < len; ++i, c = next_and_char())
+ {
+ if (c == '-')
+ {
+ if (!hyphen)
+ // first hyphen.
+ hyphen = true;
+ else
+ // second hyphen.
+ break;
+ }
+ else
+ hyphen = false;
+ }
+
+ if (len - i < 2 || next_and_char() != '>')
+ throw malformed_xml_error(
+ "'--' should not occur in comment other than in the closing tag.", offset());
+
+ next();
+}
+
+void parser_base::expects_next(const char* p, size_t n)
+{
+ if (available_size() < n+1)
+ throw malformed_xml_error(
+ "not enough stream left to check for an expected string segment.", offset());
+
+ const char* p0 = p;
+ const char* p_end = p + n;
+ char c = next_and_char();
+ for (; p != p_end; ++p, c = next_and_char())
+ {
+ if (c == *p)
+ continue;
+
+ std::ostringstream os;
+ os << "'" << std::string(p0, n) << "' was expected, but not found.";
+ throw malformed_xml_error(os.str(), offset());
+ }
+}
+
+void parser_base::parse_encoded_char(cell_buffer& buf)
+{
+ assert(cur_char() == '&');
+ next();
+ const char* p0 = mp_char;
+ for (; has_char(); next())
+ {
+ if (cur_char() != ';')
+ continue;
+
+ size_t n = mp_char - p0;
+ if (!n)
+ throw malformed_xml_error("empty encoded character.", offset());
+
+#if ORCUS_DEBUG_SAX_PARSER
+ cout << "sax_parser::parse_encoded_char: raw='" << std::string(p0, n) << "'" << endl;
+#endif
+
+ char c = decode_xml_encoded_char(p0, n);
+ if (c)
+ buf.append(&c, 1);
+ else
+ {
+ std::string utf8 = decode_xml_unicode_char(p0, n);
+
+ if (!utf8.empty())
+ {
+ buf.append(utf8.data(), utf8.size());
+ c = '1'; // just to avoid hitting the !c case below
+ }
+ }
+
+ // Move to the character past ';' before returning to the parent call.
+ next();
+
+ if (!c)
+ {
+#if ORCUS_DEBUG_SAX_PARSER
+ cout << "sax_parser::parse_encoded_char: not a known encoding name. Use the original." << endl;
+#endif
+ // Unexpected encoding name. Use the original text.
+ buf.append(p0, mp_char-p0);
+ }
+
+ return;
+ }
+
+ throw malformed_xml_error(
+ "error parsing encoded character: terminating character is not found.", offset());
+}
+
+void parser_base::value_with_encoded_char(cell_buffer& buf, std::string_view& str, char quote_char)
+{
+ assert(cur_char() == '&');
+ parse_encoded_char(buf);
+
+ const char* p0 = mp_char;
+
+ while (has_char())
+ {
+ if (cur_char() == '&')
+ {
+ if (mp_char > p0)
+ buf.append(p0, mp_char-p0);
+
+ parse_encoded_char(buf);
+ p0 = mp_char;
+ }
+
+ if (cur_char() == quote_char)
+ break;
+
+ if (cur_char() != '&')
+ next();
+ }
+
+ if (mp_char > p0)
+ buf.append(p0, mp_char-p0);
+
+ if (!buf.empty())
+ str = buf.str();
+
+ // Skip the closing quote.
+ assert(!has_char() || cur_char() == quote_char);
+ if (has_char())
+ next();
+}
+
+bool parser_base::value(std::string_view& str, bool decode)
+{
+ char c = cur_char_checked();
+ if (c != '"' && c != '\'')
+ throw malformed_xml_error("value must be quoted", offset());
+
+ char quote_char = c;
+
+ c = next_char_checked();
+
+ const char* p0 = mp_char;
+ for (; c != quote_char; c = next_char_checked())
+ {
+ if (decode && c == '&')
+ {
+ // This value contains one or more encoded characters.
+ cell_buffer& buf = get_cell_buffer();
+ buf.reset();
+ buf.append(p0, mp_char-p0);
+ value_with_encoded_char(buf, str, quote_char);
+ return true;
+ }
+ }
+
+ str = std::string_view(p0, mp_char-p0);
+
+ // Skip the closing quote.
+ next();
+
+ return false;
+}
+
+void parser_base::name(std::string_view& str)
+{
+ const char* p0 = mp_char;
+ mp_char = parse_utf8_xml_name_start_char(mp_char, mp_end);
+ if (mp_char == p0)
+ {
+ ::std::ostringstream os;
+ os << "name must begin with an alphabet, but got this instead '" << cur_char() << "'";
+ throw malformed_xml_error(os.str(), offset());
+ }
+
+#if defined(__ORCUS_CPU_FEATURES) && defined(__SSE4_2__)
+
+ const __m128i match = _mm_loadu_si128((const __m128i*)"azAZ09--__..");
+ const int mode = _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY;
+
+ size_t n_total = available_size();
+
+ while (n_total)
+ {
+ __m128i char_block = _mm_loadu_si128((const __m128i*)mp_char);
+
+ int n = std::min<size_t>(16u, n_total);
+ int r = _mm_cmpestri(match, 12, char_block, n, mode);
+ mp_char += r; // Move the current char position.
+ n_total -= r;
+
+ if (r < 16 && n_total)
+ {
+ // There is a character that does not match the SSE-based ASCII-only check.
+ // It may either by an ascii character that is not allowed, in which case stop,
+ // or it may possibly be an allowed utf-8 character, in which case move over it
+ // using the slow function.
+
+ const char* p = parse_utf8_xml_name_char(mp_char, mp_end);
+ if (p == mp_char)
+ break;
+
+ n_total -= p - mp_char;
+ mp_char = p;
+ }
+
+ }
+ cur_char_checked(); // check end of xml stream
+
+#else
+ for(;;)
+ {
+ cur_char_checked(); // check end of xml stream
+ const char* p = parse_utf8_xml_name_char(mp_char, mp_end);
+
+ if (p == mp_char)
+ break;
+
+ mp_char = p;
+ }
+#endif
+
+ str = std::string_view(p0, mp_char-p0);
+}
+
+void parser_base::element_name(parser_element& elem, std::ptrdiff_t begin_pos)
+{
+ elem.begin_pos = begin_pos;
+ name(elem.name);
+ if (cur_char() == ':')
+ {
+ elem.ns = elem.name;
+ next_check();
+ name(elem.name);
+ }
+}
+
+void parser_base::attribute_name(std::string_view& attr_ns, std::string_view& attr_name)
+{
+ name(attr_name);
+ if (cur_char() == ':')
+ {
+ // Attribute name is namespaced.
+ attr_ns = attr_name;
+ next_check();
+ name(attr_name);
+ }
+}
+
+void parser_base::characters_with_encoded_char(cell_buffer& buf)
+{
+ assert(cur_char() == '&');
+ parse_encoded_char(buf);
+
+ const char* p0 = mp_char;
+
+ while (has_char())
+ {
+ if (cur_char() == '&')
+ {
+ if (mp_char > p0)
+ buf.append(p0, mp_char-p0);
+
+ parse_encoded_char(buf);
+ p0 = mp_char;
+ }
+
+ if (cur_char() == '<')
+ break;
+
+ if (cur_char() != '&')
+ next();
+ }
+
+ if (mp_char > p0)
+ buf.append(p0, mp_char-p0);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_parser_test.cpp b/src/parser/sax_parser_test.cpp
new file mode 100644
index 0000000..ec8b1f1
--- /dev/null
+++ b/src/parser/sax_parser_test.cpp
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/sax_parser.hpp>
+#include <cstring>
+
+using namespace std;
+
+void test_handler()
+{
+ const char* test_code = "<?xml version=\"1.0\"?><root/>";
+
+ orcus::sax_handler hdl;
+ orcus::sax_parser<orcus::sax_handler> parser(test_code, hdl);
+ parser.parse();
+}
+
+void test_attr_equal_with_whitespace()
+{
+ struct _handler : public orcus::sax_handler {};
+
+ const char* content =
+ "<?xml version=\"1.0\"?>"
+ "<root attr1='some value' attr2 = \"some value\"/>"
+ ;
+
+ _handler hdl;
+ orcus::sax_parser<_handler> parser(content, hdl);
+ parser.parse();
+}
+
+void test_attr_with_encoded_chars_single_quotes()
+{
+ struct _handler : public orcus::sax_handler
+ {
+ void attribute(const orcus::sax::parser_attribute& attr)
+ {
+ if (attr.name == "attr1")
+ assert(attr.value == "'some value'");
+ }
+ };
+
+ const char* content =
+ "<?xml version=\"1.0\"?>"
+ "<root attr1='&apos;some value&apos;'/>"
+ ;
+
+ _handler hdl;
+ orcus::sax_parser<_handler> parser(content, hdl);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+ test_attr_equal_with_whitespace();
+ test_attr_with_encoded_chars_single_quotes();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_token_parser.cpp b/src/parser/sax_token_parser.cpp
new file mode 100644
index 0000000..fdf80c6
--- /dev/null
+++ b/src/parser/sax_token_parser.cpp
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/sax_token_parser.hpp"
+#include "orcus/tokens.hpp"
+
+#include <mdds/sorted_string_map.hpp>
+#include <cctype>
+
+namespace orcus {
+
+namespace {
+
+enum class decl_attr_type { unknown, version, encoding, standalone };
+
+namespace decl_attr {
+
+using map_type = mdds::sorted_string_map<decl_attr_type, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "encoding", decl_attr_type::encoding },
+ { "standalone", decl_attr_type::standalone },
+ { "version", decl_attr_type::version },
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), decl_attr_type::unknown);
+ return mt;
+}
+
+} // namespace decl_attr
+
+}
+
+sax_token_handler_wrapper_base::sax_token_handler_wrapper_base(const tokens& _tokens) :
+ m_tokens(_tokens) {}
+
+xml_token_t sax_token_handler_wrapper_base::tokenize(std::string_view name) const
+{
+ xml_token_t token = XML_UNKNOWN_TOKEN;
+ if (!name.empty())
+ token = m_tokens.get_token(name);
+ return token;
+}
+
+void sax_token_handler_wrapper_base::set_element(const sax_ns_parser_element& elem)
+{
+ m_elem.ns = elem.ns;
+ m_elem.name = tokenize(elem.name);
+ m_elem.raw_name = elem.name;
+}
+
+void sax_token_handler_wrapper_base::attribute(std::string_view name, std::string_view val)
+{
+ decl_attr_type dat = decl_attr::get().find(name);
+
+ switch (dat)
+ {
+ case decl_attr_type::version:
+ {
+ const char* p = val.data();
+ const char* p_end = p + val.size();
+
+ long v;
+ const char* endptr = parse_integer(p, p_end, v);
+
+ if (!endptr || endptr >= p_end || *endptr != '.')
+ break;
+
+ m_declaration.version_major = v;
+ p = endptr + 1;
+
+ endptr = parse_integer(p, p_end, v);
+
+ if (!endptr || endptr > p_end)
+ break;
+
+ m_declaration.version_minor = v;
+ break;
+ }
+ case decl_attr_type::encoding:
+ {
+ m_declaration.encoding = to_character_set(val);
+ break;
+ }
+ case decl_attr_type::standalone:
+ m_declaration.standalone = (val == "yes") ? true : false;
+ break;
+ default:
+ ;
+ }
+}
+
+void sax_token_handler_wrapper_base::attribute(const sax_ns_parser_attribute& attr)
+{
+ m_elem.attrs.push_back(
+ xml_token_attr_t(
+ attr.ns, tokenize(attr.name), attr.name,
+ attr.value, attr.transient));
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_token_parser_test.cpp b/src/parser/sax_token_parser_test.cpp
new file mode 100644
index 0000000..d473196
--- /dev/null
+++ b/src/parser/sax_token_parser_test.cpp
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/sax_token_parser.hpp"
+#include "orcus/tokens.hpp"
+#include "orcus/xml_namespace.hpp"
+
+#include <cstring>
+
+using namespace std;
+using namespace orcus;
+
+void test_handler()
+{
+ const char* test_code = "<?xml version=\"1.0\"?><root/>";
+
+ orcus::sax_token_handler hdl;
+ orcus::tokens token_map(nullptr, 0);
+ orcus::xmlns_repository repo;
+ orcus::xmlns_context cxt = repo.create_context();
+ orcus::sax_token_parser<orcus::sax_token_handler> parser(test_code, token_map, cxt, hdl);
+ parser.parse();
+}
+
+void test_sax_token_parser_1()
+{
+ // Test XML content.
+ const char* content = "<?xml version=\"1.0\"?><root><andy/><bruce/><charlie/><david/><edward/><frank/></root>";
+
+ // Array of tokens to define for this test.
+ const char* token_names[] = {
+ "??", // 0
+ "andy", // 1
+ "bruce", // 2
+ "charlie", // 3
+ "david", // 4
+ "edward" // 5
+ };
+
+ size_t token_count = std::size(token_names);
+
+ // Token constants.
+ const xml_token_t op_andy = 1;
+ const xml_token_t op_bruce = 2;
+ const xml_token_t op_charlie = 3;
+ const xml_token_t op_david = 4;
+ const xml_token_t op_edward = 5;
+
+ struct check
+ {
+ const char* raw_name;
+ xml_token_t token;
+ bool start_element;
+ };
+
+ // Expected outcome.
+ const check checks[] = {
+ { "root", XML_UNKNOWN_TOKEN, true }, // name not on the master token list.
+ { "andy", op_andy, true },
+ { "andy", op_andy, false },
+ { "bruce", op_bruce, true },
+ { "bruce", op_bruce, false },
+ { "charlie", op_charlie, true },
+ { "charlie", op_charlie, false },
+ { "david", op_david, true },
+ { "david", op_david, false },
+ { "edward", op_edward, true },
+ { "edward", op_edward, false },
+ { "frank", XML_UNKNOWN_TOKEN, true }, // name not on the master token list.
+ { "frank", XML_UNKNOWN_TOKEN, false }, // name not on the master token list.
+ { "root", XML_UNKNOWN_TOKEN, false }, // name not on the master token list.
+ };
+
+ class handler
+ {
+ const check* mp_head;
+ const check* mp_check;
+ public:
+ handler(const check* p) : mp_head(p), mp_check(p) {}
+
+ void declaration(const orcus::xml_declaration_t&) {}
+
+ void start_element(const orcus::xml_token_element_t& elem)
+ {
+ assert(std::string_view(mp_check->raw_name) == elem.raw_name);
+ assert(mp_check->token == elem.name);
+ assert(mp_check->start_element);
+ ++mp_check;
+ }
+
+ void end_element(const orcus::xml_token_element_t& elem)
+ {
+ assert(std::string_view(mp_check->raw_name) == elem.raw_name);
+ assert(mp_check->token == elem.name);
+ assert(!mp_check->start_element);
+ ++mp_check;
+ }
+
+ void characters(std::string_view /*val*/, bool /*transient*/) {}
+
+ size_t get_token_count() const
+ {
+ return std::distance(mp_head, mp_check);
+ }
+ };
+
+ handler hdl(checks);
+ tokens token_map(token_names, token_count);
+ xmlns_repository ns_repo;
+ xmlns_context ns_cxt = ns_repo.create_context();
+ sax_token_parser<handler> parser(content, token_map, ns_cxt, hdl);
+ parser.parse();
+
+ assert(hdl.get_token_count() == std::size(checks));
+}
+
+void test_unicode_string()
+{
+ const char* content1 = "<?xml version=\"1.0\"?><root>&#x0021;</root>";
+ const char* content2 = "<?xml version=\"1.0\"?><root>&#x00B6;</root>";
+ const char* content3 = "<?xml version=\"1.0\"?><root>&#x20B9;</root>";
+
+ class handler
+ {
+ std::string_view str;
+ public:
+ handler(std::string_view _str):
+ str(_str)
+ {}
+
+ void declaration(const orcus::xml_declaration_t&) {}
+
+ void start_element(const orcus::xml_token_element_t& /*elem*/)
+ {
+ }
+
+ void end_element(const orcus::xml_token_element_t& /*elem*/)
+ {
+ }
+
+ void characters(std::string_view val, bool /*transient*/)
+ {
+ std::cout << "charachters:" << std::endl;
+ std::cout << val << std::endl;
+ assert(val == str);
+ }
+ };
+
+ const char* token_names[] = {
+ "???",
+ };
+ size_t token_count = std::size(token_names);
+
+ tokens token_map(token_names, token_count);
+ xmlns_repository ns_repo;
+ xmlns_context ns_cxt = ns_repo.create_context();
+ handler hdl(u8"\u0021");
+ sax_token_parser<handler> parser1(content1, token_map, ns_cxt, hdl);
+ parser1.parse();
+ hdl = handler(u8"\u00B6");
+ sax_token_parser<handler> parser2(content2, token_map, ns_cxt, hdl);
+ parser2.parse();
+ hdl = handler(u8"\u20B9");
+ sax_token_parser<handler> parser3(content3, token_map, ns_cxt, hdl);
+ parser3.parse();
+}
+
+void test_declaration()
+{
+ class handler
+ {
+ xml_declaration_t& m_decl;
+ public:
+ handler(xml_declaration_t& decl) : m_decl(decl) {}
+
+ void declaration(const xml_declaration_t& decl)
+ {
+ m_decl = decl;
+ }
+
+ void start_element(const xml_token_element_t&) {}
+ void end_element(const xml_token_element_t&) {}
+ void characters(std::string_view, bool) {}
+ };
+
+ std::vector<const char*> token_names = {};
+ tokens token_map(token_names.data(), token_names.size());
+ xmlns_repository ns_repo;
+ xmlns_context ns_cxt = ns_repo.create_context();
+
+ struct check
+ {
+ std::string content;
+ xml_declaration_t decl;
+ };
+
+ std::vector<check> checks =
+ {
+ {
+ "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?><root/>",
+ { 1, 0, character_set_t::utf_8, false }
+ },
+ {
+ "<?xml version=\"1.1\" encoding=\"windows-1253\" standalone=\"yes\"?><root/>",
+ { 1, 1, character_set_t::windows_1253, true }
+ },
+ {
+ "<?xml version=\"2.0\" encoding=\"US-ASCII\" standalone=\"yes\"?><root/>",
+ { 2, 0, character_set_t::us_ascii, true }
+ },
+ };
+
+ for (const check& c : checks)
+ {
+ xml_declaration_t decl;
+ handler hdl(decl);
+ sax_token_parser<handler> parser(c.content, token_map, ns_cxt, hdl);
+ parser.parse();
+
+ assert(decl == c.decl);
+ }
+}
+
+int main()
+{
+ test_handler();
+ test_sax_token_parser_1();
+ test_unicode_string();
+ test_declaration();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_token_parser_thread.cpp b/src/parser/sax_token_parser_thread.cpp
new file mode 100644
index 0000000..3d7b16b
--- /dev/null
+++ b/src/parser/sax_token_parser_thread.cpp
@@ -0,0 +1,204 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/sax_token_parser_thread.hpp"
+#include "orcus/sax_token_parser.hpp"
+#include "orcus/string_pool.hpp"
+#include "orcus/detail/parser_token_buffer.hpp"
+#include "orcus/tokens.hpp"
+#include "orcus/xml_namespace.hpp"
+
+#include <limits>
+#include <iostream>
+
+namespace orcus { namespace sax {
+
+parse_token::parse_token() : type(parse_token_t::unknown) {}
+
+parse_token::parse_token(std::string_view _characters) :
+ type(parse_token_t::characters),
+ value(_characters)
+{
+}
+
+parse_token::parse_token(parse_token_t _type, const xml_token_element_t* _element) :
+ type(_type), value(_element)
+{
+}
+
+parse_token::parse_token(std::string_view msg, std::ptrdiff_t offset) :
+ type(parse_token_t::parse_error),
+ value(parse_error_value_t{msg, offset})
+{
+}
+
+parse_token::parse_token(const parse_token& other) :
+ type(other.type), value(other.value)
+{
+}
+
+bool parse_token::operator== (const parse_token& other) const
+{
+ return type == other.type && value == other.value;
+}
+
+bool parse_token::operator!= (const parse_token& other) const
+{
+ return !operator==(other);
+}
+
+struct parser_thread::impl
+{
+ orcus::detail::thread::parser_token_buffer<parse_tokens_t> m_token_buffer;
+ string_pool m_pool;
+ std::vector<std::unique_ptr<xml_token_element_t>> m_element_store;
+
+ parse_tokens_t m_parser_tokens; // token buffer for the parser thread.
+
+ const char* mp_char;
+ size_t m_size;
+ const tokens& m_tokens;
+ xmlns_context& m_ns_cxt;
+
+ impl(const char* p, size_t n, const tokens& tks, xmlns_context& ns_cxt, size_t min_token_size, size_t max_token_size) :
+ m_token_buffer(min_token_size, max_token_size),
+ mp_char(p), m_size(n), m_tokens(tks), m_ns_cxt(ns_cxt)
+ {
+ }
+
+ void check_and_notify()
+ {
+ m_token_buffer.check_and_notify(m_parser_tokens);
+ }
+
+ void notify_and_finish()
+ {
+ m_token_buffer.notify_and_finish(m_parser_tokens);
+ }
+
+ void abort()
+ {
+ m_token_buffer.abort();
+ }
+
+ void declaration(const orcus::xml_declaration_t& /*decl*/)
+ {
+ }
+
+ void start_element(const orcus::xml_token_element_t& elem)
+ {
+ m_element_store.emplace_back(std::make_unique<orcus::xml_token_element_t>(elem));
+ orcus::xml_token_element_t& this_elem = *m_element_store.back();
+
+ // Go through all attributes and intern transient strings.
+ std::for_each(this_elem.attrs.begin(), this_elem.attrs.end(),
+ [&](xml_token_attr_t& attr)
+ {
+ if (attr.transient)
+ {
+ attr.value = m_pool.intern(attr.value).first;
+ attr.transient = false;
+ }
+ }
+ );
+
+ m_parser_tokens.emplace_back(parse_token_t::start_element, m_element_store.back().get());
+ check_and_notify();
+ }
+
+ void end_element(const orcus::xml_token_element_t& elem)
+ {
+ assert(elem.attrs.empty());
+
+ m_element_store.emplace_back(std::make_unique<orcus::xml_token_element_t>(elem));
+ m_parser_tokens.emplace_back(parse_token_t::end_element, m_element_store.back().get());
+ check_and_notify();
+ }
+
+ void characters(std::string_view val, bool transient)
+ {
+ if (transient)
+ m_parser_tokens.emplace_back(m_pool.intern(val).first);
+ else
+ m_parser_tokens.emplace_back(val);
+
+ check_and_notify();
+ }
+
+ void start()
+ {
+ try
+ {
+ try
+ {
+ orcus::sax_token_parser<impl> parser({mp_char, m_size}, m_tokens, m_ns_cxt, *this);
+ parser.parse();
+ }
+ catch (const malformed_xml_error& e)
+ {
+ std::string_view s = m_pool.intern(e.what()).first;
+ m_parser_tokens.emplace_back(s, e.offset());
+ }
+
+ // TODO : add more exceptions that need to be tokenized and processed by the client thread.
+
+ notify_and_finish();
+ }
+ catch (const orcus::detail::parsing_aborted_error&)
+ {
+ // This is used only to abort the parsing thread prematurely.
+ }
+ }
+
+ bool next_tokens(parse_tokens_t& tokens)
+ {
+ return m_token_buffer.next_tokens(tokens);
+ }
+
+ void swap_string_pool(string_pool& pool)
+ {
+ m_pool.swap(pool);
+ }
+};
+
+parser_thread::parser_thread(
+ const char* p, size_t n, const orcus::tokens& tks, xmlns_context& ns_cxt, size_t min_token_size) :
+ mp_impl(std::make_unique<parser_thread::impl>(
+ p, n, tks, ns_cxt, min_token_size, std::numeric_limits<size_t>::max()/2)) {}
+
+parser_thread::parser_thread(
+ const char* p, size_t n, const orcus::tokens& tks, xmlns_context& ns_cxt, size_t min_token_size, size_t max_token_size) :
+ mp_impl(std::make_unique<parser_thread::impl>(
+ p, n, tks, ns_cxt, min_token_size, max_token_size)) {}
+
+parser_thread::~parser_thread()
+{
+}
+
+void parser_thread::start()
+{
+ mp_impl->start();
+}
+
+bool parser_thread::next_tokens(parse_tokens_t& tokens)
+{
+ return mp_impl->next_tokens(tokens);
+}
+
+void parser_thread::swap_string_pool(string_pool& pool)
+{
+ mp_impl->swap_string_pool(pool);
+}
+
+void parser_thread::abort()
+{
+ mp_impl->abort();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/stream.cpp b/src/parser/stream.cpp
new file mode 100644
index 0000000..c0bbb28
--- /dev/null
+++ b/src/parser/stream.cpp
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/stream.hpp>
+#include <orcus/exception.hpp>
+
+#include "utf8.hpp"
+
+#include <sstream>
+#include <fstream>
+#include <tuple>
+#include <cassert>
+#include <algorithm>
+#include <locale>
+#include <codecvt>
+#include <iostream>
+
+#include "filesystem_env.hpp"
+
+#include <boost/interprocess/file_mapping.hpp>
+#include <boost/interprocess/mapped_region.hpp>
+
+namespace bip = boost::interprocess;
+
+namespace orcus {
+
+namespace {
+
+enum class unicode_t
+{
+ unknown,
+ utf16_be,
+ utf16_le
+};
+
+unicode_t check_unicode_type(const char* p, size_t n)
+{
+ if (n > 2)
+ {
+ if (p[0] == '\xFE' && p[1] == '\xFF')
+ return unicode_t::utf16_be;
+
+ if (p[0] == '\xFF' && p[1] == '\xFE')
+ return unicode_t::utf16_le;
+ }
+
+ return unicode_t::unknown;
+}
+
+std::string convert_utf16_to_utf8(const char* p, size_t n, unicode_t ut)
+{
+ assert(ut == unicode_t::utf16_be || ut == unicode_t::utf16_le);
+
+ if (n & 0x01)
+ throw std::invalid_argument("size of a UTF-16 string must be divisible by 2.");
+
+ p += 2; // skip the BOM.
+
+ size_t n_buf = n / 2u - 1;
+ std::u16string buf(n_buf, 0);
+
+ switch (ut)
+ {
+ case unicode_t::utf16_be:
+ {
+ for (size_t i = 0; i < n_buf; ++i)
+ {
+ size_t offset = i * 2;
+ buf[i] = static_cast<char16_t>(p[offset+1] | p[offset] << 8);
+ }
+ break;
+ }
+ case unicode_t::utf16_le:
+ {
+ for (size_t i = 0; i < n_buf; ++i)
+ {
+ size_t offset = i * 2;
+ buf[i] = static_cast<char16_t>(p[offset] | p[offset+1]);
+ }
+ break;
+ }
+ default:
+ ;
+ }
+
+#if defined(_MSC_VER)
+ // char16_t does not work with MSVC just yet. This is a workaround. c.f.
+ // https://stackoverflow.com/questions/32055357/visual-studio-c-2015-stdcodecvt-with-char16-t-or-char32-t
+ const int16_t* pi16 = reinterpret_cast<const int16_t*>(buf.data());
+ const int16_t* pi16_end = pi16 + buf.size();
+ std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> conversion;
+ return conversion.to_bytes(pi16, pi16_end);
+#else
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conversion;
+ return conversion.to_bytes(buf);
+#endif
+}
+
+std::tuple<std::string_view, size_t, size_t> find_line_with_offset(std::string_view strm, std::ptrdiff_t offset)
+{
+ const char* p0 = strm.data();
+ const char* p_end = p0 + strm.size();
+ const char* p_offset = p0 + offset;
+
+ if (p_offset >= p_end)
+ {
+ std::ostringstream os;
+ os << "offset value of " << offset << " is out-of-bound for a stream of length " << strm.size();
+ throw std::invalid_argument(os.str());
+ }
+
+ // Determine the line number.
+ std::size_t line_num = 0;
+ for (const char* p = p0; p != p_offset; ++p)
+ {
+ if (*p == '\n')
+ ++line_num;
+ }
+
+ // Determine the beginning of the line.
+ const char* p_line_start = p_offset;
+
+ // if the error points at the new line character
+ // we have most likely an unterminated quote.
+ // Report the line with the actual error.
+ if (*p_offset == '\n' && offset > 0)
+ --p_line_start;
+
+ for (; p0 <= p_line_start; --p_line_start)
+ {
+ if (*p_line_start == '\n')
+ break;
+ }
+
+ ++p_line_start;
+ assert(p0 <= p_line_start);
+
+ // Determine the end of the line.
+ const char* p_line_end = p_offset;
+ for (; p_line_end < p_end; ++p_line_end)
+ {
+ if (*p_line_end == '\n')
+ // one character after the last character of the line.
+ break;
+ }
+
+ assert(p_line_start <= p_offset);
+ std::size_t offset_on_line = std::distance(p_line_start, p_offset);
+ std::string_view line(p_line_start, p_line_end - p_line_start);
+
+ return std::make_tuple(line, line_num, offset_on_line);
+}
+
+} // anonymous namespace
+
+struct file_content::impl
+{
+ boost::uintmax_t content_size;
+ bip::file_mapping mapped_file;
+ bip::mapped_region mapped_region;
+
+ std::string buffer; // its own buffer in case of stream conversion.
+
+ const char* content;
+
+ impl() : content_size(0), content(nullptr) {}
+
+ impl(std::string_view filepath) :
+ content_size(fs::file_size(std::string{filepath}.c_str())),
+ mapped_file(std::string{filepath}.c_str(), bip::read_only),
+ mapped_region(mapped_file, bip::read_only, 0, content_size),
+ content(nullptr)
+ {
+ content = static_cast<const char*>(mapped_region.get_address());
+ }
+};
+
+file_content::file_content() :
+ mp_impl(std::make_unique<impl>()) {}
+
+file_content::file_content(file_content&& other) = default;
+
+file_content::file_content(std::string_view filepath) :
+ mp_impl(std::make_unique<impl>(filepath)) {}
+
+file_content::~file_content() = default;
+
+const char* file_content::data() const
+{
+ return mp_impl->content;
+}
+
+size_t file_content::size() const
+{
+ return mp_impl->content_size;
+}
+
+bool file_content::empty() const
+{
+ return mp_impl->content_size == 0;
+}
+
+void file_content::swap(file_content& other)
+{
+ std::swap(mp_impl, other.mp_impl);
+}
+
+void file_content::load(std::string_view filepath)
+{
+ file_content tmp(filepath);
+ swap(tmp);
+}
+
+void file_content::convert_to_utf8()
+{
+ unicode_t ut = check_unicode_type(mp_impl->content, mp_impl->content_size);
+
+ switch (ut)
+ {
+ case unicode_t::utf16_be:
+ case unicode_t::utf16_le:
+ {
+ // Convert to utf-8 stream, and reset the content pointer and size.
+ mp_impl->buffer = convert_utf16_to_utf8(mp_impl->content, mp_impl->content_size, ut);
+ mp_impl->content = mp_impl->buffer.data();
+ mp_impl->content_size = mp_impl->buffer.size();
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+std::string_view file_content::str() const
+{
+ return std::string_view(mp_impl->content, mp_impl->content_size);
+}
+
+struct memory_content::impl
+{
+ std::string_view content;
+ std::string buffer; // its own buffer in case of stream conversion.
+
+ impl() {}
+ impl(std::string_view s) : content(s) {}
+};
+
+memory_content::memory_content() : mp_impl(std::make_unique<impl>()) {}
+
+memory_content::memory_content(std::string_view s) :
+ mp_impl(std::make_unique<impl>(s)) {}
+
+memory_content::memory_content(memory_content&& other) = default;
+memory_content::~memory_content() = default;
+
+const char* memory_content::data() const
+{
+ return mp_impl->content.data();
+}
+
+size_t memory_content::size() const
+{
+ return mp_impl->content.size();
+}
+
+bool memory_content::empty() const
+{
+ return mp_impl->content.empty();
+}
+
+void memory_content::swap(memory_content& other)
+{
+ std::swap(mp_impl, other.mp_impl);
+}
+
+void memory_content::convert_to_utf8()
+{
+ unicode_t ut = check_unicode_type(mp_impl->content.data(), mp_impl->content.size());
+
+ switch (ut)
+ {
+ case unicode_t::utf16_be:
+ case unicode_t::utf16_le:
+ {
+ // Convert to utf-8 stream, and reset the content pointer and size.
+ mp_impl->buffer = convert_utf16_to_utf8(mp_impl->content.data(), mp_impl->content.size(), ut);
+ mp_impl->content = mp_impl->buffer;
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+std::string_view memory_content::str() const
+{
+ return mp_impl->content;
+}
+
+line_with_offset::line_with_offset(std::string _line, std::size_t _line_number, std::size_t _offset_on_line) :
+ line(std::move(_line)),
+ line_number(_line_number),
+ offset_on_line(_offset_on_line)
+{}
+
+line_with_offset::line_with_offset(const line_with_offset& other) = default;
+line_with_offset::line_with_offset(line_with_offset&& other) = default;
+line_with_offset::~line_with_offset() = default;
+
+bool line_with_offset::operator== (const line_with_offset& other) const
+{
+ return line == other.line && line_number == other.line_number && offset_on_line == other.offset_on_line;
+}
+
+bool line_with_offset::operator!= (const line_with_offset& other) const
+{
+ return !operator==(other);
+}
+
+std::string create_parse_error_output(std::string_view strm, std::ptrdiff_t offset)
+{
+ if (strm.empty() || offset < 0)
+ return std::string();
+
+ const size_t max_line_length = 60;
+ offset = std::min<std::ptrdiff_t>(strm.size() - 1, offset);
+
+ auto line_info = find_line_with_offset(strm, offset);
+ std::string_view line = std::get<0>(line_info);
+ size_t line_num = std::get<1>(line_info);
+ size_t offset_on_line = std::get<2>(line_info);
+
+ if (offset_on_line < 30)
+ {
+ std::ostringstream os;
+ os << (line_num+1) << ":" << (offset_on_line+1) << ": ";
+ size_t line_num_width = os.str().size();
+
+ // Truncate line if it's too long.
+ if (line.size() > max_line_length)
+ line = std::string_view(line.data(), max_line_length);
+
+ os << line << std::endl;
+
+ for (size_t i = 0; i < (offset_on_line+line_num_width); ++i)
+ os << ' ';
+ os << '^';
+ return os.str();
+ }
+
+ // The error line is too long. Only show a segment of the line where the
+ // error occurred.
+
+ const size_t fixed_offset = 20;
+
+ size_t line_start = offset_on_line - fixed_offset;
+ size_t line_end = line_start + max_line_length;
+ if (line_end > line.size())
+ line_end = line.size();
+
+ size_t line_length = line_end - line_start;
+
+ line = std::string_view(line.data()+line_start, line_length);
+
+ std::ostringstream os;
+ os << line_num << ":" << (line_start+1) << ": ";
+ size_t line_num_width = os.str().size();
+
+ os << line << std::endl;
+
+ for (size_t i = 0; i < (fixed_offset+line_num_width); ++i)
+ os << ' ';
+ os << '^';
+
+ return os.str();
+}
+
+line_with_offset locate_line_with_offset(std::string_view strm, std::ptrdiff_t offset)
+{
+ auto line_info = find_line_with_offset(strm, offset);
+ std::string_view line = std::get<0>(line_info);
+ size_t line_num = std::get<1>(line_info);
+ size_t offset_on_line = std::get<2>(line_info);
+
+ return line_with_offset(std::string{line}, line_num, offset_on_line);
+}
+
+size_t locate_first_different_char(std::string_view left, std::string_view right)
+{
+ if (left.empty() || right.empty())
+ // If one of them is empty, then the first characters are considered
+ // different.
+ return 0;
+
+ size_t n = std::min(left.size(), right.size());
+ const char* p1 = left.data();
+ const char* p2 = right.data();
+ const char* p1_end = p1 + n;
+
+ for (; p1 != p1_end; ++p1, ++p2)
+ {
+ if (*p1 != *p2)
+ return std::distance(left.data(), p1);
+ }
+
+ return n;
+}
+
+std::size_t calc_logical_string_length(std::string_view s)
+{
+ std::size_t length = 0;
+
+ const char* p = s.data();
+ const char* p_end = p + s.size();
+
+ while (p < p_end)
+ {
+ ++length;
+
+ auto n_bytes = calc_utf8_byte_length(*p);
+ if (!n_bytes || n_bytes > 4)
+ {
+ std::ostringstream os;
+ os << "'" << s << "' contains invalid character at position " << std::distance(s.data(), p);
+ throw std::invalid_argument(os.str());
+ }
+
+ p += n_bytes;
+ }
+
+ if (p != p_end)
+ {
+ std::ostringstream os;
+ os << "last character of '" << s << "' ended prematurely";
+ throw std::invalid_argument(os.str());
+ }
+
+ return length;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/stream_test.cpp b/src/parser/stream_test.cpp
new file mode 100644
index 0000000..1a6e9fb
--- /dev/null
+++ b/src/parser/stream_test.cpp
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/stream.hpp"
+
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+using namespace std;
+using namespace orcus;
+
+void test_stream_create_error_output()
+{
+ test::stack_printer __sp__(__func__);
+
+ string output = create_parse_error_output("{}", 1);
+ cout << output << endl;
+ const char* expected = "1:2: {}\n ^";
+ assert(output == expected);
+}
+
+void test_stream_locate_first_different_char()
+{
+ test::stack_printer __sp__(__func__);
+
+ struct test_case
+ {
+ const char* left;
+ const char* right;
+ size_t expected;
+ };
+
+ std::vector<test_case> test_cases = {
+ { "", "a", 0 },
+ { "a", "", 0 },
+ { "", "", 0 },
+ { " ", "b", 0 },
+ { "abc", "abc", 3 },
+ { "abcd", "abce", 3 },
+ { "abc", "bbc", 0 },
+ { "abc", "acc", 1 },
+ };
+
+ for (const test_case& tc : test_cases)
+ {
+ size_t actual = locate_first_different_char(tc.left, tc.right);
+ assert(actual == tc.expected);
+ }
+}
+
+void test_stream_logical_string_length()
+{
+ test::stack_printer __sp__(__func__);
+
+ struct check
+ {
+ std::string_view value;
+ std::size_t length;
+ };
+
+ constexpr check checks[] = {
+ { "東京", 2 },
+ { "大阪は暑い", 5 },
+ { "New York", 8 },
+ { "日本は英語で言うとJapan", 14 },
+ { "fabriqué", 8 },
+ { "garçon", 6 },
+ { "вход", 4 },
+ { "выход", 5 },
+ { "помогите", 8 },
+ { "Nähe", 4 },
+ };
+
+ for (auto [value, expected_len] : checks)
+ {
+ std::size_t len = calc_logical_string_length(value);
+ std::cout << "'" << value << "' (length=" << len << ")" << std::endl;
+ assert(len == expected_len);
+ }
+}
+
+void test_stream_locate_line_with_offset()
+{
+ test::stack_printer __sp__(__func__);
+
+ std::string strm = "one\ntwo\nthree";
+
+ struct check
+ {
+ std::ptrdiff_t offset;
+ line_with_offset expected;
+ };
+
+ const std::vector<check> checks = {
+ { 0, { "one", 0, 0 } },
+ { 1, { "one", 0, 1 } },
+ { 2, { "one", 0, 2 } },
+ { 3, { "one", 0, 3 } }, // on line break
+ { 4, { "two", 1, 0 } },
+ { 5, { "two", 1, 1 } },
+ { 6, { "two", 1, 2 } },
+ { 7, { "two", 1, 3 } }, // on line break
+ { 8, { "three", 2, 0 } },
+ { 9, { "three", 2, 1 } },
+ { 10, { "three", 2, 2 } },
+ { 11, { "three", 2, 3 } },
+ { 12, { "three", 2, 4 } },
+ };
+
+ for (const auto& c : checks)
+ {
+ auto res = locate_line_with_offset(strm, c.offset);
+ assert(res == c.expected);
+ }
+
+ try
+ {
+ auto res = locate_line_with_offset(strm, strm.size());
+ assert(!"exception should have been thrown for out-of-bound offset!");
+ }
+ catch (const std::invalid_argument& e)
+ {
+ // expected
+ cout << "exception thrown as expected: '" << e.what() << "'" << endl;
+ }
+}
+
+int main()
+{
+ test_stream_create_error_output();
+ test_stream_locate_first_different_char();
+ test_stream_logical_string_length();
+ test_stream_locate_line_with_offset();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/string_pool.cpp b/src/parser/string_pool.cpp
new file mode 100644
index 0000000..e438da5
--- /dev/null
+++ b/src/parser/string_pool.cpp
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/string_pool.hpp>
+#include <orcus/exception.hpp>
+
+#include <iostream>
+#include <unordered_set>
+#include <vector>
+#include <memory>
+#include <cassert>
+#include <algorithm>
+#include <string_view>
+
+#include <boost/pool/object_pool.hpp>
+
+namespace orcus {
+
+using std::cout;
+using std::endl;
+
+using string_set_type = std::unordered_set<std::string_view>;
+using string_store_type = boost::object_pool<std::string>;
+using string_stores_type = std::vector<std::unique_ptr<string_store_type>>;
+
+struct string_pool::impl
+{
+ string_stores_type m_stores;
+ string_set_type m_set;
+
+ impl()
+ {
+ // first element is the active store used for the current instance.
+ m_stores.push_back(std::make_unique<string_store_type>(256, 0));
+ }
+};
+
+string_pool::string_pool() : mp_impl(std::make_unique<impl>()) {}
+
+string_pool::string_pool(string_pool&& other) : mp_impl(std::move(other.mp_impl)) {}
+
+string_pool::~string_pool() = default;
+
+std::pair<std::string_view, bool> string_pool::intern(std::string_view str)
+{
+ if (str.empty())
+ return std::pair<std::string_view, bool>(std::string_view(), false);
+
+ string_set_type::const_iterator itr = mp_impl->m_set.find(str);
+ if (itr == mp_impl->m_set.end())
+ {
+ // This string has not been interned. Intern it.
+ string_store_type& store = *mp_impl->m_stores[0];
+ std::string* p = store.construct(str);
+ if (!p)
+ throw general_error("failed to intern a new string instance.");
+
+ std::pair<string_set_type::iterator,bool> r =
+ mp_impl->m_set.emplace(p->data(), p->size());
+ if (!r.second)
+ throw general_error("failed to intern a new string instance.");
+
+ std::string_view ps = *r.first;
+ assert(ps == str);
+
+ return std::pair<std::string_view, bool>(ps, true);
+ }
+
+ // This string has already been interned.
+
+ std::string_view stored_str = *itr;
+ assert(stored_str == str);
+ return std::pair<std::string_view, bool>(stored_str, false);
+}
+
+std::vector<std::string_view> string_pool::get_interned_strings() const
+{
+ std::vector<std::string_view> sorted;
+ sorted.reserve(mp_impl->m_set.size());
+
+ for (std::string_view ps : mp_impl->m_set)
+ sorted.push_back(ps);
+
+ std::sort(sorted.begin(), sorted.end());
+
+ return sorted;
+}
+
+void string_pool::dump() const
+{
+ auto sorted = get_interned_strings();
+
+ cout << "interned string count: " << sorted.size() << endl;
+
+ // Dump them all to stdout.
+ size_t counter = 0;
+ for (std::string_view s : sorted)
+ cout << counter++ << ": '" << s << "'" << endl;
+}
+
+void string_pool::clear()
+{
+ mp_impl = std::make_unique<impl>();
+}
+
+size_t string_pool::size() const
+{
+ return mp_impl->m_set.size();
+}
+
+void string_pool::swap(string_pool& other)
+{
+ std::swap(mp_impl, other.mp_impl);
+}
+
+void string_pool::merge(string_pool& other)
+{
+ while (!other.mp_impl->m_stores.empty())
+ {
+ mp_impl->m_stores.push_back(
+ std::move(other.mp_impl->m_stores.back()));
+ other.mp_impl->m_stores.pop_back();
+ }
+
+ for (std::string_view p : other.mp_impl->m_set)
+ mp_impl->m_set.insert(p);
+
+ other.mp_impl->m_set.clear();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/string_pool_test.cpp b/src/parser/string_pool_test.cpp
new file mode 100644
index 0000000..7d3f864
--- /dev/null
+++ b/src/parser/string_pool_test.cpp
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/string_pool.hpp>
+
+#include <type_traits>
+
+using namespace orcus;
+
+void test_basic()
+{
+ const char* static_text = "test";
+
+ string_pool pool;
+ assert(pool.size() == 0);
+
+ std::pair<std::string_view, bool> ret = pool.intern("foo");
+ assert(ret.first == "foo");
+ assert(ret.second); // new instance
+
+ ret = pool.intern("foo");
+ assert(ret.first == "foo");
+ assert(!ret.second); // existing instance.
+
+ // Empty strings should not be interned.
+ ret = pool.intern("");
+ assert(ret.first.empty());
+ assert(!ret.second);
+
+ ret = pool.intern("A");
+ std::cout << "interned string: " << ret.first << std::endl;
+ assert(ret.second);
+ assert(pool.size() == 2);
+
+ // Duplicate string.
+ ret = pool.intern("A");
+ std::cout << "interned string: " << ret.first << std::endl;
+ assert(!ret.second);
+
+ ret = pool.intern("B");
+ std::cout << "interned string: " << ret.first << std::endl;
+ assert(pool.size() == 3);
+
+ // Interning an already-intern string should return a string_view with
+ // identical memory address.
+ std::string_view str = ret.first;
+ std::string_view str2 = pool.intern(str).first;
+ assert(str == str2);
+ assert(pool.size() == 3);
+ assert(str.data() == str2.data()); // their memory address should be identical.
+
+ std::string_view static_str(static_text);
+ ret = pool.intern(static_str);
+ str = ret.first;
+ std::cout << "interned string: " << str << std::endl;
+ assert(pool.size() == 4);
+ assert(str == static_str);
+ assert(str.data() != static_str.data());
+
+ // Make sure that the pool remains usable after calling clear().
+ pool.clear();
+ assert(pool.size() == 0);
+ ret = pool.intern(static_str);
+ assert(ret.second); // it should be a new string
+ assert(ret.first == static_str);
+}
+
+void test_merge()
+{
+ string_pool pool1;
+ std::unique_ptr<string_pool> pool2(std::make_unique<string_pool>());
+
+ pool1.intern("A");
+ pool1.intern("B");
+ pool1.intern("C");
+ std::string_view v1 = pool1.intern("same value").first;
+
+ pool2->intern("D");
+ pool2->intern("E");
+ pool2->intern("F");
+ std::string_view v2 = pool2->intern("same value").first;
+
+ assert(pool1.size() == 4);
+ assert(pool2->size() == 4);
+
+ pool1.merge(*pool2);
+
+ assert(pool1.size() == 7);
+ assert(pool2->size() == 0);
+
+ pool2.reset(); // Delete the pool2 instance altogether.
+
+ // This should not create a new entry.
+ auto r = pool1.intern("F");
+ assert(!r.second);
+
+ // v2 still points to the original string in pool2, which should now be in
+ // the merged store in pool1 (thus valid).
+ assert(v1 == v2);
+
+ std::vector<std::string_view> entries = pool1.get_interned_strings();
+ assert(entries.size() == pool1.size());
+}
+
+void test_move()
+{
+ static_assert(!std::is_copy_constructible_v<orcus::string_pool>);
+ static_assert(std::is_move_constructible_v<orcus::string_pool>);
+
+ string_pool pool1;
+ pool1.intern("A");
+ pool1.intern("B");
+ pool1.intern("C");
+ pool1.intern("D");
+ pool1.intern("E");
+
+ string_pool pool2 = std::move(pool1);
+ assert(pool2.size() == 5);
+}
+
+int main()
+{
+ test_basic();
+ test_merge();
+ test_move();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/threaded_json_parser_test.cpp b/src/parser/threaded_json_parser_test.cpp
new file mode 100644
index 0000000..5ac8053
--- /dev/null
+++ b/src/parser/threaded_json_parser_test.cpp
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/threaded_json_parser.hpp>
+
+#include <cstring>
+
+using namespace orcus;
+using namespace std;
+
+class handler
+{
+ json::parse_tokens_t m_tokens;
+
+public:
+ void begin_parse()
+ {
+ m_tokens.emplace_back(json::parse_token_t::begin_parse);
+ }
+
+ void end_parse()
+ {
+ m_tokens.emplace_back(json::parse_token_t::end_parse);
+ }
+
+ void begin_array()
+ {
+ m_tokens.emplace_back(json::parse_token_t::begin_array);
+ }
+
+ void end_array()
+ {
+ m_tokens.emplace_back(json::parse_token_t::end_array);
+ }
+
+ void begin_object()
+ {
+ m_tokens.emplace_back(json::parse_token_t::begin_object);
+ }
+
+ void object_key(const char* p, size_t len, bool transient)
+ {
+ assert(!transient); // transient is never true with the threaded parser.
+ m_tokens.emplace_back(json::parse_token_t::object_key, std::string_view{p, len});
+ }
+
+ void end_object()
+ {
+ m_tokens.emplace_back(json::parse_token_t::end_object);
+ }
+
+ void boolean_true()
+ {
+ m_tokens.emplace_back(json::parse_token_t::boolean_true);
+ }
+
+ void boolean_false()
+ {
+ m_tokens.emplace_back(json::parse_token_t::boolean_false);
+ }
+
+ void null()
+ {
+ m_tokens.emplace_back(json::parse_token_t::null);
+ }
+
+ void string(const char* p, size_t len, bool transient)
+ {
+ assert(!transient); // transient is never true with the threaded parser.
+ m_tokens.emplace_back(json::parse_token_t::string, std::string_view{p, len});
+ }
+
+ void number(double val)
+ {
+ m_tokens.emplace_back(val);
+ }
+
+ const json::parse_tokens_t& get_tokens() const
+ {
+ return m_tokens;
+ }
+};
+
+void test_parser(const char* src, const json::parse_tokens_t& expected)
+{
+ cout << "source: " << src << endl;
+
+ handler hdl;
+ threaded_json_parser<handler> parser(src, std::strlen(src), hdl, 5, 5);
+ parser.parse();
+
+ if (hdl.get_tokens() != expected)
+ {
+ cout << "Expected tokens:" << endl;
+ cout << expected;
+ cout << "Actual tokens:" << endl;
+ cout << hdl.get_tokens();
+ abort();
+ }
+}
+
+void test_threaded_json_parser_basic()
+{
+ struct test_case
+ {
+ const char* source;
+ json::parse_tokens_t expected;
+ };
+
+ test_case tcs[] =
+ {
+ {
+ "[1,2,3]",
+ {
+ { json::parse_token_t::begin_parse },
+ { json::parse_token_t::begin_array },
+ { 1.0 },
+ { 2.0 },
+ { 3.0 },
+ { json::parse_token_t::end_array },
+ { json::parse_token_t::end_parse },
+ }
+ },
+ {
+ "{\"foo\": [true, false, null]}",
+ {
+ { json::parse_token_t::begin_parse },
+ { json::parse_token_t::begin_object },
+ { json::parse_token_t::object_key, std::string_view{"foo"} },
+ { json::parse_token_t::begin_array },
+ { json::parse_token_t::boolean_true },
+ { json::parse_token_t::boolean_false },
+ { json::parse_token_t::null },
+ { json::parse_token_t::end_array },
+ { json::parse_token_t::end_object },
+ { json::parse_token_t::end_parse },
+ }
+ }
+ };
+
+ for (size_t i = 0, n = std::size(tcs); i < n; ++i)
+ test_parser(tcs[i].source, tcs[i].expected);
+}
+
+void test_threaded_json_parser_invalid()
+{
+ const char* invalids[] = {
+ "[foo]",
+ "[qwerty]",
+ "[1,2] null",
+ "{\"key\" 1: 12}",
+ "[1,,2]",
+ "\"key\": {\"inner\": 12}"
+ };
+
+ for (size_t i = 0; i < std::size(invalids); ++i)
+ {
+ const char* src = invalids[i];
+
+ try
+ {
+ handler hdl;
+ threaded_json_parser<handler> parser(src, std::strlen(src), hdl, 1);
+ parser.parse();
+ assert(false);
+ }
+ catch (const parse_error&)
+ {
+ // works as expected.
+ cout << "invalid source: " << src << endl;
+ }
+ }
+}
+
+int main()
+{
+ test_threaded_json_parser_basic();
+ test_threaded_json_parser_invalid();
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/threaded_sax_token_parser_test.cpp b/src/parser/threaded_sax_token_parser_test.cpp
new file mode 100644
index 0000000..1338b2a
--- /dev/null
+++ b/src/parser/threaded_sax_token_parser_test.cpp
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/threaded_sax_token_parser.hpp"
+#include "orcus/tokens.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/parser_base.hpp"
+#include "orcus/stream.hpp"
+
+#include <cstring>
+
+using namespace std;
+using namespace orcus;
+
+void test_sax_token_parser_1()
+{
+ // Array of tokens to define for this test.
+ const char* token_names[] = {
+ "??", // 0
+ "andy", // 1
+ "bruce", // 2
+ "charlie", // 3
+ "david", // 4
+ "edward" // 5
+ };
+
+ size_t token_count = std::size(token_names);
+
+ // Token constants.
+ const xml_token_t op_andy = 1;
+ const xml_token_t op_bruce = 2;
+ const xml_token_t op_charlie = 3;
+ const xml_token_t op_david = 4;
+ const xml_token_t op_edward = 5;
+
+ struct check
+ {
+ const char* raw_name;
+ xml_token_t token;
+ bool start_element;
+ };
+
+ tokens token_map(token_names, token_count);
+ xmlns_repository ns_repo;
+ xmlns_context ns_cxt = ns_repo.create_context();
+
+ {
+ // Test XML content.
+ const char* content = "<?xml version=\"1.0\"?><root><andy/><bruce/><charlie/><david/><edward/><frank/></root>";
+ size_t content_size = strlen(content);
+
+ // Expected outcome.
+ const check checks[] = {
+ { "root", XML_UNKNOWN_TOKEN, true }, // name not on the master token list.
+ { "andy", op_andy, true },
+ { "andy", op_andy, false },
+ { "bruce", op_bruce, true },
+ { "bruce", op_bruce, false },
+ { "charlie", op_charlie, true },
+ { "charlie", op_charlie, false },
+ { "david", op_david, true },
+ { "david", op_david, false },
+ { "edward", op_edward, true },
+ { "edward", op_edward, false },
+ { "frank", XML_UNKNOWN_TOKEN, true }, // name not on the master token list.
+ { "frank", XML_UNKNOWN_TOKEN, false }, // name not on the master token list.
+ { "root", XML_UNKNOWN_TOKEN, false }, // name not on the master token list.
+ };
+
+ class handler
+ {
+ const check* mp_head;
+ const check* mp_check;
+ public:
+ handler(const check* p) : mp_head(p), mp_check(p) {}
+
+ void start_element(const orcus::xml_token_element_t& elem)
+ {
+ assert(std::string_view(mp_check->raw_name) == elem.raw_name);
+ assert(mp_check->token == elem.name);
+ assert(mp_check->start_element);
+ ++mp_check;
+ }
+
+ void end_element(const orcus::xml_token_element_t& elem)
+ {
+ assert(std::string_view(mp_check->raw_name) == elem.raw_name);
+ assert(mp_check->token == elem.name);
+ assert(!mp_check->start_element);
+ ++mp_check;
+ }
+
+ void characters(std::string_view /*val*/, bool /*transient*/) {}
+
+ size_t get_token_count() const
+ {
+ return std::distance(mp_head, mp_check);
+ }
+ };
+
+ handler hdl(checks);
+ threaded_sax_token_parser<handler> parser(content, content_size, token_map, ns_cxt, hdl, 1, 100);
+ parser.parse();
+
+ assert(hdl.get_token_count() == std::size(checks));
+ }
+
+ {
+ // This content intentially contains invalid XML part at offset 28.
+ const char* content = "<?xml version=\"1.0\"?><root><<andy/><bruce/><charlie/><david/><edward/><frank/></root>";
+ size_t content_size = strlen(content);
+
+ class handler
+ {
+ public:
+ handler() {}
+
+ void start_element(const orcus::xml_token_element_t& /*elem*/) {}
+
+ void end_element(const orcus::xml_token_element_t& /*elem*/) {}
+
+ void characters(std::string_view /*val*/, bool /*transient*/) {}
+ };
+
+ try
+ {
+ handler hdl;
+ threaded_sax_token_parser<handler> parser(content, content_size, token_map, ns_cxt, hdl, 1, 100);
+ parser.parse();
+ assert(!"An exception was expected, but one was not thrown.");
+ }
+ catch (const malformed_xml_error& e)
+ {
+ assert(e.offset() == 28u);
+ }
+ catch (const std::exception&)
+ {
+ assert(!"Wrong exception was thrown!");
+ }
+ }
+
+ {
+ // Test XML content.
+ const char* content = "<?xml version=\"1.0\"?><root><andy/><bruce/><charlie/><david/><edward/><frank/></root>";
+ size_t content_size = strlen(content);
+
+ class mock_exception : public std::exception {};
+
+ class handler
+ {
+ public:
+ handler() {}
+
+ void start_element(const orcus::xml_token_element_t& /*elem*/) {}
+
+ void end_element(const orcus::xml_token_element_t& /*elem*/)
+ {
+ throw mock_exception();
+ }
+
+ void characters(std::string_view /*val*/, bool /*transient*/) {}
+ };
+
+ handler hdl;
+ threaded_sax_token_parser<handler> parser(content, content_size, token_map, ns_cxt, hdl, 1, 100);
+
+ try
+ {
+ parser.parse();
+ assert(!"A mock exception was expected but not thrown.");
+ }
+ catch (const mock_exception&)
+ {
+ // expected.
+ }
+ }
+}
+
+int main()
+{
+ test_sax_token_parser_1();
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/tokens.cpp b/src/parser/tokens.cpp
new file mode 100644
index 0000000..5d3c533
--- /dev/null
+++ b/src/parser/tokens.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/tokens.hpp>
+
+namespace orcus {
+
+tokens::tokens(const char** token_names, size_t token_name_count) :
+ m_token_names(token_names),
+ m_token_name_count(token_name_count)
+{
+ for (size_t i = 0; i < m_token_name_count; ++i)
+ m_tokens.emplace(m_token_names[i], xml_token_t(i));
+}
+
+tokens::~tokens() = default;
+
+bool tokens::is_valid_token(xml_token_t token) const
+{
+ return token != XML_UNKNOWN_TOKEN;
+}
+
+xml_token_t tokens::get_token(std::string_view name) const
+{
+ token_map_type::const_iterator itr = m_tokens.find(name);
+ if (itr == m_tokens.end())
+ return XML_UNKNOWN_TOKEN;
+ return itr->second;
+}
+
+std::string_view tokens::get_token_name(xml_token_t token) const
+{
+ if (size_t(token) >= m_token_name_count)
+ return "";
+
+ return m_token_names[token];
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/types.cpp b/src/parser/types.cpp
new file mode 100644
index 0000000..5d469c5
--- /dev/null
+++ b/src/parser/types.cpp
@@ -0,0 +1,1454 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/types.hpp>
+#include <orcus/parser_global.hpp>
+#include <orcus/xml_namespace.hpp>
+
+#include <limits>
+#include <sstream>
+#include <string_view>
+#include <iomanip>
+#include <mdds/sorted_string_map.hpp>
+
+#include "ostream_utils.hpp"
+
+namespace orcus {
+
+parse_error_value_t::parse_error_value_t() :
+ offset(0)
+{
+}
+
+parse_error_value_t::parse_error_value_t(const parse_error_value_t& other) = default;
+
+parse_error_value_t::parse_error_value_t(std::string_view _str, std::ptrdiff_t _offset) :
+ str(_str), offset(_offset)
+{
+}
+
+parse_error_value_t& parse_error_value_t::operator=(const parse_error_value_t& other) = default;
+
+bool parse_error_value_t::operator==(const parse_error_value_t& other) const
+{
+ return str == other.str && offset == other.offset;
+}
+
+bool parse_error_value_t::operator!=(const parse_error_value_t& other) const
+{
+ return !operator==(other);
+}
+
+xml_name_t::xml_name_t() noexcept : ns(XMLNS_UNKNOWN_ID), name() {}
+xml_name_t::xml_name_t(xmlns_id_t _ns, std::string_view _name) : ns(_ns), name(_name) {}
+xml_name_t::xml_name_t(const xml_name_t& other) = default;
+
+xml_name_t& xml_name_t::operator= (const xml_name_t& other) = default;
+
+bool xml_name_t::operator== (const xml_name_t& other) const noexcept
+{
+ return ns == other.ns && name == other.name;
+}
+
+bool xml_name_t::operator!= (const xml_name_t& other) const noexcept
+{
+ return !operator==(other);
+}
+
+std::string xml_name_t::to_string(const xmlns_context& cxt, to_string_type type) const
+{
+ std::ostringstream os;
+
+ if (ns)
+ {
+ std::string_view ns_str;
+ switch (type)
+ {
+ case use_alias:
+ ns_str = cxt.get_alias(ns);
+ break;
+ case use_short_name:
+ ns_str = cxt.get_short_name(ns);
+ break;
+
+ }
+ if (!ns_str.empty())
+ os << ns_str << ':';
+ }
+ os << name;
+
+ return os.str();
+}
+
+std::string xml_name_t::to_string(const xmlns_repository& repo) const
+{
+ std::ostringstream os;
+
+ if (ns)
+ {
+ std::string ns_str = repo.get_short_name(ns);
+ if (!ns_str.empty())
+ os << ns_str << ':';
+ }
+ os << name;
+
+ return os.str();
+}
+
+xml_token_attr_t::xml_token_attr_t() :
+ ns(XMLNS_UNKNOWN_ID), name(XML_UNKNOWN_TOKEN), transient(false) {}
+
+xml_token_attr_t::xml_token_attr_t(const xml_token_attr_t& other) = default;
+
+xml_token_attr_t::xml_token_attr_t(
+ xmlns_id_t _ns, xml_token_t _name, std::string_view _value, bool _transient) :
+ ns(_ns), name(_name), value(_value), transient(_transient) {}
+
+xml_token_attr_t::xml_token_attr_t(
+ xmlns_id_t _ns, xml_token_t _name, std::string_view _raw_name, std::string_view _value, bool _transient) :
+ ns(_ns), name(_name), raw_name(_raw_name), value(_value), transient(_transient) {}
+
+xml_token_attr_t& xml_token_attr_t::operator=(const xml_token_attr_t& other) = default;
+
+xml_token_element_t::xml_token_element_t() : ns(nullptr), name(XML_UNKNOWN_TOKEN) {}
+
+xml_token_element_t::xml_token_element_t(
+ xmlns_id_t _ns, xml_token_t _name, std::string_view _raw_name, std::vector<xml_token_attr_t>&& _attrs) :
+ ns(_ns), name(_name), raw_name(_raw_name), attrs(std::move(_attrs)) {}
+
+xml_token_element_t::xml_token_element_t(const xml_token_element_t& other) :
+ ns(other.ns), name(other.name), raw_name(other.raw_name), attrs(other.attrs) {}
+
+xml_token_element_t::xml_token_element_t(xml_token_element_t&& other) :
+ ns(other.ns), name(other.name), raw_name(other.raw_name), attrs(std::move(other.attrs)) {}
+
+xml_declaration_t::xml_declaration_t() :
+ version_major(1),
+ version_minor(0),
+ encoding(character_set_t::unspecified),
+ standalone(false) {}
+
+xml_declaration_t::xml_declaration_t(uint8_t _version_major, uint8_t _version_minor, character_set_t _encoding, bool _standalone) :
+ version_major(_version_major), version_minor(_version_minor), encoding(_encoding), standalone(_standalone) {}
+
+xml_declaration_t::xml_declaration_t(const xml_declaration_t& other) :
+ version_major(other.version_major),
+ version_minor(other.version_minor),
+ encoding(other.encoding),
+ standalone(other.standalone) {}
+
+xml_declaration_t::~xml_declaration_t() {}
+
+xml_declaration_t& xml_declaration_t::operator= (const xml_declaration_t& other)
+{
+ version_major = other.version_major;
+ version_minor = other.version_minor;
+ encoding = other.encoding;
+ standalone = other.standalone;
+ return *this;
+}
+
+bool xml_declaration_t::operator== (const xml_declaration_t& other) const
+{
+ return version_major == other.version_major && version_minor == other.version_minor &&
+ encoding == other.encoding && standalone == other.standalone;
+}
+
+bool xml_declaration_t::operator!= (const xml_declaration_t& other) const
+{
+ return !operator== (other);
+}
+
+length_t::length_t() : unit(length_unit_t::unknown), value(0.0) {}
+
+length_t::length_t(length_unit_t _unit, double _value) : unit(_unit), value(_value) {}
+
+length_t::length_t(const length_t& other) = default;
+
+length_t& length_t::operator= (const length_t& other) = default;
+
+std::string length_t::to_string() const
+{
+ std::ostringstream os;
+ os << value;
+
+ switch (unit)
+ {
+ case length_unit_t::centimeter:
+ os << " cm";
+ break;
+ case length_unit_t::inch:
+ os << " in";
+ break;
+ case length_unit_t::point:
+ os << " pt";
+ break;
+ case length_unit_t::twip:
+ os << " twip";
+ break;
+ case length_unit_t::unknown:
+ default:
+ ;
+ }
+
+ return os.str();
+}
+
+bool length_t::operator== (const length_t& other) const noexcept
+{
+ return value == other.value && unit == other.unit;
+}
+
+bool length_t::operator!= (const length_t& other) const noexcept
+{
+ return !operator== (other);
+}
+
+date_time_t::date_time_t() :
+ year(0), month(0), day(0), hour(0), minute(0), second(0.0) {}
+
+date_time_t::date_time_t(int _year, int _month, int _day) :
+ year(_year), month(_month), day(_day), hour(0), minute(0), second(0.0) {}
+
+date_time_t::date_time_t(int _year, int _month, int _day, int _hour, int _minute, double _second) :
+ year(_year), month(_month), day(_day), hour(_hour), minute(_minute), second(_second) {}
+
+date_time_t::date_time_t(const date_time_t& other) = default;
+date_time_t::~date_time_t() = default;
+
+date_time_t& date_time_t::operator= (date_time_t other)
+{
+ swap(other);
+ return *this;
+}
+
+void date_time_t::swap(date_time_t& other)
+{
+ std::swap(year, other.year);
+ std::swap(month, other.month);
+ std::swap(day, other.day);
+ std::swap(hour, other.hour);
+ std::swap(minute, other.minute);
+ std::swap(second, other.second);
+}
+
+date_time_t date_time_t::from_chars(std::string_view str)
+{
+ auto flush_int = [](int& store, const char*& digit, size_t& digit_len)
+ {
+ long v;
+ parse_integer(digit, digit + digit_len, v);
+ store = v;
+
+ digit = nullptr;
+ digit_len = 0;
+ };
+
+ auto process_char = [](const char* p, const char*& digit, size_t& digit_len)
+ {
+ if (!digit)
+ {
+ digit = p;
+ digit_len = 1;
+ return;
+ }
+
+ ++digit_len;
+ };
+
+ date_time_t ret;
+ int dash_count = 0, t_count = 0, colon_count = 0;
+
+ const char* p = str.data();
+ const char* p_end = p + str.size();
+ const char* digit = p;
+ size_t digit_len = 0;
+
+ bool valid = true;
+ for (; p != p_end && valid; ++p)
+ {
+ switch (*p)
+ {
+ case '-':
+ {
+ if (t_count || colon_count || !digit)
+ {
+ // Invalid date-time value. All dashes must occur before
+ // any of 'T' and ':' occur.
+ valid = false;
+ break;
+ }
+
+ switch (dash_count)
+ {
+ case 0:
+ // Flush year.
+ flush_int(ret.year, digit, digit_len);
+ break;
+ case 1:
+ // Flush month.
+ flush_int(ret.month, digit, digit_len);
+ break;
+ default:
+ valid = false;
+ }
+ ++dash_count;
+ }
+ break;
+ case 'T':
+ {
+ if (t_count || dash_count != 2 || !digit)
+ {
+ // Invalid date-time value.
+ valid = false;
+ break;
+ }
+
+ // Flush day.
+ flush_int(ret.day, digit, digit_len);
+ ++t_count;
+ }
+ break;
+ case ':':
+ {
+ if (!t_count || !digit)
+ {
+ // Invalid date-time value.
+ valid = false;
+ break;
+ }
+
+ switch (colon_count)
+ {
+ case 0:
+ // Flush hour.
+ flush_int(ret.hour, digit, digit_len);
+ break;
+ case 1:
+ // Flush minute.
+ flush_int(ret.minute, digit, digit_len);
+ break;
+ default:
+ valid = false;
+ }
+
+ ++colon_count;
+ }
+ break;
+ default:
+ {
+ if (t_count)
+ {
+ // Time element.
+ switch (colon_count)
+ {
+ case 0:
+ // Hour
+ process_char(p, digit, digit_len);
+ break;
+ case 1:
+ // Minute
+ process_char(p, digit, digit_len);
+ break;
+ case 2:
+ // Second
+ process_char(p, digit, digit_len);
+ break;
+ default:
+ valid = false;
+ }
+ }
+ else
+ {
+ // Date element.
+ switch (dash_count)
+ {
+ case 0:
+ // Year
+ process_char(p, digit, digit_len);
+ break;
+ case 1:
+ // Month
+ process_char(p, digit, digit_len);
+ break;
+ case 2:
+ // Day
+ process_char(p, digit, digit_len);
+ break;
+ default:
+ valid = false;
+ }
+ }
+ }
+ }
+
+ }
+
+ if (!valid || !digit)
+ return ret;
+
+ if (t_count)
+ {
+ // Flush second.
+ ret.second = strtod(digit, nullptr);
+ }
+ else
+ {
+ // Flush day.
+ flush_int(ret.day, digit, digit_len);
+ }
+
+ return ret;
+}
+
+bool date_time_t::operator== (const date_time_t& other) const
+{
+ return year == other.year && month == other.month && day == other.day &&
+ hour == other.hour && minute == other.minute && second == other.second;
+}
+
+bool date_time_t::operator!= (const date_time_t& other) const
+{
+ return !operator== (other);
+}
+
+bool date_time_t::operator< (const date_time_t& other) const
+{
+ if (year != other.year)
+ return year < other.year;
+
+ if (month != other.month)
+ return month < other.month;
+
+ if (day != other.day)
+ return day < other.day;
+
+ if (hour != other.hour)
+ return hour < other.hour;
+
+ if (minute != other.minute)
+ return minute < other.minute;
+
+ return second < other.second;
+}
+
+std::string date_time_t::to_string() const
+{
+ std::ostringstream os;
+
+ // NB: setfill is sticky for the entire run whereas setw gets reset for each
+ // value.
+ os << std::setfill('0');
+
+ os << std::setw(4) << year
+ << "-" << std::setw(2) << month
+ << "-" << std::setw(2) << day
+ << "T" << std::setw(2) << hour
+ << ":" << std::setw(2) << minute
+ << ":" << std::setw(2) << second;
+
+ return os.str();
+}
+
+namespace {
+
+namespace dump_format {
+
+using map_type = mdds::sorted_string_map<dump_format_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "check", dump_format_t::check },
+ { "csv", dump_format_t::csv },
+ { "debug-state", dump_format_t::debug_state },
+ { "flat", dump_format_t::flat },
+ { "html", dump_format_t::html },
+ { "json", dump_format_t::json },
+ { "none", dump_format_t::none },
+ { "xml", dump_format_t::xml },
+ { "yaml", dump_format_t::yaml },
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), dump_format_t::unknown);
+ return mt;
+}
+
+} // namespace dump_format
+
+namespace charset {
+
+using map_type = mdds::sorted_string_map<character_set_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "437", character_set_t::ibm437 },
+ { "850", character_set_t::ibm850 },
+ { "851", character_set_t::ibm851 },
+ { "852", character_set_t::ibm852 },
+ { "855", character_set_t::ibm855 },
+ { "857", character_set_t::ibm857 },
+ { "860", character_set_t::ibm860 },
+ { "861", character_set_t::ibm861 },
+ { "862", character_set_t::ibm862 },
+ { "863", character_set_t::ibm863 },
+ { "865", character_set_t::ibm865 },
+ { "866", character_set_t::ibm866 },
+ { "869", character_set_t::ibm869 },
+ { "904", character_set_t::ibm904 },
+ { "adobe-standard-encoding", character_set_t::adobe_standard_encoding },
+ { "adobe-symbol-encoding", character_set_t::adobe_symbol_encoding },
+ { "ami-1251", character_set_t::amiga_1251 },
+ { "ami1251", character_set_t::amiga_1251 },
+ { "amiga-1251", character_set_t::amiga_1251 },
+ { "amiga1251", character_set_t::amiga_1251 },
+ { "ansi_x3.110-1983", character_set_t::ansi_x3_110_1983 },
+ { "ansi_x3.4-1968", character_set_t::us_ascii },
+ { "ansi_x3.4-1986", character_set_t::us_ascii },
+ { "arabic", character_set_t::iso_8859_6 },
+ { "arabic7", character_set_t::asmo_449 },
+ { "asmo-708", character_set_t::iso_8859_6 },
+ { "asmo_449", character_set_t::asmo_449 },
+ { "big5", character_set_t::big5 },
+ { "big5-hkscs", character_set_t::big5_hkscs },
+ { "bocu-1", character_set_t::bocu_1 },
+ { "brf", character_set_t::brf },
+ { "bs_4730", character_set_t::bs_4730 },
+ { "bs_viewdata", character_set_t::bs_viewdata },
+ { "ca", character_set_t::csa_z243_4_1985_1 },
+ { "ccsid00858", character_set_t::ibm00858 },
+ { "ccsid00924", character_set_t::ibm00924 },
+ { "ccsid01140", character_set_t::ibm01140 },
+ { "ccsid01141", character_set_t::ibm01141 },
+ { "ccsid01142", character_set_t::ibm01142 },
+ { "ccsid01143", character_set_t::ibm01143 },
+ { "ccsid01144", character_set_t::ibm01144 },
+ { "ccsid01145", character_set_t::ibm01145 },
+ { "ccsid01146", character_set_t::ibm01146 },
+ { "ccsid01147", character_set_t::ibm01147 },
+ { "ccsid01148", character_set_t::ibm01148 },
+ { "ccsid01149", character_set_t::ibm01149 },
+ { "cesu-8", character_set_t::cesu_8 },
+ { "chinese", character_set_t::gb_2312_80 },
+ { "cn", character_set_t::gb_1988_80 },
+ { "cp-ar", character_set_t::ibm868 },
+ { "cp-gr", character_set_t::ibm869 },
+ { "cp-is", character_set_t::ibm861 },
+ { "cp00858", character_set_t::ibm00858 },
+ { "cp00924", character_set_t::ibm00924 },
+ { "cp01140", character_set_t::ibm01140 },
+ { "cp01141", character_set_t::ibm01141 },
+ { "cp01142", character_set_t::ibm01142 },
+ { "cp01143", character_set_t::ibm01143 },
+ { "cp01144", character_set_t::ibm01144 },
+ { "cp01145", character_set_t::ibm01145 },
+ { "cp01146", character_set_t::ibm01146 },
+ { "cp01147", character_set_t::ibm01147 },
+ { "cp01148", character_set_t::ibm01148 },
+ { "cp01149", character_set_t::ibm01149 },
+ { "cp037", character_set_t::ibm037 },
+ { "cp038", character_set_t::ibm038 },
+ { "cp1026", character_set_t::ibm1026 },
+ { "cp154", character_set_t::ptcp154 },
+ { "cp273", character_set_t::ibm273 },
+ { "cp274", character_set_t::ibm274 },
+ { "cp275", character_set_t::ibm275 },
+ { "cp278", character_set_t::ibm278 },
+ { "cp280", character_set_t::ibm280 },
+ { "cp281", character_set_t::ibm281 },
+ { "cp284", character_set_t::ibm284 },
+ { "cp285", character_set_t::ibm285 },
+ { "cp290", character_set_t::ibm290 },
+ { "cp297", character_set_t::ibm297 },
+ { "cp367", character_set_t::us_ascii },
+ { "cp420", character_set_t::ibm420 },
+ { "cp423", character_set_t::ibm423 },
+ { "cp424", character_set_t::ibm424 },
+ { "cp437", character_set_t::ibm437 },
+ { "cp500", character_set_t::ibm500 },
+ { "cp50220", character_set_t::cp50220 },
+ { "cp51932", character_set_t::cp51932 },
+ { "cp775", character_set_t::ibm775 },
+ { "cp819", character_set_t::iso_8859_1 },
+ { "cp850", character_set_t::ibm850 },
+ { "cp851", character_set_t::ibm851 },
+ { "cp852", character_set_t::ibm852 },
+ { "cp855", character_set_t::ibm855 },
+ { "cp857", character_set_t::ibm857 },
+ { "cp860", character_set_t::ibm860 },
+ { "cp861", character_set_t::ibm861 },
+ { "cp862", character_set_t::ibm862 },
+ { "cp863", character_set_t::ibm863 },
+ { "cp864", character_set_t::ibm864 },
+ { "cp865", character_set_t::ibm865 },
+ { "cp866", character_set_t::ibm866 },
+ { "cp868", character_set_t::ibm868 },
+ { "cp869", character_set_t::ibm869 },
+ { "cp870", character_set_t::ibm870 },
+ { "cp871", character_set_t::ibm871 },
+ { "cp880", character_set_t::ibm880 },
+ { "cp891", character_set_t::ibm891 },
+ { "cp903", character_set_t::ibm903 },
+ { "cp904", character_set_t::ibm904 },
+ { "cp905", character_set_t::ibm905 },
+ { "cp918", character_set_t::ibm918 },
+ { "cp936", character_set_t::gbk },
+ { "csa7-1", character_set_t::csa_z243_4_1985_1 },
+ { "csa7-2", character_set_t::csa_z243_4_1985_2 },
+ { "csa71", character_set_t::csa_z243_4_1985_1 },
+ { "csa72", character_set_t::csa_z243_4_1985_2 },
+ { "csa_t500-1983", character_set_t::ansi_x3_110_1983 },
+ { "csa_z243.4-1985-1", character_set_t::csa_z243_4_1985_1 },
+ { "csa_z243.4-1985-2", character_set_t::csa_z243_4_1985_2 },
+ { "csa_z243.4-1985-gr", character_set_t::csa_z243_4_1985_gr },
+ { "csadobestandardencoding", character_set_t::adobe_standard_encoding },
+ { "csascii", character_set_t::us_ascii },
+ { "csbig5", character_set_t::big5 },
+ { "csbig5hkscs", character_set_t::big5_hkscs },
+ { "csbocu-1", character_set_t::bocu_1 },
+ { "csbocu1", character_set_t::bocu_1 },
+ { "csbrf", character_set_t::brf },
+ { "cscesu-8", character_set_t::cesu_8 },
+ { "cscesu8", character_set_t::cesu_8 },
+ { "cscp50220", character_set_t::cp50220 },
+ { "cscp51932", character_set_t::cp51932 },
+ { "csdecmcs", character_set_t::dec_mcs },
+ { "csdkus", character_set_t::dk_us },
+ { "csebcdicatdea", character_set_t::ebcdic_at_de_a },
+ { "csebcdiccafr", character_set_t::ebcdic_ca_fr },
+ { "csebcdicdkno", character_set_t::ebcdic_dk_no },
+ { "csebcdicdknoa", character_set_t::ebcdic_dk_no_a },
+ { "csebcdices", character_set_t::ebcdic_es },
+ { "csebcdicesa", character_set_t::ebcdic_es_a },
+ { "csebcdicess", character_set_t::ebcdic_es_s },
+ { "csebcdicfise", character_set_t::ebcdic_fi_se },
+ { "csebcdicfisea", character_set_t::ebcdic_fi_se_a },
+ { "csebcdicfr", character_set_t::ebcdic_fr },
+ { "csebcdicit", character_set_t::ebcdic_it },
+ { "csebcdicpt", character_set_t::ebcdic_pt },
+ { "csebcdicuk", character_set_t::ebcdic_uk },
+ { "csebcdicus", character_set_t::ebcdic_us },
+ { "cseucfixwidjapanese", character_set_t::extended_unix_code_fixed_width_for_japanese },
+ { "cseuckr", character_set_t::euc_kr },
+ { "cseucpkdfmtjapanese", character_set_t::euc_jp },
+ { "csgb18030", character_set_t::gb18030 },
+ { "csgb2312", character_set_t::gb2312 },
+ { "csgbk", character_set_t::gbk },
+ { "cshalfwidthkatakana", character_set_t::jis_x0201 },
+ { "cshpdesktop", character_set_t::hp_desktop },
+ { "cshplegal", character_set_t::hp_legal },
+ { "cshpmath8", character_set_t::hp_math8 },
+ { "cshppifont", character_set_t::hp_pi_font },
+ { "cshppsmath", character_set_t::adobe_symbol_encoding },
+ { "cshproman8", character_set_t::hp_roman8 },
+ { "csibbm904", character_set_t::ibm904 },
+ { "csibm00858", character_set_t::ibm00858 },
+ { "csibm00924", character_set_t::ibm00924 },
+ { "csibm01140", character_set_t::ibm01140 },
+ { "csibm01141", character_set_t::ibm01141 },
+ { "csibm01142", character_set_t::ibm01142 },
+ { "csibm01143", character_set_t::ibm01143 },
+ { "csibm01144", character_set_t::ibm01144 },
+ { "csibm01145", character_set_t::ibm01145 },
+ { "csibm01146", character_set_t::ibm01146 },
+ { "csibm01147", character_set_t::ibm01147 },
+ { "csibm01148", character_set_t::ibm01148 },
+ { "csibm01149", character_set_t::ibm01149 },
+ { "csibm037", character_set_t::ibm037 },
+ { "csibm038", character_set_t::ibm038 },
+ { "csibm1026", character_set_t::ibm1026 },
+ { "csibm1047", character_set_t::ibm1047 },
+ { "csibm273", character_set_t::ibm273 },
+ { "csibm274", character_set_t::ibm274 },
+ { "csibm275", character_set_t::ibm275 },
+ { "csibm277", character_set_t::ibm277 },
+ { "csibm278", character_set_t::ibm278 },
+ { "csibm280", character_set_t::ibm280 },
+ { "csibm281", character_set_t::ibm281 },
+ { "csibm284", character_set_t::ibm284 },
+ { "csibm285", character_set_t::ibm285 },
+ { "csibm290", character_set_t::ibm290 },
+ { "csibm297", character_set_t::ibm297 },
+ { "csibm420", character_set_t::ibm420 },
+ { "csibm423", character_set_t::ibm423 },
+ { "csibm424", character_set_t::ibm424 },
+ { "csibm500", character_set_t::ibm500 },
+ { "csibm851", character_set_t::ibm851 },
+ { "csibm855", character_set_t::ibm855 },
+ { "csibm857", character_set_t::ibm857 },
+ { "csibm860", character_set_t::ibm860 },
+ { "csibm861", character_set_t::ibm861 },
+ { "csibm863", character_set_t::ibm863 },
+ { "csibm864", character_set_t::ibm864 },
+ { "csibm865", character_set_t::ibm865 },
+ { "csibm866", character_set_t::ibm866 },
+ { "csibm868", character_set_t::ibm868 },
+ { "csibm869", character_set_t::ibm869 },
+ { "csibm870", character_set_t::ibm870 },
+ { "csibm871", character_set_t::ibm871 },
+ { "csibm880", character_set_t::ibm880 },
+ { "csibm891", character_set_t::ibm891 },
+ { "csibm903", character_set_t::ibm903 },
+ { "csibm905", character_set_t::ibm905 },
+ { "csibm918", character_set_t::ibm918 },
+ { "csibmebcdicatde", character_set_t::ebcdic_at_de },
+ { "csibmsymbols", character_set_t::ibm_symbols },
+ { "csibmthai", character_set_t::ibm_thai },
+ { "csinvariant", character_set_t::invariant },
+ { "csiso102t617bit", character_set_t::t_61_7bit },
+ { "csiso10367box", character_set_t::iso_10367_box },
+ { "csiso103t618bit", character_set_t::t_61_8bit },
+ { "csiso10646utf1", character_set_t::iso_10646_utf_1 },
+ { "csiso10swedish", character_set_t::sen_850200_b },
+ { "csiso111ecmacyrillic", character_set_t::ecma_cyrillic },
+ { "csiso115481", character_set_t::iso_11548_1 },
+ { "csiso11swedishfornames", character_set_t::sen_850200_c },
+ { "csiso121canadian1", character_set_t::csa_z243_4_1985_1 },
+ { "csiso122canadian2", character_set_t::csa_z243_4_1985_2 },
+ { "csiso123csaz24341985gr", character_set_t::csa_z243_4_1985_gr },
+ { "csiso128t101g2", character_set_t::t_101_g2 },
+ { "csiso139csn369103", character_set_t::csn_369103 },
+ { "csiso13jisc6220jp", character_set_t::jis_c6220_1969_jp },
+ { "csiso141jusib1002", character_set_t::jus_i_b1_002 },
+ { "csiso143iecp271", character_set_t::iec_p27_1 },
+ { "csiso146serbian", character_set_t::jus_i_b1_003_serb },
+ { "csiso147macedonian", character_set_t::jus_i_b1_003_mac },
+ { "csiso14jisc6220ro", character_set_t::jis_c6220_1969_ro },
+ { "csiso150", character_set_t::greek_ccitt },
+ { "csiso150greekccitt", character_set_t::greek_ccitt },
+ { "csiso151cuba", character_set_t::nc_nc00_10_81 },
+ { "csiso153gost1976874", character_set_t::gost_19768_74 },
+ { "csiso158lap", character_set_t::latin_lap },
+ { "csiso159jisx02121990", character_set_t::jis_x0212_1990 },
+ { "csiso15italian", character_set_t::it },
+ { "csiso16portuguese", character_set_t::pt },
+ { "csiso17spanish", character_set_t::es },
+ { "csiso18greek7old", character_set_t::greek7_old },
+ { "csiso19latingreek", character_set_t::latin_greek },
+ { "csiso2022cn", character_set_t::iso_2022_cn },
+ { "csiso2022cnext", character_set_t::iso_2022_cn_ext },
+ { "csiso2022jp", character_set_t::iso_2022_jp },
+ { "csiso2022jp2", character_set_t::iso_2022_jp_2 },
+ { "csiso2022kr", character_set_t::iso_2022_kr },
+ { "csiso2033", character_set_t::iso_2033_1983 },
+ { "csiso21german", character_set_t::din_66003 },
+ { "csiso25french", character_set_t::nf_z_62_010_1973 },
+ { "csiso27latingreek1", character_set_t::latin_greek_1 },
+ { "csiso2intlrefversion", character_set_t::iso_646_irv_1983 },
+ { "csiso42jisc62261978", character_set_t::jis_c6226_1978 },
+ { "csiso47bsviewdata", character_set_t::bs_viewdata },
+ { "csiso49inis", character_set_t::inis },
+ { "csiso4unitedkingdom", character_set_t::bs_4730 },
+ { "csiso50inis8", character_set_t::inis_8 },
+ { "csiso51iniscyrillic", character_set_t::inis_cyrillic },
+ { "csiso54271981", character_set_t::iso_5427_1981 },
+ { "csiso5427cyrillic", character_set_t::iso_5427 },
+ { "csiso5428greek", character_set_t::iso_5428_1980 },
+ { "csiso57gb1988", character_set_t::gb_1988_80 },
+ { "csiso58gb231280", character_set_t::gb_2312_80 },
+ { "csiso60danishnorwegian", character_set_t::ns_4551_1 },
+ { "csiso60norwegian1", character_set_t::ns_4551_1 },
+ { "csiso61norwegian2", character_set_t::ns_4551_2 },
+ { "csiso646basic1983", character_set_t::iso_646_basic_1983 },
+ { "csiso646danish", character_set_t::ds_2089 },
+ { "csiso6937add", character_set_t::iso_6937_2_25 },
+ { "csiso69french", character_set_t::nf_z_62_010 },
+ { "csiso70videotexsupp1", character_set_t::videotex_suppl },
+ { "csiso84portuguese2", character_set_t::pt2 },
+ { "csiso85spanish2", character_set_t::es2 },
+ { "csiso86hungarian", character_set_t::msz_7795_3 },
+ { "csiso87jisx0208", character_set_t::jis_c6226_1983 },
+ { "csiso885913", character_set_t::iso_8859_13 },
+ { "csiso885914", character_set_t::iso_8859_14 },
+ { "csiso885915", character_set_t::iso_8859_15 },
+ { "csiso885916", character_set_t::iso_8859_16 },
+ { "csiso88596e", character_set_t::iso_8859_6_e },
+ { "csiso88596i", character_set_t::iso_8859_6_i },
+ { "csiso88598e", character_set_t::iso_8859_8_e },
+ { "csiso88598i", character_set_t::iso_8859_8_i },
+ { "csiso8859supp", character_set_t::iso_8859_supp },
+ { "csiso88greek7", character_set_t::greek7 },
+ { "csiso89asmo449", character_set_t::asmo_449 },
+ { "csiso90", character_set_t::iso_ir_90 },
+ { "csiso91jisc62291984a", character_set_t::jis_c6229_1984_a },
+ { "csiso92jisc62991984b", character_set_t::jis_c6229_1984_b },
+ { "csiso93jis62291984badd", character_set_t::jis_c6229_1984_b_add },
+ { "csiso94jis62291984hand", character_set_t::jis_c6229_1984_hand },
+ { "csiso95jis62291984handadd", character_set_t::jis_c6229_1984_hand_add },
+ { "csiso96jisc62291984kana", character_set_t::jis_c6229_1984_kana },
+ { "csiso99naplps", character_set_t::ansi_x3_110_1983 },
+ { "csisolatin1", character_set_t::iso_8859_1 },
+ { "csisolatin2", character_set_t::iso_8859_2 },
+ { "csisolatin3", character_set_t::iso_8859_3 },
+ { "csisolatin4", character_set_t::iso_8859_4 },
+ { "csisolatin5", character_set_t::iso_8859_9 },
+ { "csisolatin6", character_set_t::iso_8859_10 },
+ { "csisolatinarabic", character_set_t::iso_8859_6 },
+ { "csisolatincyrillic", character_set_t::iso_8859_5 },
+ { "csisolatingreek", character_set_t::iso_8859_7 },
+ { "csisolatinhebrew", character_set_t::iso_8859_8 },
+ { "csisotextcomm", character_set_t::iso_6937_2_add },
+ { "csjisencoding", character_set_t::jis_encoding },
+ { "cskoi7switched", character_set_t::koi7_switched },
+ { "cskoi8r", character_set_t::koi8_r },
+ { "cskoi8u", character_set_t::koi8_u },
+ { "csksc56011987", character_set_t::ks_c_5601_1987 },
+ { "csksc5636", character_set_t::ksc5636 },
+ { "cskz1048", character_set_t::kz_1048 },
+ { "csmacintosh", character_set_t::macintosh },
+ { "csmicrosoftpublishing", character_set_t::microsoft_publishing },
+ { "csmnem", character_set_t::mnem },
+ { "csmnemonic", character_set_t::mnemonic },
+ { "csn_369103", character_set_t::csn_369103 },
+ { "csnatsdano", character_set_t::nats_dano },
+ { "csnatsdanoadd", character_set_t::nats_dano_add },
+ { "csnatssefi", character_set_t::nats_sefi },
+ { "csnatssefiadd", character_set_t::nats_sefi_add },
+ { "csosdebcdicdf03irv", character_set_t::osd_ebcdic_df03_irv },
+ { "csosdebcdicdf041", character_set_t::osd_ebcdic_df04_1 },
+ { "csosdebcdicdf0415", character_set_t::osd_ebcdic_df04_15 },
+ { "cspc775baltic", character_set_t::ibm775 },
+ { "cspc850multilingual", character_set_t::ibm850 },
+ { "cspc862latinhebrew", character_set_t::ibm862 },
+ { "cspc8codepage437", character_set_t::ibm437 },
+ { "cspc8danishnorwegian", character_set_t::pc8_danish_norwegian },
+ { "cspc8turkish", character_set_t::pc8_turkish },
+ { "cspcp852", character_set_t::ibm852 },
+ { "csptcp154", character_set_t::ptcp154 },
+ { "csscsu", character_set_t::scsu },
+ { "csshiftjis", character_set_t::shift_jis },
+ { "cstis620", character_set_t::tis_620 },
+ { "cstscii", character_set_t::tscii },
+ { "csucs4", character_set_t::iso_10646_ucs_4 },
+ { "csunicode", character_set_t::iso_10646_ucs_2 },
+ { "csunicode11", character_set_t::unicode_1_1 },
+ { "csunicode11utf7", character_set_t::unicode_1_1_utf_7 },
+ { "csunicodeascii", character_set_t::iso_10646_ucs_basic },
+ { "csunicodeibm1261", character_set_t::iso_unicode_ibm_1261 },
+ { "csunicodeibm1264", character_set_t::iso_unicode_ibm_1264 },
+ { "csunicodeibm1265", character_set_t::iso_unicode_ibm_1265 },
+ { "csunicodeibm1268", character_set_t::iso_unicode_ibm_1268 },
+ { "csunicodeibm1276", character_set_t::iso_unicode_ibm_1276 },
+ { "csunicodejapanese", character_set_t::iso_10646_j_1 },
+ { "csunicodelatin1", character_set_t::iso_10646_unicode_latin1 },
+ { "csunknown8bit", character_set_t::unknown_8bit },
+ { "csusdk", character_set_t::us_dk },
+ { "csutf16", character_set_t::utf_16 },
+ { "csutf16be", character_set_t::utf_16be },
+ { "csutf16le", character_set_t::utf_16le },
+ { "csutf32", character_set_t::utf_32 },
+ { "csutf32be", character_set_t::utf_32be },
+ { "csutf32le", character_set_t::utf_32le },
+ { "csutf7", character_set_t::utf_7 },
+ { "csutf7imap", character_set_t::utf_7_imap },
+ { "csutf8", character_set_t::utf_8 },
+ { "csventurainternational", character_set_t::ventura_international },
+ { "csventuramath", character_set_t::ventura_math },
+ { "csventuraus", character_set_t::ventura_us },
+ { "csviqr", character_set_t::viqr },
+ { "csviscii", character_set_t::viscii },
+ { "cswindows1250", character_set_t::windows_1250 },
+ { "cswindows1251", character_set_t::windows_1251 },
+ { "cswindows1252", character_set_t::windows_1252 },
+ { "cswindows1253", character_set_t::windows_1253 },
+ { "cswindows1254", character_set_t::windows_1254 },
+ { "cswindows1255", character_set_t::windows_1255 },
+ { "cswindows1256", character_set_t::windows_1256 },
+ { "cswindows1257", character_set_t::windows_1257 },
+ { "cswindows1258", character_set_t::windows_1258 },
+ { "cswindows30latin1", character_set_t::iso_8859_1_windows_3_0_latin_1 },
+ { "cswindows31j", character_set_t::windows_31j },
+ { "cswindows31latin1", character_set_t::iso_8859_1_windows_3_1_latin_1 },
+ { "cswindows31latin2", character_set_t::iso_8859_2_windows_latin_2 },
+ { "cswindows31latin5", character_set_t::iso_8859_9_windows_latin_5 },
+ { "cswindows874", character_set_t::windows_874 },
+ { "cuba", character_set_t::nc_nc00_10_81 },
+ { "cyrillic", character_set_t::iso_8859_5 },
+ { "cyrillic-asian", character_set_t::ptcp154 },
+ { "de", character_set_t::din_66003 },
+ { "dec", character_set_t::dec_mcs },
+ { "dec-mcs", character_set_t::dec_mcs },
+ { "din_66003", character_set_t::din_66003 },
+ { "dk", character_set_t::ds_2089 },
+ { "dk-us", character_set_t::dk_us },
+ { "ds2089", character_set_t::ds_2089 },
+ { "ds_2089", character_set_t::ds_2089 },
+ { "e13b", character_set_t::iso_2033_1983 },
+ { "ebcdic-at-de", character_set_t::ebcdic_at_de },
+ { "ebcdic-at-de-a", character_set_t::ebcdic_at_de_a },
+ { "ebcdic-be", character_set_t::ibm274 },
+ { "ebcdic-br", character_set_t::ibm275 },
+ { "ebcdic-ca-fr", character_set_t::ebcdic_ca_fr },
+ { "ebcdic-cp-ar1", character_set_t::ibm420 },
+ { "ebcdic-cp-ar2", character_set_t::ibm918 },
+ { "ebcdic-cp-be", character_set_t::ibm500 },
+ { "ebcdic-cp-ca", character_set_t::ibm037 },
+ { "ebcdic-cp-ch", character_set_t::ibm500 },
+ { "ebcdic-cp-dk", character_set_t::ibm277 },
+ { "ebcdic-cp-es", character_set_t::ibm284 },
+ { "ebcdic-cp-fi", character_set_t::ibm278 },
+ { "ebcdic-cp-fr", character_set_t::ibm297 },
+ { "ebcdic-cp-gb", character_set_t::ibm285 },
+ { "ebcdic-cp-gr", character_set_t::ibm423 },
+ { "ebcdic-cp-he", character_set_t::ibm424 },
+ { "ebcdic-cp-is", character_set_t::ibm871 },
+ { "ebcdic-cp-it", character_set_t::ibm280 },
+ { "ebcdic-cp-nl", character_set_t::ibm037 },
+ { "ebcdic-cp-no", character_set_t::ibm277 },
+ { "ebcdic-cp-roece", character_set_t::ibm870 },
+ { "ebcdic-cp-se", character_set_t::ibm278 },
+ { "ebcdic-cp-tr", character_set_t::ibm905 },
+ { "ebcdic-cp-us", character_set_t::ibm037 },
+ { "ebcdic-cp-wt", character_set_t::ibm037 },
+ { "ebcdic-cp-yu", character_set_t::ibm870 },
+ { "ebcdic-cyrillic", character_set_t::ibm880 },
+ { "ebcdic-de-273+euro", character_set_t::ibm01141 },
+ { "ebcdic-dk-277+euro", character_set_t::ibm01142 },
+ { "ebcdic-dk-no", character_set_t::ebcdic_dk_no },
+ { "ebcdic-dk-no-a", character_set_t::ebcdic_dk_no_a },
+ { "ebcdic-es", character_set_t::ebcdic_es },
+ { "ebcdic-es-284+euro", character_set_t::ibm01145 },
+ { "ebcdic-es-a", character_set_t::ebcdic_es_a },
+ { "ebcdic-es-s", character_set_t::ebcdic_es_s },
+ { "ebcdic-fi-278+euro", character_set_t::ibm01143 },
+ { "ebcdic-fi-se", character_set_t::ebcdic_fi_se },
+ { "ebcdic-fi-se-a", character_set_t::ebcdic_fi_se_a },
+ { "ebcdic-fr", character_set_t::ebcdic_fr },
+ { "ebcdic-fr-297+euro", character_set_t::ibm01147 },
+ { "ebcdic-gb-285+euro", character_set_t::ibm01146 },
+ { "ebcdic-int", character_set_t::ibm038 },
+ { "ebcdic-international-500+euro", character_set_t::ibm01148 },
+ { "ebcdic-is-871+euro", character_set_t::ibm01149 },
+ { "ebcdic-it", character_set_t::ebcdic_it },
+ { "ebcdic-it-280+euro", character_set_t::ibm01144 },
+ { "ebcdic-jp-e", character_set_t::ibm281 },
+ { "ebcdic-jp-kana", character_set_t::ibm290 },
+ { "ebcdic-latin9--euro", character_set_t::ibm00924 },
+ { "ebcdic-no-277+euro", character_set_t::ibm01142 },
+ { "ebcdic-pt", character_set_t::ebcdic_pt },
+ { "ebcdic-se-278+euro", character_set_t::ibm01143 },
+ { "ebcdic-uk", character_set_t::ebcdic_uk },
+ { "ebcdic-us", character_set_t::ebcdic_us },
+ { "ebcdic-us-37+euro", character_set_t::ibm01140 },
+ { "ecma-114", character_set_t::iso_8859_6 },
+ { "ecma-118", character_set_t::iso_8859_7 },
+ { "ecma-cyrillic", character_set_t::ecma_cyrillic },
+ { "elot_928", character_set_t::iso_8859_7 },
+ { "es", character_set_t::es },
+ { "es2", character_set_t::es2 },
+ { "euc-jp", character_set_t::euc_jp },
+ { "euc-kr", character_set_t::euc_kr },
+ { "extended_unix_code_fixed_width_for_japanese", character_set_t::extended_unix_code_fixed_width_for_japanese },
+ { "extended_unix_code_packed_format_for_japanese", character_set_t::euc_jp },
+ { "fi", character_set_t::sen_850200_b },
+ { "fr", character_set_t::nf_z_62_010 },
+ { "gb", character_set_t::bs_4730 },
+ { "gb18030", character_set_t::gb18030 },
+ { "gb2312", character_set_t::gb2312 },
+ { "gb_1988-80", character_set_t::gb_1988_80 },
+ { "gb_2312-80", character_set_t::gb_2312_80 },
+ { "gbk", character_set_t::gbk },
+ { "gost_19768-74", character_set_t::gost_19768_74 },
+ { "greek", character_set_t::iso_8859_7 },
+ { "greek-ccitt", character_set_t::greek_ccitt },
+ { "greek7", character_set_t::greek7 },
+ { "greek7-old", character_set_t::greek7_old },
+ { "greek8", character_set_t::iso_8859_7 },
+ { "hebrew", character_set_t::iso_8859_8 },
+ { "hp-desktop", character_set_t::hp_desktop },
+ { "hp-legal", character_set_t::hp_legal },
+ { "hp-math8", character_set_t::hp_math8 },
+ { "hp-pi-font", character_set_t::hp_pi_font },
+ { "hp-roman8", character_set_t::hp_roman8 },
+ { "hu", character_set_t::msz_7795_3 },
+ { "hz-gb-2312", character_set_t::hz_gb_2312 },
+ { "ibm-1047", character_set_t::ibm1047 },
+ { "ibm-symbols", character_set_t::ibm_symbols },
+ { "ibm-thai", character_set_t::ibm_thai },
+ { "ibm00858", character_set_t::ibm00858 },
+ { "ibm00924", character_set_t::ibm00924 },
+ { "ibm01140", character_set_t::ibm01140 },
+ { "ibm01141", character_set_t::ibm01141 },
+ { "ibm01142", character_set_t::ibm01142 },
+ { "ibm01143", character_set_t::ibm01143 },
+ { "ibm01144", character_set_t::ibm01144 },
+ { "ibm01145", character_set_t::ibm01145 },
+ { "ibm01146", character_set_t::ibm01146 },
+ { "ibm01147", character_set_t::ibm01147 },
+ { "ibm01148", character_set_t::ibm01148 },
+ { "ibm01149", character_set_t::ibm01149 },
+ { "ibm037", character_set_t::ibm037 },
+ { "ibm038", character_set_t::ibm038 },
+ { "ibm1026", character_set_t::ibm1026 },
+ { "ibm1047", character_set_t::ibm1047 },
+ { "ibm273", character_set_t::ibm273 },
+ { "ibm274", character_set_t::ibm274 },
+ { "ibm275", character_set_t::ibm275 },
+ { "ibm277", character_set_t::ibm277 },
+ { "ibm278", character_set_t::ibm278 },
+ { "ibm280", character_set_t::ibm280 },
+ { "ibm281", character_set_t::ibm281 },
+ { "ibm284", character_set_t::ibm284 },
+ { "ibm285", character_set_t::ibm285 },
+ { "ibm290", character_set_t::ibm290 },
+ { "ibm297", character_set_t::ibm297 },
+ { "ibm367", character_set_t::us_ascii },
+ { "ibm420", character_set_t::ibm420 },
+ { "ibm423", character_set_t::ibm423 },
+ { "ibm424", character_set_t::ibm424 },
+ { "ibm437", character_set_t::ibm437 },
+ { "ibm500", character_set_t::ibm500 },
+ { "ibm775", character_set_t::ibm775 },
+ { "ibm819", character_set_t::iso_8859_1 },
+ { "ibm850", character_set_t::ibm850 },
+ { "ibm851", character_set_t::ibm851 },
+ { "ibm852", character_set_t::ibm852 },
+ { "ibm855", character_set_t::ibm855 },
+ { "ibm857", character_set_t::ibm857 },
+ { "ibm860", character_set_t::ibm860 },
+ { "ibm861", character_set_t::ibm861 },
+ { "ibm862", character_set_t::ibm862 },
+ { "ibm863", character_set_t::ibm863 },
+ { "ibm864", character_set_t::ibm864 },
+ { "ibm865", character_set_t::ibm865 },
+ { "ibm866", character_set_t::ibm866 },
+ { "ibm868", character_set_t::ibm868 },
+ { "ibm869", character_set_t::ibm869 },
+ { "ibm870", character_set_t::ibm870 },
+ { "ibm871", character_set_t::ibm871 },
+ { "ibm880", character_set_t::ibm880 },
+ { "ibm891", character_set_t::ibm891 },
+ { "ibm903", character_set_t::ibm903 },
+ { "ibm904", character_set_t::ibm904 },
+ { "ibm905", character_set_t::ibm905 },
+ { "ibm918", character_set_t::ibm918 },
+ { "iec_p27-1", character_set_t::iec_p27_1 },
+ { "inis", character_set_t::inis },
+ { "inis-8", character_set_t::inis_8 },
+ { "inis-cyrillic", character_set_t::inis_cyrillic },
+ { "invariant", character_set_t::invariant },
+ { "irv", character_set_t::iso_646_irv_1983 },
+ { "iso-10646", character_set_t::iso_10646_unicode_latin1 },
+ { "iso-10646-j-1", character_set_t::iso_10646_j_1 },
+ { "iso-10646-ucs-2", character_set_t::iso_10646_ucs_2 },
+ { "iso-10646-ucs-4", character_set_t::iso_10646_ucs_4 },
+ { "iso-10646-ucs-basic", character_set_t::iso_10646_ucs_basic },
+ { "iso-10646-unicode-latin1", character_set_t::iso_10646_unicode_latin1 },
+ { "iso-10646-utf-1", character_set_t::iso_10646_utf_1 },
+ { "iso-11548-1", character_set_t::iso_11548_1 },
+ { "iso-2022-cn", character_set_t::iso_2022_cn },
+ { "iso-2022-cn-ext", character_set_t::iso_2022_cn_ext },
+ { "iso-2022-jp", character_set_t::iso_2022_jp },
+ { "iso-2022-jp-2", character_set_t::iso_2022_jp_2 },
+ { "iso-2022-kr", character_set_t::iso_2022_kr },
+ { "iso-8859-1", character_set_t::iso_8859_1 },
+ { "iso-8859-1-windows-3.0-latin-1", character_set_t::iso_8859_1_windows_3_0_latin_1 },
+ { "iso-8859-1-windows-3.1-latin-1", character_set_t::iso_8859_1_windows_3_1_latin_1 },
+ { "iso-8859-10", character_set_t::iso_8859_10 },
+ { "iso-8859-11", character_set_t::tis_620 },
+ { "iso-8859-13", character_set_t::iso_8859_13 },
+ { "iso-8859-14", character_set_t::iso_8859_14 },
+ { "iso-8859-15", character_set_t::iso_8859_15 },
+ { "iso-8859-16", character_set_t::iso_8859_16 },
+ { "iso-8859-2", character_set_t::iso_8859_2 },
+ { "iso-8859-2-windows-latin-2", character_set_t::iso_8859_2_windows_latin_2 },
+ { "iso-8859-3", character_set_t::iso_8859_3 },
+ { "iso-8859-4", character_set_t::iso_8859_4 },
+ { "iso-8859-5", character_set_t::iso_8859_5 },
+ { "iso-8859-6", character_set_t::iso_8859_6 },
+ { "iso-8859-6-e", character_set_t::iso_8859_6_e },
+ { "iso-8859-6-i", character_set_t::iso_8859_6_i },
+ { "iso-8859-7", character_set_t::iso_8859_7 },
+ { "iso-8859-8", character_set_t::iso_8859_8 },
+ { "iso-8859-8-e", character_set_t::iso_8859_8_e },
+ { "iso-8859-8-i", character_set_t::iso_8859_8_i },
+ { "iso-8859-9", character_set_t::iso_8859_9 },
+ { "iso-8859-9-windows-latin-5", character_set_t::iso_8859_9_windows_latin_5 },
+ { "iso-celtic", character_set_t::iso_8859_14 },
+ { "iso-ir-10", character_set_t::sen_850200_b },
+ { "iso-ir-100", character_set_t::iso_8859_1 },
+ { "iso-ir-101", character_set_t::iso_8859_2 },
+ { "iso-ir-102", character_set_t::t_61_7bit },
+ { "iso-ir-103", character_set_t::t_61_8bit },
+ { "iso-ir-109", character_set_t::iso_8859_3 },
+ { "iso-ir-11", character_set_t::sen_850200_c },
+ { "iso-ir-110", character_set_t::iso_8859_4 },
+ { "iso-ir-111", character_set_t::ecma_cyrillic },
+ { "iso-ir-121", character_set_t::csa_z243_4_1985_1 },
+ { "iso-ir-122", character_set_t::csa_z243_4_1985_2 },
+ { "iso-ir-123", character_set_t::csa_z243_4_1985_gr },
+ { "iso-ir-126", character_set_t::iso_8859_7 },
+ { "iso-ir-127", character_set_t::iso_8859_6 },
+ { "iso-ir-128", character_set_t::t_101_g2 },
+ { "iso-ir-13", character_set_t::jis_c6220_1969_jp },
+ { "iso-ir-138", character_set_t::iso_8859_8 },
+ { "iso-ir-139", character_set_t::csn_369103 },
+ { "iso-ir-14", character_set_t::jis_c6220_1969_ro },
+ { "iso-ir-141", character_set_t::jus_i_b1_002 },
+ { "iso-ir-142", character_set_t::iso_6937_2_add },
+ { "iso-ir-143", character_set_t::iec_p27_1 },
+ { "iso-ir-144", character_set_t::iso_8859_5 },
+ { "iso-ir-146", character_set_t::jus_i_b1_003_serb },
+ { "iso-ir-147", character_set_t::jus_i_b1_003_mac },
+ { "iso-ir-148", character_set_t::iso_8859_9 },
+ { "iso-ir-149", character_set_t::ks_c_5601_1987 },
+ { "iso-ir-15", character_set_t::it },
+ { "iso-ir-150", character_set_t::greek_ccitt },
+ { "iso-ir-151", character_set_t::nc_nc00_10_81 },
+ { "iso-ir-152", character_set_t::iso_6937_2_25 },
+ { "iso-ir-153", character_set_t::gost_19768_74 },
+ { "iso-ir-154", character_set_t::iso_8859_supp },
+ { "iso-ir-155", character_set_t::iso_10367_box },
+ { "iso-ir-157", character_set_t::iso_8859_10 },
+ { "iso-ir-158", character_set_t::latin_lap },
+ { "iso-ir-159", character_set_t::jis_x0212_1990 },
+ { "iso-ir-16", character_set_t::pt },
+ { "iso-ir-17", character_set_t::es },
+ { "iso-ir-18", character_set_t::greek7_old },
+ { "iso-ir-19", character_set_t::latin_greek },
+ { "iso-ir-199", character_set_t::iso_8859_14 },
+ { "iso-ir-2", character_set_t::iso_646_irv_1983 },
+ { "iso-ir-21", character_set_t::din_66003 },
+ { "iso-ir-226", character_set_t::iso_8859_16 },
+ { "iso-ir-25", character_set_t::nf_z_62_010_1973 },
+ { "iso-ir-27", character_set_t::latin_greek_1 },
+ { "iso-ir-37", character_set_t::iso_5427 },
+ { "iso-ir-4", character_set_t::bs_4730 },
+ { "iso-ir-42", character_set_t::jis_c6226_1978 },
+ { "iso-ir-47", character_set_t::bs_viewdata },
+ { "iso-ir-49", character_set_t::inis },
+ { "iso-ir-50", character_set_t::inis_8 },
+ { "iso-ir-51", character_set_t::inis_cyrillic },
+ { "iso-ir-54", character_set_t::iso_5427_1981 },
+ { "iso-ir-55", character_set_t::iso_5428_1980 },
+ { "iso-ir-57", character_set_t::gb_1988_80 },
+ { "iso-ir-58", character_set_t::gb_2312_80 },
+ { "iso-ir-6", character_set_t::us_ascii },
+ { "iso-ir-60", character_set_t::ns_4551_1 },
+ { "iso-ir-61", character_set_t::ns_4551_2 },
+ { "iso-ir-69", character_set_t::nf_z_62_010 },
+ { "iso-ir-70", character_set_t::videotex_suppl },
+ { "iso-ir-8-1", character_set_t::nats_sefi },
+ { "iso-ir-8-2", character_set_t::nats_sefi_add },
+ { "iso-ir-84", character_set_t::pt2 },
+ { "iso-ir-85", character_set_t::es2 },
+ { "iso-ir-86", character_set_t::msz_7795_3 },
+ { "iso-ir-87", character_set_t::jis_c6226_1983 },
+ { "iso-ir-88", character_set_t::greek7 },
+ { "iso-ir-89", character_set_t::asmo_449 },
+ { "iso-ir-9-1", character_set_t::nats_dano },
+ { "iso-ir-9-2", character_set_t::nats_dano_add },
+ { "iso-ir-90", character_set_t::iso_ir_90 },
+ { "iso-ir-91", character_set_t::jis_c6229_1984_a },
+ { "iso-ir-92", character_set_t::jis_c6229_1984_b },
+ { "iso-ir-93", character_set_t::jis_c6229_1984_b_add },
+ { "iso-ir-94", character_set_t::jis_c6229_1984_hand },
+ { "iso-ir-95", character_set_t::jis_c6229_1984_hand_add },
+ { "iso-ir-96", character_set_t::jis_c6229_1984_kana },
+ { "iso-ir-98", character_set_t::iso_2033_1983 },
+ { "iso-ir-99", character_set_t::ansi_x3_110_1983 },
+ { "iso-unicode-ibm-1261", character_set_t::iso_unicode_ibm_1261 },
+ { "iso-unicode-ibm-1264", character_set_t::iso_unicode_ibm_1264 },
+ { "iso-unicode-ibm-1265", character_set_t::iso_unicode_ibm_1265 },
+ { "iso-unicode-ibm-1268", character_set_t::iso_unicode_ibm_1268 },
+ { "iso-unicode-ibm-1276", character_set_t::iso_unicode_ibm_1276 },
+ { "iso5427cyrillic1981", character_set_t::iso_5427_1981 },
+ { "iso646-ca", character_set_t::csa_z243_4_1985_1 },
+ { "iso646-ca2", character_set_t::csa_z243_4_1985_2 },
+ { "iso646-cn", character_set_t::gb_1988_80 },
+ { "iso646-cu", character_set_t::nc_nc00_10_81 },
+ { "iso646-de", character_set_t::din_66003 },
+ { "iso646-dk", character_set_t::ds_2089 },
+ { "iso646-es", character_set_t::es },
+ { "iso646-es2", character_set_t::es2 },
+ { "iso646-fi", character_set_t::sen_850200_b },
+ { "iso646-fr", character_set_t::nf_z_62_010 },
+ { "iso646-fr1", character_set_t::nf_z_62_010_1973 },
+ { "iso646-gb", character_set_t::bs_4730 },
+ { "iso646-hu", character_set_t::msz_7795_3 },
+ { "iso646-it", character_set_t::it },
+ { "iso646-jp", character_set_t::jis_c6220_1969_ro },
+ { "iso646-jp-ocr-b", character_set_t::jis_c6229_1984_b },
+ { "iso646-kr", character_set_t::ksc5636 },
+ { "iso646-no", character_set_t::ns_4551_1 },
+ { "iso646-no2", character_set_t::ns_4551_2 },
+ { "iso646-pt", character_set_t::pt },
+ { "iso646-pt2", character_set_t::pt2 },
+ { "iso646-se", character_set_t::sen_850200_b },
+ { "iso646-se2", character_set_t::sen_850200_c },
+ { "iso646-us", character_set_t::us_ascii },
+ { "iso646-yu", character_set_t::jus_i_b1_002 },
+ { "iso_10367-box", character_set_t::iso_10367_box },
+ { "iso_11548-1", character_set_t::iso_11548_1 },
+ { "iso_2033-1983", character_set_t::iso_2033_1983 },
+ { "iso_5427", character_set_t::iso_5427 },
+ { "iso_5427:1981", character_set_t::iso_5427_1981 },
+ { "iso_5428:1980", character_set_t::iso_5428_1980 },
+ { "iso_646.basic:1983", character_set_t::iso_646_basic_1983 },
+ { "iso_646.irv:1983", character_set_t::iso_646_irv_1983 },
+ { "iso_646.irv:1991", character_set_t::us_ascii },
+ { "iso_6937-2-25", character_set_t::iso_6937_2_25 },
+ { "iso_6937-2-add", character_set_t::iso_6937_2_add },
+ { "iso_8859-1", character_set_t::iso_8859_1 },
+ { "iso_8859-10:1992", character_set_t::iso_8859_10 },
+ { "iso_8859-14", character_set_t::iso_8859_14 },
+ { "iso_8859-14:1998", character_set_t::iso_8859_14 },
+ { "iso_8859-15", character_set_t::iso_8859_15 },
+ { "iso_8859-16", character_set_t::iso_8859_16 },
+ { "iso_8859-16:2001", character_set_t::iso_8859_16 },
+ { "iso_8859-1:1987", character_set_t::iso_8859_1 },
+ { "iso_8859-2", character_set_t::iso_8859_2 },
+ { "iso_8859-2:1987", character_set_t::iso_8859_2 },
+ { "iso_8859-3", character_set_t::iso_8859_3 },
+ { "iso_8859-3:1988", character_set_t::iso_8859_3 },
+ { "iso_8859-4", character_set_t::iso_8859_4 },
+ { "iso_8859-4:1988", character_set_t::iso_8859_4 },
+ { "iso_8859-5", character_set_t::iso_8859_5 },
+ { "iso_8859-5:1988", character_set_t::iso_8859_5 },
+ { "iso_8859-6", character_set_t::iso_8859_6 },
+ { "iso_8859-6-e", character_set_t::iso_8859_6_e },
+ { "iso_8859-6-i", character_set_t::iso_8859_6_i },
+ { "iso_8859-6:1987", character_set_t::iso_8859_6 },
+ { "iso_8859-7", character_set_t::iso_8859_7 },
+ { "iso_8859-7:1987", character_set_t::iso_8859_7 },
+ { "iso_8859-8", character_set_t::iso_8859_8 },
+ { "iso_8859-8-e", character_set_t::iso_8859_8_e },
+ { "iso_8859-8-i", character_set_t::iso_8859_8_i },
+ { "iso_8859-8:1988", character_set_t::iso_8859_8 },
+ { "iso_8859-9", character_set_t::iso_8859_9 },
+ { "iso_8859-9:1989", character_set_t::iso_8859_9 },
+ { "iso_8859-supp", character_set_t::iso_8859_supp },
+ { "iso_9036", character_set_t::asmo_449 },
+ { "iso_tr_11548-1", character_set_t::iso_11548_1 },
+ { "it", character_set_t::it },
+ { "jis_c6220-1969", character_set_t::jis_c6220_1969_jp },
+ { "jis_c6220-1969-jp", character_set_t::jis_c6220_1969_jp },
+ { "jis_c6220-1969-ro", character_set_t::jis_c6220_1969_ro },
+ { "jis_c6226-1978", character_set_t::jis_c6226_1978 },
+ { "jis_c6226-1983", character_set_t::jis_c6226_1983 },
+ { "jis_c6229-1984-a", character_set_t::jis_c6229_1984_a },
+ { "jis_c6229-1984-b", character_set_t::jis_c6229_1984_b },
+ { "jis_c6229-1984-b-add", character_set_t::jis_c6229_1984_b_add },
+ { "jis_c6229-1984-hand", character_set_t::jis_c6229_1984_hand },
+ { "jis_c6229-1984-hand-add", character_set_t::jis_c6229_1984_hand_add },
+ { "jis_c6229-1984-kana", character_set_t::jis_c6229_1984_kana },
+ { "jis_encoding", character_set_t::jis_encoding },
+ { "jis_x0201", character_set_t::jis_x0201 },
+ { "jis_x0208-1983", character_set_t::jis_c6226_1983 },
+ { "jis_x0212-1990", character_set_t::jis_x0212_1990 },
+ { "jp", character_set_t::jis_c6220_1969_ro },
+ { "jp-ocr-a", character_set_t::jis_c6229_1984_a },
+ { "jp-ocr-b", character_set_t::jis_c6229_1984_b },
+ { "jp-ocr-b-add", character_set_t::jis_c6229_1984_b_add },
+ { "jp-ocr-hand", character_set_t::jis_c6229_1984_hand },
+ { "jp-ocr-hand-add", character_set_t::jis_c6229_1984_hand_add },
+ { "js", character_set_t::jus_i_b1_002 },
+ { "jus_i.b1.002", character_set_t::jus_i_b1_002 },
+ { "jus_i.b1.003-mac", character_set_t::jus_i_b1_003_mac },
+ { "jus_i.b1.003-serb", character_set_t::jus_i_b1_003_serb },
+ { "katakana", character_set_t::jis_c6220_1969_jp },
+ { "koi7-switched", character_set_t::koi7_switched },
+ { "koi8-e", character_set_t::ecma_cyrillic },
+ { "koi8-r", character_set_t::koi8_r },
+ { "koi8-u", character_set_t::koi8_u },
+ { "korean", character_set_t::ks_c_5601_1987 },
+ { "ks_c_5601-1987", character_set_t::ks_c_5601_1987 },
+ { "ks_c_5601-1989", character_set_t::ks_c_5601_1987 },
+ { "ksc5636", character_set_t::ksc5636 },
+ { "ksc_5601", character_set_t::ks_c_5601_1987 },
+ { "kz-1048", character_set_t::kz_1048 },
+ { "l1", character_set_t::iso_8859_1 },
+ { "l10", character_set_t::iso_8859_16 },
+ { "l2", character_set_t::iso_8859_2 },
+ { "l3", character_set_t::iso_8859_3 },
+ { "l4", character_set_t::iso_8859_4 },
+ { "l5", character_set_t::iso_8859_9 },
+ { "l6", character_set_t::iso_8859_10 },
+ { "l8", character_set_t::iso_8859_14 },
+ { "lap", character_set_t::latin_lap },
+ { "latin-9", character_set_t::iso_8859_15 },
+ { "latin-greek", character_set_t::latin_greek },
+ { "latin-greek-1", character_set_t::latin_greek_1 },
+ { "latin-lap", character_set_t::latin_lap },
+ { "latin1", character_set_t::iso_8859_1 },
+ { "latin1-2-5", character_set_t::iso_8859_supp },
+ { "latin10", character_set_t::iso_8859_16 },
+ { "latin2", character_set_t::iso_8859_2 },
+ { "latin3", character_set_t::iso_8859_3 },
+ { "latin4", character_set_t::iso_8859_4 },
+ { "latin5", character_set_t::iso_8859_9 },
+ { "latin6", character_set_t::iso_8859_10 },
+ { "latin8", character_set_t::iso_8859_14 },
+ { "mac", character_set_t::macintosh },
+ { "macedonian", character_set_t::jus_i_b1_003_mac },
+ { "macintosh", character_set_t::macintosh },
+ { "microsoft-publishing", character_set_t::microsoft_publishing },
+ { "mnem", character_set_t::mnem },
+ { "mnemonic", character_set_t::mnemonic },
+ { "ms936", character_set_t::gbk },
+ { "ms_kanji", character_set_t::shift_jis },
+ { "msz_7795.3", character_set_t::msz_7795_3 },
+ { "naplps", character_set_t::ansi_x3_110_1983 },
+ { "nats-dano", character_set_t::nats_dano },
+ { "nats-dano-add", character_set_t::nats_dano_add },
+ { "nats-sefi", character_set_t::nats_sefi },
+ { "nats-sefi-add", character_set_t::nats_sefi_add },
+ { "nc_nc00-10:81", character_set_t::nc_nc00_10_81 },
+ { "nf_z_62-010", character_set_t::nf_z_62_010 },
+ { "nf_z_62-010_(1973)", character_set_t::nf_z_62_010_1973 },
+ { "no", character_set_t::ns_4551_1 },
+ { "no2", character_set_t::ns_4551_2 },
+ { "ns_4551-1", character_set_t::ns_4551_1 },
+ { "ns_4551-2", character_set_t::ns_4551_2 },
+ { "osd_ebcdic_df03_irv", character_set_t::osd_ebcdic_df03_irv },
+ { "osd_ebcdic_df04_1", character_set_t::osd_ebcdic_df04_1 },
+ { "osd_ebcdic_df04_15", character_set_t::osd_ebcdic_df04_15 },
+ { "pc-multilingual-850+euro", character_set_t::ibm00858 },
+ { "pc8-danish-norwegian", character_set_t::pc8_danish_norwegian },
+ { "pc8-turkish", character_set_t::pc8_turkish },
+ { "pt", character_set_t::pt },
+ { "pt154", character_set_t::ptcp154 },
+ { "pt2", character_set_t::pt2 },
+ { "ptcp154", character_set_t::ptcp154 },
+ { "r8", character_set_t::hp_roman8 },
+ { "ref", character_set_t::iso_646_basic_1983 },
+ { "rk1048", character_set_t::kz_1048 },
+ { "roman8", character_set_t::hp_roman8 },
+ { "scsu", character_set_t::scsu },
+ { "se", character_set_t::sen_850200_b },
+ { "se2", character_set_t::sen_850200_c },
+ { "sen_850200_b", character_set_t::sen_850200_b },
+ { "sen_850200_c", character_set_t::sen_850200_c },
+ { "serbian", character_set_t::jus_i_b1_003_serb },
+ { "shift_jis", character_set_t::shift_jis },
+ { "st_sev_358-88", character_set_t::gost_19768_74 },
+ { "strk1048-2002", character_set_t::kz_1048 },
+ { "t.101-g2", character_set_t::t_101_g2 },
+ { "t.61", character_set_t::t_61_8bit },
+ { "t.61-7bit", character_set_t::t_61_7bit },
+ { "t.61-8bit", character_set_t::t_61_8bit },
+ { "tis-620", character_set_t::tis_620 },
+ { "tscii", character_set_t::tscii },
+ { "uk", character_set_t::bs_4730 },
+ { "unicode-1-1", character_set_t::unicode_1_1 },
+ { "unicode-1-1-utf-7", character_set_t::unicode_1_1_utf_7 },
+ { "unknown-8bit", character_set_t::unknown_8bit },
+ { "us", character_set_t::us_ascii },
+ { "us-ascii", character_set_t::us_ascii },
+ { "us-dk", character_set_t::us_dk },
+ { "utf-16", character_set_t::utf_16 },
+ { "utf-16be", character_set_t::utf_16be },
+ { "utf-16le", character_set_t::utf_16le },
+ { "utf-32", character_set_t::utf_32 },
+ { "utf-32be", character_set_t::utf_32be },
+ { "utf-32le", character_set_t::utf_32le },
+ { "utf-7", character_set_t::utf_7 },
+ { "utf-7-imap", character_set_t::utf_7_imap },
+ { "utf-8", character_set_t::utf_8 },
+ { "ventura-international", character_set_t::ventura_international },
+ { "ventura-math", character_set_t::ventura_math },
+ { "ventura-us", character_set_t::ventura_us },
+ { "videotex-suppl", character_set_t::videotex_suppl },
+ { "viqr", character_set_t::viqr },
+ { "viscii", character_set_t::viscii },
+ { "windows-1250", character_set_t::windows_1250 },
+ { "windows-1251", character_set_t::windows_1251 },
+ { "windows-1252", character_set_t::windows_1252 },
+ { "windows-1253", character_set_t::windows_1253 },
+ { "windows-1254", character_set_t::windows_1254 },
+ { "windows-1255", character_set_t::windows_1255 },
+ { "windows-1256", character_set_t::windows_1256 },
+ { "windows-1257", character_set_t::windows_1257 },
+ { "windows-1258", character_set_t::windows_1258 },
+ { "windows-31j", character_set_t::windows_31j },
+ { "windows-874", character_set_t::windows_874 },
+ { "windows-936", character_set_t::gbk },
+ { "x0201", character_set_t::jis_x0201 },
+ { "x0201-7", character_set_t::jis_c6220_1969_jp },
+ { "x0208", character_set_t::jis_c6226_1983 },
+ { "x0212", character_set_t::jis_x0212_1990 },
+ { "yu", character_set_t::jus_i_b1_002 },
+};const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), character_set_t::unspecified);
+ return mt;
+}
+
+} // namespace charset
+
+} // anonymous namespace
+
+dump_format_t to_dump_format_enum(std::string_view s)
+{
+ return dump_format::get().find(s);
+}
+
+character_set_t to_character_set(std::string_view s)
+{
+ // Convert the source encoding string to all lower-case first.
+ std::string val_lower{s};
+ std::transform(val_lower.begin(), val_lower.end(), val_lower.begin(),
+ [](unsigned char c)
+ {
+ return std::tolower(c);
+ }
+ );
+
+ return charset::get().find(val_lower);
+}
+
+std::vector<std::pair<std::string_view, dump_format_t>> get_dump_format_entries()
+{
+ std::vector<std::pair<std::string_view, dump_format_t>> ret;
+ for (const auto& e : dump_format::entries)
+ ret.emplace_back(e.key, e.value);
+
+ return ret;
+}
+
+std::ostream& operator<< (std::ostream& os, const length_t& v)
+{
+ os << v.to_string();
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const date_time_t& v)
+{
+ os << v.to_string();
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, format_t v)
+{
+ static const char* values[] = {
+ "unknown",
+ "ods",
+ "xlsx",
+ "gnumeric",
+ "xls-xml",
+ "csv"
+ };
+
+ size_t vi = static_cast<std::underlying_type_t<format_t>>(v);
+ size_t n = std::size(values);
+
+ if (vi >= n)
+ os << "???";
+ else
+ os << values[vi];
+
+ return os;
+}
+
+const std::size_t INDEX_NOT_FOUND = std::numeric_limits<size_t>::max();
+const xmlns_id_t XMLNS_UNKNOWN_ID = nullptr;
+const xml_token_t XML_UNKNOWN_TOKEN = 0;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/types_test.cpp b/src/parser/types_test.cpp
new file mode 100644
index 0000000..ae22fdd
--- /dev/null
+++ b/src/parser/types_test.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/types.hpp>
+
+void test_character_set_t()
+{
+ orcus::test::stack_printer __sp__(__func__);
+
+ using orcus::character_set_t;
+
+ struct test_case
+ {
+ std::string_view input;
+ character_set_t expected;
+ };
+
+ constexpr test_case tests[] = {
+ { "utf-8", character_set_t::utf_8 },
+ { "UTF-8", character_set_t::utf_8 },
+ { "EUC-JP", character_set_t::euc_jp },
+ { "GBK", character_set_t::gbk },
+ { "Shift_JIS", character_set_t::shift_jis },
+ { "MS_Kanji", character_set_t::shift_jis },
+ { "csShiftJIS", character_set_t::shift_jis },
+ { "GB2312", character_set_t::gb2312 },
+ };
+
+ for (const auto& test : tests)
+ {
+ assert(orcus::to_character_set(test.input) == test.expected);
+ }
+}
+
+int main()
+{
+ test_character_set_t();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/utf8.cpp b/src/parser/utf8.cpp
new file mode 100644
index 0000000..e02d224
--- /dev/null
+++ b/src/parser/utf8.cpp
@@ -0,0 +1,524 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "utf8.hpp"
+
+#include <cassert>
+#include <stdexcept>
+#include <limits>
+
+// https://en.wikipedia.org/wiki/UTF-8#Encoding
+// https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-NameStartChar
+
+namespace orcus {
+
+namespace {
+
+bool valid_second_byte(uint8_t b)
+{
+ return (b & 0xC0) == 0x80;
+}
+
+bool parse_1b_start_char(uint8_t c1)
+{
+ if (c1 == '_')
+ return true;
+
+ if ('a' <= c1 && c1 <= 'z')
+ return true;
+
+ if ('A' <= c1 && c1 <= 'Z')
+ return true;
+
+ return false;
+}
+
+bool parse_1b_second_char(uint8_t c1)
+{
+ if (c1 == '-' || c1 == '.')
+ return true;
+
+ if ('0' <= c1 && c1 <= '9')
+ return true;
+
+ return false;
+}
+
+// [ #xC0- #xD6]: C3 80 -> C3 96
+// [ #xD8- #xF6]: C3 98 -> C3 B6
+// [ #xF8-#x2FF]: C3 B8 -> CB BF
+// [#x370-#x37D]: CD B0 -> CD BD
+//
+// [#x37F-#x1FFF]: (split)
+// [#x37F-#x07FF]: CD BF -> DF BF
+//
+bool parse_2b_start_char(uint8_t c1, uint8_t c2)
+{
+ if (c1 == 0xC3)
+ {
+ if (0x80 <= c2 && c2 <= 0x96)
+ return true;
+
+ if (0x98 <= c2 && c2 <= 0xB6)
+ return true;
+
+ if (0xB8 <= c2)
+ return true;
+ }
+
+ // C4 80 -> CB BF
+ if (0xC4 <= c1 && c1 <= 0xCB)
+ return 0x80 <= c2 && c2 <= 0xBF;
+
+ // CD B0 -> CD BD
+ // CD BF -> DF BF
+
+ if (c1 == 0xCD)
+ {
+ if (0xB0 <= c2 && c2 <= 0xBD)
+ return true;
+
+ return c2 == 0xBF;
+ }
+
+ // CE xx -> DF xx
+ return 0xCE <= c1 && c1 <= 0xDF;
+}
+
+// #xB7: C2 B7
+// [#x0300-#x036F]: CC 80 -> CD AF
+bool parse_2b_second_char(uint8_t c1, uint8_t c2)
+{
+ // C2 B7
+ if (c1 == 0xC2)
+ return c2 == 0xB7;
+
+ // CC 80 -> CD AF
+ // - CC xx
+ // - CD xx -> CD AF
+
+ if (c1 == 0xCC)
+ return true;
+
+ if (c1 == 0xCD)
+ return c2 <= 0xAF;
+
+ return false;
+}
+
+// [#x800-#x1FFF]: E0 A0 80 -> E1 BF BF
+//
+// [#x200C-#x200D]: E2 80 8C -> E2 80 8D
+// [#x2070-#x218F]: E2 81 B0 -> E2 86 8F
+// [#x2C00-#x2FEF]: E2 B0 80 -> E2 BF AF
+// [#x3001-#xD7FF]: E3 80 81 -> ED 9F BF
+// [#xF900-#xFDCF]: EF A4 80 -> EF B7 8F
+// [#xFDF0-#xFFFD]: EF B7 B0 -> EF BF BD
+bool parse_3b_start_char(uint8_t c1, uint8_t c2, uint8_t c3)
+{
+ // E0 A0 80 -> E1 BF BF
+ // - E0 A0 80 -> E0 BF BF
+ // - E1 xx xx
+
+ if (c1 == 0xE0)
+ {
+ // A0 80 -> BF BF
+ return (0xA0 <= c2 && c2 <= 0xBF && 0x80 <= c3 && c3 <= 0xBF);
+ }
+
+ if (c1 == 0xE1)
+ // entire E1 xx xx range is valid.
+ return true;
+
+ if (c1 == 0xE2)
+ {
+ // E2 80 8C -> E2 80 8D
+ // E2 81 B0 -> E2 86 8F
+ // E2 B0 80 -> E2 BF AF
+
+ if (c2 == 0x80)
+ // 8C -> 8D
+ return c3 == 0x8C || c3 == 0x8D;
+
+ // 81 B0 -> 86 8F
+ if (c2 == 0x81)
+ return c3 >= 0xB0;
+
+ if (0x82 <= c2 && c2 <= 0x85)
+ return true;
+
+ if (c2 == 0x86)
+ return c3 <= 0x8F;
+
+ // B0 80 -> BF AF
+ if (0xB0 <= c2 && c2 <= 0xBE)
+ return true;
+
+ if (c2 == 0xBF)
+ return c3 <= 0xAF;
+ }
+
+ // E3 80 81 -> ED 9F BF
+ // - E3 80 81 -> E3 80 BF
+ // - E3 81 xx
+ // - E4 xx xx -> EC xx xx
+ // - ED xx xx -> ED 9F xx
+ if (c1 == 0xE3)
+ {
+ if (c2 == 0x80)
+ return c3 >= 0x81;
+
+ return 0x81 <= c2;
+ }
+
+ if (0xE4 <= c1 && c1 <= 0xEC)
+ return true;
+
+ if (c1 == 0xED)
+ return c2 <= 0x9F;
+
+ // EF A4 80 -> EF B7 8F
+ // - EF A4 xx
+ // - EF A5 xx -> EF B6 xx
+ // - EF B7 xx -> EF B7 8F
+ // EF B7 B0 -> EF BF BD
+ // - EF B7 B0 -> EF B7 xx
+ // - EF B8 xx -> EF BE xx
+ // - EF BF xx -> EF BF BD
+ if (c1 == 0xEF)
+ {
+ if (c2 == 0xA4)
+ return true;
+
+ if (0xA5 <= c2 && c2 <= 0xB6)
+ return true;
+
+ if (c2 == 0xB7)
+ {
+ if (c3 <= 0x8F)
+ return true;
+
+ return 0xB0 <= c3;
+ }
+
+ if (0xB8 <= c2 && c2 <= 0xBE)
+ return true;
+
+ if (c2 == 0xBF)
+ return c3 <= 0xBD;
+ }
+
+ return false;
+}
+
+// [#x203F-#x2040]: E2 80 BF -> E2 81 80
+bool parse_3b_second_char(uint8_t c1, uint8_t c2, uint8_t c3)
+{
+ if (c1 != 0xE2)
+ return false;
+
+ if (c2 == 0x80)
+ return c3 == 0xBF;
+
+ if (c2 == 0x81)
+ return c3 == 0x80;
+
+ return false;
+}
+
+// [#x10000-#xEFFFF]: F0 90 80 80 -> F3 AF BF BF
+bool parse_4b_char(uint8_t c1, uint8_t c2, uint8_t /*c3*/, uint8_t /*c4*/)
+{
+ // F0 90 80 80 -> F3 AF BF BF
+ // - F0 90 xx xx -> F0 xx xx xx
+ // - F1 xx xx xx -> F2 xx xx xx
+ // - F3 xx xx xx -> F3 AF xx xx
+ if (c1 == 0xF0)
+ return 0x90 <= c2;
+
+ if (0xF1 <= c1 && c1 <= 0xF2)
+ return true;
+
+ if (c1 == 0xF3)
+ return c2 <= 0xAF;
+
+ return false;
+}
+
+uint8_t calc_encoded_length(uint32_t cp)
+{
+ if (cp <= 0x7F)
+ return 1;
+
+ if (0x80 <= cp && cp <= 0x7FF)
+ return 2;
+
+ if (0x800 <= cp && cp <= 0xFFFF)
+ return 3;
+
+ if (0x10000 <= cp && cp <= 0x10FFFF)
+ return 4;
+
+ throw std::runtime_error("invalid utf-8 range.");
+}
+
+// input must be less than or equal to 0x7FF
+//
+// b1: 0b110xxxxx (5)
+// b2: 0b10xxxxxx (6)
+std::vector<char> encode_2b(uint32_t cp)
+{
+ assert(cp <= 0x7FF);
+
+ // Get the lowest 6 bits
+ char low = (cp & 0x3F);
+ low |= 0x80;
+
+ // Get the next 5 bits
+ cp = cp >> 6;
+ char high = (cp & 0x1F);
+ high |= 0xC0;
+
+ std::vector<char> ret = { high, low };
+ return ret;
+}
+
+// input must be less than or equal to 0xFFFF
+//
+// b1: 0b1110xxxx (4)
+// b2: 0b10xxxxxx (6)
+// b3: 0b10xxxxxx (6)
+std::vector<char> encode_3b(uint32_t cp)
+{
+ assert(cp <= 0xFFFF);
+
+ // Get the lowest 6 bits
+ char low = (cp & 0x3F);
+ low |= 0x80;
+ cp = cp >> 6;
+
+ // Get the middle 6 bits
+ char mid = (cp & 0x3F);
+ mid |= 0x80;
+ cp = cp >> 6;
+
+ // Get the next 4 bits
+ char high = (cp & 0x0F);
+ high |= 0xE0;
+
+ std::vector<char> ret = { high, mid, low };
+ return ret;
+}
+
+// input must be less than or equal to 0x10FFFF
+//
+// b1: 0b11110xxx (3)
+// b2: 0b10xxxxxx (6)
+// b3: 0b10xxxxxx (6)
+// b4: 0b10xxxxxx (6)
+std::vector<char> encode_4b(uint32_t cp)
+{
+ assert(cp <= 0x10FFFF);
+
+ // Get the lowest 6 bits
+ char low = (cp & 0x3F);
+ low |= 0x80;
+ cp = cp >> 6;
+
+ // Get the next 6 bits
+ char mid1 = (cp & 0x3F);
+ mid1 |= 0x80;
+ cp = cp >> 6;
+
+ // Get the next 6 bits
+ char mid2 = (cp & 0x3F);
+ mid2 |= 0x80;
+ cp = cp >> 6;
+
+ // Get the next 3 bits
+ char high = (cp & 0x07);
+ high |= 0xF0;
+
+ std::vector<char> ret = { high, mid2, mid1, low };
+ return ret;
+}
+
+} // anonymous namespace
+
+const char* parse_utf8_xml_name_start_char(const char* p, const char* p_end)
+{
+ size_t n_remaining = p_end - p;
+ if (!n_remaining)
+ return p;
+
+ uint8_t n_bytes = calc_utf8_byte_length(*p);
+
+ switch (n_bytes)
+ {
+ case 1:
+ return parse_1b_start_char(*p) ? p + 1 : p;
+ case 2:
+ {
+ if (n_remaining < 2)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+
+ if (!valid_second_byte(c2))
+ return p;
+
+ return parse_2b_start_char(c1, c2) ? p + 2 : p;
+ }
+ case 3:
+ {
+ if (n_remaining < 3)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+ uint8_t c3 = p[2];
+
+ if (!valid_second_byte(c2) || !valid_second_byte(c3))
+ return p;
+
+ return parse_3b_start_char(c1, c2, c3) ? p + 3 : p;
+ }
+ case 4:
+ {
+ if (n_remaining < 4)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+ uint8_t c3 = p[2];
+ uint8_t c4 = p[3];
+
+ if (!valid_second_byte(c2) || !valid_second_byte(c3) || !valid_second_byte(c4))
+ return p;
+
+ return parse_4b_char(c1, c2, c3, c4) ? p + 4 : p;
+ }
+ }
+
+ return p;
+}
+
+const char* parse_utf8_xml_name_char(const char* p, const char* p_end)
+{
+ size_t n_remaining = p_end - p;
+ if (!n_remaining)
+ return p;
+
+ uint8_t n_bytes = calc_utf8_byte_length(*p);
+
+ switch (n_bytes)
+ {
+ case 1:
+ {
+ if (parse_1b_start_char(*p))
+ return p + 1;
+
+ return parse_1b_second_char(*p) ? p + 1 : p;
+ }
+ case 2:
+ {
+ if (n_remaining < 2)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+
+ if (!valid_second_byte(c2))
+ return p;
+
+ if (parse_2b_start_char(c1, c2))
+ return p + 2;
+
+ return parse_2b_second_char(c1, c2) ? p + 2 : p;
+ }
+ case 3:
+ {
+ if (n_remaining < 3)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+ uint8_t c3 = p[2];
+
+ if (!valid_second_byte(c2) || !valid_second_byte(c3))
+ return p;
+
+ if (parse_3b_start_char(c1, c2, c3))
+ return p + 3;
+
+ return parse_3b_second_char(c1, c2, c3) ? p + 3 : p;
+ }
+ case 4:
+ {
+ if (n_remaining < 4)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+ uint8_t c3 = p[2];
+ uint8_t c4 = p[3];
+
+ if (!valid_second_byte(c2) || !valid_second_byte(c3) || !valid_second_byte(c4))
+ return p;
+
+ return parse_4b_char(c1, c2, c3, c4) ? p + 4 : p;
+ }
+ }
+
+ return p;
+}
+
+std::vector<char> encode_utf8(uint32_t cp)
+{
+ uint8_t n_encoded = calc_encoded_length(cp);
+
+ switch (n_encoded)
+ {
+ case 1:
+ // no conversion
+ return std::vector<char>(1, cp);
+ case 2:
+ return encode_2b(cp);
+ case 3:
+ return encode_3b(cp);
+ case 4:
+ return encode_4b(cp);
+ }
+
+ throw std::logic_error("this should never be reached.");
+}
+
+uint8_t calc_utf8_byte_length(uint8_t c1)
+{
+ if ((c1 & 0x80) == 0x00)
+ // highest bit is not set.
+ return 1;
+
+ if ((c1 & 0xE0) == 0xC0)
+ // highest 3 bits are 110.
+ return 2;
+
+ if ((c1 & 0xF0) == 0xE0)
+ // highest 4 bits are 1110.
+ return 3;
+
+ if ((c1 & 0xFC) == 0xF0)
+ // highest 5 bits are 11110.
+ return 4;
+
+ return std::numeric_limits<uint8_t>::max();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/utf8.hpp b/src/parser/utf8.hpp
new file mode 100644
index 0000000..01457de
--- /dev/null
+++ b/src/parser/utf8.hpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PARSER_UTF8_HPP
+#define INCLUDED_ORCUS_PARSER_UTF8_HPP
+
+#include <vector>
+#include <cstdint>
+
+namespace orcus {
+
+const char* parse_utf8_xml_name_start_char(const char* p, const char* p_end);
+
+const char* parse_utf8_xml_name_char(const char* p, const char* p_end);
+
+std::vector<char> encode_utf8(uint32_t cp);
+
+uint8_t calc_utf8_byte_length(uint8_t c1);
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/utf8_test.cpp b/src/parser/utf8_test.cpp
new file mode 100644
index 0000000..88dcd3e
--- /dev/null
+++ b/src/parser/utf8_test.cpp
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "utf8.hpp"
+
+#include <iostream>
+#include <vector>
+#include <string>
+#include <cassert>
+#include <functional>
+#include <iomanip>
+
+using namespace orcus;
+using std::cout;
+using std::endl;
+
+struct cp_range_t
+{
+ uint32_t lower;
+ uint32_t upper;
+ bool valid;
+};
+
+using parse_func_t = std::function<const char*(const char*, const char*)>;
+
+bool check_cp_ranges(parse_func_t parse, std::vector<cp_range_t> ranges)
+{
+ for (const cp_range_t& range : ranges)
+ {
+ for (uint32_t cp = range.lower; cp <= range.upper; ++cp)
+ {
+ std::vector<char> buf;
+
+ try
+ {
+ buf = encode_utf8(cp);
+ }
+ catch (const std::exception& e)
+ {
+ cout << "failed to encode 0x" << std::hex << std::uppercase << cp
+ << " as utf-8: " << e.what() << endl;
+ return false;
+ }
+
+ const char* p = buf.data();
+ const char* p_end = p + buf.size();
+ const char* ret = parse(p, p_end);
+
+ if ((ret == p_end) != range.valid)
+ {
+ cout << "failed to parse 0x" << std::hex << std::uppercase << cp
+ << " (utf-8:";
+
+ for (char b : buf)
+ cout << ' ' << short(0xFF & b);
+ cout << ")" << endl;
+ cout << "expected to be " << (range.valid ? "valid" : "invalid")
+ << ", but was " << (range.valid ? "invalid" : "valid") << endl;
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void test_xml_name_start_char()
+{
+ bool res = check_cp_ranges(
+ parse_utf8_xml_name_start_char,
+ {
+ { 0x00, 0x40, false },
+ { 'A', 'Z', true },
+ { '[', '^', false },
+ { '_', '_', true },
+ { '`', '`', false },
+ { 'a', 'z', true },
+ { '{', 0xBF, false },
+ { 0xC0, 0xD6, true },
+ { 0xD7, 0xD7, false },
+ { 0xD8, 0xF6, true },
+ { 0xF7, 0xF7, false },
+ { 0xF8, 0x2FF, true },
+ { 0x300, 0x36F, false },
+ { 0x370, 0x37D, true },
+ { 0x37E, 0x37E, false },
+ { 0x37F, 0x1FFF, true },
+ { 0x2000, 0x200B, false },
+ { 0x200C, 0x200D, true },
+ { 0x200E, 0x206F, false },
+ { 0x2070, 0x218F, true },
+ { 0x2190, 0x2BFF, false },
+ { 0x2C00, 0x2FEF, true },
+ { 0x2FF0, 0x3000, false },
+ { 0x3001, 0xD7FF, true },
+ { 0xD800, 0xF8FF, false },
+ { 0xF900, 0xFDCF, true },
+ { 0xFDD0, 0xFDEF, false },
+ { 0xFDF0, 0xFFFD, true },
+ { 0xFFFE, 0xFFFF, false },
+ { 0x10000, 0xEFFFF, true },
+ { 0xF0000, 0xF0000, false }, // just check one byte past last valid byte.
+ }
+ );
+ assert(res);
+}
+
+void test_xml_name_char()
+{
+ bool res = check_cp_ranges(
+ parse_utf8_xml_name_char,
+ {
+ { 0x00, ',', false },
+ { '-', '.', true }, // 0x2D - 0x2E
+ { '/', '/', false },
+ { '0', '9', true },
+ { ':', '@', false },
+ { 'A', 'Z', true },
+ { '[', '^', false },
+ { '_', '_', true }, // 0x5F
+ { '`', '`', false },
+ { 'a', 'z', true },
+ { '{', 0xB6, false },
+ { 0xB7, 0xB7, true },
+ { 0xB8, 0xBF, false },
+ { 0xC0, 0xD6, true },
+ { 0xD7, 0xD7, false },
+ { 0xD8, 0xF6, true },
+ { 0xF7, 0xF7, false },
+ { 0xF8, 0x2FF, true },
+ { 0x300, 0x36F, true },
+ { 0x370, 0x37D, true },
+ { 0x37E, 0x37E, false },
+ { 0x37F, 0x1FFF, true },
+ { 0x2000, 0x200B, false },
+ { 0x200C, 0x200D, true },
+ { 0x200E, 0x203E, false },
+ { 0x203F, 0x2040, true },
+ { 0x2041, 0x206F, false },
+ { 0x2070, 0x218F, true },
+ { 0x2190, 0x2BFF, false },
+ { 0x2C00, 0x2FEF, true },
+ { 0x2FF0, 0x3000, false },
+ { 0x3001, 0xD7FF, true },
+ { 0xD800, 0xF8FF, false },
+ { 0xF900, 0xFDCF, true },
+ { 0xFDD0, 0xFDEF, false },
+ { 0xFDF0, 0xFFFD, true },
+ { 0xFFFE, 0xFFFF, false },
+ { 0x10000, 0xEFFFF, true },
+ { 0xF0000, 0xF0000, false }, // just check one byte past last valid byte.
+ }
+ );
+ assert(res);
+}
+
+int main()
+{
+ test_xml_name_start_char();
+ test_xml_name_char();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/win_stdint.h b/src/parser/win_stdint.h
new file mode 100644
index 0000000..e51d46f
--- /dev/null
+++ b/src/parser/win_stdint.h
@@ -0,0 +1,46 @@
+/*************************************************************************
+ *
+ * Copyright (c) 2013 Markus Mohrhard
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ************************************************************************/
+
+#ifndef WIN_STDINT
+#define WIN_STDINT
+
+#if _MSC_VER <= 1500
+
+typedef signed __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+#else
+
+#include <stdint.h>
+
+#endif // visual studio version
+
+#endif \ No newline at end of file
diff --git a/src/parser/xml_namespace.cpp b/src/parser/xml_namespace.cpp
new file mode 100644
index 0000000..2aafea3
--- /dev/null
+++ b/src/parser/xml_namespace.cpp
@@ -0,0 +1,490 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/xml_namespace.hpp>
+#include <orcus/exception.hpp>
+#include <orcus/string_pool.hpp>
+
+#include <unordered_map>
+#include <vector>
+#include <limits>
+#include <sstream>
+#include <algorithm>
+#include <cassert>
+
+#define ORCUS_DEBUG_XML_NAMESPACE 0
+
+using namespace std;
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+#include <cstdio>
+#include <iostream>
+#endif
+
+namespace orcus {
+
+namespace {
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+template<typename _MapType>
+void print_map_keys(const _MapType& map_store)
+{
+ cout << "keys: (";
+ bool first = true;
+ typename _MapType::const_iterator it = map_store.begin(), it_end = map_store.end();
+ for (; it != it_end; ++it)
+ {
+ if (first)
+ first = false;
+ else
+ cout << " ";
+ cout << "'" << it->first << "'";
+ }
+ cout << ")";
+};
+#endif
+
+}
+
+typedef std::unordered_map<std::string_view, std::size_t> strid_map_type;
+
+struct xmlns_repository::impl
+{
+ size_t m_predefined_ns_size;
+ string_pool m_pool; /// storage of live string instances.
+ std::vector<std::string_view> m_identifiers; /// map strings to numerical identifiers.
+ strid_map_type m_strid_map; /// string-to-numerical identifiers map for quick lookup.
+
+ impl() : m_predefined_ns_size(0) {}
+};
+
+xmlns_repository::xmlns_repository() : mp_impl(std::make_unique<impl>()) {}
+xmlns_repository::xmlns_repository(xmlns_repository&& other) : mp_impl(std::move(other.mp_impl)) {}
+xmlns_repository::~xmlns_repository() = default;
+
+xmlns_repository& xmlns_repository::operator= (xmlns_repository&& other)
+{
+ mp_impl = std::move(other.mp_impl);
+ return *this;
+}
+
+xmlns_id_t xmlns_repository::intern(std::string_view uri)
+{
+ // See if the uri is already registered.
+ strid_map_type::iterator it = mp_impl->m_strid_map.find(uri);
+ if (it != mp_impl->m_strid_map.end())
+ return it->first.data();
+
+ try
+ {
+ auto r = mp_impl->m_pool.intern(uri);
+ std::string_view uri_interned = r.first;
+
+ if (!uri_interned.empty())
+ {
+ // Intern successful.
+ if (r.second)
+ {
+ // This is a new instance. Assign a numerical identifier.
+ mp_impl->m_strid_map.insert(
+ strid_map_type::value_type(r.first, mp_impl->m_identifiers.size()));
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_repository::intern: uri='" << uri_interned << "' (" << mp_impl->m_identifiers.size() << ")" << endl;
+#endif
+ mp_impl->m_identifiers.push_back(r.first);
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "pool size=" << mp_impl->m_pool.size() << ", predefined ns size=" << mp_impl->m_predefined_ns_size <<
+ ", identifiers size=" << mp_impl->m_identifiers.size() << ", map size=" << mp_impl->m_strid_map.size() << endl;
+#endif
+ assert(mp_impl->m_pool.size()+mp_impl->m_predefined_ns_size == mp_impl->m_identifiers.size());
+ assert(mp_impl->m_pool.size()+mp_impl->m_predefined_ns_size == mp_impl->m_strid_map.size());
+ }
+ return uri_interned.data();
+ }
+ }
+ catch (const general_error&)
+ {
+ }
+
+ return XMLNS_UNKNOWN_ID;
+}
+
+void xmlns_repository::add_predefined_values(const xmlns_id_t* predefined_ns)
+{
+ if (!predefined_ns)
+ return;
+
+ const xmlns_id_t* val = &predefined_ns[0];
+ for (; *val; ++val)
+ {
+ std::string_view s(*val);
+ mp_impl->m_strid_map.insert(
+ strid_map_type::value_type(s, mp_impl->m_identifiers.size()));
+ mp_impl->m_identifiers.push_back(s);
+
+ ++mp_impl->m_predefined_ns_size;
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xlmns_repository: predefined ns='" << s << "'" << endl;
+#endif
+ }
+}
+
+xmlns_context xmlns_repository::create_context()
+{
+ return xmlns_context(*this);
+}
+
+xmlns_id_t xmlns_repository::get_identifier(size_t index) const
+{
+ if (index >= mp_impl->m_identifiers.size())
+ return XMLNS_UNKNOWN_ID;
+
+ // All identifier strings are interned which means they are all null-terminated.
+ return mp_impl->m_identifiers[index].data();
+}
+
+string xmlns_repository::get_short_name(xmlns_id_t ns_id) const
+{
+ size_t index = get_index(ns_id);
+
+ if (index == INDEX_NOT_FOUND)
+ return string("???");
+
+ std::ostringstream os;
+ os << "ns" << index;
+ return os.str();
+}
+
+size_t xmlns_repository::get_index(xmlns_id_t ns_id) const
+{
+ if (!ns_id)
+ return INDEX_NOT_FOUND;
+
+ auto it = mp_impl->m_strid_map.find(std::string_view(ns_id));
+ if (it == mp_impl->m_strid_map.end())
+ return INDEX_NOT_FOUND;
+
+ return it->second;
+}
+
+typedef std::vector<xmlns_id_t> xmlns_list_type;
+typedef std::unordered_map<std::string_view, xmlns_list_type> alias_map_type;
+
+struct xmlns_context::impl
+{
+ xmlns_repository* repo = nullptr;
+ xmlns_list_type m_all_ns; /// all namespaces ever used in this context.
+ xmlns_list_type m_default;
+ alias_map_type m_map;
+
+ bool m_trim_all_ns = true;
+
+ impl() {}
+ impl(xmlns_repository& _repo) : repo(&_repo) {}
+ impl(const impl& r) :
+ repo(r.repo), m_all_ns(r.m_all_ns), m_default(r.m_default), m_map(r.m_map), m_trim_all_ns(r.m_trim_all_ns) {}
+};
+
+xmlns_context::xmlns_context() : mp_impl(std::make_unique<impl>()) {}
+xmlns_context::xmlns_context(xmlns_repository& repo) : mp_impl(std::make_unique<impl>(repo)) {}
+xmlns_context::xmlns_context(const xmlns_context& r) : mp_impl(std::make_unique<impl>(*r.mp_impl)) {}
+xmlns_context::xmlns_context(xmlns_context&& r) : mp_impl(std::move(r.mp_impl))
+{
+ r.mp_impl = std::make_unique<impl>();
+}
+
+xmlns_context::~xmlns_context() = default;
+
+xmlns_context& xmlns_context::operator= (const xmlns_context& r)
+{
+ xmlns_context tmp(r);
+ tmp.swap(*this);
+ return *this;
+}
+
+xmlns_context& xmlns_context::operator= (xmlns_context&& r)
+{
+ xmlns_context tmp(std::move(r));
+ tmp.swap(*this);
+ return *this;
+}
+
+xmlns_id_t xmlns_context::push(std::string_view alias, std::string_view uri)
+{
+ if (!mp_impl->repo)
+ throw general_error("this context is not associated with any repo.");
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::push: key='" << alias << "', uri='" << uri << "'" << endl;
+#endif
+ mp_impl->m_trim_all_ns = true;
+
+ xmlns_id_t id = mp_impl->repo->intern(uri);
+ std::string_view uri_interned = id ? std::string_view(id) : std::string_view();
+
+ if (alias.empty())
+ {
+ // empty alias value is associated with default namespace.
+ mp_impl->m_default.push_back(uri_interned.data());
+ mp_impl->m_all_ns.push_back(uri_interned.data());
+ return mp_impl->m_default.back();
+ }
+
+ // See if this alias already exists.
+ alias_map_type::iterator it = mp_impl->m_map.find(alias);
+ if (it == mp_impl->m_map.end())
+ {
+ // This is the first time this alias is used.
+ xmlns_list_type nslist;
+ nslist.push_back(uri_interned.data());
+ mp_impl->m_all_ns.push_back(uri_interned.data());
+ std::pair<alias_map_type::iterator,bool> r =
+ mp_impl->m_map.insert(alias_map_type::value_type(alias, nslist));
+
+ if (!r.second)
+ // insertion failed.
+ throw general_error("Failed to insert new namespace.");
+
+ return nslist.back();
+ }
+
+ // The alias already exists.
+ xmlns_list_type& nslist = it->second;
+ nslist.push_back(uri_interned.data());
+ mp_impl->m_all_ns.push_back(uri_interned.data());
+ return nslist.back();
+}
+
+void xmlns_context::pop(std::string_view alias)
+{
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::pop: alias='" << alias << "'" << endl;
+#endif
+ if (alias.empty())
+ {
+ // empty alias value is associated with default namespace.
+ if (mp_impl->m_default.empty())
+ throw general_error("default namespace stack is empty.");
+
+ mp_impl->m_default.pop_back();
+ return;
+ }
+
+ // See if this alias really exists.
+ alias_map_type::iterator it = mp_impl->m_map.find(alias);
+ if (it == mp_impl->m_map.end())
+ {
+ std::ostringstream os;
+ os << "alias named '" << alias << "' was attempted to be popped, but was not found in the stack";
+ throw general_error(os.str());
+ }
+
+ xmlns_list_type& nslist = it->second;
+ if (nslist.empty())
+ throw general_error("namespace stack for this key is empty.");
+
+ nslist.pop_back();
+}
+
+xmlns_id_t xmlns_context::get(std::string_view alias) const
+{
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::get: alias='" << alias << "', default ns stack size="
+ << mp_impl->m_default.size() << ", non-default alias count=" << mp_impl->m_map.size();
+ cout << ", ";
+ print_map_keys(mp_impl->m_map);
+ cout << endl;
+#endif
+ if (alias.empty())
+ return mp_impl->m_default.empty() ? XMLNS_UNKNOWN_ID : mp_impl->m_default.back();
+
+ alias_map_type::const_iterator it = mp_impl->m_map.find(alias);
+ if (it == mp_impl->m_map.end())
+ {
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::get: alias not in this context" << endl;
+#endif
+ return XMLNS_UNKNOWN_ID;
+ }
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::get: alias stack size=" << it->second.size() << endl;
+#endif
+ return it->second.empty() ? XMLNS_UNKNOWN_ID : it->second.back();
+}
+
+size_t xmlns_context::get_index(xmlns_id_t ns_id) const
+{
+ if (!mp_impl->repo)
+ throw general_error("this context is not associated with any repo.");
+
+ return mp_impl->repo->get_index(ns_id);
+}
+
+string xmlns_context::get_short_name(xmlns_id_t ns_id) const
+{
+ if (!mp_impl->repo)
+ throw general_error("this context is not associated with any repo.");
+
+ return mp_impl->repo->get_short_name(ns_id);
+}
+
+std::string_view xmlns_context::get_alias(xmlns_id_t ns_id) const
+{
+ alias_map_type::const_iterator it = mp_impl->m_map.begin(), it_end = mp_impl->m_map.end();
+ for (; it != it_end; ++it)
+ {
+ const xmlns_list_type& lst = it->second;
+ if (lst.empty())
+ continue;
+
+ if (lst.back() == ns_id)
+ return it->first;
+ }
+
+ return std::string_view{};
+}
+
+namespace {
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+struct print_ns
+{
+ void operator() (xmlns_id_t ns_id) const
+ {
+ const char* p = ns_id;
+ printf("%p: %s\n", p, p);
+ }
+};
+#endif
+
+struct ns_item
+{
+ size_t index;
+ xmlns_id_t ns;
+
+ ns_item(size_t _index, xmlns_id_t _ns) : index(_index), ns(_ns) {}
+};
+
+struct less_ns_by_index
+{
+ bool operator() (const ns_item& left, const ns_item& right) const
+ {
+ return left.index < right.index;
+ }
+};
+
+class push_back_ns_to_item
+{
+ vector<ns_item>& m_store;
+ const xmlns_context& m_cxt;
+public:
+ push_back_ns_to_item(vector<ns_item>& store, const xmlns_context& cxt) : m_store(store), m_cxt(cxt) {}
+ void operator() (xmlns_id_t ns)
+ {
+ size_t num_id = m_cxt.get_index(ns);
+ if (num_id != INDEX_NOT_FOUND)
+ m_store.push_back(ns_item(num_id, ns));
+ }
+};
+
+class push_back_item_to_ns
+{
+ std::vector<xmlns_id_t>& m_store;
+public:
+ push_back_item_to_ns(std::vector<xmlns_id_t>& store) : m_store(store) {}
+ void operator() (const ns_item& item)
+ {
+ m_store.push_back(item.ns);
+ }
+};
+
+}
+
+std::vector<xmlns_id_t> xmlns_context::get_all_namespaces() const
+{
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::get_all_namespaces: count=" << mp_impl->m_all_ns.size() << endl;
+ std::for_each(mp_impl->m_all_ns.begin(), mp_impl->m_all_ns.end(), print_ns());
+#endif
+
+ std::vector<xmlns_id_t> nslist;
+
+ if (mp_impl->m_trim_all_ns)
+ {
+ xmlns_list_type& all_ns = mp_impl->m_all_ns;
+
+ nslist.assign(mp_impl->m_all_ns.begin(), mp_impl->m_all_ns.end());
+
+ // Sort it and remove duplicate.
+ std::sort(all_ns.begin(), all_ns.end());
+ xmlns_list_type::iterator it_unique_end =
+ std::unique(all_ns.begin(), all_ns.end());
+ all_ns.erase(it_unique_end, all_ns.end());
+
+ // Now, sort by indices.
+ vector<ns_item> items;
+ std::for_each(all_ns.begin(), all_ns.end(), push_back_ns_to_item(items, *this));
+ std::sort(items.begin(), items.end(), less_ns_by_index());
+
+ all_ns.clear();
+ std::for_each(items.begin(), items.end(), push_back_item_to_ns(all_ns));
+
+ mp_impl->m_trim_all_ns = false;
+ }
+
+ nslist.assign(mp_impl->m_all_ns.begin(), mp_impl->m_all_ns.end());
+ return nslist;
+}
+
+void xmlns_context::dump(std::ostream& os) const
+{
+ vector<xmlns_id_t> nslist = get_all_namespaces();
+ vector<xmlns_id_t>::const_iterator it = nslist.begin(), it_end = nslist.end();
+ for (; it != it_end; ++it)
+ {
+ xmlns_id_t ns_id = *it;
+ size_t num_id = get_index(ns_id);
+ if (num_id == INDEX_NOT_FOUND)
+ continue;
+
+ os << "ns" << num_id << "=\"" << ns_id << '"' << endl;
+ }
+}
+
+void xmlns_context::dump_state(std::ostream& os) const
+{
+ os << "namespaces:" << std::endl;
+ for (xmlns_id_t ns_id : get_all_namespaces())
+ {
+ size_t num_id = get_index(ns_id);
+ if (num_id == INDEX_NOT_FOUND)
+ continue;
+
+ os << " ns" << num_id << ": \"" << ns_id << '"' << std::endl;
+ }
+
+ os << "aliases:" << std::endl;
+ for (const auto& [alias, ns_list] : mp_impl->m_map)
+ {
+ os << " " << alias << ":" << std::endl;
+
+ for (const xmlns_id_t ns : ns_list)
+ os << " - " << ns << std::endl;
+ }
+}
+
+void xmlns_context::swap(xmlns_context& other) noexcept
+{
+ mp_impl.swap(other.mp_impl);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/xml_namespace_test.cpp b/src/parser/xml_namespace_test.cpp
new file mode 100644
index 0000000..de3891e
--- /dev/null
+++ b/src/parser/xml_namespace_test.cpp
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/xml_namespace.hpp"
+
+#include <cstdlib>
+#include <vector>
+#include <algorithm>
+
+using namespace orcus;
+
+namespace {
+
+void test_basic()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view xmlns1("http://some.xmlns/");
+ std::string_view xmlns2("http://other.xmlns/");
+
+ xmlns_repository repo;
+ xmlns_context cxt1 = repo.create_context();
+ xmlns_context cxt2 = repo.create_context();
+
+ std::string_view empty, myns("myns");
+ {
+ // context 1
+ xmlns_id_t test1 = cxt1.push(empty, xmlns1); // register default namespace.
+ assert(cxt1.get(empty) == test1);
+ xmlns_id_t test2 = cxt1.push(myns, xmlns2);
+ assert(cxt1.get(myns) == test2);
+ assert(test1 != test2);
+ }
+
+ {
+ // context 2
+ xmlns_id_t test1 = cxt2.push(empty, xmlns2); // register default namespace.
+ assert(cxt2.get(empty) == test1);
+ xmlns_id_t test2 = cxt2.push(myns, xmlns1);
+ assert(cxt2.get(myns) == test2);
+ assert(test1 != test2);
+ }
+
+ // Now, compare the registered namespaces between the two namespaces.
+ assert(cxt1.get(empty) == cxt2.get(myns));
+ assert(cxt1.get(myns) == cxt2.get(empty));
+}
+
+void test_all_namespaces()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view key1("a"), key2("b"), key3("c");
+ std::string_view ns1("foo"), ns2("baa"), ns3("hmm");
+
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+ xmlns_id_t ns;
+
+ ns = cxt.push(key1, ns1);
+ assert(ns1 == ns);
+ ns = cxt.push(key2, ns2);
+ assert(ns2 == ns);
+ ns = cxt.push(key3, ns3);
+ assert(ns3 == ns);
+
+ std::vector<xmlns_id_t> all_ns = cxt.get_all_namespaces();
+ assert(all_ns.size() == 3);
+ assert(ns1 == all_ns[0]);
+ assert(ns2 == all_ns[1]);
+ assert(ns3 == all_ns[2]);
+}
+
+const xmlns_id_t NS_test_name1 = "test:name:1";
+const xmlns_id_t NS_test_name2 = "test:name:2";
+const xmlns_id_t NS_test_name3 = "test:name:3";
+
+xmlns_id_t NS_test_all[] = {
+ NS_test_name1,
+ NS_test_name2,
+ NS_test_name3,
+ nullptr
+};
+
+xmlns_id_t NS_test_all_reverse[] = {
+ NS_test_name3,
+ NS_test_name2,
+ NS_test_name1,
+ nullptr
+};
+
+void test_predefined_ns()
+{
+ xmlns_repository ns_repo;
+ ns_repo.add_predefined_values(NS_test_all);
+ xmlns_context cxt = ns_repo.create_context();
+ xmlns_id_t ns_id = cxt.push("tn1", "test:name:1");
+ assert(ns_id == NS_test_name1);
+ ns_id = cxt.push("tn2", "test:name:2");
+ assert(ns_id == NS_test_name2);
+ ns_id = cxt.push("tn3", "test:name:3");
+ assert(ns_id == NS_test_name3);
+ assert(cxt.get("tn1") == NS_test_name1);
+ assert(cxt.get("tn2") == NS_test_name2);
+ assert(cxt.get("tn3") == NS_test_name3);
+}
+
+void test_xml_name_t()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ xml_name_t name1;
+ name1.ns = NS_test_name1;
+ name1.name = "foo";
+
+ xml_name_t name2 = name1;
+ assert(name1 == name2);
+
+ name2.name = "foo2";
+ assert(name1 != name2);
+
+ xml_name_t name3 = name1;
+ name3.ns = NS_test_name2;
+ assert(name1 != name3);
+}
+
+void test_ns_context()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ xmlns_repository repo;
+ repo.add_predefined_values(NS_test_all);
+
+ xmlns_repository repo2;
+ repo2.add_predefined_values(NS_test_all_reverse);
+
+ xmlns_context cxt;
+ cxt = repo.create_context(); // copy assignment
+ size_t id1 = cxt.get_index(NS_test_name3);
+ xmlns_context cxt2 = cxt; // copy ctor
+ size_t id2 = cxt2.get_index(NS_test_name3);
+
+ assert(id1 == id2);
+
+ xmlns_context cxt3 = repo2.create_context();
+ id2 = cxt3.get_index(NS_test_name3);
+
+ assert(id1 != id2);
+
+ cxt3 = std::move(cxt2); // move assignment
+ id2 = cxt3.get_index(NS_test_name3);
+
+ assert(id1 == id2);
+
+ try
+ {
+ id1 = cxt2.get_index(NS_test_name2);
+ assert(!"exception was supposed to be thrown due to no associated repos.");
+ }
+ catch (const std::exception&)
+ {
+ // expected
+ }
+
+ xmlns_context cxt4(std::move(cxt3)); // move ctor
+ id1 = cxt4.get_index(NS_test_name3);
+
+ xmlns_context cxt5 = repo.create_context();
+ id2 = cxt5.get_index(NS_test_name3);
+
+ assert(id1 == id2);
+
+ try
+ {
+ id1 = cxt3.get_index(NS_test_name2);
+ assert(!"exception was supposed to be thrown due to no associated repos.");
+ }
+ catch (const std::exception&)
+ {
+ // expected
+ }
+
+ cxt4 = repo.create_context();
+ cxt5 = repo2.create_context();
+ id1 = cxt4.get_index(NS_test_name1);
+ id2 = cxt5.get_index(NS_test_name1);
+
+ assert(id1 != id2);
+
+ cxt3 = repo.create_context();
+ cxt5.swap(cxt3);
+ id2 = cxt5.get_index(NS_test_name1);
+
+ assert(id1 == id2);
+}
+
+void test_repo_move()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ static_assert(!std::is_copy_constructible_v<xmlns_repository>);
+ static_assert(std::is_move_constructible_v<xmlns_repository>);
+
+ xmlns_repository repo;
+ repo.add_predefined_values(NS_test_all);
+
+ xmlns_repository repo_moved = std::move(repo); // move construction
+ xmlns_repository repo_moved2;
+ repo_moved2 = std::move(repo_moved); // move assignment
+
+ xmlns_id_t ns_id = repo_moved2.get_identifier(0);
+ assert(ns_id != XMLNS_UNKNOWN_ID);
+ ns_id = repo_moved2.get_identifier(1);
+ assert(ns_id != XMLNS_UNKNOWN_ID);
+ ns_id = repo_moved2.get_identifier(2);
+ assert(ns_id != XMLNS_UNKNOWN_ID);
+ ns_id = repo_moved2.get_identifier(3);
+ assert(ns_id == XMLNS_UNKNOWN_ID);
+}
+
+} // anonymous namespace
+
+int main()
+{
+ test_basic();
+ test_all_namespaces();
+ test_predefined_ns();
+ test_xml_name_t();
+ test_ns_context();
+ test_repo_move();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/xml_writer.cpp b/src/parser/xml_writer.cpp
new file mode 100644
index 0000000..a2f6c2f
--- /dev/null
+++ b/src/parser/xml_writer.cpp
@@ -0,0 +1,326 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/xml_writer.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <orcus/string_pool.hpp>
+
+#include <vector>
+
+/** To markup code that coverity warns might throw exceptions
+ which won't throw in practice, or where std::terminate is
+ an acceptable response if they do
+*/
+#if defined(__COVERITY__)
+#define suppress_fun_call_w_exception(expr) \
+ do \
+ { \
+ try \
+ { \
+ expr; \
+ } \
+ catch (const std::exception& e) \
+ { \
+ std::cerr << "Fatal exception: " << e.what() << std::endl; \
+ std::terminate(); \
+ } \
+ } while (false)
+#else
+#define suppress_fun_call_w_exception(expr) \
+ do \
+ { \
+ expr; \
+ } while (false)
+#endif
+
+namespace orcus {
+
+namespace {
+
+struct _elem
+{
+ xml_name_t name;
+ std::vector<std::string_view> ns_aliases;
+ bool open;
+
+ _elem(const xml_name_t& _name) : name(_name), open(true) {}
+};
+
+struct _attr
+{
+ xml_name_t name;
+ std::string_view value;
+
+ _attr(const xml_name_t& _name, std::string_view _value) :
+ name(_name),
+ value(_value)
+ {}
+};
+
+void write_content_encoded(std::string_view content, std::ostream& os)
+{
+ auto _flush = [&os](const char*& p0, const char* p)
+ {
+ size_t n = std::distance(p0, p);
+ os.write(p0, n);
+ p0 = nullptr;
+ };
+
+ constexpr std::string_view cv_lt = "&lt;";
+ constexpr std::string_view cv_gt = "&gt;";
+ constexpr std::string_view cv_amp = "&amp;";
+ constexpr std::string_view cv_apos = "&apos;";
+ constexpr std::string_view cv_quot = "&quot;";
+
+ const char* p = content.data();
+ const char* p_end = p + content.size();
+ const char* p0 = nullptr;
+
+ for (; p != p_end; ++p)
+ {
+ if (!p0)
+ p0 = p;
+
+ switch (*p)
+ {
+ case '<':
+ _flush(p0, p);
+ os.write(cv_lt.data(), cv_lt.size());
+ break;
+ case '>':
+ _flush(p0, p);
+ os.write(cv_gt.data(), cv_gt.size());
+ break;
+ case '&':
+ _flush(p0, p);
+ os.write(cv_amp.data(), cv_amp.size());
+ break;
+ case '\'':
+ _flush(p0, p);
+ os.write(cv_apos.data(), cv_apos.size());
+ break;
+ case '"':
+ _flush(p0, p);
+ os.write(cv_quot.data(), cv_quot.size());
+ break;
+ }
+ }
+
+ if (p0)
+ _flush(p0, p);
+}
+
+} // anonymous namespace
+
+struct xml_writer::scope::impl
+{
+ xml_writer* parent;
+ xml_name_t elem;
+
+ impl() : parent(nullptr) {}
+
+ impl(xml_writer* _parent, const xml_name_t& _elem) :
+ parent(_parent),
+ elem(_elem)
+ {
+ parent->push_element(elem);
+ }
+
+ ~impl()
+ {
+ suppress_fun_call_w_exception(parent->pop_element());
+ }
+};
+
+xml_writer::scope::scope(xml_writer* parent, const xml_name_t& elem) :
+ mp_impl(std::make_unique<impl>(parent, elem))
+{
+}
+
+xml_writer::scope::scope(scope&& other) :
+ mp_impl(std::move(other.mp_impl))
+{
+ // NB: we shouldn't have to create an impl instance for the other object
+ // since everything happens in the impl, and the envelop class doesn't
+ // access the impl internals.
+}
+
+xml_writer::scope::~scope() {}
+
+xml_writer::scope& xml_writer::scope::operator= (scope&& other)
+{
+ scope tmp(std::move(other));
+ mp_impl.swap(tmp.mp_impl);
+ return *this;
+}
+
+struct xml_writer::impl
+{
+ xmlns_repository& ns_repo;
+ std::ostream& os;
+ std::vector<_elem> elem_stack;
+ std::vector<std::string_view> ns_decls;
+ std::vector<_attr> attrs;
+
+ string_pool str_pool;
+ xmlns_repository repo;
+ xmlns_context cxt;
+
+ impl(xmlns_repository& _ns_repo, std::ostream& _os) :
+ ns_repo(_ns_repo),
+ os(_os),
+ cxt(ns_repo.create_context())
+ {}
+
+ void print(const xml_name_t& name)
+ {
+ std::string_view alias = cxt.get_alias(name.ns);
+ if (!alias.empty())
+ os << alias << ':';
+ os << name.name;
+ }
+
+ xml_name_t intern(const xml_name_t& name)
+ {
+ xml_name_t interned = name;
+ interned.name = str_pool.intern(interned.name).first;
+ return interned;
+ }
+
+ std::string_view intern(std::string_view value)
+ {
+ return str_pool.intern(value).first;
+ }
+};
+
+xml_writer::xml_writer(xmlns_repository& ns_repo, std::ostream& os) :
+ mp_impl(std::make_unique<impl>(ns_repo, os))
+{
+ os << "<?xml version=\"1.0\"?>";
+}
+
+xml_writer::xml_writer(xml_writer&& other) :
+ mp_impl(std::move(other.mp_impl))
+{
+ other.mp_impl = std::make_unique<impl>(mp_impl->ns_repo, mp_impl->os);
+}
+
+xml_writer& xml_writer::operator= (xml_writer&& other)
+{
+ xml_writer tmp(std::move(other));
+ mp_impl.swap(tmp.mp_impl);
+ return *this;
+}
+
+void xml_writer::pop_elements()
+{
+ // Pop all the elements currently on the stack.
+ while (!mp_impl->elem_stack.empty())
+ pop_element();
+}
+
+xml_writer::~xml_writer()
+{
+ suppress_fun_call_w_exception(pop_elements());
+}
+
+void xml_writer::close_current_element()
+{
+ if (!mp_impl->elem_stack.empty() && mp_impl->elem_stack.back().open)
+ {
+ mp_impl->os << '>';
+ mp_impl->elem_stack.back().open = false;
+ }
+}
+
+xml_writer::scope xml_writer::push_element_scope(const xml_name_t& name)
+{
+ return scope(this, name);
+}
+
+void xml_writer::push_element(const xml_name_t& _name)
+{
+ close_current_element();
+
+ auto& os = mp_impl->os;
+ xml_name_t name = mp_impl->intern(_name);
+
+ os << '<';
+ mp_impl->print(name);
+
+ for (std::string_view alias : mp_impl->ns_decls)
+ {
+ os << " xmlns";
+ if (!alias.empty())
+ os << ':' << alias;
+ os << "=\"";
+ xmlns_id_t ns = mp_impl->cxt.get(alias);
+ os << ns << '"';
+ }
+
+ for (const _attr& attr : mp_impl->attrs)
+ {
+ os << ' ';
+ mp_impl->print(attr.name);
+ os << "=\"";
+ os << attr.value << '"';
+ }
+
+ mp_impl->attrs.clear();
+ mp_impl->ns_decls.clear();
+
+ mp_impl->elem_stack.emplace_back(name);
+}
+
+xmlns_id_t xml_writer::add_namespace(std::string_view alias, std::string_view value)
+{
+ std::string_view alias_safe = mp_impl->intern(alias);
+ xmlns_id_t ns = mp_impl->cxt.push(alias_safe, mp_impl->intern(value));
+ mp_impl->ns_decls.push_back(alias_safe);
+ return ns;
+}
+
+void xml_writer::add_attribute(const xml_name_t& name, std::string_view value)
+{
+ mp_impl->attrs.emplace_back(mp_impl->intern(name), mp_impl->intern(value));
+}
+
+void xml_writer::add_content(std::string_view content)
+{
+ close_current_element();
+ write_content_encoded(content, mp_impl->os);
+}
+
+xml_name_t xml_writer::pop_element()
+{
+ auto& os = mp_impl->os;
+
+ const _elem& elem = mp_impl->elem_stack.back();
+ auto name = elem.name;
+
+ if (elem.open)
+ {
+ // self-closing element.
+ os << "/>";
+ }
+ else
+ {
+ os << "</";
+ mp_impl->print(name);
+ os << '>';
+ }
+
+ for (std::string_view alias : mp_impl->elem_stack.back().ns_aliases)
+ mp_impl->cxt.pop(alias);
+
+ mp_impl->elem_stack.pop_back();
+ return name;
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/xml_writer_test.cpp b/src/parser/xml_writer_test.cpp
new file mode 100644
index 0000000..a6e4bed
--- /dev/null
+++ b/src/parser/xml_writer_test.cpp
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/xml_writer.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/sax_parser.hpp"
+
+#include <iostream>
+#include <sstream>
+
+using namespace orcus;
+
+void test_encoded_content()
+{
+ const std::vector<std::string> test_contents = {
+ "1 < 2 but 3 > 2",
+ "ladies & gentlemen",
+ "'testing single quotes'",
+ "\"testing double quotes\"",
+ };
+
+ struct _handler : public sax_handler
+ {
+ std::ostringstream os_content;
+
+ void characters(std::string_view val, bool /*transient*/)
+ {
+ os_content << val;
+ }
+ };
+
+ for (const std::string& test_content : test_contents)
+ {
+ xmlns_repository repo;
+ std::ostringstream os;
+
+ {
+ xml_writer writer(repo, os);
+ auto scope_root = writer.push_element_scope({nullptr, "root"});
+ writer.add_content(test_content);
+ }
+
+ std::string stream = os.str();
+
+ _handler hdl;
+
+ sax_parser<_handler> parser(stream, hdl);
+ parser.parse();
+
+ std::string content_read = hdl.os_content.str();
+ assert(test_content == content_read);
+ }
+}
+
+void test_move()
+{
+ xmlns_repository repo;
+
+ {
+ std::ostringstream os;
+ xml_writer writer(repo, os);
+
+ writer.push_element({nullptr, "foo"});
+
+ {
+ xml_writer moved(std::move(writer)); // move constructor
+ moved.add_content("stuff");
+ }
+
+ std::string stream = os.str();
+ assert(stream == "<?xml version=\"1.0\"?><foo>stuff</foo>");
+ }
+
+ {
+ std::ostringstream os;
+ xml_writer writer(repo, os);
+
+ writer.push_element({nullptr, "foo2"});
+
+ {
+ std::ostringstream os2;
+ xml_writer moved(repo, os2);
+
+ moved = std::move(writer); // move assignment.
+ moved.add_content("stuff2");
+ }
+
+ std::string stream = os.str();
+ assert(stream == "<?xml version=\"1.0\"?><foo2>stuff2</foo2>");
+ }
+}
+
+int main()
+{
+ test_encoded_content();
+ test_move();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/yaml_parser_base.cpp b/src/parser/yaml_parser_base.cpp
new file mode 100644
index 0000000..df4db23
--- /dev/null
+++ b/src/parser/yaml_parser_base.cpp
@@ -0,0 +1,512 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/yaml_parser_base.hpp>
+#include <orcus/cell_buffer.hpp>
+#include <orcus/parser_global.hpp>
+
+#include <mdds/sorted_string_map.hpp>
+
+#include <limits>
+#include <vector>
+#include <deque>
+#include <sstream>
+#include <algorithm>
+
+namespace orcus { namespace yaml {
+
+struct scope
+{
+ size_t width;
+ detail::scope_t type;
+
+ scope(size_t _width) : width(_width), type(detail::scope_t::unset) {}
+};
+
+struct parser_base::impl
+{
+ cell_buffer m_buffer;
+ std::vector<scope> m_scopes;
+ std::deque<std::string_view> m_line_buffer;
+ const char* m_document;
+
+ size_t m_comment_length;
+
+ bool m_in_literal_block;
+ bool m_parsed_to_end_of_line;
+
+ detail::parse_token_t m_last_token;
+
+ impl() :
+ m_document(nullptr),
+ m_comment_length(0),
+ m_in_literal_block(false),
+ m_parsed_to_end_of_line(false),
+ m_last_token(detail::parse_token_t::unknown) {}
+};
+
+const size_t parser_base::parse_indent_blank_line = std::numeric_limits<size_t>::max();
+const size_t parser_base::parse_indent_end_of_stream = std::numeric_limits<size_t>::max() - 1;
+const size_t parser_base::scope_empty = std::numeric_limits<size_t>::max() - 2;
+
+parser_base::parser_base(std::string_view content) :
+ orcus::parser_base(content.data(), content.size()), mp_impl(std::make_unique<impl>()) {}
+
+parser_base::~parser_base() = default;
+
+void parser_base::push_parse_token(detail::parse_token_t t)
+{
+ mp_impl->m_last_token = t;
+}
+
+detail::parse_token_t parser_base::get_last_parse_token() const
+{
+ return mp_impl->m_last_token;
+}
+
+size_t parser_base::offset_last_char_of_line() const
+{
+ // The current parser position should be on the linefeed char after
+ // calling parse_to_end_of_line().
+ assert(mp_impl->m_parsed_to_end_of_line);
+
+ size_t pos = offset(); // character past the '\n'.
+ pos -= 1; // move back to the '\n'.
+
+ if (mp_impl->m_comment_length)
+ {
+ assert(mp_impl->m_comment_length < pos);
+ pos -= mp_impl->m_comment_length; // should be on the '#' character.
+ }
+
+ pos -= 1;
+
+ // Ignore any trailing whitespaces.
+ const char* p = mp_begin + pos;
+ for (; mp_begin < p && *p == ' '; --p, --pos)
+ ;
+
+ return pos;
+}
+
+size_t parser_base::parse_indent()
+{
+ for (size_t indent = 0; has_char(); next(), ++indent)
+ {
+ char c = cur_char();
+ switch (c)
+ {
+ case '#':
+ skip_comment();
+ return parse_indent_blank_line;
+ case '\n':
+ next();
+ return parse_indent_blank_line;
+ case ' ':
+ continue;
+ default:
+ return indent;
+ }
+ }
+
+ return parse_indent_end_of_stream;
+}
+
+std::string_view parser_base::parse_to_end_of_line()
+{
+ const char* p = mp_char;
+ size_t len = 0;
+ for (; has_char(); next(), ++len)
+ {
+ switch (cur_char())
+ {
+ case '#':
+ skip_comment();
+ break;
+ case '\'':
+ {
+ const char* p_open_quote = mp_char;
+
+ // character immediately after the closing quote.
+ const char* p_end =
+ parse_to_closing_single_quote(mp_char, remaining_size());
+
+ if (!p_end)
+ throw parse_error("parse_to_end_of_line: closing single quote was expected but not found.", offset());
+
+ size_t diff = p_end - p_open_quote - 1;
+
+ // Move the cursor to the closing quote.
+ next(diff);
+ len += diff;
+ assert(cur_char() == '\'');
+ continue;
+ }
+ break;
+ case '"':
+ {
+ const char* p_open_quote = mp_char;
+
+ // character immediately after the closing quote.
+ const char* p_end =
+ parse_to_closing_double_quote(mp_char, remaining_size());
+
+ if (!p_end)
+ throw parse_error("parse_to_end_of_line: closing double quote was expected but not found.", offset());
+
+ size_t diff = p_end - p_open_quote - 1;
+
+ // Move the cursor to the closing quote.
+ next(diff);
+ len += diff;
+ assert(cur_char() == '"');
+ continue;
+ }
+ break;
+ case '\n':
+ next();
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+
+ std::string_view ret(p, len);
+ mp_impl->m_parsed_to_end_of_line = true;
+ return ret;
+}
+
+void parser_base::skip_comment()
+{
+ assert(cur_char() == '#');
+
+ size_t n = 1;
+
+ for (; has_char(); next(), ++n)
+ {
+ if (cur_char() == '\n')
+ {
+ next();
+ break;
+ }
+ }
+
+ mp_impl->m_comment_length = n;
+}
+
+void parser_base::reset_on_new_line()
+{
+ mp_impl->m_comment_length = 0;
+ mp_impl->m_parsed_to_end_of_line = false;
+}
+
+size_t parser_base::get_scope() const
+{
+ return (mp_impl->m_scopes.empty()) ? scope_empty : mp_impl->m_scopes.back().width;
+}
+
+void parser_base::push_scope(size_t scope_width)
+{
+ mp_impl->m_scopes.emplace_back(scope_width);
+}
+
+void parser_base::clear_scopes()
+{
+ mp_impl->m_scopes.clear();
+}
+
+detail::scope_t parser_base::get_scope_type() const
+{
+ assert(!mp_impl->m_scopes.empty());
+ return mp_impl->m_scopes.back().type;
+}
+
+void parser_base::set_scope_type(detail::scope_t type)
+{
+ assert(!mp_impl->m_scopes.empty());
+ mp_impl->m_scopes.back().type = type;
+}
+
+size_t parser_base::pop_scope()
+{
+ assert(!mp_impl->m_scopes.empty());
+ mp_impl->m_scopes.pop_back();
+ return get_scope();
+}
+
+void parser_base::push_line_back(const char* p, size_t n)
+{
+ mp_impl->m_line_buffer.emplace_back(p, n);
+}
+
+std::string_view parser_base::pop_line_front()
+{
+ assert(!mp_impl->m_line_buffer.empty());
+
+ std::string_view ret = mp_impl->m_line_buffer.front();
+ mp_impl->m_line_buffer.pop_front();
+ return ret;
+}
+
+bool parser_base::has_line_buffer() const
+{
+ return !mp_impl->m_line_buffer.empty();
+}
+
+size_t parser_base::get_line_buffer_count() const
+{
+ return mp_impl->m_line_buffer.size();
+}
+
+std::string_view parser_base::merge_line_buffer()
+{
+ assert(!mp_impl->m_line_buffer.empty());
+
+ char sep = mp_impl->m_in_literal_block ? '\n' : ' ';
+
+ cell_buffer& buf = mp_impl->m_buffer;
+ buf.reset();
+
+ auto it = mp_impl->m_line_buffer.begin();
+ buf.append(it->data(), it->size());
+ ++it;
+
+ std::for_each(it, mp_impl->m_line_buffer.end(),
+ [&](std::string_view line)
+ {
+ buf.append(&sep, 1);
+ buf.append(line.data(), line.size());
+ }
+ );
+
+ mp_impl->m_line_buffer.clear();
+ mp_impl->m_in_literal_block = false;
+
+ return buf.str();
+}
+
+const char* parser_base::get_doc_hash() const
+{
+ return mp_impl->m_document;
+}
+
+void parser_base::set_doc_hash(const char* hash)
+{
+ mp_impl->m_document = hash;
+}
+
+namespace {
+
+namespace keyword {
+
+using map_type = mdds::sorted_string_map<detail::keyword_t, mdds::string_view_map_entry>;
+
+constexpr map_type::entry entries[] = {
+ { "FALSE", detail::keyword_t::boolean_false },
+ { "False", detail::keyword_t::boolean_false },
+ { "N", detail::keyword_t::boolean_false },
+ { "NO", detail::keyword_t::boolean_false },
+ { "NULL", detail::keyword_t::null },
+ { "No", detail::keyword_t::boolean_false },
+ { "Null", detail::keyword_t::null },
+ { "OFF", detail::keyword_t::boolean_false },
+ { "ON", detail::keyword_t::boolean_true },
+ { "Off", detail::keyword_t::boolean_false },
+ { "On", detail::keyword_t::boolean_true },
+ { "TRUE", detail::keyword_t::boolean_true },
+ { "True", detail::keyword_t::boolean_true },
+ { "Y", detail::keyword_t::boolean_true },
+ { "YES", detail::keyword_t::boolean_true },
+ { "Yes", detail::keyword_t::boolean_true },
+ { "false", detail::keyword_t::boolean_false },
+ { "n", detail::keyword_t::boolean_false },
+ { "no", detail::keyword_t::boolean_false },
+ { "null", detail::keyword_t::null },
+ { "off", detail::keyword_t::boolean_false },
+ { "on", detail::keyword_t::boolean_true },
+ { "true", detail::keyword_t::boolean_true },
+ { "y", detail::keyword_t::boolean_true },
+ { "yes", detail::keyword_t::boolean_true },
+ { "~", detail::keyword_t::null },
+};
+
+const map_type& get()
+{
+ static const map_type map(entries, std::size(entries), detail::keyword_t::unknown);
+ return map;
+}
+
+} // namespace keyword
+
+void throw_quoted_string_parse_error(
+ const char* func_name, const parse_quoted_string_state& ret, std::ptrdiff_t offset)
+{
+ std::ostringstream os;
+ os << func_name << ": failed to parse ";
+ if (ret.length == parse_quoted_string_state::error_illegal_escape_char)
+ os << "due to the presence of illegal escape character.";
+ else if (ret.length == parse_quoted_string_state::error_no_closing_quote)
+ os << "because the closing quote was not found.";
+ else
+ os << "due to unknown reason.";
+
+ throw parse_error(os.str(), offset);
+}
+
+}
+
+detail::keyword_t parser_base::parse_keyword(const char* p, size_t len)
+{
+ return keyword::get().find({p, len});
+}
+
+parser_base::key_value parser_base::parse_key_value(const char* p, size_t len)
+{
+ size_t scope = get_scope();
+ assert(scope != scope_empty);
+
+ assert(*p != ' ');
+ assert(len);
+
+ const char* p_end = p + len;
+
+ key_value kv;
+
+ char last = 0;
+ bool key_found = false;
+
+ const char* p_head = p;
+
+ for (; p != p_end; ++p)
+ {
+ if (*p == ' ')
+ {
+ if (!key_found)
+ {
+ if (last == ':')
+ {
+ // Key found.
+ std::size_t n = p - p_head - 1;
+ kv.key = trim({p_head, n});
+ key_found = true;
+ p_head = nullptr;
+ }
+ }
+ }
+ else
+ {
+ if (!p_head)
+ p_head = p;
+ }
+
+ last = *p;
+ }
+
+ assert(p_head);
+
+ if (key_found)
+ {
+ // Key has already been found and the value comes after the ':'.
+ kv.value = std::string_view(p_head, p-p_head);
+ }
+ else if (last == ':')
+ {
+ // Line only contains a key and ends with ':'.
+ std::size_t n = p - p_head - 1;
+ kv.key = trim({p_head, n});
+ }
+ else
+ {
+ // Key has not been found.
+ detail::scope_t st = get_scope_type();
+ if (st == detail::scope_t::map)
+ throw parse_error("key was expected, but not found.", offset_last_char_of_line());
+ }
+
+ return kv;
+}
+
+std::string_view parser_base::parse_single_quoted_string_value(const char*& p, size_t max_length)
+{
+ parse_quoted_string_state ret =
+ parse_single_quoted_string(p, max_length, mp_impl->m_buffer);
+
+ if (!ret.str)
+ throw_quoted_string_parse_error("parse_single_quoted_string_value", ret, offset());
+
+ return std::string_view(ret.str, ret.length);
+}
+
+std::string_view parser_base::parse_double_quoted_string_value(const char*& p, size_t max_length)
+{
+ parse_quoted_string_state ret =
+ parse_double_quoted_string(p, max_length, mp_impl->m_buffer);
+
+ if (!ret.str)
+ throw_quoted_string_parse_error("parse_double_quoted_string_value", ret, offset());
+
+ return std::string_view(ret.str, ret.length);
+}
+
+void parser_base::skip_blanks(const char*& p, size_t len)
+{
+ const char* p_end = p + len;
+ for (; p != p_end && *p == ' '; ++p)
+ ;
+}
+
+void parser_base::start_literal_block()
+{
+ mp_impl->m_in_literal_block = true;
+}
+
+bool parser_base::in_literal_block() const
+{
+ return mp_impl->m_in_literal_block;
+}
+
+void parser_base::handle_line_in_literal(size_t indent)
+{
+ size_t cur_scope = get_scope();
+
+ if (!has_line_buffer())
+ {
+ // Start a new multi-line string scope.
+
+ if (indent == cur_scope)
+ throw parse_error("parse: first line of a literal block must be indented.", offset());
+
+ push_scope(indent);
+ set_scope_type(yaml::detail::scope_t::multi_line_string);
+ }
+ else
+ {
+ // The current scope is already a multi-line scope.
+ assert(get_scope_type() == yaml::detail::scope_t::multi_line_string);
+ size_t leading_indent = indent - cur_scope;
+ prev(leading_indent);
+ }
+
+ std::string_view line = parse_to_end_of_line();
+ push_line_back(line.data(), line.size());
+}
+
+void parser_base::handle_line_in_multi_line_string()
+{
+ if (get_scope_type() != yaml::detail::scope_t::multi_line_string)
+ set_scope_type(yaml::detail::scope_t::multi_line_string);
+
+ std::string_view line = parse_to_end_of_line();
+ line = trim(line);
+ assert(!line.empty());
+ push_line_back(line.data(), line.size());
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/yaml_parser_test.cpp b/src/parser/yaml_parser_test.cpp
new file mode 100644
index 0000000..88103db
--- /dev/null
+++ b/src/parser/yaml_parser_test.cpp
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/yaml_parser.hpp>
+
+#include <string>
+
+void test_handler()
+{
+ constexpr std::string_view test_code =
+ "section-one:\n"
+ " - item 1\n"
+ " - item 2\n"
+ "\n";
+
+ orcus::yaml_handler hdl;
+ orcus::yaml_parser<orcus::yaml_handler> parser(test_code, hdl);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/zip_archive.cpp b/src/parser/zip_archive.cpp
new file mode 100644
index 0000000..50d5da5
--- /dev/null
+++ b/src/parser/zip_archive.cpp
@@ -0,0 +1,601 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/zip_archive.hpp>
+#include <orcus/zip_archive_stream.hpp>
+#include <orcus/string_pool.hpp>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <unordered_map>
+#include <sstream>
+#include <string_view>
+#include <iomanip>
+
+#include <zlib.h>
+#include <zconf.h>
+
+#define ORCUS_DEBUG_ZIP_ARCHIVE 0
+
+namespace orcus {
+
+namespace {
+
+struct zip_file_param
+{
+ enum compress_method_type { stored = 0, deflated = 8 };
+
+ std::string_view filename;
+ compress_method_type compress_method;
+ std::size_t offset_file_header;
+ std::size_t size_compressed;
+ std::size_t size_uncompressed;
+
+ uint16_t version_made_by;
+ uint16_t minimum_version_needed;
+ uint16_t flags;
+ uint16_t last_modified_time;
+ uint16_t last_modified_date;
+
+ uint16_t filename_length;
+ uint16_t extra_field_length;
+ uint16_t comment_length;
+
+ uint16_t disk_id_where_file_starts;
+ uint16_t file_attributes_internal;
+ uint32_t file_attributes_external;
+
+ uint32_t crc32;
+};
+
+class zip_inflater
+{
+ z_stream m_zlib_cxt;
+
+ zip_inflater(); // disabled
+public:
+ zip_inflater(std::vector<unsigned char>& raw_buf, std::vector<unsigned char>& dest_buf, const zip_file_param& param)
+ {
+ memset(&m_zlib_cxt, 0, sizeof(m_zlib_cxt));
+ m_zlib_cxt.next_in = static_cast<Bytef*>(&raw_buf[0]);
+ m_zlib_cxt.avail_in = param.size_compressed;
+
+ m_zlib_cxt.next_out = static_cast<Bytef*>(&dest_buf[0]);
+ m_zlib_cxt.avail_out = param.size_uncompressed;
+ }
+
+ ~zip_inflater()
+ {
+ inflateEnd(&m_zlib_cxt);
+ }
+
+ bool init()
+ {
+ int err = inflateInit2(&m_zlib_cxt, -MAX_WBITS);
+ return err == Z_OK;
+ }
+
+ bool inflate()
+ {
+ int err = ::inflate(&m_zlib_cxt, Z_SYNC_FLUSH);
+ if (err >= 0 && m_zlib_cxt.msg)
+ return false;
+
+ return true;
+ }
+};
+
+/**
+ * Stream doesn't know its size; only its starting offset position within
+ * the file stream.
+ */
+class zip_stream_parser
+{
+ zip_archive_stream* m_stream;
+ size_t m_pos;
+ size_t m_pos_internal;
+
+ void read_string_to_buffer(size_t n, std::vector<unsigned char>& buf)
+ {
+ if (!n)
+ throw zip_error("attempt to read string of zero size.");
+
+ m_stream->seek(m_pos+m_pos_internal);
+ m_stream->read(&buf[0], n);
+ m_pos_internal += n;
+ }
+
+public:
+ zip_stream_parser() : m_stream(nullptr), m_pos(0), m_pos_internal(0) {}
+ zip_stream_parser(zip_archive_stream* stream, size_t pos) : m_stream(stream), m_pos(pos), m_pos_internal(0) {}
+
+ std::string read_string(size_t n)
+ {
+ std::vector<unsigned char> buf(n+1, '\0');
+ read_string_to_buffer(n, buf);
+ return std::string(reinterpret_cast<const char*>(&buf[0]));
+ }
+
+ std::vector<uint8_t> read_bytes(std::size_t n)
+ {
+ if (!n)
+ throw zip_error("attempt to read string of zero size.");
+
+ std::vector<uint8_t> buf;
+ m_stream->seek(m_pos+m_pos_internal);
+ m_stream->read(buf.data(), n);
+ m_pos_internal += n;
+ return buf;
+ }
+
+ std::string_view read_string(size_t n, string_pool& pool)
+ {
+ std::vector<unsigned char> buf(n+1, '\0');
+ read_string_to_buffer(n, buf);
+ return pool.intern({reinterpret_cast<const char*>(buf.data()), n}).first;
+ }
+
+ void skip_bytes(size_t n)
+ {
+ m_pos_internal += n;
+ }
+
+ uint32_t read_4bytes()
+ {
+ m_stream->seek(m_pos+m_pos_internal);
+ unsigned char buf[4];
+ m_stream->read(&buf[0], 4);
+ m_pos_internal += 4;
+
+ uint32_t ret = buf[0];
+ ret |= (buf[1] << 8);
+ ret |= (buf[2] << 16);
+ ret |= (buf[3] << 24);
+
+ return ret;
+ }
+
+ uint16_t read_2bytes()
+ {
+ m_stream->seek(m_pos+m_pos_internal);
+ unsigned char buf[2];
+ m_stream->read(&buf[0], 2);
+ m_pos_internal += 2;
+
+ uint16_t ret = buf[0];
+ ret |= (buf[1] << 8);
+
+ return ret;
+ }
+
+ size_t tell() const
+ {
+ return m_pos + m_pos_internal;
+ }
+};
+
+/**
+ * Content of the end part of the central directory.
+ */
+struct central_dir_end
+{
+ uint32_t magic_number;
+ uint16_t this_disk_id;
+ uint16_t central_dir_disk_id;
+ uint16_t num_central_dir_records_local;
+ uint16_t num_celtral_dir_records_total;
+ uint32_t size_central_dir;
+ size_t central_dir_pos;
+ uint16_t comment_length;
+};
+
+} // anonymous namespace
+
+
+zip_file_entry_header::zip_file_entry_header() = default;
+zip_file_entry_header::zip_file_entry_header(const zip_file_entry_header& other) = default;
+zip_file_entry_header::zip_file_entry_header(zip_file_entry_header&& other) = default;
+zip_file_entry_header::~zip_file_entry_header() = default;
+
+zip_file_entry_header& zip_file_entry_header::operator=(const zip_file_entry_header& other) = default;
+zip_file_entry_header& zip_file_entry_header::operator=(zip_file_entry_header&& other) = default;
+
+std::ostream& operator<<(std::ostream& os, const zip_file_entry_header& header)
+{
+ os << "header signature: 0x" << std::hex << std::setfill('0') << std::setw(8) << header.header_signature << "\n"
+ << "version needed to extract: " << header.required_version << "\n"
+ << "general purpose bit flag: 0x" << std::hex << std::setfill('0') << std::setw(4) << header.flag << "\n"
+ << "compression method: " << header.compression_method << "\n"
+ << "last modified time: " << header.last_modified_time << "\n"
+ << "last modified date: " << header.last_modified_date << "\n"
+ << "crc32: 0x" << std::hex << std::setfill('0') << std::setw(8) << header.crc32 << "\n"
+ << "compressed size: " << header.compressed_size << "\n"
+ << "uncompressed size: " << header.uncompressed_size << "\n"
+ << "filename: " << header.filename << "\n"
+ << "extra field length: " << header.extra_field.size();
+
+ return os;
+}
+
+class zip_archive::impl
+{
+ typedef std::vector<zip_file_param> file_params_type;
+ typedef std::unordered_map<std::string_view, std::size_t> filename_map_type;
+
+ string_pool m_pool;
+ zip_archive_stream* m_stream;
+ off_t m_stream_size;
+ size_t m_central_dir_pos;
+
+ zip_stream_parser m_central_dir_end;
+
+ file_params_type m_file_params;
+ filename_map_type m_filenames;
+
+public:
+ impl(zip_archive_stream* stream);
+
+ void load();
+ zip_file_entry_header get_file_entry_header(std::size_t index) const;
+ zip_file_entry_header get_file_entry_header(std::string_view name) const;
+ std::string_view get_file_entry_name(size_t pos) const;
+
+ size_t get_file_entry_count() const
+ {
+ return m_file_params.size();
+ }
+
+ std::vector<unsigned char> read_file_entry(std::string_view entry_name) const;
+
+private:
+
+ /**
+ * Find the central directory of a zip file, located toward the end before
+ * the global comment, and starts with the byte sequence of 0x504b0506.
+ */
+ size_t seek_central_dir();
+
+ void read_central_dir_end();
+ void read_file_entries();
+};
+
+zip_archive::impl::impl(zip_archive_stream* stream) :
+ m_stream(stream), m_stream_size(0), m_central_dir_pos(0)
+{
+ if (!m_stream)
+ throw zip_error("null stream is not allowed.");
+
+ m_stream_size = m_stream->size();
+}
+
+void zip_archive::impl::load()
+{
+ size_t central_dir_end_pos = seek_central_dir();
+ if (!central_dir_end_pos)
+ throw zip_error("failed to seek the end position of the central directory");
+
+ m_central_dir_end = zip_stream_parser(m_stream, central_dir_end_pos);
+
+ // Read the end part of the central directory.
+ read_central_dir_end();
+
+ // Read file entries that are in the front part of the central directory.
+ read_file_entries();
+}
+
+zip_file_entry_header zip_archive::impl::get_file_entry_header(std::size_t index) const
+{
+ if (index >= m_file_params.size())
+ throw zip_error("invalid file entry index.");
+
+ const zip_file_param& param = m_file_params[index];
+ zip_stream_parser file_header(m_stream, param.offset_file_header);
+
+ zip_file_entry_header header;
+
+ header.header_signature = file_header.read_4bytes();
+ header.required_version = file_header.read_2bytes();
+ header.flag = file_header.read_2bytes();
+ header.compression_method = file_header.read_2bytes();
+ header.last_modified_time = file_header.read_2bytes();
+ header.last_modified_date = file_header.read_2bytes();
+ header.crc32 = file_header.read_4bytes();
+ header.compressed_size = file_header.read_4bytes();
+ header.uncompressed_size = file_header.read_4bytes();
+ uint16_t filename_len = file_header.read_2bytes();
+ uint16_t extra_field_len = file_header.read_2bytes();
+
+ if (filename_len)
+ header.filename = file_header.read_string(filename_len);
+
+ if (extra_field_len)
+ header.extra_field = file_header.read_bytes(extra_field_len);
+
+ return header;
+}
+
+zip_file_entry_header zip_archive::impl::get_file_entry_header(std::string_view name) const
+{
+ auto it = m_filenames.find(name);
+ if (it == m_filenames.end())
+ {
+ std::ostringstream os;
+ os << "file entry named '" << name << "' not found";
+ throw zip_error(os.str());
+ }
+
+ return get_file_entry_header(it->second);
+}
+
+void zip_archive::impl::read_file_entries()
+{
+ m_file_params.clear();
+
+ zip_stream_parser central_dir(m_stream, m_central_dir_pos);
+ uint32_t magic_num = central_dir.read_4bytes();
+
+ while (magic_num == 0x02014b50)
+ {
+ zip_file_param param;
+
+ param.version_made_by = central_dir.read_2bytes();
+ param.minimum_version_needed = central_dir.read_2bytes();
+ param.flags = central_dir.read_2bytes();
+ param.compress_method =
+ static_cast<zip_file_param::compress_method_type>(central_dir.read_2bytes());
+
+ param.last_modified_time = central_dir.read_2bytes();
+ param.last_modified_date = central_dir.read_2bytes();
+ param.crc32 = central_dir.read_4bytes();
+ param.size_compressed = central_dir.read_4bytes();
+ param.size_uncompressed = central_dir.read_4bytes();
+ param.filename_length = central_dir.read_2bytes();
+ param.extra_field_length = central_dir.read_2bytes();
+ param.comment_length = central_dir.read_2bytes();
+ param.disk_id_where_file_starts = central_dir.read_2bytes();
+ param.file_attributes_internal = central_dir.read_2bytes();
+ param.file_attributes_external = central_dir.read_4bytes();
+ param.offset_file_header = central_dir.read_4bytes();
+
+ if (param.filename_length)
+ param.filename = central_dir.read_string(param.filename_length, m_pool);
+
+ if (param.extra_field_length)
+ // Ignore extra field for now.
+ central_dir.skip_bytes(param.extra_field_length);
+
+ if (param.comment_length)
+ // Ignore file comment for now.
+ central_dir.skip_bytes(param.comment_length);
+
+ magic_num = central_dir.read_4bytes(); // magic number for the next entry.
+
+ m_file_params.push_back(param);
+ m_filenames.insert(filename_map_type::value_type(param.filename, m_file_params.size()-1));
+
+#if ORCUS_DEBUG_ZIP_ARCHIVE
+ std::cout << "-- file entries" << std::endl;
+ printf( " magic number: 0x%8.8x\n", magic_num);
+ std::cout << " version made by: " << param.version_made_by << std::endl;
+ std::cout << " minimum version needed to extract: " << param.minimum_version_needed << std::endl;
+ printf( " general purpose bit flag: 0x%4.4x\n", param.flags);
+ std::cout << " compression method: " << param.compress_method << " (0=stored, 8=deflated)" << std::endl;
+ std::cout << " file last modified time: " << param.last_modified_time << std::endl;
+ std::cout << " file last modified date: " << param.last_modified_date << std::endl;
+ printf( " crc32: 0x%8.8x\n", param.crc32);
+ std::cout << " compressed size: " << param.size_compressed << std::endl;
+ std::cout << " uncompressed size: " << param.size_uncompressed << std::endl;
+ std::cout << " file name length: " << param.filename_length << std::endl;
+ std::cout << " extra field length: " << param.extra_field_length << std::endl;
+ std::cout << " file comment length: " << param.comment_length << std::endl;
+ std::cout << " disk number where file starts: " << param.disk_id_where_file_starts << std::endl;
+ printf( " internal file attributes: 0x%4.4x\n", param.file_attributes_internal);
+ printf( " external file attributes: 0x%8.8x\n", param.file_attributes_external);
+ std::cout << " relative offset of local file header: " << param.offset_file_header << std::endl;
+
+ if (param.filename_length)
+ std::cout << " filename: '" << param.filename << "'" << std::endl;
+
+ std::cout << "--" << std::endl;
+#endif
+ }
+}
+
+std::string_view zip_archive::impl::get_file_entry_name(std::size_t pos) const
+{
+ if (pos >= m_file_params.size())
+ return std::string_view{};
+
+ return m_file_params[pos].filename;
+}
+
+std::vector<unsigned char> zip_archive::impl::read_file_entry(std::string_view entry_name) const
+{
+ filename_map_type::const_iterator it = m_filenames.find(entry_name);
+ if (it == m_filenames.end())
+ {
+ std::ostringstream os;
+ os << "entry named '" << entry_name << "' not found";
+ throw zip_error(os.str());
+ }
+
+
+ size_t index = it->second;
+ if (index >= m_file_params.size())
+ throw zip_error("entry index is out-of-bound");
+
+ const zip_file_param& param = m_file_params[index];
+
+ // Skip the file header section.
+ zip_stream_parser file_header(m_stream, param.offset_file_header);
+ file_header.skip_bytes(4);
+ file_header.skip_bytes(2);
+ file_header.skip_bytes(2);
+ file_header.skip_bytes(2);
+ file_header.skip_bytes(2);
+ file_header.skip_bytes(2);
+ file_header.skip_bytes(4);
+ file_header.skip_bytes(4);
+ file_header.skip_bytes(4);
+ uint16_t filename_len = file_header.read_2bytes();
+ uint16_t extra_field_len = file_header.read_2bytes();
+ file_header.skip_bytes(filename_len);
+ file_header.skip_bytes(extra_field_len);
+
+ // Data section is immediately followed by the header section.
+ m_stream->seek(file_header.tell());
+
+ std::vector<unsigned char> raw_buf(param.size_compressed+1, 0);
+ m_stream->read(raw_buf.data(), param.size_compressed);
+
+ switch (param.compress_method)
+ {
+ case zip_file_param::stored:
+ {
+ // Not compressed at all.
+ return raw_buf;
+ }
+ case zip_file_param::deflated:
+ {
+ // deflate compression
+ std::vector<unsigned char> zip_buf(param.size_uncompressed+1, 0); // null-terminated
+ zip_inflater inflater(raw_buf, zip_buf, param);
+ if (!inflater.init())
+ throw zip_error("error during initialization of inflater");
+
+ if (!inflater.inflate())
+ throw zip_error("error during inflate.");
+
+ return zip_buf;
+ }
+ }
+
+ throw std::logic_error("compress method can be either 'stored' or 'deflated', but neither has happened");
+}
+
+size_t zip_archive::impl::seek_central_dir()
+{
+ // Search for the position of 0x06054b50 (read in little endian order - so
+ // it's 0x50, 0x4b, 0x05, 0x06 in this order) somewhere near the end of
+ // the stream.
+
+ unsigned char magic[] = { 0x06, 0x05, 0x4b, 0x50 };
+ size_t n_magic = 4;
+
+ off_t max_comment_size = 0xffff;
+
+ size_t buf_size = 22 + max_comment_size; // central directory size is 22 + n (n maxing at 0xffff).
+ std::vector<unsigned char> buf(buf_size);
+
+ // Read stream backward and try to find the magic number.
+
+ size_t read_end_pos = m_stream_size;
+ while (read_end_pos)
+ {
+ if (read_end_pos < buf.size())
+ // Last segment to read.
+ buf.resize(read_end_pos);
+
+ size_t read_pos = read_end_pos - buf.size();
+ m_stream->seek(read_pos);
+ m_stream->read(&buf[0], buf.size());
+
+ // Search this byte segment for the magic number.
+ std::vector<unsigned char>::reverse_iterator i = buf.rbegin(), ie = buf.rend();
+ size_t magic_pos = 0;
+ for (; i != ie; ++i)
+ {
+ // 06 05 4b 50
+ if (*i == magic[magic_pos])
+ {
+ ++magic_pos;
+ if (magic_pos == n_magic)
+ {
+ // magic number is found.
+ size_t dist = distance(buf.rbegin(), i) + 1;
+ size_t pos = read_end_pos - dist;
+ return pos;
+ }
+ }
+ else
+ magic_pos = 0;
+ }
+
+ read_end_pos -= buf.size();
+ }
+
+ return 0;
+}
+
+void zip_archive::impl::read_central_dir_end()
+{
+ central_dir_end content;
+ content.magic_number = m_central_dir_end.read_4bytes();
+ content.this_disk_id = m_central_dir_end.read_2bytes();
+ content.central_dir_disk_id = m_central_dir_end.read_2bytes();
+ content.num_central_dir_records_local = m_central_dir_end.read_2bytes();
+ content.num_celtral_dir_records_total = m_central_dir_end.read_2bytes();
+ content.size_central_dir = m_central_dir_end.read_4bytes();
+ content.central_dir_pos = m_central_dir_end.read_4bytes();
+ m_central_dir_pos = content.central_dir_pos;
+
+ content.comment_length = m_central_dir_end.read_2bytes();
+
+#if ORCUS_DEBUG_ZIP_ARCHIVE
+ std::cout << "-- central directory content" << std::endl;
+ printf(" magic number: 0x%8.8x\n", content.magic_number);
+ std::cout << " number of this disk: " << content.this_disk_id << std::endl;
+ std::cout << " disk where central directory starts: " << content.central_dir_disk_id << std::endl;
+ std::cout << " number of central directory records on this disk: " << content.num_central_dir_records_local << std::endl;
+ std::cout << " total number of central directory records: " << content.num_celtral_dir_records_total << std::endl;
+ std::cout << " size of central directory: " << content.size_central_dir << std::endl;
+ std::cout << " offset of start of central directory, relative to start of archive: " << content.central_dir_pos << std::endl;
+ std::cout << " comment length: " << content.comment_length << std::endl;
+ std::cout << "--" << std::endl;
+#endif
+}
+
+zip_archive::zip_archive(zip_archive_stream* stream) : mp_impl(std::make_unique<impl>(stream))
+{
+}
+
+zip_archive::~zip_archive() = default;
+
+void zip_archive::load()
+{
+ mp_impl->load();
+}
+
+zip_file_entry_header zip_archive::get_file_entry_header(std::size_t index) const
+{
+ return mp_impl->get_file_entry_header(index);
+}
+
+zip_file_entry_header zip_archive::get_file_entry_header(std::string_view name) const
+{
+ return mp_impl->get_file_entry_header(name);
+}
+
+std::string_view zip_archive::get_file_entry_name(std::size_t index) const
+{
+ return mp_impl->get_file_entry_name(index);
+}
+
+size_t zip_archive::get_file_entry_count() const
+{
+ return mp_impl->get_file_entry_count();
+}
+
+std::vector<unsigned char> zip_archive::read_file_entry(std::string_view entry_name) const
+{
+ return mp_impl->read_file_entry(entry_name);
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/zip_archive_stream.cpp b/src/parser/zip_archive_stream.cpp
new file mode 100644
index 0000000..776ac14
--- /dev/null
+++ b/src/parser/zip_archive_stream.cpp
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/zip_archive_stream.hpp"
+#include "orcus/zip_archive.hpp"
+
+#include <sstream>
+#include <cstring>
+
+#ifdef _MSC_VER
+#define fseeko _fseeki64
+#define ftello _ftelli64
+#endif
+
+using namespace std;
+
+namespace orcus {
+
+zip_archive_stream::~zip_archive_stream() {}
+
+zip_archive_stream_fd::zip_archive_stream_fd(const char* filepath) :
+ m_stream(fopen(filepath, "rb"))
+{
+ if (!m_stream)
+ {
+ // Fail early at instantiation time.
+ ostringstream os;
+ os << "failed to open " << filepath << " for reading";
+ throw zip_error(os.str());
+ }
+}
+
+zip_archive_stream_fd::~zip_archive_stream_fd()
+{
+ if (m_stream)
+ fclose(m_stream);
+}
+
+size_t zip_archive_stream_fd::size() const
+{
+ if (fseeko(m_stream, 0, SEEK_END))
+ throw zip_error("failed to set seek position to the end of stream.");
+
+ return ftello(m_stream);
+}
+
+size_t zip_archive_stream_fd::tell() const
+{
+ return ftello(m_stream);
+}
+
+void zip_archive_stream_fd::read(unsigned char* buffer, size_t length) const
+{
+ size_t size_read = fread(buffer, 1, length, m_stream);
+ if (size_read != length)
+ throw zip_error("actual size read doesn't match what was expected.");
+}
+
+void zip_archive_stream_fd::seek(size_t pos)
+{
+ if (fseeko(m_stream, pos, SEEK_SET))
+ {
+ ostringstream os;
+ os << "failed to set seek position to " << pos << ".";
+ throw zip_error(os.str());
+ }
+}
+
+
+zip_archive_stream_blob::zip_archive_stream_blob(const uint8_t* blob, std::size_t size) :
+ m_blob(blob), m_cur(blob), m_size(size) {}
+
+zip_archive_stream_blob::~zip_archive_stream_blob() {}
+
+size_t zip_archive_stream_blob::size() const
+{
+ return m_size;
+}
+
+size_t zip_archive_stream_blob::tell() const
+{
+ return std::distance(m_blob, m_cur);
+}
+
+void zip_archive_stream_blob::seek(size_t pos)
+{
+ if (pos > m_size)
+ {
+ ostringstream os;
+ os << "failed to seek position to " << pos << ".";
+ throw zip_error(os.str());
+ }
+ m_cur = m_blob + pos;
+}
+
+void zip_archive_stream_blob::read(unsigned char* buffer, size_t length) const
+{
+ if (!length)
+ return;
+ // First, make sure we have enough blob to satisfy the requested stream length.
+ const size_t length_available = m_size - tell();
+ if (length_available < length)
+ throw zip_error("There is not enough stream left to fill requested length.");
+
+ memcpy(buffer, m_cur, length);
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/zip_archive_test.cpp b/src/parser/zip_archive_test.cpp
new file mode 100644
index 0000000..bbaa597
--- /dev/null
+++ b/src/parser/zip_archive_test.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <algorithm>
+#include <cstdlib>
+#include <vector>
+
+#include <orcus/zip_archive_stream.hpp>
+#include <orcus/zip_archive.hpp>
+
+#include "filesystem_env.hpp"
+
+#define ASSERT_THROW(expr) \
+try \
+{ \
+ expr; \
+ assert(0); \
+} \
+catch (...) \
+{ \
+}
+
+using namespace orcus;
+
+void test_zip_archive_stream(zip_archive_stream* const strm, const unsigned char* const data, std::size_t const length)
+{
+ assert(strm->size() == length);
+ assert(strm->tell() == 0);
+
+ std::vector<unsigned char> buffer(length, 0);
+ unsigned char* buf = buffer.data();
+
+ strm->read(buf, 2);
+ assert(std::equal(data, data + 2, buf));
+ assert(strm->tell() == 0);
+ strm->read(buf, length);
+ assert(std::equal(data, data + length, buf));
+ ASSERT_THROW(strm->read(buf, length + 1));
+ strm->read(buf, 0);
+
+ strm->seek(2);
+ assert(strm->tell() == 2);
+ strm->read(buf, 2);
+ assert(std::equal(data + 2, data + 4, buf));
+ strm->seek(length);
+ assert(strm->tell() == length);
+ ASSERT_THROW(strm->seek(length + 1));
+ assert(strm->tell() == length);
+}
+
+void test_zip_archive_stream_blob()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ const unsigned char data[] = "My hovercraft is full of eels.";
+ zip_archive_stream_blob strm(data, sizeof(data));
+ test_zip_archive_stream(&strm, data, sizeof(data));
+}
+
+void test_zip_archive_file_entry_header()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath{SRCDIR"/test/ods/raw-values-1/input.ods"};
+ assert(fs::is_regular_file(filepath));
+
+ zip_archive_stream_fd strm(filepath.string().c_str());
+
+ zip_archive archive(&strm);
+ archive.load();
+ std::size_t n_entries = archive.get_file_entry_count();
+ for (std::size_t i = 0; i < n_entries; ++i)
+ {
+ std::string_view name = archive.get_file_entry_name(i);
+ std::cout << "* entry name: " << name << std::endl;
+ zip_file_entry_header header = archive.get_file_entry_header(i);
+ assert(header.filename == name);
+ assert(header.header_signature == 0x04034b50);
+
+ // 0 = none; 8 = deflate
+ assert(header.compression_method == 0 || header.compression_method == 8);
+ }
+}
+
+int main()
+{
+ test_zip_archive_stream_blob();
+ test_zip_archive_file_entry_header();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/Makefile.am b/src/python/Makefile.am
new file mode 100644
index 0000000..a1199fd
--- /dev/null
+++ b/src/python/Makefile.am
@@ -0,0 +1,140 @@
+if BUILD_PYTHON
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include \
+ $(BOOST_CPPFLAGS) \
+ $(PYTHON_CFLAGS) \
+ $(MDDS_CFLAGS) \
+ $(LIBIXION_CFLAGS)
+
+pyexec_LTLIBRARIES = _orcus.la _orcus_json.la
+
+_orcus_la_SOURCES = \
+ python.cpp \
+ global.hpp \
+ global.cpp \
+ memory.hpp \
+ memory.cpp \
+ root.hpp \
+ root.cpp \
+ xlsx.hpp \
+ xlsx.cpp \
+ xls_xml.hpp \
+ xls_xml.cpp \
+ ods.hpp \
+ ods.cpp \
+ csv.hpp \
+ csv.cpp \
+ gnumeric.hpp \
+ gnumeric.cpp
+
+_orcus_la_LDFLAGS = -module -avoid-version -export-symbols-regex PyInit__orcus
+_orcus_la_LIBADD = \
+ ../liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(PYTHON_LIBS)
+
+if BUILD_SPREADSHEET_MODEL
+
+_orcus_la_SOURCES += \
+ document.hpp \
+ document.cpp \
+ sheet.hpp \
+ sheet.cpp \
+ sheet_rows.hpp \
+ sheet_rows.cpp \
+ cell.hpp \
+ cell.cpp \
+ formula_token.hpp \
+ formula_token.cpp \
+ formula_tokens.hpp \
+ formula_tokens.cpp \
+ named_expressions.hpp \
+ named_expressions.cpp \
+ named_expression.hpp \
+ named_expression.cpp
+
+_orcus_la_LIBADD += \
+ ../spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+ $(LIBIXION_LIBS)
+
+endif # BUILD_SPREADSHEET_MODEL
+
+_orcus_json_la_SOURCES = \
+ json.cpp
+
+_orcus_json_la_LDFLAGS = -module -avoid-version -export-symbols-regex PyInit__orcus_json
+_orcus_json_la_LIBADD = \
+ ../liborcus/liborcus-@ORCUS_API_VERSION@.la \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(PYTHON_LIBS)
+
+orcusdir = $(pythondir)/orcus
+orcustoolsdir = $(pythondir)/orcus/tools
+
+orcus_DATA = \
+ ./orcus/__init__.py \
+ ./orcus/csv.py \
+ ./orcus/gnumeric.py \
+ ./orcus/json.py \
+ ./orcus/ods.py \
+ ./orcus/xls_xml.py \
+ ./orcus/xlsx.py
+
+orcustools_DATA = \
+ ./orcus/tools/__init__.py \
+ ./orcus/tools/bugzilla.py \
+ ./orcus/tools/file_processor.py
+
+EXTRA_DIST = \
+ ./orcus/__init__.py \
+ ./orcus/csv.py \
+ ./orcus/gnumeric.py \
+ ./orcus/json.py \
+ ./orcus/ods.py \
+ ./orcus/xls_xml.py \
+ ./orcus/xlsx.py \
+ ./orcus/tools/__init__.py \
+ ./orcus/tools/bugzilla.py \
+ ./orcus/tools/file_processor.py
+
+AM_TESTS_ENVIRONMENT = \
+ PYTHONPATH=$(top_srcdir)/src/python:.libs$${PYTHONPATH:+:$${PYTHONPATH}}; export PYTHONPATH; \
+ BUILDDIR=$(top_builddir); export BUILDDIR;
+
+TESTS = \
+ ../../test/python/test_json.py \
+ ../../test/python/test_module.py \
+ ../../test/python/test_csv.py \
+ ../../test/python/test_csv_export.py
+
+if WITH_PYTHON_XLSX
+
+TESTS += ../../test/python/test_xlsx.py
+AM_TESTS_ENVIRONMENT += export WITH_PYTHON_XLSX=1;
+
+endif # WITH_PYTHON_XLSX
+
+if WITH_PYTHON_ODS
+
+TESTS += ../../test/python/test_ods.py
+AM_TESTS_ENVIRONMENT += export WITH_PYTHON_ODS=1;
+
+endif # WITH_PYTHON_ODS
+
+if WITH_PYTHON_XLS_XML
+
+TESTS += ../../test/python/test_xls_xml.py
+AM_TESTS_ENVIRONMENT += export WITH_PYTHON_XLS_XML=1;
+
+endif # WITH_PYTHON_XLS_XML
+
+if WITH_PYTHON_GNUMERIC
+
+TESTS += ../../test/python/test_gnumeric.py
+AM_TESTS_ENVIRONMENT += export WITH_PYTHON_GNUMERIC=1;
+
+endif # WITH_PYTHON_GNUMERIC
+
+endif # BUILD_PYTHON
diff --git a/src/python/Makefile.in b/src/python/Makefile.in
new file mode 100644
index 0000000..fff782a
--- /dev/null
+++ b/src/python/Makefile.in
@@ -0,0 +1,1405 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@am__append_1 = \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ document.hpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ document.cpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ sheet.hpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ sheet.cpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ sheet_rows.hpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ sheet_rows.cpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ cell.hpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ cell.cpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ formula_token.hpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ formula_token.cpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ formula_tokens.hpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ formula_tokens.cpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ named_expressions.hpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ named_expressions.cpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ named_expression.hpp \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ named_expression.cpp
+
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@am__append_2 = \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ ../spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ $(LIBIXION_LIBS)
+
+@BUILD_PYTHON_TRUE@@WITH_PYTHON_XLSX_TRUE@am__append_3 = ../../test/python/test_xlsx.py
+@BUILD_PYTHON_TRUE@@WITH_PYTHON_XLSX_TRUE@am__append_4 = export WITH_PYTHON_XLSX=1;
+@BUILD_PYTHON_TRUE@@WITH_PYTHON_ODS_TRUE@am__append_5 = ../../test/python/test_ods.py
+@BUILD_PYTHON_TRUE@@WITH_PYTHON_ODS_TRUE@am__append_6 = export WITH_PYTHON_ODS=1;
+@BUILD_PYTHON_TRUE@@WITH_PYTHON_XLS_XML_TRUE@am__append_7 = ../../test/python/test_xls_xml.py
+@BUILD_PYTHON_TRUE@@WITH_PYTHON_XLS_XML_TRUE@am__append_8 = export WITH_PYTHON_XLS_XML=1;
+@BUILD_PYTHON_TRUE@@WITH_PYTHON_GNUMERIC_TRUE@am__append_9 = ../../test/python/test_gnumeric.py
+@BUILD_PYTHON_TRUE@@WITH_PYTHON_GNUMERIC_TRUE@am__append_10 = export WITH_PYTHON_GNUMERIC=1;
+subdir = src/python
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pyexecdir)" "$(DESTDIR)$(orcusdir)" \
+ "$(DESTDIR)$(orcustoolsdir)"
+LTLIBRARIES = $(pyexec_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@am__DEPENDENCIES_2 = ../spreadsheet/liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1)
+@BUILD_PYTHON_TRUE@_orcus_la_DEPENDENCIES = ../liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_PYTHON_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_PYTHON_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+am___orcus_la_SOURCES_DIST = python.cpp global.hpp global.cpp \
+ memory.hpp memory.cpp root.hpp root.cpp xlsx.hpp xlsx.cpp \
+ xls_xml.hpp xls_xml.cpp ods.hpp ods.cpp csv.hpp csv.cpp \
+ gnumeric.hpp gnumeric.cpp document.hpp document.cpp sheet.hpp \
+ sheet.cpp sheet_rows.hpp sheet_rows.cpp cell.hpp cell.cpp \
+ formula_token.hpp formula_token.cpp formula_tokens.hpp \
+ formula_tokens.cpp named_expressions.hpp named_expressions.cpp \
+ named_expression.hpp named_expression.cpp
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@am__objects_1 = \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ document.lo \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ sheet.lo \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ sheet_rows.lo \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ cell.lo \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ formula_token.lo \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ formula_tokens.lo \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ named_expressions.lo \
+@BUILD_PYTHON_TRUE@@BUILD_SPREADSHEET_MODEL_TRUE@ named_expression.lo
+@BUILD_PYTHON_TRUE@am__orcus_la_OBJECTS = python.lo global.lo \
+@BUILD_PYTHON_TRUE@ memory.lo root.lo xlsx.lo xls_xml.lo ods.lo \
+@BUILD_PYTHON_TRUE@ csv.lo gnumeric.lo $(am__objects_1)
+_orcus_la_OBJECTS = $(am__orcus_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+_orcus_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(_orcus_la_LDFLAGS) $(LDFLAGS) -o $@
+@BUILD_PYTHON_TRUE@am__orcus_la_rpath = -rpath $(pyexecdir)
+@BUILD_PYTHON_TRUE@_orcus_json_la_DEPENDENCIES = ../liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_PYTHON_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_PYTHON_TRUE@ $(am__DEPENDENCIES_1)
+am___orcus_json_la_SOURCES_DIST = json.cpp
+@BUILD_PYTHON_TRUE@am__orcus_json_la_OBJECTS = json.lo
+_orcus_json_la_OBJECTS = $(am__orcus_json_la_OBJECTS)
+_orcus_json_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(_orcus_json_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_PYTHON_TRUE@am__orcus_json_la_rpath = -rpath $(pyexecdir)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cell.Plo ./$(DEPDIR)/csv.Plo \
+ ./$(DEPDIR)/document.Plo ./$(DEPDIR)/formula_token.Plo \
+ ./$(DEPDIR)/formula_tokens.Plo ./$(DEPDIR)/global.Plo \
+ ./$(DEPDIR)/gnumeric.Plo ./$(DEPDIR)/json.Plo \
+ ./$(DEPDIR)/memory.Plo ./$(DEPDIR)/named_expression.Plo \
+ ./$(DEPDIR)/named_expressions.Plo ./$(DEPDIR)/ods.Plo \
+ ./$(DEPDIR)/python.Plo ./$(DEPDIR)/root.Plo \
+ ./$(DEPDIR)/sheet.Plo ./$(DEPDIR)/sheet_rows.Plo \
+ ./$(DEPDIR)/xls_xml.Plo ./$(DEPDIR)/xlsx.Plo
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(_orcus_la_SOURCES) $(_orcus_json_la_SOURCES)
+DIST_SOURCES = $(am___orcus_la_SOURCES_DIST) \
+ $(am___orcus_json_la_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(orcus_DATA) $(orcustools_DATA)
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+@BUILD_PYTHON_TRUE@AM_CPPFLAGS = \
+@BUILD_PYTHON_TRUE@ -I$(top_srcdir)/include \
+@BUILD_PYTHON_TRUE@ -I$(top_srcdir)/src/include \
+@BUILD_PYTHON_TRUE@ $(BOOST_CPPFLAGS) \
+@BUILD_PYTHON_TRUE@ $(PYTHON_CFLAGS) \
+@BUILD_PYTHON_TRUE@ $(MDDS_CFLAGS) \
+@BUILD_PYTHON_TRUE@ $(LIBIXION_CFLAGS)
+
+@BUILD_PYTHON_TRUE@pyexec_LTLIBRARIES = _orcus.la _orcus_json.la
+@BUILD_PYTHON_TRUE@_orcus_la_SOURCES = python.cpp global.hpp \
+@BUILD_PYTHON_TRUE@ global.cpp memory.hpp memory.cpp root.hpp \
+@BUILD_PYTHON_TRUE@ root.cpp xlsx.hpp xlsx.cpp xls_xml.hpp \
+@BUILD_PYTHON_TRUE@ xls_xml.cpp ods.hpp ods.cpp csv.hpp csv.cpp \
+@BUILD_PYTHON_TRUE@ gnumeric.hpp gnumeric.cpp $(am__append_1)
+@BUILD_PYTHON_TRUE@_orcus_la_LDFLAGS = -module -avoid-version -export-symbols-regex PyInit__orcus
+@BUILD_PYTHON_TRUE@_orcus_la_LIBADD = ../liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_PYTHON_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_PYTHON_TRUE@ $(PYTHON_LIBS) $(am__append_2)
+@BUILD_PYTHON_TRUE@_orcus_json_la_SOURCES = \
+@BUILD_PYTHON_TRUE@ json.cpp
+
+@BUILD_PYTHON_TRUE@_orcus_json_la_LDFLAGS = -module -avoid-version -export-symbols-regex PyInit__orcus_json
+@BUILD_PYTHON_TRUE@_orcus_json_la_LIBADD = \
+@BUILD_PYTHON_TRUE@ ../liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_PYTHON_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_PYTHON_TRUE@ $(PYTHON_LIBS)
+
+@BUILD_PYTHON_TRUE@orcusdir = $(pythondir)/orcus
+@BUILD_PYTHON_TRUE@orcustoolsdir = $(pythondir)/orcus/tools
+@BUILD_PYTHON_TRUE@orcus_DATA = \
+@BUILD_PYTHON_TRUE@ ./orcus/__init__.py \
+@BUILD_PYTHON_TRUE@ ./orcus/csv.py \
+@BUILD_PYTHON_TRUE@ ./orcus/gnumeric.py \
+@BUILD_PYTHON_TRUE@ ./orcus/json.py \
+@BUILD_PYTHON_TRUE@ ./orcus/ods.py \
+@BUILD_PYTHON_TRUE@ ./orcus/xls_xml.py \
+@BUILD_PYTHON_TRUE@ ./orcus/xlsx.py
+
+@BUILD_PYTHON_TRUE@orcustools_DATA = \
+@BUILD_PYTHON_TRUE@ ./orcus/tools/__init__.py \
+@BUILD_PYTHON_TRUE@ ./orcus/tools/bugzilla.py \
+@BUILD_PYTHON_TRUE@ ./orcus/tools/file_processor.py
+
+@BUILD_PYTHON_TRUE@EXTRA_DIST = \
+@BUILD_PYTHON_TRUE@ ./orcus/__init__.py \
+@BUILD_PYTHON_TRUE@ ./orcus/csv.py \
+@BUILD_PYTHON_TRUE@ ./orcus/gnumeric.py \
+@BUILD_PYTHON_TRUE@ ./orcus/json.py \
+@BUILD_PYTHON_TRUE@ ./orcus/ods.py \
+@BUILD_PYTHON_TRUE@ ./orcus/xls_xml.py \
+@BUILD_PYTHON_TRUE@ ./orcus/xlsx.py \
+@BUILD_PYTHON_TRUE@ ./orcus/tools/__init__.py \
+@BUILD_PYTHON_TRUE@ ./orcus/tools/bugzilla.py \
+@BUILD_PYTHON_TRUE@ ./orcus/tools/file_processor.py
+
+@BUILD_PYTHON_TRUE@AM_TESTS_ENVIRONMENT = PYTHONPATH=$(top_srcdir)/src/python:.libs$${PYTHONPATH:+:$${PYTHONPATH}}; \
+@BUILD_PYTHON_TRUE@ export PYTHONPATH; \
+@BUILD_PYTHON_TRUE@ BUILDDIR=$(top_builddir); export BUILDDIR; \
+@BUILD_PYTHON_TRUE@ $(am__append_4) $(am__append_6) \
+@BUILD_PYTHON_TRUE@ $(am__append_8) $(am__append_10)
+@BUILD_PYTHON_TRUE@TESTS = ../../test/python/test_json.py \
+@BUILD_PYTHON_TRUE@ ../../test/python/test_module.py \
+@BUILD_PYTHON_TRUE@ ../../test/python/test_csv.py \
+@BUILD_PYTHON_TRUE@ ../../test/python/test_csv_export.py \
+@BUILD_PYTHON_TRUE@ $(am__append_3) $(am__append_5) \
+@BUILD_PYTHON_TRUE@ $(am__append_7) $(am__append_9)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/python/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/python/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pyexecLTLIBRARIES: $(pyexec_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pyexec_LTLIBRARIES)'; test -n "$(pyexecdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pyexecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pyexecdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pyexecdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pyexecdir)"; \
+ }
+
+uninstall-pyexecLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pyexec_LTLIBRARIES)'; test -n "$(pyexecdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pyexecdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pyexecdir)/$$f"; \
+ done
+
+clean-pyexecLTLIBRARIES:
+ -test -z "$(pyexec_LTLIBRARIES)" || rm -f $(pyexec_LTLIBRARIES)
+ @list='$(pyexec_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+_orcus.la: $(_orcus_la_OBJECTS) $(_orcus_la_DEPENDENCIES) $(EXTRA__orcus_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(_orcus_la_LINK) $(am__orcus_la_rpath) $(_orcus_la_OBJECTS) $(_orcus_la_LIBADD) $(LIBS)
+
+_orcus_json.la: $(_orcus_json_la_OBJECTS) $(_orcus_json_la_DEPENDENCIES) $(EXTRA__orcus_json_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(_orcus_json_la_LINK) $(am__orcus_json_la_rpath) $(_orcus_json_la_OBJECTS) $(_orcus_json_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cell.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csv.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/document.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/formula_token.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/formula_tokens.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnumeric.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/named_expression.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/named_expressions.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ods.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/python.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/root.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sheet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sheet_rows.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xls_xml.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlsx.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-orcusDATA: $(orcus_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(orcus_DATA)'; test -n "$(orcusdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(orcusdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(orcusdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(orcusdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(orcusdir)" || exit $$?; \
+ done
+
+uninstall-orcusDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(orcus_DATA)'; test -n "$(orcusdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(orcusdir)'; $(am__uninstall_files_from_dir)
+install-orcustoolsDATA: $(orcustools_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(orcustools_DATA)'; test -n "$(orcustoolsdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(orcustoolsdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(orcustoolsdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(orcustoolsdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(orcustoolsdir)" || exit $$?; \
+ done
+
+uninstall-orcustoolsDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(orcustools_DATA)'; test -n "$(orcustoolsdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(orcustoolsdir)'; $(am__uninstall_files_from_dir)
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+../../test/python/test_json.py.log: ../../test/python/test_json.py
+ @p='../../test/python/test_json.py'; \
+ b='../../test/python/test_json.py'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+../../test/python/test_module.py.log: ../../test/python/test_module.py
+ @p='../../test/python/test_module.py'; \
+ b='../../test/python/test_module.py'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+../../test/python/test_csv.py.log: ../../test/python/test_csv.py
+ @p='../../test/python/test_csv.py'; \
+ b='../../test/python/test_csv.py'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+../../test/python/test_csv_export.py.log: ../../test/python/test_csv_export.py
+ @p='../../test/python/test_csv_export.py'; \
+ b='../../test/python/test_csv_export.py'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+../../test/python/test_xlsx.py.log: ../../test/python/test_xlsx.py
+ @p='../../test/python/test_xlsx.py'; \
+ b='../../test/python/test_xlsx.py'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+../../test/python/test_ods.py.log: ../../test/python/test_ods.py
+ @p='../../test/python/test_ods.py'; \
+ b='../../test/python/test_ods.py'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+../../test/python/test_xls_xml.py.log: ../../test/python/test_xls_xml.py
+ @p='../../test/python/test_xls_xml.py'; \
+ b='../../test/python/test_xls_xml.py'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+../../test/python/test_gnumeric.py.log: ../../test/python/test_gnumeric.py
+ @p='../../test/python/test_gnumeric.py'; \
+ b='../../test/python/test_gnumeric.py'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pyexecdir)" "$(DESTDIR)$(orcusdir)" "$(DESTDIR)$(orcustoolsdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-am
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-am
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-am
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-am
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-am
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pyexecLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cell.Plo
+ -rm -f ./$(DEPDIR)/csv.Plo
+ -rm -f ./$(DEPDIR)/document.Plo
+ -rm -f ./$(DEPDIR)/formula_token.Plo
+ -rm -f ./$(DEPDIR)/formula_tokens.Plo
+ -rm -f ./$(DEPDIR)/global.Plo
+ -rm -f ./$(DEPDIR)/gnumeric.Plo
+ -rm -f ./$(DEPDIR)/json.Plo
+ -rm -f ./$(DEPDIR)/memory.Plo
+ -rm -f ./$(DEPDIR)/named_expression.Plo
+ -rm -f ./$(DEPDIR)/named_expressions.Plo
+ -rm -f ./$(DEPDIR)/ods.Plo
+ -rm -f ./$(DEPDIR)/python.Plo
+ -rm -f ./$(DEPDIR)/root.Plo
+ -rm -f ./$(DEPDIR)/sheet.Plo
+ -rm -f ./$(DEPDIR)/sheet_rows.Plo
+ -rm -f ./$(DEPDIR)/xls_xml.Plo
+ -rm -f ./$(DEPDIR)/xlsx.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-orcusDATA install-orcustoolsDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pyexecLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cell.Plo
+ -rm -f ./$(DEPDIR)/csv.Plo
+ -rm -f ./$(DEPDIR)/document.Plo
+ -rm -f ./$(DEPDIR)/formula_token.Plo
+ -rm -f ./$(DEPDIR)/formula_tokens.Plo
+ -rm -f ./$(DEPDIR)/global.Plo
+ -rm -f ./$(DEPDIR)/gnumeric.Plo
+ -rm -f ./$(DEPDIR)/json.Plo
+ -rm -f ./$(DEPDIR)/memory.Plo
+ -rm -f ./$(DEPDIR)/named_expression.Plo
+ -rm -f ./$(DEPDIR)/named_expressions.Plo
+ -rm -f ./$(DEPDIR)/ods.Plo
+ -rm -f ./$(DEPDIR)/python.Plo
+ -rm -f ./$(DEPDIR)/root.Plo
+ -rm -f ./$(DEPDIR)/sheet.Plo
+ -rm -f ./$(DEPDIR)/sheet_rows.Plo
+ -rm -f ./$(DEPDIR)/xls_xml.Plo
+ -rm -f ./$(DEPDIR)/xlsx.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-orcusDATA uninstall-orcustoolsDATA \
+ uninstall-pyexecLTLIBRARIES
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am check-valgrind-am check-valgrind-drd-am \
+ check-valgrind-drd-local check-valgrind-helgrind-am \
+ check-valgrind-helgrind-local check-valgrind-local \
+ check-valgrind-memcheck-am check-valgrind-memcheck-local \
+ check-valgrind-sgcheck-am check-valgrind-sgcheck-local clean \
+ clean-generic clean-libtool clean-pyexecLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-orcusDATA \
+ install-orcustoolsDATA install-pdf install-pdf-am install-ps \
+ install-ps-am install-pyexecLTLIBRARIES install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ recheck tags tags-am uninstall uninstall-am \
+ uninstall-orcusDATA uninstall-orcustoolsDATA \
+ uninstall-pyexecLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/python/cell.cpp b/src/python/cell.cpp
new file mode 100644
index 0000000..a4a46b0
--- /dev/null
+++ b/src/python/cell.cpp
@@ -0,0 +1,349 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "cell.hpp"
+#include "memory.hpp"
+#include "global.hpp"
+#include "formula_token.hpp"
+#include "formula_tokens.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/cell.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/model_context.hpp>
+
+#include <structmember.h>
+#include <string>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus { namespace python {
+
+namespace {
+
+/** non-python part of the object. */
+struct cell_data
+{
+ const ss::document* doc = nullptr;
+ const ixion::formula_cell* formula_cell = nullptr;
+ ixion::abs_address_t origin;
+};
+
+/**
+ * Python object for orcus.Cell.
+ */
+struct pyobj_cell
+{
+ PyObject_HEAD
+
+ PyObject* type;
+ PyObject* value;
+ PyObject* formula;
+
+ cell_data* data = nullptr;
+};
+
+void initialize_cell_members(pyobj_cell* self)
+{
+ Py_INCREF(Py_None);
+ self->value = Py_None;
+
+ Py_INCREF(Py_None);
+ self->formula = Py_None;
+}
+
+PyObject* create_and_init_cell_object(const char* type_name)
+{
+ PyTypeObject* cell_type = get_cell_type();
+ if (!cell_type)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to get the cell type object.");
+ return nullptr;
+ }
+
+ PyObject* obj = cell_type->tp_new(cell_type, nullptr, nullptr);
+ if (!obj)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to instantiate a cell object.");
+ return nullptr;
+ }
+
+ pyobj_cell* self = reinterpret_cast<pyobj_cell*>(obj);
+ self->type = get_python_enum_value("CellType", type_name);
+ initialize_cell_members(self);
+
+ return obj;
+}
+
+void tp_dealloc(pyobj_cell* self)
+{
+ delete self->data;
+ self->data = nullptr;
+
+ Py_CLEAR(self->type);
+ Py_CLEAR(self->value);
+ Py_CLEAR(self->formula);
+
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+PyObject* tp_new(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ pyobj_cell* self = (pyobj_cell*)type->tp_alloc(type, 0);
+ self->data = new cell_data;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+int tp_init(pyobj_cell* self, PyObject* args, PyObject* kwargs)
+{
+ static const char* kwlist[] = { "type", nullptr };
+
+ self->type = nullptr;
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", const_cast<char**>(kwlist), &self->type))
+ return -1;
+
+ if (!self->type)
+ self->type = get_python_enum_value("CellType", "UNKNOWN");
+
+ initialize_cell_members(self);
+ return 0;
+}
+
+PyObject* cell_get_formula_tokens(PyObject* self, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ pyobj_cell* obj = reinterpret_cast<pyobj_cell*>(self);
+ cell_data& data = *obj->data;
+ if (!data.formula_cell)
+ {
+ // This is not a formula cell.
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ const ixion::formula_tokens_t& tokens = data.formula_cell->get_tokens()->get();
+ return create_formula_tokens_iterator_object(*data.doc, data.origin, tokens);
+}
+
+PyMethodDef tp_methods[] =
+{
+ { "get_formula_tokens", (PyCFunction)cell_get_formula_tokens, METH_NOARGS, "Get a formula tokens iterator." },
+ { nullptr }
+};
+
+PyMemberDef tp_members[] =
+{
+ { (char*)"type", T_OBJECT_EX, offsetof(pyobj_cell, type), READONLY, (char*)"cell type" },
+ { (char*)"value", T_OBJECT_EX, offsetof(pyobj_cell, value), READONLY, (char*)"cell value" },
+ { (char*)"formula", T_OBJECT_EX, offsetof(pyobj_cell, formula), READONLY, (char*)"formula string" },
+ { nullptr }
+};
+
+PyTypeObject cell_type =
+{
+ PyVarObject_HEAD_INIT(nullptr, 0)
+ "orcus.Cell", // tp_name
+ sizeof(pyobj_cell), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)tp_dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ 0, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
+ "orcus spreadsheet cell", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ tp_methods, // tp_methods
+ tp_members, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)tp_init, // tp_init
+ 0, // tp_alloc
+ tp_new, // tp_new
+};
+
+} // anonymous namespace
+
+PyObject* create_cell_object_empty()
+{
+ PyObject* obj = create_and_init_cell_object("EMPTY");
+ if (!obj)
+ return nullptr;
+
+ return obj;
+}
+
+PyObject* create_cell_object_boolean(bool v)
+{
+ PyObject* obj = create_and_init_cell_object("BOOLEAN");
+ if (!obj)
+ return nullptr;
+
+ pyobj_cell* obj_data = reinterpret_cast<pyobj_cell*>(obj);
+
+ if (v)
+ {
+ Py_INCREF(Py_True);
+ obj_data->value = Py_True;
+ }
+ else
+ {
+ Py_INCREF(Py_False);
+ obj_data->value = Py_False;
+ }
+
+ return obj;
+}
+
+PyObject* create_cell_object_string(const std::string* p)
+{
+ PyObject* obj = create_and_init_cell_object("STRING");
+ if (!obj)
+ return nullptr;
+
+ pyobj_cell* obj_data = reinterpret_cast<pyobj_cell*>(obj);
+
+ if (p)
+ {
+ obj_data->value = PyUnicode_FromStringAndSize(p->data(), p->size());
+ if (!obj_data->value)
+ {
+ // The string contains invalid utf-8 sequence, and the function has
+ // already set a python exception which needs to be cleared.
+ PyErr_Clear();
+ Py_XDECREF(obj);
+ obj = create_and_init_cell_object("STRING_WITH_ERROR");
+ }
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ obj_data->value = Py_None;
+ }
+
+ return obj;
+}
+
+PyObject* create_cell_object_numeric(double v)
+{
+ PyObject* obj = create_and_init_cell_object("NUMERIC");
+ if (!obj)
+ return nullptr;
+
+ pyobj_cell* obj_data = reinterpret_cast<pyobj_cell*>(obj);
+ obj_data->value = PyFloat_FromDouble(v);
+
+ return obj;
+}
+
+PyObject* create_cell_object_formula(
+ const spreadsheet::document& doc, const ixion::abs_address_t& origin, const ixion::formula_cell* fc)
+{
+ if (!fc)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "failed to find class orcus.CellType.");
+ return nullptr;
+ }
+
+ const ixion::formula_tokens_t& tokens = fc->get_tokens()->get();
+ bool is_error = !tokens.empty() && tokens[0].opcode == ixion::fop_error;
+
+ PyObject* obj = create_and_init_cell_object(is_error ? "FORMULA_WITH_ERROR": "FORMULA");
+ if (!obj)
+ return nullptr;
+
+ pyobj_cell* obj_data = reinterpret_cast<pyobj_cell*>(obj);
+ obj_data->data->doc = &doc;
+ obj_data->data->origin = origin;
+ obj_data->data->formula_cell = fc;
+
+ // Create formula expression string.
+ auto* resolver = doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ const ixion::model_context& cxt = doc.get_model_context();
+ std::string formula_s = ixion::print_formula_tokens(cxt, origin, *resolver, tokens);
+ obj_data->formula = PyUnicode_FromStringAndSize(formula_s.data(), formula_s.size());
+
+ ixion::formula_result res;
+
+ try
+ {
+ res = fc->get_result_cache(
+ ixion::formula_result_wait_policy_t::throw_exception);
+ }
+ catch (const std::exception&)
+ {
+ Py_INCREF(Py_None);
+ obj_data->value = Py_None;
+ return obj;
+ }
+
+ switch (res.get_type())
+ {
+ case ixion::formula_result::result_type::value:
+ {
+ obj_data->value = PyFloat_FromDouble(res.get_value());
+ break;
+ }
+ case ixion::formula_result::result_type::string:
+ {
+ const std::string& s = res.get_string();
+ obj_data->value = PyUnicode_FromStringAndSize(s.data(), s.size());
+ break;
+ }
+ case ixion::formula_result::result_type::error:
+ {
+ ixion::formula_error_t fe = res.get_error();
+ std::string_view fename = ixion::get_formula_error_name(fe);
+ if (!fename.empty())
+ obj_data->value = PyUnicode_FromStringAndSize(fename.data(), fename.size());
+ else
+ {
+ // This should not be hit, but just in case...
+ Py_INCREF(Py_None);
+ obj_data->value = Py_None;
+ }
+ break;
+ }
+ default:
+ {
+ // This should not be hit, but just in case...
+ Py_INCREF(Py_None);
+ obj_data->value = Py_None;
+ }
+ }
+
+ return obj;
+}
+
+PyTypeObject* get_cell_type()
+{
+ return &cell_type;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/cell.hpp b/src/python/cell.hpp
new file mode 100644
index 0000000..45ea46d
--- /dev/null
+++ b/src/python/cell.hpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_CELL_HPP
+#define INCLUDED_ORCUS_PYTHON_CELL_HPP
+
+#include <string>
+#include <Python.h>
+
+namespace ixion {
+
+class formula_cell;
+struct abs_address_t;
+
+}
+
+namespace orcus {
+
+namespace spreadsheet {
+
+class document;
+
+}
+
+namespace python {
+
+PyObject* create_cell_object_empty();
+PyObject* create_cell_object_boolean(bool v);
+PyObject* create_cell_object_string(const std::string* p);
+PyObject* create_cell_object_numeric(double v);
+PyObject* create_cell_object_formula(
+ const spreadsheet::document& doc, const ixion::abs_address_t& origin, const ixion::formula_cell* fc);
+
+PyTypeObject* get_cell_type();
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/csv.cpp b/src/python/csv.cpp
new file mode 100644
index 0000000..97c5d29
--- /dev/null
+++ b/src/python/csv.cpp
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "csv.hpp"
+#include "global.hpp"
+
+#ifdef __ORCUS_PYTHON_CSV
+#include "document.hpp"
+#include "orcus/orcus_csv.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#endif
+
+namespace orcus { namespace python {
+
+#ifdef __ORCUS_PYTHON_CSV
+
+namespace {
+
+py_unique_ptr read_stream_object_from_string(PyObject* args, PyObject* kwargs)
+{
+ static const char* kwlist[] = { "stream", nullptr };
+
+ py_unique_ptr ret;
+ PyObject* file = nullptr;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", const_cast<char**>(kwlist), &file))
+ return ret;
+
+ if (!file)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Invalid file object has been passed.");
+ return ret;
+ }
+
+ PyObject* obj_str = nullptr;
+
+ if (PyObject_HasAttrString(file, "read"))
+ {
+ PyObject* func_read = PyObject_GetAttrString(file, "read"); // new reference
+ obj_str = PyObject_CallFunction(func_read, nullptr);
+ Py_XDECREF(func_read);
+ }
+
+ if (!obj_str)
+ {
+ if (PyObject_TypeCheck(file, &PyUnicode_Type))
+ obj_str = PyUnicode_FromObject(file); // new reference
+ }
+
+ if (!obj_str)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "failed to extract bytes from this object.");
+ return ret;
+ }
+
+ ret.reset(obj_str);
+ return ret;
+}
+
+} // anonymous namespace
+
+PyObject* csv_read(PyObject* /*module*/, PyObject* args, PyObject* kwargs)
+{
+ py_unique_ptr str = read_stream_object_from_string(args, kwargs);
+ if (!str)
+ return nullptr;
+
+ try
+ {
+ spreadsheet::range_size_t ss{1048576, 16384};
+ std::unique_ptr<spreadsheet::document> doc = std::make_unique<spreadsheet::document>(ss);
+ spreadsheet::import_factory fact(*doc);
+ orcus_csv app(&fact);
+
+ Py_ssize_t n = 0;
+ const char* p = PyUnicode_AsUTF8AndSize(str.get(), &n);
+ app.read_stream({p, static_cast<std::string_view::size_type>(n)});
+
+ return create_document(std::move(doc));
+ }
+ catch (const std::exception& e)
+ {
+ set_python_exception(PyExc_RuntimeError, e);
+ return nullptr;
+ }
+}
+
+#else
+
+PyObject* csv_read(PyObject*, PyObject*, PyObject*)
+{
+ PyErr_SetString(PyExc_RuntimeError, "The csv module is not enabled.");
+ return nullptr;
+}
+
+#endif
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/csv.hpp b/src/python/csv.hpp
new file mode 100644
index 0000000..e9b7b44
--- /dev/null
+++ b/src/python/csv.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_CSV_HPP
+#define INCLUDED_ORCUS_PYTHON_CSV_HPP
+
+#include <Python.h>
+
+namespace orcus { namespace python {
+
+PyObject* csv_read(PyObject* module, PyObject* args, PyObject* kwargs);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/document.cpp b/src/python/document.cpp
new file mode 100644
index 0000000..d908668
--- /dev/null
+++ b/src/python/document.cpp
@@ -0,0 +1,330 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "document.hpp"
+#include "sheet.hpp"
+#include "global.hpp"
+#include "named_expression.hpp"
+#include "named_expressions.hpp"
+
+#include <ixion/model_context.hpp>
+#include <ixion/named_expressions_iterator.hpp>
+#include <structmember.h>
+#include <object.h>
+#include <sstream>
+
+using namespace std;
+namespace ss = orcus::spreadsheet;
+
+namespace orcus { namespace python {
+
+document_data::~document_data()
+{
+}
+
+namespace {
+
+/**
+ * Python object for orcus.Document.
+ */
+struct pyobj_document
+{
+ PyObject_HEAD
+
+ PyObject* sheets; // tuple of sheet objects.
+
+ document_data* data;
+};
+
+inline pyobj_document* t(PyObject* self)
+{
+ return reinterpret_cast<pyobj_document*>(self);
+}
+
+void tp_dealloc(pyobj_document* self)
+{
+ delete self->data;
+
+ // Destroy all sheet objects.
+ Py_ssize_t n = PyTuple_Size(self->sheets);
+ for (Py_ssize_t i = 0; i < n; ++i)
+ {
+ PyObject* o = PyTuple_GetItem(self->sheets, i);
+ Py_CLEAR(o);
+ }
+ Py_CLEAR(self->sheets); // and the tuple containing the sheets.
+
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+PyObject* tp_new(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ pyobj_document* self = t(type->tp_alloc(type, 0));
+ self->data = new document_data;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+int tp_init(pyobj_document* /*self*/, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ return 0;
+}
+
+PyObject* doc_get_named_expressions(PyObject* self, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ const ss::document& doc = *t(self)->data->m_doc;
+ const ixion::model_context& cxt = doc.get_model_context();
+ return create_named_expressions_object(-1, doc, cxt.get_named_expressions_iterator());
+}
+
+PyMethodDef tp_methods[] =
+{
+ { "get_named_expressions", (PyCFunction)doc_get_named_expressions, METH_NOARGS, "Get a named expressions iterator." },
+ { nullptr }
+};
+
+PyMemberDef tp_members[] =
+{
+ { (char*)"sheets", T_OBJECT_EX, offsetof(pyobj_document, sheets), READONLY, (char*)"sheet objects" },
+ { nullptr }
+};
+
+PyTypeObject document_type =
+{
+ PyVarObject_HEAD_INIT(nullptr, 0)
+ "orcus.Document", // tp_name
+ sizeof(pyobj_document), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)tp_dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ 0, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
+ "orcus document object", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ tp_methods, // tp_methods
+ tp_members, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)tp_init, // tp_init
+ 0, // tp_alloc
+ tp_new, // tp_new
+};
+
+bool import_from_stream_object(iface::import_filter& app, PyObject* obj_bytes)
+{
+ const char* p = PyBytes_AsString(obj_bytes);
+ if (!p)
+ return false;
+
+ size_t n = PyBytes_Size(obj_bytes);
+
+ app.read_stream({p, n});
+
+ return true;
+}
+
+PyObject* create_document_object()
+{
+ PyTypeObject* type = get_document_type();
+
+ PyObject* obj_doc = create_object_from_type(type);
+ if (!obj_doc)
+ return nullptr;
+
+ type->tp_init(obj_doc, nullptr, nullptr);
+
+ return obj_doc;
+}
+
+void store_document(PyObject* self, std::unique_ptr<spreadsheet::document>&& doc)
+{
+ if (!self)
+ return;
+
+ pyobj_document* pydoc = reinterpret_cast<pyobj_document*>(self);
+ document_data* pydoc_data = pydoc->data;
+ pydoc_data->m_doc = std::move(doc);
+
+ PyTypeObject* sheet_type = get_sheet_type();
+ if (!sheet_type)
+ return;
+
+ // Create a tuple of sheet objects and store it with the pydoc instance.
+ size_t sheet_size = pydoc_data->m_doc->get_sheet_count();
+
+ pydoc->sheets = PyTuple_New(sheet_size);
+
+ for (size_t i = 0; i < sheet_size; ++i)
+ {
+ spreadsheet::sheet* sheet = pydoc_data->m_doc->get_sheet(i);
+ if (!sheet)
+ continue;
+
+ PyObject* pysheet = sheet_type->tp_new(sheet_type, nullptr, nullptr);
+ if (!pysheet)
+ continue;
+
+ sheet_type->tp_init(pysheet, nullptr, nullptr);
+
+ Py_INCREF(pysheet);
+ PyTuple_SetItem(pydoc->sheets, i, pysheet);
+
+ store_sheet(pysheet, pydoc_data->m_doc.get(), sheet);
+ }
+}
+
+} // anonoymous namespace
+
+PyTypeObject* get_document_type()
+{
+ return &document_type;
+}
+
+document_data* get_document_data(PyObject* self)
+{
+ return reinterpret_cast<pyobj_document*>(self)->data;
+}
+
+stream_with_formulas read_stream_and_formula_params_from_args(PyObject* args, PyObject* kwargs)
+{
+ static const char* kwlist[] = { "stream", "recalc", "error_policy", nullptr };
+
+ stream_with_formulas ret;
+ PyObject* file = nullptr;
+ int recalc_formula_cells = 0;
+ const char* error_policy_s = nullptr;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|ps", const_cast<char**>(kwlist), &file, &recalc_formula_cells, &error_policy_s))
+ return ret;
+
+ if (!file)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Invalid file object has been passed.");
+ return ret;
+ }
+
+ PyObject* obj_bytes = nullptr;
+
+ if (PyObject_HasAttrString(file, "read"))
+ {
+ PyObject* func_read = PyObject_GetAttrString(file, "read"); // new reference
+ obj_bytes = PyObject_CallFunction(func_read, nullptr);
+ Py_XDECREF(func_read);
+ }
+
+ if (!obj_bytes)
+ {
+ if (PyObject_TypeCheck(file, &PyBytes_Type))
+ obj_bytes = PyBytes_FromObject(file);
+ }
+
+ if (!obj_bytes)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "failed to extract bytes from this object.");
+ return ret;
+ }
+
+ if (error_policy_s)
+ {
+ ss::formula_error_policy_t error_policy = ss::to_formula_error_policy(error_policy_s);
+ if (error_policy == ss::formula_error_policy_t::unknown)
+ {
+ std::ostringstream os;
+ os << "invalid error policy value: '" << error_policy_s << "'. The value must be either 'fail' or 'skip'.";
+ PyErr_SetString(PyExc_RuntimeError, os.str().data());
+ return ret;
+ }
+
+ ret.error_policy = error_policy;
+ }
+
+ ret.stream.reset(obj_bytes);
+ ret.recalc_formula_cells = recalc_formula_cells != 0;
+
+ return ret;
+}
+
+py_unique_ptr read_stream_from_args(PyObject* args, PyObject* kwargs)
+{
+ static const char* kwlist[] = { "stream", nullptr };
+
+ py_unique_ptr obj_bytes;
+ PyObject* file = nullptr;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", const_cast<char**>(kwlist), &file))
+ return obj_bytes;
+
+ if (!file)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Invalid file object has been passed.");
+ return obj_bytes;
+ }
+
+ if (PyObject_HasAttrString(file, "read"))
+ {
+ PyObject* func_read = PyObject_GetAttrString(file, "read"); // new reference
+ obj_bytes.reset(PyObject_CallFunction(func_read, nullptr));
+ Py_XDECREF(func_read);
+ }
+
+ if (!obj_bytes)
+ {
+ if (PyObject_TypeCheck(file, &PyBytes_Type))
+ obj_bytes.reset(PyBytes_FromObject(file));
+ }
+
+ if (!obj_bytes)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "failed to extract bytes from this object.");
+ return obj_bytes;
+ }
+
+ return obj_bytes;
+}
+
+PyObject* import_from_stream_into_document(
+ PyObject* obj_bytes, iface::import_filter& app, std::unique_ptr<spreadsheet::document>&& doc)
+{
+ if (!import_from_stream_object(app, obj_bytes))
+ return nullptr;
+
+ return create_document(std::move(doc));
+}
+
+PyObject* create_document(std::unique_ptr<spreadsheet::document>&& doc)
+{
+ PyObject* obj_doc = create_document_object();
+ if (!obj_doc)
+ return nullptr;
+
+ store_document(obj_doc, std::move(doc));
+ return obj_doc;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/document.hpp b/src/python/document.hpp
new file mode 100644
index 0000000..b52c9b8
--- /dev/null
+++ b/src/python/document.hpp
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_DOCUMENT_HPP
+#define INCLUDED_ORCUS_PYTHON_DOCUMENT_HPP
+
+#include "orcus/spreadsheet/document.hpp"
+
+#include "memory.hpp"
+
+namespace orcus { namespace python {
+
+/** non-python part of the document object. */
+struct document_data
+{
+ std::unique_ptr<spreadsheet::document> m_doc;
+
+ ~document_data();
+};
+
+document_data* get_document_data(PyObject* self);
+
+struct stream_with_formulas
+{
+ py_unique_ptr stream;
+ bool recalc_formula_cells = false;
+ spreadsheet::formula_error_policy_t error_policy = spreadsheet::formula_error_policy_t::fail;
+};
+
+/**
+ * Extract a python object representing the byte stream from the arguments
+ * passed to the python orcus.<file format>.read() function, as well as
+ * several parameters related to formula calculation settings.
+ *
+ * This function handles the following python arguments: stream, recalc, and
+ * error_policy.
+ *
+ * @param args positional argument object.
+ * @param kwargs keyword argument object.
+ *
+ * @return object representing the bytes as well as formula calculation
+ * settings.
+ */
+stream_with_formulas read_stream_and_formula_params_from_args(PyObject* args, PyObject* kwargs);
+
+/**
+ * This one is similar to the function above, except that it only handles
+ * one argument called 'stream'.
+ *
+ * @return object representing the bytes.
+ */
+py_unique_ptr read_stream_from_args(PyObject* args, PyObject* kwargs);
+
+/**
+ * Import a document from a python object containing the byte stream, and
+ * create a python object of class orcus.Document.
+ *
+ * @param obj_bytes python object containing the byte stream.
+ * @param app filter instance to use to load the document.
+ * @param doc orcus document instance which will be stored within the python
+ * document object.
+ *
+ * @return python document object.
+ */
+PyObject* import_from_stream_into_document(
+ PyObject* obj_bytes, iface::import_filter& app, std::unique_ptr<spreadsheet::document>&& doc);
+
+PyObject* create_document(std::unique_ptr<spreadsheet::document>&& doc);
+
+/**
+ * Get the definition of the python class Document.
+ */
+PyTypeObject* get_document_type();
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/formula_token.cpp b/src/python/formula_token.cpp
new file mode 100644
index 0000000..971d440
--- /dev/null
+++ b/src/python/formula_token.cpp
@@ -0,0 +1,250 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "formula_token.hpp"
+#include "global.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/formula.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/model_context.hpp>
+#include <structmember.h>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus { namespace python {
+
+namespace {
+
+/** non-python part of the object's internal. */
+struct data_formula_token
+{
+ std::string repr;
+};
+
+/**
+ * Python object for orcus.NamedExpression.
+ */
+struct pyobj_formula_token
+{
+ PyObject_HEAD
+
+ PyObject* type;
+ PyObject* op;
+
+ data_formula_token* data;
+};
+
+const char* to_formula_token_type(ixion::fopcode_t op)
+{
+ switch (op)
+ {
+ case ixion::fop_single_ref:
+ case ixion::fop_range_ref:
+ case ixion::fop_table_ref:
+ return "REFERENCE";
+ case ixion::fop_named_expression:
+ return "NAME";
+ case ixion::fop_function:
+ return "FUNCTION";
+ case ixion::fop_string:
+ case ixion::fop_value:
+ return "VALUE";
+ case ixion::fop_plus:
+ case ixion::fop_minus:
+ case ixion::fop_divide:
+ case ixion::fop_multiply:
+ case ixion::fop_exponent:
+ case ixion::fop_concat:
+ case ixion::fop_equal:
+ case ixion::fop_not_equal:
+ case ixion::fop_less:
+ case ixion::fop_greater:
+ case ixion::fop_less_equal:
+ case ixion::fop_greater_equal:
+ case ixion::fop_open:
+ case ixion::fop_close:
+ case ixion::fop_sep:
+ return "OPERATOR";
+ case ixion::fop_error:
+ return "ERROR";
+ case ixion::fop_unknown:
+ default:
+ ;
+ }
+
+ return "UNKNOWN";
+}
+
+const char* to_formula_token_op(ixion::fopcode_t op)
+{
+ const char* names[] = {
+ "UNKNOWN",
+ "SINGLE_REF",
+ "RANGE_REF",
+ "TABLE_REF",
+ "NAMED_EXPRESSION",
+ "STRING",
+ "VALUE",
+ "FUNCTION",
+ "PLUS",
+ "MINUS",
+ "DIVIDE",
+ "MULTIPLY",
+ "EXPONENT",
+ "CONCAT",
+ "EQUAL",
+ "NOT_EQUAL",
+ "LESS",
+ "GREATER",
+ "LESS_EQUAL",
+ "GREATER_EQUAL",
+ "OPEN",
+ "CLOSE",
+ "SEP",
+ "ERROR",
+ };
+
+ auto n_names = std::size(names);
+ return op < n_names ? names[op] : names[0];
+}
+
+void init_members(pyobj_formula_token* self)
+{
+ Py_INCREF(Py_None);
+ self->type = Py_None;
+ Py_INCREF(Py_None);
+ self->op = Py_None;
+}
+
+PyObject* create_and_init_formula_token_object(ixion::fopcode_t op, std::string repr)
+{
+ PyTypeObject* ft_type = get_formula_token_type();
+ if (!ft_type)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to get the formula token type object.");
+ return nullptr;
+ }
+
+ PyObject* obj = ft_type->tp_new(ft_type, nullptr, nullptr);
+ if (!obj)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to instantiate a formula token object.");
+ return nullptr;
+ }
+
+ pyobj_formula_token* self = reinterpret_cast<pyobj_formula_token*>(obj);
+ init_members(self);
+ self->type = get_python_enum_value("FormulaTokenType", to_formula_token_type(op));
+ self->op = get_python_enum_value("FormulaTokenOp", to_formula_token_op(op));
+ self->data->repr = std::move(repr);
+
+ return obj;
+}
+
+void tp_dealloc(pyobj_formula_token* self)
+{
+ delete self->data;
+ self->data = nullptr;
+
+ Py_CLEAR(self->op);
+ Py_CLEAR(self->type);
+
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+int tp_init(pyobj_formula_token* self, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ init_members(self);
+ return 0;
+}
+
+PyObject* tp_new(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ pyobj_formula_token* self = (pyobj_formula_token*)type->tp_alloc(type, 0);
+ self->data = new data_formula_token;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+PyObject* tp_repr(pyobj_formula_token* self)
+{
+ return PyUnicode_FromStringAndSize(self->data->repr.data(), self->data->repr.size());
+}
+
+PyMemberDef tp_members[] =
+{
+ { (char*)"type", T_OBJECT_EX, offsetof(pyobj_formula_token, type), READONLY, (char*)"formula token type" },
+ { (char*)"op", T_OBJECT_EX, offsetof(pyobj_formula_token, op), READONLY, (char*)"formula token operator" },
+ { nullptr }
+};
+
+PyTypeObject formula_token_type =
+{
+ PyVarObject_HEAD_INIT(nullptr, 0)
+ "orcus.FormulaToken", // tp_name
+ sizeof(pyobj_formula_token), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)tp_dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ (reprfunc)tp_repr, // tp_repr
+ 0, // tp_as_number
+ 0, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
+ "orcus spreadsheet formula token", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ 0, // tp_methods
+ tp_members, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)tp_init, // tp_init
+ 0, // tp_alloc
+ tp_new, // tp_new
+};
+
+} // anonymous namespace
+
+PyObject* create_formula_token_object(const ss::document& doc, const ixion::abs_address_t& pos, const ixion::formula_token& token)
+{
+ const ixion::model_context& cxt = doc.get_model_context();
+ auto* resolver = doc.get_formula_name_resolver(ss::formula_ref_context_t::global);
+ assert(resolver);
+ std::string ft_s = ixion::print_formula_token(cxt, pos, *resolver, token);
+
+ PyObject* obj = create_and_init_formula_token_object(token.opcode, std::move(ft_s));
+ if (!obj)
+ return nullptr;
+
+ return obj;
+}
+
+PyTypeObject* get_formula_token_type()
+{
+ return &formula_token_type;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/formula_token.hpp b/src/python/formula_token.hpp
new file mode 100644
index 0000000..90b5b49
--- /dev/null
+++ b/src/python/formula_token.hpp
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_FORMULA_TOKEN_HPP
+#define INCLUDED_ORCUS_PYTHON_FORMULA_TOKEN_HPP
+
+#include "orcus/spreadsheet/types.hpp"
+
+#include <Python.h>
+
+namespace ixion {
+
+struct abs_address_t;
+class formula_token;
+
+}
+
+namespace orcus {
+
+namespace spreadsheet {
+
+class document;
+
+}
+
+namespace python {
+
+PyObject* create_formula_token_object(const spreadsheet::document& doc, const ixion::abs_address_t& pos, const ixion::formula_token& token);
+
+PyTypeObject* get_formula_token_type();
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/formula_tokens.cpp b/src/python/formula_tokens.cpp
new file mode 100644
index 0000000..1c8b77a
--- /dev/null
+++ b/src/python/formula_tokens.cpp
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "formula_tokens.hpp"
+#include "formula_token.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/formula_tokens.hpp>
+#include <structmember.h>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus { namespace python {
+
+namespace {
+
+/** non-python part. */
+struct formula_tokens_data
+{
+ const ss::document* doc;
+ ixion::abs_address_t origin;
+ const ixion::formula_tokens_t* tokens = nullptr;
+ ixion::formula_tokens_t::const_iterator pos;
+ ixion::formula_tokens_t::const_iterator end;
+};
+
+/** python object */
+struct pyobj_formula_tokens
+{
+ PyObject_HEAD
+
+ formula_tokens_data* data = nullptr;
+};
+
+inline pyobj_formula_tokens* t(PyObject* self)
+{
+ return reinterpret_cast<pyobj_formula_tokens*>(self);
+}
+
+void init_members(
+ pyobj_formula_tokens* self, const ss::document& doc, const ixion::abs_address_t& origin, const ixion::formula_tokens_t& tokens)
+{
+ assert(self->data);
+ self->data->doc = &doc;
+ self->data->origin = origin;
+ self->data->tokens = &tokens;
+}
+
+void tp_dealloc(pyobj_formula_tokens* self)
+{
+ delete self->data;
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+int tp_init(pyobj_formula_tokens* /*self*/, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ return 0;
+}
+
+PyObject* tp_new(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ pyobj_formula_tokens* self = t(type->tp_alloc(type, 0));
+ self->data = new formula_tokens_data;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+PyObject* tp_iter(PyObject* self)
+{
+ formula_tokens_data& data = *t(self)->data;
+ data.pos = data.tokens->cbegin();
+ data.end = data.tokens->cend();
+
+ Py_INCREF(self);
+ return self;
+}
+
+PyObject* tp_iternext(PyObject* self)
+{
+ formula_tokens_data& data = *t(self)->data;
+
+ if (data.pos == data.end)
+ {
+ // No more elements. Stop the iteration.
+ PyErr_SetNone(PyExc_StopIteration);
+ return nullptr;
+ }
+
+ PyObject* ft_obj = create_formula_token_object(*data.doc, data.origin, *data.pos);
+ ++data.pos;
+ return ft_obj;
+}
+
+Py_ssize_t sq_length(PyObject* self)
+{
+ formula_tokens_data& data = *t(self)->data;
+ return data.tokens->size();
+}
+
+PySequenceMethods tp_as_sequence =
+{
+ sq_length, // lenfunc sq_length
+ 0, // binaryfunc sq_concat
+ 0, // ssizeargfunc sq_repeat
+ 0, // ssizeargfunc sq_item
+ 0, // void *was_sq_slice
+ 0, // ssizeobjargproc sq_ass_item
+ 0, // void *was_sq_ass_slice
+ 0, // objobjproc sq_contains
+ 0, // binaryfunc sq_inplace_concat
+ 0, // ssizeargfunc sq_inplace_repeat
+};
+
+PyMethodDef tp_methods[] =
+{
+ { nullptr }
+};
+
+PyMemberDef tp_members[] =
+{
+ { nullptr }
+};
+
+PyTypeObject formula_tokens_type =
+{
+ PyVarObject_HEAD_INIT(nullptr, 0)
+ "orcus.FormulaTokens", // tp_name
+ sizeof(pyobj_formula_tokens), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)tp_dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ &tp_as_sequence, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
+ "orcus spreadsheet formula tokens", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ tp_iter, // tp_iter
+ tp_iternext, // tp_iternext
+ tp_methods, // tp_methods
+ tp_members, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)tp_init, // tp_init
+ 0, // tp_alloc
+ tp_new, // tp_new
+};
+
+} // anonymous namespace
+
+PyObject* create_formula_tokens_iterator_object(
+ const ss::document& doc, const ixion::abs_address_t& origin, const ixion::formula_tokens_t& tokens)
+{
+ PyTypeObject* ft_type = get_formula_tokens_type();
+ if (!ft_type)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to get the formula tokens type object.");
+ return nullptr;
+ }
+
+ PyObject* obj = ft_type->tp_new(ft_type, nullptr, nullptr);
+ if (!obj)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to instantiate a formula tokens object.");
+ return nullptr;
+ }
+
+ init_members(t(obj), doc, origin, tokens);
+
+ return obj;
+}
+
+PyTypeObject* get_formula_tokens_type()
+{
+ return &formula_tokens_type;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/formula_tokens.hpp b/src/python/formula_tokens.hpp
new file mode 100644
index 0000000..4067452
--- /dev/null
+++ b/src/python/formula_tokens.hpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_FORMULA_TOKENS_HPP
+#define INCLUDED_ORCUS_PYTHON_FORMULA_TOKENS_HPP
+
+#include <ixion/formula_tokens_fwd.hpp>
+#include <Python.h>
+
+namespace ixion {
+
+struct abs_address_t;
+
+}
+
+namespace orcus {
+
+namespace spreadsheet {
+
+class document;
+
+}
+
+namespace python {
+
+PyObject* create_formula_tokens_iterator_object(
+ const spreadsheet::document& doc, const ixion::abs_address_t& origin, const ixion::formula_tokens_t& tokens);
+
+PyTypeObject* get_formula_tokens_type();
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/global.cpp b/src/python/global.cpp
new file mode 100644
index 0000000..f8623e0
--- /dev/null
+++ b/src/python/global.cpp
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "global.hpp"
+#include "memory.hpp"
+
+#include <sstream>
+
+namespace orcus { namespace python {
+
+void set_python_exception(PyObject* type, const std::exception& e)
+{
+ std::ostringstream os;
+ os << "C++ exception caught: " << e.what();
+ PyErr_SetString(type, os.str().data());
+}
+
+PyObject* get_python_enum_value(const char* enum_class_name, const char* value_name)
+{
+ py_scoped_ref orcus_mod = PyImport_ImportModule("orcus");
+ if (!orcus_mod)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "failed to import orcus module.");
+ return nullptr;
+ }
+
+ py_scoped_ref cls = PyObject_GetAttrString(orcus_mod.get(), enum_class_name);
+ if (!cls)
+ {
+ std::ostringstream os;
+ os << "failed to find class orcus." << enum_class_name << ".";
+ PyErr_SetString(PyExc_RuntimeError, os.str().data());
+ return nullptr;
+ }
+
+ return PyObject_GetAttrString(cls.get(), value_name);
+}
+
+PyObject* create_object_from_type(PyTypeObject* type)
+{
+ if (!type)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Type object is null.");
+ return nullptr;
+ }
+
+ PyObject* obj = type->tp_new(type, nullptr, nullptr);
+ if (!obj)
+ {
+ std::ostringstream os;
+ os << "Failed to instantiate an object of type " << type->tp_name << ".";
+ PyErr_SetString(PyExc_RuntimeError, os.str().data());
+ return nullptr;
+ }
+
+ return obj;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/global.hpp b/src/python/global.hpp
new file mode 100644
index 0000000..608a7ed
--- /dev/null
+++ b/src/python/global.hpp
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_GLOBAL_HPP
+#define INCLUDED_ORCUS_PYTHON_GLOBAL_HPP
+
+#include <exception>
+#include <Python.h>
+
+namespace orcus { namespace python {
+
+void set_python_exception(PyObject* type, const std::exception& e);
+
+PyObject* get_python_enum_value(const char* enum_class_name, const char* value_name);
+
+PyObject* create_object_from_type(PyTypeObject* type);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/gnumeric.cpp b/src/python/gnumeric.cpp
new file mode 100644
index 0000000..162f18f
--- /dev/null
+++ b/src/python/gnumeric.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "gnumeric.hpp"
+#include "global.hpp"
+
+#ifdef __ORCUS_PYTHON_GNUMERIC
+#include "document.hpp"
+#include "orcus/orcus_gnumeric.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#endif
+
+namespace orcus { namespace python {
+
+#ifdef __ORCUS_PYTHON_GNUMERIC
+
+PyObject* gnumeric_read(PyObject* /*module*/, PyObject* args, PyObject* kwargs)
+{
+ stream_with_formulas data = read_stream_and_formula_params_from_args(args, kwargs);
+ if (!data.stream)
+ return nullptr;
+
+ try
+ {
+ spreadsheet::range_size_t ss{1048576, 16384};
+ std::unique_ptr<spreadsheet::document> doc = std::make_unique<spreadsheet::document>(ss);
+ spreadsheet::import_factory fact(*doc);
+ fact.set_recalc_formula_cells(data.recalc_formula_cells);
+ fact.set_formula_error_policy(data.error_policy);
+ orcus_gnumeric app(&fact);
+
+ return import_from_stream_into_document(data.stream.get(), app, std::move(doc));
+ }
+ catch (const std::exception& e)
+ {
+ set_python_exception(PyExc_RuntimeError, e);
+ return nullptr;
+ }
+}
+
+#else
+
+PyObject* gnumeric_read(PyObject*, PyObject*, PyObject*)
+{
+ PyErr_SetString(PyExc_RuntimeError, "The gnumeric module is not enabled.");
+ return nullptr;
+}
+
+#endif
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/gnumeric.hpp b/src/python/gnumeric.hpp
new file mode 100644
index 0000000..23aeec8
--- /dev/null
+++ b/src/python/gnumeric.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_GNUMERIC_HPP
+#define INCLUDED_ORCUS_PYTHON_GNUMERIC_HPP
+
+#include <Python.h>
+
+namespace orcus { namespace python {
+
+PyObject* gnumeric_read(PyObject* module, PyObject* args, PyObject* kwargs);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/json.cpp b/src/python/json.cpp
new file mode 100644
index 0000000..873523b
--- /dev/null
+++ b/src/python/json.cpp
@@ -0,0 +1,290 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/env.hpp"
+#include "orcus/json_parser.hpp"
+#include "orcus/json_document_tree.hpp"
+#include "orcus/config.hpp"
+
+#include <algorithm>
+#include <sstream>
+#include <boost/current_function.hpp>
+
+#include <Python.h>
+
+#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
+
+using namespace std;
+
+namespace orcus { namespace python {
+
+namespace {
+
+class python_json_error : public general_error
+{
+public:
+ python_json_error(const std::string& msg) : general_error("python_json_error", msg) {}
+};
+
+struct module_state
+{
+ PyObject* error;
+};
+
+int orcus_traverse(PyObject* m, visitproc visit, void* arg)
+{
+ Py_VISIT(GETSTATE(m)->error);
+ return 0;
+}
+
+int orcus_clear(PyObject* m)
+{
+ Py_CLEAR(GETSTATE(m)->error);
+ return 0;
+}
+
+struct parser_stack
+{
+ PyObject* key;
+ PyObject* node;
+ json::node_t type;
+
+ parser_stack(PyObject* _node, json::node_t _type) : key(nullptr), node(_node), type(_type) {}
+};
+
+class json_parser_handler
+{
+ PyObject* m_root;
+ std::vector<parser_stack> m_stack;
+
+ PyObject* push_value(PyObject* value)
+ {
+ if (!value)
+ {
+ std::ostringstream os;
+ os << BOOST_CURRENT_FUNCTION << ": Empty value is passed.";
+ throw python_json_error(os.str());
+ }
+
+ if (m_stack.empty())
+ {
+ std::ostringstream os;
+ os << BOOST_CURRENT_FUNCTION << ": Stack is unexpectedly empty.";
+ throw python_json_error(os.str());
+ }
+
+ parser_stack& cur = m_stack.back();
+
+ switch (cur.type)
+ {
+ case json::node_t::array:
+ {
+ PyList_Append(cur.node, value);
+ return value;
+ }
+ break;
+ case json::node_t::object:
+ {
+ assert(cur.key);
+ PyDict_SetItem(cur.node, cur.key, value);
+ cur.key = nullptr;
+ return value;
+ }
+ break;
+ default:
+ Py_DECREF(value);
+ }
+
+ std::ostringstream os;
+ os << BOOST_CURRENT_FUNCTION << ": unstackable JSON value type.";
+ throw python_json_error(os.str());
+ }
+
+public:
+ json_parser_handler() : m_root(nullptr) {}
+
+ ~json_parser_handler()
+ {
+ if (m_root)
+ Py_XDECREF(m_root);
+
+ std::for_each(m_stack.begin(), m_stack.end(),
+ [](parser_stack& ps)
+ {
+ if (ps.key)
+ {
+ Py_XDECREF(ps.key);
+ ps.key = nullptr;
+ }
+ }
+ );
+ }
+
+ void begin_parse()
+ {
+ if (m_root)
+ {
+ std::ostringstream os;
+ os << BOOST_CURRENT_FUNCTION << ": Root JSON value already exists.";
+ throw python_json_error(os.str());
+ }
+ }
+
+ void end_parse() {}
+
+ void begin_array()
+ {
+ if (m_root)
+ {
+ PyObject* array = push_value(PyList_New(0));
+ m_stack.push_back(parser_stack(array, json::node_t::array));
+ }
+ else
+ {
+ m_root = PyList_New(0);
+ m_stack.push_back(parser_stack(m_root, json::node_t::array));
+ }
+ }
+
+ void end_array()
+ {
+ if (m_stack.empty())
+ {
+ std::ostringstream os;
+ os << BOOST_CURRENT_FUNCTION << ": Stack is unexpectedly empty.";
+ throw python_json_error(os.str());
+ }
+
+ m_stack.pop_back();
+ }
+
+ void begin_object()
+ {
+ if (m_root)
+ {
+ PyObject* dict = push_value(PyDict_New());
+ m_stack.push_back(parser_stack(dict, json::node_t::object));
+ }
+ else
+ {
+ m_root = PyDict_New();
+ m_stack.push_back(parser_stack(m_root, json::node_t::object));
+ }
+ }
+
+ void object_key(std::string_view key, bool /*transient*/)
+ {
+ parser_stack& cur = m_stack.back();
+ cur.key = PyUnicode_FromStringAndSize(key.data(), key.size());
+ }
+
+ void end_object()
+ {
+ if (m_stack.empty())
+ {
+ std::ostringstream os;
+ os << BOOST_CURRENT_FUNCTION << ": Stack is unexpectedly empty.";
+ throw python_json_error(os.str());
+ }
+
+ m_stack.pop_back();
+ }
+
+ void boolean_true()
+ {
+ Py_INCREF(Py_True);
+ push_value(Py_True);
+ }
+
+ void boolean_false()
+ {
+ Py_INCREF(Py_False);
+ push_value(Py_False);
+ }
+
+ void null()
+ {
+ Py_INCREF(Py_None);
+ push_value(Py_None);
+ }
+
+ void string(std::string_view val, bool /*transient*/)
+ {
+ push_value(PyUnicode_FromStringAndSize(val.data(), val.size()));
+ }
+
+ void number(double val)
+ {
+ push_value(PyFloat_FromDouble(val));
+ }
+
+ PyObject* get_root()
+ {
+ PyObject* o = m_root;
+ m_root = nullptr;
+ return o;
+ }
+};
+
+PyObject* json_loads(PyObject* /*module*/, PyObject* args, PyObject* kwargs)
+{
+ char* stream = nullptr;
+ static const char* kwlist[] = { "s", nullptr };
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", const_cast<char**>(kwlist), &stream))
+ {
+ PyErr_SetString(PyExc_TypeError, "The method must be given a string.");
+ return nullptr;
+ }
+
+ json_parser_handler hdl;
+ orcus::json_parser<json_parser_handler> parser(stream, hdl);
+ try
+ {
+ parser.parse();
+ return hdl.get_root();
+ }
+ catch (const orcus::parse_error& e)
+ {
+ PyErr_SetString(PyExc_TypeError, e.what());
+ }
+ return nullptr;
+}
+
+PyMethodDef orcus_methods[] =
+{
+ { "loads", (PyCFunction)json_loads, METH_VARARGS | METH_KEYWORDS, "Load JSON string into a Python object." },
+ { nullptr, nullptr, 0, nullptr }
+};
+
+struct PyModuleDef moduledef =
+{
+ PyModuleDef_HEAD_INIT,
+ "_orcus_json",
+ nullptr,
+ sizeof(struct module_state),
+ orcus_methods,
+ nullptr,
+ orcus_traverse,
+ orcus_clear,
+ nullptr
+};
+
+}
+
+}}
+
+extern "C" {
+
+ORCUS_DLLPUBLIC PyObject* PyInit__orcus_json()
+{
+ PyObject* m = PyModule_Create(&orcus::python::moduledef);
+ return m;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/memory.cpp b/src/python/memory.cpp
new file mode 100644
index 0000000..d2bbd09
--- /dev/null
+++ b/src/python/memory.cpp
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "memory.hpp"
+
+namespace orcus { namespace python {
+
+void pyobj_unique_deleter::operator ()(PyObject* p) const
+{
+ Py_XDECREF(p);
+}
+
+py_scoped_ref::py_scoped_ref() : m_pyobj(nullptr) {}
+py_scoped_ref::py_scoped_ref(PyObject* p) : m_pyobj(p) {}
+
+py_scoped_ref::~py_scoped_ref()
+{
+ if (m_pyobj)
+ Py_DECREF(m_pyobj);
+}
+
+py_scoped_ref& py_scoped_ref::operator= (PyObject* p)
+{
+ if (m_pyobj)
+ Py_DECREF(m_pyobj);
+ m_pyobj = p;
+ return *this;
+}
+
+PyObject* py_scoped_ref::get()
+{
+ return m_pyobj;
+}
+
+py_scoped_ref::operator bool() const
+{
+ return m_pyobj != nullptr;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/memory.hpp b/src/python/memory.hpp
new file mode 100644
index 0000000..ecc7d65
--- /dev/null
+++ b/src/python/memory.hpp
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_MEMORY_HPP
+#define INCLUDED_ORCUS_PYTHON_MEMORY_HPP
+
+#include <memory>
+#include <Python.h>
+
+namespace orcus { namespace python {
+
+struct pyobj_unique_deleter
+{
+ void operator() (PyObject* p) const;
+};
+
+using py_unique_ptr = std::unique_ptr<PyObject, pyobj_unique_deleter>;
+
+class py_scoped_ref
+{
+ PyObject* m_pyobj;
+public:
+ py_scoped_ref();
+ py_scoped_ref(PyObject* p);
+ ~py_scoped_ref();
+
+ py_scoped_ref& operator= (PyObject* p);
+ PyObject* get();
+ operator bool() const;
+};
+
+}}
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/named_expression.cpp b/src/python/named_expression.cpp
new file mode 100644
index 0000000..1402daa
--- /dev/null
+++ b/src/python/named_expression.cpp
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "named_expression.hpp"
+#include "formula_token.hpp"
+#include "formula_tokens.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/formula.hpp>
+#include <ixion/model_context.hpp>
+#include <ixion/named_expressions_iterator.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <structmember.h>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus { namespace python {
+
+namespace {
+
+/** non-python part of the object. */
+struct named_exp_data
+{
+ const ss::document* doc = nullptr;
+ const ixion::formula_tokens_t* tokens = nullptr;
+ ixion::abs_address_t origin;
+};
+
+/**
+ * Python object for orcus.NamedExpression.
+ */
+struct pyobj_named_exp
+{
+ PyObject_HEAD
+
+ PyObject* origin;
+ PyObject* formula;
+
+ named_exp_data* data;
+};
+
+inline pyobj_named_exp* t(PyObject* self)
+{
+ return reinterpret_cast<pyobj_named_exp*>(self);
+}
+
+void init_members(pyobj_named_exp* self)
+{
+ Py_INCREF(Py_None);
+ self->origin = Py_None;
+
+ Py_INCREF(Py_None);
+ self->formula = Py_None;
+}
+
+void tp_dealloc(pyobj_named_exp* self)
+{
+ delete self->data;
+ self->data = nullptr;
+
+ Py_CLEAR(self->origin);
+ Py_CLEAR(self->formula);
+
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+int tp_init(pyobj_named_exp* self, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ init_members(self);
+ return 0;
+}
+
+PyObject* tp_new(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ pyobj_named_exp* self = (pyobj_named_exp*)type->tp_alloc(type, 0);
+ self->data = new named_exp_data;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+PyObject* ne_get_formula_tokens(PyObject* self, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ named_exp_data& data = *t(self)->data;
+ if (!data.tokens)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return create_formula_tokens_iterator_object(*data.doc, data.origin, *data.tokens);
+}
+
+PyMethodDef tp_methods[] =
+{
+ { "get_formula_tokens", (PyCFunction)ne_get_formula_tokens, METH_NOARGS, "Get a formula tokens iterator." },
+ { nullptr }
+};
+
+PyMemberDef tp_members[] =
+{
+ { (char*)"origin", T_OBJECT_EX, offsetof(pyobj_named_exp, origin), READONLY, (char*)"anchoring cell for the named expression" },
+ { (char*)"formula", T_OBJECT_EX, offsetof(pyobj_named_exp, formula), READONLY, (char*)"formula string" },
+ { nullptr }
+};
+
+PyTypeObject named_exp_type =
+{
+ PyVarObject_HEAD_INIT(nullptr, 0)
+ "orcus.NamedExpression", // tp_name
+ sizeof(pyobj_named_exp), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)tp_dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ 0, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
+ "orcus spreadsheet named expression", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ tp_methods, // tp_methods
+ tp_members, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)tp_init, // tp_init
+ 0, // tp_alloc
+ tp_new, // tp_new
+};
+
+} // anonymous namespace
+
+PyObject* create_named_exp_object(const spreadsheet::document& doc, const ixion::named_expression_t* exp)
+{
+ PyTypeObject* named_exp_type = get_named_exp_type();
+ if (!named_exp_type)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to get the named expression type object.");
+ return nullptr;
+ }
+
+ PyObject* obj = named_exp_type->tp_new(named_exp_type, nullptr, nullptr);
+ if (!obj)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to instantiate a named expression object.");
+ return nullptr;
+ }
+
+ pyobj_named_exp* self = reinterpret_cast<pyobj_named_exp*>(obj);
+ init_members(self);
+
+ if (exp)
+ {
+ named_exp_data& data = *self->data;
+ data.doc = &doc;
+ data.origin = exp->origin;
+ data.tokens = &exp->tokens;
+
+ const ixion::model_context& cxt = doc.get_model_context();
+ auto* resolver = doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+
+ // Create base
+ std::string origin_s = resolver->get_name(exp->origin, ixion::abs_address_t(), true);
+ self->origin = PyUnicode_FromStringAndSize(origin_s.data(), origin_s.size());
+
+ // Create formula expression string.
+ std::string formula_s = ixion::print_formula_tokens(cxt, exp->origin, *resolver, exp->tokens);
+ self->formula = PyUnicode_FromStringAndSize(formula_s.data(), formula_s.size());
+ }
+
+ return obj;
+}
+
+PyObject* create_named_exp_dict(const ss::document& doc, ixion::named_expressions_iterator iter)
+{
+ PyObject* dict = PyDict_New();
+ for (; iter.has(); iter.next())
+ {
+ auto ne = iter.get();
+ PyObject* name = PyUnicode_FromStringAndSize(ne.name->data(), ne.name->size());
+ PyObject* tokens = create_named_exp_object(doc, ne.expression);
+ PyDict_SetItem(dict, name, tokens);
+ }
+
+ return dict;
+}
+
+PyTypeObject* get_named_exp_type()
+{
+ return &named_exp_type;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/named_expression.hpp b/src/python/named_expression.hpp
new file mode 100644
index 0000000..5473d6f
--- /dev/null
+++ b/src/python/named_expression.hpp
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_NAMED_EXPRESSION_HPP
+#define INCLUDED_ORCUS_PYTHON_NAMED_EXPRESSION_HPP
+
+#include "orcus/spreadsheet/types.hpp"
+
+#include <Python.h>
+#include <ixion/formula_tokens_fwd.hpp>
+
+namespace ixion {
+
+class named_expressions_iterator;
+
+}
+
+namespace orcus {
+
+namespace spreadsheet {
+
+class document;
+
+}
+
+namespace python {
+
+PyObject* create_named_exp_object(const spreadsheet::document& doc, const ixion::named_expression_t* exp);
+
+PyObject* create_named_exp_dict(const spreadsheet::document& doc, ixion::named_expressions_iterator iter);
+
+PyTypeObject* get_named_exp_type();
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/named_expressions.cpp b/src/python/named_expressions.cpp
new file mode 100644
index 0000000..6faffee
--- /dev/null
+++ b/src/python/named_expressions.cpp
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "named_expressions.hpp"
+#include "named_expression.hpp"
+#include "global.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/formula.hpp>
+#include <ixion/model_context.hpp>
+#include <ixion/named_expressions_iterator.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <structmember.h>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus { namespace python {
+
+namespace {
+
+/** non-python part. */
+struct named_exps_data
+{
+ ss::sheet_t origin_sheet = -1; // -1 for global, >=0 for sheet local.
+ const ss::document* doc = nullptr;
+ ixion::named_expressions_iterator src; // original iterator to copy from.
+ ixion::named_expressions_iterator iter;
+};
+
+/** python object. */
+struct pyobj_named_exps
+{
+ PyObject_HEAD
+
+ named_exps_data* data;
+};
+
+inline pyobj_named_exps* t(PyObject* self)
+{
+ return reinterpret_cast<pyobj_named_exps*>(self);
+}
+
+PyObject* named_exps_names(PyObject* self, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ named_exps_data& data = *t(self)->data;
+ PyObject* s = PySet_New(nullptr);
+
+ for (auto iter = data.src; iter.has(); iter.next())
+ {
+ const std::string* name = iter.get().name;
+ PySet_Add(s, PyUnicode_FromStringAndSize(name->data(), name->size()));
+ }
+
+ return s;
+}
+
+void tp_dealloc(pyobj_named_exps* self)
+{
+ delete self->data;
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+int tp_init(pyobj_named_exps* /*self*/, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ return 0;
+}
+
+PyObject* tp_new(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ pyobj_named_exps* self = t(type->tp_alloc(type, 0));
+ self->data = new named_exps_data;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+PyObject* tp_iter(PyObject* self)
+{
+ named_exps_data& data = *t(self)->data;
+ data.iter = data.src;
+
+ Py_INCREF(self);
+ return self;
+}
+
+PyObject* tp_iternext(PyObject* self)
+{
+ named_exps_data& data = *t(self)->data;
+ auto& iter = data.iter;
+
+ if (!iter.has())
+ {
+ PyErr_SetNone(PyExc_StopIteration);
+ return nullptr;
+ }
+
+ ixion::named_expressions_iterator::named_expression item = iter.get();
+ iter.next();
+
+ PyObject* name = PyUnicode_FromStringAndSize(item.name->data(), item.name->size());
+ if (!name)
+ return nullptr;
+
+ PyObject* ne = create_named_exp_object(*data.doc, item.expression);
+ if (!ne)
+ return nullptr;
+
+ PyObject* tup = PyTuple_New(2);
+ PyTuple_SET_ITEM(tup, 0, name);
+ PyTuple_SET_ITEM(tup, 1, ne);
+
+ return tup;
+}
+
+Py_ssize_t sq_length(PyObject* self)
+{
+ named_exps_data& data = *t(self)->data;
+ return data.src.size();
+}
+
+PySequenceMethods tp_as_sequence =
+{
+ sq_length, // lenfunc sq_length
+ 0, // binaryfunc sq_concat
+ 0, // ssizeargfunc sq_repeat
+ 0, // ssizeargfunc sq_item
+ 0, // void *was_sq_slice
+ 0, // ssizeobjargproc sq_ass_item
+ 0, // void *was_sq_ass_slice
+ 0, // objobjproc sq_contains
+ 0, // binaryfunc sq_inplace_concat
+ 0, // ssizeargfunc sq_inplace_repeat
+};
+
+PyMethodDef tp_methods[] =
+{
+ { "names", (PyCFunction)named_exps_names, METH_NOARGS, "Get names for all named expressions stored." },
+ { nullptr }
+};
+
+PyMemberDef tp_members[] =
+{
+ { nullptr }
+};
+
+PyTypeObject named_exps_type =
+{
+ PyVarObject_HEAD_INIT(nullptr, 0)
+ "orcus.NamedExpressions", // tp_name
+ sizeof(pyobj_named_exps), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)tp_dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ &tp_as_sequence, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
+ "orcus spreadsheet formula tokens", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ tp_iter, // tp_iter
+ tp_iternext, // tp_iternext
+ tp_methods, // tp_methods
+ tp_members, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)tp_init, // tp_init
+ 0, // tp_alloc
+ tp_new, // tp_new
+};
+
+} // anonymous namespace
+
+PyObject* create_named_expressions_object(
+ spreadsheet::sheet_t origin_sheet, const spreadsheet::document& doc, ixion::named_expressions_iterator iter)
+{
+ PyTypeObject* type = get_named_exps_type();
+
+ PyObject* obj = create_object_from_type(type);
+ if (!obj)
+ return nullptr;
+
+ type->tp_init(obj, nullptr, nullptr);
+
+ named_exps_data& data = *t(obj)->data;
+ data.src = iter;
+ data.origin_sheet = origin_sheet;
+ data.doc = &doc;
+
+ return obj;
+}
+
+PyTypeObject* get_named_exps_type()
+{
+ return &named_exps_type;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/named_expressions.hpp b/src/python/named_expressions.hpp
new file mode 100644
index 0000000..cfad195
--- /dev/null
+++ b/src/python/named_expressions.hpp
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_NAMED_EXPRESSIONS_HPP
+#define INCLUDED_ORCUS_PYTHON_NAMED_EXPRESSIONS_HPP
+
+#include "orcus/spreadsheet/types.hpp"
+
+#include <Python.h>
+#include <ixion/formula_tokens_fwd.hpp>
+
+namespace ixion {
+
+class named_expressions_iterator;
+
+}
+
+namespace orcus {
+
+namespace spreadsheet {
+
+class document;
+
+}
+
+namespace python {
+
+PyObject* create_named_expressions_object(
+ spreadsheet::sheet_t origin_sheet, const spreadsheet::document& doc, ixion::named_expressions_iterator iter);
+
+PyTypeObject* get_named_exps_type();
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/ods.cpp b/src/python/ods.cpp
new file mode 100644
index 0000000..0a7f5ad
--- /dev/null
+++ b/src/python/ods.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ods.hpp"
+#include "global.hpp"
+
+#ifdef __ORCUS_PYTHON_ODS
+#include "document.hpp"
+#include "orcus/orcus_ods.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#endif
+
+namespace orcus { namespace python {
+
+#ifdef __ORCUS_PYTHON_ODS
+
+PyObject* ods_read(PyObject* /*module*/, PyObject* args, PyObject* kwargs)
+{
+ stream_with_formulas data = read_stream_and_formula_params_from_args(args, kwargs);
+ if (!data.stream)
+ return nullptr;
+
+ try
+ {
+ spreadsheet::range_size_t ss{1048576, 16384};
+ std::unique_ptr<spreadsheet::document> doc = std::make_unique<spreadsheet::document>(ss);
+ spreadsheet::import_factory fact(*doc);
+ fact.set_recalc_formula_cells(data.recalc_formula_cells);
+ fact.set_formula_error_policy(data.error_policy);
+ orcus_ods app(&fact);
+
+ return import_from_stream_into_document(data.stream.get(), app, std::move(doc));
+ }
+ catch (const std::exception& e)
+ {
+ set_python_exception(PyExc_RuntimeError, e);
+ return nullptr;
+ }
+}
+
+#else
+
+PyObject* ods_read(PyObject*, PyObject*, PyObject*)
+{
+ PyErr_SetString(PyExc_RuntimeError, "The ods module is not enabled.");
+ return nullptr;
+}
+
+#endif
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/ods.hpp b/src/python/ods.hpp
new file mode 100644
index 0000000..a25c861
--- /dev/null
+++ b/src/python/ods.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_ODS_HPP
+#define INCLUDED_ORCUS_PYTHON_ODS_HPP
+
+#include <Python.h>
+
+namespace orcus { namespace python {
+
+PyObject* ods_read(PyObject* module, PyObject* args, PyObject* kwargs);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/orcus/__init__.py b/src/python/orcus/__init__.py
new file mode 100644
index 0000000..4914d95
--- /dev/null
+++ b/src/python/orcus/__init__.py
@@ -0,0 +1,111 @@
+#######################################################################
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+########################################################################
+
+try:
+ from _orcus import *
+ from _orcus import __version__
+except ModuleNotFoundError:
+ # We do this to enable sphinx to generate documentation without having to
+ # build the C++ part.
+ pass
+
+from enum import Enum
+
+
+class FormatType(Enum):
+ """Collection of file format types currently used in orcus."""
+
+ UNKNOWN = 0
+ ODS = 1
+ XLSX = 2
+ GNUMERIC = 3
+ XLS_XML = 4
+ CSV = 5
+ YAML = 6
+ JSON = 7
+ XML = 8
+ PARQUET = 9
+
+
+class CellType(Enum):
+ """Collection of cell types stored in spreadsheet."""
+
+ UNKNOWN = 0
+ EMPTY = 1
+ BOOLEAN = 2
+ NUMERIC = 3
+ STRING = 4
+ STRING_WITH_ERROR = 5
+ FORMULA = 6
+ FORMULA_WITH_ERROR = 7
+
+
+class FormulaTokenType(Enum):
+ """Collection of formula token types."""
+
+ UNKNOWN = 0
+ REFERENCE = 1
+ VALUE = 2
+ NAME = 3
+ FUNCTION = 4
+ OPERATOR = 5
+ ERROR = 6
+
+
+class FormulaTokenOp(Enum):
+ """Collection of formula token opcodes."""
+
+ UNKNOWN = 0
+ SINGLE_REF = 1
+ RANGE_REF = 2
+ TABLE_REF = 3
+ NAMED_EXPRESSION = 4
+ STRING = 5
+ VALUE = 6
+ FUNCTION = 7
+ PLUS = 8
+ MINUS = 9
+ DIVIDE = 10
+ MULTIPLY = 11
+ EXPONENT = 12
+ CONCAT = 13
+ EQUAL = 14
+ NOT_EQUAL = 15
+ LESS = 16
+ GREATER = 17
+ LESS_EQUAL = 18
+ GREATER_EQUAL = 19
+ OPEN = 20
+ CLOSE = 21
+ SEP = 22
+ ERROR = 23
+
+
+def get_document_loader_module(format_type):
+ """Obtain a document loader module for the specified format type.
+
+ Args:
+ format_type (orcus.FormatType):
+ Format type for which to load a document loader.
+
+ Returns:
+ Document loader module.
+ """
+ m = None
+ if format_type == FormatType.ODS:
+ from . import ods as m
+ elif format_type == FormatType.XLSX:
+ from . import xlsx as m
+ elif format_type == FormatType.XLS_XML:
+ from . import xls_xml as m
+ elif format_type == FormatType.GNUMERIC:
+ from . import gnumeric as m
+ elif format_type == FormatType.CSV:
+ from . import csv as m
+
+ return m
diff --git a/src/python/orcus/csv.py b/src/python/orcus/csv.py
new file mode 100644
index 0000000..bad095f
--- /dev/null
+++ b/src/python/orcus/csv.py
@@ -0,0 +1,10 @@
+########################################################################
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+########################################################################
+
+from _orcus import _csv_read as read
+
diff --git a/src/python/orcus/gnumeric.py b/src/python/orcus/gnumeric.py
new file mode 100644
index 0000000..d7f0f23
--- /dev/null
+++ b/src/python/orcus/gnumeric.py
@@ -0,0 +1,10 @@
+########################################################################
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+########################################################################
+
+from _orcus import _gnumeric_read as read
+
diff --git a/src/python/orcus/json.py b/src/python/orcus/json.py
new file mode 100644
index 0000000..d351766
--- /dev/null
+++ b/src/python/orcus/json.py
@@ -0,0 +1,10 @@
+########################################################################
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+########################################################################
+
+from _orcus_json import *
+
diff --git a/src/python/orcus/ods.py b/src/python/orcus/ods.py
new file mode 100644
index 0000000..8bcf2b9
--- /dev/null
+++ b/src/python/orcus/ods.py
@@ -0,0 +1,10 @@
+########################################################################
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+########################################################################
+
+from _orcus import _ods_read as read
+
diff --git a/src/python/orcus/tools/__init__.py b/src/python/orcus/tools/__init__.py
new file mode 100644
index 0000000..413bd0a
--- /dev/null
+++ b/src/python/orcus/tools/__init__.py
@@ -0,0 +1,9 @@
+########################################################################
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+########################################################################
+
+
diff --git a/src/python/orcus/tools/bugzilla.py b/src/python/orcus/tools/bugzilla.py
new file mode 100644
index 0000000..f23b4d5
--- /dev/null
+++ b/src/python/orcus/tools/bugzilla.py
@@ -0,0 +1,219 @@
+########################################################################
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+########################################################################
+
+import argparse
+import requests
+import json
+import os
+import base64
+import traceback
+import concurrent.futures as cf
+from pathlib import Path
+from urllib.parse import urlparse
+
+
+class BugzillaAccess:
+ """Encapsulates access to a bugzilla server by using its REST API.
+
+ Args:
+ bzurl (str): URL to the bugzilla server.
+ cache_dir (:obj:`pathlib.Path`): path to the cache directory.
+ """
+
+ def __init__(self, bzurl, cache_dir):
+ self._bzurl = bzurl
+ self._cache_dir = cache_dir
+ os.makedirs(self._cache_dir, exist_ok=True)
+
+ def _get_cache_content(self, cache_file, func_fetch):
+ if os.path.isfile(cache_file):
+ with open(cache_file, 'r') as f:
+ return f.read()
+
+ s = func_fetch()
+ with open(cache_file, 'w') as f:
+ f.write(s)
+
+ return s
+
+ def get_bug_ids(self, bz_params):
+ """Get all bug ID's for specified bugzilla query parameters.
+
+ Args:
+ bz_params (dict):
+ dictionary containing all search parameters. Each search term
+ must form a single key-value pair.
+
+ Returns (:obj:`list` of :obj:`str`):
+ list of bug ID strings.
+ """
+
+ def _fetch():
+ r = requests.get(
+ f"{self._bzurl}/rest/bug",
+ params=bz_params
+ )
+
+ if r.status_code != 200:
+ raise RuntimeError(f"failed to query bug ids from the TDF bugzilla! (status:{r.status_code})")
+ return r.text
+
+ escape_chars = " /"
+ buf = []
+ for key in bz_params.keys():
+ v = str(bz_params[key])
+ for c in escape_chars:
+ v = v.replace(c, '-')
+ buf.append(key)
+ buf.append(v)
+
+ cache_file = '-'.join(buf) + ".json"
+ cache_file = self._cache_dir / cache_file
+ s = self._get_cache_content(cache_file, _fetch)
+
+ content = json.loads(s)
+ bugs = content.get("bugs")
+ if not bugs:
+ return []
+
+ bug_ids = [bug.get("id") for bug in bugs]
+ bug_ids = [x for x in filter(None, bug_ids)]
+ return bug_ids
+
+ def get_attachments(self, bug_id):
+ """Fetch all attachments for specified bug."""
+
+ def _fetch():
+ r = requests.get(f"{self._bzurl}/rest/bug/{bug_id}/attachment")
+ if r.status_code != 200:
+ raise RuntimeError(
+ f"failed to fetch the attachments for bug {bug_id}! (status:{r.status_code})")
+ return r.text
+
+ cache_file = self._cache_dir / f"attachments-{bug_id}.json"
+ s = self._get_cache_content(cache_file, _fetch)
+ content = json.loads(s)
+ attachments = list()
+ for d in content["bugs"][str(bug_id)]:
+ data = d["data"]
+ if not data:
+ continue
+ bytes = base64.b64decode(data)
+ attachments.append({
+ "content_type": d["content_type"],
+ "filename": d["file_name"],
+ "data": bytes
+ })
+ return attachments
+
+
+def parse_query_params(queries):
+ bz_params = dict()
+ for query in queries:
+ k, v = query.split('=')
+ if v and v[0] in ('"', "'"):
+ if v[0] != v[-1]:
+ raise argparse.ArgumentError(f"mis-matched quotes in {query}")
+ v = v[1:-1]
+ bz_params[k] = v
+ return bz_params
+
+
+def _create_argparser():
+ parser = argparse.ArgumentParser(
+ description="""This command allows you to download attachments from a
+bugzilla server that supports REST API.""")
+ parser.add_argument(
+ "--outdir", "-o", type=str, required=True,
+ help="""output directory for downloaded files. Downloaded files are
+grouped by their respective bug ID's.""")
+ parser.add_argument(
+ "--limit", type=int, default=50,
+ help="number of bugs to include in a single set of search results.")
+ parser.add_argument(
+ "--offset", type=int, default=0,
+ help="number of bugs to skip in the search results.")
+ parser.add_argument(
+ "--cont", action="store_true", default=False,
+ help="""when specified, the search continues after the initial batch
+is returned, by retrieving the next batch of results until the entire search
+results are returned. The number specified by the ``--limit`` option is used
+as the batch size.""")
+ parser.add_argument(
+ "--worker", type=int, default=8,
+ help="number of worker threads to use for parallel downloads of files.")
+ parser.add_argument(
+ "--cache-dir", type=Path, default=Path(".bugzilla"),
+ help="""directory to keep downloaded bugzilla search results. The
+command will not send the query request to the remote server when the results
+are cached. You may want to delete the cache directory after you are finished.""")
+ parser.add_argument(
+ "--url", type=str, required=True,
+ help="""base URL for bugzilla service. It must begin with the
+``http(s)://`` prefix.""")
+ parser.add_argument(
+ "query", type=str, nargs='*',
+ help="""One or more query term to use to limit your search. Each query
+term must be in the form key=value. You need to quote the value string when the
+value string contains whitespace character i.e. key="value with space".""")
+ return parser
+
+
+def main():
+ parser = _create_argparser()
+ args = parser.parse_args()
+
+ bz_params = parse_query_params(args.query)
+
+ for k, v in bz_params.items():
+ print(f"{k}: {v}")
+
+ bz_params["limit"] = args.limit
+ bz_params["offset"] = args.offset
+
+ url = urlparse(args.url)
+ cache_dir = Path(args.cache_dir) / url.netloc
+ bz = BugzillaAccess(args.url, cache_dir)
+
+ def _run(bug_id, index, totals):
+ """Top-level function for each worker thread."""
+ width = len(str(totals))
+ index_s = str(index+1)
+ index_s = ' ' * (width - len(index_s)) + index_s
+ print(f"({index_s}/{totals}) fetching attachments for bug {bug_id} ...", flush=True)
+
+ try:
+ attachments = bz.get_attachments(bug_id)
+ for attachment in attachments:
+ filepath = Path(args.outdir) / url.netloc / str(bug_id) / attachment["filename"]
+ os.makedirs(os.path.dirname(filepath), exist_ok=True)
+ with open(filepath, "wb") as f:
+ f.write(attachment["data"])
+ except Exception as e:
+ traceback.print_exc()
+ print(e)
+
+ iter_count = 0
+ while True:
+ bug_ids = bz.get_bug_ids(bz_params)
+ if not bug_ids:
+ return
+ print(f"-- iteration {iter_count+1}", flush=True)
+ with cf.ThreadPoolExecutor(max_workers=args.worker) as executor:
+ for i, bug_id in enumerate(bug_ids):
+ executor.submit(_run, bug_id, i, len(bug_ids))
+
+ if not args.cont:
+ return
+
+ bz_params["offset"] += bz_params["limit"]
+ iter_count += 1
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/python/orcus/tools/file_processor.py b/src/python/orcus/tools/file_processor.py
new file mode 100644
index 0000000..472fea3
--- /dev/null
+++ b/src/python/orcus/tools/file_processor.py
@@ -0,0 +1,295 @@
+########################################################################
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+########################################################################
+
+import argparse
+import os
+import os.path
+import sys
+import string
+import pathlib
+import enum
+import re
+import multiprocessing as mp
+import importlib.util
+
+import orcus
+
+
+class _Config:
+ ext_good = "orcus-pf.good"
+ ext_bad = "orcus-pf.bad"
+ ext_out = "orcus-pf.out"
+ prefix_skip = ".orcus-pf.skip."
+
+
+config = _Config()
+
+
+def is_special_file(filename):
+ if filename.find(config.prefix_skip) >= 0:
+ return True
+
+ return filename.endswith(config.ext_out) or filename.endswith(config.ext_good) or filename.endswith(config.ext_bad)
+
+
+def skips_by_rule(filename, skip_rules):
+ for rule in skip_rules:
+ if rule.search(filename):
+ return True
+ return False
+
+
+def sanitize_string(s):
+ """Replace non-printable characters with \\x[value]."""
+
+ buf = list()
+ for c in s:
+ if c in string.printable:
+ buf.append(c)
+ else:
+ buf.append(f"\\x{ord(c):02X}")
+
+ return "".join(buf)
+
+
+class LoadStatus(enum.Enum):
+ SUCCESS = 0
+ FAILURE = 1
+ SKIPPED = 2
+
+
+def load_doc(bytes):
+
+ buf = list()
+
+ try:
+ format_type = orcus.detect_format(bytes)
+ except Exception as e:
+ buf.append(str(e))
+ status = LoadStatus.SKIPPED
+ return None, status, buf
+
+ buf.append(f"* format type: {format_type}")
+ buf.append(f"* size: {len(bytes)} bytes")
+
+ doc = None
+
+ try:
+ loader = orcus.get_document_loader_module(format_type)
+ if loader is None:
+ buf.append(f"unhandled format type: {format_type}")
+ status = LoadStatus.SKIPPED
+ return doc, status, buf
+
+ status = LoadStatus.SUCCESS
+ doc = loader.read(bytes, error_policy="skip")
+ return doc, status, buf
+
+ except Exception as e:
+ buf.append(f"{e.__class__.__name__}: {e}")
+ status = LoadStatus.FAILURE
+ return None, status, buf
+
+
+def print_results(inpath):
+ outpath = f"{inpath}.{config.ext_out}"
+ with open(outpath, "r") as f:
+ print()
+ for line in f.readlines():
+ print(f" {line.strip()}")
+ print()
+
+
+def remove_result_files(rootdir):
+ for root, dir, files in os.walk(rootdir):
+ for filename in files:
+ if is_special_file(filename):
+ filepath = os.path.join(root, filename)
+ os.remove(filepath)
+
+
+def show_result_stats(rootdir):
+ counts = dict(good=0, bad=0, skipped=0, unprocessed=0)
+ for root, dir, files in os.walk(rootdir):
+ for filename in files:
+ if is_special_file(filename):
+ continue
+
+ inpath = os.path.join(root, filename)
+ out_filepath = f"{inpath}.{config.ext_out}"
+ good_filepath = f"{inpath}.{config.ext_good}"
+ bad_filepath = f"{inpath}.{config.ext_bad}"
+ if os.path.isfile(good_filepath):
+ counts["good"] += 1
+ elif os.path.isfile(bad_filepath):
+ counts["bad"] += 1
+ elif os.path.isfile(out_filepath):
+ counts["skipped"] += 1
+ else:
+ counts["unprocessed"] += 1
+
+ print("* result counts")
+ for cat in ("good", "bad", "skipped", "unprocessed"):
+ print(f" * {cat}: {counts[cat]}")
+
+ total = counts["good"] + counts["bad"]
+ if total:
+ print("* ratios")
+ print(f" * good: {counts['good']/total*100:.1f}%")
+ print(f" * bad: {counts['bad']/total*100:.1f}%")
+
+
+def show_results(rootdir, good, bad):
+ for root, dir, files in os.walk(rootdir):
+ for filename in files:
+ if is_special_file(filename):
+ continue
+ inpath = os.path.join(root, filename)
+ good_filepath = f"{inpath}.{config.ext_good}"
+ bad_filepath = f"{inpath}.{config.ext_bad}"
+
+ if os.path.isfile(good_filepath) and good:
+ print(sanitize_string(inpath), flush=True)
+ print_results(inpath)
+ elif os.path.isfile(bad_filepath) and bad:
+ print(sanitize_string(inpath), flush=True)
+ print_results(inpath)
+ else:
+ continue
+
+
+def load_module_from_filepath(filepath):
+ if not os.path.isfile(filepath):
+ raise RuntimeError(f"{filepath} is not a valid file.")
+
+ mod_name = os.path.splitext(os.path.basename(filepath))[0]
+ mod_name = mod_name.replace('-', '_')
+ spec = importlib.util.spec_from_file_location(mod_name, filepath)
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
+ return mod
+
+
+def process_filepath(i, inpath, outpath, processor_path):
+ mod = load_module_from_filepath(processor_path) if processor_path else None
+ term_buf = list() # terminal output buffer
+ term_buf.append(f"{i} {sanitize_string(inpath)}")
+
+ good_filepath = f"{inpath}.{config.ext_good}"
+ bad_filepath = f"{inpath}.{config.ext_bad}"
+
+ if os.path.isfile(good_filepath) or os.path.isfile(bad_filepath):
+ term_buf.append("already processed. skipping...")
+ return "\n".join(term_buf)
+
+ success = False
+ with open(inpath, 'rb') as f:
+ bytes = f.read()
+
+ buf = list() # non-terminal output buffer
+ doc, status, output = load_doc(bytes)
+ buf.extend(output)
+ if doc and mod:
+ buf.extend(mod.process_document(inpath, doc))
+
+ with open(outpath, "w") as f:
+ f.write("\n".join(buf))
+
+ term_buf.extend(buf)
+
+ if status == LoadStatus.SUCCESS:
+ pathlib.Path(good_filepath).touch()
+ elif status == LoadStatus.FAILURE:
+ pathlib.Path(bad_filepath).touch()
+
+ return "\n".join(term_buf)
+
+
+def _create_argparser():
+ parser = argparse.ArgumentParser(
+ description="""This script allows you to process a collection of spreadsheet documents.""")
+ parser.add_argument(
+ "--skip-file", type=argparse.FileType("r"),
+ help="Optional text file containing a set of regular expressions (one per line). Files that match one of these rules will be skipped.")
+ parser.add_argument("--processes", type=int, default=1, help="Number of worker processes to use.")
+ parser.add_argument("-p", "--processor", type=str, help="Python module file containing callback functions.")
+ parser.add_argument(
+ "--remove-results", action="store_true", default=False,
+ help="Remove all cached results files from the directory tree.")
+ parser.add_argument(
+ "--results", action="store_true", default=False,
+ help="Display the results of the processed files.")
+ parser.add_argument(
+ "--good", action="store_true", default=False,
+ help="Display the results of the successfully processed files.")
+ parser.add_argument(
+ "--bad", action="store_true", default=False,
+ help="Display the results of the unsuccessfully processed files.")
+ parser.add_argument(
+ "--stats", action="store_true", default=False,
+ help="Display statistics of the results. Use it with --results.")
+ parser.add_argument(
+ "rootdir", metavar="ROOT-DIR",
+ help="Root directory below which to recursively find and process test files.")
+ return parser
+
+
+def main():
+ parser = _create_argparser()
+ args = parser.parse_args()
+
+ if args.remove_results:
+ remove_result_files(args.rootdir)
+ return
+
+ if args.results:
+ if args.stats:
+ show_result_stats(args.rootdir)
+ return
+
+ show_results(args.rootdir, args.good, args.bad)
+ return
+
+ skip_rules = list()
+
+ if args.skip_file:
+ for line in args.skip_file.readlines():
+ line = line.strip()
+ if not line:
+ continue
+ rule = re.compile(line)
+ skip_rules.append(rule)
+
+ # build a list of files to process.
+ filepaths = list()
+ for root, dir, files in os.walk(args.rootdir):
+ for filename in files:
+ if is_special_file(filename):
+ continue
+
+ inpath = os.path.join(root, filename)
+ outpath = f"{inpath}.{config.ext_out}"
+ if skips_by_rule(inpath, skip_rules):
+ pathlib.Path(outpath).touch()
+ continue
+
+ filepaths.append((inpath, outpath))
+
+ with mp.Pool(processes=args.processes) as pool:
+ futures = list()
+ for i, (inpath, outpath) in enumerate(filepaths):
+ future = pool.apply_async(process_filepath, (i, inpath, outpath, args.processor))
+ futures.append(future)
+
+ for future in futures:
+ output = future.get()
+ print(output)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/python/orcus/xls_xml.py b/src/python/orcus/xls_xml.py
new file mode 100644
index 0000000..671d39b
--- /dev/null
+++ b/src/python/orcus/xls_xml.py
@@ -0,0 +1,10 @@
+########################################################################
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+########################################################################
+
+from _orcus import _xls_xml_read as read
+
diff --git a/src/python/orcus/xlsx.py b/src/python/orcus/xlsx.py
new file mode 100644
index 0000000..fd24ee1
--- /dev/null
+++ b/src/python/orcus/xlsx.py
@@ -0,0 +1,10 @@
+########################################################################
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+########################################################################
+
+from _orcus import _xlsx_read as read
+
diff --git a/src/python/python.cpp b/src/python/python.cpp
new file mode 100644
index 0000000..53fb867
--- /dev/null
+++ b/src/python/python.cpp
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/env.hpp"
+#include "orcus/info.hpp"
+
+#include "root.hpp"
+#include "xlsx.hpp"
+#include "ods.hpp"
+#include "csv.hpp"
+#include "xls_xml.hpp"
+#include "gnumeric.hpp"
+
+#ifdef __ORCUS_SPREADSHEET_MODEL
+#include "document.hpp"
+#include "sheet.hpp"
+#include "sheet_rows.hpp"
+#include "cell.hpp"
+#include "named_expression.hpp"
+#include "named_expressions.hpp"
+#include "formula_token.hpp"
+#include "formula_tokens.hpp"
+#endif
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <Python.h>
+
+#define ORCUS_DEBUG_PYTHON 0
+#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
+
+using namespace std;
+
+namespace orcus { namespace python {
+
+namespace {
+
+#if ORCUS_DEBUG_PYTHON
+void print_args(PyObject* args)
+{
+ string args_str;
+ PyObject* repr = PyObject_Repr(args);
+ if (repr)
+ {
+ Py_INCREF(repr);
+ args_str = PyBytes_AsString(repr);
+ Py_DECREF(repr);
+ }
+ cout << args_str << "\n";
+}
+#endif
+
+PyMethodDef orcus_methods[] =
+{
+ { "detect_format", (PyCFunction)detect_format, METH_VARARGS | METH_KEYWORDS,
+ "Detect the format type of a spreadsheet file." },
+
+ { "_csv_read", (PyCFunction)csv_read, METH_VARARGS | METH_KEYWORDS,
+ "Load specified csv file into a document model." },
+
+ { "_ods_read", (PyCFunction)ods_read, METH_VARARGS | METH_KEYWORDS,
+ "Load specified ods file into a document model." },
+
+ { "_xlsx_read", (PyCFunction)xlsx_read, METH_VARARGS | METH_KEYWORDS,
+ "Load specified xlsx file into a document model." },
+
+ { "_xls_xml_read", (PyCFunction)xls_xml_read, METH_VARARGS | METH_KEYWORDS,
+ "Load specified xls-xml file into a document model." },
+
+ { "_gnumeric_read", (PyCFunction)gnumeric_read, METH_VARARGS | METH_KEYWORDS,
+ "Load specified gnumeric file into a document model." },
+
+ { nullptr, nullptr, 0, nullptr }
+};
+
+struct module_state
+{
+ PyObject* error;
+};
+
+int orcus_traverse(PyObject* m, visitproc visit, void* arg)
+{
+ Py_VISIT(GETSTATE(m)->error);
+ return 0;
+}
+
+int orcus_clear(PyObject* m)
+{
+ Py_CLEAR(GETSTATE(m)->error);
+ return 0;
+}
+
+[[maybe_unused]]
+bool add_type_to_module(PyObject* m, PyTypeObject* typeobj, const char* type_name)
+{
+ if (PyType_Ready(typeobj))
+ return false;
+
+ Py_INCREF(typeobj);
+ if (PyModule_AddObject(m, type_name, reinterpret_cast<PyObject*>(typeobj)) < 0)
+ {
+ Py_DECREF(m);
+ Py_DECREF(typeobj);
+ return false;
+ }
+
+ return true;
+}
+
+bool populate_module_attributes(PyObject* m)
+{
+ std::ostringstream os;
+ os << orcus::get_version_major() << '.'
+ << orcus::get_version_minor() << '.'
+ << orcus::get_version_micro();
+
+ PyObject* version = PyUnicode_FromString(os.str().data());
+ if (PyModule_AddObject(m, "__version__", version) < 0)
+ return false;
+
+ return true;
+}
+
+}
+
+struct PyModuleDef moduledef =
+{
+ PyModuleDef_HEAD_INIT,
+ "_orcus",
+ nullptr,
+ sizeof(struct module_state),
+ orcus_methods,
+ nullptr,
+ orcus_traverse,
+ orcus_clear,
+ nullptr
+};
+
+}}
+
+extern "C" {
+
+ORCUS_DLLPUBLIC PyObject* PyInit__orcus()
+{
+ PyObject* m = PyModule_Create(&orcus::python::moduledef);
+ if (!orcus::python::populate_module_attributes(m))
+ return nullptr;
+
+#ifdef __ORCUS_SPREADSHEET_MODEL
+ if (!orcus::python::add_type_to_module(m, orcus::python::get_document_type(), "Document"))
+ return nullptr;
+
+ if (!orcus::python::add_type_to_module(m, orcus::python::get_sheet_type(), "Sheet"))
+ return nullptr;
+
+ if (!orcus::python::add_type_to_module(m, orcus::python::get_sheet_rows_type(), "SheetRows"))
+ return nullptr;
+
+ if (!orcus::python::add_type_to_module(m, orcus::python::get_cell_type(), "Cell"))
+ return nullptr;
+
+ if (!orcus::python::add_type_to_module(m, orcus::python::get_named_exp_type(), "NamedExpression"))
+ return nullptr;
+
+ if (!orcus::python::add_type_to_module(m, orcus::python::get_named_exps_type(), "NamedExpressions"))
+ return nullptr;
+
+ if (!orcus::python::add_type_to_module(m, orcus::python::get_formula_token_type(), "FormulaToken"))
+ return nullptr;
+
+ if (!orcus::python::add_type_to_module(m, orcus::python::get_formula_tokens_type(), "FormulaTokens"))
+ return nullptr;
+#endif
+
+ return m;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/root.cpp b/src/python/root.cpp
new file mode 100644
index 0000000..d3ac021
--- /dev/null
+++ b/src/python/root.cpp
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "root.hpp"
+#include "document.hpp"
+#include "global.hpp"
+
+#include "orcus/format_detection.hpp"
+#include "orcus/info.hpp"
+
+#include <iostream>
+#include <sstream>
+
+#include <object.h>
+
+using namespace std;
+
+namespace orcus { namespace python {
+
+PyObject* detect_format(PyObject* /*module*/, PyObject* args, PyObject* kwargs)
+{
+ py_unique_ptr stream = read_stream_from_args(args, kwargs);
+ if (!stream)
+ return nullptr;
+
+ char* p = nullptr;
+ Py_ssize_t n = 0;
+ if (PyBytes_AsStringAndSize(stream.get(), &p, &n) < 0)
+ return nullptr;
+
+ try
+ {
+ format_t ft = orcus::detect({p, (size_t)n});
+
+ switch (ft)
+ {
+ case format_t::ods:
+ return get_python_enum_value("FormatType", "ODS");
+ case format_t::xlsx:
+ return get_python_enum_value("FormatType", "XLSX");
+ case format_t::gnumeric:
+ return get_python_enum_value("FormatType", "GNUMERIC");
+ case format_t::xls_xml:
+ return get_python_enum_value("FormatType", "XLS_XML");
+ case format_t::parquet:
+ return get_python_enum_value("FormatType", "PARQUET");
+ case format_t::csv:
+ return get_python_enum_value("FormatType", "CSV");
+ case format_t::unknown:
+ default:
+ return get_python_enum_value("FormatType", "UNKNOWN");
+ }
+ }
+ catch (const std::exception&)
+ {
+ PyErr_SetString(PyExc_ValueError, "failed to perform deep detection on this file.");
+ return nullptr;
+ }
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/python/root.hpp b/src/python/root.hpp
new file mode 100644
index 0000000..9b679bd
--- /dev/null
+++ b/src/python/root.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_ROOT_HPP
+#define INCLUDED_ORCUS_PYTHON_ROOT_HPP
+
+#include <Python.h>
+
+namespace orcus { namespace python {
+
+PyObject* detect_format(PyObject* module, PyObject* args, PyObject* kwargs);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/sheet.cpp b/src/python/sheet.cpp
new file mode 100644
index 0000000..d4037ea
--- /dev/null
+++ b/src/python/sheet.cpp
@@ -0,0 +1,327 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "sheet.hpp"
+#include "sheet_rows.hpp"
+#include "named_expression.hpp"
+#include "named_expressions.hpp"
+
+#include <orcus/spreadsheet/types.hpp>
+#include <orcus/spreadsheet/sheet.hpp>
+#include <orcus/spreadsheet/document.hpp>
+
+#include <ixion/model_context.hpp>
+#include <ixion/named_expressions_iterator.hpp>
+
+#include <structmember.h>
+#include <bytesobject.h>
+#include <iostream>
+#include <sstream>
+#include <cstring>
+
+namespace ss = orcus::spreadsheet;
+
+namespace orcus { namespace python {
+
+sheet_data::sheet_data() : m_doc(nullptr), m_sheet(nullptr) {}
+sheet_data::~sheet_data() {}
+
+namespace {
+
+/**
+ * Python object for orcus.Sheet.
+ */
+struct pyobj_sheet
+{
+ PyObject_HEAD
+
+ PyObject* name;
+ PyObject* sheet_size;
+ PyObject* data_size;
+ PyObject* named_expressions;
+
+ sheet_data* data;
+};
+
+inline pyobj_sheet* t(PyObject* self)
+{
+ return reinterpret_cast<pyobj_sheet*>(self);
+}
+
+inline sheet_data* get_sheet_data(PyObject* self)
+{
+ return t(self)->data;
+}
+
+/**
+ * Get the underlying C++ sheet class instance from the python object
+ * representation.
+ */
+inline spreadsheet::sheet* get_core_sheet(PyObject* self)
+{
+ return get_sheet_data(self)->m_sheet;
+}
+
+void tp_dealloc(pyobj_sheet* self)
+{
+ delete self->data;
+
+ Py_CLEAR(self->name);
+ Py_CLEAR(self->sheet_size);
+ Py_CLEAR(self->data_size);
+
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+PyObject* tp_new(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ pyobj_sheet* self = (pyobj_sheet*)type->tp_alloc(type, 0);
+ self->data = new sheet_data;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+int tp_init(pyobj_sheet* /*self*/, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ return 0;
+}
+
+PyObject* sheet_get_rows(PyObject* self, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ PyTypeObject* sr_type = get_sheet_rows_type();
+
+ PyObject* rows = sr_type->tp_new(sr_type, nullptr, nullptr);
+ if (!rows)
+ return nullptr;
+
+ sr_type->tp_init(rows, nullptr, nullptr);
+
+ // Populate the sheet rows data.
+ sheet_data* data = get_sheet_data(self);
+ store_sheet_rows_data(rows, data->m_doc, data->m_sheet);
+
+ return rows;
+}
+
+namespace {
+
+format_t to_format_type_enum(PyObject* format)
+{
+ static const char* err_not_format_type = "An enum value of 'orcus.FormatType' was expected.";
+ static const char* err_format_not_supported = "Unsupported format type.";
+
+ // Check the type name.
+
+ PyTypeObject* type = Py_TYPE(format);
+ if (!type || strncmp(type->tp_name, "FormatType", 10u) != 0)
+ {
+ PyErr_SetString(PyExc_RuntimeError, err_not_format_type);
+ return format_t::unknown;
+ }
+
+ // Now check the member name.
+
+ PyObject* format_s = PyObject_GetAttrString(format, "name"); // new reference
+ if (!format_s)
+ {
+ PyErr_SetString(PyExc_RuntimeError, err_not_format_type);
+ return format_t::unknown;
+ }
+
+ // TODO : currently we only support csv format. Change this code when we
+ // add more format type(s) to support.
+
+ const char* p = PyUnicode_AsUTF8(format_s);
+ if (!p || strncmp(p, "CSV", 3u) != 0)
+ {
+ PyErr_SetString(PyExc_RuntimeError, err_format_not_supported);
+ Py_DECREF(format_s);
+ return format_t::unknown;
+ }
+
+ Py_DECREF(format_s);
+ return format_t::csv;
+}
+
+bool sheet_write_as_csv(spreadsheet::sheet* sheet, PyObject* file)
+{
+ std::ostringstream os;
+ sheet->dump_csv(os);
+ std::string s = os.str();
+
+ if (!s.empty())
+ {
+ PyObject* func_write = PyObject_GetAttrString(file, "write"); // new reference
+ if (!func_write)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "'write' function was expected, but not found.");
+ return false;
+ }
+
+ // write the content as python's utf-8 string ('s'). Use 'y' to write
+ // it as bytes (for future reference).
+ PyObject_CallFunction(func_write, "s", s.data(), nullptr);
+ Py_XDECREF(func_write);
+ }
+
+ return true;
+}
+
+}
+
+PyObject* sheet_write(PyObject* self, PyObject* args, PyObject* kwargs)
+{
+ static const char* kwlist[] = { "file", "format", nullptr };
+
+ PyObject* file = nullptr;
+ PyObject* format = nullptr;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", const_cast<char**>(kwlist), &file, &format))
+ return nullptr;
+
+ format_t ft = to_format_type_enum(format);
+
+ if (ft == format_t::unknown)
+ return nullptr;
+
+ spreadsheet::sheet* sheet = get_core_sheet(self);
+
+ switch (ft)
+ {
+ case format_t::csv:
+ {
+ if (!sheet_write_as_csv(sheet, file))
+ return nullptr;
+
+ break;
+ }
+ default:
+ {
+ PyErr_SetString(PyExc_RuntimeError, "this format is not yet supported.");
+ return nullptr;
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* sheet_get_named_expressions(PyObject* self, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ const ss::document& doc = *t(self)->data->m_doc;
+ ss::sheet_t si = t(self)->data->m_sheet->get_index();
+ const ixion::model_context& cxt = doc.get_model_context();
+ return create_named_expressions_object(si, doc, cxt.get_named_expressions_iterator(si));
+}
+
+PyMethodDef tp_methods[] =
+{
+ { "get_rows", (PyCFunction)sheet_get_rows, METH_VARARGS, "Get a sheet row iterator." },
+ { "write", (PyCFunction)sheet_write, METH_VARARGS | METH_KEYWORDS, "Write sheet content to specified file object." },
+ { "get_named_expressions", (PyCFunction)sheet_get_named_expressions, METH_NOARGS, "Get a named expressions iterator." },
+ { nullptr }
+};
+
+PyMemberDef tp_members[] =
+{
+ { (char*)"name", T_OBJECT_EX, offsetof(pyobj_sheet, name), READONLY, (char*)"sheet name" },
+ { (char*)"sheet_size", T_OBJECT_EX, offsetof(pyobj_sheet, sheet_size), READONLY, (char*)"sheet size" },
+ { (char*)"data_size", T_OBJECT_EX, offsetof(pyobj_sheet, data_size), READONLY, (char*)"data size" },
+ { nullptr }
+};
+
+PyTypeObject sheet_type =
+{
+ PyVarObject_HEAD_INIT(nullptr, 0)
+ "orcus.Sheet", // tp_name
+ sizeof(pyobj_sheet), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)tp_dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ 0, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
+ "orcus sheet object", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ tp_methods, // tp_methods
+ tp_members, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)tp_init, // tp_init
+ 0, // tp_alloc
+ tp_new, // tp_new
+};
+
+}
+
+sheet_data* get_sheet_data(PyObject* self)
+{
+ return reinterpret_cast<pyobj_sheet*>(self)->data;
+}
+
+PyTypeObject* get_sheet_type()
+{
+ return &sheet_type;
+}
+
+void store_sheet(
+ PyObject* self, const spreadsheet::document* doc, spreadsheet::sheet* orcus_sheet)
+{
+ pyobj_sheet* pysheet = reinterpret_cast<pyobj_sheet*>(self);
+ pysheet->data->m_doc = doc;
+ pysheet->data->m_sheet = orcus_sheet;
+
+ // Populate the python members.
+
+ // Sheet name
+ spreadsheet::sheet_t sid = orcus_sheet->get_index();
+ std::string_view sheet_name = doc->get_sheet_name(sid);
+ pysheet->name = PyUnicode_FromStringAndSize(sheet_name.data(), sheet_name.size());
+
+ // Data size - size of the data area.
+ ixion::abs_range_t range = orcus_sheet->get_data_range();
+ if (range.valid())
+ {
+ pysheet->data_size = PyDict_New();
+ PyDict_SetItemString(pysheet->data_size, "column", PyLong_FromLong(range.last.column+1));
+ PyDict_SetItemString(pysheet->data_size, "row", PyLong_FromLong(range.last.row+1));
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ pysheet->data_size = Py_None;
+ }
+
+ // Sheet size - size of the entire sheet.
+ pysheet->sheet_size = PyDict_New();
+ ss::range_size_t sheet_size = doc->get_sheet_size();
+ PyDict_SetItemString(pysheet->sheet_size, "column", PyLong_FromLong(sheet_size.columns));
+ PyDict_SetItemString(pysheet->sheet_size, "row", PyLong_FromLong(sheet_size.rows));
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/sheet.hpp b/src/python/sheet.hpp
new file mode 100644
index 0000000..ef349ba
--- /dev/null
+++ b/src/python/sheet.hpp
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_SHEET_HPP
+#define INCLUDED_ORCUS_PYTHON_SHEET_HPP
+
+#include <Python.h>
+
+namespace orcus {
+
+namespace spreadsheet {
+
+class sheet;
+class document;
+
+}
+
+namespace python {
+
+/** non-python part of the sheet object. */
+struct sheet_data
+{
+ const spreadsheet::document* m_doc;
+ spreadsheet::sheet* m_sheet;
+
+ sheet_data();
+ ~sheet_data();
+};
+
+PyTypeObject* get_sheet_type();
+
+void store_sheet(
+ PyObject* self, const spreadsheet::document* doc, spreadsheet::sheet* orcus_sheet);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/sheet_rows.cpp b/src/python/sheet_rows.cpp
new file mode 100644
index 0000000..be49589
--- /dev/null
+++ b/src/python/sheet_rows.cpp
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "sheet_rows.hpp"
+#include "memory.hpp"
+#include "cell.hpp"
+#include "orcus/spreadsheet/sheet.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/model_context.hpp>
+
+namespace orcus { namespace python {
+
+sheet_rows_data::sheet_rows_data() :
+ m_doc(nullptr),
+ m_sheet(nullptr),
+ m_range(ixion::abs_range_t::invalid),
+ m_current_row(-1) {}
+
+sheet_rows_data::~sheet_rows_data() {}
+
+namespace {
+
+/**
+ * Python object for orcus.SheetRows.
+ */
+struct pyobj_sheet_rows
+{
+ PyObject_HEAD
+
+ sheet_rows_data* m_data;
+};
+
+void sheet_rows_dealloc(pyobj_sheet_rows* self)
+{
+ delete self->m_data;
+
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+PyObject* sheet_rows_new(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ pyobj_sheet_rows* self = (pyobj_sheet_rows*)type->tp_alloc(type, 0);
+ self->m_data = new sheet_rows_data;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+int sheet_rows_init(pyobj_sheet_rows* /*self*/, PyObject* /*args*/, PyObject* /*kwargs*/)
+{
+ return 0;
+}
+
+PyObject* sheet_rows_iter(PyObject* self)
+{
+ sheet_rows_data* data = reinterpret_cast<pyobj_sheet_rows*>(self)->m_data;
+
+ const ixion::abs_range_t& range = data->m_range;
+ if (range.valid())
+ {
+ data->m_current_row = 0;
+
+ ixion::abs_rc_range_t sheet_range;
+ sheet_range.first.column = 0;
+ sheet_range.first.row = 0;
+ sheet_range.last.column = range.last.column;
+ sheet_range.last.row = range.last.row;
+
+ data->m_range_iterator = data->m_doc->get_model_context().get_model_iterator(
+ data->m_sheet->get_index(), ixion::rc_direction_t::horizontal, sheet_range);
+ }
+
+ Py_INCREF(self);
+ return self;
+}
+
+PyObject* sheet_rows_iternext(PyObject* self)
+{
+ sheet_rows_data* data = reinterpret_cast<pyobj_sheet_rows*>(self)->m_data;
+ ixion::model_iterator& iter = data->m_range_iterator;
+
+ if (!iter.has())
+ {
+ // No more elements. Stop the iteration.
+ PyErr_SetNone(PyExc_StopIteration);
+ return nullptr;
+ }
+
+ PyObject* pyobj_row = PyTuple_New(data->m_range.last.column+1);
+
+ for (; iter.has(); iter.next())
+ {
+ const auto& cell = iter.get();
+ if (cell.row != data->m_current_row)
+ {
+ ++data->m_current_row;
+ assert(cell.row == data->m_current_row);
+ break;
+ }
+
+ PyObject* obj = nullptr;
+ switch (cell.type)
+ {
+ case ixion::celltype_t::empty:
+ {
+ obj = create_cell_object_empty();
+ break;
+ }
+ case ixion::celltype_t::boolean:
+ {
+ obj = create_cell_object_boolean(std::get<bool>(cell.value));
+ break;
+ }
+ case ixion::celltype_t::numeric:
+ {
+ obj = create_cell_object_numeric(std::get<double>(cell.value));
+ break;
+ }
+ case ixion::celltype_t::string:
+ {
+ ixion::string_id_t sid = std::get<ixion::string_id_t>(cell.value);
+ const ixion::model_context& cxt = data->m_doc->get_model_context();
+ const std::string* ps = cxt.get_string(sid);
+ obj = create_cell_object_string(ps);
+ break;
+ }
+ case ixion::celltype_t::formula:
+ {
+ const ixion::formula_cell* fc = std::get<const ixion::formula_cell*>(cell.value);
+ ixion::abs_address_t pos(data->m_sheet->get_index(), cell.row, cell.col);
+ obj = create_cell_object_formula(*data->m_doc, pos, fc);
+ break;
+ }
+ case ixion::celltype_t::unknown:
+ break;
+ }
+
+ if (!obj)
+ return nullptr;
+
+ PyTuple_SetItem(pyobj_row, cell.col, obj);
+ }
+
+ return pyobj_row;
+}
+
+PyTypeObject sheet_rows_type =
+{
+ PyVarObject_HEAD_INIT(nullptr, 0)
+ "orcus.SheetRows", // tp_name
+ sizeof(pyobj_sheet_rows), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)sheet_rows_dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ 0, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
+ "orcus sheet rows iterator", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ (getiterfunc)sheet_rows_iter, // tp_iter
+ (iternextfunc)sheet_rows_iternext, // tp_iternext
+ 0, // tp_methods
+ 0, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)sheet_rows_init, // tp_init
+ 0, // tp_alloc
+ sheet_rows_new, // tp_new
+};
+
+}
+
+PyTypeObject* get_sheet_rows_type()
+{
+ return &sheet_rows_type;
+}
+
+void store_sheet_rows_data(PyObject* self, const spreadsheet::document* orcus_doc, const spreadsheet::sheet* orcus_sheet)
+{
+ sheet_rows_data* data = reinterpret_cast<pyobj_sheet_rows*>(self)->m_data;
+ data->m_doc = orcus_doc;
+ data->m_sheet = orcus_sheet;
+ data->m_range = orcus_sheet->get_data_range();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/sheet_rows.hpp b/src/python/sheet_rows.hpp
new file mode 100644
index 0000000..e750098
--- /dev/null
+++ b/src/python/sheet_rows.hpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_SHEET_ROWS_HPP
+#define INCLUDED_ORCUS_PYTHON_SHEET_ROWS_HPP
+
+#include <Python.h>
+#include <ixion/address.hpp>
+#include <ixion/model_iterator.hpp>
+
+namespace ixion {
+
+class formula_name_resolver;
+
+}
+
+namespace orcus {
+
+namespace spreadsheet {
+
+class sheet;
+class document;
+
+}
+
+namespace python {
+
+/** non-python part. */
+struct sheet_rows_data
+{
+ const spreadsheet::document* m_doc;
+ const spreadsheet::sheet* m_sheet;
+ ixion::abs_range_t m_range;
+ ixion::model_iterator m_range_iterator;
+
+ ixion::row_t m_current_row;
+
+ sheet_rows_data();
+ ~sheet_rows_data();
+};
+
+PyTypeObject* get_sheet_rows_type();
+
+void store_sheet_rows_data(PyObject* self, const spreadsheet::document* orcus_doc, const spreadsheet::sheet* orcus_sheet);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/xls_xml.cpp b/src/python/xls_xml.cpp
new file mode 100644
index 0000000..5caf747
--- /dev/null
+++ b/src/python/xls_xml.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xls_xml.hpp"
+#include "global.hpp"
+
+#ifdef __ORCUS_PYTHON_XLS_XML
+#include "document.hpp"
+#include "orcus/orcus_xls_xml.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#endif
+
+namespace orcus { namespace python {
+
+#ifdef __ORCUS_PYTHON_XLS_XML
+
+PyObject* xls_xml_read(PyObject* /*module*/, PyObject* args, PyObject* kwargs)
+{
+ stream_with_formulas data = read_stream_and_formula_params_from_args(args, kwargs);
+ if (!data.stream)
+ return nullptr;
+
+ try
+ {
+ spreadsheet::range_size_t ss{1048576, 16384};
+ std::unique_ptr<spreadsheet::document> doc = std::make_unique<spreadsheet::document>(ss);
+ spreadsheet::import_factory fact(*doc);
+ fact.set_recalc_formula_cells(data.recalc_formula_cells);
+ fact.set_formula_error_policy(data.error_policy);
+ orcus_xls_xml app(&fact);
+
+ return import_from_stream_into_document(data.stream.get(), app, std::move(doc));
+ }
+ catch (const std::exception& e)
+ {
+ set_python_exception(PyExc_RuntimeError, e);
+ return nullptr;
+ }
+}
+
+#else
+
+PyObject* xls_xml_read(PyObject*, PyObject*, PyObject*)
+{
+ PyErr_SetString(PyExc_RuntimeError, "The xls-xml module is not enabled.");
+ return nullptr;
+}
+
+#endif
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/xls_xml.hpp b/src/python/xls_xml.hpp
new file mode 100644
index 0000000..5639521
--- /dev/null
+++ b/src/python/xls_xml.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_XLS_XML_HPP
+#define INCLUDED_ORCUS_PYTHON_XLS_XML_HPP
+
+#include <Python.h>
+
+namespace orcus { namespace python {
+
+PyObject* xls_xml_read(PyObject* module, PyObject* args, PyObject* kwargs);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/xlsx.cpp b/src/python/xlsx.cpp
new file mode 100644
index 0000000..56cf47d
--- /dev/null
+++ b/src/python/xlsx.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "xlsx.hpp"
+#include "global.hpp"
+
+#ifdef __ORCUS_PYTHON_XLSX
+#include "document.hpp"
+#include "orcus/orcus_xlsx.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+#endif
+
+namespace orcus { namespace python {
+
+#ifdef __ORCUS_PYTHON_XLSX
+
+PyObject* xlsx_read(PyObject* /*module*/, PyObject* args, PyObject* kwargs)
+{
+ stream_with_formulas data = read_stream_and_formula_params_from_args(args, kwargs);
+ if (!data.stream)
+ return nullptr;
+
+ try
+ {
+ spreadsheet::range_size_t ss{1048576, 16384};
+ std::unique_ptr<spreadsheet::document> doc = std::make_unique<spreadsheet::document>(ss);
+ spreadsheet::import_factory fact(*doc);
+ fact.set_recalc_formula_cells(data.recalc_formula_cells);
+ fact.set_formula_error_policy(data.error_policy);
+ orcus_xlsx app(&fact);
+
+ return import_from_stream_into_document(data.stream.get(), app, std::move(doc));
+ }
+ catch (const std::exception& e)
+ {
+ set_python_exception(PyExc_RuntimeError, e);
+ return nullptr;
+ }
+}
+
+#else
+
+PyObject* xlsx_read(PyObject*, PyObject*, PyObject*)
+{
+ PyErr_SetString(PyExc_RuntimeError, "The xlsx module is not enabled.");
+ return nullptr;
+}
+
+#endif
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/python/xlsx.hpp b/src/python/xlsx.hpp
new file mode 100644
index 0000000..b3d97e9
--- /dev/null
+++ b/src/python/xlsx.hpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PYTHON_XLSX_HPP
+#define INCLUDED_ORCUS_PYTHON_XLSX_HPP
+
+#include <Python.h>
+
+namespace orcus { namespace python {
+
+PyObject* xlsx_read(PyObject* module, PyObject* args, PyObject* kwargs);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/Makefile.am b/src/spreadsheet/Makefile.am
new file mode 100644
index 0000000..8f1e0fb
--- /dev/null
+++ b/src/spreadsheet/Makefile.am
@@ -0,0 +1,90 @@
+if BUILD_SPREADSHEET_MODEL
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include \
+ -D__ORCUS_SPM_BUILDING_DLL
+
+AM_CPPFLAGS += $(BOOST_CPPFLAGS) $(LIBIXION_CFLAGS)
+
+if HAVE_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_FILESYSTEM=1"
+endif
+
+if HAVE_EXPERIMENTAL_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+endif
+
+COMMON_CPPFLAGS = $(AM_CPPFLAGS)
+
+if HAVE_STATIC_LIB
+AM_CPPFLAGS += -D__ORCUS_STATIC_LIB=1
+endif
+
+lib_LTLIBRARIES = liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_SOURCES = \
+ auto_filter.cpp \
+ check_dumper.hpp \
+ check_dumper.cpp \
+ config.cpp \
+ debug_state_dumper.hpp \
+ debug_state_dumper.cpp \
+ document.cpp \
+ document_impl.hpp \
+ document_impl.cpp \
+ document_types.cpp \
+ dumper_global.hpp \
+ dumper_global.cpp \
+ factory.cpp \
+ factory_pivot.hpp \
+ factory_pivot.cpp \
+ factory_shared_strings.hpp \
+ factory_shared_strings.cpp \
+ factory_sheet.hpp \
+ factory_sheet.cpp \
+ factory_styles.cpp \
+ factory_table.hpp \
+ factory_table.cpp \
+ flat_dumper.hpp \
+ flat_dumper.cpp \
+ formula_global.hpp \
+ formula_global.cpp \
+ html_dumper.hpp \
+ html_dumper.cpp \
+ impl_types.hpp \
+ csv_dumper.hpp \
+ csv_dumper.cpp \
+ json_dumper.hpp \
+ json_dumper.cpp \
+ number_format.hpp \
+ number_format.cpp \
+ pivot.cpp \
+ shared_formula.hpp \
+ shared_formula.cpp \
+ shared_strings.cpp \
+ sheet.cpp \
+ sheet_impl.hpp \
+ sheet_impl.cpp \
+ styles.cpp \
+ view.cpp \
+ global_settings.hpp \
+ global_settings.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBIXION_CFLAGS)
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LDFLAGS = -no-undefined
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LIBADD = \
+ $(LIBIXION_LIBS) \
+ $(BOOST_DATE_TIME_LIBS) \
+ $(BOOST_SYSTEM_LIBS) \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../liborcus/liborcus-@ORCUS_API_VERSION@.la
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LIBADD += -lstdc++fs
+else
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LIBADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+endif
diff --git a/src/spreadsheet/Makefile.in b/src/spreadsheet/Makefile.in
new file mode 100644
index 0000000..f1fabb8
--- /dev/null
+++ b/src/spreadsheet/Makefile.in
@@ -0,0 +1,1134 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_FILESYSTEM_TRUE@am__append_1 = "-DHAVE_FILESYSTEM=1"
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@am__append_2 = "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_STATIC_LIB_TRUE@am__append_3 = -D__ORCUS_STATIC_LIB=1
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_4 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_5 = $(BOOST_FILESYSTEM_LIBS)
+subdir = src/spreadsheet
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+@BUILD_SPREADSHEET_MODEL_TRUE@liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_DEPENDENCIES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ../liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_2)
+am__liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_SOURCES_DIST = \
+ auto_filter.cpp check_dumper.hpp check_dumper.cpp config.cpp \
+ debug_state_dumper.hpp debug_state_dumper.cpp document.cpp \
+ document_impl.hpp document_impl.cpp document_types.cpp \
+ dumper_global.hpp dumper_global.cpp factory.cpp \
+ factory_pivot.hpp factory_pivot.cpp factory_shared_strings.hpp \
+ factory_shared_strings.cpp factory_sheet.hpp factory_sheet.cpp \
+ factory_styles.cpp factory_table.hpp factory_table.cpp \
+ flat_dumper.hpp flat_dumper.cpp formula_global.hpp \
+ formula_global.cpp html_dumper.hpp html_dumper.cpp \
+ impl_types.hpp csv_dumper.hpp csv_dumper.cpp json_dumper.hpp \
+ json_dumper.cpp number_format.hpp number_format.cpp pivot.cpp \
+ shared_formula.hpp shared_formula.cpp shared_strings.cpp \
+ sheet.cpp sheet_impl.hpp sheet_impl.cpp styles.cpp view.cpp \
+ global_settings.hpp global_settings.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@am_liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_OBJECTS = liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_OBJECTS = $(am_liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LINK = $(LIBTOOL) \
+ $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_SPREADSHEET_MODEL_TRUE@am_liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_rpath = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ -rpath $(libdir)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Plo
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = \
+ $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_SOURCES)
+DIST_SOURCES = $(am__liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+@BUILD_SPREADSHEET_MODEL_TRUE@AM_CPPFLAGS = -I$(top_srcdir)/include \
+@BUILD_SPREADSHEET_MODEL_TRUE@ -I$(top_srcdir)/src/include \
+@BUILD_SPREADSHEET_MODEL_TRUE@ -D__ORCUS_SPM_BUILDING_DLL \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(BOOST_CPPFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(LIBIXION_CFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_1) $(am__append_2) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_3)
+@BUILD_SPREADSHEET_MODEL_TRUE@COMMON_CPPFLAGS = $(AM_CPPFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@lib_LTLIBRARIES = liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la
+@BUILD_SPREADSHEET_MODEL_TRUE@liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ auto_filter.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ check_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ check_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ config.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ debug_state_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ debug_state_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ document.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ document_impl.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ document_impl.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ document_types.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ dumper_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ dumper_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_pivot.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_pivot.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_shared_strings.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_shared_strings.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_sheet.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_sheet.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_styles.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_table.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_table.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ flat_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ flat_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ formula_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ formula_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ html_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ html_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ impl_types.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ csv_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ csv_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ json_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ json_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ number_format.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ number_format.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ pivot.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ shared_formula.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ shared_formula.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ shared_strings.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ sheet.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ sheet_impl.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ sheet_impl.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ styles.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ view.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ global_settings.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ global_settings.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBIXION_CFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LDFLAGS = -no-undefined
+@BUILD_SPREADSHEET_MODEL_TRUE@liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LIBADD = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(LIBIXION_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(BOOST_DATE_TIME_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ../liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_4) $(am__append_5)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/spreadsheet/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/spreadsheet/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la: $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_DEPENDENCIES) $(EXTRA_liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LINK) $(am_liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_rpath) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo: auto_filter.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo `test -f 'auto_filter.cpp' || echo '$(srcdir)/'`auto_filter.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='auto_filter.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo `test -f 'auto_filter.cpp' || echo '$(srcdir)/'`auto_filter.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo: check_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo `test -f 'check_dumper.cpp' || echo '$(srcdir)/'`check_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='check_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo `test -f 'check_dumper.cpp' || echo '$(srcdir)/'`check_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo: config.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo `test -f 'config.cpp' || echo '$(srcdir)/'`config.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo `test -f 'config.cpp' || echo '$(srcdir)/'`config.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo: debug_state_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo `test -f 'debug_state_dumper.cpp' || echo '$(srcdir)/'`debug_state_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='debug_state_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo `test -f 'debug_state_dumper.cpp' || echo '$(srcdir)/'`debug_state_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo: document.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo `test -f 'document.cpp' || echo '$(srcdir)/'`document.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='document.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo `test -f 'document.cpp' || echo '$(srcdir)/'`document.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo: document_impl.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo `test -f 'document_impl.cpp' || echo '$(srcdir)/'`document_impl.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='document_impl.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo `test -f 'document_impl.cpp' || echo '$(srcdir)/'`document_impl.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo: document_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo `test -f 'document_types.cpp' || echo '$(srcdir)/'`document_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='document_types.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo `test -f 'document_types.cpp' || echo '$(srcdir)/'`document_types.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo: dumper_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo `test -f 'dumper_global.cpp' || echo '$(srcdir)/'`dumper_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dumper_global.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo `test -f 'dumper_global.cpp' || echo '$(srcdir)/'`dumper_global.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo: factory.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo `test -f 'factory.cpp' || echo '$(srcdir)/'`factory.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo `test -f 'factory.cpp' || echo '$(srcdir)/'`factory.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo: factory_pivot.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo `test -f 'factory_pivot.cpp' || echo '$(srcdir)/'`factory_pivot.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory_pivot.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo `test -f 'factory_pivot.cpp' || echo '$(srcdir)/'`factory_pivot.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo: factory_shared_strings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo `test -f 'factory_shared_strings.cpp' || echo '$(srcdir)/'`factory_shared_strings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory_shared_strings.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo `test -f 'factory_shared_strings.cpp' || echo '$(srcdir)/'`factory_shared_strings.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo: factory_sheet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo `test -f 'factory_sheet.cpp' || echo '$(srcdir)/'`factory_sheet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory_sheet.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo `test -f 'factory_sheet.cpp' || echo '$(srcdir)/'`factory_sheet.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo: factory_styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo `test -f 'factory_styles.cpp' || echo '$(srcdir)/'`factory_styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory_styles.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo `test -f 'factory_styles.cpp' || echo '$(srcdir)/'`factory_styles.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo: factory_table.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo `test -f 'factory_table.cpp' || echo '$(srcdir)/'`factory_table.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory_table.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo `test -f 'factory_table.cpp' || echo '$(srcdir)/'`factory_table.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo: flat_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo `test -f 'flat_dumper.cpp' || echo '$(srcdir)/'`flat_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='flat_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo `test -f 'flat_dumper.cpp' || echo '$(srcdir)/'`flat_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo: formula_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo `test -f 'formula_global.cpp' || echo '$(srcdir)/'`formula_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='formula_global.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo `test -f 'formula_global.cpp' || echo '$(srcdir)/'`formula_global.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo: html_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo `test -f 'html_dumper.cpp' || echo '$(srcdir)/'`html_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='html_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo `test -f 'html_dumper.cpp' || echo '$(srcdir)/'`html_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo: csv_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo `test -f 'csv_dumper.cpp' || echo '$(srcdir)/'`csv_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csv_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo `test -f 'csv_dumper.cpp' || echo '$(srcdir)/'`csv_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo: json_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo `test -f 'json_dumper.cpp' || echo '$(srcdir)/'`json_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo `test -f 'json_dumper.cpp' || echo '$(srcdir)/'`json_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo: number_format.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo `test -f 'number_format.cpp' || echo '$(srcdir)/'`number_format.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='number_format.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo `test -f 'number_format.cpp' || echo '$(srcdir)/'`number_format.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo: pivot.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo `test -f 'pivot.cpp' || echo '$(srcdir)/'`pivot.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pivot.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo `test -f 'pivot.cpp' || echo '$(srcdir)/'`pivot.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo: shared_formula.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo `test -f 'shared_formula.cpp' || echo '$(srcdir)/'`shared_formula.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='shared_formula.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo `test -f 'shared_formula.cpp' || echo '$(srcdir)/'`shared_formula.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo: shared_strings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo `test -f 'shared_strings.cpp' || echo '$(srcdir)/'`shared_strings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='shared_strings.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo `test -f 'shared_strings.cpp' || echo '$(srcdir)/'`shared_strings.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo: sheet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo `test -f 'sheet.cpp' || echo '$(srcdir)/'`sheet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sheet.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo `test -f 'sheet.cpp' || echo '$(srcdir)/'`sheet.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo: sheet_impl.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo `test -f 'sheet_impl.cpp' || echo '$(srcdir)/'`sheet_impl.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sheet_impl.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo `test -f 'sheet_impl.cpp' || echo '$(srcdir)/'`sheet_impl.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo: styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo `test -f 'styles.cpp' || echo '$(srcdir)/'`styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='styles.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo `test -f 'styles.cpp' || echo '$(srcdir)/'`styles.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo: view.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo `test -f 'view.cpp' || echo '$(srcdir)/'`view.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='view.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo `test -f 'view.cpp' || echo '$(srcdir)/'`view.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo: global_settings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo `test -f 'global_settings.cpp' || echo '$(srcdir)/'`global_settings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='global_settings.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo `test -f 'global_settings.cpp' || echo '$(srcdir)/'`global_settings.cpp
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-am
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-am
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-am
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-am
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-am
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am am--depfiles check check-am check-valgrind-am \
+ check-valgrind-drd-am check-valgrind-drd-local \
+ check-valgrind-helgrind-am check-valgrind-helgrind-local \
+ check-valgrind-local check-valgrind-memcheck-am \
+ check-valgrind-memcheck-local check-valgrind-sgcheck-am \
+ check-valgrind-sgcheck-local clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/spreadsheet/auto_filter.cpp b/src/spreadsheet/auto_filter.cpp
new file mode 100644
index 0000000..3262305
--- /dev/null
+++ b/src/spreadsheet/auto_filter.cpp
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/spreadsheet/auto_filter.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+auto_filter_column_t::auto_filter_column_t() = default;
+auto_filter_column_t::auto_filter_column_t(const auto_filter_column_t& other) = default;
+auto_filter_column_t::auto_filter_column_t(auto_filter_column_t&& other) = default;
+auto_filter_column_t::~auto_filter_column_t() = default;
+
+auto_filter_column_t& auto_filter_column_t::operator=(const auto_filter_column_t& other) = default;
+auto_filter_column_t& auto_filter_column_t::operator=(auto_filter_column_t&& other) = default;
+
+void auto_filter_column_t::reset()
+{
+ match_values.clear();
+}
+
+void auto_filter_column_t::swap(auto_filter_column_t& r)
+{
+ match_values.swap(r.match_values);
+}
+
+auto_filter_t::auto_filter_t() : range(ixion::abs_range_t::invalid) {}
+auto_filter_t::auto_filter_t(const auto_filter_t& other) = default;
+auto_filter_t::auto_filter_t(auto_filter_t&& other) = default;
+auto_filter_t::~auto_filter_t() = default;
+
+auto_filter_t& auto_filter_t::operator=(const auto_filter_t& other) = default;
+auto_filter_t& auto_filter_t::operator=(auto_filter_t&& other) = default;
+
+void auto_filter_t::reset()
+{
+ range = ixion::abs_range_t(ixion::abs_range_t::invalid);
+ columns.clear();
+}
+
+void auto_filter_t::swap(auto_filter_t& r)
+{
+ std::swap(range, r.range);
+ columns.swap(r.columns);
+}
+
+void auto_filter_t::commit_column(col_t col, auto_filter_column_t data)
+{
+ if (col < 0)
+ // Invalid column index. Nothing happens.
+ return;
+
+ columns.insert_or_assign(col, std::move(data));
+}
+
+table_column_t::table_column_t() : identifier(0), totals_row_function(totals_row_function_t::none) {}
+
+table_column_t::table_column_t(const table_column_t& other) = default;
+table_column_t::~table_column_t() = default;
+
+table_column_t& table_column_t::operator=(const table_column_t& other) = default;
+
+void table_column_t::reset()
+{
+ identifier = 0;
+ name = std::string_view{};
+ totals_row_label = std::string_view{};
+ totals_row_function = totals_row_function_t::none;
+}
+
+table_style_t::table_style_t() :
+ show_first_column(false),
+ show_last_column(false),
+ show_row_stripes(false),
+ show_column_stripes(false) {}
+
+table_style_t::table_style_t(const table_style_t& other) = default;
+table_style_t::~table_style_t() = default;
+
+table_style_t& table_style_t::operator=(const table_style_t& other) = default;
+
+void table_style_t::reset()
+{
+ name = std::string_view{};
+ show_first_column = false;
+ show_last_column = false;
+ show_row_stripes = false;
+ show_column_stripes = false;
+}
+
+table_t::table_t() : identifier(0), range(ixion::abs_range_t::invalid), totals_row_count(0) {}
+table_t::table_t(const table_t& other) = default;
+table_t::table_t(table_t&& other) = default;
+table_t::~table_t() = default;
+
+table_t& table_t::operator=(const table_t& other) = default;
+table_t& table_t::operator=(table_t&& other) = default;
+
+void table_t::reset()
+{
+ identifier = 0;
+ name = std::string_view{};
+ display_name = std::string_view{};
+ range = ixion::abs_range_t(ixion::abs_range_t::invalid);
+ totals_row_count = 0;
+ filter.reset();
+ columns.clear();
+ style.reset();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/check_dumper.cpp b/src/spreadsheet/check_dumper.cpp
new file mode 100644
index 0000000..191b5a0
--- /dev/null
+++ b/src/spreadsheet/check_dumper.cpp
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "check_dumper.hpp"
+#include "sheet_impl.hpp"
+#include "number_format.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/model_context.hpp>
+#include <ixion/cell.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+
+#include <string>
+#include <algorithm>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+namespace {
+
+void write_cell_position(std::ostream& os, std::string_view sheet_name, row_t row, col_t col)
+{
+ os << sheet_name << '/' << row << '/' << col << ':';
+}
+
+std::string escape_chars(const std::string& str)
+{
+ if (str.empty())
+ return str;
+
+ std::string ret;
+ const char* p = &str[0];
+ const char* p_end = p + str.size();
+ for (; p != p_end; ++p)
+ {
+ if (*p == '"')
+ ret.push_back('\\');
+ ret.push_back(*p);
+ }
+ return ret;
+}
+
+}
+
+check_dumper::check_dumper(const detail::sheet_impl& sheet, std::string_view sheet_name) :
+ m_sheet(sheet), m_sheet_name(sheet_name)
+{
+}
+
+void check_dumper::dump(std::ostream& os) const
+{
+ dump_cell_values(os);
+ dump_merged_cell_info(os);
+}
+
+void check_dumper::dump_cell_values(std::ostream& os) const
+{
+ ixion::abs_range_t range = m_sheet.get_data_range();
+ if (!range.valid())
+ // Sheet is empty. Nothing to print.
+ return;
+
+ const ixion::model_context& cxt = m_sheet.doc.get_model_context();
+ const ixion::formula_name_resolver* resolver =
+ m_sheet.doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+
+ size_t row_count = range.last.row + 1;
+ size_t col_count = range.last.column + 1;
+
+ for (size_t row = 0; row < row_count; ++row)
+ {
+ for (size_t col = 0; col < col_count; ++col)
+ {
+ ixion::abs_address_t pos(m_sheet.sheet_id, row, col);
+ switch (cxt.get_celltype(pos))
+ {
+ case ixion::celltype_t::string:
+ {
+ write_cell_position(os, m_sheet_name, row, col);
+ size_t sindex = cxt.get_string_identifier(pos);
+ const std::string* p = cxt.get_string(sindex);
+ assert(p);
+ os << "string:\"" << escape_chars(*p) << '"' << std::endl;
+ break;
+ }
+ case ixion::celltype_t::numeric:
+ {
+ write_cell_position(os, m_sheet_name, row, col);
+ os << "numeric:";
+ detail::format_to_file_output(os, cxt.get_numeric_value(pos));
+ os << std::endl;
+ break;
+ }
+ case ixion::celltype_t::boolean:
+ {
+ write_cell_position(os, m_sheet_name, row, col);
+ os << "boolean:" << (cxt.get_boolean_value(pos) ? "true" : "false") << std::endl;
+ break;
+ }
+ case ixion::celltype_t::formula:
+ {
+ write_cell_position(os, m_sheet_name, row, col);
+ os << "formula";
+
+ // print the formula and the formula result.
+ const ixion::formula_cell* cell = cxt.get_formula_cell(pos);
+ assert(cell);
+ const ixion::formula_tokens_store_ptr_t& ts = cell->get_tokens();
+ if (ts)
+ {
+ const ixion::formula_tokens_t& tokens = ts->get();
+ std::string formula;
+ if (resolver)
+ {
+ pos = cell->get_parent_position(pos);
+ formula = ixion::print_formula_tokens(
+ m_sheet.doc.get_model_context(), pos, *resolver, tokens);
+ }
+ else
+ formula = "???";
+
+ os << ':';
+
+ ixion::formula_group_t fg = cell->get_group_properties();
+
+ if (fg.grouped)
+ os << '{' << formula << '}';
+ else
+ os << formula;
+
+ try
+ {
+ ixion::formula_result res = cell->get_result_cache(
+ ixion::formula_result_wait_policy_t::throw_exception);
+ os << ':' << res.str(m_sheet.doc.get_model_context());
+ }
+ catch (const std::exception&)
+ {
+ os << ":#RES!";
+ }
+ }
+
+ os << std::endl;
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ }
+}
+
+void check_dumper::dump_merged_cell_info(std::ostream& os) const
+{
+ // Sort by rows first then by columns.
+
+ struct _entry
+ {
+ row_t row;
+ col_t col;
+ const merge_size* ms;
+
+ _entry(row_t _row, col_t _col, const merge_size* _ms) :
+ row(_row), col(_col), ms(_ms) {}
+ };
+
+ std::vector<_entry> entries;
+
+ for (const auto& col_entry : m_sheet.merge_ranges)
+ {
+ col_t col = col_entry.first;
+
+ for (const auto& row_entry : *col_entry.second)
+ {
+ row_t row = row_entry.first;
+ const merge_size& ms = row_entry.second;
+
+ entries.emplace_back(row, col, &ms);
+ }
+ }
+
+ std::sort(entries.begin(), entries.end(),
+ [](const _entry& left, const _entry& right) -> bool
+ {
+ if (left.row != right.row)
+ return left.row < right.row;
+
+ if (left.col != right.col)
+ return left.col < right.col;
+
+ return left.ms < right.ms;
+ }
+ );
+
+ for (const _entry e : entries)
+ {
+ os << m_sheet_name << '/' << e.row << '/' << e.col << ":merge-width:" << e.ms->width << std::endl;
+ os << m_sheet_name << '/' << e.row << '/' << e.col << ":merge-height:" << e.ms->height << std::endl;
+ }
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/check_dumper.hpp b/src/spreadsheet/check_dumper.hpp
new file mode 100644
index 0000000..3a55a2c
--- /dev/null
+++ b/src/spreadsheet/check_dumper.hpp
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_CHECK_DUMPER_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_CHECK_DUMPER_HPP
+
+#include <ostream>
+#include <string_view>
+
+namespace orcus { namespace spreadsheet {
+
+namespace detail {
+
+struct sheet_impl;
+
+class check_dumper
+{
+ const sheet_impl& m_sheet;
+ std::string_view m_sheet_name;
+
+public:
+ check_dumper(const sheet_impl& sheet, std::string_view sheet_name);
+ void dump(std::ostream& os) const;
+
+private:
+ void dump_cell_values(std::ostream& os) const;
+ void dump_merged_cell_info(std::ostream& os) const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/config.cpp b/src/spreadsheet/config.cpp
new file mode 100644
index 0000000..45a7934
--- /dev/null
+++ b/src/spreadsheet/config.cpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/spreadsheet/config.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+document_config::document_config() :
+ output_precision(-1) {}
+
+document_config::document_config(const document_config& r) :
+ output_precision(r.output_precision) {}
+
+document_config::~document_config() {}
+
+document_config& document_config::operator= (const document_config& r)
+{
+ output_precision = r.output_precision;
+ return *this;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/csv_dumper.cpp b/src/spreadsheet/csv_dumper.cpp
new file mode 100644
index 0000000..5aa5a4e
--- /dev/null
+++ b/src/spreadsheet/csv_dumper.cpp
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "csv_dumper.hpp"
+#include "dumper_global.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/model_context.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+#include <mdds/multi_type_vector/collection.hpp>
+
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+namespace {
+
+void dump_string(std::ostream& os, const std::string& s)
+{
+ // Scan for any special characters that necessitate quoting.
+ bool outer_quotes = s.find_first_of(",\"") != std::string::npos;
+
+ if (outer_quotes)
+ os << '"';
+
+ for (const char c : s)
+ {
+ switch (c)
+ {
+ case '"':
+ {
+ os << c << c;
+ break;
+ }
+ default:
+ os << c;
+ }
+ }
+
+ if (outer_quotes)
+ os << '"';
+}
+
+void dump_empty(std::ostream& /*os*/)
+{
+ // Do nothing.
+}
+
+}
+
+csv_dumper::csv_dumper(const document& doc) :
+ m_doc(doc), m_sep(','), m_quote('"')
+{
+}
+
+void csv_dumper::dump(std::ostream& os, ixion::sheet_t sheet_id) const
+{
+ const ixion::model_context& cxt = m_doc.get_model_context();
+ ixion::abs_range_t data_range = cxt.get_data_range(sheet_id);
+ if (!data_range.valid())
+ return;
+
+ ixion::abs_rc_range_t iter_range;
+ iter_range.first.column = 0;
+ iter_range.first.row = 0;
+ iter_range.last.column = data_range.last.column;
+ iter_range.last.row = data_range.last.row;
+
+ auto iter = cxt.get_model_iterator(
+ sheet_id, ixion::rc_direction_t::horizontal, iter_range);
+
+ for (; iter.has(); iter.next())
+ {
+ const auto& cell = iter.get();
+
+ if (cell.col == 0 && cell.row > 0)
+ os << std::endl;
+
+ if (cell.col > 0)
+ os << m_sep;
+
+ dump_cell_value(os, cxt, cell, dump_string, dump_empty);
+ }
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/csv_dumper.hpp b/src/spreadsheet/csv_dumper.hpp
new file mode 100644
index 0000000..a03bbe9
--- /dev/null
+++ b/src/spreadsheet/csv_dumper.hpp
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_CSV_DUMPER_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_CSV_DUMPER_HPP
+
+#include <string>
+#include <ostream>
+#include <ixion/types.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+
+namespace detail {
+
+class csv_dumper
+{
+ const document& m_doc;
+ const char m_sep;
+ const char m_quote;
+
+public:
+ csv_dumper(const document& doc);
+
+ void dump(std::ostream& os, ixion::sheet_t sheet_id) const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/spreadsheet/debug_state_dumper.cpp b/src/spreadsheet/debug_state_dumper.cpp
new file mode 100644
index 0000000..c748924
--- /dev/null
+++ b/src/spreadsheet/debug_state_dumper.cpp
@@ -0,0 +1,460 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "debug_state_dumper.hpp"
+#include "check_dumper.hpp"
+#include "document_impl.hpp"
+#include "sheet_impl.hpp"
+#include "ostream_utils.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/named_expressions_iterator.hpp>
+
+#include <fstream>
+#include <algorithm>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+namespace {
+
+void print_named_expressions(const ixion::model_context& cxt, ixion::named_expressions_iterator iter, std::ostream& os)
+{
+ auto resolver = ixion::formula_name_resolver::get(ixion::formula_name_resolver_t::excel_a1, &cxt);
+
+ if (!resolver)
+ return;
+
+ const ixion::abs_address_t origin{0, 0, 0};
+ ixion::print_config config;
+ config.display_sheet = ixion::display_sheet_t::always;
+
+ for (; iter.has(); iter.next())
+ {
+ auto name = iter.get();
+
+ std::string exp = ixion::print_formula_tokens(
+ config, cxt, origin, *resolver, name.expression->tokens);
+
+ os << "- name: " << *name.name << std::endl;
+ os << " origin: " << resolver->get_name(name.expression->origin, origin, true) << std::endl;
+ os << " expression: " << exp << std::endl;
+ }
+}
+
+} // anonymous namespace
+
+doc_debug_state_dumper::doc_debug_state_dumper(const document_impl& doc) : m_doc(doc)
+{
+}
+
+void doc_debug_state_dumper::dump(const fs::path& outdir) const
+{
+ dump_properties(outdir);
+ dump_styles(outdir);
+ dump_named_expressions(outdir);
+}
+
+void doc_debug_state_dumper::dump_properties(const fs::path& outdir) const
+{
+ const fs::path outpath = outdir / "properties.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ of << "formula-grammar: " << m_doc.grammar << std::endl;
+ of << "origin-date: " << m_doc.origin_date << std::endl;
+ of << "output-precision: " << short(m_doc.doc_config.output_precision) << std::endl;
+}
+
+void doc_debug_state_dumper::dump_styles(const fs::path& outdir) const
+{
+ const fs::path outpath = outdir / "styles.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ of << std::boolalpha;
+
+ auto to_string = [](std::optional<bool> v) -> std::string
+ {
+ if (!v)
+ return "(unset)";
+
+ return *v ? "true" : "false";
+ };
+
+ auto dump_xf = [&of,to_string](std::size_t i, const cell_format_t& xf)
+ {
+ of << " - id: " << i << std::endl
+ << " font: " << xf.font << std::endl
+ << " fill: " << xf.fill << std::endl
+ << " border: " << xf.border << std::endl
+ << " protection: " << xf.protection << std::endl
+ << " number-format: " << xf.number_format << std::endl
+ << " style-xf: " << xf.style_xf << std::endl
+ << " horizontal-alignment: " << xf.hor_align << std::endl
+ << " vertical-alignment: " << xf.ver_align << std::endl
+ << " apply-number-format: " << xf.apply_num_format << std::endl
+ << " apply-font: " << xf.apply_font << std::endl
+ << " apply-fill: " << xf.apply_fill << std::endl
+ << " apply-border: " << xf.apply_border << std::endl
+ << " apply-alignment: " << xf.apply_alignment << std::endl
+ << " apply-protection: " << xf.apply_protection << std::endl
+ << " wrap-text: " << to_string(xf.wrap_text) << std::endl
+ << " shrink-to-fit: " << to_string(xf.shrink_to_fit) << std::endl;
+ };
+
+ auto optional_value = [&of](std::string_view name, const auto& v, int level=2)
+ {
+ // v is of type std::optional<T>.
+
+ constexpr char q = '"';
+ constexpr const char* indent_unit_s = " ";
+
+ std::string indent = indent_unit_s;
+ for (int i = 0; i < level - 1; ++i)
+ indent += indent_unit_s;
+
+ of << indent << name << ": ";
+
+ if (v)
+ {
+ std::ostringstream os;
+ os << *v;
+ std::string s = os.str();
+ bool quote = s.find_first_of("#:-") != s.npos;
+ if (quote)
+ of << q << s << q;
+ else
+ of << s;
+ }
+ else
+ of << "(unset)";
+
+ of << std::endl;
+ };
+
+ auto dump_border = [&optional_value](const border_attrs_t& _attrs)
+ {
+ optional_value("style", _attrs.style, 3);
+ optional_value("color", _attrs.border_color, 3);
+ optional_value("width", _attrs.border_width, 3);
+ };
+
+ of << "cell-styles:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_cell_styles_count(); ++i)
+ {
+ const cell_style_t* cs = m_doc.styles_store.get_cell_style(i);
+ assert(cs);
+
+ of << " - id: " << i << std::endl
+ << " name: " << cs->name << std::endl
+ << " display-name: " << cs->display_name << std::endl
+ << " parent: " << cs->parent_name << std::endl
+ << " xf: " << cs->xf << std::endl
+ << " builtin: " << cs->builtin << std::endl;
+ }
+
+ of << "cell-style-formats:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_cell_style_formats_count(); ++i)
+ {
+ const cell_format_t* xf = m_doc.styles_store.get_cell_style_format(i);
+ assert(xf);
+ dump_xf(i, *xf);
+ }
+
+ of << "cell-formats:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_cell_formats_count(); ++i)
+ {
+ const cell_format_t* xf = m_doc.styles_store.get_cell_format(i);
+ assert(xf);
+ dump_xf(i, *xf);
+ }
+
+ of << "fonts:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_font_count(); ++i)
+ {
+ const font_t* font = m_doc.styles_store.get_font(i);
+ assert(font);
+
+ of << " - id: " << i << std::endl;
+ optional_value("name", font->name, 2);
+ optional_value("name-asian", font->name_asian, 2);
+ optional_value("name-complex", font->name_complex, 2);
+ optional_value("size", font->size, 2);
+ optional_value("size-asian", font->size_asian, 2);
+ optional_value("size-complex", font->size_complex, 2);
+ optional_value("bold", font->bold, 2);
+ optional_value("bold-asian", font->bold_asian, 2);
+ optional_value("bold-complex", font->bold_complex, 2);
+ optional_value("italic", font->italic, 2);
+ optional_value("italic-asian", font->italic_asian, 2);
+ optional_value("italic-complex", font->italic_complex, 2);
+ optional_value("underline-style", font->underline_style, 2);
+ optional_value("underline-width", font->underline_width, 2);
+ optional_value("underline-mode", font->underline_mode, 2);
+ optional_value("underline-type", font->underline_type, 2);
+ optional_value("underline-color", font->underline_color, 2);
+ optional_value("color", font->color, 2);
+ optional_value("strikethrough-style", font->strikethrough_style, 2);
+ optional_value("strikethrough-width", font->strikethrough_width, 2);
+ optional_value("strikethrough-type", font->strikethrough_type, 2);
+ optional_value("strikethrough-text", font->strikethrough_text, 2);
+ }
+
+ of << "fills:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_fill_count(); ++i)
+ {
+ const fill_t* fill = m_doc.styles_store.get_fill(i);
+ assert(fill);
+
+ of << " - id: " << i << std::endl;
+ optional_value("pattern", fill->pattern_type, 2);
+ optional_value("fg-color", fill->fg_color, 2);
+ optional_value("bg-color", fill->bg_color, 2);
+ }
+
+ of << "borders:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_border_count(); ++i)
+ {
+ const border_t* border = m_doc.styles_store.get_border(i);
+ assert(border);
+
+ of << " - id: " << i << std::endl;
+
+ of << " top:" << std::endl;
+ dump_border(border->top);
+ of << " bottom:" << std::endl;
+ dump_border(border->bottom);
+ of << " left:" << std::endl;
+ dump_border(border->left);
+ of << " right:" << std::endl;
+ dump_border(border->right);
+ of << " diagonal:" << std::endl;
+ dump_border(border->diagonal);
+ of << " diagonal-bl-tr:" << std::endl;
+ dump_border(border->diagonal_bl_tr);
+ of << " diagonal-tl-br:" << std::endl;
+ dump_border(border->diagonal_tl_br);
+ }
+
+ of << "protections:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_protection_count(); ++i)
+ {
+ const protection_t* prot = m_doc.styles_store.get_protection(i);
+ assert(prot);
+
+ of << " - id: " << i << std::endl;
+ optional_value("locked", prot->locked, 2);
+ optional_value("hidden", prot->hidden, 2);
+ optional_value("print-content", prot->print_content, 2);
+ optional_value("formula-hidden", prot->formula_hidden, 2);
+ }
+
+ of << "number-formats:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_number_format_count(); ++i)
+ {
+ const number_format_t* numfmt = m_doc.styles_store.get_number_format(i);
+ assert(numfmt);
+
+ of << " - id: " << i << std::endl;
+ optional_value("identifier", numfmt->identifier, 2);
+ optional_value("format-string", numfmt->format_string, 2);
+ }
+}
+
+void doc_debug_state_dumper::dump_named_expressions(const fs::path& outdir) const
+{
+ const fs::path outpath = outdir / "named-expressions.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ print_named_expressions(m_doc.context, m_doc.context.get_named_expressions_iterator(), of);
+}
+
+sheet_debug_state_dumper::sheet_debug_state_dumper(const sheet_impl& sheet, std::string_view sheet_name) :
+ m_sheet(sheet), m_sheet_name(sheet_name) {}
+
+void sheet_debug_state_dumper::dump(const fs::path& outdir) const
+{
+ dump_cell_values(outdir);
+ dump_cell_formats(outdir);
+ dump_column_formats(outdir);
+ dump_row_formats(outdir);
+ dump_column_widths(outdir);
+ dump_row_heights(outdir);
+ dump_auto_filter(outdir);
+ dump_named_expressions(outdir);
+}
+
+void sheet_debug_state_dumper::dump_cell_values(const fs::path& outdir) const
+{
+ check_dumper dumper{m_sheet, m_sheet_name};
+ fs::path outpath = outdir / "cell-values.txt";
+ std::ofstream of{outpath.native()};
+ if (of)
+ dumper.dump(of);
+}
+
+void sheet_debug_state_dumper::dump_cell_formats(const fs::path& outdir) const
+{
+ fs::path outpath = outdir / "cell-formats.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ std::vector<col_t> columns;
+ for (const auto& node : m_sheet.cell_formats)
+ columns.push_back(node.first);
+
+ std::sort(columns.begin(), columns.end());
+
+ for (const col_t col : columns)
+ {
+ of << "column: " << col << std::endl;
+
+ auto it = m_sheet.cell_formats.find(col);
+ assert(it != m_sheet.cell_formats.end());
+ const segment_row_index_type& rows = *it->second;
+
+ for (const auto& seg : rows.segment_range())
+ {
+ // NB: end position is not inclusive.
+ of << " - rows: " << seg.start << '-' << (seg.end - 1) << std::endl;
+ of << " xf: " << seg.value << std::endl;
+ }
+ }
+}
+
+void sheet_debug_state_dumper::dump_column_formats(const fs::path& outdir) const
+{
+ fs::path outpath = outdir / "column-formats.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ for (const auto& seg : m_sheet.column_formats.segment_range())
+ {
+ of << "- columns: " << seg.start << '-' << (seg.end - 1) << std::endl;
+ of << " xf: " << seg.value << std::endl;
+ }
+}
+
+void sheet_debug_state_dumper::dump_row_formats(const fs::path& outdir) const
+{
+ fs::path outpath = outdir / "row-formats.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ for (const auto& seg : m_sheet.row_formats.segment_range())
+ {
+ of << "- rows: " << seg.start << '-' << (seg.end - 1) << std::endl;
+ of << " xf: " << seg.value << std::endl;
+ }
+}
+
+void sheet_debug_state_dumper::dump_column_widths(const fs::path& outdir) const
+{
+ fs::path outpath = outdir / "column-widths.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ for (const auto& seg : m_sheet.col_widths.segment_range())
+ {
+ of << "- columns: " << seg.start << '-' << (seg.end - 1) << std::endl;
+ of << " width: ";
+
+ if (seg.value == get_default_column_width())
+ of << "(default)";
+ else
+ of << seg.value;
+
+ of << std::endl;
+ }
+}
+
+void sheet_debug_state_dumper::dump_row_heights(const fs::path& outdir) const
+{
+ fs::path outpath = outdir / "row-heights.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ for (const auto& seg : m_sheet.row_heights.segment_range())
+ {
+ of << "- rows: " << seg.start << '-' << (seg.end - 1) << std::endl;
+ of << " height: ";
+
+ if (seg.value == get_default_row_height())
+ of << "(default)";
+ else
+ of << seg.value;
+
+ of << std::endl;
+ }
+}
+
+void sheet_debug_state_dumper::dump_auto_filter(const fs::path& outdir) const
+{
+ if (!m_sheet.auto_filter_data)
+ return;
+
+ fs::path outpath = outdir / "auto-filter.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ const auto_filter_t& data = *m_sheet.auto_filter_data;
+
+ auto resolver = ixion::formula_name_resolver::get(
+ ixion::formula_name_resolver_t::excel_a1, nullptr);
+
+ if (!resolver)
+ return;
+
+ ixion::abs_address_t origin;
+ ixion::range_t name{data.range};
+ name.set_absolute(false);
+
+ of << "range: " << resolver->get_name(name, origin, false) << "\n";
+ of << "columns:\n";
+
+ for (const auto& [col, cdata] : data.columns)
+ {
+ of << "- column: " << col << "\n";
+ of << " match-values:\n";
+
+ for (const auto& v : cdata.match_values)
+ of << " - " << v << std::endl;
+ }
+}
+
+void sheet_debug_state_dumper::dump_named_expressions(const fs::path& outdir) const
+{
+ const fs::path outpath = outdir / "named-expressions.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ const ixion::model_context& cxt = m_sheet.doc.get_model_context();
+ print_named_expressions(cxt, cxt.get_named_expressions_iterator(m_sheet.sheet_id), of);
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/debug_state_dumper.hpp b/src/spreadsheet/debug_state_dumper.hpp
new file mode 100644
index 0000000..7e895ca
--- /dev/null
+++ b/src/spreadsheet/debug_state_dumper.hpp
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "filesystem_env.hpp"
+
+#include <string_view>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+
+namespace detail {
+
+struct document_impl;
+struct sheet_impl;
+
+class doc_debug_state_dumper
+{
+ const document_impl& m_doc;
+
+public:
+ doc_debug_state_dumper(const document_impl& doc);
+
+ void dump(const fs::path& outdir) const;
+
+private:
+ void dump_properties(const fs::path& outdir) const;
+ void dump_styles(const fs::path& outdir) const;
+ void dump_named_expressions(const fs::path& outdir) const;
+};
+
+class sheet_debug_state_dumper
+{
+ const sheet_impl& m_sheet;
+ std::string_view m_sheet_name;
+
+public:
+ sheet_debug_state_dumper(const sheet_impl& sheet, std::string_view sheet_name);
+
+ void dump(const fs::path& outdir) const;
+
+private:
+ void dump_cell_values(const fs::path& outdir) const;
+ void dump_cell_formats(const fs::path& outdir) const;
+ void dump_column_formats(const fs::path& outdir) const;
+ void dump_row_formats(const fs::path& outdir) const;
+ void dump_column_widths(const fs::path& outdir) const;
+ void dump_row_heights(const fs::path& outdir) const;
+ void dump_auto_filter(const fs::path& outdir) const;
+ void dump_named_expressions(const fs::path& outdir) const;
+};
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/document.cpp b/src/spreadsheet/document.cpp
new file mode 100644
index 0000000..dc8daec
--- /dev/null
+++ b/src/spreadsheet/document.cpp
@@ -0,0 +1,526 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "document_impl.hpp"
+#include "debug_state_dumper.hpp"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <map>
+#include <algorithm>
+
+using namespace std;
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+class find_sheet_by_name
+{
+ std::string_view m_name;
+public:
+ find_sheet_by_name(std::string_view name) : m_name(name) {}
+ bool operator() (const std::unique_ptr<detail::sheet_item>& v) const
+ {
+ return v->name == m_name;
+ }
+};
+
+}
+
+document::document(const range_size_t& sheet_size) : mp_impl(std::make_unique<detail::document_impl>(*this, sheet_size)) {}
+
+document::~document() {}
+
+shared_strings& document::get_shared_strings()
+{
+ return mp_impl->ss_store;
+}
+
+const shared_strings& document::get_shared_strings() const
+{
+ return mp_impl->ss_store;
+}
+
+styles& document::get_styles()
+{
+ return mp_impl->styles_store;
+}
+
+const styles& document::get_styles() const
+{
+ return mp_impl->styles_store;
+}
+
+pivot_collection& document::get_pivot_collection()
+{
+ return mp_impl->pivots;
+}
+
+const pivot_collection& document::get_pivot_collection() const
+{
+ return mp_impl->pivots;
+}
+
+ixion::model_context& document::get_model_context()
+{
+ return mp_impl->context;
+}
+
+const ixion::model_context& document::get_model_context() const
+{
+ return mp_impl->context;
+}
+
+const document_config& document::get_config() const
+{
+ return mp_impl->doc_config;
+}
+
+void document::set_config(const document_config& cfg)
+{
+ mp_impl->doc_config = cfg;
+ ixion::config ixion_cfg = mp_impl->context.get_config();
+ ixion_cfg.output_precision = cfg.output_precision;
+ mp_impl->context.set_config(ixion_cfg);
+}
+
+string_pool& document::get_string_pool()
+{
+ return mp_impl->string_pool_store;
+}
+
+const string_pool& document::get_string_pool() const
+{
+ return mp_impl->string_pool_store;
+}
+
+void document::insert_table(table_t* p)
+{
+ if (!p)
+ return;
+
+ std::string_view name = p->name;
+ mp_impl->tables.emplace(name, std::unique_ptr<table_t>(p));
+}
+
+const table_t* document::get_table(std::string_view name) const
+{
+ auto it = mp_impl->tables.find(name);
+ return it == mp_impl->tables.end() ? nullptr : it->second.get();
+}
+
+void document::finalize_import()
+{
+ std::for_each(mp_impl->sheets.begin(), mp_impl->sheets.end(),
+ [](std::unique_ptr<detail::sheet_item>& sh)
+ {
+ sh->data.finalize_import();
+ }
+ );
+
+ mp_impl->styles_store.finalize_import();
+}
+
+sheet* document::append_sheet(std::string_view sheet_name)
+{
+ std::string_view sheet_name_safe = mp_impl->string_pool_store.intern(sheet_name).first;
+ sheet_t sheet_index = static_cast<sheet_t>(mp_impl->sheets.size());
+
+ mp_impl->sheets.push_back(
+ std::make_unique<detail::sheet_item>(*this, sheet_name_safe, sheet_index));
+
+ mp_impl->context.append_sheet(std::string{sheet_name_safe});
+
+ return &mp_impl->sheets.back()->data;
+}
+
+sheet* document::get_sheet(std::string_view sheet_name)
+{
+ const sheet* sh = const_cast<const document*>(this)->get_sheet(sheet_name);
+ return const_cast<sheet*>(sh);
+}
+
+const sheet* document::get_sheet(std::string_view sheet_name) const
+{
+ auto it = std::find_if(
+ mp_impl->sheets.begin(), mp_impl->sheets.end(), find_sheet_by_name(sheet_name));
+
+ if (it == mp_impl->sheets.end())
+ return nullptr;
+
+ return &(*it)->data;
+}
+
+sheet* document::get_sheet(sheet_t sheet_pos)
+{
+ const sheet* sh = const_cast<const document*>(this)->get_sheet(sheet_pos);
+ return const_cast<sheet*>(sh);
+}
+
+const sheet* document::get_sheet(sheet_t sheet_pos) const
+{
+ if (static_cast<size_t>(sheet_pos) >= mp_impl->sheets.size())
+ return nullptr;
+
+ return &mp_impl->sheets[sheet_pos]->data;
+}
+
+void document::recalc_formula_cells()
+{
+ ixion::abs_range_set_t empty;
+
+ ixion::model_context& cxt = get_model_context();
+ std::vector<ixion::abs_range_t> sorted = ixion::query_and_sort_dirty_cells(
+ cxt, empty, &mp_impl->dirty_cells);
+ ixion::calculate_sorted_cells(cxt, sorted, 0);
+}
+
+void document::clear()
+{
+ mp_impl = std::make_unique<detail::document_impl>(*this, get_sheet_size());
+}
+
+void document::dump(dump_format_t format, const std::string& output) const
+{
+ if (format == dump_format_t::none)
+ return;
+
+ if (format == dump_format_t::check)
+ {
+ // For this output, we write to a single file.
+ std::ostream* ostrm = &std::cout;
+ std::unique_ptr<std::ofstream> fs;
+
+ if (!output.empty())
+ {
+ if (fs::is_directory(output))
+ {
+ std::ostringstream os;
+ os << "Output file path points to an existing directory.";
+ throw std::invalid_argument(os.str());
+ }
+
+ // Output to stdout when output path is not given.
+ fs = std::make_unique<std::ofstream>(output.data());
+ ostrm = fs.get();
+ }
+
+ dump_check(*ostrm);
+ return;
+ }
+
+ if (output.empty())
+ throw std::invalid_argument("No output directory.");
+
+ if (fs::exists(output))
+ {
+ if (!fs::is_directory(output))
+ {
+ std::ostringstream os;
+ os << "A file named '" << output << "' already exists, and is not a directory.";
+ throw std::invalid_argument(os.str());
+ }
+ }
+ else
+ fs::create_directory(output);
+
+ switch (format)
+ {
+ case dump_format_t::csv:
+ dump_csv(output);
+ break;
+ case dump_format_t::flat:
+ dump_flat(output);
+ break;
+ case dump_format_t::html:
+ dump_html(output);
+ break;
+ case dump_format_t::json:
+ dump_json(output);
+ break;
+ case dump_format_t::debug_state:
+ dump_debug_state(output);
+ break;
+ // coverity[dead_error_line] - following conditions exist to avoid compiler warning
+ case dump_format_t::none:
+ case dump_format_t::unknown:
+ break;
+ default:
+ ;
+ }
+}
+
+void document::dump_check(ostream& os) const
+{
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ sheet->data.dump_check(os, sheet->name);
+}
+
+void document::dump_flat(const string& outdir) const
+{
+ cout << "----------------------------------------------------------------------" << endl;
+ cout << " Document content summary" << endl;
+ cout << "----------------------------------------------------------------------" << endl;
+ mp_impl->ss_store.dump(cout);
+
+ cout << "number of sheets: " << mp_impl->sheets.size() << endl;
+
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ {
+ fs::path outpath{outdir};
+ outpath /= std::string{sheet->name};
+ outpath.replace_extension(".txt");
+
+ std::ofstream file(outpath.native());
+ if (!file)
+ {
+ cerr << "failed to create file: " << outpath << endl;
+ return;
+ }
+
+ file << "---" << endl;
+ file << "Sheet name: " << sheet->name << endl;
+ sheet->data.dump_flat(file);
+ }
+}
+
+void document::dump_html(const string& outdir) const
+{
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ {
+ fs::path outpath{outdir};
+ outpath /= std::string{sheet->name};
+ outpath.replace_extension(".html");
+
+ std::ofstream file(outpath.native());
+ if (!file)
+ {
+ cerr << "failed to create file: " << outpath << endl;
+ return;
+ }
+
+ sheet->data.dump_html(file);
+ }
+}
+
+void document::dump_json(const string& outdir) const
+{
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ {
+ fs::path outpath{outdir};
+ outpath /= std::string{sheet->name};
+ outpath.replace_extension(".json");
+
+ std::ofstream file(outpath.native());
+ if (!file)
+ {
+ cerr << "failed to create file: " << outpath << endl;
+ return;
+ }
+
+ sheet->data.dump_json(file);
+ }
+}
+
+void document::dump_csv(const std::string& outdir) const
+{
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ {
+ fs::path outpath{outdir};
+ outpath /= std::string{sheet->name};
+ outpath.replace_extension(".csv");
+
+ ofstream file(outpath.c_str());
+ if (!file)
+ {
+ cerr << "failed to create file: " << outpath << endl;
+ return;
+ }
+
+ sheet->data.dump_csv(file);
+ }
+}
+
+void document::dump_debug_state(const std::string& outdir) const
+{
+ detail::doc_debug_state_dumper dumper{*mp_impl};
+ fs::path output_dir{outdir};
+ dumper.dump(output_dir);
+
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ {
+ fs::path outpath = output_dir;
+ outpath /= std::string{sheet->name};
+ fs::create_directories(outpath);
+ sheet->data.dump_debug_state(outpath.string(), sheet->name);
+ }
+}
+
+sheet_t document::get_sheet_index(std::string_view name) const
+{
+ auto it = std::find_if(
+ mp_impl->sheets.begin(), mp_impl->sheets.end(), find_sheet_by_name(name));
+
+ if (it == mp_impl->sheets.end())
+ return ixion::invalid_sheet;
+
+ auto it_beg = mp_impl->sheets.begin();
+ size_t pos = std::distance(it_beg, it);
+ return static_cast<sheet_t>(pos);
+}
+
+std::string_view document::get_sheet_name(sheet_t sheet_pos) const
+{
+ if (sheet_pos < 0)
+ return std::string_view{};
+
+ size_t pos = static_cast<size_t>(sheet_pos);
+ if (pos >= mp_impl->sheets.size())
+ return std::string_view{};
+
+ return mp_impl->sheets[pos]->name;
+}
+
+void document::set_sheet_name(sheet_t sheet_pos, std::string name)
+{
+ assert(mp_impl->sheets.size() == mp_impl->context.get_sheet_count());
+
+ std::string_view name_interned = mp_impl->string_pool_store.intern(name).first;
+ mp_impl->context.set_sheet_name(sheet_pos, std::move(name)); // will throw on invalid name or position
+ mp_impl->sheets[sheet_pos]->name = name_interned;
+}
+
+range_size_t document::get_sheet_size() const
+{
+ ixion::rc_size_t ss = mp_impl->context.get_sheet_size();
+ range_size_t ret;
+ ret.rows = ss.row;
+ ret.columns = ss.column;
+ return ret;
+}
+
+void document::set_sheet_size(const range_size_t& sheet_size)
+{
+ mp_impl->context.set_sheet_size({sheet_size.rows, sheet_size.columns});
+}
+
+size_t document::get_sheet_count() const
+{
+ return mp_impl->sheets.size();
+}
+
+void document::set_origin_date(int year, int month, int day)
+{
+ mp_impl->origin_date.year = year;
+ mp_impl->origin_date.month = month;
+ mp_impl->origin_date.day = day;
+}
+
+date_time_t document::get_origin_date() const
+{
+ return mp_impl->origin_date;
+}
+
+void document::set_formula_grammar(formula_grammar_t grammar)
+{
+ if (mp_impl->grammar == grammar)
+ return;
+
+ mp_impl->grammar = grammar;
+
+ ixion::formula_name_resolver_t resolver_type_global = ixion::formula_name_resolver_t::unknown;
+ ixion::formula_name_resolver_t resolver_type_named_exp_base = ixion::formula_name_resolver_t::unknown;
+ ixion::formula_name_resolver_t resolver_type_named_range = ixion::formula_name_resolver_t::unknown;
+ char arg_sep = 0;
+
+ switch (mp_impl->grammar)
+ {
+ case formula_grammar_t::xls_xml:
+ resolver_type_global = ixion::formula_name_resolver_t::excel_r1c1;
+ arg_sep = ',';
+ break;
+ case formula_grammar_t::xlsx:
+ resolver_type_global = ixion::formula_name_resolver_t::excel_a1;
+ arg_sep = ',';
+ break;
+ case formula_grammar_t::ods:
+ resolver_type_global = ixion::formula_name_resolver_t::odff;
+ resolver_type_named_exp_base = ixion::formula_name_resolver_t::calc_a1;
+ resolver_type_named_range = ixion::formula_name_resolver_t::odf_cra;
+ arg_sep = ';';
+ break;
+ case formula_grammar_t::gnumeric:
+ // TODO : Use Excel A1 name resolver for now.
+ resolver_type_global = ixion::formula_name_resolver_t::excel_a1;
+ arg_sep = ',';
+ break;
+ default:
+ ;
+ }
+
+ mp_impl->name_resolver_global.reset();
+ mp_impl->name_resolver_named_exp_base.reset();
+
+ if (resolver_type_global != ixion::formula_name_resolver_t::unknown)
+ {
+ mp_impl->name_resolver_global =
+ ixion::formula_name_resolver::get(resolver_type_global, &mp_impl->context);
+
+ if (resolver_type_named_exp_base != ixion::formula_name_resolver_t::unknown)
+ {
+ mp_impl->name_resolver_named_exp_base =
+ ixion::formula_name_resolver::get(resolver_type_named_exp_base, &mp_impl->context);
+ }
+
+ if (resolver_type_named_range != ixion::formula_name_resolver_t::unknown)
+ {
+ mp_impl->name_resolver_named_range =
+ ixion::formula_name_resolver::get(resolver_type_named_range, &mp_impl->context);
+ }
+
+ ixion::config cfg = mp_impl->context.get_config();
+ cfg.sep_function_arg = arg_sep;
+ cfg.output_precision = mp_impl->doc_config.output_precision;
+ mp_impl->context.set_config(cfg);
+ }
+}
+
+formula_grammar_t document::get_formula_grammar() const
+{
+ return mp_impl->grammar;
+}
+
+const ixion::formula_name_resolver* document::get_formula_name_resolver(formula_ref_context_t cxt) const
+{
+ switch (cxt)
+ {
+ case formula_ref_context_t::global:
+ return mp_impl->name_resolver_global.get();
+ case formula_ref_context_t::named_expression_base:
+ if (mp_impl->name_resolver_named_exp_base)
+ return mp_impl->name_resolver_named_exp_base.get();
+ break;
+ case formula_ref_context_t::named_range:
+ if (mp_impl->name_resolver_named_range)
+ return mp_impl->name_resolver_named_range.get();
+ break;
+ default:
+ ;
+ }
+
+ return mp_impl->name_resolver_global.get();
+}
+
+void document::insert_dirty_cell(const ixion::abs_address_t& pos)
+{
+ mp_impl->dirty_cells.insert(pos);
+}
+
+}}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/document_impl.cpp b/src/spreadsheet/document_impl.cpp
new file mode 100644
index 0000000..db6050a
--- /dev/null
+++ b/src/spreadsheet/document_impl.cpp
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "document_impl.hpp"
+
+#include <algorithm>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+namespace {
+
+class find_column_by_name
+{
+ std::string_view m_name;
+public:
+ find_column_by_name(std::string_view name) : m_name(name) {}
+
+ bool operator() (const table_column_t& col) const
+ {
+ return col.name == m_name;
+ }
+};
+
+void adjust_row_range(ixion::abs_range_t& range, const table_t& tab, ixion::table_areas_t areas)
+{
+ bool headers = (areas & ixion::table_area_headers);
+ bool data = (areas & ixion::table_area_data);
+ bool totals = (areas & ixion::table_area_totals);
+
+ if (headers)
+ {
+ if (data)
+ {
+ if (totals)
+ {
+ // All areas.
+ return;
+ }
+
+ // Headers + data
+ range.last.row -= tab.totals_row_count;
+ return;
+ }
+
+ if (totals)
+ {
+ // Header + total is invalid.
+ range = ixion::abs_range_t(ixion::abs_range_t::invalid);
+ return;
+ }
+
+ // Headers only.
+ range.last.row = range.first.row;
+ return;
+ }
+
+ if (data)
+ {
+ ++range.first.row;
+
+ if (totals)
+ {
+ // Data + total
+ return;
+ }
+
+ // Data only
+ range.last.row -= tab.totals_row_count;
+ return;
+ }
+
+ if (totals)
+ {
+ // Total only
+ if (!tab.totals_row_count)
+ {
+ // This table has not total rows. Return empty range.
+ range = ixion::abs_range_t();
+ return;
+ }
+
+ range.first.row = range.last.row - tab.totals_row_count - 1;
+ return;
+ }
+
+ // Empty range.
+ range = ixion::abs_range_t();
+}
+
+}
+
+sheet_item::sheet_item(document& doc, std::string_view _name, sheet_t sheet_index) :
+ name(_name), data(doc, sheet_index) {}
+
+
+const table_t* ixion_table_handler::find_table(const ixion::abs_address_t& pos) const
+{
+ auto it = m_tables.begin(), it_end = m_tables.end();
+ for (; it != it_end; ++it)
+ {
+ const table_t* p = it->second.get();
+ if (p->range.contains(pos))
+ return p;
+ }
+
+ return nullptr;
+}
+
+std::string_view ixion_table_handler::get_string(ixion::string_id_t sid) const
+{
+ if (sid == ixion::empty_string_id)
+ return std::string_view{};
+
+ const std::string* p = m_context.get_string(sid);
+ if (!p || p->empty())
+ return std::string_view{};
+
+ return std::string_view(p->data(), p->size());
+}
+
+col_t ixion_table_handler::find_column(const table_t& tab, std::string_view name, size_t offset) const
+{
+ if (offset >= tab.columns.size())
+ return -1;
+
+ table_t::columns_type::const_iterator it_beg = tab.columns.begin();
+ table_t::columns_type::const_iterator it_end = tab.columns.end();
+
+ std::advance(it_beg, offset);
+ table_t::columns_type::const_iterator it =
+ std::find_if(it_beg, it_end, find_column_by_name(name));
+
+ if (it == it_end)
+ // not found.
+ return -1;
+
+ size_t dist = std::distance(tab.columns.begin(), it);
+ return tab.range.first.column + dist;
+}
+
+ixion::abs_range_t ixion_table_handler::get_range_from_table(
+ const table_t& tab, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const
+{
+ if (column_first != ixion::empty_string_id)
+ {
+ std::string_view col1_name = get_string(column_first);
+ if (col1_name.empty())
+ return ixion::abs_range_t(ixion::abs_range_t::invalid);
+
+ col_t col1_index = find_column(tab, col1_name, 0);
+ if (col1_index < 0)
+ return ixion::abs_range_t(ixion::abs_range_t::invalid);
+
+ if (column_last != ixion::empty_string_id)
+ {
+ std::string_view col2_name = get_string(column_last);
+ if (!col2_name.empty())
+ {
+ // column range table reference.
+ col_t col2_index = find_column(tab, col2_name, col1_index);
+ ixion::abs_range_t range = tab.range;
+ range.first.column = col1_index;
+ range.last.column = col2_index;
+ adjust_row_range(range, tab, areas);
+ return range;
+ }
+ }
+
+ // single column table reference.
+ ixion::abs_range_t range = tab.range;
+ range.first.column = range.last.column = col1_index;
+ adjust_row_range(range, tab, areas);
+ return range;
+ }
+
+ return ixion::abs_range_t();
+}
+
+ixion_table_handler::ixion_table_handler(const ixion::model_context& cxt, const table_store_type& tables) :
+ m_context(cxt), m_tables(tables) {}
+
+ixion::abs_range_t ixion_table_handler::get_range(
+ const ixion::abs_address_t& pos, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const
+{
+ const table_t* tab = find_table(pos);
+ if (!tab)
+ return ixion::abs_range_t(ixion::abs_range_t::invalid);
+
+ return get_range_from_table(*tab, column_first, column_last, areas);
+
+}
+
+ixion::abs_range_t ixion_table_handler::get_range(
+ ixion::string_id_t table, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const
+{
+ std::string_view tab_name = get_string(table);
+ if (tab_name.empty())
+ // no table name given.
+ return ixion::abs_range_t(ixion::abs_range_t::invalid);
+
+ auto it = m_tables.find(tab_name);
+ if (it == m_tables.end())
+ // no table by this name found.
+ return ixion::abs_range_t(ixion::abs_range_t::invalid);
+
+ const table_t* tab = it->second.get();
+ return get_range_from_table(*tab, column_first, column_last, areas);
+}
+
+document_impl::document_impl(document& _doc, const range_size_t& sheet_size) :
+ doc(_doc),
+ context({sheet_size.rows, sheet_size.columns}),
+ styles_store(),
+ ss_store(context),
+ pivots(doc),
+ name_resolver_global(ixion::formula_name_resolver::get(ixion::formula_name_resolver_t::excel_a1, &context)),
+ grammar(formula_grammar_t::xlsx),
+ table_handler(context, tables)
+{
+ context.set_table_handler(&table_handler);
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/document_impl.hpp b/src/spreadsheet/document_impl.hpp
new file mode 100644
index 0000000..44ee91f
--- /dev/null
+++ b/src/spreadsheet/document_impl.hpp
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <orcus/spreadsheet/auto_filter.hpp>
+#include <orcus/spreadsheet/config.hpp>
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/spreadsheet/pivot.hpp>
+#include <orcus/spreadsheet/shared_strings.hpp>
+#include <orcus/spreadsheet/sheet.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+#include <orcus/string_pool.hpp>
+#include <orcus/types.hpp>
+
+#include <ixion/config.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/interface/table_handler.hpp>
+#include <ixion/matrix.hpp>
+#include <ixion/model_context.hpp>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+/**
+ * Single sheet entry which consists of a sheet name and a sheet data.
+ */
+struct sheet_item
+{
+ sheet_item(const sheet_item&) = delete;
+ sheet_item& operator=(const sheet_item&) = delete;
+
+ std::string_view name;
+ sheet data;
+ sheet_item(document& doc, std::string_view _name, sheet_t sheet_index);
+};
+
+typedef std::map<std::string_view, std::unique_ptr<table_t>> table_store_type;
+typedef std::vector<std::unique_ptr<sheet_item>> sheet_items_type;
+
+class ixion_table_handler : public ixion::iface::table_handler
+{
+ const ixion::model_context& m_context;
+ const table_store_type& m_tables;
+
+ const table_t* find_table(const ixion::abs_address_t& pos) const;
+
+ std::string_view get_string(ixion::string_id_t sid) const;
+
+ col_t find_column(const table_t& tab, std::string_view name, size_t offset) const;
+
+ ixion::abs_range_t get_range_from_table(
+ const table_t& tab, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const;
+
+public:
+ ixion_table_handler(const ixion::model_context& cxt, const table_store_type& tables);
+
+ virtual ixion::abs_range_t get_range(
+ const ixion::abs_address_t& pos, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const override;
+
+ virtual ixion::abs_range_t get_range(
+ ixion::string_id_t table, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const override;
+};
+
+struct document_impl
+{
+ document_impl(const document_impl&) = delete;
+ document_impl& operator=(const document_impl&) = delete;
+
+ document& doc;
+
+ document_config doc_config;
+ string_pool string_pool_store;
+ ixion::model_context context;
+ date_time_t origin_date;
+ sheet_items_type sheets;
+ styles styles_store;
+ shared_strings ss_store;
+ ixion::abs_range_set_t dirty_cells;
+
+ pivot_collection pivots;
+
+ std::unique_ptr<ixion::formula_name_resolver> name_resolver_global;
+ std::unique_ptr<ixion::formula_name_resolver> name_resolver_named_exp_base;
+ std::unique_ptr<ixion::formula_name_resolver> name_resolver_named_range;
+ formula_grammar_t grammar;
+
+ table_store_type tables;
+ ixion_table_handler table_handler;
+
+ document_impl(document& _doc, const range_size_t& sheet_size);
+};
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/document_types.cpp b/src/spreadsheet/document_types.cpp
new file mode 100644
index 0000000..88e0724
--- /dev/null
+++ b/src/spreadsheet/document_types.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/spreadsheet/document_types.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+color_t::color_t() :
+ alpha(0), red(0), green(0), blue(0)
+{
+}
+
+color_t::color_t(color_elem_t _red, color_elem_t _green, color_elem_t _blue) :
+ alpha(255), red(_red), green(_green), blue(_blue)
+{
+}
+
+color_t::color_t(color_elem_t _alpha, color_elem_t _red, color_elem_t _green, color_elem_t _blue) :
+ alpha(_alpha), red(_red), green(_green), blue(_blue)
+{
+}
+
+void color_t::reset()
+{
+ *this = color_t();
+}
+
+bool color_t::operator==(const color_t& other) const
+{
+ return alpha == other.alpha && red == other.red && green == other.green && blue == other.blue;
+}
+
+bool color_t::operator!=(const color_t& other) const
+{
+ return !operator==(other);
+}
+
+format_run::format_run() :
+ pos(0), size(0),
+ font_size(0),
+ bold(false), italic(false) {}
+
+void format_run::reset()
+{
+ pos = 0;
+ size = 0;
+ font = std::string_view{};
+ font_size = 0;
+ bold = false;
+ italic = false;
+ color = color_t();
+}
+
+bool format_run::formatted() const
+{
+ if (bold || italic)
+ return true;
+
+ if (font_size)
+ return true;
+
+ if (!font.empty())
+ return true;
+
+ if (color.alpha || color.red || color.green || color.blue)
+ return true;
+
+ return false;
+}
+
+}} // namespace orcus::spreadsheet
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/dumper_global.cpp b/src/spreadsheet/dumper_global.cpp
new file mode 100644
index 0000000..f500f3c
--- /dev/null
+++ b/src/spreadsheet/dumper_global.cpp
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "dumper_global.hpp"
+#include "number_format.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/cell.hpp>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+void dump_cell_value(
+ std::ostream& os, const ixion::model_context& cxt, const ixion::model_iterator::cell& cell,
+ func_str_handler str_handler,
+ func_empty_handler empty_handler)
+{
+ switch (cell.type)
+ {
+ case ixion::celltype_t::empty:
+ empty_handler(os);
+ break;
+ case ixion::celltype_t::boolean:
+ {
+ os << (std::get<bool>(cell.value) ? "true" : "false");
+ break;
+ }
+ case ixion::celltype_t::numeric:
+ {
+ format_to_file_output(os, std::get<double>(cell.value));
+ break;
+ }
+ case ixion::celltype_t::string:
+ {
+ const std::string* p = cxt.get_string(std::get<ixion::string_id_t>(cell.value));
+ assert(p);
+ str_handler(os, *p);
+ break;
+ }
+ case ixion::celltype_t::formula:
+ {
+ const ixion::formula_cell* fc = std::get<const ixion::formula_cell*>(cell.value);
+ assert(fc);
+ ixion::formula_result res;
+
+ try
+ {
+ res = fc->get_result_cache(
+ ixion::formula_result_wait_policy_t::throw_exception);
+ }
+ catch (const std::exception&)
+ {
+ os << "\"#RES!\"";
+ break;
+ }
+
+ switch (res.get_type())
+ {
+ case ixion::formula_result::result_type::value:
+ format_to_file_output(os, res.get_value());
+ break;
+ case ixion::formula_result::result_type::string:
+ {
+ const std::string& s = res.get_string();
+ str_handler(os, s);
+ }
+ break;
+ case ixion::formula_result::result_type::error:
+ os << "\"#ERR!\"";
+ break;
+ default:
+ ;
+ }
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/dumper_global.hpp b/src/spreadsheet/dumper_global.hpp
new file mode 100644
index 0000000..96c5afc
--- /dev/null
+++ b/src/spreadsheet/dumper_global.hpp
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_DUMPER_GLOBAL_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_DUMPER_GLOBAL_HPP
+
+#include <ixion/model_context.hpp>
+#include <ixion/model_iterator.hpp>
+
+#include <ostream>
+#include <functional>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+using func_str_handler = std::function<void(std::ostream&, const std::string&)>;
+using func_empty_handler = std::function<void(std::ostream&)>;
+
+void dump_cell_value(
+ std::ostream& os, const ixion::model_context& cxt, const ixion::model_iterator::cell& cell,
+ func_str_handler str_handler,
+ func_empty_handler empty_handler);
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory.cpp b/src/spreadsheet/factory.cpp
new file mode 100644
index 0000000..9cd7884
--- /dev/null
+++ b/src/spreadsheet/factory.cpp
@@ -0,0 +1,410 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/spreadsheet/factory.hpp"
+
+#include <orcus/spreadsheet/shared_strings.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+#include <orcus/spreadsheet/sheet.hpp>
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/spreadsheet/view.hpp>
+#include <orcus/exception.hpp>
+#include <orcus/string_pool.hpp>
+
+#include "factory_pivot.hpp"
+#include "factory_shared_strings.hpp"
+#include "factory_sheet.hpp"
+#include "global_settings.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_tokens.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/model_context.hpp>
+#include <sstream>
+#include <iostream>
+#include <unordered_map>
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+class import_ref_resolver : public iface::import_reference_resolver
+{
+ document& m_doc;
+ const ixion::formula_name_resolver* m_resolver;
+
+public:
+ import_ref_resolver(document& doc) : m_doc(doc), m_resolver(nullptr) {}
+
+ void set_formula_ref_context(formula_ref_context_t cxt)
+ {
+ m_resolver = m_doc.get_formula_name_resolver(cxt);
+ }
+
+ virtual src_address_t resolve_address(std::string_view address) override
+ {
+ if (!m_resolver)
+ throw std::runtime_error("import_ref_resolver::resolve_address: formula resolver is null!");
+
+ ixion::formula_name_t name = m_resolver->resolve(address, ixion::abs_address_t());
+
+ if (name.type != ixion::formula_name_t::cell_reference)
+ {
+ std::ostringstream os;
+ os << address << " is not a valid cell address.";
+ throw orcus::invalid_arg_error(os.str());
+ }
+
+ auto addr = std::get<ixion::address_t>(name.value);
+ src_address_t ret;
+ ret.sheet = addr.sheet;
+ ret.column = addr.column;
+ ret.row = addr.row;
+ return ret;
+ }
+
+ virtual src_range_t resolve_range(std::string_view range) override
+ {
+ if (!m_resolver)
+ throw std::runtime_error("import_ref_resolver::resolve_range: formula resolver is null!");
+
+ ixion::formula_name_t name = m_resolver->resolve(range, ixion::abs_address_t());
+
+ switch (name.type)
+ {
+ case ixion::formula_name_t::range_reference:
+ {
+ auto v = std::get<ixion::range_t>(name.value);
+ src_range_t ret;
+ ret.first.sheet = v.first.sheet;
+ ret.first.column = v.first.column;
+ ret.first.row = v.first.row;
+ ret.last.sheet = v.last.sheet;
+ ret.last.column = v.last.column;
+ ret.last.row = v.last.row;
+ return ret;
+ }
+ case ixion::formula_name_t::cell_reference:
+ {
+ // Single cell address is still considered a valid "range".
+ auto addr = std::get<ixion::address_t>(name.value);
+ src_address_t cell;
+ cell.sheet = addr.sheet;
+ cell.column = addr.column;
+ cell.row = addr.row;
+
+ src_range_t ret;
+ ret.first = cell;
+ ret.last = cell;
+ return ret;
+ }
+ default:
+ ;
+ }
+
+ std::ostringstream os;
+ os << "'" << range << "' is not a valid range address.";
+ throw orcus::invalid_arg_error(os.str());
+ }
+};
+
+class import_global_named_exp : public iface::import_named_expression
+{
+ document& m_doc;
+ std::string_view m_name;
+ ixion::abs_address_t m_base;
+ ixion::formula_tokens_t m_tokens;
+
+ void define(std::string_view name, std::string_view expression, formula_ref_context_t ref_cxt)
+ {
+ string_pool& sp = m_doc.get_string_pool();
+ m_name = sp.intern(name).first;
+
+ const ixion::formula_name_resolver* resolver = m_doc.get_formula_name_resolver(ref_cxt);
+ assert(resolver);
+
+ ixion::model_context& cxt = m_doc.get_model_context();
+ m_tokens = ixion::parse_formula_string(cxt, m_base, *resolver, expression);
+ }
+public:
+ import_global_named_exp(document& doc) : m_doc(doc), m_base(0, 0, 0) {}
+ virtual ~import_global_named_exp() override {}
+
+ virtual void set_base_position(const src_address_t& pos) override
+ {
+ m_base.sheet = pos.sheet;
+ m_base.row = pos.row;
+ m_base.column = pos.column;
+ }
+
+ virtual void set_named_expression(std::string_view name, std::string_view expression) override
+ {
+ define(name, expression, formula_ref_context_t::global);
+ }
+
+ virtual void set_named_range(std::string_view name, std::string_view range) override
+ {
+ define(name, range, formula_ref_context_t::named_range);
+ }
+
+ virtual void commit() override
+ {
+ ixion::model_context& cxt = m_doc.get_model_context();
+ cxt.set_named_expression(std::string{m_name}, m_base, std::move(m_tokens));
+
+ m_name = std::string_view{};
+ m_base.sheet = 0;
+ m_base.row = 0;
+ m_base.column = 0;
+ }
+};
+
+using sheet_ifaces_type = std::vector<std::unique_ptr<import_sheet>>;
+
+} // anonymous namespace
+
+import_factory_config::import_factory_config() = default;
+import_factory_config::import_factory_config(const import_factory_config& other) = default;
+import_factory_config::~import_factory_config() = default;
+
+import_factory_config& import_factory_config::operator=(const import_factory_config& other) = default;
+
+struct import_factory::impl
+{
+ std::shared_ptr<import_factory_config> m_config;
+ import_factory& m_envelope;
+ document& m_doc;
+ view* m_view;
+ character_set_t m_charset;
+
+ import_global_settings m_global_settings;
+ import_pivot_cache_def m_pc_def;
+ import_pivot_cache_records m_pc_records;
+ import_ref_resolver m_ref_resolver;
+ import_global_named_exp m_global_named_exp;
+ import_styles m_styles;
+ detail::import_shared_strings shared_strings;
+
+ sheet_ifaces_type m_sheets;
+
+ bool m_recalc_formula_cells;
+ formula_error_policy_t m_error_policy;
+
+ impl(import_factory& envelope, document& doc) :
+ m_config(std::make_shared<import_factory_config>()),
+ m_envelope(envelope),
+ m_doc(doc),
+ m_view(nullptr),
+ m_charset(character_set_t::unspecified),
+ m_global_settings(envelope, doc),
+ m_pc_def(doc),
+ m_pc_records(doc),
+ m_ref_resolver(doc),
+ m_global_named_exp(doc),
+ m_styles(m_config, doc.get_styles(), doc.get_string_pool()),
+ shared_strings(doc.get_string_pool(), doc.get_model_context(), doc.get_styles(), doc.get_shared_strings()),
+ m_recalc_formula_cells(false),
+ m_error_policy(formula_error_policy_t::fail)
+ {
+ }
+};
+
+import_factory::import_factory(document& doc) :
+ mp_impl(std::make_unique<impl>(*this, doc)) {}
+
+import_factory::import_factory(document& doc, view& view_store) :
+ mp_impl(std::make_unique<impl>(*this, doc))
+{
+ // Store the optional view store.
+ mp_impl->m_view = &view_store;
+}
+
+import_factory::~import_factory() {}
+
+iface::import_global_settings* import_factory::get_global_settings()
+{
+ return &mp_impl->m_global_settings;
+}
+
+iface::import_shared_strings* import_factory::get_shared_strings()
+{
+ return &mp_impl->shared_strings;
+}
+
+iface::import_styles* import_factory::get_styles()
+{
+ return &mp_impl->m_styles;
+}
+
+iface::import_named_expression* import_factory::get_named_expression()
+{
+ return &mp_impl->m_global_named_exp;
+}
+
+iface::import_reference_resolver* import_factory::get_reference_resolver(formula_ref_context_t cxt)
+{
+ mp_impl->m_ref_resolver.set_formula_ref_context(cxt);
+ return &mp_impl->m_ref_resolver;
+}
+
+iface::import_pivot_cache_definition* import_factory::create_pivot_cache_definition(
+ pivot_cache_id_t cache_id)
+{
+ mp_impl->m_pc_def.create_cache(cache_id);
+ return &mp_impl->m_pc_def;
+}
+
+iface::import_pivot_cache_records* import_factory::create_pivot_cache_records(
+ orcus::spreadsheet::pivot_cache_id_t cache_id)
+{
+ pivot_collection& pcs = mp_impl->m_doc.get_pivot_collection();
+ pivot_cache* pc = pcs.get_cache(cache_id);
+ if (!pc)
+ return nullptr;
+
+ mp_impl->m_pc_records.set_cache(pc);
+ return &mp_impl->m_pc_records;
+}
+
+iface::import_sheet* import_factory::append_sheet(sheet_t sheet_index, std::string_view name)
+{
+ assert(sheet_index == static_cast<sheet_t>(mp_impl->m_doc.get_sheet_count()));
+
+ sheet* sh = mp_impl->m_doc.append_sheet(name);
+
+ if (!sh)
+ return nullptr;
+
+ sheet_view* sv = nullptr;
+ if (mp_impl->m_view)
+ sv = mp_impl->m_view->get_or_create_sheet_view(sheet_index);
+
+ mp_impl->m_sheets.push_back(
+ std::make_unique<import_sheet>(mp_impl->m_doc, *sh, sv));
+
+ import_sheet* p = mp_impl->m_sheets.back().get();
+ p->set_character_set(mp_impl->m_charset);
+ p->set_fill_missing_formula_results(!mp_impl->m_recalc_formula_cells);
+ p->set_formula_error_policy(mp_impl->m_error_policy);
+ return p;
+}
+
+iface::import_sheet* import_factory::get_sheet(std::string_view name)
+{
+ sheet_t si = mp_impl->m_doc.get_sheet_index(name);
+ if (si == ixion::invalid_sheet)
+ return nullptr;
+
+ return mp_impl->m_sheets.at(si).get();
+}
+
+iface::import_sheet* import_factory::get_sheet(sheet_t sheet_index)
+{
+ if (sheet_index < 0 || size_t(sheet_index) >= mp_impl->m_sheets.size())
+ return nullptr;
+
+ return mp_impl->m_sheets[sheet_index].get();
+}
+
+void import_factory::finalize()
+{
+ mp_impl->m_doc.finalize_import();
+
+ if (mp_impl->m_recalc_formula_cells)
+ mp_impl->m_doc.recalc_formula_cells();
+}
+
+void import_factory::set_config(const import_factory_config& config)
+{
+ // NB: update the object state.
+ *mp_impl->m_config = config;
+}
+
+void import_factory::set_default_row_size(row_t row_size)
+{
+ range_size_t ss = mp_impl->m_doc.get_sheet_size();
+ ss.rows = row_size;
+ mp_impl->m_doc.set_sheet_size(ss);
+}
+
+void import_factory::set_default_column_size(col_t col_size)
+{
+ range_size_t ss = mp_impl->m_doc.get_sheet_size();
+ ss.columns = col_size;
+ mp_impl->m_doc.set_sheet_size(ss);
+}
+
+void import_factory::set_character_set(character_set_t charset)
+{
+ mp_impl->m_charset = charset;
+
+ for (std::unique_ptr<import_sheet>& sheet : mp_impl->m_sheets)
+ sheet->set_character_set(charset);
+}
+
+character_set_t import_factory::get_character_set() const
+{
+ return mp_impl->m_charset;
+}
+
+void import_factory::set_recalc_formula_cells(bool b)
+{
+ mp_impl->m_recalc_formula_cells = b;
+}
+
+void import_factory::set_formula_error_policy(formula_error_policy_t policy)
+{
+ mp_impl->m_error_policy = policy;
+}
+
+struct export_factory::impl
+{
+ const document& m_doc;
+
+ std::vector<std::unique_ptr<export_sheet>> m_sheets;
+ std::unordered_map<std::string_view, sheet_t> m_sheet_index_map;
+
+ impl(const document& doc) : m_doc(doc) {}
+
+ export_sheet* get_sheet(std::string_view name)
+ {
+ auto it = m_sheet_index_map.find(name);
+ if (it != m_sheet_index_map.end())
+ {
+ // Instance for this sheet already exists.
+ sheet_t sheet_pos = it->second;
+ assert(size_t(sheet_pos) < m_sheets.size());
+ return m_sheets[sheet_pos].get();
+ }
+
+ const sheet* sh = m_doc.get_sheet(name);
+ if (!sh)
+ return nullptr;
+
+ sheet_t sheet_pos = m_sheets.size();
+ m_sheets.emplace_back(std::make_unique<export_sheet>(m_doc, *sh));
+
+ m_sheet_index_map.insert(
+ std::make_pair(name, sheet_pos));
+
+ return m_sheets[sheet_pos].get();
+ }
+};
+
+export_factory::export_factory(const document& doc) :
+ mp_impl(std::make_unique<impl>(doc)) {}
+
+export_factory::~export_factory() {}
+
+const iface::export_sheet* export_factory::get_sheet(std::string_view sheet_name) const
+{
+ return mp_impl->get_sheet(sheet_name);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_pivot.cpp b/src/spreadsheet/factory_pivot.cpp
new file mode 100644
index 0000000..2761da5
--- /dev/null
+++ b/src/spreadsheet/factory_pivot.cpp
@@ -0,0 +1,303 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "factory_pivot.hpp"
+
+#include "orcus/string_pool.hpp"
+#include "orcus/exception.hpp"
+
+#include <sstream>
+#include <iostream>
+#include <cassert>
+
+namespace orcus { namespace spreadsheet {
+
+class import_pc_field_group : public iface::import_pivot_cache_field_group
+{
+ using range_grouping_type = pivot_cache_group_data_t::range_grouping_type;
+
+ document& m_doc;
+ pivot_cache_field_t& m_parent_field;
+ std::unique_ptr<pivot_cache_group_data_t> m_data;
+ pivot_cache_item_t m_current_field_item;
+
+private:
+ std::string_view intern(std::string_view s)
+ {
+ return m_doc.get_string_pool().intern(s).first;
+ }
+
+ range_grouping_type& get_range_grouping()
+ {
+ if (!m_data->range_grouping)
+ m_data->range_grouping = range_grouping_type();
+
+ return *m_data->range_grouping;
+ }
+
+public:
+ import_pc_field_group(document& doc, pivot_cache_field_t& parent, size_t base_index) :
+ m_doc(doc),
+ m_parent_field(parent),
+ m_data(std::make_unique<pivot_cache_group_data_t>(base_index)) {}
+
+ ~import_pc_field_group() override {}
+
+ void link_base_to_group_items(size_t group_item_index) override
+ {
+ pivot_cache_indices_t& b2g = m_data->base_to_group_indices;
+ b2g.push_back(group_item_index);
+ }
+
+ void set_field_item_string(std::string_view value) override
+ {
+ m_current_field_item.type = pivot_cache_item_t::item_type::character;
+ m_current_field_item.value = intern(value);
+ }
+
+ void set_field_item_numeric(double v) override
+ {
+ m_current_field_item.type = pivot_cache_item_t::item_type::numeric;
+ m_current_field_item.value = v;
+ }
+
+ void commit_field_item() override
+ {
+ m_data->items.push_back(std::move(m_current_field_item));
+ }
+
+ void set_range_grouping_type(pivot_cache_group_by_t group_by) override
+ {
+ get_range_grouping().group_by = group_by;
+ }
+
+ void set_range_auto_start(bool b) override
+ {
+ get_range_grouping().auto_start = b;
+ }
+
+ void set_range_auto_end(bool b) override
+ {
+ get_range_grouping().auto_end = b;
+ }
+
+ void set_range_start_number(double v) override
+ {
+ get_range_grouping().start = v;
+ }
+
+ void set_range_end_number(double v) override
+ {
+ get_range_grouping().end = v;
+ }
+
+ void set_range_start_date(const date_time_t& dt) override
+ {
+ get_range_grouping().start_date = dt;
+ }
+
+ void set_range_end_date(const date_time_t& dt) override
+ {
+ get_range_grouping().end_date = dt;
+ }
+
+ void set_range_interval(double v) override
+ {
+ get_range_grouping().interval = v;
+ }
+
+ void commit() override
+ {
+ m_parent_field.group_data = std::move(m_data);
+ }
+};
+
+std::string_view import_pivot_cache_def::intern(std::string_view s)
+{
+ return m_doc.get_string_pool().intern(s).first;
+}
+
+import_pivot_cache_def::import_pivot_cache_def(document& doc) : m_doc(doc) {}
+
+import_pivot_cache_def::~import_pivot_cache_def() {}
+
+void import_pivot_cache_def::create_cache(pivot_cache_id_t cache_id)
+{
+ m_src_type = unknown;
+ m_cache = std::make_unique<pivot_cache>(cache_id, m_doc.get_string_pool());
+}
+
+void import_pivot_cache_def::set_worksheet_source(std::string_view ref, std::string_view sheet_name)
+{
+ assert(m_cache);
+
+ const ixion::formula_name_resolver* resolver =
+ m_doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ assert(resolver);
+
+ m_src_type = worksheet;
+ m_src_sheet_name = intern(sheet_name);
+
+ ixion::formula_name_t fn = resolver->resolve(ref, ixion::abs_address_t(0,0,0));
+
+ if (fn.type != ixion::formula_name_t::range_reference)
+ {
+ std::ostringstream os;
+ os << "'" << ref << "' is not a valid range.";
+ throw xml_structure_error(os.str());
+ }
+
+ m_src_range = std::get<ixion::range_t>(fn.value).to_abs(ixion::abs_address_t(0,0,0));
+}
+
+void import_pivot_cache_def::set_worksheet_source(std::string_view table_name)
+{
+ assert(m_cache);
+
+ m_src_table_name = intern(table_name);
+}
+
+void import_pivot_cache_def::set_field_count(size_t n)
+{
+ m_current_fields.reserve(n);
+}
+
+void import_pivot_cache_def::set_field_name(std::string_view name)
+{
+ m_current_field.name = intern(name);
+}
+
+iface::import_pivot_cache_field_group* import_pivot_cache_def::start_field_group(size_t base_index)
+{
+ m_current_field_group =
+ std::make_unique<import_pc_field_group>(m_doc, m_current_field, base_index);
+
+ return m_current_field_group.get();
+}
+
+void import_pivot_cache_def::set_field_min_value(double v)
+{
+ m_current_field.min_value = v;
+}
+
+void import_pivot_cache_def::set_field_max_value(double v)
+{
+ m_current_field.max_value = v;
+}
+
+void import_pivot_cache_def::set_field_min_date(const date_time_t& dt)
+{
+ m_current_field.min_date = dt;
+}
+
+void import_pivot_cache_def::set_field_max_date(const date_time_t& dt)
+{
+ m_current_field.max_date = dt;
+}
+
+void import_pivot_cache_def::commit_field()
+{
+ m_current_fields.push_back(std::move(m_current_field));
+}
+
+void import_pivot_cache_def::set_field_item_string(std::string_view value)
+{
+ m_current_field_item.type = pivot_cache_item_t::item_type::character;
+ m_current_field_item.value = intern(value);
+}
+
+void import_pivot_cache_def::set_field_item_numeric(double v)
+{
+ m_current_field_item.type = pivot_cache_item_t::item_type::numeric;
+ m_current_field_item.value = v;
+}
+
+void import_pivot_cache_def::set_field_item_date_time(const date_time_t& dt)
+{
+ m_current_field_item.type = pivot_cache_item_t::item_type::date_time;
+ m_current_field_item.value = dt;
+}
+
+void import_pivot_cache_def::set_field_item_error(error_value_t ev)
+{
+ m_current_field_item.type = pivot_cache_item_t::item_type::error;
+ m_current_field_item.value = ev;
+}
+
+void import_pivot_cache_def::commit_field_item()
+{
+ m_current_field.items.push_back(std::move(m_current_field_item));
+}
+
+void import_pivot_cache_def::commit()
+{
+ m_cache->insert_fields(std::move(m_current_fields));
+ assert(m_current_fields.empty());
+
+ if (!m_src_table_name.empty())
+ {
+ m_doc.get_pivot_collection().insert_worksheet_cache(
+ m_src_table_name, std::move(m_cache));
+ return;
+ }
+
+ m_doc.get_pivot_collection().insert_worksheet_cache(
+ m_src_sheet_name, m_src_range, std::move(m_cache));
+}
+
+import_pivot_cache_records::import_pivot_cache_records(document& doc) :
+ m_doc(doc), m_cache(nullptr) {}
+
+import_pivot_cache_records::~import_pivot_cache_records() {}
+
+void import_pivot_cache_records::set_cache(pivot_cache* p)
+{
+ m_cache = p;
+}
+
+void import_pivot_cache_records::set_record_count(size_t n)
+{
+ m_records.reserve(n);
+}
+
+void import_pivot_cache_records::append_record_value_numeric(double v)
+{
+ m_current_record.emplace_back(v);
+}
+
+void import_pivot_cache_records::append_record_value_character(std::string_view s)
+{
+ m_current_record.emplace_back(s);
+}
+
+void import_pivot_cache_records::append_record_value_shared_item(size_t index)
+{
+ m_current_record.emplace_back(index);
+}
+
+void import_pivot_cache_records::commit_record()
+{
+ if (!m_cache)
+ {
+ m_current_record.clear();
+ return;
+ }
+
+ m_records.push_back(std::move(m_current_record));
+}
+
+void import_pivot_cache_records::commit()
+{
+ if (!m_cache)
+ return;
+
+ m_cache->insert_records(std::move(m_records));
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_pivot.hpp b/src/spreadsheet/factory_pivot.hpp
new file mode 100644
index 0000000..465fef1
--- /dev/null
+++ b/src/spreadsheet/factory_pivot.hpp
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_FACTORY_PIVOT_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_FACTORY_PIVOT_HPP
+
+#include "orcus/spreadsheet/pivot.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/import_interface_pivot.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+class import_pc_field_group;
+
+/**
+ * Concrete implementation of the import_pivot_cache_definition interface.
+ */
+class import_pivot_cache_def : public iface::import_pivot_cache_definition
+{
+ enum source_type { unknown = 0, worksheet, external, consolidation, scenario };
+
+ document& m_doc;
+
+ pivot_cache_id_t m_cache_id = 0;
+
+ source_type m_src_type = unknown;
+ std::string_view m_src_sheet_name;
+ ixion::abs_range_t m_src_range;
+ std::string_view m_src_table_name;
+
+ std::unique_ptr<pivot_cache> m_cache;
+ pivot_cache::fields_type m_current_fields;
+ pivot_cache_field_t m_current_field;
+ pivot_cache_item_t m_current_field_item;
+
+ std::unique_ptr<import_pc_field_group> m_current_field_group;
+
+private:
+ std::string_view intern(std::string_view s);
+
+public:
+ import_pivot_cache_def(document& doc);
+ ~import_pivot_cache_def();
+
+ void create_cache(pivot_cache_id_t cache_id);
+
+ virtual void set_worksheet_source(std::string_view ref, std::string_view sheet_name) override;
+
+ virtual void set_worksheet_source(std::string_view table_name) override;
+
+ virtual void set_field_count(size_t n) override;
+
+ virtual void set_field_name(std::string_view name) override;
+
+ virtual iface::import_pivot_cache_field_group* start_field_group(size_t base_index) override;
+
+ virtual void set_field_min_value(double v) override;
+
+ virtual void set_field_max_value(double v) override;
+
+ virtual void set_field_min_date(const date_time_t& dt) override;
+
+ virtual void set_field_max_date(const date_time_t& dt) override;
+
+ virtual void commit_field() override;
+
+ virtual void set_field_item_string(std::string_view value) override;
+
+ virtual void set_field_item_numeric(double v) override;
+
+ virtual void set_field_item_date_time(const date_time_t& dt) override;
+
+ virtual void set_field_item_error(error_value_t ev) override;
+
+ virtual void commit_field_item() override;
+
+ virtual void commit() override;
+};
+
+/**
+ * Concrete implementation of the import_pivot_cache_records interface.
+ */
+class import_pivot_cache_records : public iface::import_pivot_cache_records
+{
+ document& m_doc;
+ pivot_cache* m_cache; //< cache to push the records to at the very end.
+
+ pivot_cache_record_t m_current_record;
+ pivot_cache::records_type m_records;
+
+public:
+ import_pivot_cache_records(document& doc);
+ ~import_pivot_cache_records();
+
+ void set_cache(pivot_cache* p);
+
+ virtual void set_record_count(size_t n) override;
+
+ virtual void append_record_value_numeric(double v) override;
+
+ virtual void append_record_value_character(std::string_view s) override;
+
+ virtual void append_record_value_shared_item(size_t index) override;
+
+ virtual void commit_record() override;
+
+ virtual void commit() override;
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_shared_strings.cpp b/src/spreadsheet/factory_shared_strings.cpp
new file mode 100644
index 0000000..a8375c0
--- /dev/null
+++ b/src/spreadsheet/factory_shared_strings.cpp
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "factory_shared_strings.hpp"
+
+#include <orcus/spreadsheet/shared_strings.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+#include <orcus/string_pool.hpp>
+#include <ixion/model_context.hpp>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+import_shared_strings::import_shared_strings(
+ string_pool& sp, ixion::model_context& cxt, styles& st, shared_strings& ss_store) :
+ m_string_pool(sp),
+ m_cxt(cxt),
+ m_styles(st),
+ m_ss_store(ss_store)
+{
+}
+
+import_shared_strings::~import_shared_strings() {}
+
+size_t import_shared_strings::append(std::string_view s)
+{
+ return m_cxt.append_string(s);
+}
+
+size_t import_shared_strings::add(std::string_view s)
+{
+ return m_cxt.add_string(s);
+}
+
+void import_shared_strings::set_segment_font(size_t font_index)
+{
+ const font_t* font_data = m_styles.get_font(font_index);
+ if (!font_data)
+ return;
+
+ m_cur_format.bold = font_data->bold ? *font_data->bold : false;
+ m_cur_format.italic = font_data->italic ? *font_data->italic : false;
+
+ if (font_data->name)
+ m_cur_format.font = *font_data->name; // font names are already interned when set.
+
+ if (font_data->size)
+ m_cur_format.font_size = *font_data->size;
+
+ if (font_data->color)
+ m_cur_format.color = *font_data->color;
+}
+
+void import_shared_strings::set_segment_bold(bool b)
+{
+ m_cur_format.bold = b;
+}
+
+void import_shared_strings::set_segment_italic(bool b)
+{
+ m_cur_format.italic = b;
+}
+
+void import_shared_strings::set_segment_font_name(std::string_view s)
+{
+ m_cur_format.font = m_string_pool.intern(s).first;
+}
+
+void import_shared_strings::set_segment_font_size(double point)
+{
+ m_cur_format.font_size = point;
+}
+
+void import_shared_strings::set_segment_font_color(
+ color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ m_cur_format.color = color_t(alpha, red, green, blue);
+}
+
+void import_shared_strings::append_segment(std::string_view s)
+{
+ if (s.empty())
+ return;
+
+ size_t start_pos = m_cur_segment_string.size();
+ m_cur_segment_string += s;
+
+ if (m_cur_format.formatted())
+ {
+ // This segment is formatted.
+ // Record the position and size of the format run.
+ m_cur_format.pos = start_pos;
+ m_cur_format.size = s.size();
+
+ if (!mp_cur_format_runs)
+ mp_cur_format_runs = std::make_unique<format_runs_t>();
+
+ mp_cur_format_runs->push_back(m_cur_format);
+ m_cur_format.reset();
+ }
+}
+
+size_t import_shared_strings::commit_segments()
+{
+ ixion::string_id_t sindex = m_cxt.append_string(m_cur_segment_string);
+ m_cur_segment_string.clear();
+ m_ss_store.set_format_runs(sindex, std::move(mp_cur_format_runs));
+ mp_cur_format_runs.reset();
+
+ return sindex;
+}
+
+}}} // namespace orcus::spreadsheet::detail
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_shared_strings.hpp b/src/spreadsheet/factory_shared_strings.hpp
new file mode 100644
index 0000000..b49d274
--- /dev/null
+++ b/src/spreadsheet/factory_shared_strings.hpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/document_types.hpp>
+
+#include <memory>
+
+namespace ixion {
+
+class model_context;
+
+}
+
+namespace orcus {
+
+class string_pool;
+
+namespace spreadsheet {
+
+class styles;
+class shared_strings;
+
+namespace detail {
+
+class import_shared_strings : public iface::import_shared_strings
+{
+ orcus::string_pool& m_string_pool;
+ ixion::model_context& m_cxt;
+ styles& m_styles;
+ shared_strings& m_ss_store;
+
+ std::string m_cur_segment_string;
+ format_run m_cur_format;
+ std::unique_ptr<format_runs_t> mp_cur_format_runs;
+
+public:
+ import_shared_strings(
+ string_pool& sp, ixion::model_context& cxt, styles& st,
+ orcus::spreadsheet::shared_strings& ss_store);
+ virtual ~import_shared_strings() override;
+
+ virtual size_t append(std::string_view s) override;
+ virtual size_t add(std::string_view s) override;
+
+ virtual void set_segment_font(size_t font_index) override;
+ virtual void set_segment_bold(bool b) override;
+ virtual void set_segment_italic(bool b) override;
+ virtual void set_segment_font_name(std::string_view s) override;
+ virtual void set_segment_font_size(double point) override;
+ virtual void set_segment_font_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void append_segment(std::string_view s) override;
+ virtual size_t commit_segments() override;
+};
+
+}}} // namespace orcus::spreadsheet::detail
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_sheet.cpp b/src/spreadsheet/factory_sheet.cpp
new file mode 100644
index 0000000..dcc6639
--- /dev/null
+++ b/src/spreadsheet/factory_sheet.cpp
@@ -0,0 +1,640 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "factory_sheet.hpp"
+#include "orcus/spreadsheet/sheet.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/view.hpp"
+#include "orcus/measurement.hpp"
+#include "orcus/string_pool.hpp"
+
+#include "formula_global.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/model_context.hpp>
+#include <ixion/formula.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+import_sheet_named_exp::import_sheet_named_exp(document& doc, sheet_t sheet_index) :
+ m_doc(doc), m_sheet_index(sheet_index), m_base(sheet_index, 0, 0) {}
+
+import_sheet_named_exp::~import_sheet_named_exp() {}
+
+void import_sheet_named_exp::define(
+ std::string_view name, std::string_view expression, formula_ref_context_t ref_cxt)
+{
+ string_pool& sp = m_doc.get_string_pool();
+ m_name = sp.intern(name).first;
+
+ const ixion::formula_name_resolver* resolver = m_doc.get_formula_name_resolver(ref_cxt);
+ assert(resolver);
+
+ ixion::model_context& cxt = m_doc.get_model_context();
+ m_tokens = ixion::parse_formula_string(cxt, m_base, *resolver, expression);
+}
+
+void import_sheet_named_exp::set_base_position(const src_address_t& pos)
+{
+ m_base.sheet = pos.sheet;
+ m_base.row = pos.row;
+ m_base.column = pos.column;
+}
+
+void import_sheet_named_exp::set_named_expression(std::string_view name, std::string_view expression)
+{
+ define(name, expression, formula_ref_context_t::global);
+}
+
+void import_sheet_named_exp::set_named_range(std::string_view name, std::string_view range)
+{
+ define(name, range, formula_ref_context_t::named_range);
+}
+
+void import_sheet_named_exp::commit()
+{
+ ixion::model_context& cxt = m_doc.get_model_context();
+ cxt.set_named_expression(m_sheet_index, std::string{m_name}, m_base, std::move(m_tokens));
+
+ m_name = std::string_view{};
+ m_base.sheet = 0;
+ m_base.row = 0;
+ m_base.column = 0;
+}
+
+import_data_table::import_data_table(sheet& sh) : m_sheet(sh) {}
+import_data_table::~import_data_table() {}
+
+void import_data_table::reset()
+{
+}
+
+void import_data_table::set_type(data_table_type_t /*type*/)
+{
+}
+
+void import_data_table::set_range(const range_t& /*range*/)
+{
+}
+
+void import_data_table::set_first_reference(std::string_view /*ref*/, bool /*deleted*/)
+{
+}
+
+void import_data_table::set_second_reference(std::string_view /*ref*/, bool /*deleted*/)
+{
+}
+
+void import_data_table::commit()
+{
+}
+
+import_auto_filter::import_auto_filter(sheet& sh, string_pool& sp) :
+ m_sheet(sh),
+ m_string_pool(sp),
+ m_cur_col(-1) {}
+
+void import_auto_filter::reset()
+{
+ mp_data.reset(new auto_filter_t);
+ m_cur_col = -1;
+ m_cur_col_data.reset();
+}
+
+void import_auto_filter::set_range(const range_t& range)
+{
+ mp_data->range = to_abs_range(range, m_sheet.get_index());
+}
+
+void import_auto_filter::set_column(col_t col)
+{
+ m_cur_col = col;
+}
+
+void import_auto_filter::append_column_match_value(std::string_view value)
+{
+ // The string pool belongs to the document.
+ value = m_string_pool.intern(value).first;
+ m_cur_col_data.match_values.insert(value);
+}
+
+void import_auto_filter::commit_column()
+{
+ if (!mp_data)
+ return;
+
+ mp_data->commit_column(m_cur_col, m_cur_col_data);
+ m_cur_col_data.reset();
+}
+
+void import_auto_filter::commit()
+{
+ m_sheet.set_auto_filter_data(mp_data.release());
+}
+
+import_array_formula::import_array_formula(document& doc, sheet& sheet) :
+ m_doc(doc), m_sheet(sheet), m_missing_formula_result(), m_error_policy(formula_error_policy_t::fail)
+{
+ m_range.first.column = -1;
+ m_range.first.row = -1;
+ m_range.last = m_range.first;
+}
+
+import_array_formula::~import_array_formula()
+{
+}
+
+void import_array_formula::set_range(const range_t& range)
+{
+ m_range = range;
+
+ // Initialize the result matrix with the missing result value.
+ switch (m_missing_formula_result.get_type())
+ {
+ case ixion::formula_result::result_type::value:
+ {
+ ixion::matrix _mtx(
+ m_range.last.row - m_range.first.row + 1,
+ m_range.last.column - m_range.first.column + 1,
+ m_missing_formula_result.get_value());
+ m_result_mtx.swap(_mtx);
+ break;
+ }
+ case ixion::formula_result::result_type::error:
+ {
+ ixion::matrix _mtx(
+ m_range.last.row - m_range.first.row + 1,
+ m_range.last.column - m_range.first.column + 1,
+ m_missing_formula_result.get_error());
+ m_result_mtx.swap(_mtx);
+ break;
+ }
+ case ixion::formula_result::result_type::string:
+ {
+ ixion::matrix _mtx(
+ m_range.last.row - m_range.first.row + 1,
+ m_range.last.column - m_range.first.column + 1,
+ m_missing_formula_result.get_string());
+ m_result_mtx.swap(_mtx);
+ break;
+ }
+ default:
+ {
+ ixion::matrix _mtx(
+ m_range.last.row - m_range.first.row + 1,
+ m_range.last.column - m_range.first.column + 1);
+ m_result_mtx.swap(_mtx);
+ }
+ }
+}
+
+void import_array_formula::set_formula(formula_grammar_t /*grammar*/, std::string_view formula)
+{
+ const ixion::formula_name_resolver* resolver =
+ m_doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ if (!resolver)
+ return;
+
+ // Tokenize the formula string and store it.
+ ixion::model_context& cxt = m_doc.get_model_context();
+ ixion::abs_address_t pos(m_sheet.get_index(), m_range.first.row, m_range.first.column);
+
+ try
+ {
+ m_tokens = ixion::parse_formula_string(cxt, pos, *resolver, formula);
+ }
+ catch (const std::exception& e)
+ {
+ if (m_error_policy == formula_error_policy_t::fail)
+ throw;
+
+ std::string_view error_s = e.what();
+ m_tokens = ixion::create_formula_error_tokens(cxt, formula, error_s);
+ }
+}
+
+void import_array_formula::set_result_value(row_t row, col_t col, double value)
+{
+ m_result_mtx.set(row, col, value);
+}
+
+void import_array_formula::set_result_string(row_t /*row*/, col_t /*col*/, std::string_view /*value*/)
+{
+ // TODO : handle this
+}
+
+void import_array_formula::set_result_empty(row_t /*row*/, col_t /*col*/)
+{
+ // TODO : handle this
+}
+
+void import_array_formula::set_result_bool(row_t row, col_t col, bool value)
+{
+ m_result_mtx.set(row, col, value);
+}
+
+void import_array_formula::commit()
+{
+ ixion::formula_result cached_results(std::move(m_result_mtx));
+ m_sheet.set_grouped_formula(m_range, std::move(m_tokens), std::move(cached_results));
+}
+
+void import_array_formula::set_missing_formula_result(ixion::formula_result result)
+{
+ m_missing_formula_result = std::move(result);
+}
+
+void import_array_formula::set_formula_error_policy(formula_error_policy_t policy)
+{
+ m_error_policy = policy;
+}
+
+void import_array_formula::reset()
+{
+ m_tokens.clear();
+ m_result_mtx = ixion::matrix();
+ m_range.first.row = -1;
+ m_range.first.column = -1;
+ m_range.last.row = -1;
+ m_range.last.column = -1;
+}
+
+import_formula::import_formula(document& doc, sheet& sheet, shared_formula_pool& pool) :
+ m_doc(doc),
+ m_sheet(sheet),
+ m_shared_formula_pool(pool),
+ m_row(-1),
+ m_col(-1),
+ m_shared_index(0),
+ m_shared(false),
+ m_error_policy(formula_error_policy_t::fail) {}
+
+import_formula::~import_formula() {}
+
+void import_formula::set_position(row_t row, col_t col)
+{
+ m_row = row;
+ m_col = col;
+}
+
+void import_formula::set_formula(formula_grammar_t /*grammar*/, std::string_view formula)
+{
+ if (m_row < 0 || m_col < 0)
+ return;
+
+ const ixion::formula_name_resolver* resolver =
+ m_doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ if (!resolver)
+ return;
+
+ // Tokenize the formula string and store it.
+ ixion::model_context& cxt = m_doc.get_model_context();
+ ixion::abs_address_t pos(m_sheet.get_index(), m_row, m_col);
+
+ ixion::formula_tokens_t tokens;
+ try
+ {
+ tokens = ixion::parse_formula_string(cxt, pos, *resolver, formula);
+ }
+ catch (const std::exception& e)
+ {
+ if (m_error_policy == formula_error_policy_t::fail)
+ throw;
+
+ std::string_view error_s = e.what();
+ tokens = ixion::create_formula_error_tokens(cxt, formula, error_s);
+ }
+
+ m_tokens_store = ixion::formula_tokens_store::create();
+ m_tokens_store->get() = std::move(tokens);
+}
+
+void import_formula::set_shared_formula_index(size_t index)
+{
+ m_shared = true;
+ m_shared_index = index;
+}
+
+void import_formula::set_result_value(double value)
+{
+ m_result = ixion::formula_result(value);
+}
+
+void import_formula::set_result_string(std::string_view value)
+{
+ m_result = ixion::formula_result(std::string{value});
+}
+
+void import_formula::set_result_empty() {}
+void import_formula::set_result_bool(bool /*value*/) {}
+
+void import_formula::commit()
+{
+ if (m_row < 0 || m_col < 0)
+ return;
+
+ if (m_shared)
+ {
+ if (m_tokens_store)
+ {
+ if (m_result)
+ m_sheet.set_formula(m_row, m_col, m_tokens_store, *m_result);
+ else
+ m_sheet.set_formula(m_row, m_col, m_tokens_store);
+
+ m_shared_formula_pool.add(m_shared_index, m_tokens_store);
+ }
+ else
+ {
+ ixion::formula_tokens_store_ptr_t ts = m_shared_formula_pool.get(m_shared_index);
+ if (!ts)
+ return;
+
+ if (m_result)
+ m_sheet.set_formula(m_row, m_col, ts, *m_result);
+ else
+ m_sheet.set_formula(m_row, m_col, ts);
+ }
+ return;
+ }
+
+ if (m_result)
+ m_sheet.set_formula(m_row, m_col, m_tokens_store, *m_result);
+ else
+ m_sheet.set_formula(m_row, m_col, m_tokens_store);
+}
+
+void import_formula::set_missing_formula_result(ixion::formula_result result)
+{
+ m_result = std::move(result);
+}
+
+void import_formula::set_formula_error_policy(formula_error_policy_t policy)
+{
+ m_error_policy = policy;
+}
+
+void import_formula::reset()
+{
+ m_tokens_store.reset();
+ m_result.reset();
+ m_row = -1;
+ m_col = -1;
+ m_shared_index = 0;
+ m_shared = false;
+}
+
+import_sheet::import_sheet(document& doc, sheet& sh, sheet_view* view) :
+ m_doc(doc),
+ m_sheet(sh),
+ m_formula(doc, sh, m_shared_formula_pool),
+ m_array_formula(doc, sh),
+ m_named_exp(doc, sh.get_index()),
+ m_sheet_properties(doc, sh),
+ m_data_table(sh),
+ m_auto_filter(sh, doc.get_string_pool()),
+ m_table(doc, sh),
+ m_charset(character_set_t::unspecified),
+ m_fill_missing_formula_results(false)
+{
+ if (view)
+ m_sheet_view = std::make_unique<import_sheet_view>(*view, sh.get_index());
+}
+
+import_sheet::~import_sheet() {}
+
+iface::import_sheet_view* import_sheet::get_sheet_view()
+{
+ return m_sheet_view.get();
+}
+
+iface::import_auto_filter* import_sheet::get_auto_filter()
+{
+ m_auto_filter.reset();
+ return &m_auto_filter;
+}
+
+iface::import_conditional_format* import_sheet::get_conditional_format()
+{
+ return nullptr;
+}
+
+iface::import_data_table* import_sheet::get_data_table()
+{
+ return &m_data_table;
+}
+
+iface::import_named_expression* import_sheet::get_named_expression()
+{
+ return &m_named_exp;
+}
+
+iface::import_sheet_properties* import_sheet::get_sheet_properties()
+{
+ return &m_sheet_properties;
+}
+
+iface::import_table* import_sheet::get_table()
+{
+ m_table.reset();
+ return &m_table;
+}
+
+iface::import_formula* import_sheet::get_formula()
+{
+ m_formula.reset();
+
+ if (m_fill_missing_formula_results)
+ {
+ m_formula.set_missing_formula_result(
+ ixion::formula_result(ixion::formula_error_t::no_result_error));
+ }
+
+ return &m_formula;
+}
+
+iface::import_array_formula* import_sheet::get_array_formula()
+{
+ m_array_formula.reset();
+
+ if (m_fill_missing_formula_results)
+ {
+ m_array_formula.set_missing_formula_result(
+ ixion::formula_result(ixion::formula_error_t::no_result_error));
+ }
+
+ return &m_array_formula;
+}
+
+void import_sheet::set_auto(row_t row, col_t col, std::string_view s)
+{
+ m_sheet.set_auto(row, col, s);
+}
+
+void import_sheet::set_bool(row_t row, col_t col, bool value)
+{
+ m_sheet.set_bool(row, col, value);
+}
+
+void import_sheet::set_date_time(row_t row, col_t col, int year, int month, int day, int hour, int minute, double second)
+{
+ m_sheet.set_date_time(row, col, year, month, day, hour, minute, second);
+}
+
+void import_sheet::set_format(row_t row, col_t col, size_t xf_index)
+{
+ m_sheet.set_format(row, col, xf_index);
+}
+
+void import_sheet::set_format(
+ row_t row_start, col_t col_start, row_t row_end, col_t col_end, size_t xf_index)
+{
+ m_sheet.set_format(row_start, col_start, row_end, col_end, xf_index);
+}
+
+void import_sheet::set_column_format(col_t col, col_t col_span, std::size_t xf_index)
+{
+ m_sheet.set_column_format(col, col_span, xf_index);
+}
+
+void import_sheet::set_row_format(row_t row, std::size_t xf_index)
+{
+ m_sheet.set_row_format(row, xf_index);
+}
+
+void import_sheet::set_string(row_t row, col_t col, string_id_t sindex)
+{
+ m_sheet.set_string(row, col, sindex);
+}
+
+void import_sheet::set_value(row_t row, col_t col, double value)
+{
+ m_sheet.set_value(row, col, value);
+}
+
+void import_sheet::fill_down_cells(row_t src_row, col_t src_col, row_t range_size)
+{
+ m_sheet.fill_down_cells(src_row, src_col, range_size);
+}
+
+range_size_t import_sheet::get_sheet_size() const
+{
+ return m_doc.get_sheet_size();
+}
+
+void import_sheet::set_character_set(character_set_t charset)
+{
+ m_charset = charset;
+}
+
+void import_sheet::set_fill_missing_formula_results(bool b)
+{
+ m_fill_missing_formula_results = b;
+}
+
+void import_sheet::set_formula_error_policy(formula_error_policy_t policy)
+{
+ m_formula.set_formula_error_policy(policy);
+ m_array_formula.set_formula_error_policy(policy);
+}
+
+import_sheet_view::import_sheet_view(sheet_view& view, sheet_t si) :
+ m_view(view), m_sheet_index(si) {}
+
+import_sheet_view::~import_sheet_view() {}
+
+void import_sheet_view::set_split_pane(
+ double hor_split, double ver_split,
+ const orcus::spreadsheet::address_t& top_left_cell,
+ orcus::spreadsheet::sheet_pane_t active_pane)
+{
+ m_view.set_split_pane(hor_split, ver_split, top_left_cell);
+ m_view.set_active_pane(active_pane);
+}
+
+void import_sheet_view::set_frozen_pane(
+ orcus::spreadsheet::col_t visible_columns,
+ orcus::spreadsheet::row_t visible_rows,
+ const orcus::spreadsheet::address_t& top_left_cell,
+ orcus::spreadsheet::sheet_pane_t active_pane)
+{
+ m_view.set_frozen_pane(visible_columns, visible_rows, top_left_cell);
+ m_view.set_active_pane(active_pane);
+}
+
+void import_sheet_view::set_selected_range(sheet_pane_t pane, range_t range)
+{
+ m_view.set_selection(pane, range);
+}
+
+void import_sheet_view::set_sheet_active()
+{
+ m_view.get_document_view().set_active_sheet(m_sheet_index);
+}
+
+import_sheet_properties::import_sheet_properties(document& doc, sheet& sh) :
+ m_doc(doc), m_sheet(sh) {}
+
+import_sheet_properties::~import_sheet_properties() {}
+
+void import_sheet_properties::set_column_width(col_t col, col_t col_span, double width, orcus::length_unit_t unit)
+{
+ col_width_t w = orcus::convert(width, unit, length_unit_t::twip);
+ m_sheet.set_col_width(col, col_span, w);
+}
+
+void import_sheet_properties::set_column_hidden(col_t col, col_t col_span, bool hidden)
+{
+ m_sheet.set_col_hidden(col, col_span, hidden);
+}
+
+void import_sheet_properties::set_row_height(row_t row, double height, orcus::length_unit_t unit)
+{
+ row_height_t h = orcus::convert(height, unit, length_unit_t::twip);
+ m_sheet.set_row_height(row, h);
+}
+
+void import_sheet_properties::set_row_hidden(row_t row, bool hidden)
+{
+ m_sheet.set_row_hidden(row, hidden);
+}
+
+void import_sheet_properties::set_merge_cell_range(const range_t& range)
+{
+ m_sheet.set_merge_cell_range(range);
+}
+
+export_sheet::export_sheet(const document& doc, const sheet& sh) : m_doc(doc), m_sheet(sh) {}
+export_sheet::~export_sheet() {}
+
+void export_sheet::write_string(std::ostream& os, row_t row, col_t col) const
+{
+ const ixion::model_context& cxt = m_doc.get_model_context();
+ ixion::abs_address_t pos(m_sheet.get_index(), row, col);
+
+ switch (cxt.get_celltype(pos))
+ {
+ case ixion::celltype_t::string:
+ {
+ size_t str_id = cxt.get_string_identifier(pos);
+ const std::string* p = cxt.get_string(str_id);
+ if (p)
+ os << *p;
+ }
+ break;
+ case ixion::celltype_t::numeric:
+ os << cxt.get_numeric_value(pos);
+ break;
+ default:
+ ;
+ }
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/spreadsheet/factory_sheet.hpp b/src/spreadsheet/factory_sheet.hpp
new file mode 100644
index 0000000..ded4d10
--- /dev/null
+++ b/src/spreadsheet/factory_sheet.hpp
@@ -0,0 +1,275 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_FACTORY_SHEET_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_FACTORY_SHEET_HPP
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/import_interface_view.hpp>
+#include <orcus/spreadsheet/auto_filter.hpp>
+
+#include <orcus/spreadsheet/export_interface.hpp>
+
+#include "factory_table.hpp"
+#include "shared_formula.hpp"
+
+#include <memory>
+#include <optional>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/matrix.hpp>
+
+namespace orcus {
+
+class string_pool;
+
+namespace spreadsheet {
+
+class document;
+class sheet_view;
+class sheet;
+class import_sheet_view;
+
+class import_sheet_named_exp : public iface::import_named_expression
+{
+ document& m_doc;
+ sheet_t m_sheet_index;
+ std::string_view m_name;
+ ixion::abs_address_t m_base;
+ ixion::formula_tokens_t m_tokens;
+
+ void define(std::string_view name, std::string_view expression, formula_ref_context_t ref_cxt);
+
+public:
+ import_sheet_named_exp(document& doc, sheet_t sheet_index);
+ virtual ~import_sheet_named_exp() override;
+
+ virtual void set_base_position(const src_address_t& pos) override;
+ virtual void set_named_expression(std::string_view name, std::string_view expression) override;
+ virtual void set_named_range(std::string_view name, std::string_view range) override;
+ virtual void commit();
+};
+
+/**
+ * Implement the sheet properties import interface, but the actual
+ * properties are stored in sheet.
+ */
+class import_sheet_properties : public iface::import_sheet_properties
+{
+ document& m_doc;
+ sheet& m_sheet;
+public:
+ import_sheet_properties(document& doc, sheet& sh);
+ ~import_sheet_properties();
+
+ virtual void set_column_width(col_t col, col_t col_span, double width, orcus::length_unit_t unit);
+ virtual void set_column_hidden(col_t col, col_t col_span, bool hidden);
+ virtual void set_row_height(row_t row, double height, orcus::length_unit_t unit);
+ virtual void set_row_hidden(row_t row, bool hidden);
+ virtual void set_merge_cell_range(const range_t& range);
+};
+
+class import_data_table : public iface::import_data_table
+{
+ sheet& m_sheet;
+public:
+ import_data_table(sheet& sh);
+ ~import_data_table();
+
+ void reset();
+
+ virtual void set_type(data_table_type_t type) override;
+
+ virtual void set_range(const range_t& range) override;
+
+ virtual void set_first_reference(std::string_view ref, bool deleted) override;
+
+ virtual void set_second_reference(std::string_view ref, bool deleted) override;
+
+ virtual void commit() override;
+};
+
+class import_auto_filter : public orcus::spreadsheet::iface::import_auto_filter
+{
+ sheet& m_sheet;
+ string_pool& m_string_pool;
+ std::unique_ptr<auto_filter_t> mp_data;
+ col_t m_cur_col;
+ auto_filter_column_t m_cur_col_data;
+
+public:
+ import_auto_filter(sheet& sh, string_pool& sp);
+
+ void reset();
+
+ virtual void set_range(const range_t& range) override;
+
+ virtual void set_column(col_t col) override;
+
+ virtual void append_column_match_value(std::string_view value) override;
+
+ virtual void commit_column() override;
+
+ virtual void commit() override;
+};
+
+class import_array_formula : public iface::import_array_formula
+{
+ document& m_doc;
+ sheet& m_sheet;
+
+ range_t m_range;
+ ixion::formula_tokens_t m_tokens;
+ ixion::formula_result m_missing_formula_result;
+ ixion::matrix m_result_mtx;
+ formula_error_policy_t m_error_policy;
+
+public:
+ import_array_formula(document& doc, sheet& sheet);
+ virtual ~import_array_formula() override;
+
+ virtual void set_range(const range_t& range) override;
+
+ virtual void set_formula(formula_grammar_t grammar, std::string_view formula) override;
+
+ virtual void set_result_value(row_t row, col_t col, double value) override;
+
+ virtual void set_result_string(row_t row, col_t col, std::string_view value) override;
+
+ virtual void set_result_empty(row_t row, col_t col) override;
+
+ virtual void set_result_bool(row_t row, col_t col, bool value) override;
+
+ virtual void commit() override;
+
+ void set_missing_formula_result(ixion::formula_result result);
+
+ void set_formula_error_policy(formula_error_policy_t policy);
+
+ void reset();
+};
+
+class import_formula : public iface::import_formula
+{
+ document& m_doc;
+ sheet& m_sheet;
+ shared_formula_pool& m_shared_formula_pool;
+
+ row_t m_row;
+ col_t m_col;
+ size_t m_shared_index;
+ bool m_shared;
+
+ ixion::formula_tokens_store_ptr_t m_tokens_store;
+ std::optional<ixion::formula_result> m_result;
+ formula_error_policy_t m_error_policy;
+
+public:
+ import_formula(document& doc, sheet& sheet, shared_formula_pool& pool);
+ virtual ~import_formula() override;
+
+ virtual void set_position(row_t row, col_t col) override;
+ virtual void set_formula(formula_grammar_t grammar, std::string_view formula) override;
+ virtual void set_shared_formula_index(size_t index) override;
+ virtual void set_result_value(double value) override;
+ virtual void set_result_string(std::string_view value) override;
+ virtual void set_result_empty() override;
+ virtual void set_result_bool(bool value) override;
+ virtual void commit() override;
+
+ void set_missing_formula_result(ixion::formula_result result);
+ void set_formula_error_policy(formula_error_policy_t policy);
+
+ void reset();
+};
+
+class import_sheet : public iface::import_sheet
+{
+ document& m_doc;
+ sheet& m_sheet;
+ shared_formula_pool m_shared_formula_pool;
+ import_formula m_formula;
+ import_array_formula m_array_formula;
+ import_sheet_named_exp m_named_exp;
+ import_sheet_properties m_sheet_properties;
+ import_data_table m_data_table;
+ import_auto_filter m_auto_filter;
+ import_table m_table;
+ character_set_t m_charset;
+
+ std::unique_ptr<import_sheet_view> m_sheet_view;
+
+ bool m_fill_missing_formula_results;
+
+public:
+ import_sheet(document& doc, sheet& sh, sheet_view* view);
+ virtual ~import_sheet() override;
+
+ virtual iface::import_sheet_view* get_sheet_view() override;
+ virtual iface::import_auto_filter* get_auto_filter() override;
+ virtual iface::import_conditional_format* get_conditional_format() override;
+ virtual iface::import_data_table* get_data_table() override;
+ virtual iface::import_named_expression* get_named_expression() override;
+ virtual iface::import_sheet_properties* get_sheet_properties() override;
+ virtual iface::import_table* get_table() override;
+ virtual iface::import_formula* get_formula() override;
+ virtual iface::import_array_formula* get_array_formula() override;
+ virtual void set_auto(row_t row, col_t col, std::string_view s) override;
+ virtual void set_bool(row_t row, col_t col, bool value) override;
+ virtual void set_date_time(row_t row, col_t col, int year, int month, int day, int hour, int minute, double second) override;
+ virtual void set_format(row_t row, col_t col, size_t xf_index) override;
+ virtual void set_format(row_t row_start, col_t col_start, row_t row_end, col_t col_end, size_t xf_index) override;
+ virtual void set_column_format(col_t col, col_t col_span, std::size_t xf_index) override;
+ virtual void set_row_format(row_t row, std::size_t xf_index) override;
+ virtual void set_string(row_t row, col_t col, string_id_t sindex) override;
+ virtual void set_value(row_t row, col_t col, double value) override;
+ virtual void fill_down_cells(row_t src_row, col_t src_col, row_t range_size) override;
+ virtual range_size_t get_sheet_size() const override;
+
+ void set_character_set(character_set_t charset);
+ void set_fill_missing_formula_results(bool b);
+ void set_formula_error_policy(formula_error_policy_t policy);
+};
+
+class import_sheet_view : public iface::import_sheet_view
+{
+ sheet_view& m_view;
+ sheet_t m_sheet_index;
+public:
+ import_sheet_view(sheet_view& view, sheet_t si);
+ virtual ~import_sheet_view();
+ virtual void set_sheet_active() override;
+
+ virtual void set_split_pane(
+ double hor_split, double ver_split,
+ const address_t& top_left_cell,
+ sheet_pane_t active_pane) override;
+
+ virtual void set_frozen_pane(
+ col_t visible_columns, row_t visible_rows,
+ const address_t& top_left_cell,
+ sheet_pane_t active_pane) override;
+
+ virtual void set_selected_range(sheet_pane_t pane, range_t range) override;
+};
+
+class export_sheet : public iface::export_sheet
+{
+ const document& m_doc;
+ const sheet& m_sheet;
+public:
+ export_sheet(const document& doc, const sheet& sh);
+ ~export_sheet();
+
+ virtual void write_string(std::ostream& os, row_t row, col_t col) const override;
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_styles.cpp b/src/spreadsheet/factory_styles.cpp
new file mode 100644
index 0000000..91c6844
--- /dev/null
+++ b/src/spreadsheet/factory_styles.cpp
@@ -0,0 +1,870 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/spreadsheet/factory.hpp"
+#include "orcus/spreadsheet/styles.hpp"
+#include "orcus/string_pool.hpp"
+
+#include <unordered_map>
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+class import_font_style : public iface::import_font_style
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_font_style() = delete;
+ import_font_style(styles& _styles_model, string_pool& sp);
+ import_font_style(std::shared_ptr<import_factory_config> _config, styles& _styles_model, string_pool& sp);
+ virtual ~import_font_style() override;
+
+ virtual void set_bold(bool b) override;
+ virtual void set_bold_asian(bool b) override;
+ virtual void set_bold_complex(bool b) override;
+
+ virtual void set_italic(bool b) override;
+ virtual void set_italic_asian(bool b) override;
+ virtual void set_italic_complex(bool b) override;
+
+ virtual void set_name(std::string_view s) override;
+ virtual void set_name_asian(std::string_view s) override;
+ virtual void set_name_complex(std::string_view s) override;
+
+ virtual void set_size(double point) override;
+ virtual void set_size_asian(double point) override;
+ virtual void set_size_complex(double point) override;
+
+ virtual void set_underline(underline_t e) override;
+ virtual void set_underline_width(underline_width_t e) override;
+ virtual void set_underline_mode(underline_mode_t e) override;
+ virtual void set_underline_type(underline_type_t e) override;
+ virtual void set_underline_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void set_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void set_strikethrough_style(strikethrough_style_t s) override;
+ virtual void set_strikethrough_type(strikethrough_type_t s) override;
+ virtual void set_strikethrough_width(strikethrough_width_t s) override;
+ virtual void set_strikethrough_text(strikethrough_text_t s) override;
+ virtual std::size_t commit() override;
+
+ void reset();
+};
+
+class import_fill_style : public iface::import_fill_style
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_fill_style() = delete;
+ import_fill_style(styles& _styles_model, string_pool& sp);
+ virtual ~import_fill_style() override;
+
+ virtual void set_pattern_type(fill_pattern_t fp) override;
+ virtual void set_fg_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void set_bg_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual size_t commit() override;
+
+ void reset();
+};
+
+class import_border_style : public iface::import_border_style
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_border_style() = delete;
+ import_border_style(styles& _styles_model, string_pool& sp);
+ virtual ~import_border_style() override;
+
+ virtual void set_style(border_direction_t dir, border_style_t style) override;
+ virtual void set_color(
+ border_direction_t dir, color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void set_width(border_direction_t dir, double width, orcus::length_unit_t unit) override;
+ virtual size_t commit() override;
+
+ void reset();
+};
+
+class import_cell_protection : public iface::import_cell_protection
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_cell_protection() = delete;
+ import_cell_protection(styles& _styles_model, string_pool& sp);
+ virtual ~import_cell_protection() override;
+
+ virtual void set_hidden(bool b) override;
+ virtual void set_locked(bool b) override;
+ virtual void set_print_content(bool b) override;
+ virtual void set_formula_hidden(bool b) override;
+ virtual size_t commit() override;
+
+ void reset();
+};
+
+class import_number_format : public iface::import_number_format
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_number_format() = delete;
+ import_number_format(styles& _styles_model, string_pool& sp);
+ virtual ~import_number_format() override;
+
+ virtual void set_identifier(std::size_t id) override;
+ virtual void set_code(std::string_view s) override;
+ virtual size_t commit() override;
+
+ void reset();
+};
+
+class import_xf : public iface::import_xf
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_xf() = delete;
+ import_xf(styles& _styles_model, string_pool& sp);
+ virtual ~import_xf() override;
+
+ virtual void set_font(size_t index) override;
+ virtual void set_fill(size_t index) override;
+ virtual void set_border(size_t index) override;
+ virtual void set_protection(size_t index) override;
+ virtual void set_number_format(size_t index) override;
+ virtual void set_style_xf(size_t index) override;
+ virtual void set_apply_alignment(bool b) override;
+ virtual void set_horizontal_alignment(hor_alignment_t align) override;
+ virtual void set_vertical_alignment(ver_alignment_t align) override;
+ virtual void set_wrap_text(bool b) override;
+ virtual void set_shrink_to_fit(bool b) override;
+ virtual size_t commit() override;
+
+ void reset(xf_category_t cat);
+};
+
+class import_cell_style : public iface::import_cell_style
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_cell_style() = delete;
+ import_cell_style(styles& _styles_model, string_pool& sp);
+ virtual ~import_cell_style() override;
+
+ void set_name(std::string_view s) override;
+ void set_display_name(std::string_view s) override;
+ void set_xf(size_t index) override;
+ void set_builtin(size_t index) override;
+ void set_parent_name(std::string_view s) override;
+ void commit() override;
+
+ void reset();
+};
+
+struct import_font_style::impl
+{
+ std::shared_ptr<import_factory_config> config;
+ styles& styles_model;
+ string_pool& str_pool;
+
+ std::unordered_map<font_t, std::size_t, font_t::hash> font_cache;
+ font_t cur_font;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ config(std::make_shared<import_factory_config>()),
+ styles_model(_styles_model),
+ str_pool(sp) {}
+
+ impl(std::shared_ptr<import_factory_config> _config, styles& _styles_model, string_pool& sp) :
+ config(_config), styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_font_style::import_font_style(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_font_style::import_font_style(
+ std::shared_ptr<import_factory_config> _config, styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_config, _styles_model, sp))
+{
+}
+
+import_font_style::~import_font_style() = default;
+
+void import_font_style::set_bold(bool b)
+{
+ mp_impl->cur_font.bold = b;
+}
+
+void import_font_style::set_bold_asian(bool b)
+{
+ mp_impl->cur_font.bold_asian = b;
+}
+
+void import_font_style::set_bold_complex(bool b)
+{
+ mp_impl->cur_font.bold_complex = b;
+}
+
+void import_font_style::set_italic(bool b)
+{
+ mp_impl->cur_font.italic = b;
+}
+
+void import_font_style::set_italic_asian(bool b)
+{
+ mp_impl->cur_font.italic_asian = b;
+}
+
+void import_font_style::set_italic_complex(bool b)
+{
+ mp_impl->cur_font.italic_complex = b;
+}
+
+void import_font_style::set_name(std::string_view s)
+{
+ mp_impl->cur_font.name = mp_impl->str_pool.intern(s).first;
+}
+
+void import_font_style::set_name_asian(std::string_view s)
+{
+ mp_impl->cur_font.name_asian = mp_impl->str_pool.intern(s).first;
+}
+
+void import_font_style::set_name_complex(std::string_view s)
+{
+ mp_impl->cur_font.name_complex = mp_impl->str_pool.intern(s).first;
+}
+
+void import_font_style::set_size(double point)
+{
+ mp_impl->cur_font.size = point;
+}
+
+void import_font_style::set_size_asian(double point)
+{
+ mp_impl->cur_font.size_asian = point;
+}
+
+void import_font_style::set_size_complex(double point)
+{
+ mp_impl->cur_font.size_complex = point;
+}
+
+void import_font_style::set_underline(underline_t e)
+{
+ mp_impl->cur_font.underline_style = e;
+}
+
+void import_font_style::set_underline_width(underline_width_t e)
+{
+ mp_impl->cur_font.underline_width = e;
+}
+
+void import_font_style::set_underline_mode(underline_mode_t e)
+{
+ mp_impl->cur_font.underline_mode = e;
+}
+
+void import_font_style::set_underline_type(underline_type_t e)
+{
+ mp_impl->cur_font.underline_type = e;
+}
+
+void import_font_style::set_underline_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ mp_impl->cur_font.underline_color = color_t(alpha, red, green, blue);
+}
+
+void import_font_style::set_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ mp_impl->cur_font.color = color_t(alpha, red, green, blue);
+}
+
+void import_font_style::set_strikethrough_style(strikethrough_style_t s)
+{
+ mp_impl->cur_font.strikethrough_style = s;
+}
+
+void import_font_style::set_strikethrough_type(strikethrough_type_t s)
+{
+ mp_impl->cur_font.strikethrough_type = s;
+}
+
+void import_font_style::set_strikethrough_width(strikethrough_width_t s)
+{
+ mp_impl->cur_font.strikethrough_width = s;
+}
+
+void import_font_style::set_strikethrough_text(strikethrough_text_t s)
+{
+ mp_impl->cur_font.strikethrough_text = s;
+}
+
+std::size_t import_font_style::commit()
+{
+ if (mp_impl->config->enable_font_cache)
+ {
+ auto it = mp_impl->font_cache.find(mp_impl->cur_font);
+ if (it != mp_impl->font_cache.end())
+ return it->second;
+ }
+
+ std::size_t font_id = mp_impl->styles_model.append_font(mp_impl->cur_font);
+ mp_impl->font_cache.insert({mp_impl->cur_font, font_id});
+ mp_impl->cur_font.reset();
+ return font_id;
+}
+
+void import_font_style::reset()
+{
+ mp_impl->cur_font.reset();
+}
+
+struct import_fill_style::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ fill_t cur_fill;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_fill_style::import_fill_style(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_fill_style::~import_fill_style()
+{
+}
+
+void import_fill_style::set_pattern_type(fill_pattern_t fp)
+{
+ mp_impl->cur_fill.pattern_type = fp;
+}
+
+void import_fill_style::set_fg_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ mp_impl->cur_fill.fg_color = color_t{alpha, red, green, blue};
+}
+
+void import_fill_style::set_bg_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ mp_impl->cur_fill.bg_color = color_t{alpha, red, green, blue};
+}
+
+size_t import_fill_style::commit()
+{
+ size_t fill_id = mp_impl->styles_model.append_fill(mp_impl->cur_fill);
+ mp_impl->cur_fill.reset();
+ return fill_id;
+}
+
+void import_fill_style::reset()
+{
+ mp_impl->cur_fill.reset();
+}
+
+struct import_border_style::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ border_t cur_border;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+
+ border_attrs_t* get_border_attrs(border_direction_t dir)
+ {
+ switch (dir)
+ {
+ case border_direction_t::top:
+ return &cur_border.top;
+ case border_direction_t::bottom:
+ return &cur_border.bottom;
+ case border_direction_t::left:
+ return &cur_border.left;
+ case border_direction_t::right:
+ return &cur_border.right;
+ case border_direction_t::diagonal:
+ return &cur_border.diagonal;
+ case border_direction_t::diagonal_bl_tr:
+ return &cur_border.diagonal_bl_tr;
+ case border_direction_t::diagonal_tl_br:
+ return &cur_border.diagonal_tl_br;
+ case border_direction_t::unknown:
+ ;
+ }
+
+ return nullptr;
+ }
+};
+
+import_border_style::import_border_style(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_border_style::~import_border_style()
+{
+}
+
+void import_border_style::set_style(border_direction_t dir, border_style_t style)
+{
+ border_attrs_t* v = mp_impl->get_border_attrs(dir);
+ if (!v)
+ return;
+
+ v->style = style;
+}
+
+void import_border_style::set_color(
+ border_direction_t dir, color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ border_attrs_t* v = mp_impl->get_border_attrs(dir);
+ if (!v)
+ return;
+
+ v->border_color = color_t(alpha, red, green, blue);
+}
+
+void import_border_style::set_width(border_direction_t dir, double width, orcus::length_unit_t unit)
+{
+ border_attrs_t* v = mp_impl->get_border_attrs(dir);
+ if (!v)
+ return;
+
+ length_t bw{unit, width};
+ v->border_width = bw;
+}
+
+size_t import_border_style::commit()
+{
+ size_t border_id = mp_impl->styles_model.append_border(mp_impl->cur_border);
+ mp_impl->cur_border.reset();
+ return border_id;
+}
+
+void import_border_style::reset()
+{
+ mp_impl->cur_border.reset();
+}
+
+struct import_cell_protection::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ protection_t cur_protection;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_cell_protection::import_cell_protection(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_cell_protection::~import_cell_protection()
+{
+}
+
+void import_cell_protection::set_hidden(bool b)
+{
+ mp_impl->cur_protection.hidden = b;
+}
+
+void import_cell_protection::set_locked(bool b)
+{
+ mp_impl->cur_protection.locked = b;
+}
+
+void import_cell_protection::set_print_content(bool b)
+{
+ mp_impl->cur_protection.print_content = b;
+}
+
+void import_cell_protection::set_formula_hidden(bool b)
+{
+ mp_impl->cur_protection.formula_hidden = b;
+}
+
+std::size_t import_cell_protection::commit()
+{
+ std::size_t cp_id = mp_impl->styles_model.append_protection(mp_impl->cur_protection);
+ mp_impl->cur_protection.reset();
+ return cp_id;
+}
+
+void import_cell_protection::reset()
+{
+ mp_impl->cur_protection.reset();
+}
+
+struct import_number_format::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ number_format_t cur_numfmt;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_number_format::import_number_format(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_number_format::~import_number_format()
+{
+}
+
+void import_number_format::set_identifier(std::size_t id)
+{
+ mp_impl->cur_numfmt.identifier = id;
+}
+
+void import_number_format::set_code(std::string_view s)
+{
+ mp_impl->cur_numfmt.format_string = s;
+}
+
+size_t import_number_format::commit()
+{
+ std::size_t fmt_id = mp_impl->styles_model.append_number_format(mp_impl->cur_numfmt);
+ mp_impl->cur_numfmt.reset();
+
+ return fmt_id;
+}
+
+void import_number_format::reset()
+{
+ mp_impl->cur_numfmt.reset();
+}
+
+struct import_xf::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ cell_format_t cur_cell_format;
+ xf_category_t xf_category = xf_category_t::unknown;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_xf::import_xf(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_xf::~import_xf()
+{
+}
+
+void import_xf::set_font(size_t index)
+{
+ mp_impl->cur_cell_format.font = index;
+}
+
+void import_xf::set_fill(size_t index)
+{
+ mp_impl->cur_cell_format.fill = index;
+}
+
+void import_xf::set_border(size_t index)
+{
+ mp_impl->cur_cell_format.border = index;
+
+ // TODO : we need to decide whether to have interface methods for these
+ // apply_foo attributes. For now there is only one, for alignment.
+ mp_impl->cur_cell_format.apply_border = index > 0;
+}
+
+void import_xf::set_protection(size_t index)
+{
+ mp_impl->cur_cell_format.protection = index;
+}
+
+void import_xf::set_number_format(size_t index)
+{
+ mp_impl->cur_cell_format.number_format = index;
+}
+
+void import_xf::set_style_xf(size_t index)
+{
+ mp_impl->cur_cell_format.style_xf = index;
+}
+
+void import_xf::set_apply_alignment(bool b)
+{
+ mp_impl->cur_cell_format.apply_alignment = b;
+}
+
+void import_xf::set_horizontal_alignment(hor_alignment_t align)
+{
+ mp_impl->cur_cell_format.hor_align = align;
+}
+
+void import_xf::set_vertical_alignment(ver_alignment_t align)
+{
+ mp_impl->cur_cell_format.ver_align = align;
+}
+
+void import_xf::set_wrap_text(bool b)
+{
+ mp_impl->cur_cell_format.wrap_text = b;
+}
+
+void import_xf::set_shrink_to_fit(bool b)
+{
+ mp_impl->cur_cell_format.shrink_to_fit = b;
+}
+
+
+size_t import_xf::commit()
+{
+ size_t xf_id = 0;
+
+ switch (mp_impl->xf_category)
+ {
+ case xf_category_t::cell:
+ xf_id = mp_impl->styles_model.append_cell_format(mp_impl->cur_cell_format);
+ break;
+ case xf_category_t::cell_style:
+ xf_id = mp_impl->styles_model.append_cell_style_format(mp_impl->cur_cell_format);
+ break;
+ case xf_category_t::differential:
+ xf_id = mp_impl->styles_model.append_diff_cell_format(mp_impl->cur_cell_format);
+ break;
+ case xf_category_t::unknown:
+ throw std::logic_error("unknown cell format category");
+ }
+
+ mp_impl->cur_cell_format.reset();
+ return xf_id;
+}
+
+void import_xf::reset(xf_category_t cat)
+{
+ if (cat == xf_category_t::unknown)
+ throw std::invalid_argument("The specified category is 'unknown'.");
+
+ mp_impl->cur_cell_format.reset();
+ mp_impl->xf_category = cat;
+}
+
+struct import_cell_style::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ cell_style_t cur_cell_style;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_cell_style::import_cell_style(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_cell_style::~import_cell_style() {}
+
+void import_cell_style::set_name(std::string_view s)
+{
+ mp_impl->cur_cell_style.name = mp_impl->str_pool.intern(s).first;
+}
+
+void import_cell_style::set_display_name(std::string_view s)
+{
+ mp_impl->cur_cell_style.display_name = mp_impl->str_pool.intern(s).first;
+}
+
+void import_cell_style::set_xf(size_t index)
+{
+ mp_impl->cur_cell_style.xf = index;
+}
+
+void import_cell_style::set_builtin(size_t index)
+{
+ mp_impl->cur_cell_style.builtin = index;
+}
+
+void import_cell_style::set_parent_name(std::string_view s)
+{
+ mp_impl->cur_cell_style.parent_name = mp_impl->str_pool.intern(s).first;
+}
+
+void import_cell_style::commit()
+{
+ mp_impl->styles_model.append_cell_style(mp_impl->cur_cell_style);
+ mp_impl->cur_cell_style.reset();
+}
+
+void import_cell_style::reset()
+{
+ mp_impl->cur_cell_style.reset();
+}
+
+} // anonymous namespace
+
+struct import_styles::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ import_font_style font_style;
+ import_fill_style fill_style;
+ import_border_style border_style;
+ import_cell_protection cell_protection;
+ import_number_format number_format;
+ import_xf xf;
+ import_cell_style cell_style;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model),
+ str_pool(sp),
+ font_style(_styles_model, sp),
+ fill_style(_styles_model, sp),
+ border_style(_styles_model, sp),
+ cell_protection(_styles_model, sp),
+ number_format(_styles_model, sp),
+ xf(_styles_model, sp),
+ cell_style(_styles_model, sp)
+ {}
+
+ impl(std::shared_ptr<import_factory_config> config, styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model),
+ str_pool(sp),
+ font_style(config, _styles_model, sp),
+ fill_style(_styles_model, sp),
+ border_style(_styles_model, sp),
+ cell_protection(_styles_model, sp),
+ number_format(_styles_model, sp),
+ xf(_styles_model, sp),
+ cell_style(_styles_model, sp)
+ {}
+};
+
+import_styles::import_styles(styles& styles_store, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(styles_store, sp)) {}
+
+import_styles::import_styles(std::shared_ptr<import_factory_config> config, styles& styles_store, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(config, styles_store, sp)) {}
+
+import_styles::~import_styles() = default;
+
+iface::import_font_style* import_styles::start_font_style()
+{
+ mp_impl->font_style.reset();
+ return &mp_impl->font_style;
+}
+
+iface::import_fill_style* import_styles::start_fill_style()
+{
+ mp_impl->fill_style.reset();
+ return &mp_impl->fill_style;
+}
+
+iface::import_border_style* import_styles::start_border_style()
+{
+ mp_impl->border_style.reset();
+ return &mp_impl->border_style;
+}
+
+iface::import_cell_protection* import_styles::start_cell_protection()
+{
+ mp_impl->cell_protection.reset();
+ return &mp_impl->cell_protection;
+}
+
+iface::import_number_format* import_styles::start_number_format()
+{
+ mp_impl->number_format.reset();
+ return &mp_impl->number_format;
+}
+
+iface::import_xf* import_styles::start_xf(xf_category_t cat)
+{
+ mp_impl->xf.reset(cat);
+ return &mp_impl->xf;
+}
+
+iface::import_cell_style* import_styles::start_cell_style()
+{
+ mp_impl->cell_style.reset();
+ return &mp_impl->cell_style;
+}
+
+void import_styles::set_font_count(size_t n)
+{
+ mp_impl->styles_model.reserve_font_store(n);
+}
+
+void import_styles::set_fill_count(size_t n)
+{
+ mp_impl->styles_model.reserve_fill_store(n);
+}
+
+void import_styles::set_border_count(size_t n)
+{
+ mp_impl->styles_model.reserve_border_store(n);
+}
+
+void import_styles::set_number_format_count(size_t n)
+{
+ mp_impl->styles_model.reserve_number_format_store(n);
+}
+
+void import_styles::set_xf_count(xf_category_t cat, size_t n)
+{
+ switch (cat)
+ {
+ case xf_category_t::cell:
+ mp_impl->styles_model.reserve_cell_format_store(n);
+ break;
+ case xf_category_t::cell_style:
+ mp_impl->styles_model.reserve_cell_style_format_store(n);
+ break;
+ case xf_category_t::differential:
+ mp_impl->styles_model.reserve_diff_cell_format_store(n);
+ break;
+ case xf_category_t::unknown:
+ break;
+ }
+}
+
+void import_styles::set_cell_style_count(size_t n)
+{
+ mp_impl->styles_model.reserve_cell_style_store(n);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_table.cpp b/src/spreadsheet/factory_table.cpp
new file mode 100644
index 0000000..a77b7af
--- /dev/null
+++ b/src/spreadsheet/factory_table.cpp
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "factory_table.hpp"
+#include "formula_global.hpp"
+
+#include "orcus/string_pool.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/sheet.hpp"
+#include "orcus/spreadsheet/auto_filter.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+class table_auto_filter : public iface::import_auto_filter
+{
+ string_pool& m_pool;
+ sheet_t m_sheet_pos;
+ col_t m_cur_col;
+ auto_filter_column_t m_cur_col_data;
+ auto_filter_t m_filter_data;
+
+ auto_filter_t* mp_data;
+
+public:
+ table_auto_filter(document& doc, sheet& sh) :
+ m_pool(doc.get_string_pool()),
+ m_sheet_pos(sh.get_index()),
+ m_cur_col(-1),
+ mp_data(nullptr) {}
+
+ void reset(auto_filter_t* data)
+ {
+ mp_data = data;
+ m_cur_col = -1;
+ m_cur_col_data.reset();
+ m_filter_data.reset();
+ }
+
+ virtual void set_range(const range_t& range)
+ {
+ m_filter_data.range = to_abs_range(range, m_sheet_pos);
+ }
+
+ virtual void set_column(orcus::spreadsheet::col_t col)
+ {
+ m_cur_col = col;
+ }
+
+ virtual void append_column_match_value(std::string_view value)
+ {
+ // The string pool belongs to the document.
+ value = m_pool.intern(value).first;
+ m_cur_col_data.match_values.insert(value);
+ };
+
+ virtual void commit_column()
+ {
+ m_filter_data.commit_column(m_cur_col, m_cur_col_data);
+ m_cur_col_data.reset();
+ }
+
+ virtual void commit()
+ {
+ if (!mp_data)
+ return;
+
+ mp_data->swap(m_filter_data);
+ }
+};
+
+}
+
+struct import_table::impl
+{
+ document& m_doc;
+ sheet& m_sheet;
+
+ table_auto_filter m_auto_filter;
+
+ std::unique_ptr<table_t> mp_data;
+ table_column_t m_column;
+
+ impl(const impl&) = delete;
+ impl& operator=(const impl&) = delete;
+
+ impl(document& doc, sheet& sh) :
+ m_doc(doc), m_sheet(sh), m_auto_filter(doc, sh) {}
+};
+
+import_table::import_table(document& doc, sheet& sh) : mp_impl(std::make_unique<impl>(doc, sh)) {}
+
+import_table::~import_table() {}
+
+iface::import_auto_filter* import_table::get_auto_filter()
+{
+ mp_impl->m_auto_filter.reset(&mp_impl->mp_data->filter);
+ return &mp_impl->m_auto_filter;
+}
+
+void import_table::set_range(const range_t& range)
+{
+ mp_impl->mp_data->range = to_abs_range(range, mp_impl->m_sheet.get_index());
+}
+
+void import_table::set_identifier(size_t id)
+{
+ mp_impl->mp_data->identifier = id;
+}
+
+void import_table::set_name(std::string_view name)
+{
+ string_pool& sp = mp_impl->m_doc.get_string_pool();
+ mp_impl->mp_data->name = sp.intern(name).first;
+}
+
+void import_table::set_display_name(std::string_view name)
+{
+ string_pool& sp = mp_impl->m_doc.get_string_pool();
+ mp_impl->mp_data->display_name = sp.intern(name).first;
+}
+
+void import_table::set_totals_row_count(size_t row_count)
+{
+ mp_impl->mp_data->totals_row_count = row_count;
+}
+
+void import_table::set_column_count(size_t n)
+{
+ mp_impl->mp_data->columns.reserve(n);
+}
+
+void import_table::set_column_identifier(size_t id)
+{
+ mp_impl->m_column.identifier = id;
+}
+
+void import_table::set_column_name(std::string_view name)
+{
+ string_pool& sp = mp_impl->m_doc.get_string_pool();
+ mp_impl->m_column.name = sp.intern(name).first;
+}
+
+void import_table::set_column_totals_row_label(std::string_view label)
+{
+ string_pool& sp = mp_impl->m_doc.get_string_pool();
+ mp_impl->m_column.totals_row_label = sp.intern(label).first;
+}
+
+void import_table::set_column_totals_row_function(orcus::spreadsheet::totals_row_function_t func)
+{
+ mp_impl->m_column.totals_row_function = func;
+}
+
+void import_table::commit_column()
+{
+ mp_impl->mp_data->columns.push_back(mp_impl->m_column);
+ mp_impl->m_column.reset();
+}
+
+void import_table::set_style_name(std::string_view name)
+{
+ table_style_t& style = mp_impl->mp_data->style;
+ string_pool& sp = mp_impl->m_doc.get_string_pool();
+ style.name = sp.intern(name).first;
+}
+
+void import_table::set_style_show_first_column(bool b)
+{
+ table_style_t& style = mp_impl->mp_data->style;
+ style.show_first_column = b;
+}
+
+void import_table::set_style_show_last_column(bool b)
+{
+ table_style_t& style = mp_impl->mp_data->style;
+ style.show_last_column = b;
+}
+
+void import_table::set_style_show_row_stripes(bool b)
+{
+ table_style_t& style = mp_impl->mp_data->style;
+ style.show_row_stripes = b;
+}
+
+void import_table::set_style_show_column_stripes(bool b)
+{
+ table_style_t& style = mp_impl->mp_data->style;
+ style.show_column_stripes = b;
+}
+
+void import_table::commit()
+{
+ mp_impl->m_doc.insert_table(mp_impl->mp_data.release());
+ mp_impl->mp_data.reset(new table_t);
+}
+
+void import_table::reset()
+{
+ mp_impl->mp_data.reset(new table_t);
+ mp_impl->m_column.reset();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_table.hpp b/src/spreadsheet/factory_table.hpp
new file mode 100644
index 0000000..0a274b4
--- /dev/null
+++ b/src/spreadsheet/factory_table.hpp
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_TABLE_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_TABLE_HPP
+
+#include "orcus/spreadsheet/import_interface.hpp"
+
+#include <memory>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+class sheet;
+
+class import_table : public iface::import_table
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_table(document& doc, sheet& sh);
+ ~import_table();
+
+ virtual iface::import_auto_filter* get_auto_filter() override;
+
+ virtual void set_range(const range_t& range) override;
+ virtual void set_identifier(size_t id) override;
+ virtual void set_name(std::string_view name) override;
+ virtual void set_display_name(std::string_view name) override;
+ virtual void set_totals_row_count(size_t row_count) override;
+
+ virtual void set_column_count(size_t n) override;
+
+ virtual void set_column_identifier(size_t id) override;
+ virtual void set_column_name(std::string_view name) override;
+ virtual void set_column_totals_row_label(std::string_view label) override;
+ virtual void set_column_totals_row_function(orcus::spreadsheet::totals_row_function_t func) override;
+ virtual void commit_column() override;
+
+ virtual void set_style_name(std::string_view name) override;
+ virtual void set_style_show_first_column(bool b) override;
+ virtual void set_style_show_last_column(bool b) override;
+ virtual void set_style_show_row_stripes(bool b) override;
+ virtual void set_style_show_column_stripes(bool b) override;
+
+ virtual void commit() override;
+
+ void reset();
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/flat_dumper.cpp b/src/spreadsheet/flat_dumper.cpp
new file mode 100644
index 0000000..9be4245
--- /dev/null
+++ b/src/spreadsheet/flat_dumper.cpp
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "flat_dumper.hpp"
+#include "number_format.hpp"
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/stream.hpp>
+
+#include <ixion/formula.hpp>
+#include <ixion/model_context.hpp>
+#include <ixion/model_iterator.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/cell.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+using std::cout;
+using std::endl;
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+flat_dumper::flat_dumper(const document& doc) : m_doc(doc) {}
+
+void flat_dumper::dump(std::ostream& os, ixion::sheet_t sheet_id) const
+{
+ const ixion::model_context& cxt = m_doc.get_model_context();
+ ixion::abs_range_t range = cxt.get_data_range(sheet_id);
+ if (!range.valid())
+ // Sheet is empty. Nothing to print.
+ return;
+
+ const ixion::formula_name_resolver* resolver =
+ m_doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ if (!resolver)
+ return;
+
+ size_t row_count = range.last.row + 1;
+ size_t col_count = range.last.column + 1;
+ os << "rows: " << row_count << " cols: " << col_count << endl;
+
+ // Always start at the top-left corner.
+ range.first.row = 0;
+ range.first.column = 0;
+ ixion::model_iterator iter = cxt.get_model_iterator(
+ sheet_id, ixion::rc_direction_t::vertical, range);
+
+ std::vector<std::string> mx(row_count*col_count);
+
+ auto to_pos = [col_count](size_t row, size_t col) -> size_t
+ {
+ return col_count * row + col;
+ };
+
+ // Calculate column widths as we iterate.
+ std::vector<size_t> col_widths(col_count, 0);
+ auto it_colwidth = col_widths.begin();
+ col_t current_col = 0;
+
+ for (; iter.has(); iter.next())
+ {
+ const ixion::model_iterator::cell& c = iter.get();
+ if (c.col > current_col)
+ {
+ ++current_col;
+ ++it_colwidth;
+ assert(current_col == c.col);
+ }
+
+ size_t cell_str_width = 0;
+
+ switch (c.type)
+ {
+ case ixion::celltype_t::string:
+ {
+ ixion::string_id_t sindex = std::get<ixion::string_id_t>(c.value);
+ const std::string* p = cxt.get_string(sindex);
+ assert(p);
+ cell_str_width = calc_logical_string_length(*p);
+ mx[to_pos(c.row, c.col)] = std::move(*p);
+ break;
+ }
+ case ixion::celltype_t::numeric:
+ {
+ std::ostringstream os2;
+ format_to_file_output(os2, std::get<double>(c.value));
+ os2 << " [v]";
+ std::string s = os2.str();
+ cell_str_width = calc_logical_string_length(s);
+ mx[to_pos(c.row, c.col)] = std::move(s);
+ break;
+ }
+ case ixion::celltype_t::boolean:
+ {
+ std::ostringstream os2;
+ os2 << (std::get<bool>(c.value) ? "true" : "false") << " [b]";
+ std::string s = os2.str();
+ cell_str_width = calc_logical_string_length(s);
+ mx[to_pos(c.row, c.col)] = std::move(s);
+ break;
+ }
+ case ixion::celltype_t::formula:
+ {
+ // print the formula and the formula result.
+ const ixion::formula_cell* cell = std::get<const ixion::formula_cell*>(c.value);
+ assert(cell);
+ const ixion::formula_tokens_store_ptr_t& ts = cell->get_tokens();
+ if (ts)
+ {
+ const ixion::formula_tokens_t& tokens = ts->get();
+
+ std::ostringstream os2;
+ std::string formula;
+ if (resolver)
+ {
+ ixion::abs_address_t pos(sheet_id, c.row, c.col);
+ pos = cell->get_parent_position(pos);
+ formula = ixion::print_formula_tokens(
+ cxt, pos, *resolver, tokens);
+ }
+ else
+ formula = "???";
+
+ ixion::formula_group_t fg = cell->get_group_properties();
+
+ if (fg.grouped)
+ os2 << '{' << formula << '}';
+ else
+ os2 << formula;
+
+ try
+ {
+ ixion::formula_result res = cell->get_result_cache(
+ ixion::formula_result_wait_policy_t::throw_exception);
+ os2 << " (" << res.str(cxt) << ")";
+ }
+ catch (const std::exception&)
+ {
+ os2 << "(#RES!)";
+ }
+
+ std::string s = os2.str();
+ cell_str_width = calc_logical_string_length(s);
+ mx[to_pos(c.row, c.col)] = std::move(s);
+ }
+ break;
+ }
+ default:
+ ;
+ }
+
+ if (*it_colwidth < cell_str_width)
+ *it_colwidth = cell_str_width;
+ }
+
+ // Create a row separator string;
+ std::ostringstream os2;
+ os2 << '+';
+ for (size_t i = 0; i < col_widths.size(); ++i)
+ {
+ os2 << '-';
+ size_t cw = col_widths[i];
+ for (size_t j = 0; j < cw; ++j)
+ os2 << '-';
+ os2 << "-+";
+ }
+
+ std::string sep = os2.str();
+
+ // Now print to stdout.
+ os << sep << endl;
+ for (size_t r = 0; r < row_count; ++r)
+ {
+ os << "|";
+ for (size_t c = 0; c < col_count; ++c)
+ {
+ size_t cw = col_widths[c]; // column width
+ const std::string& s = mx[to_pos(r, c)];
+ if (s.empty())
+ {
+ for (size_t i = 0; i < cw; ++i)
+ os << ' ';
+ os << " |";
+ }
+ else
+ {
+ os << ' ' << s;
+ cw -= calc_logical_string_length(s);
+ for (size_t i = 0; i < cw; ++i)
+ os << ' ';
+ os << " |";
+ }
+ }
+ os << endl;
+ os << sep << endl;
+ }
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/flat_dumper.hpp b/src/spreadsheet/flat_dumper.hpp
new file mode 100644
index 0000000..2a72938
--- /dev/null
+++ b/src/spreadsheet/flat_dumper.hpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_FLAT_DUMPER_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_FLAT_DUMPER_HPP
+
+#include <string>
+#include <ostream>
+#include <ixion/types.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+
+namespace detail {
+
+class flat_dumper
+{
+ const document& m_doc;
+
+public:
+ flat_dumper(const document& doc);
+
+ void dump(std::ostream& os, ixion::sheet_t sheet_id) const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/spreadsheet/formula_global.cpp b/src/spreadsheet/formula_global.cpp
new file mode 100644
index 0000000..a4d7c6d
--- /dev/null
+++ b/src/spreadsheet/formula_global.cpp
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "formula_global.hpp"
+
+#include <ixion/address.hpp>
+#include <ixion/formula_name_resolver.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+ixion::abs_range_t to_abs_range(
+ const ixion::formula_name_resolver& resolver, const char* p_ref, size_t n_ref)
+{
+ ixion::abs_range_t range(ixion::abs_range_t::invalid);
+ ixion::abs_address_t pos(0,0,0);
+
+ ixion::formula_name_t res = resolver.resolve({p_ref, n_ref}, pos);
+ switch (res.type)
+ {
+ case ixion::formula_name_t::cell_reference:
+ // Single cell reference.
+ range.first = std::get<ixion::address_t>(res.value).to_abs(pos);
+ range.last = range.first;
+ break;
+ case ixion::formula_name_t::range_reference:
+ // Range reference.
+ range = std::get<ixion::range_t>(res.value).to_abs(pos);
+ break;
+ default:
+ ; // Unsupported range. Leave it invalid.
+ }
+
+ return range;
+}
+
+ixion::abs_range_t to_abs_range(const range_t& range, sheet_t sheet_pos)
+{
+ ixion::abs_range_t ret;
+ ret.first.column = range.first.column;
+ ret.first.row = range.first.row;
+ ret.first.sheet = sheet_pos;
+
+ ret.last.column = range.last.column;
+ ret.last.row = range.last.row;
+ ret.last.sheet = sheet_pos;
+
+ return ret;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/formula_global.hpp b/src/spreadsheet/formula_global.hpp
new file mode 100644
index 0000000..9f43a65
--- /dev/null
+++ b/src/spreadsheet/formula_global.hpp
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_FORMULA_GLOBAL_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_FORMULA_GLOBAL_HPP
+
+#include "orcus/spreadsheet/types.hpp"
+
+#include <cstdlib>
+
+namespace ixion {
+
+struct abs_range_t;
+class formula_name_resolver;
+
+}
+
+namespace orcus { namespace spreadsheet {
+
+struct range_t;
+
+/**
+ * Parse a string representing a 2-dimensional range using the passed name
+ * resolver, and return an absolute range object. The sheet index will be
+ * unconditionally set to 0. It returns an invalid range object in case the
+ * parsing fails.
+ *
+ * @param resolver name resolver to use to resolve the range string.
+ * @param p_ref pointer to the first character of the range string.
+ * @param n_ref length of the range string.
+ *
+ * @return absolute range object, which may be set invalid in case the
+ * parsing is unsuccessful.
+ */
+ixion::abs_range_t to_abs_range(
+ const ixion::formula_name_resolver& resolver, const char* p_ref, size_t n_ref);
+
+ixion::abs_range_t to_abs_range(const range_t& range, sheet_t sheet_pos);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/global_settings.cpp b/src/spreadsheet/global_settings.cpp
new file mode 100644
index 0000000..71778bd
--- /dev/null
+++ b/src/spreadsheet/global_settings.cpp
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "global_settings.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+struct import_global_settings::impl
+{
+ import_factory& m_factory;
+ document& m_doc;
+
+ impl(import_factory& factory, document& doc) :
+ m_factory(factory), m_doc(doc) {}
+};
+
+import_global_settings::import_global_settings(import_factory& factory, document& doc) :
+ mp_impl(std::make_unique<impl>(factory, doc)) {}
+
+import_global_settings::~import_global_settings() {}
+
+void import_global_settings::set_origin_date(int year, int month, int day)
+{
+ mp_impl->m_doc.set_origin_date(year, month, day);
+}
+
+void import_global_settings::set_default_formula_grammar(formula_grammar_t grammar)
+{
+ mp_impl->m_doc.set_formula_grammar(grammar);
+}
+
+formula_grammar_t import_global_settings::get_default_formula_grammar() const
+{
+ return mp_impl->m_doc.get_formula_grammar();
+}
+
+void import_global_settings::set_character_set(character_set_t charset)
+{
+ mp_impl->m_factory.set_character_set(charset);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/global_settings.hpp b/src/spreadsheet/global_settings.hpp
new file mode 100644
index 0000000..8213833
--- /dev/null
+++ b/src/spreadsheet/global_settings.hpp
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_GLOBAL_SETTINGS_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_GLOBAL_SETTINGS_HPP
+
+#include "orcus/spreadsheet/import_interface.hpp"
+
+#include <memory>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+class import_factory;
+
+class import_global_settings : public spreadsheet::iface::import_global_settings
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_global_settings(import_factory& factory, document& doc);
+ virtual ~import_global_settings() override;
+
+ virtual void set_origin_date(int year, int month, int day) override;
+
+ virtual void set_default_formula_grammar(orcus::spreadsheet::formula_grammar_t grammar) override;
+
+ virtual orcus::spreadsheet::formula_grammar_t get_default_formula_grammar() const override;
+
+ virtual void set_character_set(character_set_t charset) override;
+};
+
+}}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/html_dumper.cpp b/src/spreadsheet/html_dumper.cpp
new file mode 100644
index 0000000..cdf04de
--- /dev/null
+++ b/src/spreadsheet/html_dumper.cpp
@@ -0,0 +1,695 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "html_dumper.hpp"
+#include "impl_types.hpp"
+#include "number_format.hpp"
+
+#include "orcus/spreadsheet/styles.hpp"
+#include "orcus/spreadsheet/shared_strings.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/sheet.hpp"
+
+#include <ixion/address.hpp>
+#include <ixion/model_context.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/cell.hpp>
+
+#include <sstream>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+namespace {
+
+void build_rgb_color(std::ostringstream& os, const color_t& color_value)
+{
+ // Special colors.
+ if (color_value.alpha == 255 && color_value.red == 0 && color_value.green == 0 && color_value.blue == 0)
+ {
+ os << "black";
+ return;
+ }
+
+ if (color_value.alpha == 255 && color_value.red == 255 && color_value.green == 0 && color_value.blue == 0)
+ {
+ os << "red";
+ return;
+ }
+
+ if (color_value.alpha == 255 && color_value.red == 0 && color_value.green == 255 && color_value.blue == 0)
+ {
+ os << "green";
+ return;
+ }
+
+ if (color_value.alpha == 255 && color_value.red == 0 && color_value.green == 0 && color_value.blue == 255)
+ {
+ os << "blue";
+ return;
+ }
+
+ os << "rgb("
+ << static_cast<short>(color_value.red) << ","
+ << static_cast<short>(color_value.green) << ","
+ << static_cast<short>(color_value.blue) << ")";
+}
+
+const char* css_style_global =
+"table, td { "
+ "border-collapse : collapse; "
+"}\n"
+
+"table { "
+ "border-spacing : 0px; "
+"}\n"
+
+"td { "
+ "width : 1in; border: 1px solid lightgray; "
+"}\n"
+
+"td.empty { "
+ "color : white; "
+"}\n";
+
+class html_elem
+{
+public:
+ struct attr
+ {
+ std::string name;
+ std::string value;
+
+ attr(const std::string& _name, const std::string& _value) : name(_name), value(_value) {}
+ };
+
+ typedef std::vector<attr> attrs_type;
+
+ html_elem(std::ostream& strm, const char* name, const char* style = nullptr, const char* style_class = nullptr) :
+ m_strm(strm), m_name(name)
+ {
+ m_strm << '<' << m_name;
+
+ if (style)
+ m_strm << " style=\"" << style << "\"";
+
+ if (style_class)
+ m_strm << " class=\"" << style_class << "\"";
+
+ m_strm << '>';
+ }
+
+ html_elem(std::ostream& strm, const char* name, const attrs_type& attrs) :
+ m_strm(strm), m_name(name)
+ {
+ m_strm << '<' << m_name;
+
+ attrs_type::const_iterator it = attrs.begin(), it_end = attrs.end();
+ for (; it != it_end; ++it)
+ m_strm << " " << it->name << "=\"" << it->value << "\"";
+
+ m_strm << '>';
+ }
+
+ ~html_elem()
+ {
+ m_strm << "</" << m_name << '>';
+ }
+
+private:
+ std::ostream& m_strm;
+ const char* m_name;
+};
+
+void print_formatted_text(std::ostream& strm, const std::string& text, const format_runs_t& formats)
+{
+ typedef html_elem elem;
+
+ const char* p_span = "span";
+
+ size_t pos = 0;
+ format_runs_t::const_iterator itr = formats.begin(), itr_end = formats.end();
+ for (; itr != itr_end; ++itr)
+ {
+ const format_run& run = *itr;
+ if (pos < run.pos)
+ {
+ // flush unformatted text.
+ strm << std::string(&text[pos], run.pos-pos);
+ pos = run.pos;
+ }
+
+ if (!run.size)
+ continue;
+
+ std::string style = "";
+ if (run.bold)
+ style += "font-weight: bold;";
+ else
+ style += "font-weight: normal;";
+
+ if (run.italic)
+ style += "font-style: italic;";
+ else
+ style += "font-style: normal;";
+
+ if (!run.font.empty())
+ {
+ style += "font-family: ";
+ style += run.font;
+ style += ";";
+ }
+
+ if (run.font_size)
+ {
+ std::ostringstream os;
+ os << "font-size: " << run.font_size << "pt;";
+ style += os.str();
+ }
+
+ const color_t& col = run.color;
+ if (col.red || col.green || col.blue)
+ {
+ std::ostringstream os;
+ os << "color: ";
+ build_rgb_color(os, col);
+ os << ";";
+ style += os.str();
+ }
+
+ if (style.empty())
+ strm << std::string(&text[pos], run.size);
+ else
+ {
+ elem span(strm, p_span, style.c_str());
+ strm << std::string(&text[pos], run.size);
+ }
+
+ pos += run.size;
+ }
+
+ if (pos < text.size())
+ {
+ // flush the remaining unformatted text.
+ strm << std::string(&text[pos], text.size() - pos);
+ }
+}
+
+void build_border_style(std::ostringstream& os, const char* style_name, const border_attrs_t& attrs)
+{
+ if (!attrs.style || *attrs.style == border_style_t::none)
+ return;
+
+ os << style_name << ": ";
+ switch (*attrs.style)
+ {
+ case border_style_t::thin:
+ {
+ os << "solid 1px ";
+ break;
+ }
+ case border_style_t::medium:
+ {
+ os << "solid 2px ";
+ break;
+ }
+ case border_style_t::thick:
+ {
+ os << "solid 3px ";
+ break;
+ }
+ case border_style_t::hair:
+ {
+ os << "solid 0.5px ";
+ break;
+ }
+ case border_style_t::dotted:
+ {
+ os << "dotted 1px ";
+ break;
+ }
+ case border_style_t::dashed:
+ {
+ os << "dashed 1px ";
+ break;
+ }
+ case border_style_t::double_border:
+ {
+ os << "3px double ";
+ break;
+ }
+ case border_style_t::dash_dot:
+ {
+ // CSS doesn't support dash-dot.
+ os << "dashed 1px ";
+ break;
+ }
+ case border_style_t::dash_dot_dot:
+ {
+ // CSS doesn't support dash-dot-dot.
+ os << "dashed 1px ";
+ break;
+ }
+ case border_style_t::medium_dashed:
+ {
+ os << "dashed 2px ";
+ break;
+ }
+ case border_style_t::medium_dash_dot:
+ {
+ // CSS doesn't support dash-dot.
+ os << "dashed 2px ";
+ break;
+ }
+ case border_style_t::medium_dash_dot_dot:
+ {
+ // CSS doesn't support dash-dot-dot.
+ os << "dashed 2px ";
+ break;
+ }
+ case border_style_t::slant_dash_dot:
+ {
+ // CSS doesn't support dash-dot.
+ os << "dashed 2px ";
+ break;
+ }
+ default:;
+ }
+
+ build_rgb_color(os, *attrs.border_color);
+ os << "; ";
+}
+
+void build_style_string(std::string& str, const styles& styles, const cell_format_t& fmt)
+{
+ std::ostringstream os;
+
+ {
+ const font_t* p = styles.get_font(fmt.font);
+ if (p)
+ {
+ if (p->name && !p->name.value().empty())
+ os << "font-family: " << *p->name << ";";
+ if (p->size)
+ os << "font-size: " << *p->size << "pt;";
+ if (p->bold && *p->bold)
+ os << "font-weight: bold;";
+ if (p->italic && *p->italic)
+ os << "font-style: italic;";
+
+ if (p->color)
+ {
+ const color_t& r = *p->color;
+ if (r.red || r.green || r.blue)
+ {
+ os << "color: ";
+ build_rgb_color(os, r);
+ os << ";";
+ }
+ }
+ }
+ }
+
+ {
+ const fill_t* p = styles.get_fill(fmt.fill);
+ if (p)
+ {
+ if (p->pattern_type && *p->pattern_type == fill_pattern_t::solid && p->fg_color)
+ {
+ const color_t& r = *p->fg_color;
+ os << "background-color: ";
+ build_rgb_color(os, r);
+ os << ";";
+ }
+ }
+ }
+
+ {
+ const border_t* p = styles.get_border(fmt.border);
+ if (p)
+ {
+ build_border_style(os, "border-top", p->top);
+ build_border_style(os, "border-bottom", p->bottom);
+ build_border_style(os, "border-left", p->left);
+ build_border_style(os, "border-right", p->right);
+ }
+ }
+
+ if (fmt.apply_alignment)
+ {
+ if (fmt.hor_align != hor_alignment_t::unknown)
+ {
+ os << "text-align: ";
+ switch (fmt.hor_align)
+ {
+ case hor_alignment_t::left:
+ os << "left";
+ break;
+ case hor_alignment_t::center:
+ os << "center";
+ break;
+ case hor_alignment_t::right:
+ os << "right";
+ break;
+ default:
+ ;
+ }
+ os << ";";
+ }
+
+ if (fmt.ver_align != ver_alignment_t::unknown)
+ {
+ os << "vertical-align: ";
+ switch (fmt.ver_align)
+ {
+ case ver_alignment_t::top:
+ os << "top";
+ break;
+ case ver_alignment_t::middle:
+ os << "middle";
+ break;
+ case ver_alignment_t::bottom:
+ os << "bottom";
+ break;
+ default:
+ ;
+ }
+ os << ";";
+ }
+ }
+
+ str += os.str();
+}
+
+void dump_html_head(std::ostream& os)
+{
+ typedef html_elem elem;
+
+ const char* p_head = "head";
+ const char* p_style = "style";
+
+ elem elem_head(os, p_head);
+ {
+ elem elem_style(os, p_style);
+ os << css_style_global;
+ }
+}
+
+void build_html_elem_attributes(html_elem::attrs_type& attrs, const std::string& style, const merge_size* p_merge_size)
+{
+ attrs.push_back(html_elem::attr("style", style));
+ if (p_merge_size)
+ {
+ if (p_merge_size->width > 1)
+ {
+ std::ostringstream os2;
+ os2 << p_merge_size->width;
+ attrs.push_back(html_elem::attr("colspan", os2.str()));
+ }
+
+ if (p_merge_size->height > 1)
+ {
+ std::ostringstream os2;
+ os2 << p_merge_size->height;
+ attrs.push_back(html_elem::attr("rowspan", os2.str()));
+ }
+ }
+}
+
+}
+
+html_dumper::html_dumper(
+ const document& doc,
+ const col_merge_size_type& merge_ranges,
+ sheet_t sheet_id) :
+ m_doc(doc),
+ m_merge_ranges(merge_ranges),
+ m_sheet_id(sheet_id)
+{
+ build_overlapped_ranges();
+}
+
+void html_dumper::dump(std::ostream& os) const
+{
+ const sheet* sh = m_doc.get_sheet(m_sheet_id);
+ if (!sh)
+ return;
+
+ typedef html_elem elem;
+
+ const char* p_html = "html";
+ const char* p_body = "body";
+ const char* p_table = "table";
+ const char* p_tr = "tr";
+ const char* p_td = "td";
+
+ ixion::abs_range_t range = sh->get_data_range();
+
+ elem root(os, p_html);
+ dump_html_head(os);
+
+ {
+ elem elem_body(os, p_body);
+
+ if (!range.valid())
+ // Sheet is empty. Nothing to print.
+ return;
+
+ const ixion::model_context& cxt = m_doc.get_model_context();
+ const ixion::formula_name_resolver* resolver =
+ m_doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ const shared_strings& sstrings = m_doc.get_shared_strings();
+
+ elem table(os, p_table);
+
+ row_t row_count = range.last.row + 1;
+ col_t col_count = range.last.column + 1;
+ for (row_t row = 0; row < row_count; ++row)
+ {
+ // Set the row height.
+ std::string row_style;
+ row_height_t rh = sh->get_row_height(row, nullptr, nullptr);
+
+ // Convert height from twip to inches.
+ if (rh != get_default_row_height())
+ {
+ std::string style;
+ double val = orcus::convert(rh, length_unit_t::twip, length_unit_t::inch);
+ std::ostringstream os_style;
+ os_style << "height: " << val << "in;";
+ row_style += os_style.str();
+ }
+
+ const char* style_str = nullptr;
+ if (!row_style.empty())
+ style_str = row_style.c_str();
+ elem tr(os, p_tr, style_str);
+
+ const detail::overlapped_col_index_type* p_overlapped = get_overlapped_ranges(row);
+
+ for (col_t col = 0; col < col_count; ++col)
+ {
+ ixion::abs_address_t pos(m_sheet_id, row, col);
+
+ const merge_size* p_merge_size = get_merge_size(row, col);
+ if (!p_merge_size && p_overlapped)
+ {
+ // Check if this cell is overlapped by a merged cell.
+ col_t overlapped_origin = -1;
+ col_t last_col = -1;
+ if (p_overlapped->search_tree(col, overlapped_origin, nullptr, &last_col).second && overlapped_origin >= 0)
+ {
+ // Skip all overlapped cells on this row.
+ col = last_col - 1;
+ continue;
+ }
+ }
+ size_t xf_id = sh->get_cell_format(row, col);
+ std::string style;
+
+ if (row == 0)
+ {
+ // Set the column width.
+ col_width_t cw = sh->get_col_width(col, nullptr, nullptr);
+
+ // Convert width from twip to inches.
+ if (cw != get_default_column_width())
+ {
+ double val = orcus::convert(cw, length_unit_t::twip, length_unit_t::inch);
+ std::ostringstream os_style;
+ os_style << "width: " << val << "in;";
+ style += os_style.str();
+ }
+ }
+
+ {
+ // Apply cell format.
+ const styles& styles = m_doc.get_styles();
+ const cell_format_t* fmt = styles.get_cell_format(xf_id);
+ if (fmt)
+ build_style_string(style, styles, *fmt);
+ }
+
+ ixion::celltype_t ct = cxt.get_celltype(pos);
+ if (ct == ixion::celltype_t::empty)
+ {
+ html_elem::attrs_type attrs;
+ build_html_elem_attributes(attrs, style, p_merge_size);
+ attrs.push_back(html_elem::attr("class", "empty"));
+ elem td(os, p_td, attrs);
+ os << '-'; // empty cell.
+ continue;
+ }
+
+ html_elem::attrs_type attrs;
+ build_html_elem_attributes(attrs, style, p_merge_size);
+ elem td(os, p_td, attrs);
+
+ switch (ct)
+ {
+ case ixion::celltype_t::string:
+ {
+ size_t sindex = cxt.get_string_identifier(pos);
+ const std::string* p = cxt.get_string(sindex);
+ assert(p);
+ const format_runs_t* pformat = sstrings.get_format_runs(sindex);
+ if (pformat)
+ print_formatted_text(os, *p, *pformat);
+ else
+ os << *p;
+
+ break;
+ }
+ case ixion::celltype_t::numeric:
+ format_to_file_output(os, cxt.get_numeric_value(pos));
+ break;
+ case ixion::celltype_t::boolean:
+ os << (cxt.get_boolean_value(pos) ? "true" : "false");
+ break;
+ case ixion::celltype_t::formula:
+ {
+ // print the formula and the formula result.
+ const ixion::formula_cell* cell = cxt.get_formula_cell(pos);
+ assert(cell);
+ const ixion::formula_tokens_store_ptr_t& ts = cell->get_tokens();
+ if (ts)
+ {
+ const ixion::formula_tokens_t& tokens = ts->get();
+
+ std::string formula;
+ if (resolver)
+ {
+ pos = cell->get_parent_position(pos);
+ formula = ixion::print_formula_tokens(
+ m_doc.get_model_context(), pos, *resolver, tokens);
+ }
+ else
+ formula = "???";
+
+ ixion::formula_group_t fg = cell->get_group_properties();
+
+ if (fg.grouped)
+ os << '{' << formula << '}';
+ else
+ os << formula;
+
+ try
+ {
+ ixion::formula_result res = cell->get_result_cache(
+ ixion::formula_result_wait_policy_t::throw_exception);
+ os << " (" << res.str(m_doc.get_model_context()) << ")";
+ }
+ catch (const std::exception&)
+ {
+ os << " (#RES!)";
+ }
+ }
+
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ }
+ }
+}
+
+const overlapped_col_index_type* html_dumper::get_overlapped_ranges(row_t row) const
+{
+ overlapped_cells_type::const_iterator it = m_overlapped_ranges.find(row);
+ if (it == m_overlapped_ranges.end())
+ return nullptr;
+
+ return it->second.get();
+}
+
+const merge_size* html_dumper::get_merge_size(row_t row, col_t col) const
+{
+ col_merge_size_type::const_iterator it_col = m_merge_ranges.find(col);
+ if (it_col == m_merge_ranges.end())
+ return nullptr;
+
+ merge_size_type& col_merge_sizes = *it_col->second;
+ merge_size_type::const_iterator it_row = col_merge_sizes.find(row);
+ if (it_row == col_merge_sizes.end())
+ return nullptr;
+
+ return &it_row->second;
+}
+
+void html_dumper::build_overlapped_ranges()
+{
+ const sheet* sh = m_doc.get_sheet(m_sheet_id);
+ if (!sh)
+ return;
+
+ range_size_t sheet_size = m_doc.get_sheet_size();
+
+ detail::col_merge_size_type::const_iterator it_col = m_merge_ranges.begin(), it_col_end = m_merge_ranges.end();
+ for (; it_col != it_col_end; ++it_col)
+ {
+ col_t col = it_col->first;
+ const detail::merge_size_type& data = *it_col->second;
+ detail::merge_size_type::const_iterator it = data.begin(), it_end = data.end();
+ for (; it != it_end; ++it)
+ {
+ row_t row = it->first;
+ const detail::merge_size& item = it->second;
+ for (row_t i = 0; i < item.height; ++i, ++row)
+ {
+ // Get the container for this row.
+ detail::overlapped_cells_type::iterator it_cont = m_overlapped_ranges.find(row);
+ if (it_cont == m_overlapped_ranges.end())
+ {
+ auto p = std::make_unique<detail::overlapped_col_index_type>(0, sheet_size.columns, -1);
+ std::pair<detail::overlapped_cells_type::iterator, bool> r =
+ m_overlapped_ranges.insert(detail::overlapped_cells_type::value_type(row, std::move(p)));
+
+ if (!r.second)
+ {
+ // Insertion failed.
+ return;
+ }
+
+ it_cont = r.first;
+ }
+
+ detail::overlapped_col_index_type& cont = *it_cont->second;
+ cont.insert_back(col, col+item.width, col);
+ }
+ }
+ }
+
+ // Build trees.
+ for (auto& range : m_overlapped_ranges)
+ range.second->build_tree();
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/html_dumper.hpp b/src/spreadsheet/html_dumper.hpp
new file mode 100644
index 0000000..4e66809
--- /dev/null
+++ b/src/spreadsheet/html_dumper.hpp
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_HTML_DUMPER_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_HTML_DUMPER_HPP
+
+#include <string>
+#include <ostream>
+#include <ixion/types.hpp>
+
+#include "impl_types.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+
+namespace detail {
+
+class html_dumper
+{
+ const document& m_doc;
+ overlapped_cells_type m_overlapped_ranges;
+ const col_merge_size_type& m_merge_ranges;
+ sheet_t m_sheet_id;
+
+ const overlapped_col_index_type* get_overlapped_ranges(row_t row) const;
+ const merge_size* get_merge_size(row_t row, col_t col) const;
+
+ void build_overlapped_ranges();
+
+public:
+ html_dumper(
+ const document& doc,
+ const col_merge_size_type& merge_ranges,
+ sheet_t sheet_id);
+
+ void dump(std::ostream& os) const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/spreadsheet/impl_types.hpp b/src/spreadsheet/impl_types.hpp
new file mode 100644
index 0000000..bed30db
--- /dev/null
+++ b/src/spreadsheet/impl_types.hpp
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_DETAIL_IMPL_TYPES_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_DETAIL_IMPL_TYPES_HPP
+
+#include "orcus/spreadsheet/types.hpp"
+
+#include <mdds/flat_segment_tree.hpp>
+#include <unordered_map>
+#include <memory>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+struct merge_size
+{
+ col_t width;
+ row_t height;
+
+ merge_size(col_t _width, row_t _height) :
+ width(_width), height(_height) {}
+};
+
+// Merged cell data stored in sheet.
+typedef std::unordered_map<row_t, detail::merge_size> merge_size_type;
+typedef std::unordered_map<col_t, std::unique_ptr<merge_size_type>> col_merge_size_type;
+
+// Overlapped cells per row, used when rendering sheet content.
+typedef mdds::flat_segment_tree<col_t, col_t> overlapped_col_index_type;
+typedef std::unordered_map<row_t, std::unique_ptr<overlapped_col_index_type>> overlapped_cells_type;
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/json_dumper.cpp b/src/spreadsheet/json_dumper.cpp
new file mode 100644
index 0000000..3fe6184
--- /dev/null
+++ b/src/spreadsheet/json_dumper.cpp
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "json_dumper.hpp"
+#include "dumper_global.hpp"
+
+#include "orcus/json_global.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/model_context.hpp>
+#include <ixion/formula_name_resolver.hpp>
+
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+json_dumper::json_dumper(const document& doc) : m_doc(doc) {}
+
+void json_dumper::dump(std::ostream& os, ixion::sheet_t sheet_id) const
+{
+ const ixion::model_context& cxt = m_doc.get_model_context();
+ ixion::abs_range_t data_range = cxt.get_data_range(sheet_id);
+ if (!data_range.valid())
+ return;
+
+ ixion::abs_rc_range_t iter_range;
+ iter_range.first.column = 0;
+ iter_range.first.row = 0;
+ iter_range.last.column = data_range.last.column;
+ iter_range.last.row = data_range.last.row;
+
+ auto iter = cxt.get_model_iterator(
+ sheet_id, ixion::rc_direction_t::horizontal, iter_range);
+
+ std::vector<std::string> column_labels;
+ column_labels.reserve(data_range.last.column+1);
+
+ // Get the column labels.
+ auto resolver = ixion::formula_name_resolver::get(ixion::formula_name_resolver_t::excel_a1, &cxt);
+ for (ixion::col_t i = 0; i <= data_range.last.column; ++i)
+ column_labels.emplace_back(resolver->get_column_name(i));
+
+ os << "[" << std::endl;
+
+ ixion::row_t row = iter.get().row;
+ ixion::col_t col = iter.get().col;
+ assert(row == 0);
+ assert(col == 0);
+
+ os << " {";
+ os << "\"" << column_labels[col] << "\": ";
+
+ func_str_handler str_handler = [](std::ostream& _os, const std::string& s)
+ {
+ _os << '"' << json::escape_string(s) << '"';
+ };
+
+ func_empty_handler empty_handler = [](std::ostream& _os) { _os << "null"; };
+
+ dump_cell_value(os, cxt, iter.get(), str_handler, empty_handler);
+
+ ixion::row_t last_row = row;
+
+ for (iter.next(); iter.has(); iter.next())
+ {
+ const auto& cell = iter.get();
+ ixion::row_t this_row = cell.row;
+ ixion::col_t this_col = cell.col;
+
+ if (this_row > last_row)
+ os << "}," << std::endl;
+
+ if (this_col == 0)
+ os << " {";
+ else
+ os << ", ";
+
+ os << "\"" << column_labels.at(this_col) << "\": ";
+
+ dump_cell_value(os, cxt, cell, str_handler, empty_handler);
+ last_row = this_row;
+ }
+
+ os << "}" << std::endl << "]" << std::endl;
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/json_dumper.hpp b/src/spreadsheet/json_dumper.hpp
new file mode 100644
index 0000000..a695091
--- /dev/null
+++ b/src/spreadsheet/json_dumper.hpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_JSON_DUMPER_HPP
+#define INCLUDED_ORCUS_JSON_DUMPER_HPP
+
+#include <string>
+#include <ostream>
+
+#include <ixion/types.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+
+namespace detail {
+
+class json_dumper
+{
+ const document& m_doc;
+
+public:
+ json_dumper(const document& doc);
+
+ void dump(std::ostream& os, ixion::sheet_t sheet_id) const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/number_format.cpp b/src/spreadsheet/number_format.cpp
new file mode 100644
index 0000000..1823ef0
--- /dev/null
+++ b/src/spreadsheet/number_format.cpp
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "number_format.hpp"
+#include "ostream_utils.hpp"
+
+#include <ostream>
+#include <iomanip>
+#include <limits>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+void format_to_file_output(std::ostream& os, double v)
+{
+ ::orcus::detail::ostream_format_guard guard(os);
+ os << std::setprecision(std::numeric_limits<double>::digits10 + 1) << v;
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/number_format.hpp b/src/spreadsheet/number_format.hpp
new file mode 100644
index 0000000..ea18847
--- /dev/null
+++ b/src/spreadsheet/number_format.hpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_NUMBER_FORMAT_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_NUMBER_FORMAT_HPP
+
+#include <iosfwd>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+/**
+ * Format a numeric value to a lossless string representation appripriate
+ * for file output.
+ *
+ * @param os output stream to add the string representation to.
+ * @param v source numeric value to format.
+ */
+void format_to_file_output(std::ostream& os, double v);
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/pivot.cpp b/src/spreadsheet/pivot.cpp
new file mode 100644
index 0000000..4bc21ee
--- /dev/null
+++ b/src/spreadsheet/pivot.cpp
@@ -0,0 +1,371 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/spreadsheet/pivot.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/string_pool.hpp"
+
+#include <ixion/address.hpp>
+
+#include <unordered_map>
+#include <cassert>
+#include <sstream>
+
+namespace orcus { namespace spreadsheet {
+
+pivot_cache_record_value_t::pivot_cache_record_value_t() :
+ type(record_type::unknown), value(false) {}
+
+pivot_cache_record_value_t::pivot_cache_record_value_t(std::string_view s) :
+ type(record_type::character), value(s)
+{
+}
+
+pivot_cache_record_value_t::pivot_cache_record_value_t(double v) :
+ type(record_type::numeric), value(v)
+{
+}
+
+pivot_cache_record_value_t::pivot_cache_record_value_t(size_t index) :
+ type(record_type::shared_item_index), value(index)
+{
+}
+
+bool pivot_cache_record_value_t::operator== (const pivot_cache_record_value_t& other) const
+{
+ return type == other.type && value == other.value;
+}
+
+bool pivot_cache_record_value_t::operator!= (const pivot_cache_record_value_t& other) const
+{
+ return !operator==(other);
+}
+
+pivot_cache_item_t::pivot_cache_item_t() : type(item_type::unknown) {}
+
+pivot_cache_item_t::pivot_cache_item_t(std::string_view s) :
+ type(item_type::character), value(s)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(double numeric) :
+ type(item_type::numeric), value(numeric)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(bool boolean) :
+ type(item_type::boolean), value(boolean)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(const date_time_t& date_time) :
+ type(item_type::date_time), value(date_time)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(error_value_t error) :
+ type(item_type::error), value(error)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(const pivot_cache_item_t& other) :
+ type(other.type), value(other.value)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(pivot_cache_item_t&& other) :
+ type(other.type), value(std::move(other.value))
+{
+ other.type = item_type::unknown;
+ other.value = false;
+}
+
+bool pivot_cache_item_t::operator< (const pivot_cache_item_t& other) const
+{
+ if (type != other.type)
+ return type < other.type;
+
+ return value < other.value;
+}
+
+bool pivot_cache_item_t::operator== (const pivot_cache_item_t& other) const
+{
+ return type == other.type && value == other.value;
+}
+
+pivot_cache_item_t& pivot_cache_item_t::operator= (pivot_cache_item_t other)
+{
+ swap(other);
+ return *this;
+}
+
+void pivot_cache_item_t::swap(pivot_cache_item_t& other)
+{
+ std::swap(type, other.type);
+ std::swap(value, other.value);
+}
+
+pivot_cache_group_data_t::pivot_cache_group_data_t(size_t _base_field) :
+ base_field(_base_field) {}
+
+pivot_cache_group_data_t::pivot_cache_group_data_t(const pivot_cache_group_data_t& other) :
+ base_to_group_indices(other.base_to_group_indices),
+ range_grouping(other.range_grouping),
+ items(other.items),
+ base_field(other.base_field) {}
+
+pivot_cache_group_data_t::pivot_cache_group_data_t(pivot_cache_group_data_t&& other) :
+ base_to_group_indices(std::move(other.base_to_group_indices)),
+ range_grouping(std::move(other.range_grouping)),
+ items(std::move(other.items)),
+ base_field(other.base_field) {}
+
+pivot_cache_field_t::pivot_cache_field_t() {}
+
+pivot_cache_field_t::pivot_cache_field_t(std::string_view _name) : name(_name) {}
+
+pivot_cache_field_t::pivot_cache_field_t(const pivot_cache_field_t& other) :
+ name(other.name),
+ items(other.items),
+ min_value(other.min_value),
+ max_value(other.max_value),
+ min_date(other.min_date),
+ max_date(other.max_date),
+ group_data(std::make_unique<pivot_cache_group_data_t>(*other.group_data)) {}
+
+pivot_cache_field_t::pivot_cache_field_t(pivot_cache_field_t&& other) :
+ name(other.name),
+ items(std::move(other.items)),
+ min_value(std::move(other.min_value)),
+ max_value(std::move(other.max_value)),
+ min_date(std::move(other.min_date)),
+ max_date(std::move(other.max_date)),
+ group_data(std::move(other.group_data))
+{
+ other.name = std::string_view{};
+}
+
+struct pivot_cache::impl
+{
+ pivot_cache_id_t m_cache_id;
+
+ string_pool& m_string_pool;
+
+ std::string_view m_src_sheet_name;
+
+ pivot_cache::fields_type m_fields;
+
+ pivot_cache::records_type m_records;
+
+ impl(pivot_cache_id_t cache_id, string_pool& sp) :
+ m_cache_id(cache_id), m_string_pool(sp) {}
+};
+
+pivot_cache::pivot_cache(pivot_cache_id_t cache_id, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(cache_id, sp)) {}
+
+pivot_cache::~pivot_cache() {}
+
+void pivot_cache::insert_fields(fields_type fields)
+{
+ mp_impl->m_fields = std::move(fields);
+}
+
+void pivot_cache::insert_records(records_type records)
+{
+ mp_impl->m_records = std::move(records);
+}
+
+size_t pivot_cache::get_field_count() const
+{
+ return mp_impl->m_fields.size();
+}
+
+const pivot_cache_field_t* pivot_cache::get_field(size_t index) const
+{
+ return index < mp_impl->m_fields.size() ? &mp_impl->m_fields[index] : nullptr;
+}
+
+pivot_cache_id_t pivot_cache::get_id() const
+{
+ return mp_impl->m_cache_id;
+}
+
+const pivot_cache::records_type& pivot_cache::get_all_records() const
+{
+ return mp_impl->m_records;
+}
+
+namespace {
+
+constexpr const ixion::sheet_t ignored_sheet = -1;
+
+struct worksheet_range
+{
+ std::string_view sheet; /// it must be an interned string with the document.
+ ixion::abs_range_t range; /// sheet indices are ignored.
+
+ worksheet_range(std::string_view _sheet, ixion::abs_range_t _range) :
+ sheet(std::move(_sheet)), range(std::move(_range))
+ {
+ range.first.sheet = ignored_sheet;
+ range.last.sheet = ignored_sheet;
+ }
+
+ bool operator== (const worksheet_range& other) const
+ {
+ return sheet == other.sheet && range == other.range;
+ }
+
+ struct hash
+ {
+ std::hash<std::string_view> ps_hasher;
+ ixion::abs_range_t::hash range_hasher;
+
+ size_t operator() (const worksheet_range& v) const
+ {
+ assert(v.range.first.sheet == ignored_sheet);
+ assert(v.range.last.sheet == ignored_sheet);
+
+ size_t n = ps_hasher(v.sheet);
+ n ^= range_hasher(v.range);
+ return n;
+ }
+ };
+};
+
+using range_map_type = std::unordered_map<worksheet_range, std::unordered_set<pivot_cache_id_t>, worksheet_range::hash>;
+using name_map_type = std::unordered_map<std::string_view, std::unordered_set<pivot_cache_id_t>>;
+
+using caches_type = std::unordered_map<pivot_cache_id_t, std::unique_ptr<pivot_cache>>;
+
+}
+
+struct pivot_collection::impl
+{
+ document& m_doc;
+
+ range_map_type m_worksheet_range_map; /// mapping of sheet name & range pair to cache ID.
+ name_map_type m_table_map; /// mapping of table name to cache ID.
+
+ caches_type m_caches;
+
+ impl(document& doc) : m_doc(doc) {}
+
+ void ensure_unique_cache(pivot_cache_id_t cache_id)
+ {
+ if (m_caches.count(cache_id) > 0)
+ {
+ std::ostringstream os;
+ os << "Pivot cache with the ID of " << cache_id << " already exists.";
+ throw std::invalid_argument(os.str());
+ }
+ }
+};
+
+pivot_collection::pivot_collection(document& doc) : mp_impl(std::make_unique<impl>(doc)) {}
+
+pivot_collection::~pivot_collection() {}
+
+void pivot_collection::insert_worksheet_cache(
+ std::string_view sheet_name, const ixion::abs_range_t& range,
+ std::unique_ptr<pivot_cache>&& cache)
+{
+ // First, ensure that no caches exist for the cache ID.
+ pivot_cache_id_t cache_id = cache->get_id();
+ mp_impl->ensure_unique_cache(cache_id);
+
+ // Check and see if there is already a cache for this location. If yes,
+ // overwrite the existing cache.
+ mp_impl->m_caches[cache_id] = std::move(cache);
+
+ worksheet_range key(sheet_name, range);
+
+ range_map_type& range_map = mp_impl->m_worksheet_range_map;
+ auto it = range_map.find(key);
+
+ if (it == range_map.end())
+ {
+ // sheet name must be interned with the document it belongs to.
+ key.sheet = mp_impl->m_doc.get_string_pool().intern(key.sheet).first;
+ range_map.insert(range_map_type::value_type(std::move(key), {cache_id}));
+ return;
+ }
+
+ auto& id_set = it->second;
+ id_set.insert(cache_id);
+}
+
+void pivot_collection::insert_worksheet_cache(
+ std::string_view table_name, std::unique_ptr<pivot_cache>&& cache)
+{
+ // First, ensure that no caches exist for the cache ID.
+ pivot_cache_id_t cache_id = cache->get_id();
+ mp_impl->ensure_unique_cache(cache_id);
+
+ mp_impl->m_caches[cache_id] = std::move(cache);
+
+ name_map_type& name_map = mp_impl->m_table_map;
+ auto it = name_map.find(table_name);
+
+ if (it == name_map.end())
+ {
+ // First cache to be associated with this name.
+ std::string_view table_name_interned =
+ mp_impl->m_doc.get_string_pool().intern(table_name).first;
+ name_map.insert(name_map_type::value_type(table_name_interned, {cache_id}));
+ return;
+ }
+
+ auto& id_set = it->second;
+ id_set.insert(cache_id);
+}
+
+size_t pivot_collection::get_cache_count() const
+{
+ return mp_impl->m_caches.size();
+}
+
+const pivot_cache* pivot_collection::get_cache(
+ std::string_view sheet_name, const ixion::abs_range_t& range) const
+{
+ worksheet_range wr(sheet_name, range);
+
+ auto it = mp_impl->m_worksheet_range_map.find(wr);
+ if (it == mp_impl->m_worksheet_range_map.end())
+ return nullptr;
+
+ // Pick the first cache ID.
+ assert(!it->second.empty());
+ pivot_cache_id_t cache_id = *it->second.cbegin();
+ return mp_impl->m_caches[cache_id].get();
+}
+
+namespace {
+
+template<typename _CachesT, typename _CacheT>
+_CacheT* get_cache_impl(_CachesT& caches, pivot_cache_id_t cache_id)
+{
+ auto it = caches.find(cache_id);
+ return it == caches.end() ? nullptr : it->second.get();
+}
+
+}
+
+pivot_cache* pivot_collection::get_cache(pivot_cache_id_t cache_id)
+{
+ return get_cache_impl<caches_type, pivot_cache>(mp_impl->m_caches, cache_id);
+}
+
+const pivot_cache* pivot_collection::get_cache(pivot_cache_id_t cache_id) const
+{
+ return get_cache_impl<const caches_type, const pivot_cache>(mp_impl->m_caches, cache_id);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/shared_formula.cpp b/src/spreadsheet/shared_formula.cpp
new file mode 100644
index 0000000..e17a0ee
--- /dev/null
+++ b/src/spreadsheet/shared_formula.cpp
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "shared_formula.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+shared_formula_pool::shared_formula_pool() {}
+shared_formula_pool::~shared_formula_pool() {}
+
+void shared_formula_pool::add(
+ size_t sf_index, const ixion::formula_tokens_store_ptr_t& sf_tokens)
+{
+ m_store.emplace(sf_index, sf_tokens);
+}
+
+ixion::formula_tokens_store_ptr_t shared_formula_pool::get(size_t sf_index) const
+{
+ auto it = m_store.find(sf_index);
+ if (it == m_store.end())
+ return ixion::formula_tokens_store_ptr_t();
+
+ return it->second;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/shared_formula.hpp b/src/spreadsheet/shared_formula.hpp
new file mode 100644
index 0000000..a72c9f3
--- /dev/null
+++ b/src/spreadsheet/shared_formula.hpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_SHARED_FORMULA_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_SHARED_FORMULA_HPP
+
+#include <ixion/formula_tokens.hpp>
+
+#include <unordered_map>
+
+namespace orcus { namespace spreadsheet {
+
+class shared_formula_pool
+{
+ using store_type = std::unordered_map<size_t, ixion::formula_tokens_store_ptr_t>;
+
+ store_type m_store;
+
+public:
+ shared_formula_pool();
+ ~shared_formula_pool();
+
+ void add(size_t sf_index, const ixion::formula_tokens_store_ptr_t& sf_tokens);
+
+ ixion::formula_tokens_store_ptr_t get(size_t sf_index) const;
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/shared_strings.cpp b/src/spreadsheet/shared_strings.cpp
new file mode 100644
index 0000000..f133e50
--- /dev/null
+++ b/src/spreadsheet/shared_strings.cpp
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/spreadsheet/shared_strings.hpp>
+#include <ixion/model_context.hpp>
+
+#include <iostream>
+#include <algorithm>
+#include <unordered_map>
+
+namespace orcus { namespace spreadsheet {
+
+// format runs for all shared strings, mapped by string IDs.
+using format_runs_map_type = std::unordered_map<size_t, std::unique_ptr<format_runs_t>>;
+
+struct shared_strings::impl
+{
+ ixion::model_context& context;
+
+ /**
+ * Container for all format runs of all formatted strings. Format runs
+ * are mapped with the string IDs.
+ */
+ format_runs_map_type formats;
+
+ impl(ixion::model_context& cxt) : context(cxt) {}
+};
+
+shared_strings::shared_strings(ixion::model_context& cxt) : mp_impl(std::make_unique<impl>(cxt)) {}
+
+shared_strings::~shared_strings() = default;
+
+void shared_strings::set_format_runs(std::size_t sindex, std::unique_ptr<format_runs_t> runs)
+{
+ mp_impl->formats.insert_or_assign(sindex, std::move(runs));
+}
+
+const format_runs_t* shared_strings::get_format_runs(std::size_t index) const
+{
+ auto it = mp_impl->formats.find(index);
+ if (it != mp_impl->formats.end())
+ return it->second.get();
+ return nullptr;
+}
+
+const std::string* shared_strings::get_string(std::size_t index) const
+{
+ return mp_impl->context.get_string(index);
+}
+
+void shared_strings::dump(std::ostream& os) const
+{
+ os << "number of shared strings: " << mp_impl->context.get_string_count() << std::endl;
+}
+
+}}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/sheet.cpp b/src/spreadsheet/sheet.cpp
new file mode 100644
index 0000000..4ffa8df
--- /dev/null
+++ b/src/spreadsheet/sheet.cpp
@@ -0,0 +1,555 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/spreadsheet/sheet.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/exception.hpp"
+
+#include "json_dumper.hpp"
+#include "check_dumper.hpp"
+#include "csv_dumper.hpp"
+#include "flat_dumper.hpp"
+#include "html_dumper.hpp"
+#include "sheet_impl.hpp"
+#include "debug_state_dumper.hpp"
+
+#include <iostream>
+#include <algorithm>
+#include <vector>
+#include <cassert>
+#include <cstdlib>
+
+#include <ixion/exceptions.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/model_context.hpp>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/gregorian/greg_date.hpp>
+
+#include "filesystem_env.hpp"
+
+#define ORCUS_DEBUG_SHEET 0
+
+using namespace std;
+namespace gregorian = boost::gregorian;
+namespace posix_time = boost::posix_time;
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+ixion::abs_range_t to_ixion_range(sheet_t sheet, const range_t& range)
+{
+ ixion::abs_range_t pos;
+
+ pos.first.sheet = sheet;
+ pos.first.row = range.first.row;
+ pos.first.column = range.first.column;
+ pos.last.sheet = sheet;
+ pos.last.row = range.last.row;
+ pos.last.column = range.last.column;
+
+ return pos;
+}
+
+}
+
+const row_t sheet::max_row_limit = 1048575;
+const col_t sheet::max_col_limit = 1023;
+
+sheet::sheet(document& doc, sheet_t sheet_index) :
+ mp_impl(std::make_unique<detail::sheet_impl>(doc, *this, sheet_index)) {}
+
+sheet::~sheet() noexcept
+{
+}
+
+void sheet::set_auto(row_t row, col_t col, std::string_view s)
+{
+ if (s.empty())
+ return;
+
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+
+ // First, see if this can be parsed as a number.
+ char* endptr = nullptr;
+ double val = strtod(s.data(), &endptr);
+ const char* endptr_check = s.data() + s.size();
+ if (endptr == endptr_check)
+ // Treat this as a numeric value.
+ cxt.set_numeric_cell(ixion::abs_address_t(mp_impl->sheet_id,row,col), val);
+ else
+ // Treat this as a string value.
+ cxt.set_string_cell(ixion::abs_address_t(mp_impl->sheet_id,row,col), s);
+}
+
+void sheet::set_string(row_t row, col_t col, string_id_t sindex)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ cxt.set_string_cell(ixion::abs_address_t(mp_impl->sheet_id,row,col), sindex);
+
+#if ORCUS_DEBUG_SHEET
+ cout << "sheet::set_string: sheet=" << mp_impl->sheet_id << "; row=" << row << "; col=" << col << "; si=" << sindex << endl;
+#endif
+}
+
+void sheet::set_value(row_t row, col_t col, double value)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ cxt.set_numeric_cell(ixion::abs_address_t(mp_impl->sheet_id,row,col), value);
+}
+
+void sheet::set_bool(row_t row, col_t col, bool value)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ cxt.set_boolean_cell(ixion::abs_address_t(mp_impl->sheet_id,row,col), value);
+}
+
+void sheet::set_date_time(row_t row, col_t col, int year, int month, int day, int hour, int minute, double second)
+{
+ // Convert this to a double value representing days since epoch.
+
+ date_time_t dt_origin = mp_impl->doc.get_origin_date();
+
+ gregorian::date origin(dt_origin.year, dt_origin.month, dt_origin.day);
+ gregorian::date d(year, month, day);
+
+ double days_since_epoch = (d - origin).days();
+
+ long ms = second * 1000000.0;
+
+ posix_time::time_duration t(
+ posix_time::hours(hour) +
+ posix_time::minutes(minute) +
+ posix_time::microseconds(ms)
+ );
+
+ double time_as_day = t.total_microseconds();
+ time_as_day /= 1000000.0; // microseconds to seconds
+ time_as_day /= 60.0 * 60.0 * 24.0; // seconds to day
+
+ set_value(row, col, days_since_epoch + time_as_day);
+}
+
+void sheet::set_format(row_t row, col_t col, size_t index)
+{
+ set_format(row, col, row, col, index);
+}
+
+void sheet::set_format(row_t row_start, col_t col_start, row_t row_end, col_t col_end, size_t index)
+{
+ for (col_t col = col_start; col <= col_end; ++col)
+ {
+ auto itr = mp_impl->cell_formats.find(col);
+ if (itr == mp_impl->cell_formats.end())
+ {
+ auto p = std::make_unique<detail::segment_row_index_type>(0, mp_impl->doc.get_sheet_size().rows, 0);
+ auto r = mp_impl->cell_formats.emplace(col, std::move(p));
+
+ if (!r.second)
+ {
+ cerr << "insertion of new cell format container failed!" << endl;
+ return;
+ }
+
+ itr = r.first;
+ }
+
+ detail::segment_row_index_type& con = *itr->second;
+ con.insert_back(row_start, row_end+1, index);
+ }
+}
+
+void sheet::set_column_format(col_t col, col_t col_span, std::size_t index)
+{
+ if (col_span > 0)
+ mp_impl->column_formats.insert_back(col, col + col_span, index);
+}
+
+void sheet::set_row_format(row_t row, std::size_t index)
+{
+ mp_impl->row_formats.insert_back(row, row+1, index);
+}
+
+void sheet::set_formula(row_t row, col_t col, const ixion::formula_tokens_store_ptr_t& tokens)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ ixion::abs_address_t pos(mp_impl->sheet_id, row, col);
+
+ cxt.set_formula_cell(pos, tokens);
+ try
+ {
+ ixion::register_formula_cell(cxt, pos);
+ mp_impl->doc.insert_dirty_cell(pos);
+ }
+ catch ([[maybe_unused]] const ixion::formula_registration_error& e)
+ {
+#if ORCUS_DEBUG_SHEET
+ cout << "sheet::set_formula: sheet=" << mp_impl->sheet_id << "; row=" << row << "; col=" << col << "; e=" << e.what() << endl;
+#endif
+ }
+}
+
+void sheet::set_formula(
+ row_t row, col_t col, const ixion::formula_tokens_store_ptr_t& tokens,
+ ixion::formula_result result)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ ixion::abs_address_t pos(mp_impl->sheet_id, row, col);
+
+ cxt.set_formula_cell(pos, tokens, result);
+
+ try
+ {
+ ixion::register_formula_cell(cxt, pos);
+ mp_impl->doc.insert_dirty_cell(pos);
+ }
+ catch ([[maybe_unused]] const ixion::formula_registration_error& e)
+ {
+#if ORCUS_DEBUG_SHEET
+ cout << "sheet::set_formula: sheet=" << mp_impl->sheet_id << "; row=" << row << "; col=" << col << "; e=" << e.what() << endl;
+#endif
+ }
+}
+
+void sheet::set_grouped_formula(const range_t& range, ixion::formula_tokens_t tokens)
+{
+ ixion::abs_range_t pos = to_ixion_range(mp_impl->sheet_id, range);
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+
+ cxt.set_grouped_formula_cells(pos, std::move(tokens));
+ try
+ {
+ ixion::register_formula_cell(cxt, pos.first);
+ mp_impl->doc.insert_dirty_cell(pos.first);
+ }
+ catch ([[maybe_unused]] const ixion::formula_registration_error& e)
+ {
+#if ORCUS_DEBUG_SHEET
+ cout << "sheet::set_formula: sheet=" << mp_impl->sheet_id << "; range=" << range << "; e=" << e.what() << endl;
+#endif
+ }
+}
+
+void sheet::set_grouped_formula(const range_t& range, ixion::formula_tokens_t tokens, ixion::formula_result result)
+{
+ ixion::abs_range_t pos = to_ixion_range(mp_impl->sheet_id, range);
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+
+ cxt.set_grouped_formula_cells(pos, std::move(tokens), std::move(result));
+ try
+ {
+ ixion::register_formula_cell(cxt, pos.first);
+ mp_impl->doc.insert_dirty_cell(pos.first);
+ }
+ catch ([[maybe_unused]] const ixion::formula_registration_error& e)
+ {
+#if ORCUS_DEBUG_SHEET
+ cout << "sheet::set_formula: sheet=" << mp_impl->sheet_id << "; range=" << range << "; e=" << e.what() << endl;
+#endif
+ }
+}
+
+void sheet::set_col_width(col_t col, col_t col_span, col_width_t width)
+{
+ mp_impl->col_width_pos =
+ mp_impl->col_widths.insert(mp_impl->col_width_pos, col, col+col_span, width).first;
+}
+
+col_width_t sheet::get_col_width(col_t col, col_t* col_start, col_t* col_end) const
+{
+ detail::col_widths_store_type& col_widths = mp_impl->col_widths;
+ if (!col_widths.is_tree_valid())
+ col_widths.build_tree();
+
+ col_width_t ret = 0;
+ if (!col_widths.search_tree(col, ret, col_start, col_end).second)
+ throw orcus::general_error("sheet::get_col_width: failed to search tree.");
+
+ return ret;
+}
+
+void sheet::set_col_hidden(col_t col, col_t col_span, bool hidden)
+{
+ mp_impl->col_hidden_pos =
+ mp_impl->col_hidden.insert(mp_impl->col_hidden_pos, col, col+col_span, hidden).first;
+}
+
+bool sheet::is_col_hidden(col_t col, col_t* col_start, col_t* col_end) const
+{
+ detail::col_hidden_store_type& col_hidden = mp_impl->col_hidden;
+ if (!col_hidden.is_tree_valid())
+ col_hidden.build_tree();
+
+ bool hidden = false;
+ if (!col_hidden.search_tree(col, hidden, col_start, col_end).second)
+ throw orcus::general_error("sheet::is_col_hidden: failed to search tree.");
+
+ return hidden;
+}
+
+void sheet::set_row_height(row_t row, row_height_t height)
+{
+ mp_impl->row_height_pos =
+ mp_impl->row_heights.insert(mp_impl->row_height_pos, row, row+1, height).first;
+}
+
+row_height_t sheet::get_row_height(row_t row, row_t* row_start, row_t* row_end) const
+{
+ detail::row_heights_store_type& row_heights = mp_impl->row_heights;
+ if (!row_heights.is_tree_valid())
+ row_heights.build_tree();
+
+ row_height_t ret = 0;
+ if (!row_heights.search_tree(row, ret, row_start, row_end).second)
+ throw orcus::general_error("sheet::get_row_height: failed to search tree.");
+
+ return ret;
+}
+
+void sheet::set_row_hidden(row_t row, bool hidden)
+{
+ mp_impl->row_hidden_pos =
+ mp_impl->row_hidden.insert(mp_impl->row_hidden_pos, row, row+1, hidden).first;
+}
+
+bool sheet::is_row_hidden(row_t row, row_t* row_start, row_t* row_end) const
+{
+ detail::row_hidden_store_type& row_hidden = mp_impl->row_hidden;
+ if (!row_hidden.is_tree_valid())
+ row_hidden.build_tree();
+
+ bool hidden = false;
+ if (!row_hidden.search_tree(row, hidden, row_start, row_end).second)
+ throw orcus::general_error("sheet::is_row_hidden: failed to search tree.");
+
+ return hidden;
+}
+
+void sheet::set_merge_cell_range(const range_t& range)
+{
+ detail::col_merge_size_type::iterator it_col = mp_impl->merge_ranges.find(range.first.column);
+ if (it_col == mp_impl->merge_ranges.end())
+ {
+ auto p = std::make_unique<detail::merge_size_type>();
+ pair<detail::col_merge_size_type::iterator, bool> r =
+ mp_impl->merge_ranges.insert(
+ detail::col_merge_size_type::value_type(range.first.column, std::move(p)));
+
+ if (!r.second)
+ // Insertion failed.
+ return;
+
+ it_col = r.first;
+ }
+
+ detail::merge_size_type& col_data = *it_col->second;
+ detail::merge_size sz(range.last.column-range.first.column+1, range.last.row-range.first.row+1);
+ col_data.insert(
+ detail::merge_size_type::value_type(range.first.row, sz));
+}
+
+void sheet::fill_down_cells(row_t src_row, col_t src_col, row_t range_size)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ ixion::abs_address_t src_pos(mp_impl->sheet_id, src_row, src_col);
+ cxt.fill_down_cells(src_pos, range_size);
+}
+
+range_t sheet::get_merge_cell_range(row_t row, col_t col) const
+{
+ range_t ret;
+ ret.first.column = col;
+ ret.first.row = row;
+ ret.last.column = col;
+ ret.last.row = row;
+
+ detail::col_merge_size_type::const_iterator it_col = mp_impl->merge_ranges.find(col);
+ if (it_col == mp_impl->merge_ranges.end())
+ return ret; // not a merged cell
+
+ const detail::merge_size_type& col_data = *it_col->second;
+ detail::merge_size_type::const_iterator it = col_data.find(row);
+ if (it == col_data.end())
+ return ret; // not a merged cell
+
+ const detail::merge_size& ms = it->second;
+ ret.last.column += ms.width - 1;
+ ret.last.row += ms.height - 1;
+
+ return ret;
+}
+
+size_t sheet::get_string_identifier(row_t row, col_t col) const
+{
+ const ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ return cxt.get_string_identifier(ixion::abs_address_t(mp_impl->sheet_id, row, col));
+}
+
+auto_filter_t* sheet::get_auto_filter_data()
+{
+ return mp_impl->auto_filter_data.get();
+}
+
+const auto_filter_t* sheet::get_auto_filter_data() const
+{
+ return mp_impl->auto_filter_data.get();
+}
+
+void sheet::set_auto_filter_data(auto_filter_t* p)
+{
+ mp_impl->auto_filter_data.reset(p);
+}
+
+ixion::abs_range_t sheet::get_data_range() const
+{
+ return mp_impl->get_data_range();
+}
+
+sheet_t sheet::get_index() const
+{
+ return mp_impl->sheet_id;
+}
+
+date_time_t sheet::get_date_time(row_t row, col_t col) const
+{
+ const ixion::model_context& cxt = mp_impl->doc.get_model_context();
+
+ // raw value as days since epoch.
+ double dt_raw = cxt.get_numeric_value(
+ ixion::abs_address_t(mp_impl->sheet_id, row, col));
+
+ double days_since_epoch = std::floor(dt_raw);
+ double time_fraction = dt_raw - days_since_epoch;
+
+ date_time_t dt_origin = mp_impl->doc.get_origin_date();
+
+ posix_time::ptime origin(
+ gregorian::date(
+ gregorian::greg_year(dt_origin.year),
+ gregorian::greg_month(dt_origin.month),
+ gregorian::greg_day(dt_origin.day)
+ )
+ );
+
+ posix_time::ptime date_part = origin + gregorian::days(days_since_epoch);
+
+ long hours = 0;
+ long minutes = 0;
+ double seconds = 0.0;
+
+ if (time_fraction)
+ {
+ // Convert a fraction day to microseconds.
+ long long ms = time_fraction * 24.0 * 60.0 * 60.0 * 1000000.0;
+ posix_time::time_duration td = posix_time::microsec(ms);
+
+ hours = td.hours();
+ minutes = td.minutes();
+ seconds = td.seconds(); // long to double
+
+ td -= posix_time::hours(hours);
+ td -= posix_time::minutes(minutes);
+ td -= posix_time::seconds((long)seconds);
+
+ ms = td.total_microseconds(); // remaining microseconds.
+
+ seconds += ms / 1000000.0;
+ }
+
+ gregorian::date d = date_part.date();
+
+ return date_time_t(d.year(), d.month(), d.day(), hours, minutes, seconds);
+}
+
+void sheet::finalize_import()
+{
+ mp_impl->col_widths.build_tree();
+ mp_impl->row_heights.build_tree();
+}
+
+void sheet::dump_flat(std::ostream& os) const
+{
+ detail::flat_dumper dumper(mp_impl->doc);
+ dumper.dump(os, mp_impl->sheet_id);
+}
+
+void sheet::dump_check(ostream& os, std::string_view sheet_name) const
+{
+ detail::check_dumper dumper(*mp_impl, sheet_name);
+ dumper.dump(os);
+}
+
+void sheet::dump_html(std::ostream& os) const
+{
+ if (!mp_impl->col_widths.is_tree_valid())
+ mp_impl->col_widths.build_tree();
+
+ if (!mp_impl->row_heights.is_tree_valid())
+ mp_impl->row_heights.build_tree();
+
+ detail::html_dumper dumper(mp_impl->doc, mp_impl->merge_ranges, mp_impl->sheet_id);
+ dumper.dump(os);
+}
+
+void sheet::dump_json(std::ostream& os) const
+{
+ detail::json_dumper dumper(mp_impl->doc);
+ dumper.dump(os, mp_impl->sheet_id);
+}
+
+void sheet::dump_csv(std::ostream& os) const
+{
+ detail::csv_dumper dumper(mp_impl->doc);
+ dumper.dump(os, mp_impl->sheet_id);
+}
+
+void sheet::dump_debug_state(const std::string& output_dir, std::string_view sheet_name) const
+{
+ fs::path outdir{output_dir};
+ detail::sheet_debug_state_dumper dumper(*mp_impl, sheet_name);
+ dumper.dump(outdir);
+}
+
+size_t sheet::get_cell_format(row_t row, col_t col) const
+{
+ // Check the cell format store first
+ auto it = mp_impl->cell_formats.find(col);
+ if (it != mp_impl->cell_formats.end())
+ {
+ detail::segment_row_index_type& con = *it->second;
+ if (!con.is_tree_valid())
+ con.build_tree();
+
+ // Return only if the index is not a default index
+ std::size_t index;
+ if (con.search_tree(row, index).second && index)
+ return index;
+ }
+
+ // Not found in the cell format store. Check the row store.
+ if (!mp_impl->row_formats.is_tree_valid())
+ mp_impl->row_formats.build_tree();
+
+ std::size_t index;
+ if (mp_impl->row_formats.search_tree(row, index).second && index)
+ return index;
+
+ // Not found in the row store. Check the column store.
+ if (!mp_impl->column_formats.is_tree_valid())
+ mp_impl->column_formats.build_tree();
+
+ if (mp_impl->column_formats.search_tree(col, index).second && index)
+ return index;
+
+ // Not found. Return the default format index.
+ return 0;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/sheet_impl.cpp b/src/spreadsheet/sheet_impl.cpp
new file mode 100644
index 0000000..1364e25
--- /dev/null
+++ b/src/spreadsheet/sheet_impl.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "sheet_impl.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/model_context.hpp>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+sheet_impl::sheet_impl(document& _doc, sheet& /*sh*/, sheet_t sheet_index) :
+ doc(_doc),
+ col_widths(0, doc.get_sheet_size().columns, get_default_column_width()),
+ row_heights(0, doc.get_sheet_size().rows, get_default_row_height()),
+ col_width_pos(col_widths.begin()),
+ row_height_pos(row_heights.begin()),
+ col_hidden(0, doc.get_sheet_size().columns, false),
+ row_hidden(0, doc.get_sheet_size().rows, false),
+ col_hidden_pos(col_hidden.begin()),
+ row_hidden_pos(row_hidden.begin()),
+ column_formats(0, doc.get_sheet_size().columns, 0),
+ row_formats(0, doc.get_sheet_size().rows, 0),
+ sheet_id(sheet_index) {}
+
+sheet_impl::~sheet_impl() {}
+
+const detail::merge_size* sheet_impl::get_merge_size(row_t row, col_t col) const
+{
+ detail::col_merge_size_type::const_iterator it_col = merge_ranges.find(col);
+ if (it_col == merge_ranges.end())
+ return nullptr;
+
+ detail::merge_size_type& col_merge_sizes = *it_col->second;
+ detail::merge_size_type::const_iterator it_row = col_merge_sizes.find(row);
+ if (it_row == col_merge_sizes.end())
+ return nullptr;
+
+ return &it_row->second;
+}
+
+ixion::abs_range_t sheet_impl::get_data_range() const
+{
+ const ixion::model_context& cxt = doc.get_model_context();
+ return cxt.get_data_range(sheet_id);
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/sheet_impl.hpp b/src/spreadsheet/sheet_impl.hpp
new file mode 100644
index 0000000..11f691a
--- /dev/null
+++ b/src/spreadsheet/sheet_impl.hpp
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_SHEET_IMPL_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_SHEET_IMPL_HPP
+
+#include "impl_types.hpp"
+#include "orcus/spreadsheet/auto_filter.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+class sheet;
+
+namespace detail {
+
+using segment_row_index_type = mdds::flat_segment_tree<row_t, std::size_t>;
+using segment_col_index_type = mdds::flat_segment_tree<col_t, std::size_t>;
+typedef std::unordered_map<col_t, std::unique_ptr<segment_row_index_type>> cell_format_type;
+
+// Widths and heights are stored in twips.
+typedef mdds::flat_segment_tree<col_t, col_width_t> col_widths_store_type;
+typedef mdds::flat_segment_tree<row_t, row_height_t> row_heights_store_type;
+
+// hidden information
+typedef mdds::flat_segment_tree<col_t, bool> col_hidden_store_type;
+typedef mdds::flat_segment_tree<row_t, bool> row_hidden_store_type;
+
+struct sheet_impl
+{
+ document& doc;
+
+ mutable col_widths_store_type col_widths;
+ mutable row_heights_store_type row_heights;
+ col_widths_store_type::const_iterator col_width_pos;
+ row_heights_store_type::const_iterator row_height_pos;
+
+ mutable col_hidden_store_type col_hidden;
+ mutable row_hidden_store_type row_hidden;
+ col_hidden_store_type::const_iterator col_hidden_pos;
+ row_hidden_store_type::const_iterator row_hidden_pos;
+
+ detail::col_merge_size_type merge_ranges; /// 2-dimensional merged cell ranges.
+
+ std::unique_ptr<auto_filter_t> auto_filter_data;
+
+ cell_format_type cell_formats;
+ segment_col_index_type column_formats;
+ segment_row_index_type row_formats;
+ const sheet_t sheet_id;
+
+ sheet_impl() = delete;
+ sheet_impl(const sheet_impl&) = delete;
+ sheet_impl& operator=(const sheet_impl&) = delete;
+
+ sheet_impl(document& _doc, sheet& sh, sheet_t sheet_index);
+ ~sheet_impl();
+
+ const detail::merge_size* get_merge_size(row_t row, col_t col) const;
+
+ ixion::abs_range_t get_data_range() const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/styles.cpp b/src/spreadsheet/styles.cpp
new file mode 100644
index 0000000..328814e
--- /dev/null
+++ b/src/spreadsheet/styles.cpp
@@ -0,0 +1,485 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/spreadsheet/styles.hpp"
+#include "orcus/string_pool.hpp"
+
+#include "ostream_utils.hpp"
+
+#include <functional>
+#include <algorithm>
+#include <cassert>
+#include <iomanip>
+#include <vector>
+#include <map>
+
+namespace orcus { namespace spreadsheet {
+
+font_t::font_t() = default;
+font_t::font_t(const font_t& other) = default;
+font_t::~font_t() = default;
+
+font_t& font_t::operator=(const font_t& other) = default;
+
+bool font_t::operator==(const font_t& other) const
+{
+ if (name != other.name)
+ return false;
+
+ if (name_asian != other.name_asian)
+ return false;
+
+ if (name_complex != other.name_complex)
+ return false;
+
+ if (size != other.size)
+ return false;
+
+ if (size_asian != other.size_asian)
+ return false;
+
+ if (size_complex != other.size_complex)
+ return false;
+
+ if (bold != other.bold)
+ return false;
+
+ if (bold_asian != other.bold_asian)
+ return false;
+
+ if (bold_complex != other.bold_complex)
+ return false;
+
+ if (italic != other.italic)
+ return false;
+
+ if (italic_asian != other.italic_asian)
+ return false;
+
+ if (italic_complex != other.italic_complex)
+ return false;
+
+ if (underline_style != other.underline_style)
+ return false;
+
+ if (underline_width != other.underline_width)
+ return false;
+
+ if (underline_mode != other.underline_mode)
+ return false;
+
+ if (underline_type != other.underline_type)
+ return false;
+
+ if (underline_color != other.underline_color)
+ return false;
+
+ if (color != other.color)
+ return false;
+
+ if (strikethrough_style != other.strikethrough_style)
+ return false;
+
+ if (strikethrough_width != other.strikethrough_width)
+ return false;
+
+ if (strikethrough_type != other.strikethrough_type)
+ return false;
+
+ if (strikethrough_text != other.strikethrough_text)
+ return false;
+
+ return true;
+}
+
+bool font_t::operator!=(const font_t& other) const
+{
+ return !operator==(other);
+}
+
+void font_t::reset()
+{
+ *this = font_t();
+}
+
+std::size_t font_t::hash::operator()(const font_t& v) const
+{
+ std::size_t hash_value = 0u;
+
+ if (v.name)
+ hash_value |= std::hash<std::string_view>{}(*v.name);
+
+ if (v.size)
+ hash_value |= std::hash<double>{}(*v.size);
+
+ if (v.bold)
+ hash_value |= std::hash<bool>{}(*v.bold);
+
+ if (v.italic)
+ hash_value |= std::hash<bool>{}(*v.italic);
+
+ return hash_value;
+}
+
+fill_t::fill_t() = default;
+
+void fill_t::reset()
+{
+ *this = fill_t();
+}
+
+border_attrs_t::border_attrs_t() = default;
+
+void border_attrs_t::reset()
+{
+ *this = border_attrs_t();
+}
+
+border_t::border_t() = default;
+
+void border_t::reset()
+{
+ *this = border_t();
+}
+
+protection_t::protection_t() = default;
+
+void protection_t::reset()
+{
+ *this = protection_t();
+}
+
+number_format_t::number_format_t() = default;
+
+void number_format_t::reset()
+{
+ *this = number_format_t();
+}
+
+bool number_format_t::operator== (const number_format_t& other) const noexcept
+{
+ return identifier == other.identifier && format_string == other.format_string;
+}
+
+bool number_format_t::operator!= (const number_format_t& other) const noexcept
+{
+ return !operator== (other);
+}
+
+cell_format_t::cell_format_t() :
+ font(0),
+ fill(0),
+ border(0),
+ protection(0),
+ number_format(0),
+ style_xf(0),
+ hor_align(hor_alignment_t::unknown),
+ ver_align(ver_alignment_t::unknown),
+ apply_num_format(false),
+ apply_font(false),
+ apply_fill(false),
+ apply_border(false),
+ apply_alignment(false),
+ apply_protection(false)
+{
+}
+
+void cell_format_t::reset()
+{
+ *this = cell_format_t();
+}
+
+cell_style_t::cell_style_t() :
+ xf(0), builtin(0)
+{
+}
+
+void cell_style_t::reset()
+{
+ *this = cell_style_t();
+}
+
+std::ostream& operator<< (std::ostream& os, const color_t& c)
+{
+ ::orcus::detail::ostream_format_guard ifs(os);
+
+ os << std::uppercase;
+
+ os << "(ARGB:"
+ << ' ' << std::hex << std::setfill('0') << std::setw(2) << int(c.alpha & 0xFF)
+ << ' ' << std::hex << std::setfill('0') << std::setw(2) << int(c.red & 0xFF)
+ << ' ' << std::hex << std::setfill('0') << std::setw(2) << int(c.green & 0xFF)
+ << ' ' << std::hex << std::setfill('0') << std::setw(2) << int(c.blue & 0xFF)
+ << ")";
+
+ return os;
+}
+
+struct styles::impl
+{
+ std::vector<font_t> fonts;
+ std::vector<fill_t> fills;
+ std::vector<border_t> borders;
+ std::vector<protection_t> protections;
+ std::vector<number_format_t> number_formats;
+ std::vector<cell_format_t> cell_style_formats;
+ std::vector<cell_format_t> cell_formats;
+ std::vector<cell_format_t> dxf_formats;
+ std::vector<cell_style_t> cell_styles;
+ std::map<std::size_t, std::size_t> cell_styles_map; // style xf to style position in `cell_styles`
+
+ string_pool str_pool;
+};
+
+styles::styles() : mp_impl(std::make_unique<impl>()) {}
+styles::~styles() {}
+
+void styles::reserve_font_store(size_t n)
+{
+ mp_impl->fonts.reserve(n);
+}
+
+std::size_t styles::append_font(const font_t& font)
+{
+ mp_impl->fonts.emplace_back(font);
+ return mp_impl->fonts.size() - 1;
+}
+
+void styles::reserve_fill_store(size_t n)
+{
+ mp_impl->fills.reserve(n);
+}
+
+std::size_t styles::append_fill(const fill_t& fill)
+{
+ mp_impl->fills.emplace_back(fill);
+ return mp_impl->fills.size() - 1;
+}
+
+void styles::reserve_border_store(size_t n)
+{
+ mp_impl->borders.reserve(n);
+}
+
+std::size_t styles::append_border(const border_t& border)
+{
+ mp_impl->borders.emplace_back(border);
+ return mp_impl->borders.size() - 1;
+}
+
+std::size_t styles::append_protection(const protection_t& protection)
+{
+ mp_impl->protections.emplace_back(protection);
+ return mp_impl->protections.size() - 1;
+}
+
+void styles::reserve_number_format_store(size_t n)
+{
+ mp_impl->number_formats.reserve(n);
+}
+
+std::size_t styles::append_number_format(const number_format_t& nf)
+{
+ if (nf.format_string)
+ {
+ number_format_t copied = nf;
+ copied.format_string = mp_impl->str_pool.intern(*nf.format_string).first;
+ mp_impl->number_formats.emplace_back(copied);
+ }
+ else
+ mp_impl->number_formats.emplace_back(nf);
+
+ return mp_impl->number_formats.size() - 1;
+}
+
+void styles::reserve_cell_style_format_store(size_t n)
+{
+ mp_impl->cell_style_formats.reserve(n);
+}
+
+size_t styles::append_cell_style_format(const cell_format_t& cf)
+{
+ mp_impl->cell_style_formats.push_back(cf);
+ return mp_impl->cell_style_formats.size() - 1;
+}
+
+void styles::reserve_cell_format_store(size_t n)
+{
+ mp_impl->cell_formats.reserve(n);
+}
+
+size_t styles::append_cell_format(const cell_format_t& cf)
+{
+ mp_impl->cell_formats.push_back(cf);
+ return mp_impl->cell_formats.size() - 1;
+}
+
+void styles::reserve_diff_cell_format_store(size_t n)
+{
+ mp_impl->dxf_formats.reserve(n);
+}
+
+size_t styles::append_diff_cell_format(const cell_format_t& cf)
+{
+ mp_impl->dxf_formats.push_back(cf);
+ return mp_impl->dxf_formats.size() - 1;
+}
+
+void styles::reserve_cell_style_store(size_t n)
+{
+ mp_impl->cell_styles.reserve(n);
+}
+
+void styles::append_cell_style(const cell_style_t& cs)
+{
+ mp_impl->cell_styles.push_back(cs);
+}
+
+const font_t* styles::get_font(size_t index) const
+{
+ if (index >= mp_impl->fonts.size())
+ return nullptr;
+
+ return &mp_impl->fonts[index];
+}
+
+const cell_format_t* styles::get_cell_format(size_t index) const
+{
+ if (index >= mp_impl->cell_formats.size())
+ return nullptr;
+
+ return &mp_impl->cell_formats[index];
+}
+
+const fill_t* styles::get_fill(size_t index) const
+{
+ if (index >= mp_impl->fills.size())
+ return nullptr;
+
+ return &mp_impl->fills[index];
+}
+
+const border_t* styles::get_border(size_t index) const
+{
+ if (index >= mp_impl->borders.size())
+ return nullptr;
+
+ return &mp_impl->borders[index];
+}
+
+const protection_t* styles::get_protection(size_t index) const
+{
+ if (index >= mp_impl->protections.size())
+ return nullptr;
+
+ return &mp_impl->protections[index];
+}
+
+const number_format_t* styles::get_number_format(size_t index) const
+{
+ if (index >= mp_impl->number_formats.size())
+ return nullptr;
+
+ return &mp_impl->number_formats[index];
+}
+
+const cell_format_t* styles::get_cell_style_format(size_t index) const
+{
+ if (index >= mp_impl->cell_style_formats.size())
+ return nullptr;
+
+ return &mp_impl->cell_style_formats[index];
+}
+
+const cell_format_t* styles::get_dxf_format(size_t index) const
+{
+ if (index >= mp_impl->dxf_formats.size())
+ return nullptr;
+
+ return &mp_impl->dxf_formats[index];
+}
+
+const cell_style_t* styles::get_cell_style(size_t index) const
+{
+ if (index >= mp_impl->cell_styles.size())
+ return nullptr;
+
+ return &mp_impl->cell_styles[index];
+}
+
+const cell_style_t* styles::get_cell_style_by_xf(size_t xfid) const
+{
+ auto it = mp_impl->cell_styles_map.find(xfid);
+ if (it == mp_impl->cell_styles_map.end())
+ return nullptr;
+
+ auto index = it->second;
+ return &mp_impl->cell_styles[index];
+}
+
+size_t styles::get_font_count() const
+{
+ return mp_impl->fonts.size();
+}
+
+size_t styles::get_fill_count() const
+{
+ return mp_impl->fills.size();
+}
+
+size_t styles::get_border_count() const
+{
+ return mp_impl->borders.size();
+}
+
+size_t styles::get_protection_count() const
+{
+ return mp_impl->protections.size();
+}
+
+size_t styles::get_number_format_count() const
+{
+ return mp_impl->number_formats.size();
+}
+
+size_t styles::get_cell_formats_count() const
+{
+ return mp_impl->cell_formats.size();
+}
+
+size_t styles::get_cell_style_formats_count() const
+{
+ return mp_impl->cell_style_formats.size();
+}
+
+size_t styles::get_dxf_count() const
+{
+ return mp_impl->dxf_formats.size();
+}
+
+size_t styles::get_cell_styles_count() const
+{
+ return mp_impl->cell_styles.size();
+}
+
+void styles::clear()
+{
+ mp_impl = std::make_unique<impl>();
+}
+
+void styles::finalize_import()
+{
+ for (std::size_t i = 0; i < mp_impl->cell_styles.size(); ++i)
+ {
+ const auto& entry = mp_impl->cell_styles[i];
+ mp_impl->cell_styles_map.insert_or_assign(entry.xf, i);
+ }
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/view.cpp b/src/spreadsheet/view.cpp
new file mode 100644
index 0000000..7e21fff
--- /dev/null
+++ b/src/spreadsheet/view.cpp
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/spreadsheet/view.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <cassert>
+#include <iostream>
+
+namespace orcus { namespace spreadsheet {
+
+struct view::impl
+{
+ document& m_doc;
+
+ std::vector<std::unique_ptr<sheet_view>> m_sheet_views;
+ sheet_t m_active_sheet;
+
+ impl(document& doc) : m_doc(doc), m_active_sheet(0) {}
+};
+
+view::view(document& doc) : mp_impl(std::make_unique<impl>(doc)) {}
+view::~view() {}
+
+sheet_view* view::get_or_create_sheet_view(sheet_t sheet)
+{
+ if (sheet < 0)
+ return nullptr;
+
+ sheet_t n = mp_impl->m_doc.get_sheet_count();
+ if (sheet >= n)
+ return nullptr;
+
+ // Make sure the container is large enough for the requested sheet view index.
+ n = mp_impl->m_sheet_views.size();
+ if (sheet >= n)
+ mp_impl->m_sheet_views.resize(sheet+1);
+
+ if (!mp_impl->m_sheet_views[sheet])
+ mp_impl->m_sheet_views[sheet] = std::make_unique<sheet_view>(*this);
+
+ return mp_impl->m_sheet_views[sheet].get();
+}
+
+const sheet_view* view::get_sheet_view(sheet_t sheet) const
+{
+ if (sheet < 0)
+ return nullptr;
+
+ sheet_t n = mp_impl->m_doc.get_sheet_count();
+ if (sheet >= n)
+ return nullptr;
+
+ n = mp_impl->m_sheet_views.size();
+ if (sheet >= n)
+ return nullptr;
+
+ assert(mp_impl->m_sheet_views[sheet]);
+ return mp_impl->m_sheet_views[sheet].get();
+}
+
+void view::set_active_sheet(sheet_t sheet)
+{
+ mp_impl->m_active_sheet = sheet;
+}
+
+sheet_t view::get_active_sheet() const
+{
+ return mp_impl->m_active_sheet;
+}
+
+namespace {
+
+/**
+ * Stores all data for a single sheet pane.
+ */
+struct sheet_pane_data
+{
+ range_t m_selection;
+
+ sheet_pane_data()
+ {
+ m_selection.first.row = -1;
+ m_selection.first.column = -1;
+ m_selection.last = m_selection.first;
+ }
+};
+
+size_t to_pane_index(sheet_pane_t pos)
+{
+ switch (pos)
+ {
+ case sheet_pane_t::top_left:
+ return 0;
+ case sheet_pane_t::top_right:
+ return 1;
+ case sheet_pane_t::bottom_left:
+ return 2;
+ case sheet_pane_t::bottom_right:
+ return 3;
+ case sheet_pane_t::unspecified:
+ default:
+ throw std::runtime_error("invalid sheet pane.");
+ }
+}
+
+} // anonymous namespace
+
+struct sheet_view::impl
+{
+ view& m_doc_view;
+ sheet_pane_data m_panes[4];
+ sheet_pane_t m_active_pane;
+ split_pane_t m_split_pane;
+ frozen_pane_t m_frozen_pane;
+
+ sheet_pane_data& get_pane(sheet_pane_t pos)
+ {
+ return m_panes[to_pane_index(pos)];
+ }
+
+ const sheet_pane_data& get_pane(sheet_pane_t pos) const
+ {
+ return m_panes[to_pane_index(pos)];
+ }
+
+ impl(view& doc_view) : m_doc_view(doc_view), m_active_pane(sheet_pane_t::top_left)
+ {
+ m_split_pane.hor_split = 0.0;
+ m_split_pane.ver_split = 0.0;
+ m_split_pane.top_left_cell.row = -1;
+ m_split_pane.top_left_cell.column = -1;
+ m_frozen_pane.visible_columns = 0;
+ m_frozen_pane.visible_rows = 0;
+ m_frozen_pane.top_left_cell.row = -1;
+ m_frozen_pane.top_left_cell.column = -1;
+ }
+};
+
+sheet_view::sheet_view(view& doc_view) : mp_impl(std::make_unique<impl>(doc_view)) {}
+sheet_view::~sheet_view() {}
+
+const range_t& sheet_view::get_selection(sheet_pane_t pos) const
+{
+ const sheet_pane_data& pd = mp_impl->get_pane(pos);
+ return pd.m_selection;
+}
+
+void sheet_view::set_selection(sheet_pane_t pos, const range_t& range)
+{
+ sheet_pane_data& pd = mp_impl->get_pane(pos);
+ pd.m_selection = range;
+}
+
+void sheet_view::set_active_pane(sheet_pane_t pos)
+{
+ mp_impl->m_active_pane = pos;
+}
+
+sheet_pane_t sheet_view::get_active_pane() const
+{
+ return mp_impl->m_active_pane;
+}
+
+void sheet_view::set_split_pane(
+ double hor_split, double ver_split, const address_t& top_left_cell)
+{
+ mp_impl->m_split_pane.hor_split = hor_split;
+ mp_impl->m_split_pane.ver_split = ver_split;
+ mp_impl->m_split_pane.top_left_cell = top_left_cell;
+}
+
+const split_pane_t& sheet_view::get_split_pane() const
+{
+ return mp_impl->m_split_pane;
+}
+
+void sheet_view::set_frozen_pane(col_t visible_cols, row_t visible_rows, const address_t& top_left_cell)
+{
+ mp_impl->m_frozen_pane.visible_columns = visible_cols;
+ mp_impl->m_frozen_pane.visible_rows = visible_rows;
+ mp_impl->m_frozen_pane.top_left_cell = top_left_cell;
+}
+
+const frozen_pane_t& sheet_view::get_frozen_pane() const
+{
+ return mp_impl->m_frozen_pane;
+}
+
+view& sheet_view::get_document_view()
+{
+ return mp_impl->m_doc_view;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
new file mode 100644
index 0000000..ea4eca9
--- /dev/null
+++ b/src/test/Makefile.am
@@ -0,0 +1,10 @@
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include
+
+noinst_LIBRARIES = liborcus-test.a
+
+liborcus_test_a_SOURCES = \
+ test_global.cpp \
+ mock_spreadsheet.cpp
diff --git a/src/test/Makefile.in b/src/test/Makefile.in
new file mode 100644
index 0000000..bddc4f2
--- /dev/null
+++ b/src/test/Makefile.in
@@ -0,0 +1,704 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/test
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+liborcus_test_a_AR = $(AR) $(ARFLAGS)
+liborcus_test_a_LIBADD =
+am_liborcus_test_a_OBJECTS = test_global.$(OBJEXT) \
+ mock_spreadsheet.$(OBJEXT)
+liborcus_test_a_OBJECTS = $(am_liborcus_test_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/mock_spreadsheet.Po \
+ ./$(DEPDIR)/test_global.Po
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(liborcus_test_a_SOURCES)
+DIST_SOURCES = $(liborcus_test_a_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include
+
+noinst_LIBRARIES = liborcus-test.a
+liborcus_test_a_SOURCES = \
+ test_global.cpp \
+ mock_spreadsheet.cpp
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/test/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/test/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+liborcus-test.a: $(liborcus_test_a_OBJECTS) $(liborcus_test_a_DEPENDENCIES) $(EXTRA_liborcus_test_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f liborcus-test.a
+ $(AM_V_AR)$(liborcus_test_a_AR) liborcus-test.a $(liborcus_test_a_OBJECTS) $(liborcus_test_a_LIBADD)
+ $(AM_V_at)$(RANLIB) liborcus-test.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mock_spreadsheet.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_global.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-am
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-am
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-am
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-am
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-am
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/mock_spreadsheet.Po
+ -rm -f ./$(DEPDIR)/test_global.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/mock_spreadsheet.Po
+ -rm -f ./$(DEPDIR)/test_global.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am \
+ check-valgrind-am check-valgrind-drd-am \
+ check-valgrind-drd-local check-valgrind-helgrind-am \
+ check-valgrind-helgrind-local check-valgrind-local \
+ check-valgrind-memcheck-am check-valgrind-memcheck-local \
+ check-valgrind-sgcheck-am check-valgrind-sgcheck-local clean \
+ clean-generic clean-libtool clean-noinstLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/test/mock_spreadsheet.cpp b/src/test/mock_spreadsheet.cpp
new file mode 100644
index 0000000..bf4f629
--- /dev/null
+++ b/src/test/mock_spreadsheet.cpp
@@ -0,0 +1,319 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "mock_spreadsheet.hpp"
+
+#include <cassert>
+
+using namespace orcus::spreadsheet;
+
+namespace orcus { namespace spreadsheet { namespace mock {
+
+//import_factory
+
+import_factory::~import_factory()
+{
+}
+
+orcus::spreadsheet::iface::import_global_settings* import_factory::get_global_settings()
+{
+ assert(false);
+ return nullptr;
+}
+
+orcus::spreadsheet::iface::import_shared_strings* import_factory::get_shared_strings()
+{
+ assert(false);
+ return nullptr;
+}
+
+orcus::spreadsheet::iface::import_styles* import_factory::get_styles()
+{
+ assert(false);
+ return nullptr;
+}
+
+orcus::spreadsheet::iface::import_sheet* import_factory::append_sheet(orcus::spreadsheet::sheet_t, std::string_view)
+{
+ assert(false);
+ return nullptr;
+}
+
+orcus::spreadsheet::iface::import_sheet* import_factory::get_sheet(std::string_view)
+{
+ assert(false);
+ return nullptr;
+}
+
+orcus::spreadsheet::iface::import_sheet* import_factory::get_sheet(orcus::spreadsheet::sheet_t)
+{
+ assert(false);
+ return nullptr;
+}
+
+void import_factory::finalize() {}
+
+// import_shared_strings
+
+import_shared_strings::~import_shared_strings()
+{
+}
+
+size_t import_shared_strings::append(std::string_view)
+{
+ assert(false);
+ return 0;
+}
+
+size_t import_shared_strings::add(std::string_view)
+{
+ assert(false);
+ return 0;
+}
+
+void import_shared_strings::set_segment_font(size_t)
+{
+ assert(false);
+}
+
+void import_shared_strings::set_segment_bold(bool)
+{
+ assert(false);
+}
+
+void import_shared_strings::set_segment_italic(bool)
+{
+ assert(false);
+}
+
+void import_shared_strings::set_segment_font_name(std::string_view)
+{
+ assert(false);
+}
+
+void import_shared_strings::set_segment_font_size(double)
+{
+ assert(false);
+}
+
+void import_shared_strings::set_segment_font_color(color_elem_t, color_elem_t, color_elem_t, color_elem_t)
+{
+ assert(false);
+}
+
+void import_shared_strings::append_segment(std::string_view)
+{
+ assert(false);
+}
+
+size_t import_shared_strings::commit_segments()
+{
+ assert(false);
+ return 0;
+}
+
+// import sheet properties
+
+import_sheet_properties::~import_sheet_properties()
+{
+}
+
+void import_sheet_properties::set_column_width(col_t, col_t, double, length_unit_t)
+{
+ assert(false);
+}
+
+void import_sheet_properties::set_column_hidden(col_t, col_t, bool)
+{
+ assert(false);
+}
+
+void import_sheet_properties::set_row_height(row_t, double, length_unit_t)
+{
+ assert(false);
+}
+
+void import_sheet_properties::set_row_hidden(row_t, bool)
+{
+ assert(false);
+}
+
+void import_sheet_properties::set_merge_cell_range(const range_t&)
+{
+ assert(false);
+}
+
+import_reference_resolver::~import_reference_resolver()
+{
+}
+
+spreadsheet::src_address_t import_reference_resolver::resolve_address(std::string_view)
+{
+ spreadsheet::src_address_t ret;
+ ret.column = ret.row = ret.sheet = 0;
+ assert(false);
+ return ret;
+}
+
+spreadsheet::src_range_t import_reference_resolver::resolve_range(std::string_view)
+{
+ spreadsheet::src_range_t ret;
+ ret.first.column = ret.first.row = ret.last.column = ret.last.row = 0;
+ ret.first.sheet = ret.last.sheet = 0;
+ assert(false);
+ return ret;
+}
+
+import_array_formula::~import_array_formula()
+{
+}
+
+void import_array_formula::set_range(const range_t&)
+{
+ assert(false);
+}
+
+void import_array_formula::set_formula(formula_grammar_t, std::string_view)
+{
+ assert(false);
+}
+
+void import_array_formula::set_result_value(row_t, col_t, double)
+{
+ assert(false);
+}
+
+void import_array_formula::set_result_string(row_t, col_t, std::string_view)
+{
+ assert(false);
+}
+
+void import_array_formula::set_result_empty(row_t, col_t)
+{
+ assert(false);
+}
+
+void import_array_formula::set_result_bool(row_t, col_t, bool)
+{
+ assert(false);
+}
+
+void import_array_formula::commit()
+{
+ assert(false);
+}
+
+import_formula::~import_formula()
+{
+}
+
+void import_formula::set_position(row_t, col_t)
+{
+ assert(false);
+}
+
+void import_formula::set_formula(formula_grammar_t, std::string_view)
+{
+ assert(false);
+}
+
+void import_formula::set_shared_formula_index(size_t)
+{
+ assert(false);
+}
+
+void import_formula::set_result_value(double)
+{
+ assert(false);
+}
+
+void import_formula::set_result_string(std::string_view)
+{
+ assert(false);
+}
+
+void import_formula::set_result_bool(bool)
+{
+ assert(false);
+}
+
+void import_formula::set_result_empty()
+{
+ assert(false);
+}
+
+void import_formula::commit()
+{
+ assert(false);
+}
+
+// import_sheet
+
+import_sheet::~import_sheet()
+{
+}
+
+void import_sheet::set_auto(row_t, col_t, std::string_view)
+{
+ assert(false);
+}
+
+void import_sheet::set_value(row_t, col_t, double)
+{
+ assert(false);
+}
+
+void import_sheet::set_bool(row_t, col_t, bool)
+{
+ assert(false);
+}
+
+void import_sheet::set_date_time(row_t, col_t, int, int, int, int, int, double)
+{
+ assert(false);
+}
+
+void import_sheet::set_string(row_t, col_t, string_id_t)
+{
+ assert(false);
+}
+
+void import_sheet::set_format(row_t, col_t, size_t)
+{
+ assert(false);
+}
+
+void import_sheet::set_format(row_t, col_t, row_t, col_t, size_t)
+{
+ assert(false);
+}
+
+void import_sheet::set_column_format(col_t, col_t, std::size_t)
+{
+ assert(false);
+}
+
+void import_sheet::set_row_format(row_t, std::size_t)
+{
+ assert(false);
+}
+
+void import_sheet::fill_down_cells(row_t, col_t, row_t)
+{
+ assert(false);
+}
+
+orcus::spreadsheet::range_size_t import_sheet::get_sheet_size() const
+{
+ assert(false);
+ orcus::spreadsheet::range_size_t ret;
+ ret.columns = ret.rows = 0;
+ return ret;
+}
+
+}}}
+
diff --git a/src/test/test_global.cpp b/src/test/test_global.cpp
new file mode 100644
index 0000000..f689591
--- /dev/null
+++ b/src/test/test_global.cpp
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+
+#include <orcus/stream.hpp>
+#include <orcus/parser_global.hpp>
+
+namespace orcus { namespace test {
+
+stack_printer::stack_printer(const char* msg) :
+ m_msg(msg)
+{
+ std::cerr << m_msg << ": --begin" << std::endl;
+ m_start_time = get_time();
+}
+
+stack_printer::~stack_printer()
+{
+ double end_time = get_time();
+ std::cerr << m_msg << ": --end (duration: " << (end_time-m_start_time) << " sec)" << std::endl;
+}
+
+double stack_printer::get_time() const
+{
+ double v = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
+ return v / 1000.0;
+}
+
+assert_error::assert_error(const char* filename, size_t line_no, const char* msg)
+{
+ std::ostringstream os;
+ os << filename << ":" << line_no << ": " << msg;
+ m_msg = os.str();
+}
+
+const char* assert_error::what() const noexcept
+{
+ return m_msg.data();
+}
+
+void verify_content(
+ const char* filename, size_t line_no, std::string_view expected, const std::string& actual)
+{
+ std::string_view s1 = expected;
+ std::string_view s2(actual.data(), actual.size());
+ s1 = trim(s1);
+ s2 = trim(s2);
+
+ if (s1 != s2)
+ {
+ // TODO : improve the error message to make it more viewer-friendly.
+
+ size_t diff_pos = locate_first_different_char(s1, s2);
+ std::string msg_s1 = create_parse_error_output(s1, diff_pos);
+ std::string msg_s2 = create_parse_error_output(s2, diff_pos);
+
+ std::ostringstream os;
+ os << "content is not as expected: " << std::endl << std::endl
+ << "* expected:" << std::endl << std::endl
+ << msg_s1 << std::endl
+ << "* actual:" << std::endl << std::endl
+ << msg_s2;
+
+ throw assert_error(filename, line_no, os.str().data());
+ }
+}
+
+}} // namespace orcus::test
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */