sqlce 0.1.0__tar.gz → 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. sqlce-0.1.2/.github/workflows/release.yml +162 -0
  2. {sqlce-0.1.0 → sqlce-0.1.2}/PKG-INFO +25 -6
  3. {sqlce-0.1.0 → sqlce-0.1.2}/README.md +18 -5
  4. {sqlce-0.1.0 → sqlce-0.1.2}/bindings/src/module.cpp +39 -0
  5. {sqlce-0.1.0 → sqlce-0.1.2}/core/CMakeLists.txt +21 -2
  6. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/application/SdfDatabase.hpp +6 -0
  7. sqlce-0.1.2/core/include/sdf/domain/EncryptionMode.hpp +48 -0
  8. sqlce-0.1.2/core/include/sdf/domain/IPageCipher.hpp +23 -0
  9. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/domain/PageLayout.hpp +8 -0
  10. sqlce-0.1.2/core/include/sdf/infrastructure/AesCbc.hpp +30 -0
  11. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/infrastructure/FileStorage.hpp +7 -0
  12. sqlce-0.1.2/core/include/sdf/infrastructure/Sha256.hpp +16 -0
  13. sqlce-0.1.2/core/include/sdf/infrastructure/Sha512.hpp +16 -0
  14. sqlce-0.1.2/core/include/sdf/parsing/SdfPageCipher.hpp +41 -0
  15. {sqlce-0.1.0/core/app → sqlce-0.1.2/core}/main.cpp +67 -27
  16. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/application/SdfDatabase.cpp +23 -2
  17. sqlce-0.1.2/core/src/infrastructure/AesCbc.cpp +230 -0
  18. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/infrastructure/FileStorage.cpp +43 -0
  19. sqlce-0.1.2/core/src/infrastructure/Sha256.cpp +126 -0
  20. sqlce-0.1.2/core/src/infrastructure/Sha512.cpp +144 -0
  21. sqlce-0.1.2/core/src/parsing/SdfPageCipher.cpp +151 -0
  22. {sqlce-0.1.0 → sqlce-0.1.2}/docs/build.txt +5 -2
  23. sqlce-0.1.2/docs/en/cpp.md +47 -0
  24. sqlce-0.1.2/docs/en/python.md +51 -0
  25. sqlce-0.1.2/docs/ru/cpp.md +47 -0
  26. sqlce-0.1.2/docs/ru/python.md +51 -0
  27. sqlce-0.1.2/main.py +112 -0
  28. {sqlce-0.1.0 → sqlce-0.1.2}/pyproject.toml +18 -2
  29. sqlce-0.1.2/python/sqlce/__init__.py +6 -0
  30. sqlce-0.1.2/python/sqlce/__init__.pyi +7 -0
  31. {sqlce-0.1.0 → sqlce-0.1.2}/python/sqlce/_sdf_native.pyi +13 -0
  32. {sqlce-0.1.0 → sqlce-0.1.2}/requirements.txt +1 -0
  33. sqlce-0.1.2/research/sdf_d3.py +90 -0
  34. sqlce-0.1.2/research/sdf_d4.py +94 -0
  35. sqlce-0.1.0/.github/workflows/release.yml +0 -78
  36. sqlce-0.1.0/docs/4.0/ru/00-overview.md +0 -50
  37. sqlce-0.1.0/docs/4.0/ru/01-rows.md +0 -119
  38. sqlce-0.1.0/docs/4.0/ru/02-lob.md +0 -69
  39. sqlce-0.1.0/docs/4.0/ru/03-column-types.md +0 -80
  40. sqlce-0.1.0/docs/4.0/ru/04-catalog.md +0 -66
  41. sqlce-0.1.0/docs/4.0/ru/05-limitations.md +0 -50
  42. sqlce-0.1.0/docs/4.0/ru/catalog/00-schema.md +0 -94
  43. sqlce-0.1.0/docs/4.0/ru/catalog/01-row-layout.md +0 -107
  44. sqlce-0.1.0/docs/4.0/ru/catalog/02-classification.md +0 -32
  45. sqlce-0.1.0/docs/4.0/ru/catalog/03-status.md +0 -72
  46. sqlce-0.1.0/main.py +0 -76
  47. sqlce-0.1.0/python/sqlce/__init__.py +0 -4
  48. sqlce-0.1.0/python/sqlce/__init__.pyi +0 -5
  49. {sqlce-0.1.0 → sqlce-0.1.2}/.gitignore +0 -0
  50. {sqlce-0.1.0 → sqlce-0.1.2}/CMakeLists.txt +0 -0
  51. {sqlce-0.1.0 → sqlce-0.1.2}/LICENSE +0 -0
  52. {sqlce-0.1.0 → sqlce-0.1.2}/bindings/CMakeLists.txt +0 -0
  53. {sqlce-0.1.0 → sqlce-0.1.2}/bindings/src/value_convert.cpp +0 -0
  54. {sqlce-0.1.0 → sqlce-0.1.2}/bindings/src/value_convert.hpp +0 -0
  55. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/application/ColumnSchema.hpp +0 -0
  56. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/domain/ColumnDef.hpp +0 -0
  57. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/domain/ColumnType.hpp +0 -0
  58. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/domain/ColumnValue.hpp +0 -0
  59. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/domain/DateTimeValue.hpp +0 -0
  60. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/domain/Guid.hpp +0 -0
  61. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/domain/IPageStorage.hpp +0 -0
  62. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/domain/NumericValue.hpp +0 -0
  63. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/domain/Row.hpp +0 -0
  64. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/domain/TableDef.hpp +0 -0
  65. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/infrastructure/BinaryReader.hpp +0 -0
  66. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/infrastructure/PageView.hpp +0 -0
  67. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/CatalogPageScanner.hpp +0 -0
  68. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/CatalogRow.hpp +0 -0
  69. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/CatalogRowDecoder.hpp +0 -0
  70. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/CatalogSchema.hpp +0 -0
  71. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/ICatalogPageScanner.hpp +0 -0
  72. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/ICatalogRowDecoder.hpp +0 -0
  73. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/ILobChainRegistry.hpp +0 -0
  74. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/IRowDecoder.hpp +0 -0
  75. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/ITableCatalogBuilder.hpp +0 -0
  76. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/LobChainRegistry.hpp +0 -0
  77. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/RowDecoder.hpp +0 -0
  78. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/TableCatalogBuilder.hpp +0 -0
  79. {sqlce-0.1.0 → sqlce-0.1.2}/core/include/sdf/parsing/TextDecoder.hpp +0 -0
  80. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/domain/ColumnDef.cpp +0 -0
  81. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/domain/ColumnType.cpp +0 -0
  82. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/domain/ColumnValue.cpp +0 -0
  83. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/domain/DateTimeValue.cpp +0 -0
  84. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/domain/Guid.cpp +0 -0
  85. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/domain/NumericValue.cpp +0 -0
  86. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/domain/Row.cpp +0 -0
  87. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/domain/TableDef.cpp +0 -0
  88. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/infrastructure/BinaryReader.cpp +0 -0
  89. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/infrastructure/PageView.cpp +0 -0
  90. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/parsing/CatalogPageScanner.cpp +0 -0
  91. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/parsing/CatalogRow.cpp +0 -0
  92. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/parsing/CatalogRowDecoder.cpp +0 -0
  93. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/parsing/CatalogSchema.cpp +0 -0
  94. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/parsing/LobChainRegistry.cpp +0 -0
  95. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/parsing/RowDecoder.cpp +0 -0
  96. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/parsing/TableCatalogBuilder.cpp +0 -0
  97. {sqlce-0.1.0 → sqlce-0.1.2}/core/src/parsing/TextDecoder.cpp +0 -0
  98. {sqlce-0.1.0 → sqlce-0.1.2}/core/tests/CMakeLists.txt +0 -0
  99. {sqlce-0.1.0 → sqlce-0.1.2}/core/tests/count_test.cpp +0 -0
  100. {sqlce-0.1.0 → sqlce-0.1.2}/docs/CONVENTIONS.md +0 -0
  101. {sqlce-0.1.0 → sqlce-0.1.2}/research/catalog_parse/sdf_pages.py +0 -0
  102. {sqlce-0.1.0 → sqlce-0.1.2}/research/catalog_parse/syscatalog.py +0 -0
  103. {sqlce-0.1.0 → sqlce-0.1.2}/research/sdf_reader.py +0 -0
@@ -0,0 +1,162 @@
1
+ name: Build and release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ jobs:
8
+ build-linux:
9
+ name: Build wheel (Linux)
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Build wheels
15
+ uses: pypa/cibuildwheel@v2.21.3
16
+ env:
17
+ CIBW_ARCHS_LINUX: x86_64
18
+ CIBW_BUILD_VERBOSITY: 1
19
+
20
+ - name: Build sdist
21
+ run: |
22
+ python -m pip install --upgrade pip build
23
+ python -m build --sdist
24
+
25
+ - name: Collect wheels and sdist into one flat folder
26
+ run: |
27
+ mkdir -p collected
28
+ cp wheelhouse/*.whl collected/
29
+ cp dist/*.tar.gz collected/
30
+
31
+ - uses: actions/upload-artifact@v4
32
+ with:
33
+ name: dist-linux
34
+ path: collected/*
35
+
36
+ build-windows:
37
+ name: Build wheel (Windows)
38
+ runs-on: windows-latest
39
+ steps:
40
+ - uses: actions/checkout@v4
41
+
42
+ - name: Build wheels
43
+ uses: pypa/cibuildwheel@v2.21.3
44
+ env:
45
+ CIBW_ARCHS_WINDOWS: AMD64
46
+ CIBW_BUILD_VERBOSITY: 1
47
+ CIBW_CMAKE_ARGS: "-DSDF_BUILD_PYTHON_BINDINGS=ON"
48
+
49
+ - uses: actions/upload-artifact@v4
50
+ with:
51
+ name: dist-windows
52
+ path: wheelhouse/*
53
+
54
+ build-cpp-linux:
55
+ name: Build C++ library (Linux, ${{ matrix.link }})
56
+ runs-on: ubuntu-latest
57
+ strategy:
58
+ matrix:
59
+ link: [static, shared]
60
+ steps:
61
+ - uses: actions/checkout@v4
62
+
63
+ - name: Configure CMake
64
+ run: |
65
+ cmake -S . -B build \
66
+ -DCMAKE_BUILD_TYPE=Release \
67
+ -DBUILD_SHARED_LIBS=${{ matrix.link == 'shared' && 'ON' || 'OFF' }}
68
+
69
+ - name: Build libsdf
70
+ run: cmake --build build --target libsdf -j
71
+
72
+ - name: Package library + headers
73
+ run: |
74
+ version="${GITHUB_REF_NAME#v}"
75
+ pkg="libsdf-${version}-linux-x86_64-${{ matrix.link }}"
76
+ mkdir -p "$pkg/lib" "$pkg/include"
77
+ cp build/dist/lib/libsdf.* "$pkg/lib/"
78
+ cp -r core/include/. "$pkg/include/"
79
+ tar -czf "${pkg}.tar.gz" "$pkg"
80
+
81
+ - uses: actions/upload-artifact@v4
82
+ with:
83
+ name: cpp-linux-${{ matrix.link }}
84
+ path: libsdf-*.tar.gz
85
+
86
+ build-cpp-windows:
87
+ name: Build C++ library (Windows, ${{ matrix.link }})
88
+ runs-on: windows-latest
89
+ strategy:
90
+ matrix:
91
+ link: [static, shared]
92
+ steps:
93
+ - uses: actions/checkout@v4
94
+
95
+ - name: Configure CMake
96
+ shell: pwsh
97
+ run: |
98
+ $shared = if ("${{ matrix.link }}" -eq "shared") { "ON" } else { "OFF" }
99
+ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=$shared
100
+
101
+ - name: Build libsdf
102
+ run: cmake --build build --target libsdf --config Release -j
103
+
104
+ - name: Package library + headers
105
+ shell: pwsh
106
+ run: |
107
+ $version = "${env:GITHUB_REF_NAME}" -replace '^v', ''
108
+ $pkg = "libsdf-$version-windows-x86_64-${{ matrix.link }}"
109
+ New-Item -ItemType Directory -Force -Path "$pkg/lib" | Out-Null
110
+ New-Item -ItemType Directory -Force -Path "$pkg/include" | Out-Null
111
+ Copy-Item "build/dist/lib/libsdf.*" "$pkg/lib/"
112
+ Copy-Item -Recurse "core/include/*" "$pkg/include/"
113
+ Compress-Archive -Path $pkg -DestinationPath "$pkg.zip"
114
+
115
+ - uses: actions/upload-artifact@v4
116
+ with:
117
+ name: cpp-windows-${{ matrix.link }}
118
+ path: libsdf-*.zip
119
+
120
+ publish:
121
+ name: Publish to PyPI
122
+ needs: [build-linux, build-windows]
123
+ runs-on: ubuntu-latest
124
+ environment: pypi
125
+ permissions:
126
+ id-token: write
127
+ steps:
128
+ - uses: actions/download-artifact@v4
129
+ with:
130
+ pattern: dist-*
131
+ path: dist
132
+ merge-multiple: true
133
+
134
+ - name: Publish to PyPI
135
+ uses: pypa/gh-action-pypi-publish@release/v1
136
+ with:
137
+ packages-dir: dist
138
+
139
+ publish-release:
140
+ name: Publish GitHub Release
141
+ needs: [build-cpp-linux, build-cpp-windows, build-linux, build-windows]
142
+ runs-on: ubuntu-latest
143
+ permissions:
144
+ contents: write
145
+ steps:
146
+ - uses: actions/download-artifact@v4
147
+ with:
148
+ pattern: cpp-*
149
+ path: release-assets
150
+ merge-multiple: true
151
+
152
+ - uses: actions/download-artifact@v4
153
+ with:
154
+ pattern: dist-*
155
+ path: release-assets
156
+ merge-multiple: true
157
+
158
+ - name: Create GitHub Release
159
+ uses: softprops/action-gh-release@v2
160
+ with:
161
+ files: release-assets/*
162
+ generate_release_notes: true
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: sqlce
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Cross-platform lib for reading SQL Server CE (.sdf)
5
5
  Author-Email: boykopovar <boykopovar@gmail.com>
6
6
  License: MIT
@@ -19,6 +19,12 @@ Classifier: Operating System :: POSIX :: Linux
19
19
  Project-URL: Homepage, https://github.com/boykopovar/sqlce
20
20
  Project-URL: Issues, https://github.com/boykopovar/sqlce/issues
21
21
  Requires-Python: >=3.8
22
+ Provides-Extra: dev
23
+ Requires-Dist: scikit-build-core>=0.10; extra == "dev"
24
+ Requires-Dist: pybind11>=2.12; extra == "dev"
25
+ Requires-Dist: build; extra == "dev"
26
+ Requires-Dist: twine; extra == "dev"
27
+ Requires-Dist: pytest; extra == "dev"
22
28
  Description-Content-Type: text/markdown
23
29
 
24
30
  # sqlce
@@ -27,21 +33,34 @@ Description-Content-Type: text/markdown
27
33
 
28
34
  Анализ внутреннего устройства формата по декомпилированным компонентам SQL CE. Цель - предоставить кроссплатформенную и независимую от рантайма реализацию чтения `.sdf` и документацию формата.
29
35
 
30
- ## Структура
31
36
 
32
37
  - `core/` - реализация парсера на C++
33
38
  - `bindings/` - Биндинги для C++ библиотеки к другим языкам
34
39
  - `python/sqlce/` - Python API
35
40
  - `research/` - Экспериментальные скрипты
36
41
 
37
- ## Установка
38
42
 
39
43
  ```bash
40
44
  pip install sqlce
41
45
  ```
42
46
 
43
- [Документирование формата](docs/4.0/ru/00-overview.md)
47
+ ```python
48
+ from sqlce import SdfDatabase
44
49
 
45
- Текущая [реализация](main.py) поддерживает чтение списка таблиц, структуры таблиц, содержимого записей. Использует c++.
50
+ db = SdfDatabase("example.sdf", password="secret123")
46
51
 
47
- [Соглашения по написанию кода](docs/CONVENTIONS.md)
52
+ for table_name in db.list_tables():
53
+ print(table_name, db.table_schema(table_name))
54
+ for row in db.read_table(table_name):
55
+ print(row)
56
+ ```
57
+
58
+ Текущая [реализация](main.py) поддерживает чтение (поддерживается передача пароля) списка таблиц, структуры таблиц, содержимого записей. Использует c++.
59
+
60
+ [Документация](docs/ru/python.md)
61
+
62
+ [Documentation](docs/en/python.md)
63
+
64
+ [Соглашения по написанию кода](docs/CONVENTIONS.md) (PR приветствуются)
65
+
66
+ > Исключительно для интероперабельности с существующими файлами `.sdf` формата. Не содержит оригинальный код продукта.
@@ -4,21 +4,34 @@
4
4
 
5
5
  Анализ внутреннего устройства формата по декомпилированным компонентам SQL CE. Цель - предоставить кроссплатформенную и независимую от рантайма реализацию чтения `.sdf` и документацию формата.
6
6
 
7
- ## Структура
8
7
 
9
8
  - `core/` - реализация парсера на C++
10
9
  - `bindings/` - Биндинги для C++ библиотеки к другим языкам
11
10
  - `python/sqlce/` - Python API
12
11
  - `research/` - Экспериментальные скрипты
13
12
 
14
- ## Установка
15
13
 
16
14
  ```bash
17
15
  pip install sqlce
18
16
  ```
19
17
 
20
- [Документирование формата](docs/4.0/ru/00-overview.md)
18
+ ```python
19
+ from sqlce import SdfDatabase
21
20
 
22
- Текущая [реализация](main.py) поддерживает чтение списка таблиц, структуры таблиц, содержимого записей. Использует c++.
21
+ db = SdfDatabase("example.sdf", password="secret123")
23
22
 
24
- [Соглашения по написанию кода](docs/CONVENTIONS.md)
23
+ for table_name in db.list_tables():
24
+ print(table_name, db.table_schema(table_name))
25
+ for row in db.read_table(table_name):
26
+ print(row)
27
+ ```
28
+
29
+ Текущая [реализация](main.py) поддерживает чтение (поддерживается передача пароля) списка таблиц, структуры таблиц, содержимого записей. Использует c++.
30
+
31
+ [Документация](docs/ru/python.md)
32
+
33
+ [Documentation](docs/en/python.md)
34
+
35
+ [Соглашения по написанию кода](docs/CONVENTIONS.md) (PR приветствуются)
36
+
37
+ > Исключительно для интероперабельности с существующими файлами `.sdf` формата. Не содержит оригинальный код продукта.
@@ -9,6 +9,7 @@
9
9
 
10
10
  #include "sdf/application/ColumnSchema.hpp"
11
11
  #include "sdf/application/SdfDatabase.hpp"
12
+ #include "sdf/domain/EncryptionMode.hpp"
12
13
  #include "sdf/domain/Row.hpp"
13
14
 
14
15
  #include "value_convert.hpp"
@@ -26,7 +27,9 @@ constexpr char ModuleDoc[] = "Native reader for SQL Server Compact (.sdf) databa
26
27
  constexpr char DatabaseClassName[] = "SdfDatabase";
27
28
  constexpr char DatabaseDoc[] = "Reads tables, schemas and rows from a .sdf database file.";
28
29
  constexpr char InitDoc[] = "Open a .sdf file at the given path.";
30
+ constexpr char InitWithPasswordDoc[] = "Open a password-protected .sdf file, auto-detecting its encryption mode.";
29
31
  constexpr char PathArgName[] = "path";
32
+ constexpr char PasswordArgName[] = "password";
30
33
  constexpr char ListTablesName[] = "list_tables";
31
34
  constexpr char ListTablesDoc[] = "Return the names of all tables in the database.";
32
35
  constexpr char TableSchemaName[] = "table_schema";
@@ -44,6 +47,9 @@ constexpr char DeclaredSizeAttrName[] = "declared_size";
44
47
  constexpr char PrecisionAttrName[] = "precision";
45
48
  constexpr char ScaleAttrName[] = "scale";
46
49
 
50
+ constexpr char UnsupportedEncryptionModeErrorName[] = "UnsupportedEncryptionModeError";
51
+ constexpr char InvalidPasswordErrorName[] = "InvalidPasswordError";
52
+
47
53
  py::dict RowToDict(const domain::Row& row)
48
54
  {
49
55
  py::dict result;
@@ -75,12 +81,40 @@ std::optional<int> OptionalByteToInt(std::optional<std::uint8_t> value)
75
81
  return static_cast<int>(*value);
76
82
  }
77
83
 
84
+ void RegisterExceptions(py::module_& module)
85
+ {
86
+ static const py::exception<domain::UnsupportedEncryptionModeException> unsupportedModeError(
87
+ module, UnsupportedEncryptionModeErrorName, PyExc_ValueError);
88
+ static const py::exception<domain::InvalidPasswordException> invalidPasswordError(
89
+ module, InvalidPasswordErrorName, PyExc_ValueError);
90
+
91
+ py::register_exception_translator([](std::exception_ptr lastException) {
92
+ try
93
+ {
94
+ if (lastException)
95
+ {
96
+ std::rethrow_exception(lastException);
97
+ }
98
+ }
99
+ catch (const domain::UnsupportedEncryptionModeException& error)
100
+ {
101
+ PyErr_SetString(unsupportedModeError.ptr(), error.what());
102
+ }
103
+ catch (const domain::InvalidPasswordException& error)
104
+ {
105
+ PyErr_SetString(invalidPasswordError.ptr(), error.what());
106
+ }
107
+ });
108
+ }
109
+
78
110
  }
79
111
 
80
112
  PYBIND11_MODULE(_sdf_native, module)
81
113
  {
82
114
  module.doc() = ModuleDoc;
83
115
 
116
+ RegisterExceptions(module);
117
+
84
118
  py::class_<application::ColumnSchema>(module, SchemaClassName, SchemaDoc)
85
119
  .def_property_readonly(
86
120
  OrdinalAttrName,
@@ -103,6 +137,11 @@ PYBIND11_MODULE(_sdf_native, module)
103
137
 
104
138
  py::class_<application::SdfDatabase>(module, DatabaseClassName, DatabaseDoc)
105
139
  .def(py::init<const std::string&>(), py::arg(PathArgName), InitDoc)
140
+ .def(
141
+ py::init<const std::string&, const std::string&>(),
142
+ py::arg(PathArgName),
143
+ py::arg(PasswordArgName),
144
+ InitWithPasswordDoc)
106
145
  .def(ListTablesName, &application::SdfDatabase::ListTables, ListTablesDoc)
107
146
  .def(
108
147
  TableSchemaName,
@@ -18,21 +18,32 @@ add_library(libsdf
18
18
  src/domain/NumericValue.cpp
19
19
  src/domain/Row.cpp
20
20
  src/domain/TableDef.cpp
21
+ src/infrastructure/AesCbc.cpp
21
22
  src/infrastructure/BinaryReader.cpp
22
23
  src/infrastructure/FileStorage.cpp
23
24
  src/infrastructure/PageView.cpp
25
+ src/infrastructure/Sha256.cpp
26
+ src/infrastructure/Sha512.cpp
24
27
  src/parsing/CatalogPageScanner.cpp
25
28
  src/parsing/CatalogRow.cpp
26
29
  src/parsing/CatalogRowDecoder.cpp
27
30
  src/parsing/CatalogSchema.cpp
28
31
  src/parsing/LobChainRegistry.cpp
29
32
  src/parsing/RowDecoder.cpp
33
+ src/parsing/SdfPageCipher.cpp
30
34
  src/parsing/TableCatalogBuilder.cpp
31
35
  src/parsing/TextDecoder.cpp
32
36
  src/application/SdfDatabase.cpp
33
37
  )
34
38
 
35
- set_target_properties(libsdf PROPERTIES PREFIX "" OUTPUT_NAME "libsdf" POSITION_INDEPENDENT_CODE ON)
39
+ set_target_properties(libsdf PROPERTIES
40
+ PREFIX ""
41
+ OUTPUT_NAME "libsdf"
42
+ POSITION_INDEPENDENT_CODE ON
43
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/dist/lib"
44
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/dist/lib"
45
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/dist/lib"
46
+ )
36
47
 
37
48
  target_include_directories(libsdf PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
38
49
 
@@ -45,7 +56,7 @@ else()
45
56
  target_compile_options(libsdf PRIVATE -Wall -Wextra)
46
57
  endif()
47
58
 
48
- add_executable(sdf_dump app/main.cpp)
59
+ add_executable(sdf_dump main.cpp)
49
60
  target_link_libraries(sdf_dump PRIVATE libsdf)
50
61
 
51
62
  if(MSVC)
@@ -53,6 +64,14 @@ if(MSVC)
53
64
  target_compile_definitions(sdf_dump PRIVATE NOMINMAX _CRT_SECURE_NO_WARNINGS)
54
65
  else()
55
66
  target_compile_options(sdf_dump PRIVATE -Wall -Wextra)
67
+ if(MINGW)
68
+ target_link_options(sdf_dump PRIVATE
69
+ -static
70
+ -static-libgcc
71
+ -static-libstdc++
72
+ -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive
73
+ )
74
+ endif()
56
75
  endif()
57
76
 
58
77
  enable_testing()
@@ -7,6 +7,7 @@
7
7
  #include <vector>
8
8
 
9
9
  #include "sdf/application/ColumnSchema.hpp"
10
+ #include "sdf/domain/IPageCipher.hpp"
10
11
  #include "sdf/domain/IPageStorage.hpp"
11
12
  #include "sdf/domain/Row.hpp"
12
13
  #include "sdf/domain/TableDef.hpp"
@@ -22,6 +23,7 @@ class SdfDatabase
22
23
  {
23
24
  public:
24
25
  explicit SdfDatabase(const std::string& path);
26
+ SdfDatabase(const std::string& path, const std::string& password);
25
27
 
26
28
  std::vector<std::string> ListTables() const;
27
29
  std::vector<ColumnSchema> TableSchema(const std::string& tableName) const;
@@ -36,6 +38,10 @@ private:
36
38
 
37
39
  std::map<std::string, domain::TableDef> _tables;
38
40
 
41
+ explicit SdfDatabase(std::unique_ptr<domain::IPageStorage> storage);
42
+
43
+ static std::unique_ptr<domain::IPageStorage> OpenStorage(const std::string& path, const std::string& password);
44
+
39
45
  void AssignDataPages();
40
46
  const domain::TableDef& RequireTable(const std::string& tableName) const;
41
47
  };
@@ -0,0 +1,48 @@
1
+ #ifndef SDF_DOMAIN_ENCRYPTION_MODE_HPP
2
+ #define SDF_DOMAIN_ENCRYPTION_MODE_HPP
3
+
4
+ #include <cstdint>
5
+ #include <stdexcept>
6
+ #include <string>
7
+
8
+ namespace sdf::domain
9
+ {
10
+
11
+ enum class EncryptionMode : std::uint32_t
12
+ {
13
+ None = 0,
14
+ Rc4Sha1 = 1,
15
+ Aes128Sha1 = 2,
16
+ Aes128Sha256 = 3,
17
+ Aes256Sha512 = 4
18
+ };
19
+
20
+ class UnsupportedEncryptionModeException final : public std::runtime_error
21
+ {
22
+ public:
23
+ explicit UnsupportedEncryptionModeException(EncryptionMode mode)
24
+ : std::runtime_error("unsupported .sdf encryption mode: " + std::to_string(static_cast<std::uint32_t>(mode)))
25
+ , _mode(mode)
26
+ {
27
+ }
28
+
29
+ EncryptionMode Mode() const
30
+ {
31
+ return _mode;
32
+ }
33
+
34
+ private:
35
+ EncryptionMode _mode;
36
+ };
37
+
38
+ class InvalidPasswordException final : public std::runtime_error
39
+ {
40
+ public:
41
+ InvalidPasswordException() : std::runtime_error("password verification failed")
42
+ {
43
+ }
44
+ };
45
+
46
+ }
47
+
48
+ #endif
@@ -0,0 +1,23 @@
1
+ #ifndef SDF_DOMAIN_I_PAGE_CIPHER_HPP
2
+ #define SDF_DOMAIN_I_PAGE_CIPHER_HPP
3
+
4
+ #include <cstddef>
5
+ #include <cstdint>
6
+ #include <span>
7
+ #include <vector>
8
+
9
+ namespace sdf::domain
10
+ {
11
+
12
+ class IPageCipher
13
+ {
14
+ public:
15
+ virtual ~IPageCipher() = default;
16
+
17
+ virtual bool VerifyPassword() const = 0;
18
+ virtual std::vector<std::uint8_t> DecryptPage(std::size_t pageNumber, std::span<const std::uint8_t> page) const = 0;
19
+ };
20
+
21
+ }
22
+
23
+ #endif
@@ -14,6 +14,14 @@ constexpr std::size_t LobPageHeaderLength = 16;
14
14
  constexpr std::size_t SlotArrayBaseIndex = 1017;
15
15
  constexpr std::size_t RowHeaderLength = 28;
16
16
 
17
+ constexpr std::size_t PlaintextHeaderLength = 16;
18
+ constexpr std::size_t Page0ModeOffset = 184;
19
+ constexpr std::size_t Page0VerifierOffset = 76;
20
+ constexpr std::size_t Page0VerifierLength = 96;
21
+ constexpr std::size_t Page0KeyParamOffset = 188;
22
+ constexpr std::size_t Page0KeyParamLength = 4;
23
+ constexpr std::size_t MaxPasswordLength = 40;
24
+
17
25
  }
18
26
 
19
27
  #endif
@@ -0,0 +1,30 @@
1
+ #ifndef SDF_INFRASTRUCTURE_AES_CBC_HPP
2
+ #define SDF_INFRASTRUCTURE_AES_CBC_HPP
3
+
4
+ #include <array>
5
+ #include <cstddef>
6
+ #include <cstdint>
7
+ #include <span>
8
+ #include <vector>
9
+
10
+ namespace sdf::infrastructure
11
+ {
12
+
13
+ class AesCbcDecryptor
14
+ {
15
+ public:
16
+ explicit AesCbcDecryptor(std::span<const std::uint8_t> key, std::span<const std::uint8_t, 16> iv);
17
+
18
+ std::vector<std::uint8_t> Decrypt(std::span<const std::uint8_t> ciphertext) const;
19
+
20
+ private:
21
+ std::vector<std::uint32_t> _roundKeys;
22
+ std::size_t _roundCount;
23
+ std::array<std::uint8_t, 16> _iv;
24
+
25
+ void DecryptBlock(const std::uint8_t* in, std::uint8_t* out) const;
26
+ };
27
+
28
+ }
29
+
30
+ #endif
@@ -2,18 +2,23 @@
2
2
  #define SDF_INFRASTRUCTURE_FILE_STORAGE_HPP
3
3
 
4
4
  #include <cstdint>
5
+ #include <optional>
5
6
  #include <string>
6
7
  #include <vector>
7
8
 
9
+ #include "sdf/domain/IPageCipher.hpp"
8
10
  #include "sdf/domain/IPageStorage.hpp"
9
11
 
10
12
  namespace sdf::infrastructure
11
13
  {
12
14
 
15
+ std::vector<std::uint8_t> ReadFirstPageRaw(const std::string& path);
16
+
13
17
  class FileStorage final : public domain::IPageStorage
14
18
  {
15
19
  public:
16
20
  explicit FileStorage(const std::string& path);
21
+ FileStorage(const std::string& path, const domain::IPageCipher& cipher);
17
22
 
18
23
  std::size_t PageCount() const override;
19
24
  std::span<const std::uint8_t> PageBytes(std::size_t pageNumber) const override;
@@ -21,6 +26,8 @@ public:
21
26
  private:
22
27
  std::vector<std::uint8_t> _fileBytes;
23
28
  std::size_t _pageCount;
29
+
30
+ void Load(const std::string& path);
24
31
  };
25
32
 
26
33
  }
@@ -0,0 +1,16 @@
1
+ #ifndef SDF_INFRASTRUCTURE_SHA256_HPP
2
+ #define SDF_INFRASTRUCTURE_SHA256_HPP
3
+
4
+ #include <array>
5
+ #include <cstddef>
6
+ #include <cstdint>
7
+ #include <span>
8
+
9
+ namespace sdf::infrastructure
10
+ {
11
+
12
+ std::array<std::uint8_t, 32> Sha256(std::span<const std::uint8_t> message);
13
+
14
+ }
15
+
16
+ #endif
@@ -0,0 +1,16 @@
1
+ #ifndef SDF_INFRASTRUCTURE_SHA512_HPP
2
+ #define SDF_INFRASTRUCTURE_SHA512_HPP
3
+
4
+ #include <array>
5
+ #include <cstddef>
6
+ #include <cstdint>
7
+ #include <span>
8
+
9
+ namespace sdf::infrastructure
10
+ {
11
+
12
+ std::array<std::uint8_t, 64> Sha512(std::span<const std::uint8_t> message);
13
+
14
+ }
15
+
16
+ #endif
@@ -0,0 +1,41 @@
1
+ #ifndef SDF_PARSING_SDF_PAGE_CIPHER_HPP
2
+ #define SDF_PARSING_SDF_PAGE_CIPHER_HPP
3
+
4
+ #include <array>
5
+ #include <cstddef>
6
+ #include <cstdint>
7
+ #include <span>
8
+ #include <string>
9
+ #include <vector>
10
+
11
+ #include "sdf/domain/EncryptionMode.hpp"
12
+ #include "sdf/domain/IPageCipher.hpp"
13
+
14
+ namespace sdf::parsing
15
+ {
16
+
17
+ class SdfPageCipher final : public domain::IPageCipher
18
+ {
19
+ public:
20
+ SdfPageCipher(std::span<const std::uint8_t> page0, std::string password);
21
+
22
+ static domain::EncryptionMode ReadMode(std::span<const std::uint8_t> page0);
23
+
24
+ bool VerifyPassword() const override;
25
+ std::vector<std::uint8_t> DecryptPage(std::size_t pageNumber, std::span<const std::uint8_t> page) const override;
26
+
27
+ private:
28
+ domain::EncryptionMode _mode;
29
+ std::string _password;
30
+ std::vector<std::uint8_t> _passwordUtf16Le;
31
+ std::vector<std::uint8_t> _page0Ciphertext;
32
+ std::array<std::uint8_t, 4> _page0KeyParam;
33
+
34
+ std::vector<std::uint8_t> DecryptPage0(std::span<const std::uint8_t> page0) const;
35
+ std::vector<std::uint8_t> DeriveKey(std::span<const std::uint8_t> keyParam) const;
36
+ std::vector<std::uint8_t> HashPasswordWith(std::span<const std::uint8_t> keyParam) const;
37
+ };
38
+
39
+ }
40
+
41
+ #endif