Compare commits
831 Commits
hello_worl
...
release-d2
Author | SHA1 | Date | |
---|---|---|---|
257e857116 | |||
0035faa416 | |||
5c34c26080 | |||
b6f8c9e242 | |||
0698353fbf | |||
9576f78abf | |||
7b07edd9e4 | |||
a5b01bb0d7 | |||
1c5fed05bf | |||
d4983cf3c6 | |||
fc246ee396 | |||
167e470091 | |||
dae719f78a | |||
df96407669 | |||
17762b40b7 | |||
4f4ec089fd | |||
f58c658be1 | |||
e92e980fde | |||
71b6c72c46 | |||
da75443d4c | |||
a45692fa4c | |||
112c2c4212 | |||
f8fb458e32 | |||
20f4d50ad6 | |||
0eaf54bd22 | |||
978dd70770 | |||
9a49761c01 | |||
880e6e49d6 | |||
4a221e52db | |||
4f1593a0ed | |||
18166f6123 | |||
228b6dd031 | |||
a1a0abe83b | |||
77ece05bf1 | |||
9e624619b3 | |||
5c5c62dc55 | |||
53358d2e03 | |||
c178a2273b | |||
f86d0e697a | |||
4d806021d0 | |||
98a0c42040 | |||
0eb33f823c | |||
2dad1688b5 | |||
f1110bd849 | |||
b1a0fcbc57 | |||
e3e00b1716 | |||
faaddd1234 | |||
f37515707f | |||
86652ca8d4 | |||
819959745d | |||
f91874182e | |||
dfb17c851b | |||
e2952ec8c1 | |||
9560ccf476 | |||
e7ea76a7ac | |||
bae54a906b | |||
b0f268f371 | |||
b39735bb08 | |||
6af681bad6 | |||
9b84d9d8e0 | |||
4694bb9dd7 | |||
f758566041 | |||
cef5fcd86f | |||
8e297f32d4 | |||
be16229bf7 | |||
11e500520a | |||
00e645e7a3 | |||
3ff4a59373 | |||
5265a94a80 | |||
b3fa531aa0 | |||
8753d39b66 | |||
ed0bf268ba | |||
d0f5819072 | |||
d2e7528dae | |||
1d07890668 | |||
82a07737ec | |||
9091f9bd02 | |||
5d95b188d8 | |||
a4000f6497 | |||
12c5339295 | |||
4064592acc | |||
b9c2f3631d | |||
d2ec3b8350 | |||
19422ced3e | |||
540e67fcd8 | |||
89854a584a | |||
8b74920270 | |||
a74cd1c926 | |||
5189fefaa1 | |||
23c8a5eefc | |||
90c83a492c | |||
c99b60186d | |||
64ee637b74 | |||
5cec2cf819 | |||
680881003c | |||
d7b5f51fdc | |||
33047fc047 | |||
74ef768b6f | |||
d457d9688c | |||
267f8eca67 | |||
e7ae031ce7 | |||
5f0217545c | |||
5a5905d257 | |||
2e7a81563d | |||
4c6e053e81 | |||
11cb4d5a44 | |||
a81582d3cd | |||
4011773374 | |||
1d8f8566c5 | |||
5f8104efea | |||
5cc96228f4 | |||
e65e4e44cb | |||
8d4fc0e346 | |||
cd5c3afce7 | |||
a2c012ead4 | |||
26747a6d0f | |||
f90a6e30ea | |||
362aeef3c7 | |||
350b4ad6c2 | |||
887167add2 | |||
4dab05aef5 | |||
43318acffa | |||
6d2155d1ed | |||
0e2276bab8 | |||
95d58d04fb | |||
d7d0690575 | |||
7ae0befc37 | |||
4ae0becf79 | |||
5aeddd87e3 | |||
4f3497326f | |||
80aae23dc0 | |||
2f4868f59e | |||
c45ec45457 | |||
aa1b5fa4cf | |||
464b541f67 | |||
e1d3fe0d6b | |||
4273e72e74 | |||
e0a2676d54 | |||
1313b562bd | |||
f7bdd5042d | |||
412b187c4f | |||
38acb5dfc3 | |||
317cfabc72 | |||
5ac257de48 | |||
48decc83f6 | |||
6ada347ec4 | |||
bf00ff0e41 | |||
748fea3d43 | |||
320d8c1143 | |||
eddf89a321 | |||
fb5cd6603f | |||
4fa431c10b | |||
7ca34da417 | |||
f762e658de | |||
2133896165 | |||
4571a95a06 | |||
aecb6d55e4 | |||
2fb0ddf709 | |||
1269ee7fad | |||
da3c9107db | |||
2a1919208d | |||
2cff1add56 | |||
debb3eb981 | |||
74e6a4cbff | |||
5c710051c5 | |||
36b6542bf3 | |||
0abc07e31b | |||
1ec8d721f1 | |||
7df2244f65 | |||
c2b4595c33 | |||
f06806dafd | |||
c5f0825edb | |||
517551348a | |||
cdf62cbb98 | |||
4cbf1b9a9a | |||
a66f1499a4 | |||
29734d5ee1 | |||
2c582617e3 | |||
87968a87f0 | |||
9d4d3cd331 | |||
553cde0d0c | |||
90f94dbfc2 | |||
fffc66f18b | |||
ea14ccac3a | |||
e59499b127 | |||
afab2f6878 | |||
e927c51b61 | |||
dd008c3a08 | |||
54a78ff04e | |||
878c944ebf | |||
d9b363330b | |||
c9f91c16c2 | |||
5f56a5cc9b | |||
6cb449ae19 | |||
d93c6dff10 | |||
41030161df | |||
2d4f1054fd | |||
52026ba1a3 | |||
c214f3334a | |||
cda6eb92f3 | |||
02c8fb1880 | |||
7bd1f56f93 | |||
22680ffaf0 | |||
892fec6905 | |||
a2c8df83c6 | |||
8037bc9535 | |||
70925cbde4 | |||
e38cf01f07 | |||
e8760cd714 | |||
d1d979d2f1 | |||
615e06aa50 | |||
7edfc16f25 | |||
fe91d042db | |||
33fe14ffa1 | |||
1e879b93b7 | |||
6287663957 | |||
1d49c965fe | |||
441edf0d37 | |||
f59ad72ca2 | |||
0f3b71e63f | |||
1890b4101e | |||
bda4e643af | |||
03fc6280c9 | |||
04727ae57a | |||
84ee494834 | |||
08483e6e2f | |||
2fab740bf5 | |||
5f4cff3c00 | |||
91b959ff9d | |||
038f0ee493 | |||
3afaa0fc85 | |||
e050339311 | |||
61a5d100b0 | |||
2049931937 | |||
0d46cee20d | |||
bd1fc01ca1 | |||
4b832dd3d7 | |||
942d548fdd | |||
9187bcf62b | |||
8c576ef9c5 | |||
1499f42361 | |||
edae4563ff | |||
c6ecbd6d12 | |||
536435c057 | |||
ecde378aba | |||
dd3e5913ed | |||
641c6ae637 | |||
a8bed71255 | |||
540def399e | |||
37b6095e13 | |||
1edd322352 | |||
38ae116356 | |||
8fd49469c9 | |||
70022d5a96 | |||
01ad572499 | |||
e407ad7246 | |||
2e5263764c | |||
474230ae97 | |||
a9f55ebd02 | |||
1b08d0f851 | |||
528f9be635 | |||
d06724ffe1 | |||
d37cd50d99 | |||
8f21670439 | |||
69666a0b31 | |||
1d600186cd | |||
147a37ac6e | |||
f634c208ac | |||
aa34239eb5 | |||
965e280b53 | |||
45dd2e38e3 | |||
ee58ba4e9b | |||
0fbe1b96c3 | |||
4247ac0651 | |||
e5a66e1160 | |||
7d5595b405 | |||
71b38b243e | |||
5dc74e6fd7 | |||
2f45cbe6d9 | |||
e470a1da09 | |||
ddb158e433 | |||
d033335350 | |||
3cc6ca215e | |||
561cf9e2b4 | |||
876a0a2a23 | |||
0d0ebc8437 | |||
628b4d656b | |||
758907ab5a | |||
deaa293c67 | |||
c30ef720c4 | |||
693e7324ed | |||
7699ae2294 | |||
7105c19c72 | |||
0825c9869a | |||
9da47f75c0 | |||
73377068c6 | |||
3a0b41d2cc | |||
7f5f74e2a6 | |||
fc337922ac | |||
ce94af3f00 | |||
4f81c47734 | |||
bae1908c3b | |||
52c4744242 | |||
79a1a6f896 | |||
656039e011 | |||
3df78cd515 | |||
4ca4c31539 | |||
37009a7923 | |||
a60e7c27b7 | |||
3bc48c04f7 | |||
9147a91cc0 | |||
0a809037ac | |||
aa171fa069 | |||
adb23d9d6c | |||
92103bfc41 | |||
fbdb48a1ee | |||
5a0ba33b4c | |||
54ac86fce7 | |||
ce7c416fb7 | |||
aefd65b9e9 | |||
32b345ed0b | |||
8cd38dccbf | |||
3c45558dfc | |||
2fb1c7e401 | |||
6138d0a37e | |||
df8e1d31d6 | |||
c27cc56e31 | |||
2b536ff053 | |||
ff4adaebf1 | |||
142387aa04 | |||
b107dc756b | |||
f4b336dd77 | |||
3c86aae616 | |||
6485a780a7 | |||
c87e92da71 | |||
deaa1f13f5 | |||
da2b588deb | |||
d53430abbc | |||
382df7b2af | |||
84feeb8c1f | |||
8a562e1cc5 | |||
2d2cd2bbb6 | |||
22378d0a9f | |||
32d7c7b9e2 | |||
8fa5488d77 | |||
31b75d1e50 | |||
d55089b582 | |||
69f918664d | |||
cb8f26046a | |||
969af651d3 | |||
fb4a768415 | |||
62593c48a6 | |||
25c629f570 | |||
ea2bf8998b | |||
0efe94db45 | |||
dc03e01cf8 | |||
ffce1dc4df | |||
02d92449f9 | |||
0b218f57c2 | |||
16a09d6814 | |||
806eaa229a | |||
7b034be393 | |||
d4212abe3b | |||
ee9cdbe1e7 | |||
845373e049 | |||
6493a5e10e | |||
41d6c7188c | |||
00ed62c04c | |||
959807c08b | |||
8730c6380c | |||
472249cd6d | |||
0c7f8c8b5e | |||
3adf0df9c7 | |||
6571129686 | |||
baff558ff2 | |||
74d1bb08fe | |||
74fe0c55cc | |||
6a5b16c644 | |||
04929302d7 | |||
3938cb0282 | |||
db04367579 | |||
c87eed730e | |||
7b6b53b7d3 | |||
a204aa8c48 | |||
8e82ba2f2e | |||
eed1a1a94e | |||
9c70aab4a6 | |||
d9a596649c | |||
7725abeac8 | |||
ad85c59107 | |||
5705fd3d00 | |||
c9df80fb73 | |||
67b2764dc7 | |||
e58407f156 | |||
eb8f292181 | |||
b839af9207 | |||
56601b7c4f | |||
6ace1e641c | |||
5f41a2665b | |||
5ceb0e5f83 | |||
5834201fbb | |||
98d045827e | |||
14a40bdcd6 | |||
47ce0408d5 | |||
de210c5c7e | |||
eba7d402c9 | |||
36d8aeabd3 | |||
30ff7be0e4 | |||
238bc58f66 | |||
2b60c04f1a | |||
1bf3809b47 | |||
0c05d298d0 | |||
829357faaf | |||
22c9e4bdb2 | |||
11029c93c8 | |||
87c65a70b0 | |||
096509c2be | |||
23b662c2aa | |||
5afe78d015 | |||
05c0eb2f78 | |||
5dbe160633 | |||
5b57f4279a | |||
6baa9a251c | |||
941d714630 | |||
2830eb76b6 | |||
b229645dd3 | |||
f191ade18b | |||
b33cd06031 | |||
22da505869 | |||
fa3f7801d2 | |||
7cfe9aad8e | |||
7ac6ec609a | |||
245eba8d5b | |||
07112682c6 | |||
7a2033da60 | |||
c9d816503d | |||
38400e4406 | |||
52b9316858 | |||
94afbd4f60 | |||
d139eb9729 | |||
bbd1d187b2 | |||
bf6469b4a3 | |||
cf7ba595aa | |||
e0605edb6e | |||
817e3fcef1 | |||
df44abc316 | |||
341dbf14ae | |||
1780657789 | |||
585ff0a1fe | |||
9f805f761d | |||
10b3757558 | |||
e4aab88831 | |||
a9b7b00011 | |||
80dd6282f5 | |||
17fc48aa26 | |||
9e55e5f63c | |||
e31f51648c | |||
538fcdb43c | |||
4330c015a5 | |||
e45122184e | |||
f218ec44af | |||
fa1cf8bb73 | |||
e41cb307a7 | |||
7ff3b59801 | |||
5a9ab80753 | |||
c63a18b1dd | |||
cd91f6b60a | |||
8b7db3d544 | |||
c1fa5dc287 | |||
9f78e2320f | |||
40dac704d0 | |||
d51acfd033 | |||
e10594b006 | |||
0c570438e4 | |||
9844416a4e | |||
564ca7511c | |||
21f5a34b75 | |||
652b603ec6 | |||
ae260e6479 | |||
4b14478e8e | |||
dc3fe3c18e | |||
6ddd44828b | |||
0ea44e5ead | |||
00544de1d1 | |||
c32fe257cc | |||
76830ae91c | |||
fb3e94b45c | |||
def449607c | |||
3facd25794 | |||
d3f78982e6 | |||
805244f796 | |||
5a1d1c0a2f | |||
57aa0d556c | |||
765315b69c | |||
6b66127691 | |||
1c64096c38 | |||
c7e9a95a3f | |||
c8f39af001 | |||
5c51e17156 | |||
1c6e40220b | |||
75aeedb7b5 | |||
96c56e2589 | |||
52536fcb97 | |||
1a2733f5ce | |||
a0290c315a | |||
b656fbc3d4 | |||
9ca27361dc | |||
87e6b8d19f | |||
8da1b77aa5 | |||
af0e24d9bf | |||
e5c5c0da43 | |||
791c076b51 | |||
ec6326001d | |||
59ee1ada56 | |||
55119253da | |||
713aa7380f | |||
fdc227cb72 | |||
77c88515b2 | |||
f21cb465e6 | |||
4b70330710 | |||
0ba964a475 | |||
72b9437ef5 | |||
1770c8a1e2 | |||
6648d941c9 | |||
cbfd9566d1 | |||
0c6a557878 | |||
6a82e96db7 | |||
1f4781f06a | |||
e4e8f141b6 | |||
9472043d80 | |||
e918f2e60e | |||
32e2878fb1 | |||
338199be12 | |||
f12de38211 | |||
a1b8de0cb0 | |||
40f8af85a8 | |||
3d3ea32357 | |||
2e19e297d9 | |||
95b72d19fb | |||
324e28e5f2 | |||
c8ff73b56e | |||
61f77767bf | |||
d97247ffe0 | |||
b3bac826f1 | |||
71af674eef | |||
00339ee4fd | |||
de2e1bd1d6 | |||
7b9c7ddde4 | |||
d28f727742 | |||
87b580a72a | |||
86b36b48a3 | |||
35df47eaf8 | |||
c35f7abc5b | |||
e1494f4ed0 | |||
a6b9de9a59 | |||
ea7cf59ec7 | |||
956415a6a2 | |||
8e7fb4394b | |||
0da80081f3 | |||
d49f35f0f3 | |||
2b6ffa3c3f | |||
a0e336712f | |||
0b86f437f0 | |||
99b77e868d | |||
610f6f4246 | |||
1e82dacd6d | |||
423f575386 | |||
6eec25e4c0 | |||
1c16ef2601 | |||
78a819b360 | |||
a8e1197ad0 | |||
576a05a038 | |||
87f4964df5 | |||
3a70c0972b | |||
ecbeabff48 | |||
85a98222d4 | |||
8a07554c1d | |||
a13b369792 | |||
6236214be6 | |||
ad956ffd70 | |||
06013211d4 | |||
a8f185ea57 | |||
ae31e7f929 | |||
ae484e22c7 | |||
f64bcce564 | |||
4e3c98bcb5 | |||
24fbb8ba86 | |||
59cc34b4e8 | |||
aeee05be89 | |||
a8b1e25e89 | |||
fc3ec47330 | |||
b2245cc3b2 | |||
ec40d80e6d | |||
7644dfc879 | |||
263c14e0ff | |||
5ba2936773 | |||
e463b81e16 | |||
7fe47a237d | |||
26032a9d88 | |||
ef8b7d2792 | |||
6db4a31916 | |||
77db01b015 | |||
e2fe6f7320 | |||
3ebc4e92eb | |||
b8c54eba0c | |||
ad62d4c012 | |||
57a9221fb3 | |||
b6f27416c0 | |||
9541287d4a | |||
8094e0fe4d | |||
585d79a219 | |||
4c23a2d761 | |||
e19e70e065 | |||
8378af7564 | |||
381c739e46 | |||
2afef8a741 | |||
9d70927ad4 | |||
db7eb9a397 | |||
b16d781826 | |||
080ca9df86 | |||
ccf308d022 | |||
13a394e07f | |||
0041d68807 | |||
127c6525f7 | |||
9447967f12 | |||
2ce09ff08a | |||
efe8bf3e46 | |||
4d86f0e3d9 | |||
086b406748 | |||
56ed98268f | |||
493060955b | |||
a2cf756f4a | |||
16e0fddaca | |||
4d6eb5752e | |||
af4ab51df4 | |||
b77a41abd2 | |||
2e29f48810 | |||
3e63b2f816 | |||
3151b5508e | |||
c5bf8591e3 | |||
c871806822 | |||
381bfd27a8 | |||
957b94a48d | |||
cfc95b2dd1 | |||
b616d9c0f2 | |||
85c747ad1a | |||
e1305a240e | |||
cd38c961a3 | |||
21e72a0513 | |||
193492c518 | |||
b8a6b47b29 | |||
d96b8646ce | |||
4368c1ae4a | |||
c2c87e0363 | |||
2b8b5661eb | |||
7f3cda0ab3 | |||
2b5c34279c | |||
de89f86a26 | |||
9d013ff481 | |||
7e31eda638 | |||
d3b8e6089b | |||
d5b0bb69df | |||
7856d4e0bf | |||
12c7d8f1c9 | |||
0b6254a4fb | |||
2141b12b29 | |||
e7a396655c | |||
fc9726b3ec | |||
690cee7199 | |||
d72f11cbdb | |||
3edc8be1aa | |||
f430d6d398 | |||
637c9f24c2 | |||
9ce4835000 | |||
68bb2729d7 | |||
eebce9924d | |||
1692142bae | |||
3600d88987 | |||
04e5af6fe6 | |||
3892d52eec | |||
27b08561e1 | |||
ce9bbb7558 | |||
e45db79a77 | |||
7e1866ade9 | |||
ebdd31315d | |||
48de8f2561 | |||
1d65ca210f | |||
61de47fd00 | |||
3d77d6425e | |||
12371c21d2 | |||
4e50d80f5f | |||
2edee450aa | |||
539aa1e7eb | |||
08c7647298 | |||
3097e12e98 | |||
6f31e645ec | |||
73e0629ab4 | |||
b6b9181c66 | |||
2915b48130 | |||
cbca442f14 | |||
5d5e48e1e9 | |||
263111ef4d | |||
d76dea463c | |||
0bc0340c20 | |||
8ac88201d7 | |||
5922b72326 | |||
6d74a3b48e | |||
2554f8b3e1 | |||
d096d00bea | |||
2ed10afef7 | |||
70896b8761 | |||
6815402ba1 | |||
fadfeea744 | |||
591c738730 | |||
9f2441bc82 | |||
26f1993f3d | |||
5b628e7ad7 | |||
f6b027c591 | |||
70cee81406 | |||
dd4556e4e1 | |||
9c2e71045f | |||
507c894c15 | |||
329e8be825 | |||
30a992efad | |||
77e0222201 | |||
8559ab53cc | |||
5f0c1a1c41 | |||
f0efe2f9e0 | |||
5923f3f0cf | |||
21be39e2c9 | |||
89a7ffd45f | |||
9a3dcd0675 | |||
7cac015723 | |||
34e0baff5a | |||
71116f4be9 | |||
2d1b146abf | |||
11c7c49d7b | |||
3e90ec87b9 | |||
7a6174953d | |||
d8a3cd5dfb | |||
afe2148a17 | |||
57fe7aafc5 | |||
feb7e4c184 | |||
b63b9ffef2 | |||
4ae353a9b6 | |||
ca7a1624b5 | |||
54f929a883 | |||
f200472c4f | |||
f245d7d31f | |||
04211bb1ac | |||
287168a6cc | |||
38a3113ab6 | |||
bc69e67a5b | |||
6aab7bf2f2 | |||
754607fa2d | |||
fc71e02fa4 | |||
3d8887c6ac | |||
05107858aa | |||
92197bce9c | |||
9d28d20858 | |||
fea0a2e1c3 | |||
8e17515b27 | |||
e195c10d6d | |||
c0d1aab3e0 | |||
806325d649 | |||
ee3b15d885 | |||
de0005d5ee | |||
2fb59e356c | |||
6ab8ea640f | |||
fb52ca6518 | |||
db8ad57828 | |||
cf478dcb43 | |||
049f0b2245 | |||
1be4adf333 | |||
4a474de9bc | |||
6ca6ae82ba | |||
2c43777477 | |||
0ec41de34e | |||
9a920c5a99 | |||
cafc6b7422 | |||
a9887c0803 | |||
90db4e5f18 | |||
e4337e468b | |||
de35f76917 | |||
e79e3756c5 | |||
03d7b5fd26 | |||
84164ab2d2 | |||
bfc87b50b1 | |||
1b9f8f40f4 | |||
cb427dccd0 | |||
12d3513a50 | |||
00810e9341 | |||
059be4e32a | |||
f92c8ab577 | |||
89a6196b04 | |||
c548d200b6 | |||
3901493274 | |||
c971969a73 | |||
b1e548b96a | |||
bb5939a663 | |||
8778ce8764 | |||
32926661a1 | |||
325259da28 | |||
8a2ba6c171 | |||
c4da8394d2 | |||
a243a38d4d | |||
56fb5595f9 | |||
346b01be07 | |||
411a3fe65d | |||
eec9a9d730 | |||
9b46116a83 | |||
258be70528 | |||
973b7e97b1 | |||
d7a1d19fdf | |||
be9655c0b1 | |||
df76f9eb2c | |||
0231d48c91 | |||
51124966c3 | |||
9730ef773e | |||
681eb55db3 | |||
5644250e94 | |||
7a6934187a | |||
e0addbdea2 | |||
c1f9630634 | |||
661e60c24a | |||
b447d4c329 | |||
60b4a32995 | |||
6b1ccc7ed2 | |||
36124a1738 | |||
e6629ad319 | |||
bf78d45b2f |
12
.gdblogger.json
Normal file
12
.gdblogger.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"log_functions": [
|
||||
{
|
||||
"function": "oxTraceHook",
|
||||
"ignore_frames": 3,
|
||||
"file_var": "file",
|
||||
"line_var": "line",
|
||||
"channel_var": "ch",
|
||||
"msg_var": "msg"
|
||||
}
|
||||
]
|
||||
}
|
18
.gitignore
vendored
18
.gitignore
vendored
@ -1,5 +1,15 @@
|
||||
build/current
|
||||
build/gba
|
||||
build/*-release
|
||||
build/*-debug
|
||||
.current_build
|
||||
compile_commands.json
|
||||
build
|
||||
conanbuild
|
||||
dist
|
||||
tags
|
||||
nostalgia.gba
|
||||
nostalgia.sav
|
||||
nostalgia_media.oxfs
|
||||
media_header.txt
|
||||
studio_state.json
|
||||
CMakeLists.txt.user
|
||||
Session.vim
|
||||
ROM.oxfs
|
||||
graph_info.json
|
||||
|
5
.liccor
5
.liccor
@ -1,5 +0,0 @@
|
||||
Copyright 2016-2017 gtalent2@gmail.com
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
9
.liccor.yml
Normal file
9
.liccor.yml
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
source:
|
||||
- src
|
||||
copyright_notice: |-
|
||||
Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
44
.vs/launch.vs.json
Normal file
44
.vs/launch.vs.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"version": "0.2.1",
|
||||
"defaults": {},
|
||||
"configurations": [
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "nostalgia.exe (Install)",
|
||||
"name": "nostalgia.exe (Install)",
|
||||
"args": [
|
||||
"${projectDir}/sample_project"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "nostalgia.exe",
|
||||
"name": "nostalgia.exe",
|
||||
"args": [
|
||||
"${projectDir}/sample_project"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "nostalgia-studio.exe (Install)",
|
||||
"name": "nostalgia-studio.exe (Install)",
|
||||
"args": [
|
||||
"-profile",
|
||||
"${projectDir}/src/nostalgia/studio/nostalgia-studio-dev.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "nostalgia-studio.exe",
|
||||
"name": "nostalgia-studio.exe",
|
||||
"args": [
|
||||
"-profile",
|
||||
"${projectDir}/src/nostalgia/studio/nostalgia-studio-dev.json"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
141
CMakeLists.txt
141
CMakeLists.txt
@ -1,35 +1,128 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
project(wombat)
|
||||
project(nostalgia)
|
||||
|
||||
set(WOMBAT_BUILD_TYPE "Native" CACHE STRING "The type of build to produce(Native/GBA)")
|
||||
set(NOSTALGIA_BUILD_TYPE "Native" CACHE STRING "The type of build to produce(Native/GBA)")
|
||||
set(NOSTALGIA_IDE_BUILD ON CACHE STRING "Build for IDE's to run")
|
||||
set(NOSTALGIA_QT_PATH "" CACHE STRING "Path to Qt Libraries")
|
||||
set(NOSTALGIA_BUILD_PLAYER ON CACHE BOOL "Build Player")
|
||||
set(NOSTALGIA_BUILD_STUDIO ON CACHE BOOL "Build Studio")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
||||
include(address_sanitizer)
|
||||
|
||||
if (WOMBAT_BUILD_TYPE STREQUAL "GBA")
|
||||
include(GBA)
|
||||
if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA")
|
||||
set(NOSTALGIA_BUILD_STUDIO OFF)
|
||||
set(OX_BARE_METAL ON)
|
||||
set(OX_USE_STDLIB OFF)
|
||||
else()
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${NOSTALGIA_QT_PATH})
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif()
|
||||
|
||||
add_definitions(
|
||||
-std=c++11
|
||||
-Wall
|
||||
-Wsign-compare
|
||||
-nostdlib
|
||||
-fno-exceptions
|
||||
-fno-rtti
|
||||
#-g
|
||||
#-fcolor-diagnostics
|
||||
#--analyze
|
||||
#-Os # GCC size optimization flag
|
||||
)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
add_definitions(
|
||||
-Werror
|
||||
)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
|
||||
include(GenerateExportHeader)
|
||||
include(address_sanitizer)
|
||||
|
||||
set(NOSTALGIA_CONAN_PATHS ${CMAKE_SOURCE_DIR}/conanbuild/conan_paths.cmake)
|
||||
if(NOT NOSTALGIA_BUILD_TYPE STREQUAL "GBA" AND EXISTS ${NOSTALGIA_CONAN_PATHS})
|
||||
include(${NOSTALGIA_CONAN_PATHS})
|
||||
endif()
|
||||
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/dist/${NOSTALGIA_BUILD_CONFIG}")
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
if(NOT OX_BARE_METAL)
|
||||
add_definitions(-DOX_USE_STDLIB)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
# enable ccache
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
if(CCACHE_PROGRAM)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DDEBUG)
|
||||
else()
|
||||
add_definitions(-DNDEBUG)
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
# forces colored output when using ninja
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color")
|
||||
|
||||
# enable warnings
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-align")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused-variable")
|
||||
|
||||
if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA")
|
||||
include(GBA)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unwind-tables")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=arm7tdmi")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=arm7tdmi")
|
||||
endif()
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOSTALGIA_IDE_BUILD)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_MACOSX_RPATH OFF)
|
||||
set(CMAKE_INSTALL_NAME_DIR "@executable_path/../Library/nostalgia")
|
||||
set(NOSTALGIA_DIST_BIN nostalgia-studio.app/Contents/MacOS)
|
||||
set(NOSTALGIA_DIST_LIB nostalgia-studio.app/Contents/Library)
|
||||
set(NOSTALGIA_DIST_PLUGIN nostalgia-studio.app/Contents/Plugins)
|
||||
set(NOSTALGIA_DIST_RESOURCES nostalgia-studio.app/Contents/Resources)
|
||||
set(NOSTALGIA_DIST_MAC_APP_CONTENTS nostalgia-studio.app/Contents)
|
||||
else()
|
||||
set(CMAKE_INSTALL_RPATH "$ORIGIN" "$ORIGIN/../lib/nostalgia" "$ORIGIN/../")
|
||||
if(NOT ${NOSTALGIA_QT_PATH} STREQUAL "")
|
||||
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "${NOSTALGIA_QT_PATH}/lib")
|
||||
endif()
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
set(NOSTALGIA_DIST_BIN bin)
|
||||
set(NOSTALGIA_DIST_LIB lib)
|
||||
set(NOSTALGIA_DIST_PLUGIN lib/nostalgia/plugins)
|
||||
set(NOSTALGIA_DIST_RESOURCES share)
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_subdirectory(deps/ox)
|
||||
include_directories(SYSTEM deps/ox/src)
|
||||
|
||||
if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA")
|
||||
add_subdirectory(deps/gbastartup)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
86
Dockerfile
86
Dockerfile
@ -1,33 +1,61 @@
|
||||
FROM wombatant/devenv
|
||||
FROM fedora:30
|
||||
|
||||
ENV DEVKITPRO /opt/devkitPro
|
||||
ENV DEVKITARM ${DEVKITPRO}/devkitARM
|
||||
RUN dnf update -y
|
||||
|
||||
###############################################################################
|
||||
# Install Ox
|
||||
# Install gosu
|
||||
|
||||
RUN git clone -b release-0.1 https://github.com/wombatant/ox.git /usr/local/src/ox && \
|
||||
cd /usr/local/src/ox && \
|
||||
# setup build dirs
|
||||
mkdir -p \
|
||||
/usr/local/src/ox/build/release \
|
||||
/usr/local/src/ox/build/windows \
|
||||
/usr/local/src/ox/build/gba; \
|
||||
# install Ox for native environment
|
||||
cd /usr/local/src/ox/build/release && \
|
||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../../ && \
|
||||
make -j install; \
|
||||
# install Ox for GBA
|
||||
cd /usr/local/src/ox/build/gba && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DCMAKE_TOOLCHAIN_FILE=cmake/Modules/GBA.cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=/opt/devkitPro/devkitARM \
|
||||
-DOX_USE_STDLIB=OFF ../../ && \
|
||||
make -j install; \
|
||||
# install Ox for Windows
|
||||
cd /usr/local/src/ox/build/windows && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DCMAKE_TOOLCHAIN_FILE=cmake/Modules/Mingw.cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr/x86_64-w64-mingw32 \
|
||||
-DOX_BUILD_EXEC=OFF ../../ && \
|
||||
make -j install
|
||||
RUN dnf install -y curl gnupg
|
||||
RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4
|
||||
RUN curl -o /usr/local/bin/gosu -SL "https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64" && \
|
||||
curl -o /usr/local/bin/gosu.asc -SL "https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64.asc" && \
|
||||
gpg --verify /usr/local/bin/gosu.asc && \
|
||||
rm /usr/local/bin/gosu.asc && \
|
||||
chmod +x /usr/local/bin/gosu
|
||||
|
||||
###############################################################################
|
||||
# Install dev tools
|
||||
|
||||
RUN dnf install -y clang
|
||||
RUN dnf install -y llvm
|
||||
RUN dnf install -y libasan
|
||||
RUN dnf install -y mingw64-gcc-c++
|
||||
RUN dnf install -y cmake
|
||||
RUN dnf install -y make
|
||||
RUN dnf install -y git
|
||||
RUN dnf install -y vim
|
||||
RUN dnf install -y sudo
|
||||
RUN dnf install -y fuse-devel
|
||||
RUN dnf install -y qt5-devel
|
||||
RUN dnf install -y findutils
|
||||
RUN dnf install -y ninja-build
|
||||
RUN dnf install -y libcxx-devel libcxxabi-devel
|
||||
|
||||
###############################################################################
|
||||
# Install devkitARM
|
||||
|
||||
#RUN dnf install -y lbzip2
|
||||
#RUN curl -o /tmp/devkitArm.tar.bz2 -SL https://phoenixnap.dl.sourceforge.net/project/devkitpro/devkitARM/devkitARM_r47/devkitARM_r47-x86_64-linux.tar.bz2
|
||||
#WORKDIR /opt
|
||||
#RUN tar xf /tmp/devkitArm.tar.bz2
|
||||
#ENV DEVKITARM /opt/devkitARM
|
||||
|
||||
###############################################################################
|
||||
# Setup sudoers
|
||||
|
||||
ADD devenv/sudoers /etc/sudoers
|
||||
|
||||
###############################################################################
|
||||
# Setup working directory
|
||||
|
||||
RUN mkdir /usr/src/project
|
||||
WORKDIR /usr/src/project
|
||||
|
||||
###############################################################################
|
||||
# Setup entrypoint
|
||||
|
||||
ADD devenv/entrypoint.sh /
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
ENV CC clang
|
||||
ENV CXX clang++
|
||||
|
134
Makefile
134
Makefile
@ -2,83 +2,113 @@ OS=$(shell uname | tr [:upper:] [:lower:])
|
||||
HOST_ENV=${OS}-$(shell uname -m)
|
||||
DEVENV=devenv$(shell pwd | sed 's/\//-/g')
|
||||
DEVENV_IMAGE=nostalgia-devenv
|
||||
ifneq ($(shell which docker),)
|
||||
CURRENT_BUILD=$(file < .current_build)
|
||||
ifneq ($(shell which docker 2> /dev/null),)
|
||||
ifeq ($(shell docker inspect --format="{{.State.Status}}" ${DEVENV} 2>&1),running)
|
||||
ENV_RUN=docker exec -i -t --user $(shell id -u ${USER}) ${DEVENV}
|
||||
endif
|
||||
endif
|
||||
|
||||
make:
|
||||
${ENV_RUN} make -j -C build HOST_ENV=${HOST_ENV}
|
||||
preinstall:
|
||||
${ENV_RUN} make -j -C build ARGS="preinstall" HOST_ENV=${HOST_ENV}
|
||||
ifeq ($(OS),windows)
|
||||
RM_RF=Remove-Item -ErrorAction Ignore -Path -Recurse
|
||||
else
|
||||
RM_RF=rm -rf
|
||||
endif
|
||||
|
||||
ifeq ($(OS),darwin)
|
||||
NOSTALGIA_STUDIO=./dist/${CURRENT_BUILD}/nostalgia-studio.app/Contents/MacOS/nostalgia-studio
|
||||
NOSTALGIA_STUDIO_PROFILE=dist/${CURRENT_BUILD}/nostalgia-studio.app/Contents/Resources/nostalgia-studio.json
|
||||
MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA
|
||||
else
|
||||
NOSTALGIA_STUDIO=./dist/${CURRENT_BUILD}/bin/nostalgia-studio
|
||||
NOSTALGIA_STUDIO_PROFILE=dist/${CURRENT_BUILD}/share/nostalgia-studio.json
|
||||
MGBA=mgba-qt
|
||||
endif
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target;)
|
||||
.PHONY: pkg-gba
|
||||
pkg-gba:
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target install;)
|
||||
${ENV_RUN} ./scripts/gba-pkg sample_project
|
||||
.PHONY: install
|
||||
install:
|
||||
${ENV_RUN} make -j -C build ARGS="install" HOST_ENV=${HOST_ENV}
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target install;)
|
||||
.PHONY: clean
|
||||
clean:
|
||||
${ENV_RUN} make -j -C build ARGS="clean" HOST_ENV=${HOST_ENV}
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target clean;)
|
||||
.PHONY: purge
|
||||
purge:
|
||||
${ENV_RUN} rm -rf $$(find build -mindepth 1 -maxdepth 1 -type d)
|
||||
test:
|
||||
${ENV_RUN} make -j -C build ARGS="test" HOST_ENV=${HOST_ENV}
|
||||
${ENV_RUN} ${RM_RF} build .current_build dist
|
||||
.PHONY: test
|
||||
test: build
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target test;)
|
||||
|
||||
run: make
|
||||
./build/current/src/player/nostalgia -debug
|
||||
gba-run: make
|
||||
${ENV_RUN} mgba-qt build/current/src/player/nostalgia.bin
|
||||
gdb: make
|
||||
gdb ./build/current/src/wombat/wombat
|
||||
.PHONY: run
|
||||
run: install
|
||||
${ENV_RUN} ./dist/${CURRENT_BUILD}/bin/nostalgia sample_project
|
||||
.PHONY: run-studio
|
||||
run-studio: install
|
||||
${ENV_RUN} ${NOSTALGIA_STUDIO} -profile ${NOSTALGIA_STUDIO_PROFILE}
|
||||
.PHONY: gba-run
|
||||
gba-run: pkg-gba
|
||||
${MGBA} nostalgia.gba
|
||||
.PHONY: gdb
|
||||
gdb: install
|
||||
${ENV_RUN} gdb --args ./dist/${CURRENT_BUILD}/bin/nostalgia sample_project
|
||||
.PHONY: gdb-studio
|
||||
gdb-studio: install
|
||||
${ENV_RUN} gdb --args ${NOSTALGIA_STUDIO} -profile ${NOSTALGIA_STUDIO_PROFILE}
|
||||
|
||||
devenv-build:
|
||||
docker build --no-cache . -t ${DEVENV_IMAGE}
|
||||
devenv:
|
||||
docker run -d -v $(shell pwd):/usr/src/project \
|
||||
.PHONY: devenv-image
|
||||
devenv-image:
|
||||
docker build . -t ${DEVENV_IMAGE}
|
||||
.PHONY: devenv-create
|
||||
devenv-create:
|
||||
docker run -d \
|
||||
-e LOCAL_USER_ID=$(shell id -u ${USER}) \
|
||||
-e DISPLAY=$(DISPLAY) \
|
||||
-e QT_AUTO_SCREEN_SCALE_FACTOR=1 \
|
||||
-v /tmp/.X11-unix:/tmp/.X11-unix \
|
||||
-v /run/dbus/:/run/dbus/ \
|
||||
-v $(shell pwd):/usr/src/project \
|
||||
-v /dev/shm:/dev/shm \
|
||||
--restart=always \
|
||||
--name ${DEVENV} \
|
||||
-t ${DEVENV_IMAGE} bash
|
||||
.PHONY: devenv-destroy
|
||||
devenv-destroy:
|
||||
docker rm -f ${DEVENV}
|
||||
|
||||
shell:
|
||||
.PHONY: devenv-shell
|
||||
devenv-shell:
|
||||
${ENV_RUN} bash
|
||||
|
||||
release:
|
||||
${ENV_RUN} rm -rf build/${HOST_ENV}-release
|
||||
${ENV_RUN} ./scripts/setup_build ${HOST_ENV}
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s ${HOST_ENV}-release build/current
|
||||
.PHONY: conan
|
||||
conan:
|
||||
@mkdir -p conanbuild && cd conanbuild && conan install ../ --build=missing
|
||||
|
||||
debug:
|
||||
${ENV_RUN} rm -rf build/${HOST_ENV}-debug
|
||||
${ENV_RUN} ./scripts/setup_build ${HOST_ENV} debug
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s ${HOST_ENV}-debug build/current
|
||||
.PHONY: configure-release
|
||||
configure-release:
|
||||
${ENV_RUN} ${RM_RF} build/${HOST_ENV}-release
|
||||
${ENV_RUN} ./scripts/setup-build ${HOST_ENV} release
|
||||
|
||||
windows:
|
||||
${ENV_RUN} rm -rf build/windows
|
||||
${ENV_RUN} ./scripts/setup_build windows
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s windows build/current
|
||||
.PHONY: configure-debug
|
||||
configure-debug:
|
||||
${ENV_RUN} ${RM_RF} build/${HOST_ENV}-debug
|
||||
${ENV_RUN} ./scripts/setup-build ${HOST_ENV} debug
|
||||
|
||||
windows-debug:
|
||||
${ENV_RUN} rm -rf build/windows
|
||||
${ENV_RUN} ./scripts/setup_build windows debug
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s windows build/current
|
||||
.PHONY: configure-asan
|
||||
configure-asan:
|
||||
${ENV_RUN} ${RM_RF} build/${HOST_ENV}-asan
|
||||
${ENV_RUN} ./scripts/setup-build ${HOST_ENV} asan
|
||||
|
||||
gba:
|
||||
${ENV_RUN} rm -rf build/gba-release
|
||||
${ENV_RUN} ./scripts/setup_build gba
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s gba-release build/current
|
||||
.PHONY: configure-gba
|
||||
configure-gba:
|
||||
${ENV_RUN} ${RM_RF} build/gba-release
|
||||
${ENV_RUN} ./scripts/setup-build gba release
|
||||
|
||||
gba-debug:
|
||||
${ENV_RUN} rm -rf build/gba-debug
|
||||
${ENV_RUN} ./scripts/setup_build gba debug
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s gba-debug build/current
|
||||
.PHONY: configure-gba-debug
|
||||
configure-gba-debug:
|
||||
${ENV_RUN} ${RM_RF} build/gba-debug
|
||||
${ENV_RUN} ./scripts/setup-build gba debug
|
||||
|
18
README.md
18
README.md
@ -1 +1,19 @@
|
||||
# Nostalgia
|
||||
|
||||
## Setup
|
||||
|
||||
### Linux
|
||||
|
||||
Make sure conan is using the C++11 version of libstdc++.
|
||||
|
||||
conan profile update settings.compiler.libcxx=libstdc++11 default
|
||||
|
||||
### macOS
|
||||
|
||||
Install and use gmake instead of the make that comes with the system.
|
||||
|
||||
## Build
|
||||
|
||||
Build options: release, debug, gba, gba-debug
|
||||
|
||||
make purge conan configure-{gba,release,debug} install
|
||||
|
@ -1,33 +0,0 @@
|
||||
all: gba_build gba_debug_build native_build native_debug_build windows_release windows_debug
|
||||
|
||||
MAKE=make -j
|
||||
|
||||
gba_build:
|
||||
@if [ -d gba-release ]; then \
|
||||
${MAKE} -C gba-release ${ARGS}; \
|
||||
fi
|
||||
|
||||
gba_debug_build:
|
||||
@if [ -d gba-debug ]; then \
|
||||
${MAKE} -C gba-debug ${ARGS}; \
|
||||
fi
|
||||
|
||||
native_build:
|
||||
@if [ -d ${HOST_ENV}-release ]; then \
|
||||
${MAKE} -C ${HOST_ENV}-release ${ARGS}; \
|
||||
fi
|
||||
|
||||
native_debug_build:
|
||||
@if [ -d ${HOST_ENV}-debug ]; then \
|
||||
${MAKE} -C ${HOST_ENV}-debug ${ARGS}; \
|
||||
fi
|
||||
|
||||
windows_release:
|
||||
@if [ -d windows-release ]; then \
|
||||
${MAKE} -C windows-release ${ARGS}; \
|
||||
fi
|
||||
|
||||
windows_debug:
|
||||
@if [ -d windows-debug ]; then \
|
||||
${MAKE} -C windows-debug ${ARGS}; \
|
||||
fi
|
@ -1,49 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
# - Try to find Jansson
|
||||
# Once done this will define
|
||||
# JANSSON_FOUND - System has Jansson
|
||||
# JANSSON_INCLUDE_DIRS - The Jansson include directories
|
||||
# JANSSON_LIBRARIES - The libraries needed to use Jansson
|
||||
# JANSSON_DEFINITIONS - Compiler switches required for using Jansson
|
||||
|
||||
find_path(JANSSON_INCLUDE_DIR jansson.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
)
|
||||
|
||||
find_library(JANSSON_LIBRARY
|
||||
NAMES
|
||||
jansson
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
)
|
||||
|
||||
set(JANSSON_LIBRARIES ${JANSSON_LIBRARY})
|
||||
set(JANSSON_INCLUDE_DIRS ${JANSSON_INCLUDE_DIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
# handle the QUIETLY and REQUIRED arguments and set JANSSON_FOUND to TRUE
|
||||
# if all listed variables are TRUE
|
||||
find_package_handle_standard_args(Jansson DEFAULT_MSG
|
||||
JANSSON_LIBRARY JANSSON_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(JANSSON_INCLUDE_DIR JANSSON_LIBRARY)
|
@ -1,4 +0,0 @@
|
||||
|
||||
function(BuildStaticLib libName srcFiles)
|
||||
endfunction()
|
||||
|
@ -1,10 +1,5 @@
|
||||
set(CMAKE_SYSTEM_NAME "Generic")
|
||||
set(DEVKITARM $ENV{DEVKITARM})
|
||||
set(DEVKITPRO $ENV{DEVKITPRO})
|
||||
|
||||
if(NOT DEVKITPRO)
|
||||
message(FATAL_ERROR "DEVKITPRO environment variable not set")
|
||||
endif()
|
||||
|
||||
if(NOT DEVKITARM)
|
||||
message(FATAL_ERROR "DEVKITARM environment variable not set")
|
||||
@ -24,18 +19,10 @@ set(CMAKE_FIND_LIBRARY_PREFIXES lib)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||
|
||||
set(LINKER_FLAGS "-specs=gba.specs")
|
||||
add_definitions (
|
||||
-DARM7
|
||||
)
|
||||
|
||||
function(BuildStaticLib LIBNAME SRCFILES)
|
||||
add_library(${LIBNAME} OBJECT ${SRCFILES})
|
||||
set(OBJS ${OBJS} $<TARGET_OBJECTS:${LIBNAME}>)
|
||||
endfunction()
|
||||
add_definitions(-DARM7)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
|
||||
macro(OBJCOPY_FILE EXE_NAME)
|
||||
set(FO ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.bin)
|
||||
set(FI ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME})
|
9
conanfile.py
Normal file
9
conanfile.py
Normal file
@ -0,0 +1,9 @@
|
||||
from conans import ConanFile, CMake
|
||||
|
||||
class NostalgiaConan(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
requires = "jsoncpp/1.9.2", "sdl2/2.0.10@bincrafters/stable"
|
||||
generators = "cmake", "cmake_find_package", "cmake_paths"
|
||||
#default_options = {
|
||||
# "sdl2:nas": False
|
||||
#}
|
12
deps/gbastartup/CMakeLists.txt
vendored
Normal file
12
deps/gbastartup/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
enable_language(C ASM)
|
||||
|
||||
add_library(
|
||||
GbaStartup
|
||||
gba_crt0.s
|
||||
cstartup.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
GbaStartup
|
||||
OxStd
|
||||
)
|
63
deps/gbastartup/cstartup.cpp
vendored
Normal file
63
deps/gbastartup/cstartup.cpp
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/bit.hpp>
|
||||
#include <ox/std/heapmgr.hpp>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
|
||||
// this warning is too dumb to realize that it can actually confirm the hard
|
||||
// coded address aligns with the requirement of HeapSegment, so it must be
|
||||
// suppressed
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
|
||||
#define MEM_WRAM_BEGIN reinterpret_cast<uint8_t*>(0x02000000)
|
||||
#define MEM_WRAM_END reinterpret_cast<uint8_t*>(0x0203FFFF)
|
||||
|
||||
#define HEAP_BEGIN reinterpret_cast<ox::heapmgr::HeapSegment*>(MEM_WRAM_BEGIN)
|
||||
// set size to half of WRAM
|
||||
#define HEAP_SIZE ((MEM_WRAM_END - MEM_WRAM_BEGIN) / 2)
|
||||
#define HEAP_END reinterpret_cast<ox::heapmgr::HeapSegment*>(MEM_WRAM_BEGIN + HEAP_SIZE)
|
||||
|
||||
extern void (*__preinit_array_start[]) (void);
|
||||
extern void (*__preinit_array_end[]) (void);
|
||||
extern void (*__init_array_start[]) (void);
|
||||
extern void (*__init_array_end[]) (void);
|
||||
|
||||
namespace ox::heapmgr {
|
||||
|
||||
void initHeap(char *heapBegin, char *heapEnd);
|
||||
|
||||
}
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
void __libc_init_array() {
|
||||
auto preInits = __preinit_array_end - __preinit_array_start;
|
||||
for (decltype(preInits) i = 0; i < preInits; i++) {
|
||||
__preinit_array_start[i]();
|
||||
}
|
||||
auto inits = __init_array_end - __init_array_start;
|
||||
for (decltype(inits) i = 0; i < inits; i++) {
|
||||
__preinit_array_start[i]();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv);
|
||||
|
||||
int c_start() {
|
||||
const char *args[2] = {"", "rom.oxfs"};
|
||||
ox::heapmgr::initHeap(ox::bit_cast<char*>(HEAP_BEGIN), ox::bit_cast<char*>(HEAP_END));
|
||||
return main(2, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
258
deps/gbastartup/gba_crt0.s
vendored
Normal file
258
deps/gbastartup/gba_crt0.s
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
/*--------------------------------------------------------------------------------
|
||||
Copyright devkitPro Project
|
||||
https://github.com/devkitPro/devkitarm-crtls/blob/master/gba_crt0.s
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
obtain one at https://mozilla.org/MPL/2.0/.
|
||||
--------------------------------------------------------------------------------*/
|
||||
|
||||
.section ".crt0","ax"
|
||||
.global _start
|
||||
.align
|
||||
|
||||
.arm
|
||||
.cpu arm7tdmi
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
_start:
|
||||
@---------------------------------------------------------------------------------
|
||||
b rom_header_end
|
||||
|
||||
.fill 156,1,0 @ Nintendo Logo Character Data (8000004h)
|
||||
.fill 16,1,0 @ Game Title
|
||||
.byte 0x30,0x31 @ Maker Code (80000B0h)
|
||||
.byte 0x96 @ Fixed Value (80000B2h)
|
||||
.byte 0x00 @ Main Unit Code (80000B3h)
|
||||
.byte 0x00 @ Device Type (80000B4h)
|
||||
.fill 7,1,0 @ unused
|
||||
.byte 0x00 @ Software Version No (80000BCh)
|
||||
.byte 0xf0 @ Complement Check (80000BDh)
|
||||
.byte 0x00,0x00 @ Checksum (80000BEh)
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
rom_header_end:
|
||||
@---------------------------------------------------------------------------------
|
||||
b start_vector @ This branch must be here for proper
|
||||
@ positioning of the following header.
|
||||
|
||||
.GLOBAL __boot_method, __slave_number
|
||||
@---------------------------------------------------------------------------------
|
||||
__boot_method:
|
||||
@---------------------------------------------------------------------------------
|
||||
.byte 0 @ boot method (0=ROM boot, 3=Multiplay boot)
|
||||
@---------------------------------------------------------------------------------
|
||||
__slave_number:
|
||||
@---------------------------------------------------------------------------------
|
||||
.byte 0 @ slave # (1=slave#1, 2=slave#2, 3=slave#3)
|
||||
|
||||
.byte 0 @ reserved
|
||||
.byte 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
|
||||
.global start_vector
|
||||
.align
|
||||
@---------------------------------------------------------------------------------
|
||||
start_vector:
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r0, #0x4000000 @ REG_BASE
|
||||
str r0, [r0, #0x208]
|
||||
|
||||
mov r0, #0x12 @ Switch to IRQ Mode
|
||||
msr cpsr, r0
|
||||
ldr sp, =__sp_irq @ Set IRQ stack
|
||||
mov r0, #0x1f @ Switch to System Mode
|
||||
msr cpsr, r0
|
||||
ldr sp, =__sp_usr @ Set user stack
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Enter Thumb mode
|
||||
@---------------------------------------------------------------------------------
|
||||
add r0, pc, #1
|
||||
bx r0
|
||||
|
||||
.thumb
|
||||
|
||||
ldr r0, =__text_start
|
||||
lsl r0, #5 @ Was code compiled at 0x08000000 or higher?
|
||||
bcs DoEWRAMClear @ yes, you can not run it in external WRAM
|
||||
|
||||
mov r0, pc
|
||||
lsl r0, #5 @ Are we running from ROM (0x8000000 or higher) ?
|
||||
bcc SkipEWRAMClear @ No, so no need to do a copy.
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ We were started in ROM, silly emulators. :P
|
||||
@ So we need to copy to ExWRAM.
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r2, #2
|
||||
lsl r2, r2, #24 @ r2= 0x02000000
|
||||
ldr r3, =__end__ @ last ewram address
|
||||
sub r3, r2 @ r3= actual binary size
|
||||
mov r6, r2 @ r6= 0x02000000
|
||||
lsl r1, r2, #2 @ r1= 0x08000000
|
||||
|
||||
bl CopyMem
|
||||
|
||||
bx r6 @ Jump to the code to execute
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
DoEWRAMClear: @ Clear External WRAM to 0x00
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r1, #0x40
|
||||
lsl r1, #12 @ r1 = 0x40000
|
||||
lsl r0, r1, #7 @ r0 = 0x2000000
|
||||
bl ClearMem
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
SkipEWRAMClear: @ Clear Internal WRAM to 0x00
|
||||
@---------------------------------------------------------------------------------
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Clear BSS section to 0x00
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r0, =__bss_start__
|
||||
ldr r1, =__bss_end__
|
||||
sub r1, r0
|
||||
bl ClearMem
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Clear SBSS section to 0x00
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r0, =__sbss_start__
|
||||
ldr r1, =__sbss_end__
|
||||
sub r1, r0
|
||||
bl ClearMem
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy initialized data (data section) from LMA to VMA (ROM to RAM)
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r1, =__data_lma
|
||||
ldr r2, =__data_start__
|
||||
ldr r4, =__data_end__
|
||||
bl CopyMemChk
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy internal work ram (iwram section) from LMA to VMA (ROM to RAM)
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r1,= __iwram_lma
|
||||
ldr r2,= __iwram_start__
|
||||
ldr r4,= __iwram_end__
|
||||
bl CopyMemChk
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy internal work ram overlay 0 (iwram0 section) from LMA to VMA (ROM to RAM)
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r2,= __load_stop_iwram0
|
||||
ldr r1,= __load_start_iwram0
|
||||
sub r3, r2, r1 @ Is there any data to copy?
|
||||
beq CIW0Skip @ no
|
||||
|
||||
ldr r2,= __iwram_overlay_start
|
||||
bl CopyMem
|
||||
@---------------------------------------------------------------------------------
|
||||
CIW0Skip:
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy external work ram (ewram section) from LMA to VMA (ROM to RAM)
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r1, =__ewram_lma
|
||||
ldr r2, =__ewram_start
|
||||
ldr r4, =__ewram_end
|
||||
bl CopyMemChk
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
CEW0Skip:
|
||||
@---------------------------------------------------------------------------------
|
||||
@ set heap end
|
||||
@---------------------------------------------------------------------------------
|
||||
// fake_heap_end does not appear to exist,
|
||||
// and Nostalgia has its own heap allocator anyway
|
||||
//ldr r1, =fake_heap_end
|
||||
//ldr r0, =__eheap_end
|
||||
//str r0, [r1]
|
||||
@---------------------------------------------------------------------------------
|
||||
@ global constructors
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r3, =__libc_init_array
|
||||
bl _blx_r3_stub
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Jump to user code
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r3, =c_start
|
||||
bl _blx_r3_stub
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Clear memory to 0x00 if length != 0
|
||||
@---------------------------------------------------------------------------------
|
||||
@ r0 = Start Address
|
||||
@ r1 = Length
|
||||
@---------------------------------------------------------------------------------
|
||||
ClearMem:
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r2,#3 @ These commands are used in cases where
|
||||
add r1,r2 @ the length is not a multiple of 4,
|
||||
bic r1,r2 @ even though it should be.
|
||||
|
||||
beq ClearMX @ Length is zero so exit
|
||||
|
||||
mov r2,#0
|
||||
@---------------------------------------------------------------------------------
|
||||
ClrLoop:
|
||||
@---------------------------------------------------------------------------------
|
||||
stmia r0!, {r2}
|
||||
sub r1,#4
|
||||
bne ClrLoop
|
||||
@---------------------------------------------------------------------------------
|
||||
ClearMX:
|
||||
@---------------------------------------------------------------------------------
|
||||
bx lr
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
_blx_r3_stub:
|
||||
@---------------------------------------------------------------------------------
|
||||
bx r3
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy memory if length != 0
|
||||
@---------------------------------------------------------------------------------
|
||||
@ r1 = Source Address
|
||||
@ r2 = Dest Address
|
||||
@ r4 = Dest Address + Length
|
||||
@---------------------------------------------------------------------------------
|
||||
CopyMemChk:
|
||||
@---------------------------------------------------------------------------------
|
||||
sub r3, r4, r2 @ Is there any data to copy?
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy memory
|
||||
@---------------------------------------------------------------------------------
|
||||
@ r1 = Source Address
|
||||
@ r2 = Dest Address
|
||||
@ r3 = Length
|
||||
@---------------------------------------------------------------------------------
|
||||
CopyMem:
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r0, #3 @ These commands are used in cases where
|
||||
add r3, r0 @ the length is not a multiple of 4,
|
||||
bic r3, r0 @ even though it should be.
|
||||
beq CIDExit @ Length is zero so exit
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
CIDLoop:
|
||||
@---------------------------------------------------------------------------------
|
||||
ldmia r1!, {r0}
|
||||
stmia r2!, {r0}
|
||||
sub r3, #4
|
||||
bne CIDLoop
|
||||
@---------------------------------------------------------------------------------
|
||||
CIDExit:
|
||||
@---------------------------------------------------------------------------------
|
||||
bx lr
|
||||
|
||||
.align
|
||||
.pool
|
||||
.end
|
||||
|
12
deps/ox/.gdblogger.json
vendored
Normal file
12
deps/ox/.gdblogger.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"log_functions": [
|
||||
{
|
||||
"function": "ox::trace::gdblogger::captureLogFunc",
|
||||
"ignore_frames": 3,
|
||||
"file_var": "file",
|
||||
"line_var": "line",
|
||||
"channel_var": "ch",
|
||||
"msg_var": "msg"
|
||||
}
|
||||
]
|
||||
}
|
10
deps/ox/.gitignore
vendored
Normal file
10
deps/ox/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
build/current
|
||||
build/gba
|
||||
build/*-asan
|
||||
build/*-debug
|
||||
build/*-release
|
||||
tags
|
||||
conanbuildinfo.cmake
|
||||
conanbuildinfo.txt
|
||||
conaninfo.txt
|
||||
graph_info.json
|
9
deps/ox/.liccor.yml
vendored
Normal file
9
deps/ox/.liccor.yml
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
source:
|
||||
- src
|
||||
copyright_notice: |-
|
||||
Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
11
deps/ox/.travis.yml
vendored
Normal file
11
deps/ox/.travis.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
language: cpp
|
||||
sudo: false
|
||||
dist: trusty
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- cmake
|
||||
script: ./scripts/cibuild
|
76
deps/ox/CMakeLists.txt
vendored
Normal file
76
deps/ox/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(Ox)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
|
||||
include(address_sanitizer)
|
||||
|
||||
if(NOT DEFINED OX_RUN_TESTS)
|
||||
set(OX_RUN_TESTS ON)
|
||||
endif()
|
||||
if(NOT DEFINED OX_BUILD_EXEC)
|
||||
set(OX_BUILD_EXEC ON)
|
||||
endif()
|
||||
if(NOT DEFINED OX_USE_STDLIB)
|
||||
set(OX_USE_STDLIB ON)
|
||||
endif()
|
||||
if(NOT DEFINED OX_BARE_METAL)
|
||||
set(OX_BARE_METAL OFF)
|
||||
endif()
|
||||
|
||||
set(OX_RUN_TESTS ${OX_RUN_TESTS} CACHE BOOL "Run tests (ON/OFF)")
|
||||
set(OX_BUILD_EXEC ${OX_BUILD_EXEC} CACHE BOOL "Build executables (ON/OFF)")
|
||||
set(OX_USE_STDLIB ${OX_USE_STDLIB} CACHE BOOL "Build libraries that need the std lib (ON/OFF)")
|
||||
set(OX_BARE_METAL ${OX_BARE_METAL} CACHE BOOL "Bare metal build (TRUE/FALSE)")
|
||||
|
||||
# can't run tests without building them
|
||||
if(NOT OX_BUILD_EXEC OR NOT OX_USE_STDLIB)
|
||||
set(OX_BUILD_EXEC OFF)
|
||||
set(OX_RUN_TESTS OFF)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
add_definitions(-DNDEBUG)
|
||||
else()
|
||||
add_definitions(-DDEBUG)
|
||||
endif()
|
||||
|
||||
if(NOT OX_USE_STDLIB)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-align")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused-variable")
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||
endif()
|
||||
# forces colored output when using ninja
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color")
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
|
||||
include_directories("src")
|
||||
|
||||
install(FILES OxConfig.cmake DESTINATION lib/ox)
|
||||
|
||||
add_subdirectory(src)
|
373
deps/ox/LICENSE
vendored
Normal file
373
deps/ox/LICENSE
vendored
Normal file
@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
68
deps/ox/Makefile
vendored
Normal file
68
deps/ox/Makefile
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
OS=$(shell uname | tr [:upper:] [:lower:])
|
||||
HOST_ENV=${OS}-$(shell uname -m)
|
||||
DEVENV=devenv$(shell pwd | sed 's/\//-/g')
|
||||
DEVENV_IMAGE=wombatant/devenv
|
||||
ifneq ($(shell which docker 2>&1),)
|
||||
ifeq ($(shell docker inspect --format="{{.State.Status}}" ${DEVENV} 2>&1),running)
|
||||
ENV_RUN=docker exec -i -t --user $(shell id -u ${USER}) ${DEVENV}
|
||||
endif
|
||||
endif
|
||||
|
||||
all:
|
||||
${ENV_RUN} ./scripts/run-make build
|
||||
preinstall:
|
||||
${ENV_RUN} ./scripts/run-make build preinstall
|
||||
install:
|
||||
${ENV_RUN} ./scripts/run-make build install
|
||||
clean:
|
||||
${ENV_RUN} ./scripts/run-make build clean
|
||||
purge:
|
||||
${ENV_RUN} rm -rf build
|
||||
test:
|
||||
${ENV_RUN} ./scripts/run-make build test
|
||||
|
||||
devenv:
|
||||
docker pull ${DEVENV_IMAGE}
|
||||
docker run -d -v $(shell pwd):/usr/src/project \
|
||||
-e LOCAL_USER_ID=$(shell id -u ${USER}) \
|
||||
--name ${DEVENV} -t ${DEVENV_IMAGE} bash
|
||||
devenv-destroy:
|
||||
docker rm -f ${DEVENV}
|
||||
devenv-shell:
|
||||
${ENV_RUN} bash
|
||||
|
||||
configure-release:
|
||||
${ENV_RUN} rm -rf build/${HOST_ENV}-release
|
||||
${ENV_RUN} ./scripts/setup_build ${HOST_ENV}
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s ${HOST_ENV}-release build/current
|
||||
|
||||
configure-debug:
|
||||
${ENV_RUN} rm -rf build/${HOST_ENV}-debug
|
||||
${ENV_RUN} ./scripts/setup_build ${HOST_ENV} debug
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s ${HOST_ENV}-debug build/current
|
||||
|
||||
configure-asan:
|
||||
${ENV_RUN} rm -rf build/${HOST_ENV}-asan
|
||||
${ENV_RUN} ./scripts/setup_build ${HOST_ENV} asan
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s ${HOST_ENV}-asan build/current
|
||||
|
||||
configure-windows:
|
||||
${ENV_RUN} rm -rf build/windows
|
||||
${ENV_RUN} ./scripts/setup_build windows
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s windows build/current
|
||||
|
||||
configure-windows-debug:
|
||||
${ENV_RUN} rm -rf build/windows
|
||||
${ENV_RUN} ./scripts/setup_build windows debug
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s windows build/current
|
||||
|
||||
configure-gba:
|
||||
${ENV_RUN} rm -rf build/gba-release
|
||||
${ENV_RUN} ./scripts/setup_build gba
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s gba-release build/current
|
15
deps/ox/OxConfig.cmake
vendored
Normal file
15
deps/ox/OxConfig.cmake
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
if("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
|
||||
set(Ox_INCLUDE_DIRS /usr/local/include/)
|
||||
set(OxStd_LIBRARY /usr/local/lib/ox/libOxStd.a)
|
||||
set(OxFS_LIBRARY /usr/local/lib/ox/libOxFS.a)
|
||||
set(OxClArgs_LIBRARY /usr/local/lib/ox/libOxClArgs.a)
|
||||
set(OxMetalClaw_LIBRARY /usr/local/lib/ox/libOxMetalClaw.a)
|
||||
set(OxModel_LIBRARY /usr/local/lib/ox/libOxModelClaw.a)
|
||||
else("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
|
||||
set(Ox_INCLUDE_DIRS ${CMAKE_FIND_ROOT_PATH}/include/)
|
||||
set(OxStd_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxStd.a)
|
||||
set(OxFS_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxFS.a)
|
||||
set(OxClArgs_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxClArgs.a)
|
||||
set(OxMetalClaw_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxMetalClaw.a)
|
||||
set(OxModel_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxModel.a)
|
||||
endif("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
|
24
deps/ox/cmake/modules/GBA.cmake
vendored
Normal file
24
deps/ox/cmake/modules/GBA.cmake
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
set(CMAKE_SYSTEM_NAME "Generic")
|
||||
|
||||
set(DEVKITARM $ENV{DEVKITARM})
|
||||
|
||||
if(NOT DEVKITARM)
|
||||
message(FATAL_ERROR "DEVKITARM environment variable not set")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_COMPILER ${DEVKITARM}/bin/arm-none-eabi-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${DEVKITARM}/bin/arm-none-eabi-g++)
|
||||
set(CMAKE_FIND_ROOT_PATH ${DEVKITARM})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_PREFIXES lib)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||
|
||||
set(LINKER_FLAGS "-specs=gba.specs")
|
||||
add_definitions (
|
||||
-DARM7
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
18
deps/ox/cmake/modules/Mingw.cmake
vendored
Normal file
18
deps/ox/cmake/modules/Mingw.cmake
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
|
||||
|
||||
# cross compilers to use for C and C++
|
||||
set(CMAKE_C_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-g++)
|
||||
set(CMAKE_RC_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-windres)
|
||||
|
||||
# target environment on the build host system
|
||||
# set 1st to dir with the cross compiler's C/C++ headers/libs
|
||||
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
|
||||
|
||||
# modify default behavior of FIND_XXX() commands to
|
||||
# search for headers/libs in the target environment and
|
||||
# search for programs in the build host environment
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
52
deps/ox/cmake/modules/address_sanitizer.cmake
vendored
Normal file
52
deps/ox/cmake/modules/address_sanitizer.cmake
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
# This file belongs Nick Overdijk, and is from https://github.com/NickNick/wubwubcmake
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2013 Nick Overdijk
|
||||
#
|
||||
# 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.option(USE_ASAN "Enable Address Sanitizer, if your compiler supports it" ON)
|
||||
|
||||
option(USE_ASAN "Enable Address Sanitizer, if your compiler supports it" OFF)
|
||||
if(USE_ASAN)
|
||||
include(CheckCXXSourceCompiles)
|
||||
# If the compiler understands -fsanitize=address, add it to the flags (gcc since 4.8 & clang since version 3.2)
|
||||
set(CMAKE_REQUIRED_FLAGS_BAK "${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fsanitize=address")
|
||||
CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" FLAG_FSANA_SUPPORTED)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BAK}")
|
||||
|
||||
if(FLAG_FSANA_SUPPORTED)
|
||||
set(asan_flag "-fsanitize=address")
|
||||
else(FLAG_FSANA_SUPPORTED)
|
||||
# Alternatively, try if it understands -faddress-sanitizer (clang until version 3.2)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -faddress-sanitizer")
|
||||
CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" FLAG_FASAN_SUPPORTED)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BAK}")
|
||||
|
||||
if(FLAG_FASAN_SUPPORTED)
|
||||
set(asan_flag "-faddress-sanitizer")
|
||||
endif(FLAG_FASAN_SUPPORTED)
|
||||
endif(FLAG_FSANA_SUPPORTED)
|
||||
|
||||
if(FLAG_FSANA_SUPPORTED OR FLAG_FASAN_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${asan_flag}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${asan_flag}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${asan_flag}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${asan_flag}")
|
||||
endif()
|
||||
|
||||
endif(USE_ASAN)
|
8
deps/ox/scripts/cibuild
vendored
Executable file
8
deps/ox/scripts/cibuild
vendored
Executable file
@ -0,0 +1,8 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
make -j release
|
||||
make -j debug
|
||||
make -j
|
||||
make -j test
|
8
deps/ox/scripts/run-make
vendored
Executable file
8
deps/ox/scripts/run-make
vendored
Executable file
@ -0,0 +1,8 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
for f in $(find $1 -maxdepth 1 -mindepth 1 -type d)
|
||||
do
|
||||
cmake --build "$f" --target $2 --
|
||||
done
|
@ -8,13 +8,16 @@ TARGET=$1
|
||||
BUILD_TYPE=$2
|
||||
|
||||
if [[ $TARGET == windows ]]; then
|
||||
toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/Modules/Mingw.cmake"
|
||||
toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/modules/Mingw.cmake"
|
||||
elif [[ $TARGET == gba ]]; then
|
||||
toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/Modules/GBA.cmake -DWOMBAT_BUILD_TYPE=GBA"
|
||||
toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/modules/GBA.cmake -DOX_USE_STDLIB=OFF -DCMAKE_INSTALL_PREFIX=$DEVKITARM"
|
||||
fi
|
||||
|
||||
if [[ $BUILD_TYPE == debug ]]; then
|
||||
if [[ $BUILD_TYPE == asan ]]; then
|
||||
buildTypeArgs="-DUSE_ASAN=ON -DCMAKE_BUILD_TYPE=Debug"
|
||||
buildDir="build/${TARGET}-asan"
|
||||
elif [[ $BUILD_TYPE == debug ]]; then
|
||||
buildTypeArgs="-DCMAKE_BUILD_TYPE=Debug"
|
||||
buildDir="build/${TARGET}-debug"
|
||||
else
|
||||
buildTypeArgs="-DCMAKE_BUILD_TYPE=Release"
|
||||
@ -24,7 +27,8 @@ fi
|
||||
mkdir -p $buildDir
|
||||
pushd $buildDir
|
||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-GNinja \
|
||||
$buildTypeArgs \
|
||||
$toolchain \
|
||||
$project
|
||||
$toolchain \
|
||||
$project
|
||||
popd
|
3
deps/ox/src/CMakeLists.txt
vendored
Normal file
3
deps/ox/src/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
add_subdirectory(ox)
|
10
deps/ox/src/ox/CMakeLists.txt
vendored
Normal file
10
deps/ox/src/ox/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
if(${OX_USE_STDLIB})
|
||||
add_subdirectory(clargs)
|
||||
add_subdirectory(claw)
|
||||
add_subdirectory(oc)
|
||||
endif()
|
||||
add_subdirectory(fs)
|
||||
add_subdirectory(mc)
|
||||
add_subdirectory(ptrarith)
|
||||
add_subdirectory(model)
|
||||
add_subdirectory(std)
|
29
deps/ox/src/ox/clargs/CMakeLists.txt
vendored
Normal file
29
deps/ox/src/ox/clargs/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
add_library(
|
||||
OxClArgs
|
||||
clargs.cpp
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
OxClArgs
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
|
||||
target_link_libraries(OxClArgs OxStd)
|
||||
|
||||
install(
|
||||
FILES
|
||||
clargs.hpp
|
||||
DESTINATION
|
||||
include/ox/clargs
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
OxClArgs
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
53
deps/ox/src/ox/clargs/clargs.cpp
vendored
Normal file
53
deps/ox/src/ox/clargs/clargs.cpp
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/strops.hpp>
|
||||
#include "clargs.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
using namespace ::std;
|
||||
|
||||
ClArgs::ClArgs(int argc, const char **args) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
string arg = args[i];
|
||||
if (arg[0] == '-') {
|
||||
while (arg[0] == '-' && arg.size()) {
|
||||
arg = arg.substr(1);
|
||||
}
|
||||
m_bools[arg] = true;
|
||||
|
||||
// parse additional arguments
|
||||
if (i < argc && args[i + 1]) {
|
||||
string val = args[i + 1];
|
||||
if (val.size() && val[i] != '-') {
|
||||
if (val == "false") {
|
||||
m_bools[arg] = false;
|
||||
}
|
||||
m_strings[arg] = val;
|
||||
m_ints[arg] = ox_atoi(val.c_str());
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ClArgs::getBool(const char *arg) {
|
||||
return m_bools[arg];
|
||||
}
|
||||
|
||||
string ClArgs::getString(const char *arg) {
|
||||
return m_strings[arg];
|
||||
}
|
||||
|
||||
int ClArgs::getInt(const char *arg) {
|
||||
return m_ints[arg];
|
||||
}
|
||||
|
||||
}
|
32
deps/ox/src/ox/clargs/clargs.hpp
vendored
Normal file
32
deps/ox/src/ox/clargs/clargs.hpp
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <map>
|
||||
#include <string>
|
||||
|
||||
namespace ox {
|
||||
|
||||
class ClArgs {
|
||||
private:
|
||||
::std::map<::std::string, bool> m_bools;
|
||||
::std::map<::std::string, ::std::string> m_strings;
|
||||
::std::map<::std::string, int> m_ints;
|
||||
|
||||
public:
|
||||
ClArgs(int argc, const char **args);
|
||||
|
||||
bool getBool(const char *arg);
|
||||
|
||||
::std::string getString(const char *arg);
|
||||
|
||||
int getInt(const char *arg);
|
||||
};
|
||||
|
||||
}
|
14
deps/ox/src/ox/claw/CMakeLists.txt
vendored
Normal file
14
deps/ox/src/ox/claw/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
add_library(
|
||||
OxClaw
|
||||
read.cpp
|
||||
write.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
OxClaw
|
||||
OxMetalClaw
|
||||
OxOrganicClaw
|
||||
)
|
||||
|
||||
add_subdirectory(test)
|
12
deps/ox/src/ox/claw/claw.hpp
vendored
Normal file
12
deps/ox/src/ox/claw/claw.hpp
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "read.hpp"
|
||||
#include "write.hpp"
|
@ -1,18 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "gfx.hpp"
|
||||
namespace ox {
|
||||
|
||||
namespace nostalgia {
|
||||
namespace core {
|
||||
|
||||
ox::Error init();
|
||||
enum class ClawFormat: int {
|
||||
None,
|
||||
Metal,
|
||||
Organic,
|
||||
};
|
||||
|
||||
}
|
||||
}
|
68
deps/ox/src/ox/claw/read.cpp
vendored
Normal file
68
deps/ox/src/ox/claw/read.cpp
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "read.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace detail {
|
||||
|
||||
ValErr<ClawHeader> readHeader(const char *buff, std::size_t buffLen) noexcept {
|
||||
const auto s1End = ox_strchr(buff, ';', buffLen);
|
||||
if (!s1End) {
|
||||
return OxError(1);
|
||||
}
|
||||
const auto s1Size = s1End - buff;
|
||||
String fmt(buff, s1Size);
|
||||
buff += s1Size + 1;
|
||||
buffLen -= s1Size + 1;
|
||||
|
||||
const auto s2End = ox_strchr(buff, ';', buffLen);
|
||||
if (!s2End) {
|
||||
return OxError(1);
|
||||
}
|
||||
const auto s2Size = s2End - buff;
|
||||
String typeName(buff, s2Size);
|
||||
buff += s2Size + 1;
|
||||
buffLen -= s2Size + 1;
|
||||
|
||||
const auto s3End = ox_strchr(buff, ';', buffLen);
|
||||
if (!s3End) {
|
||||
return OxError(1);
|
||||
}
|
||||
const auto s3Size = s3End - buff;
|
||||
String versionStr(buff, s3Size);
|
||||
buff += s3Size + 1;
|
||||
buffLen -= s3Size + 1;
|
||||
|
||||
ClawHeader hdr;
|
||||
if (fmt == "M1") {
|
||||
hdr.fmt = ClawFormat::Metal;
|
||||
} else if (fmt == "O1") {
|
||||
hdr.fmt = ClawFormat::Organic;
|
||||
} else {
|
||||
return OxError(1);
|
||||
}
|
||||
hdr.typeName = typeName;
|
||||
hdr.typeVersion = ox_atoi(versionStr.c_str());
|
||||
hdr.data = buff;
|
||||
hdr.dataSize = buffLen;
|
||||
return hdr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ValErr<Vector<char>> stripClawHeader(const char *buff, std::size_t buffLen) noexcept {
|
||||
auto header = detail::readHeader(buff, buffLen);
|
||||
oxReturnError(header);
|
||||
Vector<char> out(header.value.dataSize);
|
||||
ox_memcpy(out.data(), header.value.data, out.size());
|
||||
return ox::move(out);
|
||||
}
|
||||
|
||||
}
|
57
deps/ox/src/ox/claw/read.hpp
vendored
Normal file
57
deps/ox/src/ox/claw/read.hpp
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/mc/read.hpp>
|
||||
#include <ox/oc/read.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "format.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct ClawHeader {
|
||||
String typeName;
|
||||
int typeVersion = -1;
|
||||
ClawFormat fmt = ClawFormat::None;
|
||||
const char *data = nullptr;
|
||||
std::size_t dataSize = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] ValErr<ClawHeader> readHeader(const char *buff, std::size_t buffLen) noexcept;
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] ValErr<Vector<char>> stripClawHeader(const char *buff, std::size_t buffLen) noexcept;
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error readClaw(char *buff, std::size_t buffLen, T *val) {
|
||||
auto header = detail::readHeader(buff, buffLen);
|
||||
oxReturnError(header);
|
||||
switch (header.value.fmt) {
|
||||
case ClawFormat::Metal:
|
||||
{
|
||||
MetalClawReader reader(bit_cast<uint8_t*>(header.value.data), buffLen);
|
||||
return model(&reader, val);
|
||||
}
|
||||
case ClawFormat::Organic:
|
||||
{
|
||||
OrganicClawReader reader(bit_cast<uint8_t*>(header.value.data), buffLen);
|
||||
return model(&reader, val);
|
||||
}
|
||||
case ClawFormat::None:
|
||||
return OxError(1);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
}
|
14
deps/ox/src/ox/claw/test/CMakeLists.txt
vendored
Normal file
14
deps/ox/src/ox/claw/test/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
add_executable(
|
||||
ClawTest
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
ClawTest
|
||||
OxClaw
|
||||
)
|
||||
|
||||
add_test("Test\\ ClawTest\\ ClawHeaderReader" ClawTest ClawHeaderReader)
|
||||
add_test("Test\\ ClawTest\\ ClawHeaderReader2" ClawTest ClawHeaderReader2)
|
||||
add_test("Test\\ ClawTest\\ ClawWriter" ClawTest ClawWriter)
|
||||
add_test("Test\\ ClawTest\\ ClawReader" ClawTest ClawReader)
|
206
deps/ox/src/ox/claw/test/tests.cpp
vendored
Normal file
206
deps/ox/src/ox/claw/test/tests.cpp
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#undef NDEBUG
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ox/claw/format.hpp>
|
||||
#include <ox/claw/read.hpp>
|
||||
#include <ox/claw/write.hpp>
|
||||
#include <ox/mc/mc.hpp>
|
||||
#include <ox/model/model.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
union TestUnion {
|
||||
static constexpr auto TypeName = "TestUnion";
|
||||
static constexpr auto Fields = 3;
|
||||
bool Bool;
|
||||
uint32_t Int = 5;
|
||||
char String[32];
|
||||
};
|
||||
|
||||
struct TestStructNest {
|
||||
static constexpr auto TypeName = "TestStructNest";
|
||||
static constexpr auto Fields = 3;
|
||||
bool Bool = false;
|
||||
uint32_t Int = 0;
|
||||
ox::BString<32> String = "";
|
||||
};
|
||||
|
||||
struct TestStruct {
|
||||
static constexpr auto TypeName = "TestStruct";
|
||||
static constexpr auto Fields = 16;
|
||||
bool Bool = false;
|
||||
int32_t Int = 0;
|
||||
int32_t Int1 = 0;
|
||||
int32_t Int2 = 0;
|
||||
int32_t Int3 = 0;
|
||||
int32_t Int4 = 0;
|
||||
int32_t Int5 = 0;
|
||||
int32_t Int6 = 0;
|
||||
int32_t Int7 = 0;
|
||||
int32_t Int8 = 0;
|
||||
TestUnion Union;
|
||||
char *CString = nullptr;
|
||||
ox::BString<32> String = "";
|
||||
uint32_t List[4] = {0, 0, 0, 0};
|
||||
TestStructNest EmptyStruct;
|
||||
TestStructNest Struct;
|
||||
|
||||
~TestStruct() {
|
||||
delete[] CString;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestUnion *obj) {
|
||||
io->template setTypeInfo<TestUnion>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", ox::SerStr(obj->String)));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStructNest *obj) {
|
||||
io->template setTypeInfo<TestStructNest>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStruct *obj) {
|
||||
io->template setTypeInfo<TestStruct>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("Int1", &obj->Int1));
|
||||
oxReturnError(io->field("Int2", &obj->Int2));
|
||||
oxReturnError(io->field("Int3", &obj->Int3));
|
||||
oxReturnError(io->field("Int4", &obj->Int4));
|
||||
oxReturnError(io->field("Int5", &obj->Int5));
|
||||
oxReturnError(io->field("Int6", &obj->Int6));
|
||||
oxReturnError(io->field("Int7", &obj->Int7));
|
||||
oxReturnError(io->field("Int8", &obj->Int8));
|
||||
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
|
||||
oxReturnError(io->field("CString", ox::SerStr(&obj->CString)));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
oxReturnError(io->field("List", obj->List, 4));
|
||||
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
|
||||
oxReturnError(io->field("Struct", &obj->Struct));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
std::map<std::string, ox::Error(*)()> tests = {
|
||||
{
|
||||
{
|
||||
"ClawHeaderReader",
|
||||
[] {
|
||||
ox::String hdr = "O1;com.drinkingtea.ox.claw.test.Header;2;";
|
||||
auto [ch, err] = ox::detail::readHeader(hdr.c_str(), hdr.len() + 1);
|
||||
oxAssert(err, "Error parsing header");
|
||||
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong");
|
||||
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong");
|
||||
oxAssert(ch.typeVersion == 2, "Type version wrong");
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"ClawHeaderReader2",
|
||||
[] {
|
||||
ox::String hdr = "M1;com.drinkingtea.ox.claw.test.Header2;3;";
|
||||
auto [ch, err] = ox::detail::readHeader(hdr.c_str(), hdr.len() + 1);
|
||||
oxAssert(err, "Error parsing header");
|
||||
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
|
||||
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong");
|
||||
oxAssert(ch.typeVersion == 3, "Type version wrong");
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"ClawWriter",
|
||||
[] {
|
||||
// This test doesn't confirm much, but it does show that the writer
|
||||
// doesn't segfault
|
||||
TestStruct ts;
|
||||
oxReturnError(ox::writeClaw(&ts, ox::ClawFormat::Metal));
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"ClawReader",
|
||||
[] {
|
||||
TestStruct testIn, testOut;
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.Union.Int = 42;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.CString = new char[ox_strlen("c-string") + 1];
|
||||
ox_strcpy(testIn.CString, "c-string");
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
auto [buff, err] = ox::writeClaw(&testIn, ox::ClawFormat::Metal);
|
||||
oxAssert(err, "writeMC failed");
|
||||
oxAssert(ox::readClaw(buff.data(), buff.size(), &testOut), "writeMC failed");
|
||||
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
|
||||
|
||||
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
|
||||
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
|
||||
oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch");
|
||||
oxAssert(testIn.Int2 == testOut.Int2, "Int2 value mismatch");
|
||||
oxAssert(testIn.Int3 == testOut.Int3, "Int3 value mismatch");
|
||||
oxAssert(testIn.Int4 == testOut.Int4, "Int4 value mismatch");
|
||||
oxAssert(testIn.Int5 == testOut.Int5, "Int5 value mismatch");
|
||||
oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch");
|
||||
oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch");
|
||||
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
|
||||
oxAssert(ox_strcmp(testIn.CString, testOut.CString) == 0, "CString value mismatch");
|
||||
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
|
||||
oxAssert(testIn.String == testOut.String, "String value mismatch");
|
||||
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
|
||||
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
|
||||
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
|
||||
oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.String == testOut.EmptyStruct.String, "EmptyStruct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch");
|
||||
oxAssert(testIn.Struct.String == testOut.Struct.String, "Struct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch");
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
int retval = -1;
|
||||
if (argc > 0) {
|
||||
auto testName = args[1];
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
retval = tests[testName]();
|
||||
} else {
|
||||
retval = 1;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
23
deps/ox/src/ox/claw/write.cpp
vendored
Normal file
23
deps/ox/src/ox/claw/write.cpp
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "write.hpp"
|
||||
|
||||
namespace ox::detail {
|
||||
|
||||
struct versioned_type {
|
||||
static constexpr int TypeVersion = 4;
|
||||
};
|
||||
|
||||
struct unversioned_type {
|
||||
};
|
||||
|
||||
static_assert(type_version<versioned_type>::value == 4);
|
||||
static_assert(type_version<unversioned_type>::value == -1);
|
||||
|
||||
}
|
104
deps/ox/src/ox/claw/write.hpp
vendored
Normal file
104
deps/ox/src/ox/claw/write.hpp
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/mc/write.hpp>
|
||||
#include <ox/oc/write.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "format.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct TypeInfoCatcher {
|
||||
|
||||
const char *name = nullptr;
|
||||
|
||||
template<typename T = void>
|
||||
constexpr void setTypeInfo(const char *name = T::TypeName, int = T::Fields) noexcept {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
constexpr ox::Error field(...) noexcept {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::Write;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr int getTypeVersion(int version = T::TypeVersion) noexcept {
|
||||
return version;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr int getTypeVersion(...) noexcept {
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<typename T, typename = int>
|
||||
struct type_version {
|
||||
static constexpr auto value = -1;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct type_version<T, decltype((void) T::TypeVersion, -1)> {
|
||||
static constexpr auto value = T::TypeVersion;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr const char *getTypeName(T *t) noexcept {
|
||||
TypeInfoCatcher tnc;
|
||||
model(&tnc, t);
|
||||
return tnc.name;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValErr<String> writeClawHeader(T *t, ClawFormat fmt) noexcept {
|
||||
String out;
|
||||
switch (fmt) {
|
||||
case ClawFormat::Metal:
|
||||
out += "M1;";
|
||||
break;
|
||||
case ClawFormat::Organic:
|
||||
out += "O1;";
|
||||
break;
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
out += detail::getTypeName(t);
|
||||
out += ";";
|
||||
const auto tn = detail::type_version<T>::value;
|
||||
if (tn > -1) {
|
||||
out += tn;
|
||||
}
|
||||
out += ";";
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValErr<Vector<char>> writeClaw(T *t, ClawFormat fmt) {
|
||||
auto [header, headerErr] = detail::writeClawHeader(t, fmt);
|
||||
oxReturnError(headerErr);
|
||||
const auto [data, dataErr] = fmt == ClawFormat::Metal ? writeMC(t) : writeOC(t);
|
||||
oxReturnError(dataErr);
|
||||
ox::Vector<char> out(header.len() + data.size());
|
||||
memcpy(out.data(), header.data(), header.len());
|
||||
memcpy(out.data() + header.len(), data.data(), data.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
71
deps/ox/src/ox/fs/CMakeLists.txt
vendored
Normal file
71
deps/ox/src/ox/fs/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
add_library(
|
||||
OxFS
|
||||
filestore/filestoretemplate.cpp
|
||||
filesystem/filelocation.cpp
|
||||
filesystem/pathiterator.cpp
|
||||
filesystem/directory.cpp
|
||||
filesystem/filesystem.cpp
|
||||
filesystem/passthroughfs.cpp
|
||||
)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
if(NOT APPLE)
|
||||
target_link_libraries(
|
||||
OxFS PUBLIC
|
||||
stdc++fs
|
||||
)
|
||||
endif()
|
||||
set_property(
|
||||
TARGET
|
||||
OxFS
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(
|
||||
OxFS PUBLIC
|
||||
OxMetalClaw
|
||||
)
|
||||
|
||||
if(OX_BUILD_EXEC STREQUAL "ON")
|
||||
#add_executable(
|
||||
# oxfstool
|
||||
# toollib.cpp
|
||||
# oxfstool.cpp
|
||||
#)
|
||||
#set_target_properties(oxfstool PROPERTIES OUTPUT_NAME oxfs)
|
||||
#target_link_libraries(
|
||||
# oxfstool
|
||||
# OxFS
|
||||
# OxMetalClaw
|
||||
# OxStd
|
||||
#)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES
|
||||
filestore/filestoretemplate.hpp
|
||||
DESTINATION
|
||||
include/ox/fs/filestore
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
filesystem/filesystem.hpp
|
||||
filesystem/pathiterator.hpp
|
||||
DESTINATION
|
||||
include/ox/fs/filesystem
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
OxFS
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
16
deps/ox/src/ox/fs/filestore/filestoretemplate.cpp
vendored
Normal file
16
deps/ox/src/ox/fs/filestore/filestoretemplate.cpp
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "filestoretemplate.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template class FileStoreTemplate<uint16_t>;
|
||||
template class FileStoreTemplate<uint32_t>;
|
||||
|
||||
}
|
777
deps/ox/src/ox/fs/filestore/filestoretemplate.hpp
vendored
Normal file
777
deps/ox/src/ox/fs/filestore/filestoretemplate.hpp
vendored
Normal file
@ -0,0 +1,777 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/ptrarith/nodebuffer.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
using InodeId_t = uint64_t;
|
||||
using FsSize_t = std::size_t;
|
||||
|
||||
struct StatInfo {
|
||||
InodeId_t inode = 0;
|
||||
InodeId_t links = 0;
|
||||
FsSize_t size = 0;
|
||||
uint8_t fileType = 0;
|
||||
};
|
||||
|
||||
template<typename size_t>
|
||||
struct OX_PACKED FileStoreItem: public ptrarith::Item<size_t> {
|
||||
ox::LittleEndian<size_t> id = 0;
|
||||
ox::LittleEndian<uint8_t> fileType = 0;
|
||||
ox::LittleEndian<size_t> links = 0;
|
||||
ox::LittleEndian<size_t> left = 0;
|
||||
ox::LittleEndian<size_t> right = 0;
|
||||
|
||||
FileStoreItem() = default;
|
||||
|
||||
explicit FileStoreItem(size_t size) {
|
||||
this->setSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of the data + the size of the Item type
|
||||
*/
|
||||
size_t fullSize() const {
|
||||
return sizeof(*this) + this->size();
|
||||
}
|
||||
|
||||
ptrarith::Ptr<uint8_t, std::size_t> data() {
|
||||
return ptrarith::Ptr<uint8_t, std::size_t>(this, this->fullSize(), sizeof(*this), this->size());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename size_t>
|
||||
class FileStoreTemplate {
|
||||
|
||||
public:
|
||||
using InodeId_t = size_t;
|
||||
|
||||
private:
|
||||
using Item = FileStoreItem<size_t>;
|
||||
using ItemPtr = typename ptrarith::NodeBuffer<size_t, FileStoreItem<size_t>>::ItemPtr;
|
||||
using Buffer = ptrarith::NodeBuffer<size_t, FileStoreItem<size_t>>;
|
||||
|
||||
static constexpr InodeId_t ReservedInodeEnd = 100;
|
||||
static constexpr auto MaxInode = MaxValue<size_t> / 2;
|
||||
|
||||
struct OX_PACKED FileStoreData {
|
||||
ox::LittleEndian<size_t> rootNode = 0;
|
||||
ox::Random random;
|
||||
};
|
||||
|
||||
size_t m_buffSize = 0;
|
||||
mutable Buffer *m_buffer = nullptr;
|
||||
|
||||
public:
|
||||
FileStoreTemplate() = default;
|
||||
|
||||
FileStoreTemplate(void *buff, size_t buffSize);
|
||||
|
||||
[[nodiscard]] static Error format(void *buffer, size_t bufferSize);
|
||||
|
||||
[[nodiscard]] Error setSize(InodeId_t buffSize);
|
||||
|
||||
[[nodiscard]] Error incLinks(InodeId_t id);
|
||||
|
||||
[[nodiscard]] Error decLinks(InodeId_t id);
|
||||
|
||||
[[nodiscard]] Error write(InodeId_t id, void *data, FsSize_t dataLen, uint8_t fileType = 0);
|
||||
|
||||
[[nodiscard]] Error remove(InodeId_t id);
|
||||
|
||||
[[nodiscard]] Error read(InodeId_t id, void *data, FsSize_t dataSize, FsSize_t *size = nullptr) const;
|
||||
|
||||
[[nodiscard]] Error read(InodeId_t id, FsSize_t readStart, FsSize_t readSize, void *data, FsSize_t *size = nullptr) const;
|
||||
|
||||
const ptrarith::Ptr<uint8_t, std::size_t> read(InodeId_t id) const;
|
||||
|
||||
/**
|
||||
* Reads the "file" at the given id. You are responsible for freeing
|
||||
* the data when done with it.
|
||||
* @param id id of the "file"
|
||||
* @param readStart where in the data to start reading
|
||||
* @param readSize how much data to read
|
||||
* @param data pointer to the pointer where the data is stored
|
||||
* @param size pointer to a value that will be assigned the size of data
|
||||
* @return 0 if read is a success
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] ox::Error read(InodeId_t id, FsSize_t readStart,
|
||||
FsSize_t readSize, T *data,
|
||||
FsSize_t *size) const;
|
||||
|
||||
[[nodiscard]] ValErr<StatInfo> stat(InodeId_t id);
|
||||
|
||||
[[nodiscard]] ox::Error resize();
|
||||
|
||||
[[nodiscard]] ox::Error resize(std::size_t size, void *newBuff = nullptr);
|
||||
|
||||
[[nodiscard]] InodeId_t spaceNeeded(FsSize_t size);
|
||||
|
||||
[[nodiscard]] InodeId_t size() const;
|
||||
|
||||
[[nodiscard]] InodeId_t available();
|
||||
|
||||
[[nodiscard]] char *buff();
|
||||
|
||||
[[nodiscard]] Error walk(Error(*cb)(uint8_t, uint64_t, uint64_t));
|
||||
|
||||
[[nodiscard]] ValErr<InodeId_t> generateInodeId();
|
||||
|
||||
bool valid() const;
|
||||
|
||||
[[nodiscard]] ox::Error compact();
|
||||
|
||||
private:
|
||||
FileStoreData *fileStoreData() const;
|
||||
|
||||
/**
|
||||
* Places the given Item at the given ID. If it already exists, the
|
||||
* existing value will be overwritten.
|
||||
*/
|
||||
Error placeItem(ItemPtr item);
|
||||
|
||||
/**
|
||||
* Places the given Item at the given ID. If it already exists, the
|
||||
* existing value will be overwritten.
|
||||
*/
|
||||
Error placeItem(ItemPtr root, ItemPtr item, int depth = 0);
|
||||
|
||||
/**
|
||||
* Removes the given Item at the given ID. If it already exists, the
|
||||
* existing value will be overwritten.
|
||||
*/
|
||||
Error unplaceItem(ItemPtr item);
|
||||
|
||||
/**
|
||||
* Removes the given Item at the given ID. If it already exists, the
|
||||
* existing value will be overwritten.
|
||||
*/
|
||||
Error unplaceItem(ItemPtr root, ItemPtr item, int depth = 0);
|
||||
|
||||
Error remove(ItemPtr item);
|
||||
|
||||
/**
|
||||
* Finds the parent an inode by its ID.
|
||||
*/
|
||||
ItemPtr findParent(ItemPtr ptr, size_t id, size_t oldAddr) const;
|
||||
|
||||
/**
|
||||
* Finds an inode by its ID.
|
||||
*/
|
||||
ItemPtr find(ItemPtr item, InodeId_t id, int depth = 0) const;
|
||||
|
||||
/**
|
||||
* Finds an inode by its ID.
|
||||
*/
|
||||
ItemPtr find(InodeId_t id) const;
|
||||
|
||||
/**
|
||||
* Gets the root inode.
|
||||
*/
|
||||
ItemPtr rootInode();
|
||||
|
||||
bool canWrite(ItemPtr existing, size_t size);
|
||||
|
||||
};
|
||||
|
||||
template<typename size_t>
|
||||
FileStoreTemplate<size_t>::FileStoreTemplate(void *buff, size_t buffSize) {
|
||||
m_buffSize = buffSize;
|
||||
m_buffer = reinterpret_cast<ptrarith::NodeBuffer<size_t, FileStoreItem<size_t>>*>(buff);
|
||||
if (!m_buffer->valid(buffSize)) {
|
||||
m_buffSize = 0;
|
||||
m_buffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::format(void *buffer, size_t bufferSize) {
|
||||
auto nb = new (buffer) Buffer(bufferSize);
|
||||
auto fsData = nb->malloc(sizeof(FileStoreData));
|
||||
if (fsData.valid()) {
|
||||
auto data = nb->template dataOf<FileStoreData>(fsData);
|
||||
if (data.valid()) {
|
||||
new (data) FileStoreData;
|
||||
return OxError(0);
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::format::fail") << "Could not read data section of FileStoreData";
|
||||
}
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::setSize(InodeId_t size) {
|
||||
if (m_buffSize >= size) {
|
||||
return m_buffer->setSize(size);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::incLinks(InodeId_t id) {
|
||||
auto item = find(id);
|
||||
if (item.valid()) {
|
||||
item->links++;
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::decLinks(InodeId_t id) {
|
||||
auto item = find(id);
|
||||
if (item.valid()) {
|
||||
item->links--;
|
||||
if (item->links == 0) {
|
||||
remove(item);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::write(InodeId_t id, void *data, FsSize_t dataSize, uint8_t fileType) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Attempting to write to inode" << id;
|
||||
auto existing = find(id);
|
||||
if (!canWrite(existing, dataSize)) {
|
||||
oxReturnError(compact());
|
||||
existing = find(id);
|
||||
}
|
||||
|
||||
if (canWrite(existing, dataSize)) {
|
||||
// delete the old node if it exists
|
||||
if (existing.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Freeing old version of inode found at offset:" << existing.offset();
|
||||
auto err = m_buffer->free(existing);
|
||||
if (err) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write::fail") << "Free of old version of inode failed";
|
||||
return err;
|
||||
}
|
||||
existing = nullptr;
|
||||
}
|
||||
|
||||
// write the given data
|
||||
auto dest = m_buffer->malloc(dataSize);
|
||||
// if first malloc failed, compact and try again
|
||||
if (!dest.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Allocation failed, compacting";
|
||||
oxReturnError(compact());
|
||||
dest = m_buffer->malloc(dataSize);
|
||||
}
|
||||
if (dest.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Memory allocated";
|
||||
dest->id = id;
|
||||
dest->fileType = fileType;
|
||||
auto destData = m_buffer->template dataOf<uint8_t>(dest);
|
||||
if (destData.valid()) {
|
||||
oxAssert(destData.size() == dataSize, "Allocation size does not match data.");
|
||||
// write data if any was provided
|
||||
if (data != nullptr) {
|
||||
ox_memcpy(destData, data, dest->size());
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Data written";
|
||||
}
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Searching for root node at" << fsData->rootNode;
|
||||
auto root = m_buffer->ptr(fsData->rootNode);
|
||||
if (root.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Placing" << dest->id << "on" << root->id << "at" << destData.offset();
|
||||
return placeItem(dest);
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Initializing root inode:" << dest->id << "( offset:" << dest.offset()
|
||||
<< ", data size:" << destData.size() << ")";
|
||||
fsData->rootNode = dest.offset();
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Root inode:" << dest->id;
|
||||
return OxError(0);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write::fail") << "Could not place item due to absence of FileStore header.";
|
||||
}
|
||||
}
|
||||
}
|
||||
oxReturnError(m_buffer->free(dest));
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::remove(InodeId_t id) {
|
||||
return remove(find(id));
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::read(InodeId_t id, void *out, FsSize_t outSize, FsSize_t *size) const {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read") << "Attempting to read from inode" << id;
|
||||
|
||||
auto src = find(id);
|
||||
|
||||
// error check
|
||||
if (!src.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not find requested item:" << id;
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
auto srcData = m_buffer->template dataOf<uint8_t>(src);
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::found") << id << "found at"<< src.offset()
|
||||
<< "with data section at" << srcData.offset();
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::outSize") << srcData.offset() << srcData.size() << outSize;
|
||||
|
||||
// error check
|
||||
if (!(srcData.valid() && srcData.size() <= outSize)) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail")
|
||||
<< "Could not read data section of item:" << id;
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail").del("")
|
||||
<< "Item data section size: " << srcData.size()
|
||||
<< ", Expected size: " << outSize;
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
ox_memcpy(out, srcData, srcData.size());
|
||||
if (size) {
|
||||
*size = src.size();
|
||||
}
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::read(InodeId_t id, FsSize_t readStart, FsSize_t readSize, void *data, FsSize_t *size) const {
|
||||
auto src = find(id);
|
||||
if (src.valid()) {
|
||||
auto srcData = src->data();
|
||||
if (srcData.valid()) {
|
||||
auto sub = srcData.template subPtr<uint8_t>(readStart, readSize);
|
||||
if (sub.valid()) {
|
||||
ox_memcpy(data, sub, sub.size());
|
||||
if (size) {
|
||||
*size = sub.size();
|
||||
}
|
||||
return OxError(0);
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not read requested data sub-section of item:" << id;
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not read data section of item:" << id;
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not find requested item:" << id;
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
template<typename T>
|
||||
Error FileStoreTemplate<size_t>::read(InodeId_t id, FsSize_t readStart,
|
||||
FsSize_t readSize, T *data, FsSize_t *size) const {
|
||||
auto src = find(id);
|
||||
if (src.valid()) {
|
||||
auto srcData = src->data();
|
||||
if (srcData.valid()) {
|
||||
auto sub = srcData.template subPtr<uint8_t>(readStart, readSize);
|
||||
if (sub.valid() && sub.size() % sizeof(T)) {
|
||||
for (FsSize_t i = 0; i < sub.size() / sizeof(T); i++) {
|
||||
// do byte-by-byte copy to ensure alignment is right when
|
||||
// copying to final destination
|
||||
T tmp;
|
||||
for (size_t ii = 0; ii < sizeof(T); ii++) {
|
||||
reinterpret_cast<uint8_t*>(&tmp)[ii] = *(sub.get() + ii);
|
||||
}
|
||||
*(data + i) = tmp;
|
||||
}
|
||||
if (size) {
|
||||
*size = sub.size();
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
const ptrarith::Ptr<uint8_t, std::size_t> FileStoreTemplate<size_t>::read(InodeId_t id) const {
|
||||
auto item = find(id);
|
||||
if (item.valid()) {
|
||||
return item->data();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
ox::Error FileStoreTemplate<size_t>::resize() {
|
||||
oxReturnError(compact());
|
||||
const auto newSize = size() - available();
|
||||
oxTrace("ox::fs::FileStoreTemplate::resize") << "resize to:" << newSize;
|
||||
oxReturnError(m_buffer->setSize(newSize));
|
||||
oxTrace("ox::fs::FileStoreTemplate::resize") << "resized to:" << m_buffer->size();
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::resize(std::size_t size, void *newBuff) {
|
||||
if (m_buffer->size() > size) {
|
||||
return OxError(1);
|
||||
}
|
||||
m_buffSize = size;
|
||||
if (newBuff) {
|
||||
m_buffer = reinterpret_cast<Buffer*>(newBuff);
|
||||
oxReturnError(m_buffer->setSize(size));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
ValErr<StatInfo> FileStoreTemplate<size_t>::stat(InodeId_t id) {
|
||||
auto inode = find(id);
|
||||
if (inode.valid()) {
|
||||
return ValErr<StatInfo>({
|
||||
id,
|
||||
inode->links,
|
||||
inode->size(),
|
||||
inode->fileType,
|
||||
});
|
||||
}
|
||||
return ValErr<StatInfo>({}, OxError(0));
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::InodeId_t FileStoreTemplate<size_t>::spaceNeeded(FsSize_t size) {
|
||||
return m_buffer->spaceNeeded(size);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::InodeId_t FileStoreTemplate<size_t>::size() const {
|
||||
return m_buffer->size();
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::InodeId_t FileStoreTemplate<size_t>::available() {
|
||||
return m_buffer->available();
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
char *FileStoreTemplate<size_t>::buff() {
|
||||
return reinterpret_cast<char*>(m_buffer);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) {
|
||||
for (auto i = m_buffer->iterator(); i.valid(); i.next()) {
|
||||
oxReturnError(cb(i->fileType, i.ptr().offset(), i.ptr().end()));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
ValErr<typename FileStoreTemplate<size_t>::InodeId_t> FileStoreTemplate<size_t>::generateInodeId() {
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
for (auto i = 0; i < 100; i++) {
|
||||
auto inode = fsData->random.gen() % MaxValue<InodeId_t>;
|
||||
if (inode > ReservedInodeEnd && !find(inode).valid()) {
|
||||
return inode;
|
||||
}
|
||||
}
|
||||
return {0, OxError(2)};
|
||||
}
|
||||
return {0, OxError(1)};
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
ox::Error FileStoreTemplate<size_t>::compact() {
|
||||
auto isFirstItem = true;
|
||||
return m_buffer->compact([this, &isFirstItem](uint64_t oldAddr, ItemPtr item) -> ox::Error {
|
||||
if (isFirstItem) {
|
||||
isFirstItem = false;
|
||||
return OxError(0);
|
||||
}
|
||||
if (!item.valid()) {
|
||||
return OxError(1);
|
||||
}
|
||||
oxTrace("ox::FileStoreTemplate::compact::moveItem")
|
||||
<< "Moving Item:" << item->id
|
||||
<< "from" << oldAddr
|
||||
<< "to" << item.offset();
|
||||
// update rootInode if this is it
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData && oldAddr == fsData->rootNode) {
|
||||
fsData->rootNode = item.offset();
|
||||
}
|
||||
auto parent = findParent(rootInode(), item->id, oldAddr);
|
||||
oxAssert(parent.valid() || rootInode() == item.offset(),
|
||||
"Parent inode not found for item that should have parent.");
|
||||
if (parent.valid()) {
|
||||
if (parent->left == oldAddr) {
|
||||
parent->left = item;
|
||||
} else if (parent->right == oldAddr) {
|
||||
parent->right = item;
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::FileStoreData *FileStoreTemplate<size_t>::fileStoreData() const {
|
||||
auto first = m_buffer->firstItem();
|
||||
if (first.valid()) {
|
||||
auto data = first->data();
|
||||
if (data.valid()) {
|
||||
return reinterpret_cast<FileStoreData*>(data.get());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
auto root = m_buffer->ptr(fsData->rootNode);
|
||||
if (root.valid()) {
|
||||
if (root->id == item->id) {
|
||||
fsData->rootNode = item;
|
||||
item->left = root->left;
|
||||
item->right = root->right;
|
||||
oxTrace("ox::fs::FileStoreTemplate::placeItem") << "Overwrote Root Item:" << item->id;
|
||||
return OxError(0);
|
||||
} else {
|
||||
return placeItem(root, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth) {
|
||||
if (depth < 5000) {
|
||||
if (item->id > root->id) {
|
||||
auto right = m_buffer->ptr(root->right);
|
||||
if (!right.valid() || right->id == item->id) {
|
||||
root->right = item.offset();
|
||||
if (right.valid()) {
|
||||
item->left = right->left;
|
||||
item->right = right->right;
|
||||
}
|
||||
oxTrace("ox::fs::FileStoreTemplate::placeItem") << "Placed Item:" << item->id;
|
||||
return OxError(0);
|
||||
} else {
|
||||
return placeItem(right, item, depth + 1);
|
||||
}
|
||||
} else if (item->id < root->id) {
|
||||
auto left = m_buffer->ptr(root->left);
|
||||
if (!left.valid() || left->id == item->id) {
|
||||
root->left = item.offset();
|
||||
if (left.valid()) {
|
||||
item->left = left->left;
|
||||
item->right = left->right;
|
||||
}
|
||||
oxTrace("ox::fs::FileStoreTemplate::placeItem") << "Placed Item:" << item->id;
|
||||
return OxError(0);
|
||||
} else {
|
||||
return placeItem(left, item, depth + 1);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::placeItem::fail") << "Cannot insert an item on itself.";
|
||||
return OxError(1);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::placeItem::fail") << "Excessive recursion depth, stopping before stack overflow.";
|
||||
return OxError(2);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr item) {
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
auto root = m_buffer->ptr(fsData->rootNode);
|
||||
if (root.valid()) {
|
||||
if (root->id == item->id) {
|
||||
item->left = root->left;
|
||||
item->right = root->right;
|
||||
auto left = m_buffer->ptr(item->left);
|
||||
auto right = m_buffer->ptr(item->right);
|
||||
if (right.valid()) {
|
||||
auto oldRoot = fsData->rootNode;
|
||||
fsData->rootNode = item->right;
|
||||
if (left.valid()) {
|
||||
auto err = placeItem(left);
|
||||
// undo if unable to place the left side of the tree
|
||||
if (err) {
|
||||
fsData->rootNode = oldRoot;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else if (left.valid()) {
|
||||
fsData->rootNode = item->left;
|
||||
} else {
|
||||
fsData->rootNode = 0;
|
||||
}
|
||||
return OxError(0);
|
||||
} else {
|
||||
return unplaceItem(root, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int depth) {
|
||||
if (depth >= 5000) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::unplaceItem::fail") << "Excessive recursion depth, stopping before stack overflow.";
|
||||
return OxError(1);
|
||||
}
|
||||
if (item->id > root->id) {
|
||||
auto right = m_buffer->ptr(root->right);
|
||||
if (right->id == item->id) {
|
||||
root->right = 0;
|
||||
oxTrace("ox::fs::FileStoreTemplate::unplaceItem") << "Unplaced Item:" << item->id;
|
||||
} else {
|
||||
return unplaceItem(right, item, depth + 1);
|
||||
}
|
||||
} else if (item->id < root->id) {
|
||||
auto left = m_buffer->ptr(root->left);
|
||||
if (left->id == item->id) {
|
||||
root->left = 0;
|
||||
oxTrace("ox::fs::FileStoreTemplate::unplaceItem") << "Unplaced Item:" << item->id;
|
||||
} else {
|
||||
return unplaceItem(left, item, depth + 1);
|
||||
}
|
||||
} else {
|
||||
return OxError(1);
|
||||
}
|
||||
if (item->right) {
|
||||
oxReturnError(placeItem(m_buffer->ptr(item->right)));
|
||||
}
|
||||
if (item->left) {
|
||||
oxReturnError(placeItem(m_buffer->ptr(item->left)));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::remove(ItemPtr item) {
|
||||
if (item.valid()) {
|
||||
oxReturnError(unplaceItem(item));
|
||||
oxReturnError(m_buffer->free(item));
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::findParent(ItemPtr item, size_t id, size_t oldAddr) const {
|
||||
// This is a little bit confusing. findParent uses the inode ID to find
|
||||
// where the target ID should be, but the actual address of that item is
|
||||
// currently invalid, so we check it against what is known to be the old
|
||||
// address of the item to confirm that we have the right item.
|
||||
if (item.valid()) {
|
||||
if (id > item->id) {
|
||||
if (item->right == oldAddr) {
|
||||
return item;
|
||||
} else {
|
||||
auto right = m_buffer->ptr(item->right);
|
||||
return findParent(right, id, oldAddr);
|
||||
}
|
||||
} else if (id < item->id) {
|
||||
if (item->left == oldAddr) {
|
||||
return item;
|
||||
} else {
|
||||
auto left = m_buffer->ptr(item->left);
|
||||
return findParent(left, id, oldAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(ItemPtr item, InodeId_t id, int depth) const {
|
||||
if (depth > 5000) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find::fail") << "Excessive recursion depth, stopping before stack overflow. Search for:" << id;
|
||||
return nullptr;
|
||||
}
|
||||
if (!item.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find::fail") << "item invalid";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (id > item->id) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find") << "Not a match, searching on" << item->right;
|
||||
return find(m_buffer->ptr(item->right), id, depth + 1);
|
||||
} else if (id < item->id) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find") << "Not a match, searching on" << item->left;
|
||||
return find(m_buffer->ptr(item->left), id, depth + 1);
|
||||
} else if (id == item->id) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find") << "Found" << id << "at" << item;
|
||||
return item;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(InodeId_t id) const {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find") << "Searching for inode:" << id;
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
auto root = m_buffer->ptr(fsData->rootNode);
|
||||
if (root.valid()) {
|
||||
auto item = find(root, id);
|
||||
return item;
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find::fail") << "No root node";
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find::fail") << "No FileStore Data";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the root inode.
|
||||
*/
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::rootInode() {
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
return m_buffer->ptr(fsData->rootNode);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
bool FileStoreTemplate<size_t>::canWrite(ItemPtr existing, size_t size) {
|
||||
return existing.size() >= size || m_buffer->spaceNeeded(size) <= m_buffer->available();
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
bool FileStoreTemplate<size_t>::valid() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
extern template class FileStoreTemplate<uint16_t>;
|
||||
extern template class FileStoreTemplate<uint32_t>;
|
||||
|
||||
using FileStore16 = FileStoreTemplate<uint16_t>;
|
||||
using FileStore32 = FileStoreTemplate<uint32_t>;
|
||||
|
||||
}
|
19
deps/ox/src/ox/fs/filesystem/directory.cpp
vendored
Normal file
19
deps/ox/src/ox/fs/filesystem/directory.cpp
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "directory.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template class Directory<FileStore16, uint16_t>;
|
||||
template class Directory<FileStore32, uint32_t>;
|
||||
|
||||
template struct DirectoryEntry<uint16_t>;
|
||||
template struct DirectoryEntry<uint32_t>;
|
||||
|
||||
}
|
373
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
Normal file
373
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
Normal file
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/fs/filesystem/pathiterator.hpp>
|
||||
#include <ox/fs/filestore/filestoretemplate.hpp>
|
||||
#include <ox/ptrarith/nodebuffer.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename InodeId_t>
|
||||
struct OX_PACKED DirectoryEntry {
|
||||
|
||||
public:
|
||||
struct OX_PACKED DirectoryEntryData {
|
||||
// DirectoryEntry fields
|
||||
LittleEndian<InodeId_t> inode = 0;
|
||||
char name[MaxFileNameLength];
|
||||
|
||||
static constexpr std::size_t spaceNeeded(std::size_t chars) {
|
||||
return offsetof(DirectoryEntryData, name) + chars;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// NodeBuffer fields
|
||||
LittleEndian<InodeId_t> prev = 0;
|
||||
LittleEndian<InodeId_t> next = 0;
|
||||
|
||||
|
||||
private:
|
||||
LittleEndian<InodeId_t> m_bufferSize = sizeof(DirectoryEntry);
|
||||
|
||||
public:
|
||||
DirectoryEntry() = default;
|
||||
|
||||
[[nodiscard]] ox::Error init(InodeId_t inode, const char *name, InodeId_t bufferSize) {
|
||||
m_bufferSize = bufferSize;
|
||||
auto d = data();
|
||||
if (d.valid()) {
|
||||
d->inode = inode;
|
||||
ox_strncpy(d->name, name, ox::min(bufferSize, static_cast<InodeId_t>(MaxFileNameLength)));
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
ptrarith::Ptr<DirectoryEntryData, InodeId_t> data() {
|
||||
oxTrace("ox::fs::DirectoryEntry::data") << this->fullSize() << sizeof(*this) << this->size();
|
||||
return ptrarith::Ptr<DirectoryEntryData, InodeId_t>(this, this->fullSize(), sizeof(*this), this->size(), this->size());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of the data + the size of the Item type
|
||||
*/
|
||||
InodeId_t fullSize() const {
|
||||
return m_bufferSize;
|
||||
}
|
||||
|
||||
InodeId_t size() const {
|
||||
return fullSize() - sizeof(*this);
|
||||
}
|
||||
|
||||
void setSize(InodeId_t) {
|
||||
// ignore set value
|
||||
}
|
||||
|
||||
static constexpr std::size_t spaceNeeded(std::size_t chars) {
|
||||
return sizeof(DirectoryEntry) + offsetof(DirectoryEntryData, name) + chars;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
class Directory {
|
||||
|
||||
private:
|
||||
using Buffer = ptrarith::NodeBuffer<InodeId_t, DirectoryEntry<InodeId_t>>;
|
||||
|
||||
InodeId_t m_inodeId = 0;
|
||||
std::size_t m_size = 0;
|
||||
FileStore m_fs;
|
||||
|
||||
public:
|
||||
Directory() = default;
|
||||
|
||||
Directory(FileStore fs, InodeId_t inode);
|
||||
|
||||
/**
|
||||
* Initializes Directory.
|
||||
*/
|
||||
[[nodiscard]] ox::Error init() noexcept;
|
||||
|
||||
[[nodiscard]] ox::Error mkdir(PathIterator path, bool parents, FileName *nameBuff = nullptr);
|
||||
|
||||
/**
|
||||
* @param parents indicates the operation should create non-existent directories in the path, like mkdir -p
|
||||
*/
|
||||
[[nodiscard]] ox::Error write(PathIterator it, InodeId_t inode, FileName *nameBuff = nullptr) noexcept;
|
||||
|
||||
[[nodiscard]] ox::Error remove(PathIterator it, FileName *nameBuff = nullptr) noexcept;
|
||||
|
||||
template<typename F>
|
||||
[[nodiscard]] ox::Error ls(F cb) noexcept;
|
||||
|
||||
[[nodiscard]] ValErr<typename FileStore::InodeId_t> findEntry(const FileName &name) const noexcept;
|
||||
|
||||
[[nodiscard]] ValErr<typename FileStore::InodeId_t> find(PathIterator name, FileName *nameBuff = nullptr) const noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
Directory<FileStore, InodeId_t>::Directory(FileStore fs, InodeId_t inodeId) {
|
||||
m_fs = fs;
|
||||
m_inodeId = inodeId;
|
||||
auto buff = m_fs.read(inodeId).template to<Buffer>();
|
||||
if (buff.valid()) {
|
||||
m_size = buff.size();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ox::Error Directory<FileStore, InodeId_t>::init() noexcept {
|
||||
constexpr auto Size = sizeof(Buffer);
|
||||
oxTrace("ox::fs::Directory::init") << "Initializing Directory with Inode ID:" << m_inodeId;
|
||||
oxReturnError(m_fs.write(m_inodeId, nullptr, Size, FileType_Directory));
|
||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (!buff.valid()) {
|
||||
m_size = 0;
|
||||
return OxError(1);
|
||||
}
|
||||
new (buff) Buffer(Size);
|
||||
m_size = Size;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ox::Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, FileName *nameBuff) {
|
||||
if (path.valid()) {
|
||||
oxTrace("ox::fs::Directory::mkdir") << path.fullPath();
|
||||
// reuse nameBuff if it has already been allocated, as it is a rather large variable
|
||||
if (nameBuff == nullptr) {
|
||||
nameBuff = reinterpret_cast<FileName*>(ox_alloca(sizeof(FileName)));
|
||||
}
|
||||
|
||||
// determine if already exists
|
||||
auto name = nameBuff;
|
||||
path.get(name);
|
||||
auto childInode = find(name->c_str());
|
||||
if (!childInode.ok()) {
|
||||
// if this is not the last item in the path and parents is disabled,
|
||||
// return an error
|
||||
if (!parents && path.hasNext()) {
|
||||
return OxError(1);
|
||||
}
|
||||
childInode = m_fs.generateInodeId();
|
||||
oxTrace("ox::fs::Directory::mkdir") << "Generated Inode ID:" << childInode.value;
|
||||
oxLogError(childInode.error);
|
||||
oxReturnError(childInode.error);
|
||||
|
||||
// initialize the directory
|
||||
Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
|
||||
oxReturnError(child.init());
|
||||
|
||||
auto err = write(name->c_str(), childInode.value);
|
||||
if (err) {
|
||||
oxLogError(err);
|
||||
// could not index the directory, delete it
|
||||
oxLogError(m_fs.remove(childInode.value));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
|
||||
if (path.hasNext()) {
|
||||
oxReturnError(child.mkdir(path.next(), parents, nameBuff));
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ox::Error Directory<FileStore, InodeId_t>::write(PathIterator path, InodeId_t inode, FileName *nameBuff) noexcept {
|
||||
// reuse nameBuff if it has already been allocated, as it is a rather large variable
|
||||
if (nameBuff == nullptr) {
|
||||
nameBuff = reinterpret_cast<FileName*>(ox_alloca(sizeof(FileName)));
|
||||
}
|
||||
auto name = nameBuff;
|
||||
|
||||
if (path.next().hasNext()) { // not yet at target directory, recurse to next one
|
||||
oxReturnError(path.get(name));
|
||||
|
||||
oxTrace("ox::fs::Directory::write") << "Attempting to write to next sub-Directory: "
|
||||
<< name->c_str() << " of " << path.fullPath();
|
||||
|
||||
auto [nextChild, err] = findEntry(*name);
|
||||
oxReturnError(err);
|
||||
|
||||
oxTrace("ox::fs::Directory::write") << name->c_str() << ": " << nextChild;
|
||||
|
||||
if (nextChild) {
|
||||
// reuse name because it is a rather large variable and will not be used again
|
||||
// be attentive that this remains true
|
||||
name = nullptr;
|
||||
return Directory(m_fs, nextChild).write(path.next(), inode, nameBuff);
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::write") << name->c_str()
|
||||
<< "not found and not allowed to create it.";
|
||||
return OxError(1);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::write") << path.fullPath();
|
||||
// insert the new entry on this directory
|
||||
|
||||
// get the name
|
||||
path.next(name);
|
||||
|
||||
// find existing version of directory
|
||||
oxTrace("ox::fs::Directory::write") << "Searching for directory inode" << m_inodeId;
|
||||
auto oldStat = m_fs.stat(m_inodeId);
|
||||
oxReturnError(oldStat);
|
||||
oxTrace("ox::fs::Directory::write") << "Found existing directory of size" << oldStat.value.size;
|
||||
auto old = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (!old.valid()) {
|
||||
oxTrace("ox::fs::Directory::write::fail") << "Could not read existing version of Directory";
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
const auto pathSize = name->len() + 1;
|
||||
const auto entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize);
|
||||
const auto newSize = oldStat.value.size + Buffer::spaceNeeded(entryDataSize);
|
||||
auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.value.size);
|
||||
if (cpy == nullptr) {
|
||||
oxTrace("ox::fs::Directory::write::fail") << "Could not allocate memory for copy of Directory";
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
// TODO: look for old version of this entry and delete it
|
||||
oxReturnError(cpy->setSize(newSize));
|
||||
auto val = cpy->malloc(entryDataSize);
|
||||
if (!val.valid()) {
|
||||
oxTrace("ox::fs::Directory::write::fail") << "Could not allocate memory for new directory entry";
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
oxTrace("ox::fs::Directory::write") << "Attempting to write Directory entry:" << name->data();
|
||||
oxTrace("ox::fs::Directory::write") << "Attempting to write Directory to FileStore";
|
||||
oxReturnError(val->init(inode, name->data(), val.size()));
|
||||
return m_fs.write(m_inodeId, cpy, cpy->size(), FileType_Directory);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ox::Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameBuff) noexcept {
|
||||
// reuse nameBuff if it has already been allocated, as it is a rather large variable
|
||||
if (nameBuff == nullptr) {
|
||||
nameBuff = reinterpret_cast<FileName*>(ox_alloca(sizeof(FileName)));
|
||||
}
|
||||
auto &name = *nameBuff;
|
||||
oxReturnError(path.get(&name));
|
||||
|
||||
oxTrace("ox::fs::Directory::remove") << name.c_str();
|
||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (buff.valid()) {
|
||||
oxTrace("ox::fs::Directory::remove") << "Found directory buffer.";
|
||||
for (auto i = buff->iterator(); i.valid(); i.next()) {
|
||||
auto data = i->data();
|
||||
if (data.valid()) {
|
||||
if (ox_strncmp(data->name, name.c_str(), name.len()) == 0) {
|
||||
oxReturnError(buff->free(i));
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::remove") << "INVALID DIRECTORY ENTRY";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::remove::fail") << "Could not find directory buffer";
|
||||
return OxError(1);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
template<typename F>
|
||||
ox::Error Directory<FileStore, InodeId_t>::ls(F cb) noexcept {
|
||||
oxTrace("ox::fs::Directory::ls");
|
||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (!buff.valid()) {
|
||||
oxTrace("ox::fs::Directory::ls::fail") << "Could not directory buffer";
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
oxTrace("ox::fs::Directory::ls") << "Found directory buffer.";
|
||||
for (auto i = buff->iterator(); i.valid(); i.next()) {
|
||||
auto data = i->data();
|
||||
if (data.valid()) {
|
||||
oxReturnError(cb(data->name, data->inode));
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::ls") << "INVALID DIRECTORY ENTRY";
|
||||
}
|
||||
}
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ValErr<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry(const FileName &name) const noexcept {
|
||||
oxTrace("ox::fs::Directory::findEntry") << name.c_str();
|
||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (!buff.valid()) {
|
||||
oxTrace("ox::fs::Directory::findEntry::fail") << "Could not findEntry directory buffer";
|
||||
return {0, OxError(2)};
|
||||
}
|
||||
oxTrace("ox::fs::Directory::findEntry") << "Found directory buffer, size:" << buff.size();
|
||||
for (auto i = buff->iterator(); i.valid(); i.next()) {
|
||||
auto data = i->data();
|
||||
if (data.valid()) {
|
||||
oxTrace("ox::fs::Directory::findEntry").del("") << "Comparing \"" << name.c_str() << "\" to \"" << data->name << "\"";
|
||||
if (ox_strncmp(data->name, name.c_str(), MaxFileNameLength) == 0) {
|
||||
oxTrace("ox::fs::Directory::findEntry").del("") << "\"" << name.c_str() << "\" match found.";
|
||||
return static_cast<InodeId_t>(data->inode);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::findEntry") << "INVALID DIRECTORY ENTRY";
|
||||
}
|
||||
}
|
||||
oxTrace("ox::fs::Directory::findEntry::fail") << "Entry not present";
|
||||
return {0, OxError(1)};
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ValErr<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::find(PathIterator path, FileName *nameBuff) const noexcept {
|
||||
// reuse nameBuff if it has already been allocated, as it is a rather large variable
|
||||
if (nameBuff == nullptr) {
|
||||
nameBuff = reinterpret_cast<FileName*>(ox_alloca(sizeof(FileName)));
|
||||
}
|
||||
|
||||
// determine if already exists
|
||||
auto name = nameBuff;
|
||||
oxReturnError(path.get(name));
|
||||
|
||||
auto v = findEntry(name->c_str());
|
||||
oxReturnError(v);
|
||||
// recurse if not at end of path
|
||||
if (auto p = path.next(); p.valid()) {
|
||||
Directory dir(m_fs, v.value);
|
||||
name = nullptr;
|
||||
return dir.find(p, nameBuff);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
extern template class Directory<FileStore16, uint16_t>;
|
||||
extern template class Directory<FileStore32, uint32_t>;
|
||||
|
||||
extern template struct DirectoryEntry<uint16_t>;
|
||||
extern template struct DirectoryEntry<uint32_t>;
|
||||
|
||||
using Directory16 = Directory<FileStore16, uint16_t>;
|
||||
using Directory32 = Directory<FileStore32, uint32_t>;
|
||||
|
||||
}
|
69
deps/ox/src/ox/fs/filesystem/filelocation.cpp
vendored
Normal file
69
deps/ox/src/ox/fs/filesystem/filelocation.cpp
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "filelocation.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
FileAddress::FileAddress() {
|
||||
m_data.inode = 0;
|
||||
m_type = FileAddressType::Inode;
|
||||
}
|
||||
|
||||
FileAddress::FileAddress(const FileAddress &other) {
|
||||
operator=(other);
|
||||
}
|
||||
|
||||
FileAddress::FileAddress(std::nullptr_t) {
|
||||
}
|
||||
|
||||
FileAddress::FileAddress(uint64_t inode) {
|
||||
m_data.inode = inode;
|
||||
m_type = FileAddressType::Inode;
|
||||
}
|
||||
|
||||
FileAddress::FileAddress(char *path) {
|
||||
auto pathSize = ox_strlen(path) + 1;
|
||||
m_data.path = new char[pathSize];
|
||||
memcpy(m_data.path, path, pathSize);
|
||||
m_type = FileAddressType::Path;
|
||||
}
|
||||
|
||||
FileAddress::FileAddress(const char *path) {
|
||||
m_data.constPath = path;
|
||||
m_type = FileAddressType::ConstPath;
|
||||
}
|
||||
|
||||
FileAddress::~FileAddress() {
|
||||
if (m_type == FileAddressType::Path) {
|
||||
delete[] m_data.path;
|
||||
m_data.path = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const FileAddress &FileAddress::operator=(const FileAddress &other) {
|
||||
m_type = other.m_type;
|
||||
switch (m_type) {
|
||||
case FileAddressType::Path:
|
||||
{
|
||||
auto strSize = ox_strlen(other.m_data.path) + 1;
|
||||
m_data.path = new char[strSize];
|
||||
ox_memcpy(m_data.path, other.m_data.path, strSize);
|
||||
break;
|
||||
}
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Inode:
|
||||
m_data = other.m_data;
|
||||
break;
|
||||
case FileAddressType::None:
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
114
deps/ox/src/ox/fs/filesystem/filelocation.hpp
vendored
Normal file
114
deps/ox/src/ox/fs/filesystem/filelocation.hpp
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/std.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
enum class FileAddressType: int8_t {
|
||||
None = -1,
|
||||
Path,
|
||||
ConstPath,
|
||||
Inode,
|
||||
};
|
||||
|
||||
class FileAddress {
|
||||
|
||||
template<typename T>
|
||||
friend ox::Error model(T*, FileAddress*);
|
||||
|
||||
public:
|
||||
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress";
|
||||
static constexpr auto Fields = 2;
|
||||
|
||||
union Data {
|
||||
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress.Data";
|
||||
static constexpr auto Fields = 3;
|
||||
char *path;
|
||||
const char *constPath;
|
||||
uint64_t inode;
|
||||
};
|
||||
|
||||
protected:
|
||||
FileAddressType m_type = FileAddressType::None;
|
||||
Data m_data;
|
||||
|
||||
public:
|
||||
FileAddress();
|
||||
|
||||
FileAddress(const FileAddress &other);
|
||||
|
||||
FileAddress(std::nullptr_t);
|
||||
|
||||
FileAddress(uint64_t inode);
|
||||
|
||||
FileAddress(char *path);
|
||||
|
||||
FileAddress(const char *path);
|
||||
|
||||
~FileAddress();
|
||||
|
||||
const FileAddress &operator=(const FileAddress &other);
|
||||
|
||||
[[nodiscard]] constexpr FileAddressType type() const noexcept {
|
||||
switch (m_type) {
|
||||
case FileAddressType::Path:
|
||||
case FileAddressType::ConstPath:
|
||||
return FileAddressType::Path;
|
||||
default:
|
||||
return m_type;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr ValErr<uint64_t> getInode() const noexcept {
|
||||
switch (m_type) {
|
||||
case FileAddressType::Inode:
|
||||
return m_data.inode;
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr ValErr<const char*> getPath() const noexcept {
|
||||
switch (m_type) {
|
||||
case FileAddressType::Path:
|
||||
return m_data.path;
|
||||
case FileAddressType::ConstPath:
|
||||
return m_data.constPath;
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return m_type != FileAddressType::None;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, FileAddress::Data *obj) {
|
||||
io->template setTypeInfo<FileAddress::Data>();
|
||||
oxReturnError(io->field("path", SerStr(&obj->path)));
|
||||
oxReturnError(io->field("constPath", SerStr(&obj->path)));
|
||||
oxReturnError(io->field("inode", &obj->inode));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, FileAddress *fa) {
|
||||
io->template setTypeInfo<FileAddress>();
|
||||
oxReturnError(io->field("type", bit_cast<int8_t*>(&fa->m_type)));
|
||||
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
}
|
88
deps/ox/src/ox/fs/filesystem/filesystem.cpp
vendored
Normal file
88
deps/ox/src/ox/fs/filesystem/filesystem.cpp
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "filesystem.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> FileSystem::read(FileAddress addr) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return read(addr.getInode().value);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return read(addr.getPath().value);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] ox::Error FileSystem::read(FileAddress addr, void *buffer, std::size_t size) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return read(addr.getInode().value, buffer, size);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return read(addr.getPath().value, buffer, size);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] ox::Error FileSystem::read(FileAddress addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return read(addr.getInode().value, readStart, readSize, buffer, size);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return read(addr.getPath().value, readStart, readSize, buffer, size);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] ox::Error FileSystem::remove(FileAddress addr, bool recursive) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return remove(addr.getInode().value, recursive);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return remove(addr.getPath().value, recursive);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error FileSystem::write(FileAddress addr, void *buffer, uint64_t size, uint8_t fileType) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return write(addr.getInode().value, buffer, size, fileType);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return write(addr.getPath().value, buffer, size, fileType);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
ox::ValErr<FileStat> FileSystem::stat(FileAddress addr) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return stat(addr.getInode().value);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return stat(addr.getPath().value);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
template class FileSystemTemplate<FileStore16, Directory16>;
|
||||
template class FileSystemTemplate<FileStore32, Directory32>;
|
||||
|
||||
}
|
423
deps/ox/src/ox/fs/filesystem/filesystem.hpp
vendored
Normal file
423
deps/ox/src/ox/fs/filesystem/filesystem.hpp
vendored
Normal file
@ -0,0 +1,423 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/fs/filestore/filestoretemplate.hpp>
|
||||
#include <ox/fs/filesystem/filelocation.hpp>
|
||||
#include <ox/fs/filesystem/types.hpp>
|
||||
|
||||
#include "directory.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
class FileSystem {
|
||||
|
||||
public:
|
||||
virtual ~FileSystem() = default;
|
||||
|
||||
[[nodiscard]] virtual ox::Error mkdir(const char *path, bool recursive = false) = 0;
|
||||
|
||||
/**
|
||||
* Moves an entry from one directory to another.
|
||||
* @param src the path to the file
|
||||
* @param dest the path of the destination directory
|
||||
*/
|
||||
[[nodiscard]] virtual ox::Error move(const char *src, const char *dest) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error read(const char *path, void *buffer, std::size_t buffSize) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::ValErr<uint8_t*> read(const char *path) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error read(uint64_t inode, void *buffer, std::size_t size) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::ValErr<uint8_t*> read(uint64_t inode) = 0;
|
||||
|
||||
[[nodiscard]] ox::Error read(FileAddress addr, void *buffer, std::size_t size);
|
||||
|
||||
[[nodiscard]] ox::Error read(FileAddress addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size);
|
||||
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> read(FileAddress addr);
|
||||
|
||||
[[nodiscard]] virtual ox::Error remove(const char *path, bool recursive = false) = 0;
|
||||
|
||||
[[nodiscard]] ox::Error remove(FileAddress addr, bool recursive = false);
|
||||
|
||||
[[nodiscard]] virtual ox::Error resize(uint64_t size, void *buffer = nullptr) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) = 0;
|
||||
|
||||
[[nodiscard]] ox::Error write(FileAddress addr, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile);
|
||||
|
||||
[[nodiscard]] virtual ox::ValErr<FileStat> stat(uint64_t inode) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::ValErr<FileStat> stat(const char *path) = 0;
|
||||
|
||||
[[nodiscard]] ox::ValErr<FileStat> stat(FileAddress addr);
|
||||
|
||||
[[nodiscard]] virtual uint64_t spaceNeeded(uint64_t size) = 0;
|
||||
|
||||
[[nodiscard]] virtual uint64_t available() = 0;
|
||||
|
||||
[[nodiscard]] virtual uint64_t size() const = 0;
|
||||
|
||||
[[nodiscard]] virtual char *buff() = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error walk(ox::Error(*cb)(uint8_t, uint64_t, uint64_t)) = 0;
|
||||
|
||||
[[nodiscard]] virtual bool valid() const = 0;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* FileSystemTemplate used to create file system that wraps around a FileStore,
|
||||
* taking an inode size and a directory type as parameters.
|
||||
*
|
||||
* Note: Directory parameter must have a default constructor.
|
||||
*/
|
||||
template<typename FileStore, typename Directory>
|
||||
class FileSystemTemplate: public FileSystem {
|
||||
private:
|
||||
static constexpr auto InodeFsData = 2;
|
||||
|
||||
struct OX_PACKED FileSystemData {
|
||||
LittleEndian<typename FileStore::InodeId_t> rootDirInode;
|
||||
};
|
||||
|
||||
FileStore m_fs;
|
||||
void(*m_freeBuffer)(char*) = nullptr;
|
||||
|
||||
public:
|
||||
FileSystemTemplate() = default;
|
||||
|
||||
FileSystemTemplate(void *buffer, uint64_t bufferSize, void(*freeBuffer)(char*) = [] (char *buff) { delete buff; });
|
||||
|
||||
FileSystemTemplate(FileStore fs);
|
||||
|
||||
~FileSystemTemplate();
|
||||
|
||||
[[nodiscard]] static ox::Error format(void *buff, uint64_t buffSize);
|
||||
|
||||
[[nodiscard]] ox::Error mkdir(const char *path, bool recursive = false) override;
|
||||
|
||||
[[nodiscard]] ox::Error move(const char *src, const char *dest) override;
|
||||
|
||||
[[nodiscard]] ox::Error read(const char *path, void *buffer, std::size_t buffSize) override;
|
||||
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> read(const char*) override;
|
||||
|
||||
[[nodiscard]] ox::Error read(uint64_t inode, void *buffer, std::size_t size) override;
|
||||
|
||||
[[nodiscard]] ox::Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) override;
|
||||
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> read(uint64_t) override;
|
||||
|
||||
template<typename F>
|
||||
[[nodiscard]] ox::Error ls(const char *dir, F cb);
|
||||
|
||||
[[nodiscard]] ox::Error remove(const char *path, bool recursive = false) override;
|
||||
|
||||
/**
|
||||
* Resizes FileSystem to minimum possible size.
|
||||
*/
|
||||
[[nodiscard]] ox::Error resize();
|
||||
|
||||
[[nodiscard]] ox::Error resize(uint64_t size, void *buffer = nullptr) override;
|
||||
|
||||
[[nodiscard]] ox::Error write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override;
|
||||
|
||||
[[nodiscard]] ox::Error write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override;
|
||||
|
||||
[[nodiscard]] ox::ValErr<FileStat> stat(uint64_t inode) override;
|
||||
|
||||
[[nodiscard]] ox::ValErr<FileStat> stat(const char *path) override;
|
||||
|
||||
uint64_t spaceNeeded(uint64_t size) override;
|
||||
|
||||
uint64_t available() override;
|
||||
|
||||
uint64_t size() const override;
|
||||
|
||||
char *buff() override;
|
||||
|
||||
[[nodiscard]] ox::Error walk(ox::Error(*cb)(uint8_t, uint64_t, uint64_t)) override;
|
||||
|
||||
bool valid() const override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] ValErr<FileSystemData> fileSystemData() const noexcept;
|
||||
|
||||
/**
|
||||
* Finds the inode ID at the given path.
|
||||
*/
|
||||
[[nodiscard]] ValErr<uint64_t> find(const char *path) const noexcept;
|
||||
|
||||
[[nodiscard]] ValErr<Directory> rootDir() const noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
FileSystemTemplate<FileStore, Directory>::FileSystemTemplate(FileStore fs) {
|
||||
m_fs = fs;
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
FileSystemTemplate<FileStore, Directory>::FileSystemTemplate(void *buffer, uint64_t bufferSize, void(*freeBuffer)(char*)):
|
||||
m_fs(buffer, bufferSize),
|
||||
m_freeBuffer(freeBuffer) {
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
FileSystemTemplate<FileStore, Directory>::~FileSystemTemplate() {
|
||||
if (m_freeBuffer && m_fs.buff()) {
|
||||
m_freeBuffer(m_fs.buff());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buffSize) {
|
||||
oxReturnError(FileStore::format(buff, buffSize));
|
||||
FileStore fs(buff, buffSize);
|
||||
|
||||
constexpr auto rootDirInode = MaxValue<typename FileStore::InodeId_t> / 2;
|
||||
Directory rootDir(fs, rootDirInode);
|
||||
oxReturnError(rootDir.init());
|
||||
|
||||
FileSystemData fd;
|
||||
fd.rootDirInode = rootDirInode;
|
||||
oxTrace("ox::fs::FileSystemTemplate::format") << "rootDirInode:" << fd.rootDirInode;
|
||||
oxReturnError(fs.write(InodeFsData, &fd, sizeof(fd)));
|
||||
|
||||
if (!fs.read(fd.rootDirInode).valid()) {
|
||||
oxTrace("ox::fs::FileSystemTemplate::format::error") << "FileSystemTemplate::format did not correctly create root directory";
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::mkdir(const char *path, bool recursive) {
|
||||
oxTrace("ox::fs::FileSystemTemplate::mkdir") << "path:" << path << "recursive:" << recursive;
|
||||
auto rootDir = this->rootDir();
|
||||
oxReturnError(rootDir.error);
|
||||
return rootDir.value.mkdir(path, recursive);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::move(const char *src, const char *dest) {
|
||||
auto fd = fileSystemData();
|
||||
oxReturnError(fd.error);
|
||||
Directory rootDir(m_fs, fd.value.rootDirInode);
|
||||
auto [inode, err] = rootDir.find(src);
|
||||
oxReturnError(err);
|
||||
oxReturnError(rootDir.write(dest, inode));
|
||||
oxReturnError(rootDir.remove(src));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::read(const char *path, void *buffer, std::size_t buffSize) {
|
||||
auto fd = fileSystemData();
|
||||
oxReturnError(fd.error);
|
||||
Directory rootDir(m_fs, fd.value.rootDirInode);
|
||||
auto [inode, err] = rootDir.find(path);
|
||||
oxReturnError(err);
|
||||
return read(inode, buffer, buffSize);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> FileSystemTemplate<FileStore, Directory>::read(const char *path) {
|
||||
auto fd = fileSystemData();
|
||||
oxReturnError(fd.error);
|
||||
Directory rootDir(m_fs, fd.value.rootDirInode);
|
||||
auto [inode, err] = rootDir.find(path);
|
||||
oxReturnError(err);
|
||||
return read(inode);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::read(uint64_t inode, void *buffer, std::size_t buffSize) {
|
||||
return m_fs.read(inode, buffer, buffSize);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) {
|
||||
return m_fs.read(inode, readStart, readSize, reinterpret_cast<uint8_t*>(buffer), size);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> FileSystemTemplate<FileStore, Directory>::read(uint64_t inode) {
|
||||
auto data = m_fs.read(inode);
|
||||
if (!data.valid()) {
|
||||
return OxError(1);
|
||||
}
|
||||
return data.get();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
template<typename F>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::ls(const char *path, F cb) {
|
||||
oxTrace("ox::FileSystemTemplate::ls") << "path:" << path;
|
||||
auto [s, err] = stat(path);
|
||||
oxReturnError(err);
|
||||
Directory dir(m_fs, s.inode);
|
||||
return dir.ls(cb);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::remove(const char *path, bool recursive) {
|
||||
auto fd = fileSystemData();
|
||||
oxReturnError(fd.error);
|
||||
Directory rootDir(m_fs, fd.value.rootDirInode);
|
||||
auto inode = rootDir.find(path);
|
||||
oxReturnError(inode.error);
|
||||
auto st = stat(inode.value);
|
||||
oxReturnError(st.error);
|
||||
if (st.value.fileType == FileType_NormalFile || recursive) {
|
||||
if (auto err = rootDir.remove(path)) {
|
||||
// removal failed, try putting the index back
|
||||
oxLogError(rootDir.write(path, inode.value));
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
oxTrace("FileSystemTemplate::remove::fail") << "Tried to remove directory without recursive setting.";
|
||||
return OxError(1);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::resize() {
|
||||
return m_fs.resize();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::resize(uint64_t size, void *buffer) {
|
||||
oxReturnError(m_fs.resize(size, buffer));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::write(const char *path, void *buffer, uint64_t size, uint8_t fileType) {
|
||||
auto [inode, err] = find(path);
|
||||
if (err) {
|
||||
auto generated = m_fs.generateInodeId();
|
||||
oxReturnError(generated.error);
|
||||
inode = generated.value;
|
||||
}
|
||||
auto rootDir = this->rootDir();
|
||||
oxReturnError(rootDir.error);
|
||||
oxReturnError(rootDir.value.write(path, inode));
|
||||
oxReturnError(write(inode, buffer, size, fileType));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType) {
|
||||
return m_fs.write(inode, buffer, size, fileType);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ValErr<FileStat> FileSystemTemplate<FileStore, Directory>::stat(uint64_t inode) {
|
||||
auto s = m_fs.stat(inode);
|
||||
FileStat out;
|
||||
out.inode = s.value.inode;
|
||||
out.links = s.value.links;
|
||||
out.size = s.value.size;
|
||||
out.fileType = s.value.fileType;
|
||||
return {out, s.error};
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ValErr<FileStat> FileSystemTemplate<FileStore, Directory>::stat(const char *path) {
|
||||
auto inode = find(path);
|
||||
if (inode.error) {
|
||||
return {{}, inode.error};
|
||||
}
|
||||
return stat(inode.value);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
uint64_t FileSystemTemplate<FileStore, Directory>::spaceNeeded(uint64_t size) {
|
||||
return m_fs.spaceNeeded(size);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
uint64_t FileSystemTemplate<FileStore, Directory>::available() {
|
||||
return m_fs.available();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
uint64_t FileSystemTemplate<FileStore, Directory>::size() const {
|
||||
return m_fs.size();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
char *FileSystemTemplate<FileStore, Directory>::buff() {
|
||||
return m_fs.buff();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::walk(ox::Error(*cb)(uint8_t, uint64_t, uint64_t)) {
|
||||
return m_fs.walk(cb);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
bool FileSystemTemplate<FileStore, Directory>::valid() const {
|
||||
return m_fs.valid();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ValErr<typename FileSystemTemplate<FileStore, Directory>::FileSystemData> FileSystemTemplate<FileStore, Directory>::fileSystemData() const noexcept {
|
||||
FileSystemData fd;
|
||||
auto err = m_fs.read(InodeFsData, &fd, sizeof(fd));
|
||||
if (err != 0) {
|
||||
return {fd, err};
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ValErr<uint64_t> FileSystemTemplate<FileStore, Directory>::find(const char *path) const noexcept {
|
||||
auto fd = fileSystemData();
|
||||
if (fd.error) {
|
||||
return {0, fd.error};
|
||||
}
|
||||
// return root as a special case
|
||||
if (ox_strcmp(path, "/") == 0) {
|
||||
return static_cast<uint64_t>(fd.value.rootDirInode);
|
||||
}
|
||||
Directory rootDir(m_fs, fd.value.rootDirInode);
|
||||
auto inode = rootDir.find(path);
|
||||
if (inode.error) {
|
||||
return {0, inode.error};
|
||||
}
|
||||
return inode.value;
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ValErr<Directory> FileSystemTemplate<FileStore, Directory>::rootDir() const noexcept {
|
||||
auto fd = fileSystemData();
|
||||
if (fd.error) {
|
||||
return {{}, fd.error};
|
||||
}
|
||||
return Directory(m_fs, fd.value.rootDirInode);
|
||||
}
|
||||
|
||||
extern template class FileSystemTemplate<FileStore16, Directory16>;
|
||||
extern template class FileSystemTemplate<FileStore32, Directory32>;
|
||||
|
||||
using FileSystem16 = FileSystemTemplate<FileStore16, Directory16>;
|
||||
using FileSystem32 = FileSystemTemplate<FileStore32, Directory32>;
|
||||
|
||||
}
|
170
deps/ox/src/ox/fs/filesystem/passthroughfs.cpp
vendored
Normal file
170
deps/ox/src/ox/fs/filesystem/passthroughfs.cpp
vendored
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "passthroughfs.hpp"
|
||||
|
||||
#if defined(OX_HAS_PASSTHROUGHFS)
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace ox {
|
||||
|
||||
PassThroughFS::PassThroughFS(const char *dirPath) {
|
||||
m_path = dirPath;
|
||||
}
|
||||
|
||||
PassThroughFS::~PassThroughFS() {
|
||||
}
|
||||
|
||||
std::string PassThroughFS::basePath() {
|
||||
return m_path.string();
|
||||
}
|
||||
|
||||
Error PassThroughFS::mkdir(const char *path, bool recursive) {
|
||||
bool success = false;
|
||||
const auto p = m_path / stripSlash(path);
|
||||
const auto u8p = p.u8string();
|
||||
oxTrace("ox::fs::PassThroughFS::mkdir") << u8p.c_str();
|
||||
if (recursive) {
|
||||
if (std::filesystem::is_directory(p)) {
|
||||
success = true;
|
||||
} else {
|
||||
success = std::filesystem::create_directories(p);
|
||||
}
|
||||
} else {
|
||||
success = std::filesystem::create_directory(p);
|
||||
}
|
||||
return OxError(success ? 0 : 1);
|
||||
}
|
||||
|
||||
Error PassThroughFS::move(const char *src, const char *dest) {
|
||||
std::filesystem::rename(m_path / stripSlash(src), m_path / stripSlash(dest));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error PassThroughFS::read(const char *path, void *buffer, std::size_t buffSize) {
|
||||
try {
|
||||
std::ifstream file((m_path / stripSlash(path)), std::ios::binary | std::ios::ate);
|
||||
const std::size_t size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
if (size > buffSize) {
|
||||
oxTrace("ox::fs::PassThroughFS::read::error") << "Read failed: Buffer too small:" << path;
|
||||
return OxError(1);
|
||||
}
|
||||
file.read(static_cast<char*>(buffer), buffSize);
|
||||
} catch (const std::fstream::failure&) {
|
||||
oxTrace("ox::fs::PassThroughFS::read::error") << "Read failed:" << path;
|
||||
throw OxError(2);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
ValErr<uint8_t*> PassThroughFS::read(const char*) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
Error PassThroughFS::read(uint64_t, void*, std::size_t) {
|
||||
// unsupported
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
Error PassThroughFS::read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) {
|
||||
// unsupported
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
ValErr<uint8_t*> PassThroughFS::read(uint64_t) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
Error PassThroughFS::remove(const char *path, bool recursive) {
|
||||
if (recursive) {
|
||||
return OxError(std::filesystem::remove_all(m_path / stripSlash(path)) != 0);
|
||||
} else {
|
||||
return OxError(std::filesystem::remove(m_path / stripSlash(path)) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error PassThroughFS::resize(uint64_t, void*) {
|
||||
// unsupported
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
Error PassThroughFS::write(const char *path, void *buffer, uint64_t size, uint8_t) {
|
||||
auto p = (m_path / stripSlash(path));
|
||||
try {
|
||||
std::ofstream f(p, std::ios::binary);
|
||||
f.write(static_cast<char*>(buffer), size);
|
||||
} catch (const std::fstream::failure&) {
|
||||
oxTrace("ox::fs::PassThroughFS::write::error") << "Write failed:" << path;
|
||||
throw OxError(1);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error PassThroughFS::write(uint64_t, void*, uint64_t, uint8_t) {
|
||||
// unsupported
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
ValErr<FileStat> PassThroughFS::stat(uint64_t) {
|
||||
// unsupported
|
||||
return {{}, OxError(1)};
|
||||
}
|
||||
|
||||
ValErr<FileStat> PassThroughFS::stat(const char *path) {
|
||||
std::error_code ec;
|
||||
const auto p = m_path / stripSlash(path);
|
||||
uint8_t type = std::filesystem::is_directory(p, ec) ?
|
||||
FileType_Directory : FileType_NormalFile;
|
||||
oxTrace("PassThroughFS::stat") << ec.message().c_str() << path;
|
||||
uint64_t size = type == FileType_Directory ? 0 : std::filesystem::file_size(p, ec);
|
||||
oxTrace("PassThroughFS::stat") << ec.message().c_str() << path;
|
||||
oxTrace("PassThroughFS::stat::size") << path << size;
|
||||
return {{0, 0, size, type}, OxError(ec.value())};
|
||||
}
|
||||
|
||||
uint64_t PassThroughFS::spaceNeeded(uint64_t size) {
|
||||
return size;
|
||||
}
|
||||
|
||||
uint64_t PassThroughFS::available() {
|
||||
std::error_code ec;
|
||||
auto s = std::filesystem::space(m_path, ec);
|
||||
return s.available;
|
||||
}
|
||||
|
||||
uint64_t PassThroughFS::size() const {
|
||||
std::error_code ec;
|
||||
auto s = std::filesystem::space(m_path, ec);
|
||||
return s.capacity;
|
||||
}
|
||||
|
||||
char *PassThroughFS::buff() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Error PassThroughFS::walk(Error(*)(uint8_t, uint64_t, uint64_t)) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
bool PassThroughFS::valid() const {
|
||||
return std::filesystem::is_directory(m_path);
|
||||
}
|
||||
|
||||
const char *PassThroughFS::stripSlash(const char *path) {
|
||||
auto pathLen = ox_strlen(path);
|
||||
for (decltype(pathLen) i = 0; i < pathLen && path[0] == '/'; i++) {
|
||||
path++;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
100
deps/ox/src/ox/fs/filesystem/passthroughfs.hpp
vendored
Normal file
100
deps/ox/src/ox/fs/filesystem/passthroughfs.hpp
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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
|
||||
|
||||
#if __has_include(<filesystem>)
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#define OX_HAS_PASSTHROUGHFS
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef OX_HAS_PASSTHROUGHFS
|
||||
|
||||
#include "filesystem.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class PassThroughFS: public FileSystem {
|
||||
private:
|
||||
std::filesystem::path m_path;
|
||||
|
||||
public:
|
||||
PassThroughFS(const char *dirPath);
|
||||
|
||||
~PassThroughFS();
|
||||
|
||||
[[nodiscard]] std::string basePath();
|
||||
|
||||
ox::Error mkdir(const char *path, bool recursive = false) override;
|
||||
|
||||
ox::Error move(const char *src, const char *dest) override;
|
||||
|
||||
ox::Error read(const char *path, void *buffer, std::size_t buffSize) override;
|
||||
|
||||
ox::ValErr<uint8_t*> read(const char*) override;
|
||||
|
||||
ox::Error read(uint64_t inode, void *buffer, std::size_t size) override;
|
||||
|
||||
ox::Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) override;
|
||||
|
||||
ox::ValErr<uint8_t*> read(uint64_t) override;
|
||||
|
||||
template<typename F>
|
||||
ox::Error ls(const char *dir, F cb);
|
||||
|
||||
ox::Error remove(const char *path, bool recursive = false) override;
|
||||
|
||||
ox::Error resize(uint64_t size, void *buffer = nullptr) override;
|
||||
|
||||
ox::Error write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override;
|
||||
|
||||
ox::Error write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override;
|
||||
|
||||
ox::ValErr<FileStat> stat(uint64_t inode) override;
|
||||
|
||||
ox::ValErr<FileStat> stat(const char *path) override;
|
||||
|
||||
uint64_t spaceNeeded(uint64_t size) override;
|
||||
|
||||
uint64_t available() override;
|
||||
|
||||
uint64_t size() const override;
|
||||
|
||||
char *buff() override;
|
||||
|
||||
ox::Error walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) override;
|
||||
|
||||
bool valid() const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Strips the leading slashes from a string.
|
||||
*/
|
||||
const char *stripSlash(const char *path);
|
||||
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
ox::Error PassThroughFS::ls(const char *dir, F cb) {
|
||||
for (auto &p : std::filesystem::directory_iterator(m_path / stripSlash(dir))) {
|
||||
auto u8p = p.path().filename().u8string();
|
||||
oxReturnError(cb(u8p.c_str(), 0));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
214
deps/ox/src/ox/fs/filesystem/pathiterator.cpp
vendored
Normal file
214
deps/ox/src/ox/fs/filesystem/pathiterator.cpp
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/memops.hpp>
|
||||
#include <ox/std/strops.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
#include "pathiterator.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
PathIterator::PathIterator(const char *path, std::size_t maxSize, std::size_t iterator) {
|
||||
m_path = path;
|
||||
m_maxSize = maxSize;
|
||||
m_iterator = iterator;
|
||||
}
|
||||
|
||||
PathIterator::PathIterator(const char *path): PathIterator(path, ox_strlen(path)) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error PathIterator::dirPath(char *out, std::size_t outSize) {
|
||||
int idx = ox_lastIndexOf(m_path, '/', m_maxSize);
|
||||
std::size_t size = idx + 1;
|
||||
if (idx >= 0 && size < outSize) {
|
||||
ox_memcpy(out, m_path, size);
|
||||
out[size] = 0;
|
||||
return OxError(0);
|
||||
} else {
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error PathIterator::fileName(char *out, std::size_t outSize) {
|
||||
auto idx = ox_lastIndexOf(m_path, '/', m_maxSize);
|
||||
if (idx >= 0) {
|
||||
idx++; // pass up the preceding /
|
||||
std::size_t fileNameSize = ox_strlen(&m_path[idx]);
|
||||
if (fileNameSize < outSize) {
|
||||
ox_memcpy(out, &m_path[idx], fileNameSize);
|
||||
out[fileNameSize] = 0;
|
||||
return OxError(0);
|
||||
} else {
|
||||
return OxError(1);
|
||||
}
|
||||
} else {
|
||||
return OxError(2);
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the get item in the path
|
||||
Error PathIterator::get(char *pathOut, std::size_t pathOutSize) {
|
||||
std::size_t size = 0;
|
||||
if (m_iterator >= m_maxSize) {
|
||||
oxTrace("ox::fs::PathIterator::get") << "m_iterator >= m_maxSize";
|
||||
return OxError(1);
|
||||
}
|
||||
if (!ox_strlen(&m_path[m_iterator])) {
|
||||
oxTrace("ox::fs::PathIterator::get") << "!ox_strlen(&m_path[m_iterator])";
|
||||
return OxError(1);
|
||||
}
|
||||
auto start = m_iterator;
|
||||
if (m_path[start] == '/') {
|
||||
start++;
|
||||
}
|
||||
// end is at the next /
|
||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||
// correct end if it is invalid, which happens if there is no next /
|
||||
if (!substr) {
|
||||
substr = ox_strchr(&m_path[start], 0, m_maxSize - start);
|
||||
}
|
||||
std::size_t end = substr - m_path;
|
||||
size = end - start;
|
||||
// cannot fit the output in the output parameter
|
||||
if (size >= pathOutSize || size == 0) {
|
||||
return OxError(1);
|
||||
}
|
||||
ox_memcpy(pathOut, &m_path[start], size);
|
||||
// truncate trailing /
|
||||
if (size && pathOut[size - 1] == '/') {
|
||||
size--;
|
||||
}
|
||||
pathOut[size] = 0; // end with null terminator
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
// Gets the get item in the path
|
||||
Error PathIterator::next(char *pathOut, std::size_t pathOutSize) {
|
||||
std::size_t size = 0;
|
||||
auto retval = OxError(1);
|
||||
if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) {
|
||||
retval = OxError(0);
|
||||
if (m_path[m_iterator] == '/') {
|
||||
m_iterator++;
|
||||
}
|
||||
std::size_t start = m_iterator;
|
||||
// end is at the next /
|
||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||
// correct end if it is invalid, which happens if there is no next /
|
||||
if (!substr) {
|
||||
substr = ox_strchr(&m_path[start], 0, m_maxSize - start);
|
||||
}
|
||||
std::size_t end = substr - m_path;
|
||||
size = end - start;
|
||||
// cannot fit the output in the output parameter
|
||||
if (size >= pathOutSize) {
|
||||
return OxError(1);
|
||||
}
|
||||
ox_memcpy(pathOut, &m_path[start], size);
|
||||
}
|
||||
// truncate trailing /
|
||||
if (size && pathOut[size - 1] == '/') {
|
||||
size--;
|
||||
}
|
||||
pathOut[size] = 0; // end with null terminator
|
||||
m_iterator += size;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error PathIterator::get(BString<MaxFileNameLength> *fileName) {
|
||||
return get(fileName->data(), fileName->cap());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error PathIterator::next(BString<MaxFileNameLength> *fileName) {
|
||||
return next(fileName->data(), fileName->cap());
|
||||
}
|
||||
|
||||
ValErr<std::size_t> PathIterator::nextSize() const {
|
||||
std::size_t size = 0;
|
||||
auto retval = OxError(1);
|
||||
auto it = m_iterator;
|
||||
if (it < m_maxSize && ox_strlen(&m_path[it])) {
|
||||
retval = OxError(0);
|
||||
if (m_path[it] == '/') {
|
||||
it++;
|
||||
}
|
||||
std::size_t start = it;
|
||||
// end is at the next /
|
||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||
// correct end if it is invalid, which happens if there is no next /
|
||||
if (!substr) {
|
||||
substr = ox_strchr(&m_path[start], 0, m_maxSize - start);
|
||||
}
|
||||
std::size_t end = substr - m_path;
|
||||
size = end - start;
|
||||
}
|
||||
it += size;
|
||||
return {size, retval};
|
||||
}
|
||||
|
||||
bool PathIterator::hasNext() const {
|
||||
std::size_t size = 0;
|
||||
if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) {
|
||||
std::size_t start = m_iterator;
|
||||
if (m_path[start] == '/') {
|
||||
start++;
|
||||
}
|
||||
// end is at the next /
|
||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||
// correct end if it is invalid, which happens if there is no next /
|
||||
if (!substr) {
|
||||
substr = ox_strchr(&m_path[start], 0, m_maxSize - start);
|
||||
}
|
||||
std::size_t end = substr - m_path;
|
||||
size = end - start;
|
||||
}
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
bool PathIterator::valid() const {
|
||||
return m_iterator < m_maxSize && m_path[m_iterator] != 0;
|
||||
}
|
||||
|
||||
PathIterator PathIterator::next() const {
|
||||
std::size_t size = 0;
|
||||
auto iterator = m_iterator;
|
||||
if (iterator < m_maxSize && ox_strlen(&m_path[iterator])) {
|
||||
if (m_path[iterator] == '/') {
|
||||
iterator++;
|
||||
}
|
||||
std::size_t start = iterator;
|
||||
// end is at the next /
|
||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||
// correct end if it is invalid, which happens if there is no next /
|
||||
if (!substr) {
|
||||
substr = ox_strchr(&m_path[start], 0, m_maxSize - start);
|
||||
}
|
||||
std::size_t end = substr - m_path;
|
||||
size = end - start;
|
||||
}
|
||||
iterator += size;
|
||||
return PathIterator(m_path, m_maxSize, iterator + 1);
|
||||
}
|
||||
|
||||
const char *PathIterator::fullPath() const {
|
||||
return m_path;
|
||||
}
|
||||
|
||||
}
|
74
deps/ox/src/ox/fs/filesystem/pathiterator.hpp
vendored
Normal file
74
deps/ox/src/ox/fs/filesystem/pathiterator.hpp
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/std.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
constexpr std::size_t MaxFileNameLength = 255;
|
||||
using FileName = BString<MaxFileNameLength>;
|
||||
|
||||
class PathIterator {
|
||||
private:
|
||||
const char *m_path = nullptr;
|
||||
std::size_t m_iterator = 0;
|
||||
std::size_t m_maxSize = 0;
|
||||
|
||||
public:
|
||||
PathIterator(const char *path, std::size_t maxSize, std::size_t iterator = 0);
|
||||
|
||||
PathIterator(const char *path);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error dirPath(char *pathOut, std::size_t pathOutSize);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error fileName(char *out, std::size_t outSize);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error next(char *pathOut, std::size_t pathOutSize);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error get(char *pathOut, std::size_t pathOutSize);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error next(FileName *fileName);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error get(FileName *fileName);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
ValErr<std::size_t> nextSize() const;
|
||||
|
||||
bool hasNext() const;
|
||||
|
||||
bool valid() const;
|
||||
|
||||
[[nodiscard]] PathIterator next() const;
|
||||
|
||||
const char *fullPath() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
44
deps/ox/src/ox/fs/filesystem/types.hpp
vendored
Normal file
44
deps/ox/src/ox/fs/filesystem/types.hpp
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/types.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
enum FsType {
|
||||
OxFS_16 = 1,
|
||||
OxFS_32 = 2,
|
||||
OxFS_64 = 3
|
||||
};
|
||||
|
||||
enum FileType {
|
||||
FileType_NormalFile = 1,
|
||||
FileType_Directory = 2
|
||||
};
|
||||
|
||||
constexpr const char *toString(FileType t) {
|
||||
switch (t) {
|
||||
case FileType_NormalFile:
|
||||
return "Normal File";
|
||||
case FileType_Directory:
|
||||
return "Directory";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
struct FileStat {
|
||||
uint64_t inode = 0;
|
||||
uint64_t links = 0;
|
||||
uint64_t size = 0;
|
||||
uint8_t fileType = 0;
|
||||
};
|
||||
|
||||
}
|
15
deps/ox/src/ox/fs/fs.hpp
vendored
Normal file
15
deps/ox/src/ox/fs/fs.hpp
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "filestore/filestoretemplate.hpp"
|
||||
#include "filesystem/filelocation.hpp"
|
||||
#include "filesystem/filesystem.hpp"
|
||||
#include "filesystem/passthroughfs.hpp"
|
||||
#include "filesystem/directory.hpp"
|
27
deps/ox/src/ox/fs/test/CMakeLists.txt
vendored
Normal file
27
deps/ox/src/ox/fs/test/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
add_executable(
|
||||
FSTests
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
FSTests
|
||||
OxFS
|
||||
OxStd
|
||||
OxMetalClaw
|
||||
)
|
||||
|
||||
add_test("Test\\ PathIterator::next1" FSTests PathIterator::next1)
|
||||
add_test("Test\\ PathIterator::next2" FSTests PathIterator::next2)
|
||||
add_test("Test\\ PathIterator::next3" FSTests PathIterator::next3)
|
||||
add_test("Test\\ PathIterator::next4" FSTests PathIterator::next4)
|
||||
add_test("Test\\ PathIterator::next5" FSTests PathIterator::next5)
|
||||
add_test("Test\\ PathIterator::hasNext" FSTests PathIterator::hasNext)
|
||||
|
||||
add_test("Test\\ PathIterator::dirPath" FSTests PathIterator::dirPath)
|
||||
add_test("Test\\ PathIterator::fileName" FSTests PathIterator::fileName)
|
||||
|
||||
add_test("Test\\ NodeBuffer::insert" FSTests "NodeBuffer::insert")
|
||||
add_test("Test\\ FileStore::readWrite" FSTests "FileStore::readWrite")
|
||||
|
||||
add_test("Test\\ Directory" FSTests "Directory")
|
||||
add_test("Test\\ FileSystem" FSTests "FileSystem")
|
231
deps/ox/src/ox/fs/test/tests.cpp
vendored
Normal file
231
deps/ox/src/ox/fs/test/tests.cpp
vendored
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// make sure asserts are enabled for the test file
|
||||
#undef NDEBUG
|
||||
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
#include <ox/fs/filestore/filestoretemplate.hpp>
|
||||
#include <ox/fs/filesystem/filesystem.hpp>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace ox;
|
||||
|
||||
map<string, int(*)(string)> tests = {
|
||||
{
|
||||
{
|
||||
"PathIterator::next1",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "/usr/share/charset.gbag";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::next2",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "/usr/share/";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::next3",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "/";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "\0") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::next4",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "usr/share/charset.gbag";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::next5",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "usr/share/";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::dirPath",
|
||||
[] (string) {
|
||||
int retval = 0;
|
||||
string path = "/usr/share/charset.gbag";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.dirPath(buff, path.size()) == 0 && ox_strcmp(buff, "/usr/share/") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::fileName",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "/usr/share/charset.gbag";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.fileName(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::hasNext",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
const auto path = "/file1";
|
||||
PathIterator it(path, ox_strlen(path));
|
||||
oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext");
|
||||
oxAssert(!it.next().hasNext(), "PathIterator shows incorrect hasNext");
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"Ptr::subPtr",
|
||||
[](string) {
|
||||
constexpr auto buffLen = 5000;
|
||||
ox::ptrarith::Ptr<uint8_t, uint32_t> p(ox_alloca(buffLen), buffLen, 500, 500);
|
||||
oxAssert(p.valid(), "Ptr::subPtr: Ptr p is invalid.");
|
||||
|
||||
auto subPtr = p.subPtr<uint64_t>(50);
|
||||
oxAssert(subPtr.valid(), "Ptr::subPtr: Ptr subPtr is invalid.");
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
{
|
||||
"NodeBuffer::insert",
|
||||
[](string) {
|
||||
int err = 0;
|
||||
constexpr auto buffLen = 5000;
|
||||
auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
|
||||
oxAssert(list->malloc(50).valid(), "NodeBuffer::insert: malloc 1 failed");
|
||||
oxAssert(list->malloc(50).valid(), "NodeBuffer::insert: malloc 2 failed");
|
||||
auto first = list->firstItem();
|
||||
oxAssert(first.valid(), "NodeBuffer::insert: Could not access first item");
|
||||
oxAssert(first->size() == 50, "NodeBuffer::insert: First item size invalid");
|
||||
return err;
|
||||
}
|
||||
},
|
||||
{
|
||||
"FileStore::readWrite",
|
||||
[](string) {
|
||||
constexpr auto buffLen = 5000;
|
||||
constexpr auto str1 = "Hello, World!";
|
||||
constexpr auto str1Len = ox_strlen(str1) + 1;
|
||||
constexpr auto str2 = "Hello, Moon!";
|
||||
constexpr auto str2Len = ox_strlen(str2) + 1;
|
||||
auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
|
||||
oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed.");
|
||||
ox::FileStore32 fileStore(list, buffLen);
|
||||
oxAssert(fileStore.write(4, const_cast<char*>(str1), str1Len, 1), "FileStore::write 1 failed.");
|
||||
oxAssert(fileStore.write(5, const_cast<char*>(str2), str2Len, 1), "FileStore::write 2 failed.");
|
||||
|
||||
char str1Read[str1Len];
|
||||
size_t str1ReadSize = 0;
|
||||
oxAssert(fileStore.read(4, reinterpret_cast<void*>(str1Read), str1Len, &str1ReadSize), "FileStore::read 1 failed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
{
|
||||
"Directory",
|
||||
[](string) {
|
||||
std::vector<uint8_t> fsBuff(5000);
|
||||
oxAssert(ox::FileStore32::format(fsBuff.data(), fsBuff.size()), "FS format failed");
|
||||
ox::FileStore32 fileStore(fsBuff.data(), fsBuff.size());
|
||||
ox::Directory32 dir(fileStore, 105);
|
||||
|
||||
oxTrace("ox::fs::test::Directory") << "Init";
|
||||
oxAssert(dir.init(), "Init failed");
|
||||
|
||||
oxTrace("ox::fs::test::Directory") << "write 1";
|
||||
oxAssert(dir.write("/file1", 1), "Directory write of file1 failed");
|
||||
|
||||
oxTrace("ox::fs::test::Directory") << "find";
|
||||
oxAssert(dir.find("file1").error, "Could not find file1");
|
||||
oxAssert(dir.find("file1").value == 1, "Could not find file1");
|
||||
|
||||
oxTrace("ox::fs::test::Directory") << "write 2";
|
||||
oxAssert(dir.write("/file3", 3), "Directory write of file3 failed");
|
||||
|
||||
oxTrace("ox::fs::test::Directory") << "write 3";
|
||||
oxAssert(dir.write("/file2", 2), "Directory write of file2 failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
{
|
||||
"FileSystem",
|
||||
[](string) {
|
||||
std::vector<uint8_t> fsBuff(5000);
|
||||
oxTrace("ox::fs::test::FileSystem") << "format";
|
||||
oxAssert(ox::FileSystem32::format(fsBuff.data(), fsBuff.size()), "FileSystem format failed");
|
||||
ox::FileSystem32 fs(ox::FileStore32(fsBuff.data(), fsBuff.size()));
|
||||
|
||||
oxTrace("ox::fs::test::FileSystem") << "mkdir";
|
||||
oxAssert(fs.mkdir("/dir", true), "mkdir failed");
|
||||
oxAssert(fs.stat("/dir").error, "mkdir failed");
|
||||
oxAssert(fs.mkdir("/l1d1/l2d1/l3d1", true), "mkdir failed");
|
||||
oxAssert(fs.stat("/l1d1/l2d1/l3d1").error, "mkdir failed");
|
||||
oxAssert(fs.mkdir("/l1d1/l2d2", true), "mkdir failed");
|
||||
oxAssert(fs.stat("/l1d1/l2d2").error, "mkdir failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
int retval = -1;
|
||||
if (argc > 1) {
|
||||
auto testName = args[1];
|
||||
string testArg = "";
|
||||
if (args[2]) {
|
||||
testArg = args[2];
|
||||
}
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
retval = tests[testName](testArg);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
43
deps/ox/src/ox/mc/CMakeLists.txt
vendored
Normal file
43
deps/ox/src/ox/mc/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
add_library(
|
||||
OxMetalClaw
|
||||
presenceindicator.cpp
|
||||
read.cpp
|
||||
write.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
OxMetalClaw PUBLIC
|
||||
OxModel
|
||||
OxStd
|
||||
)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
set_property(
|
||||
TARGET
|
||||
OxMetalClaw
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES
|
||||
intops.hpp
|
||||
err.hpp
|
||||
mc.hpp
|
||||
presenceindicator.hpp
|
||||
read.hpp
|
||||
types.hpp
|
||||
write.hpp
|
||||
DESTINATION
|
||||
include/ox/mc
|
||||
)
|
||||
|
||||
install(TARGETS OxMetalClaw
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS STREQUAL "ON")
|
||||
add_subdirectory(test)
|
||||
endif()
|
19
deps/ox/src/ox/mc/err.hpp
vendored
Normal file
19
deps/ox/src/ox/mc/err.hpp
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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
|
||||
|
||||
namespace ox {
|
||||
|
||||
enum {
|
||||
MC_PRESENCEMASKOUTBOUNDS = 1,
|
||||
MC_BUFFENDED = 2,
|
||||
MC_OUTBUFFENDED = 4
|
||||
};
|
||||
|
||||
}
|
152
deps/ox/src/ox/mc/intops.hpp
vendored
Normal file
152
deps/ox/src/ox/mc/intops.hpp
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/assert.hpp>
|
||||
#include <ox/std/bit.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
|
||||
namespace ox::mc {
|
||||
|
||||
template<typename T>
|
||||
static constexpr auto Bits = sizeof(T) << 3;
|
||||
|
||||
/**
|
||||
* Returns highest bit other than possible signed bit.
|
||||
* Bit numbering starts at 0.
|
||||
*/
|
||||
template<typename I>
|
||||
[[nodiscard]] constexpr std::size_t highestBit(I val) noexcept {
|
||||
auto shiftStart = sizeof(I) * 8 - 1;
|
||||
// find most significant non-sign indicator bit
|
||||
std::size_t highestBit = 0;
|
||||
// start at one bit lower if signed
|
||||
if constexpr(ox::is_signed_v<I>) {
|
||||
--shiftStart;
|
||||
}
|
||||
for (int i = shiftStart; i > -1; --i) {
|
||||
const auto bitValue = (val >> i) & 1;
|
||||
if (bitValue) {
|
||||
highestBit = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return highestBit;
|
||||
}
|
||||
|
||||
static_assert(highestBit(int8_t(0b10000000)) == 0);
|
||||
static_assert(highestBit(1) == 0);
|
||||
static_assert(highestBit(2) == 1);
|
||||
static_assert(highestBit(4) == 2);
|
||||
static_assert(highestBit(8) == 3);
|
||||
static_assert(highestBit(uint64_t(1) << 31) == 31);
|
||||
static_assert(highestBit(uint64_t(1) << 63) == 63);
|
||||
|
||||
struct McInt {
|
||||
uint8_t data[9] = {0};
|
||||
// length of integer in bytes
|
||||
std::size_t length = 0;
|
||||
};
|
||||
|
||||
template<typename I>
|
||||
[[nodiscard]] constexpr McInt encodeInteger(I input) noexcept {
|
||||
McInt out;
|
||||
// move input to uint64_t to allow consistent bit manipulation, and to avoid
|
||||
// overflow concerns
|
||||
uint64_t val = 0;
|
||||
ox_memcpy(&val, &input, sizeof(I));
|
||||
if (val) {
|
||||
// bits needed to represent number factoring in space possibly
|
||||
// needed for signed bit
|
||||
const auto bits = highestBit(val) + 1 + (ox::is_signed_v<I> ? 1 : 0);
|
||||
// bytes needed to store value
|
||||
std::size_t bytes = bits / 8 + (bits % 8 != 0);
|
||||
const auto bitsAvailable = bytes * 8; // bits available to integer value
|
||||
const auto bitsNeeded = bits + bytes;
|
||||
// factor in bits needed for bytesIndicator (does not affect bytesIndicator)
|
||||
// bits for integer + bits neded to represent bytes > bits available
|
||||
if (bitsNeeded > bitsAvailable && bytes != 9) {
|
||||
++bytes;
|
||||
}
|
||||
const auto bytesIndicator = onMask<uint8_t>(bytes - 1);
|
||||
|
||||
// ensure we are copying from little endian represenstation
|
||||
LittleEndian<I> leVal = val;
|
||||
if (bytes == 9) {
|
||||
out.data[0] = bytesIndicator;
|
||||
ox_memcpy(&out.data[1], &leVal, sizeof(I));
|
||||
} else {
|
||||
auto intermediate =
|
||||
static_cast<uint64_t>(leVal.raw()) << bytes |
|
||||
static_cast<uint64_t>(bytesIndicator);
|
||||
ox_memcpy(out.data, &intermediate, sizeof(intermediate));
|
||||
}
|
||||
out.length = bytes;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes indicated by the bytes indicator of a variable
|
||||
* length integer.
|
||||
*/
|
||||
[[nodiscard]] static constexpr std::size_t countBytes(uint8_t b) noexcept {
|
||||
std::size_t i = 0;
|
||||
for (; (b >> i) & 1; i++);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static_assert(countBytes(0b00000000) == 1);
|
||||
static_assert(countBytes(0b00000001) == 2);
|
||||
static_assert(countBytes(0b00000011) == 3);
|
||||
static_assert(countBytes(0b00000111) == 4);
|
||||
static_assert(countBytes(0b00001111) == 5);
|
||||
static_assert(countBytes(0b00011111) == 6);
|
||||
static_assert(countBytes(0b00111111) == 7);
|
||||
static_assert(countBytes(0b01111111) == 8);
|
||||
static_assert(countBytes(0b11111111) == 9);
|
||||
|
||||
template<typename I>
|
||||
[[nodiscard]] constexpr ValErr<I> decodeInteger(uint8_t buff[9], std::size_t buffLen, std::size_t *bytesRead) noexcept {
|
||||
const auto bytes = countBytes(buff[0]);
|
||||
if (bytes == 9) {
|
||||
*bytesRead = bytes;
|
||||
I out = 0;
|
||||
memcpy(&out, &buff[1], sizeof(I));
|
||||
return {LittleEndian<I>(out), OxError(0)};
|
||||
} else if (buffLen >= bytes) {
|
||||
*bytesRead = bytes;
|
||||
uint64_t decoded = 0;
|
||||
memcpy(&decoded, &buff[0], bytes);
|
||||
decoded >>= bytes;
|
||||
auto out = static_cast<I>(decoded);
|
||||
// move sign bit
|
||||
if constexpr(ox::is_signed_v<I>) {
|
||||
const auto valBits = bytes << 3;
|
||||
// get sign
|
||||
uint64_t sign = decoded >> (valBits - 1);
|
||||
// remove sign
|
||||
decoded &= uint64_t(~0) ^ (uint64_t(1) << valBits);
|
||||
// set sign
|
||||
decoded |= sign << (Bits<I> - 1);
|
||||
memcpy(&out, &decoded, sizeof(out));
|
||||
}
|
||||
return {out, OxError(0)};
|
||||
}
|
||||
return {0, OxError(1)};
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
[[nodiscard]] ValErr<I> decodeInteger(McInt m) noexcept {
|
||||
std::size_t bytesRead;
|
||||
return decodeInteger<I>(m.data, 9, &bytesRead);
|
||||
}
|
||||
|
||||
}
|
14
deps/ox/src/ox/mc/mc.hpp
vendored
Normal file
14
deps/ox/src/ox/mc/mc.hpp
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "intops.hpp"
|
||||
#include "read.hpp"
|
||||
#include "types.hpp"
|
||||
#include "write.hpp"
|
59
deps/ox/src/ox/mc/presenceindicator.cpp
vendored
Normal file
59
deps/ox/src/ox/mc/presenceindicator.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/byteswap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
#include "err.hpp"
|
||||
#include "presenceindicator.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
FieldPresenceIndicator::FieldPresenceIndicator(uint8_t *mask, std::size_t maxLen) {
|
||||
m_mask = mask;
|
||||
m_maskLen = maxLen;
|
||||
}
|
||||
|
||||
ValErr<bool> FieldPresenceIndicator::get(std::size_t i) const {
|
||||
if (i / 8 < m_maskLen) {
|
||||
return (m_mask[i / 8] >> (i % 8)) & 1;
|
||||
} else {
|
||||
return {false, OxError(MC_PRESENCEMASKOUTBOUNDS)};
|
||||
}
|
||||
}
|
||||
|
||||
Error FieldPresenceIndicator::set(std::size_t i, bool on) {
|
||||
if (i / 8 < m_maskLen) {
|
||||
if (on) {
|
||||
m_mask[i / 8] |= 1 << (i % 8);
|
||||
} else {
|
||||
m_mask[i / 8] &= ~(1 << (i % 8));
|
||||
}
|
||||
return OxError(0);
|
||||
} else {
|
||||
return OxError(MC_PRESENCEMASKOUTBOUNDS);
|
||||
}
|
||||
}
|
||||
|
||||
void FieldPresenceIndicator::setFields(int fields) noexcept {
|
||||
m_fields = fields;
|
||||
m_maskLen = (fields / 8 + 1) - (fields % 8 == 0);
|
||||
}
|
||||
|
||||
int FieldPresenceIndicator::getFields() const noexcept {
|
||||
return m_fields;
|
||||
}
|
||||
|
||||
void FieldPresenceIndicator::setMaxLen(int maxLen) noexcept {
|
||||
m_maskLen = maxLen;
|
||||
}
|
||||
|
||||
int FieldPresenceIndicator::getMaxLen() const noexcept {
|
||||
return m_maskLen;
|
||||
}
|
||||
|
||||
}
|
39
deps/ox/src/ox/mc/presenceindicator.hpp
vendored
Normal file
39
deps/ox/src/ox/mc/presenceindicator.hpp
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/error.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
class FieldPresenceIndicator {
|
||||
private:
|
||||
uint8_t *m_mask = nullptr;
|
||||
std::size_t m_maskLen = 0;
|
||||
std::size_t m_fields = 0;
|
||||
|
||||
public:
|
||||
FieldPresenceIndicator(uint8_t *mask, std::size_t maxLen);
|
||||
|
||||
[[nodiscard]] ValErr<bool> get(std::size_t i) const;
|
||||
|
||||
[[nodiscard]] Error set(std::size_t i, bool on);
|
||||
|
||||
void setFields(int) noexcept;
|
||||
|
||||
int getFields() const noexcept;
|
||||
|
||||
void setMaxLen(int) noexcept;
|
||||
|
||||
int getMaxLen() const noexcept;
|
||||
|
||||
};
|
||||
|
||||
}
|
154
deps/ox/src/ox/mc/read.cpp
vendored
Normal file
154
deps/ox/src/ox/mc/read.cpp
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/assert.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
|
||||
#include "read.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
MetalClawReader::MetalClawReader(uint8_t *buff, std::size_t buffLen, int unionIdx, MetalClawReader *parent) noexcept:
|
||||
m_fieldPresence(buff, buffLen),
|
||||
m_unionIdx(unionIdx),
|
||||
m_buffLen(buffLen),
|
||||
m_buff(buff),
|
||||
m_parent(parent) {
|
||||
}
|
||||
|
||||
MetalClawReader::~MetalClawReader() noexcept {
|
||||
if (m_parent) {
|
||||
m_parent->m_buffIt += m_buffIt;
|
||||
}
|
||||
if (m_field != m_fields) {
|
||||
oxTrace("ox::mc::MetalClawReader::error") << "MetalClawReader: incorrect fields number given";
|
||||
}
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, int8_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, int16_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, int32_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, int64_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
|
||||
Error MetalClawReader::field(const char*, uint8_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, uint16_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, uint32_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, uint64_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, bool *val) {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
auto valErr = m_fieldPresence.get(m_field);
|
||||
*val = valErr.value;
|
||||
oxReturnError(valErr.error);
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, SerStr val) {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(err);
|
||||
auto data = val.data(size + 1);
|
||||
// read the string
|
||||
if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) {
|
||||
if (m_buffIt + size <= m_buffLen) {
|
||||
ox_memcpy(data, &m_buff[m_buffIt], size);
|
||||
data[size] = 0;
|
||||
m_buffIt += size;
|
||||
} else {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
} else {
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
}
|
||||
} else {
|
||||
auto data = val.data();
|
||||
if (data) {
|
||||
data[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
[[nodiscard]] ValErr<ArrayLength> MetalClawReader::arrayLength(const char*, bool pass) {
|
||||
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto out = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead).value;
|
||||
if (pass) {
|
||||
m_buffIt += bytesRead;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
[[nodiscard]] StringLength MetalClawReader::stringLength(const char*) {
|
||||
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
return len.value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MetalClawReader MetalClawReader::child(const char*, int unionIdx) {
|
||||
return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, unionIdx, this);
|
||||
}
|
||||
|
||||
bool MetalClawReader::fieldPresent(const char*) const {
|
||||
return m_fieldPresence.get(m_field).value;
|
||||
}
|
||||
|
||||
bool MetalClawReader::fieldPresent(int fieldNo) const {
|
||||
return m_fieldPresence.get(fieldNo).value;
|
||||
}
|
||||
|
||||
void MetalClawReader::nextField() noexcept {
|
||||
++m_field;
|
||||
}
|
||||
|
||||
}
|
281
deps/ox/src/ox/mc/read.hpp
vendored
Normal file
281
deps/ox/src/ox/mc/read.hpp
vendored
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/model/optype.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "err.hpp"
|
||||
#include "intops.hpp"
|
||||
#include "presenceindicator.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
class MetalClawReader {
|
||||
|
||||
private:
|
||||
FieldPresenceIndicator m_fieldPresence;
|
||||
int m_fields = 0;
|
||||
int m_field = 0;
|
||||
int m_unionIdx = -1;
|
||||
std::size_t m_buffIt = 0;
|
||||
std::size_t m_buffLen = 0;
|
||||
uint8_t *m_buff = nullptr;
|
||||
MetalClawReader *m_parent = nullptr;
|
||||
|
||||
public:
|
||||
MetalClawReader(uint8_t *buff, std::size_t buffLen, int unionIdx = -1, MetalClawReader *parent = nullptr) noexcept;
|
||||
|
||||
~MetalClawReader() noexcept;
|
||||
|
||||
[[nodiscard]] Error field(const char*, int8_t *val);
|
||||
[[nodiscard]] Error field(const char*, int16_t *val);
|
||||
[[nodiscard]] Error field(const char*, int32_t *val);
|
||||
[[nodiscard]] Error field(const char*, int64_t *val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, uint8_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint16_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint32_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint64_t *val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, bool *val);
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, T *val, std::size_t len);
|
||||
|
||||
// map handler
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, HashMap<String, T> *val);
|
||||
|
||||
// array handler, with callback to allow handling individual elements
|
||||
template<typename T, typename Handler>
|
||||
[[nodiscard]] Error field(const char*, Handler handler);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, ox::Vector<T> *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, T *val);
|
||||
|
||||
template<typename U>
|
||||
[[nodiscard]] Error field(const char*, UnionView<U> val);
|
||||
|
||||
template<std::size_t L>
|
||||
[[nodiscard]] Error field(const char*, ox::BString<L> *val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, SerStr val);
|
||||
|
||||
/**
|
||||
* Reads an array length from the current location in the buffer.
|
||||
* @param pass indicates that the parsing should iterate past the array length
|
||||
*/
|
||||
[[nodiscard]] ValErr<ArrayLength> arrayLength(const char *name, bool pass = true);
|
||||
|
||||
/**
|
||||
* Reads an string length from the current location in the buffer.
|
||||
*/
|
||||
[[nodiscard]] StringLength stringLength(const char *name);
|
||||
|
||||
template<typename T = std::nullptr_t>
|
||||
void setTypeInfo(const char *name = T::TypeName, int fields = T::Fields);
|
||||
|
||||
/**
|
||||
* Returns a MetalClawReader to parse a child object.
|
||||
*/
|
||||
[[nodiscard]] MetalClawReader child(const char *name, int unionIdx = -1);
|
||||
|
||||
/**
|
||||
* Indicates whether or not the next field to be read is present.
|
||||
*/
|
||||
bool fieldPresent(const char *name) const;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the given field is present.
|
||||
*/
|
||||
bool fieldPresent(int fieldNo) const;
|
||||
|
||||
void nextField() noexcept;
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::Read;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename I>
|
||||
[[nodiscard]] Error readInteger(I *val);
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char*, T *val) {
|
||||
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val && m_fieldPresence.get(m_field)) {
|
||||
auto reader = child("");
|
||||
oxReturnError(model(&reader, val));
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Error MetalClawReader::field(const char*, UnionView<U> val) {
|
||||
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val.get() && m_fieldPresence.get(m_field)) {
|
||||
auto reader = child("", val.idx());
|
||||
oxReturnError(model(&reader, val.get()));
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<std::size_t L>
|
||||
Error MetalClawReader::field(const char *name, ox::BString<L> *val) {
|
||||
return field(name, SerStr(val->data(), val->cap()));
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
Error MetalClawReader::readInteger(I *val) {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
std::size_t bytesRead = 0;
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
oxTrace("ox::MetalClaw::readInteger") << "Buffer ended";
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
auto valErr = mc::decodeInteger<I>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(valErr.error);
|
||||
*val = valErr.value;
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(len.error);
|
||||
|
||||
// read the list
|
||||
if (valLen >= len.value) {
|
||||
auto reader = child("");
|
||||
reader.setTypeInfo("List", len.value);
|
||||
for (std::size_t i = 0; i < len.value; i++) {
|
||||
oxReturnError(reader.field("", &val[i]));
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen;
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
}
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char*, HashMap<String, T> *val) {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(len.error);
|
||||
|
||||
// read the list
|
||||
auto reader = child("");
|
||||
reader.setTypeInfo("List", len.value);
|
||||
for (std::size_t i = 0; i < len.value; i++) {
|
||||
auto keyLen = reader.stringLength(nullptr);
|
||||
auto wkey = ox_malloca(keyLen + 1, char, 0);
|
||||
oxReturnError(reader.field("", SerStr(wkey.get(), keyLen)));
|
||||
oxReturnError(reader.field("", &val->at(wkey.get())));
|
||||
}
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T, typename Handler>
|
||||
Error MetalClawReader::field(const char*, Handler handler) {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(len.error);
|
||||
|
||||
// read the list
|
||||
auto reader = child("");
|
||||
reader.setTypeInfo("List", len.value);
|
||||
for (std::size_t i = 0; i < len.value; i++) {
|
||||
T val;
|
||||
oxReturnError(reader.field("", &val));
|
||||
oxReturnError(handler(i, &val));
|
||||
}
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char* name, ox::Vector<T> *val) {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
// set size of val if the field is present, don't worry about it if not
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
const auto [len, err] = arrayLength(name, false);
|
||||
oxReturnError(err);
|
||||
val->resize(len);
|
||||
}
|
||||
return field(name, val->data(), val->size());
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void MetalClawReader::setTypeInfo(const char*, int fields) {
|
||||
m_fields = fields;
|
||||
m_buffIt = (fields / 8 + 1) - (fields % 8 == 0);
|
||||
m_fieldPresence.setFields(fields);
|
||||
m_fieldPresence.setMaxLen(m_buffIt);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error readMC(uint8_t *buff, std::size_t buffLen, T *val) {
|
||||
MetalClawReader reader(buff, buffLen);
|
||||
return model(&reader, val);
|
||||
}
|
||||
|
||||
}
|
15
deps/ox/src/ox/mc/test/CMakeLists.txt
vendored
Normal file
15
deps/ox/src/ox/mc/test/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
add_executable(
|
||||
McTest
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
McTest
|
||||
OxMetalClaw
|
||||
)
|
||||
|
||||
add_test("Test\\ McTest\\ Writer" McTest MetalClawWriter)
|
||||
add_test("Test\\ McTest\\ Reader" McTest MetalClawReader)
|
||||
add_test("Test\\ McTest\\ MetalClawDef" McTest MetalClawDef)
|
||||
add_test("Test\\ McTest\\ encodeInteger" McTest encodeInteger)
|
||||
add_test("Test\\ McTest\\ decodeInteger" McTest decodeInteger)
|
407
deps/ox/src/ox/mc/test/tests.cpp
vendored
Normal file
407
deps/ox/src/ox/mc/test/tests.cpp
vendored
Normal file
@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "ox/std/hashmap.hpp"
|
||||
#undef NDEBUG
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ox/mc/mc.hpp>
|
||||
#include <ox/model/model.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
union TestUnion {
|
||||
static constexpr auto TypeName = "TestUnion";
|
||||
static constexpr auto Fields = 3;
|
||||
bool Bool;
|
||||
uint32_t Int = 5;
|
||||
char String[32];
|
||||
};
|
||||
|
||||
struct TestStructNest {
|
||||
static constexpr auto TypeName = "TestStructNest";
|
||||
static constexpr auto Fields = 3;
|
||||
bool Bool = false;
|
||||
uint32_t Int = 0;
|
||||
ox::BString<32> String = "";
|
||||
};
|
||||
|
||||
struct TestStruct {
|
||||
static constexpr auto TypeName = "TestStruct";
|
||||
static constexpr auto Fields = 17;
|
||||
bool Bool = false;
|
||||
int32_t Int = 0;
|
||||
int32_t Int1 = 0;
|
||||
int32_t Int2 = 0;
|
||||
int32_t Int3 = 0;
|
||||
int32_t Int4 = 0;
|
||||
int32_t Int5 = 0;
|
||||
int32_t Int6 = 0;
|
||||
int32_t Int7 = 0;
|
||||
int32_t Int8 = 0;
|
||||
TestUnion Union;
|
||||
char *CString = nullptr;
|
||||
ox::BString<32> String = "";
|
||||
uint32_t List[4] = {0, 0, 0, 0};
|
||||
ox::HashMap<ox::String, int> Map;
|
||||
TestStructNest EmptyStruct;
|
||||
TestStructNest Struct;
|
||||
|
||||
~TestStruct() {
|
||||
delete[] CString;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestUnion *obj) {
|
||||
io->template setTypeInfo<TestUnion>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", ox::SerStr(obj->String)));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStructNest *obj) {
|
||||
io->template setTypeInfo<TestStructNest>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStruct *obj) {
|
||||
io->template setTypeInfo<TestStruct>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("Int1", &obj->Int1));
|
||||
oxReturnError(io->field("Int2", &obj->Int2));
|
||||
oxReturnError(io->field("Int3", &obj->Int3));
|
||||
oxReturnError(io->field("Int4", &obj->Int4));
|
||||
oxReturnError(io->field("Int5", &obj->Int5));
|
||||
oxReturnError(io->field("Int6", &obj->Int6));
|
||||
oxReturnError(io->field("Int7", &obj->Int7));
|
||||
oxReturnError(io->field("Int8", &obj->Int8));
|
||||
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
|
||||
oxReturnError(io->field("CString", ox::SerStr(&obj->CString)));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
oxReturnError(io->field("List", obj->List, 4));
|
||||
oxReturnError(io->field("Map", &obj->Map));
|
||||
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
|
||||
oxReturnError(io->field("Struct", &obj->Struct));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
std::map<std::string, ox::Error(*)()> tests = {
|
||||
{
|
||||
{
|
||||
"MetalClawWriter",
|
||||
[] {
|
||||
// This test doesn't confirm much, but it does show that the writer
|
||||
// doesn't segfault
|
||||
constexpr size_t buffLen = 1024;
|
||||
uint8_t buff[buffLen];
|
||||
TestStruct ts;
|
||||
|
||||
oxReturnError(ox::writeMC(buff, buffLen, &ts));
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"MetalClawReader",
|
||||
[] {
|
||||
constexpr size_t buffLen = 1024;
|
||||
uint8_t buff[buffLen];
|
||||
TestStruct testIn, testOut;
|
||||
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.Union.Int = 42;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.CString = new char[ox_strlen("c-string") + 1];
|
||||
ox_strcpy(testIn.CString, "c-string");
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Map["asdf"] = 93;
|
||||
testIn.Map["aoeu"] = 94;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed");
|
||||
oxAssert(ox::readMC(buff, buffLen, &testOut), "readMC failed");
|
||||
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
|
||||
|
||||
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
|
||||
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
|
||||
oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch");
|
||||
oxAssert(testIn.Int2 == testOut.Int2, "Int2 value mismatch");
|
||||
oxAssert(testIn.Int3 == testOut.Int3, "Int3 value mismatch");
|
||||
oxAssert(testIn.Int4 == testOut.Int4, "Int4 value mismatch");
|
||||
oxAssert(testIn.Int5 == testOut.Int5, "Int5 value mismatch");
|
||||
oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch");
|
||||
oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch");
|
||||
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
|
||||
oxAssert(ox_strcmp(testIn.CString, testOut.CString) == 0, "CString value mismatch");
|
||||
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
|
||||
oxAssert(testIn.String == testOut.String, "String value mismatch");
|
||||
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
|
||||
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
|
||||
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
|
||||
oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch");
|
||||
oxAssert(testIn.Map["asdf"] == testOut.Map["asdf"], "Map[\"asdf\"] value mismatch");
|
||||
oxAssert(testIn.Map["aoeu"] == testOut.Map["aoeu"], "Map[\"aoeu\"] value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.String == testOut.EmptyStruct.String, "EmptyStruct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch");
|
||||
oxAssert(testIn.Struct.String == testOut.Struct.String, "Struct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch");
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"encodeInteger",
|
||||
[] {
|
||||
using ox::MaxValue;
|
||||
using ox::mc::McInt;
|
||||
using ox::mc::encodeInteger;
|
||||
|
||||
constexpr auto check = [](McInt val, std::vector<uint8_t> &&expected) {
|
||||
if (val.length != expected.size()) {
|
||||
std::cout << "val.length: " << val.length << ", expected: " << expected.size() << '\n';
|
||||
return OxError(1);
|
||||
}
|
||||
for (std::size_t i = 0; i < expected.size(); i++) {
|
||||
if (expected[i] != val.data[i]) {
|
||||
std::cout << i << ": " << static_cast<uint32_t>(val.data[i]) << '\n';
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
};
|
||||
constexpr auto check64 = [](McInt val, auto expected) {
|
||||
if (val.length != 9) {
|
||||
std::cout << "val.length: " << val.length << '\n';
|
||||
return OxError(1);
|
||||
}
|
||||
ox::LittleEndian<decltype(expected)> decoded = *reinterpret_cast<decltype(expected)*>(&val.data[1]);
|
||||
if (expected != decoded) {
|
||||
std::cout << "decoded: " << decoded << ", expected: " << expected << '\n';
|
||||
return OxError(1);
|
||||
}
|
||||
return OxError(0);
|
||||
};
|
||||
|
||||
oxAssert(check(encodeInteger(int64_t(1)), {0b00000010}), "Encode 1 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(2)), {0b00000100}), "Encode 2 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(3)), {0b00000110}), "Encode 3 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(4)), {0b00001000}), "Encode 4 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(128)), {0b00000001, 0b10}), "Encode 128 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(129)), {0b00000101, 0b10}), "Encode 129 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(130)), {0b00001001, 0b10}), "Encode 130 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(131)), {0b00001101, 0b10}), "Encode 131 fail");
|
||||
|
||||
oxAssert(check(encodeInteger(int64_t(-1)), {255, 255, 255, 255, 255, 255, 255, 255, 255}), "Encode -1 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-2)), {255, 254, 255, 255, 255, 255, 255, 255, 255}), "Encode -2 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-3)), {255, 253, 255, 255, 255, 255, 255, 255, 255}), "Encode -3 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-4)), {255, 252, 255, 255, 255, 255, 255, 255, 255}), "Encode -4 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-128)), {255, 128, 255, 255, 255, 255, 255, 255, 255}), "Encode -128 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-129)), {255, 127, 255, 255, 255, 255, 255, 255, 255}), "Encode -129 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-130)), {255, 126, 255, 255, 255, 255, 255, 255, 255}), "Encode -130 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-131)), {255, 125, 255, 255, 255, 255, 255, 255, 255}), "Encode -131 fail");
|
||||
|
||||
oxAssert(check(encodeInteger(uint32_t(0xffffffff)), {0b11101111, 255, 255, 255, 0b00011111}), "Encode 0xffffffff fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(1)), {0b0010}), "Encode 1 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(2)), {0b0100}), "Encode 2 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(3)), {0b0110}), "Encode 3 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(4)), {0b1000}), "Encode 4 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(128)), {0b0001, 0b10}), "Encode 128 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(129)), {0b0101, 0b10}), "Encode 129 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(130)), {0b1001, 0b10}), "Encode 130 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(131)), {0b1101, 0b10}), "Encode 131 fail");
|
||||
|
||||
// Signed check needs lambda templates to run correctly without
|
||||
// code deduplication
|
||||
//oxAssert(check64(encodeInteger(MaxValue<int64_t>), MaxValue<int64_t>), "Encode MaxValue<int64_t> fail");
|
||||
oxAssert(check64(encodeInteger(MaxValue<uint64_t>), MaxValue<uint64_t>), "Encode MaxValue<uint64_t> fail");
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"decodeInteger",
|
||||
[] {
|
||||
using ox::MaxValue;
|
||||
using ox::mc::McInt;
|
||||
using ox::mc::encodeInteger;
|
||||
using ox::mc::decodeInteger;
|
||||
|
||||
constexpr auto check = [](auto val) {
|
||||
auto result = decodeInteger<decltype(val)>(encodeInteger(val));
|
||||
oxReturnError(result.error);
|
||||
if (result.value != val) {
|
||||
std::cout << "Bad value: " << result.value << ", expected: " << val << '\n';
|
||||
return OxError(1);
|
||||
}
|
||||
return OxError(0);
|
||||
};
|
||||
oxAssert(check(uint32_t(14)), "Decode of 14 failed.");
|
||||
oxAssert(check(int64_t(-1)), "Decode of -1 failed.");
|
||||
oxAssert(check(int64_t(1)), "Decode of 1 failed.");
|
||||
oxAssert(check(int64_t(2)), "Decode of 2 failed.");
|
||||
oxAssert(check(int64_t(42)), "Decode of 42 failed.");
|
||||
oxAssert(check(int64_t(130)), "Decode of 130 failed.");
|
||||
oxAssert(check(int64_t(131)), "Decode of 131 failed.");
|
||||
oxAssert(check(uint64_t(1)), "Decode of 1 failed.");
|
||||
oxAssert(check(uint64_t(2)), "Decode of 2 failed.");
|
||||
oxAssert(check(uint64_t(42)), "Decode of 42 failed.");
|
||||
oxAssert(check(uint64_t(130)), "Decode of 130 failed.");
|
||||
oxAssert(check(uint64_t(131)), "Decode of 131 failed.");
|
||||
oxAssert(check(0xffffffff), "Decode of 0xffffffff failed.");
|
||||
oxAssert(check(0xffffffffffff), "Decode of 0xffffffffffff failed.");
|
||||
oxAssert(check(0xffffffffffffffff), "Decode of U64 max failed.");
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"MetalClawDef",
|
||||
[] {
|
||||
//constexpr size_t descBuffLen = 1024;
|
||||
//uint8_t descBuff[descBuffLen];
|
||||
constexpr size_t dataBuffLen = 1024;
|
||||
uint8_t dataBuff[dataBuffLen];
|
||||
TestStruct testIn, testOut;
|
||||
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed");
|
||||
auto type = ox::buildTypeDef(&testIn);
|
||||
oxAssert(type.error, "Descriptor write failed");
|
||||
ox::walkModel<ox::MetalClawReader>(type.value, dataBuff, dataBuffLen,
|
||||
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
|
||||
//std::cout << f.fieldName.c_str() << '\n';
|
||||
auto fieldName = f.fieldName.c_str();
|
||||
switch (f.type->primitiveType) {
|
||||
case ox::PrimitiveType::UnsignedInteger:
|
||||
std::cout << fieldName << ":\tuint" << f.type->length * 8 << "_t:\t";
|
||||
switch (f.type->length) {
|
||||
case 1: {
|
||||
uint8_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
uint16_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
uint32_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
uint64_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::cout << '\n';
|
||||
break;
|
||||
case ox::PrimitiveType::SignedInteger:
|
||||
std::cout << fieldName << ":\tint" << f.type->length * 8 << "_t:\t";
|
||||
switch (f.type->length) {
|
||||
case 1: {
|
||||
int8_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
int16_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int32_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
int64_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::cout << '\n';
|
||||
break;
|
||||
case ox::PrimitiveType::Bool: {
|
||||
bool i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << fieldName << ":\t" << "bool:\t\t" << (i ? "true" : "false") << '\n';
|
||||
break;
|
||||
}
|
||||
case ox::PrimitiveType::String: {
|
||||
ox::Vector<char> v(rdr->stringLength(fieldName) + 1);
|
||||
//std::cout << rdr->stringLength() << '\n';
|
||||
oxAssert(rdr->field(fieldName, ox::SerStr(v.data(), v.size())), "Walking model failed.");
|
||||
std::cout << fieldName << ":\t" << "string:\t\t" << v.data() << '\n';
|
||||
break;
|
||||
}
|
||||
case ox::PrimitiveType::Struct:
|
||||
break;
|
||||
case ox::PrimitiveType::Union:
|
||||
break;
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
);
|
||||
delete type.value;
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
int retval = -1;
|
||||
if (argc > 0) {
|
||||
auto testName = args[1];
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
retval = tests[testName]();
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
18
src/core/core.cpp → deps/ox/src/ox/mc/types.hpp
vendored
18
src/core/core.cpp → deps/ox/src/ox/mc/types.hpp
vendored
@ -1,20 +1,20 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/string.hpp>
|
||||
#include <ox/std/strops.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include "gfx.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace core {
|
||||
namespace ox {
|
||||
|
||||
ox::Error init() {
|
||||
auto err = initGfx();
|
||||
return err;
|
||||
}
|
||||
using StringLength = uint32_t;
|
||||
using ArrayLength = uint32_t;
|
||||
|
||||
}
|
||||
}
|
97
deps/ox/src/ox/mc/write.cpp
vendored
Normal file
97
deps/ox/src/ox/mc/write.cpp
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/assert.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
|
||||
#include "write.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept:
|
||||
m_fieldPresence(buff, buffLen),
|
||||
m_unionIdx(unionIdx),
|
||||
m_buffLen(buffLen),
|
||||
m_buff(buff) {
|
||||
}
|
||||
|
||||
MetalClawWriter::~MetalClawWriter() noexcept {
|
||||
if (m_field != m_fields) {
|
||||
oxTrace("ox::mc::MetalClawWriter::error") << "MetalClawReader: incorrect fields number given";
|
||||
}
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int8_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int16_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int32_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int64_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint8_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint16_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint32_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint64_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, bool *val) noexcept {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
oxReturnError(m_fieldPresence.set(m_field, *val));
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, SerStr val) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (val.len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
const auto strLen = mc::encodeInteger(val.len());
|
||||
if (m_buffIt + strLen.length + val.len() < m_buffLen) {
|
||||
ox_memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
|
||||
m_buffIt += strLen.length;
|
||||
// write the string
|
||||
ox_memcpy(&m_buff[m_buffIt], val.c_str(), val.len());
|
||||
m_buffIt += val.len();
|
||||
fieldSet = true;
|
||||
} else {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
}
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
std::size_t MetalClawWriter::size() noexcept {
|
||||
return m_buffIt;
|
||||
}
|
||||
|
||||
}
|
249
deps/ox/src/ox/mc/write.hpp
vendored
Normal file
249
deps/ox/src/ox/mc/write.hpp
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/model/optype.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
#include <ox/std/bit.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/units.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "intops.hpp"
|
||||
#include "err.hpp"
|
||||
#include "ox/std/hashmap.hpp"
|
||||
#include "presenceindicator.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
class MetalClawWriter {
|
||||
|
||||
private:
|
||||
FieldPresenceIndicator m_fieldPresence;
|
||||
int m_fields = 0;
|
||||
int m_field = 0;
|
||||
int m_unionIdx = -1;
|
||||
std::size_t m_buffIt = 0;
|
||||
std::size_t m_buffLen = 0;
|
||||
uint8_t *m_buff = nullptr;
|
||||
|
||||
public:
|
||||
MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept;
|
||||
|
||||
~MetalClawWriter() noexcept;
|
||||
|
||||
[[nodiscard]] Error field(const char*, int8_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, int16_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, int32_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, int64_t *val) noexcept;
|
||||
|
||||
[[nodiscard]] Error field(const char*, uint8_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, uint16_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, uint32_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, uint64_t *val) noexcept;
|
||||
|
||||
[[nodiscard]] Error field(const char*, bool *val) noexcept;
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, T *val, std::size_t len);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, Vector<T> *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, HashMap<String, T> *val);
|
||||
|
||||
template<std::size_t L>
|
||||
[[nodiscard]] Error field(const char*, ox::BString<L> *val) noexcept;
|
||||
|
||||
[[nodiscard]] Error field(const char*, SerStr val) noexcept;
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, T *val);
|
||||
|
||||
template<typename U>
|
||||
[[nodiscard]] Error field(const char*, UnionView<U> val);
|
||||
|
||||
template<typename T = std::nullptr_t>
|
||||
void setTypeInfo(const char *name = T::TypeName, int fields = T::Fields);
|
||||
|
||||
std::size_t size() noexcept;
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::Write;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename I>
|
||||
[[nodiscard]] Error appendInteger(I val) noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<std::size_t L>
|
||||
Error MetalClawWriter::field(const char *name, ox::BString<L> *val) noexcept {
|
||||
return field(name, SerStr(val->data(), val->cap()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawWriter::field(const char*, T *val) {
|
||||
bool fieldSet = false;
|
||||
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
|
||||
oxReturnError(model(&writer, val));
|
||||
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
|
||||
m_buffIt += writer.m_buffIt;
|
||||
fieldSet = true;
|
||||
}
|
||||
}
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Error MetalClawWriter::field(const char*, UnionView<U> val) {
|
||||
bool fieldSet = false;
|
||||
if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt, val.idx());
|
||||
oxReturnError(model(&writer, val.get()));
|
||||
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
|
||||
m_buffIt += writer.m_buffIt;
|
||||
fieldSet = true;
|
||||
}
|
||||
}
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawWriter::field(const char*, T *val, std::size_t len) {
|
||||
bool fieldSet = false;
|
||||
|
||||
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
const auto arrLen = mc::encodeInteger(len);
|
||||
if (m_buffIt + arrLen.length < m_buffLen) {
|
||||
ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length);
|
||||
m_buffIt += arrLen.length;
|
||||
} else {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
|
||||
writer.setTypeInfo<T>("List", len);
|
||||
|
||||
// write the array
|
||||
for (std::size_t i = 0; i < len; i++) {
|
||||
oxReturnError(writer.field("", &val[i]));
|
||||
}
|
||||
|
||||
m_buffIt += writer.m_buffIt;
|
||||
fieldSet = true;
|
||||
}
|
||||
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawWriter::field(const char*, Vector<T> *val) {
|
||||
return field(nullptr, val->data(), val->size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error MetalClawWriter::field(const char*, HashMap<String, T> *val) {
|
||||
auto &keys = val->keys();
|
||||
auto len = keys.size();
|
||||
bool fieldSet = false;
|
||||
|
||||
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
const auto arrLen = mc::encodeInteger(len);
|
||||
if (m_buffIt + arrLen.length < m_buffLen) {
|
||||
ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length);
|
||||
m_buffIt += arrLen.length;
|
||||
} else {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
|
||||
// double len for both key and value
|
||||
writer.setTypeInfo("Map", len * 2);
|
||||
|
||||
// write the array
|
||||
for (std::size_t i = 0; i < len; i++) {
|
||||
auto &key = keys[i];
|
||||
const auto keyLen = ox_strlen(key);
|
||||
auto wkey = static_cast<char*>(ox_alloca(keyLen + 1));
|
||||
memcpy(wkey, key.c_str(), keyLen + 1);
|
||||
oxReturnError(writer.field("", SerStr(&wkey, keyLen)));
|
||||
oxReturnError(writer.field("", &(*val)[key]));
|
||||
}
|
||||
|
||||
m_buffIt += writer.m_buffIt;
|
||||
fieldSet = true;
|
||||
}
|
||||
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
Error MetalClawWriter::appendInteger(I val) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
auto mi = mc::encodeInteger(val);
|
||||
if (mi.length < m_buffLen) {
|
||||
fieldSet = true;
|
||||
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
|
||||
m_buffIt += mi.length;
|
||||
} else {
|
||||
oxReturnError(OxError(MC_BUFFENDED));
|
||||
}
|
||||
}
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return OxError(0);
|
||||
;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void MetalClawWriter::setTypeInfo(const char*, int fields) {
|
||||
m_fields = fields;
|
||||
m_fieldPresence.setFields(fields);
|
||||
m_buffIt = m_fieldPresence.getMaxLen();
|
||||
ox_memset(m_buff, 0, m_buffIt);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValErr<Vector<char>> writeMC(T *val) {
|
||||
Vector<char> buff(10 * units::MB);
|
||||
MetalClawWriter writer(bit_cast<uint8_t*>(buff.data()), buff.size());
|
||||
oxReturnError(model(&writer, val));
|
||||
buff.resize(writer.size());
|
||||
return buff;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error writeMC(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) {
|
||||
MetalClawWriter writer(buff, buffLen);
|
||||
auto err = model(&writer, val);
|
||||
if (sizeOut) {
|
||||
*sizeOut = writer.size();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
37
deps/ox/src/ox/model/CMakeLists.txt
vendored
Normal file
37
deps/ox/src/ox/model/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
add_library(
|
||||
OxModel
|
||||
desctypes.cpp
|
||||
descwrite.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
OxModel PUBLIC
|
||||
OxStd
|
||||
)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
set_property(
|
||||
TARGET
|
||||
OxModel
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES
|
||||
descread.hpp
|
||||
desctypes.hpp
|
||||
descwrite.hpp
|
||||
optype.hpp
|
||||
model.hpp
|
||||
types.hpp
|
||||
walk.hpp
|
||||
DESTINATION
|
||||
include/ox/model
|
||||
)
|
||||
|
||||
install(TARGETS OxModel
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
7
deps/ox/src/ox/model/definition-language.txt
vendored
Normal file
7
deps/ox/src/ox/model/definition-language.txt
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<Type> : <TypeName><FieldList>
|
||||
<FieldList> : <FieldList> | <FieldList><Field>
|
||||
<Field> : <FieldType><TypeID><FieldName>
|
||||
<TypeID> : <TypeName> | <TypeName><Type>
|
||||
<TypeName> : <string>
|
||||
<FieldType> : <0: single> | <1: list>
|
||||
<FieldName> : <string>
|
42
deps/ox/src/ox/model/descread.hpp
vendored
Normal file
42
deps/ox/src/ox/model/descread.hpp
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "desctypes.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename ReaderBase>
|
||||
class TypeDescReader: public ReaderBase {
|
||||
private:
|
||||
TypeStore m_typeStore;
|
||||
|
||||
public:
|
||||
TypeDescReader(uint8_t *buff, std::size_t buffLen);
|
||||
|
||||
const TypeStore &typeStore() const;
|
||||
|
||||
};
|
||||
|
||||
template<typename ReaderBase>
|
||||
TypeDescReader<ReaderBase>::TypeDescReader(uint8_t *buff, std::size_t buffLen): ReaderBase(buff, buffLen) {
|
||||
}
|
||||
|
||||
template<typename ReaderBase>
|
||||
const TypeStore &TypeDescReader<ReaderBase>::typeStore() const {
|
||||
return m_typeStore;
|
||||
}
|
||||
|
||||
template<typename ReaderBase, typename T>
|
||||
int readMCDef(uint8_t *buff, std::size_t buffLen, T *val) {
|
||||
TypeDescReader<ReaderBase> reader(buff, buffLen);
|
||||
return model(&reader, val);
|
||||
}
|
||||
|
||||
}
|
19
deps/ox/src/ox/model/desctypes.cpp
vendored
Normal file
19
deps/ox/src/ox/model/desctypes.cpp
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "desctypes.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
DescriptorField::~DescriptorField() {
|
||||
if (ownsType) {
|
||||
delete type;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
184
deps/ox/src/ox/model/desctypes.hpp
vendored
Normal file
184
deps/ox/src/ox/model/desctypes.hpp
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/bit.hpp>
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/bstring.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
using ModelString = BString<100>;
|
||||
using FieldName = ModelString;
|
||||
using TypeName = ModelString;
|
||||
|
||||
enum class PrimitiveType: uint8_t {
|
||||
UnsignedInteger = 0,
|
||||
SignedInteger = 1,
|
||||
Bool = 2,
|
||||
// Float = 3, reserved, but not implemented
|
||||
String = 4,
|
||||
Struct = 5,
|
||||
Union = 6,
|
||||
};
|
||||
|
||||
struct DescriptorField {
|
||||
// order of fields matters
|
||||
|
||||
static constexpr auto TypeVersion = 1;
|
||||
|
||||
// only serialize type name if type has already been serialized
|
||||
struct DescriptorType *type = nullptr;
|
||||
FieldName fieldName;
|
||||
int subscriptLevels = 0;
|
||||
|
||||
// do not serialize the following
|
||||
TypeName typeName; // gives reference to type for lookup if type is null
|
||||
bool ownsType = false;
|
||||
|
||||
constexpr DescriptorField() noexcept = default;
|
||||
|
||||
/**
|
||||
* Allow for explicit copying.
|
||||
*/
|
||||
constexpr explicit DescriptorField(const DescriptorField &other) noexcept {
|
||||
type = other.type;
|
||||
fieldName = other.fieldName;
|
||||
subscriptLevels = other.subscriptLevels;
|
||||
typeName = other.typeName;
|
||||
ownsType = false; // is copy, only owns type if move
|
||||
}
|
||||
|
||||
constexpr DescriptorField(DescriptorType *type, const FieldName &fieldName, int subscriptLevels, const TypeName &typeName, bool ownsType) noexcept {
|
||||
this->type = type;
|
||||
this->fieldName = fieldName;
|
||||
this->subscriptLevels = subscriptLevels;
|
||||
this->typeName = typeName;
|
||||
this->ownsType = ownsType;
|
||||
}
|
||||
|
||||
constexpr DescriptorField(DescriptorField &&other) noexcept {
|
||||
type = other.type;
|
||||
fieldName = other.fieldName;
|
||||
subscriptLevels = other.subscriptLevels;
|
||||
typeName = other.typeName;
|
||||
ownsType = other.ownsType;
|
||||
|
||||
other.type = {};
|
||||
other.fieldName = "";
|
||||
other.subscriptLevels = {};
|
||||
other.typeName = "";
|
||||
other.ownsType = {};
|
||||
}
|
||||
|
||||
~DescriptorField();
|
||||
|
||||
const DescriptorField &operator=(DescriptorField &&other) noexcept {
|
||||
type = other.type;
|
||||
fieldName = other.fieldName;
|
||||
subscriptLevels = other.subscriptLevels;
|
||||
typeName = other.typeName;
|
||||
ownsType = other.ownsType;
|
||||
|
||||
other.type = {};
|
||||
other.fieldName = "";
|
||||
other.subscriptLevels = {};
|
||||
other.typeName = "";
|
||||
other.ownsType = {};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using FieldList = Vector<DescriptorField>;
|
||||
|
||||
struct DescriptorType {
|
||||
static constexpr auto TypeVersion = 1;
|
||||
TypeName typeName;
|
||||
PrimitiveType primitiveType;
|
||||
// fieldList only applies to structs
|
||||
FieldList fieldList;
|
||||
// - number of bytes for integer and float types
|
||||
// - number of fields for structs and lists
|
||||
int64_t length = 0;
|
||||
bool preloadable = false;
|
||||
|
||||
DescriptorType() = default;
|
||||
|
||||
DescriptorType(TypeName tn, PrimitiveType t, int b): typeName(tn), primitiveType(t), length(b) {
|
||||
}
|
||||
|
||||
DescriptorType(TypeName tn, PrimitiveType t, FieldList fl): typeName(tn), primitiveType(t), fieldList(fl) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
Error model(T *io, DescriptorType *type) {
|
||||
io->template setTypeInfo<T>("net.drinkingtea.ox.DescriptorType", 5);
|
||||
oxReturnError(io->field("typeName", &type->typeName));
|
||||
oxReturnError(io->field("primitiveType", bit_cast<uint8_t*>(&type->primitiveType)));
|
||||
oxReturnError(io->field("fieldList", &type->fieldList));
|
||||
oxReturnError(io->field("length", &type->length));
|
||||
oxReturnError(io->field("preloadable", &type->preloadable));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error modelWrite(T *io, DescriptorField *field) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("ox::DescriptorField", 4);
|
||||
if (field->ownsType) {
|
||||
BString<2> empty = "";
|
||||
oxReturnError(io->field("typeName", SerStr(&empty)));
|
||||
oxReturnError(io->field("type", field->type));
|
||||
} else {
|
||||
oxReturnError(io->field("typeName", SerStr(&field->type->typeName)));
|
||||
oxReturnError(io->field("type", static_cast<decltype(field->type)>(nullptr)));
|
||||
}
|
||||
oxReturnError(io->field("fieldName", &field->fieldName));
|
||||
// defaultValue is unused now, but leave placeholder for backwards compatibility
|
||||
int DefaultValue = 0;
|
||||
oxReturnError(io->field("defaultValue", &DefaultValue));
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error modelRead(T *io, DescriptorField *field) {
|
||||
auto err = OxError(0);
|
||||
auto &typeStore = io->typeStore();
|
||||
io->setTypeInfo("ox::DescriptorField", 4);
|
||||
err |= io->field("typeName", &field->typeName);
|
||||
if (field->typeName == "") {
|
||||
field->ownsType = true;
|
||||
if (field->type == nullptr) {
|
||||
field->type = new DescriptorType;
|
||||
}
|
||||
err |= io->field("type", field->type);
|
||||
typeStore[field->type->typeName] = field->type;
|
||||
} else {
|
||||
// should be empty, so discard
|
||||
DescriptorType t;
|
||||
err |= io->field("type", &t);
|
||||
field->type = typeStore[field->typeName];
|
||||
}
|
||||
err |= io->field("fieldName", &field->fieldName);
|
||||
// defaultValue is unused now, but placeholder for backwards compatibility
|
||||
err |= io->field("defaultValue", nullptr);
|
||||
return err;
|
||||
}
|
||||
|
||||
using TypeStore = ox::HashMap<ModelString, DescriptorType*>;
|
||||
|
||||
}
|
163
deps/ox/src/ox/model/descwrite.cpp
vendored
Normal file
163
deps/ox/src/ox/model/descwrite.cpp
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2015 - 2019 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/typeinfo.hpp>
|
||||
|
||||
#include "descwrite.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct preloadable_type {
|
||||
static constexpr auto Preloadable = true;
|
||||
};
|
||||
|
||||
struct non_preloadable_type {
|
||||
static constexpr auto Preloadable = false;
|
||||
};
|
||||
|
||||
struct non_preloadable_type2 {
|
||||
};
|
||||
|
||||
static_assert(preloadable<preloadable_type>::value);
|
||||
static_assert(!preloadable<non_preloadable_type>::value);
|
||||
static_assert(!preloadable<non_preloadable_type2>::value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static_assert([] {
|
||||
int i = 0;
|
||||
return indirectionLevels(i) == 0;
|
||||
}(), "indirectionLevels broken: indirectionLevels(int)");
|
||||
|
||||
static_assert([] {
|
||||
int i = 0;
|
||||
return indirectionLevels(&i) == 1;
|
||||
}(), "indirectionLevels broken: indirectionLevels(int*)");
|
||||
|
||||
static_assert([] {
|
||||
int i[2] = {};
|
||||
return indirectionLevels(i) == 1;
|
||||
}(), "indirectionLevels broken: indirectionLevels(int[])");
|
||||
|
||||
TypeDescWriter::TypeDescWriter(TypeStore *typeStore) {
|
||||
if (!typeStore) {
|
||||
m_typeStoreOwnerRef = new TypeStore;
|
||||
typeStore = m_typeStoreOwnerRef;
|
||||
}
|
||||
m_typeStore = typeStore;
|
||||
}
|
||||
|
||||
TypeDescWriter::~TypeDescWriter() {
|
||||
// does not own it's elements
|
||||
delete m_typeStoreOwnerRef;
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(int8_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:int8_t";
|
||||
constexpr auto PT = PrimitiveType::SignedInteger;
|
||||
constexpr auto Bytes = 1;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(int16_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:int16_t";
|
||||
constexpr auto PT = PrimitiveType::SignedInteger;
|
||||
constexpr auto Bytes = 2;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(int32_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:int32_t";
|
||||
constexpr auto PT = PrimitiveType::SignedInteger;
|
||||
constexpr auto Bytes = 4;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(int64_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:int64_t";
|
||||
constexpr auto PT = PrimitiveType::SignedInteger;
|
||||
constexpr auto Bytes = 8;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(uint8_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:uint8_t";
|
||||
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
||||
constexpr auto Bytes = 1;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(uint16_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:uint16_t";
|
||||
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
||||
constexpr auto Bytes = 2;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(uint32_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:uint32_t";
|
||||
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
||||
constexpr auto Bytes = 4;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(uint64_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:uint64_t";
|
||||
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
||||
constexpr auto Bytes = 8;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(char*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:string";
|
||||
constexpr auto PT = PrimitiveType::String;
|
||||
return getType(TypeName, PT, 0, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(SerStr, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:string";
|
||||
constexpr auto PT = PrimitiveType::String;
|
||||
return getType(TypeName, PT, 0, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(String*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:string";
|
||||
constexpr auto PT = PrimitiveType::String;
|
||||
return getType(TypeName, PT, 0, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(bool*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:bool";
|
||||
constexpr auto PT = PrimitiveType::Bool;
|
||||
constexpr auto Bytes = 0;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::getType(TypeName tn, PrimitiveType pt, int b, bool *alreadyExisted) {
|
||||
if (m_typeStore->contains(tn)) {
|
||||
*alreadyExisted = true;
|
||||
auto type = m_typeStore->at(tn);
|
||||
oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType");
|
||||
return type;
|
||||
} else {
|
||||
*alreadyExisted = false;
|
||||
auto &t = m_typeStore->at(tn);
|
||||
if (!t) {
|
||||
t = new DescriptorType;
|
||||
}
|
||||
t->typeName = tn;
|
||||
t->primitiveType = pt;
|
||||
t->length = b;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
254
deps/ox/src/ox/model/descwrite.hpp
vendored
Normal file
254
deps/ox/src/ox/model/descwrite.hpp
vendored
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright 2015 - 2019 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/byteswap.hpp>
|
||||
#include <ox/std/bstring.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "desctypes.hpp"
|
||||
#include "optype.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<bool>
|
||||
struct BoolWrapper {
|
||||
};
|
||||
|
||||
template<typename T, typename = BoolWrapper<true>>
|
||||
struct preloadable: false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct preloadable<T, BoolWrapper<T::Preloadable>> {
|
||||
static constexpr bool value = T::Preloadable;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static constexpr int indirectionLevels(T) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static constexpr int indirectionLevels(T *t) {
|
||||
return 1 + indirectionLevels(*t);
|
||||
}
|
||||
|
||||
class TypeDescWriter {
|
||||
|
||||
private:
|
||||
struct NameCatcher {
|
||||
|
||||
TypeName name;
|
||||
|
||||
template<typename T = std::nullptr_t>
|
||||
constexpr void setTypeInfo(const char *n = T::TypeName, int = T::Fields) noexcept {
|
||||
this->name = n;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr ox::Error field(const char*, T*, std::size_t) noexcept {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr ox::Error field(const char*, T) noexcept {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::WriteDefinition;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TypeStore *m_typeStoreOwnerRef = nullptr;
|
||||
TypeStore *m_typeStore = nullptr;
|
||||
DescriptorType *m_type = nullptr;
|
||||
|
||||
public:
|
||||
explicit TypeDescWriter(TypeStore *typeStore = nullptr);
|
||||
|
||||
~TypeDescWriter();
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] ox::Error field(const char *name, T *val, std::size_t valLen);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] ox::Error field(const char *name, T val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] ox::Error field(const char *name, T *val);
|
||||
|
||||
template<typename T = std::nullptr_t>
|
||||
void setTypeInfo(const char *name = T::TypeName, int fields = T::Fields);
|
||||
|
||||
[[nodiscard]] DescriptorType *definition() noexcept {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::WriteDefinition;
|
||||
}
|
||||
|
||||
private:
|
||||
DescriptorType *type(int8_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(int16_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(int32_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(int64_t *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(uint8_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(uint16_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(uint32_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(uint64_t *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(bool *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(char *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(SerStr val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(String *val, bool *alreadyExisted);
|
||||
|
||||
template<std::size_t sz>
|
||||
DescriptorType *type(BString<sz> *val, bool *alreadyExisted);
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *type(T *val, bool *alreadyExisted);
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *type(Vector<T> *val, bool *alreadyExisted);
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *type(HashMap<String, T> *val, bool *alreadyExisted);
|
||||
|
||||
template<typename U>
|
||||
DescriptorType *type(UnionView<U> val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *getType(TypeName tn, PrimitiveType t, int b, bool *alreadyExisted);
|
||||
};
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
ox::Error TypeDescWriter::field(const char *name, T *val, std::size_t) {
|
||||
if (m_type) {
|
||||
constexpr typename ox::remove_pointer<decltype(val)>::type *p = nullptr;
|
||||
bool alreadyExisted = false;
|
||||
const auto t = type(p, &alreadyExisted);
|
||||
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
|
||||
if (t == nullptr) {
|
||||
type(p, &alreadyExisted);
|
||||
}
|
||||
m_type->fieldList.emplace_back(t, name, indirectionLevels(val), alreadyExisted ? t->typeName : "", !alreadyExisted);
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error TypeDescWriter::field(const char *name, T val) {
|
||||
if (m_type) {
|
||||
bool alreadyExisted = false;
|
||||
const auto t = type(val, &alreadyExisted);
|
||||
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
|
||||
m_type->fieldList.emplace_back(t, name, 0, alreadyExisted ? t->typeName : "", !alreadyExisted);
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error TypeDescWriter::field(const char *name, T *val) {
|
||||
if (m_type) {
|
||||
bool alreadyExisted = false;
|
||||
const auto t = type(val, &alreadyExisted);
|
||||
oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated");
|
||||
m_type->fieldList.emplace_back(t, name, 0, alreadyExisted ? t->typeName : "", !alreadyExisted);
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<std::size_t sz>
|
||||
DescriptorType *TypeDescWriter::type(BString<sz> *val, bool *alreadyExisted) {
|
||||
return type(SerStr(val), alreadyExisted);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *TypeDescWriter::type(T *val, bool *alreadyExisted) {
|
||||
NameCatcher nc;
|
||||
oxLogError(model(&nc, val));
|
||||
if (m_typeStore->contains(nc.name)) {
|
||||
*alreadyExisted = true;
|
||||
return m_typeStore->at(nc.name);
|
||||
} else {
|
||||
TypeDescWriter dw(m_typeStore);
|
||||
oxLogError(model(&dw, val));
|
||||
*alreadyExisted = false;
|
||||
return dw.m_type;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *TypeDescWriter::type(Vector<T> *val, bool *alreadyExisted) {
|
||||
return type(val->data(), alreadyExisted);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *TypeDescWriter::type(HashMap<String, T>*, bool *alreadyExisted) {
|
||||
return type(static_cast<T*>(nullptr), alreadyExisted);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
DescriptorType *TypeDescWriter::type(UnionView<U> val, bool *alreadyExisted) {
|
||||
return type(val.get(), alreadyExisted);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void TypeDescWriter::setTypeInfo(const char *name, int) {
|
||||
auto &t = m_typeStore->at(name);
|
||||
if (!t) {
|
||||
t = new DescriptorType;
|
||||
}
|
||||
m_type = t;
|
||||
m_type->typeName = name;
|
||||
if (is_union_v<T>) {
|
||||
m_type->primitiveType = PrimitiveType::Union;
|
||||
} else {
|
||||
m_type->primitiveType = PrimitiveType::Struct;
|
||||
}
|
||||
m_type->preloadable = detail::preloadable<T>::value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] ValErr<DescriptorType*> buildTypeDef(T *val) {
|
||||
TypeDescWriter writer;
|
||||
Error err = model(&writer, val);
|
||||
return {writer.definition(), err};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error writeTypeDef(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) {
|
||||
auto def = buildTypeDef(val);
|
||||
auto err = def.error;
|
||||
if (!err) {
|
||||
oxReturnError(writeType(buff, buffLen, def.value, sizeOut));
|
||||
}
|
||||
delete def.value;
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
15
deps/ox/src/ox/model/model.hpp
vendored
Normal file
15
deps/ox/src/ox/model/model.hpp
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2015 - 2019 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "descread.hpp"
|
||||
#include "desctypes.hpp"
|
||||
#include "descwrite.hpp"
|
||||
#include "types.hpp"
|
||||
#include "walk.hpp"
|
54
deps/ox/src/ox/model/optype.hpp
vendored
Normal file
54
deps/ox/src/ox/model/optype.hpp
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/assert.hpp>
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/strops.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace OpType {
|
||||
constexpr auto Read = "Read";
|
||||
constexpr auto Write = "Write";
|
||||
constexpr auto WriteDefinition = "WriteDefinition";
|
||||
}
|
||||
|
||||
// empty default implementations of model functions
|
||||
|
||||
template<typename T, typename O>
|
||||
[[nodiscard]] ox::Error modelRead(T*, O*) {
|
||||
return OxError(1, "Model: modelRead not implemented");
|
||||
}
|
||||
|
||||
template<typename T, typename O>
|
||||
[[nodiscard]] ox::Error modelWrite(T*, O*) {
|
||||
return OxError(1, "Model: modelWrite not implemented");
|
||||
}
|
||||
|
||||
template<typename T, typename O>
|
||||
[[nodiscard]] ox::Error modelWriteDefinition(T*, O*) {
|
||||
return OxError(1, "Model: modelWriteDefinition not implemented");
|
||||
}
|
||||
|
||||
template<typename T, typename O>
|
||||
[[nodiscard]] ox::Error model(T *io, O *obj) {
|
||||
ox::Error err;
|
||||
if constexpr(ox_strcmp(T::opType(), ox::OpType::Read) == 0) {
|
||||
err = modelRead(io, obj);
|
||||
} else if constexpr(ox_strcmp(T::opType(), ox::OpType::Write) == 0) {
|
||||
err = modelWrite(io, obj);
|
||||
} else if constexpr(ox_strcmp(T::opType(), ox::OpType::WriteDefinition) == 0) {
|
||||
err = modelWriteDefinition(io, obj);
|
||||
}
|
||||
oxAssert(err, "Missing model function");
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
93
deps/ox/src/ox/model/types.hpp
vendored
Normal file
93
deps/ox/src/ox/model/types.hpp
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/bstring.hpp>
|
||||
#include <ox/std/strops.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/typetraits.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
class SerStr {
|
||||
|
||||
protected:
|
||||
int m_cap = 0;
|
||||
char *m_str = nullptr;
|
||||
char **m_tgt = nullptr;
|
||||
|
||||
public:
|
||||
template<std::size_t sz>
|
||||
constexpr SerStr(BString<sz> *str) noexcept {
|
||||
m_str = str->data();
|
||||
m_cap = str->cap();
|
||||
}
|
||||
|
||||
constexpr SerStr(char *str, int cap) noexcept {
|
||||
m_str = str;
|
||||
m_cap = cap;
|
||||
}
|
||||
|
||||
constexpr SerStr(char **tgt, int cap = -1) noexcept {
|
||||
m_tgt = tgt;
|
||||
m_str = const_cast<char*>(*tgt);
|
||||
m_cap = cap;
|
||||
}
|
||||
|
||||
template<std::size_t cap>
|
||||
constexpr SerStr(char (&str)[cap]) noexcept {
|
||||
m_str = str;
|
||||
m_cap = cap;
|
||||
}
|
||||
|
||||
constexpr const char *c_str() noexcept {
|
||||
return m_str;
|
||||
}
|
||||
|
||||
constexpr char *data(std::size_t sz = 0) noexcept {
|
||||
if (m_tgt && sz) {
|
||||
*m_tgt = new char[sz];
|
||||
m_str = *m_tgt;
|
||||
m_cap = sz;
|
||||
}
|
||||
return m_str;
|
||||
}
|
||||
|
||||
constexpr int len() noexcept {
|
||||
return m_str ? ox_strlen(m_str) : 0;
|
||||
}
|
||||
|
||||
constexpr int cap() noexcept {
|
||||
return m_cap;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename Union>
|
||||
class UnionView {
|
||||
|
||||
protected:
|
||||
int m_idx = -1;
|
||||
typename enable_if<is_union_v<Union>, Union>::type *m_union = nullptr;
|
||||
|
||||
public:
|
||||
constexpr explicit UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) {
|
||||
}
|
||||
|
||||
constexpr auto idx() noexcept {
|
||||
return m_idx;
|
||||
}
|
||||
|
||||
constexpr Union *get() noexcept {
|
||||
return m_union;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
155
deps/ox/src/ox/model/walk.hpp
vendored
Normal file
155
deps/ox/src/ox/model/walk.hpp
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/error.hpp>
|
||||
|
||||
#include "desctypes.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename Reader, typename T>
|
||||
class DataWalker {
|
||||
template<typename ReaderBase, typename FH>
|
||||
friend ox::Error parseField(const DescriptorField &field, ReaderBase *rdr, DataWalker<ReaderBase, FH> *walker);
|
||||
|
||||
private:
|
||||
Vector<const DescriptorType*> m_typeStack;
|
||||
T m_fieldHandler;
|
||||
Vector<FieldName> m_path;
|
||||
Vector<TypeName> m_typePath;
|
||||
|
||||
public:
|
||||
DataWalker(DescriptorType *type, T fieldHandler);
|
||||
|
||||
[[nodiscard]] const DescriptorType *type() const noexcept;
|
||||
|
||||
[[nodiscard]] ox::Error read(const DescriptorField&, Reader *rdr);
|
||||
|
||||
protected:
|
||||
void pushNamePath(FieldName fn);
|
||||
|
||||
void popNamePath();
|
||||
|
||||
void pushType(const DescriptorType *type);
|
||||
|
||||
void popType();
|
||||
|
||||
};
|
||||
|
||||
template<typename Reader, typename T>
|
||||
DataWalker<Reader, T>::DataWalker(DescriptorType *type, T fieldHandler): m_fieldHandler(fieldHandler) {
|
||||
m_typeStack.push_back(type);
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
const DescriptorType *DataWalker<Reader, T>::type() const noexcept {
|
||||
return m_typeStack.back();
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
ox::Error DataWalker<Reader, T>::read(const DescriptorField &f, Reader *rdr) {
|
||||
// get const ref of paths
|
||||
const auto &pathCr = m_path;
|
||||
const auto &typePathCr = m_typePath;
|
||||
return m_fieldHandler(pathCr, typePathCr, f, rdr);
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void DataWalker<Reader, T>::pushNamePath(FieldName fn) {
|
||||
m_path.push_back(fn);
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void DataWalker<Reader, T>::popNamePath() {
|
||||
m_path.pop_back();
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void DataWalker<Reader, T>::pushType(const DescriptorType *type) {
|
||||
m_typeStack.push_back(type);
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void DataWalker<Reader, T>::popType() {
|
||||
m_typeStack.pop_back();
|
||||
}
|
||||
|
||||
template<typename Reader, typename FH>
|
||||
static ox::Error parseField(const DescriptorField &field, Reader *rdr, DataWalker<Reader, FH> *walker) {
|
||||
walker->pushNamePath(field.fieldName);
|
||||
if (field.subscriptLevels) {
|
||||
// add array handling
|
||||
const auto [arrayLen, err] = rdr->arrayLength(field.fieldName.c_str(), true);
|
||||
oxReturnError(err);
|
||||
auto child = rdr->child(field.fieldName.c_str());
|
||||
child.setTypeInfo(field.fieldName.c_str(), arrayLen);
|
||||
DescriptorField f(field); // create mutable copy
|
||||
--f.subscriptLevels;
|
||||
BString<100> subscript;
|
||||
for (std::size_t i = 0; i < arrayLen; i++) {
|
||||
subscript = "[";
|
||||
subscript += i;
|
||||
subscript += "]";
|
||||
walker->pushNamePath(subscript);
|
||||
oxReturnError(parseField(f, &child, walker));
|
||||
walker->popNamePath();
|
||||
}
|
||||
rdr->nextField();
|
||||
} else {
|
||||
switch (field.type->primitiveType) {
|
||||
case PrimitiveType::UnsignedInteger:
|
||||
case PrimitiveType::SignedInteger:
|
||||
case PrimitiveType::Bool:
|
||||
case PrimitiveType::String:
|
||||
oxReturnError(walker->read(field, rdr));
|
||||
break;
|
||||
case PrimitiveType::Struct:
|
||||
case PrimitiveType::Union:
|
||||
if (rdr->fieldPresent(field.fieldName.c_str())) {
|
||||
auto child = rdr->child(field.fieldName.c_str());
|
||||
walker->pushType(field.type);
|
||||
oxReturnError(model(&child, walker));
|
||||
walker->popType();
|
||||
rdr->nextField();
|
||||
} else {
|
||||
// skip and discard absent field
|
||||
int discard;
|
||||
oxReturnError(rdr->field(field.fieldName.c_str(), &discard));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
walker->popNamePath();
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename Reader, typename FH>
|
||||
ox::Error model(Reader *rdr, DataWalker<Reader, FH> *walker) {
|
||||
auto type = walker->type();
|
||||
if (!type) {
|
||||
return OxError(1);
|
||||
}
|
||||
auto typeName = type->typeName.c_str();
|
||||
auto &fields = type->fieldList;
|
||||
rdr->setTypeInfo(typeName, fields.size());
|
||||
for (std::size_t i = 0; i < fields.size(); i++) {
|
||||
oxReturnError(parseField(fields[i], rdr, walker));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename Reader, typename Handler>
|
||||
ox::Error walkModel(DescriptorType *type, uint8_t *data, std::size_t dataLen, Handler handler) {
|
||||
DataWalker<Reader, Handler> walker(type, handler);
|
||||
Reader rdr(data, dataLen);
|
||||
return model(&rdr, &walker);
|
||||
}
|
||||
|
||||
}
|
40
deps/ox/src/ox/oc/CMakeLists.txt
vendored
Normal file
40
deps/ox/src/ox/oc/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
add_library(
|
||||
OxOrganicClaw
|
||||
read.cpp
|
||||
write.cpp
|
||||
)
|
||||
|
||||
find_package(JsonCpp REQUIRED)
|
||||
|
||||
target_compile_options(OxOrganicClaw PRIVATE -Wsign-conversion)
|
||||
|
||||
target_link_libraries(
|
||||
OxOrganicClaw PUBLIC
|
||||
OxModel
|
||||
JsonCpp::JsonCpp
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
OxOrganicClaw
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
oc.hpp
|
||||
read.hpp
|
||||
write.hpp
|
||||
DESTINATION
|
||||
include/ox/oc
|
||||
)
|
||||
|
||||
install(TARGETS OxOrganicClaw
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS STREQUAL "ON")
|
||||
add_subdirectory(test)
|
||||
endif()
|
12
deps/ox/src/ox/oc/oc.hpp
vendored
Normal file
12
deps/ox/src/ox/oc/oc.hpp
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "read.hpp"
|
||||
#include "write.hpp"
|
255
deps/ox/src/ox/oc/read.cpp
vendored
Normal file
255
deps/ox/src/ox/oc/read.cpp
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 2015 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/bit.hpp>
|
||||
|
||||
#include "read.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
OrganicClawReader::OrganicClawReader(const uint8_t *buff, std::size_t buffSize) {
|
||||
auto json = bit_cast<const char*>(buff);
|
||||
auto jsonLen = ox_strnlen(json, buffSize);
|
||||
Json::CharReaderBuilder parserBuilder;
|
||||
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
|
||||
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
|
||||
throw OxError(1, "Could not parse JSON");
|
||||
}
|
||||
}
|
||||
|
||||
OrganicClawReader::OrganicClawReader(const char *json, std::size_t jsonLen) {
|
||||
Json::CharReaderBuilder parserBuilder;
|
||||
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
|
||||
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
|
||||
throw OxError(1, "Could not parse JSON");
|
||||
}
|
||||
}
|
||||
|
||||
OrganicClawReader::OrganicClawReader(const Json::Value &json, int unionIdx):
|
||||
m_json(json),
|
||||
m_unionIdx(unionIdx) {
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, int8_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isInt()) {
|
||||
*val = static_cast<int8_t>(jv.asInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, int16_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isInt()) {
|
||||
*val = static_cast<int16_t>(jv.asInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, int32_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isInt()) {
|
||||
*val = static_cast<int32_t>(jv.asInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, int64_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isInt() || jv.isInt64()) {
|
||||
*val = static_cast<int64_t>(jv.asInt64());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
Error OrganicClawReader::field(const char *key, uint8_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isUInt()) {
|
||||
*val = static_cast<uint8_t>(jv.asUInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, uint16_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isUInt()) {
|
||||
*val = static_cast<uint16_t>(jv.asUInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, uint32_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isUInt()) {
|
||||
*val = static_cast<uint32_t>(jv.asUInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, uint64_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isUInt() || jv.isUInt64()) {
|
||||
*val = static_cast<uint64_t>(jv.asUInt64());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, bool *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = false;
|
||||
} else if (jv.isBool()) {
|
||||
*val = jv.asBool();
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, SerStr val) {
|
||||
auto err = OxError(0);
|
||||
const char *begin = nullptr, *end = nullptr;
|
||||
const auto &jv = value(key);
|
||||
if (targetValid()) {
|
||||
if (jv.empty()) {
|
||||
auto data = val.data();
|
||||
if (data) {
|
||||
data[0] = 0;
|
||||
}
|
||||
} else if (jv.isString()) {
|
||||
jv.getString(&begin, &end);
|
||||
auto strSize = end - begin;
|
||||
auto data = val.data(static_cast<std::size_t>(strSize) + 1);
|
||||
if (strSize >= val.cap()) {
|
||||
err = OxError(1, "String size exceeds capacity of destination");
|
||||
} else {
|
||||
ox_memcpy(data, begin, static_cast<std::size_t>(strSize));
|
||||
data[strSize] = 0;
|
||||
}
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
[[nodiscard]] ValErr<std::size_t> OrganicClawReader::arrayLength(const char *key, bool) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
return 0;
|
||||
}
|
||||
if (jv.isArray()) {
|
||||
return jv.size();
|
||||
}
|
||||
return OxError(1, "Type mismatch");
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t OrganicClawReader::stringLength(const char *key) {
|
||||
const char *begin = nullptr, *end = nullptr;
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
return 0;
|
||||
}
|
||||
if (jv.isString()) {
|
||||
jv.getString(&begin, &end);
|
||||
return static_cast<std::size_t>(end - begin);
|
||||
}
|
||||
return OxError(1, "Type mismatch");
|
||||
}
|
||||
|
||||
OrganicClawReader OrganicClawReader::child(const char *key, int unionIdx) {
|
||||
return OrganicClawReader(m_json[key], unionIdx);
|
||||
}
|
||||
|
||||
bool OrganicClawReader::fieldPresent(const char *key) {
|
||||
return !m_json[key].empty();
|
||||
}
|
||||
|
||||
Json::Value &OrganicClawReader::value(const char *key) {
|
||||
if (m_json.isArray()) {
|
||||
return m_json[m_fieldIt];
|
||||
} else {
|
||||
return m_json[key];
|
||||
}
|
||||
}
|
||||
|
||||
bool OrganicClawReader::targetValid() noexcept {
|
||||
return static_cast<int>(m_fieldIt) == m_unionIdx || m_unionIdx == -1;
|
||||
}
|
||||
|
||||
}
|
204
deps/ox/src/ox/oc/read.hpp
vendored
Normal file
204
deps/ox/src/ox/oc/read.hpp
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2015 - 2020 gtalent2@gmail.com
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <json/json.h>
|
||||
|
||||
#include <ox/model/optype.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
class OrganicClawReader {
|
||||
|
||||
private:
|
||||
Json::Value m_json;
|
||||
Json::ArrayIndex m_fieldIt = 0;
|
||||
int m_unionIdx = -1;
|
||||
|
||||
public:
|
||||
OrganicClawReader() = default;
|
||||
|
||||
OrganicClawReader(const uint8_t *buff, std::size_t buffSize);
|
||||
|
||||
OrganicClawReader(const char *json, std::size_t buffSize);
|
||||
|
||||
OrganicClawReader(const Json::Value &json, int unionIdx = -1);
|
||||
|
||||
[[nodiscard]] Error field(const char *key, int8_t *val);
|
||||
[[nodiscard]] Error field(const char *key, int16_t *val);
|
||||
[[nodiscard]] Error field(const char *key, int32_t *val);
|
||||
[[nodiscard]] Error field(const char *key, int64_t *val);
|
||||
|
||||
[[nodiscard]] Error field(const char *key, uint8_t *val);
|
||||
[[nodiscard]] Error field(const char *key, uint16_t *val);
|
||||
[[nodiscard]] Error field(const char *key, uint32_t *val);
|
||||
[[nodiscard]] Error field(const char *key, uint64_t *val);
|
||||
|
||||
[[nodiscard]] Error field(const char *key, bool *val);
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char *key, T *val, std::size_t len);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char *key, Vector<T> *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, HashMap<String, T> *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char *key, T *val);
|
||||
|
||||
template<typename U>
|
||||
[[nodiscard]] Error field(const char *key, UnionView<U> val);
|
||||
|
||||
template<std::size_t L>
|
||||
[[nodiscard]] Error field(const char *key, ox::BString<L> *val);
|
||||
|
||||
[[nodiscard]] Error field(const char *key, SerStr val);
|
||||
|
||||
/**
|
||||
* Reads an array length from the current location in the buffer.
|
||||
* @param pass indicates that the parsing should iterate past the array length
|
||||
*/
|
||||
[[nodiscard]] ValErr<std::size_t> arrayLength(const char *key, bool pass = true);
|
||||
|
||||
/**
|
||||
* Reads an string length from the current location in the buffer.
|
||||
*/
|
||||
[[nodiscard]] std::size_t stringLength(const char *name);
|
||||
|
||||
template<typename T = void>
|
||||
constexpr void setTypeInfo(const char* = T::TypeName, int = T::Fields) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a OrganicClawReader to parse a child object.
|
||||
*/
|
||||
[[nodiscard]] OrganicClawReader child(const char *key, int unionIdx = -1);
|
||||
|
||||
// compatibility stub
|
||||
constexpr void nextField() noexcept {}
|
||||
|
||||
bool fieldPresent(const char *key);
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::Read;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Json::Value &value(const char *key);
|
||||
|
||||
bool targetValid() noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Error OrganicClawReader::field(const char *key, T *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty() || jv.isObject()) {
|
||||
auto reader = child(key);
|
||||
return model(&reader, val);
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Error OrganicClawReader::field(const char *key, UnionView<U> val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty() || jv.isObject()) {
|
||||
auto reader = child(key, val.idx());
|
||||
err = model(&reader, val.get());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
template<std::size_t L>
|
||||
Error OrganicClawReader::field(const char *name, ox::BString<L> *val) {
|
||||
return field(name, SerStr(val->data(), val->cap()));
|
||||
}
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) {
|
||||
const auto &srcVal = value(key);
|
||||
auto srcSize = srcVal.size();
|
||||
if (srcSize > valLen) {
|
||||
return OxError(1);
|
||||
}
|
||||
OrganicClawReader r(srcVal);
|
||||
for (decltype(srcSize) i = 0; i < srcSize; ++i) {
|
||||
oxReturnError(r.field("", &val[i]));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error OrganicClawReader::field(const char *key, ox::Vector<T> *val) {
|
||||
return field(key, val->data(), val->size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error OrganicClawReader::field(const char *key, HashMap<String, T> *val) {
|
||||
const auto &srcVal = value(key);
|
||||
auto keys = srcVal.getMemberNames();
|
||||
auto srcSize = srcVal.size();
|
||||
OrganicClawReader r(srcVal);
|
||||
for (decltype(srcSize) i = 0; i < srcSize; ++i) {
|
||||
auto k = keys[i].c_str();
|
||||
oxReturnError(r.field(k, &val->at(k)));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error readOC(const char *json, std::size_t jsonSize, T *val) noexcept {
|
||||
// OrganicClawReader constructor can throw, but readOC should return its errors.
|
||||
try {
|
||||
Json::Value doc;
|
||||
Json::CharReaderBuilder parserBuilder;
|
||||
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
|
||||
if (!parser->parse(json, json + jsonSize, &doc, nullptr)) {
|
||||
return OxError(1, "Could not parse JSON");
|
||||
}
|
||||
OrganicClawReader reader(json, jsonSize);
|
||||
return model(&reader, val);
|
||||
} catch (Error err) {
|
||||
return err;
|
||||
} catch (...) {
|
||||
return OxError(1, "Unkown Error");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValErr<std::unique_ptr<T>> readOC(const char *json) {
|
||||
auto val = std::make_unique<T>();
|
||||
oxReturnError(readOC(json, ox_strlen(json), val.get()));
|
||||
return {std::move(val), OxError(0)};
|
||||
}
|
||||
|
||||
}
|
13
deps/ox/src/ox/oc/test/CMakeLists.txt
vendored
Normal file
13
deps/ox/src/ox/oc/test/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
add_executable(
|
||||
OcTest
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
OcTest
|
||||
OxOrganicClaw
|
||||
)
|
||||
|
||||
add_test("Test\\ OcTest\\ Writer" OcTest OrganicClawWriter)
|
||||
add_test("Test\\ OcTest\\ Reader" OcTest OrganicClawReader)
|
||||
add_test("Test\\ OcTest\\ OrganicClawDef" OcTest OrganicClawDef)
|
288
deps/ox/src/ox/oc/test/tests.cpp
vendored
Normal file
288
deps/ox/src/ox/oc/test/tests.cpp
vendored
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright 2015 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#undef NDEBUG
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <ox/model/model.hpp>
|
||||
#include <ox/oc/oc.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
union TestUnion {
|
||||
static constexpr auto TypeName = "TestUnion";
|
||||
static constexpr auto Fields = 3;
|
||||
bool Bool;
|
||||
uint32_t Int = 5;
|
||||
char String[32];
|
||||
};
|
||||
|
||||
struct TestStructNest {
|
||||
bool Bool = false;
|
||||
uint32_t Int = 0;
|
||||
ox::BString<32> String = "";
|
||||
};
|
||||
|
||||
struct TestStruct {
|
||||
bool Bool = false;
|
||||
int32_t Int = 0;
|
||||
int32_t Int1 = 0;
|
||||
int32_t Int2 = 0;
|
||||
int32_t Int3 = 0;
|
||||
int32_t Int4 = 0;
|
||||
int32_t Int5 = 0;
|
||||
int32_t Int6 = 0;
|
||||
int32_t Int7 = 0;
|
||||
int32_t Int8 = 0;
|
||||
TestUnion Union;
|
||||
char *CString = nullptr;
|
||||
ox::BString<32> String = "";
|
||||
uint32_t List[4] = {0, 0, 0, 0};
|
||||
ox::HashMap<ox::String, int> Map;
|
||||
TestStructNest EmptyStruct;
|
||||
TestStructNest Struct;
|
||||
|
||||
~TestStruct() {
|
||||
delete[] CString;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestUnion *obj) {
|
||||
io->template setTypeInfo<TestUnion>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", ox::SerStr(obj->String)));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStructNest *obj) {
|
||||
io->setTypeInfo("TestStructNest", 3);
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStruct *obj) {
|
||||
io->setTypeInfo("TestStruct", 17);
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("Int1", &obj->Int1));
|
||||
oxReturnError(io->field("Int2", &obj->Int2));
|
||||
oxReturnError(io->field("Int3", &obj->Int3));
|
||||
oxReturnError(io->field("Int4", &obj->Int4));
|
||||
oxReturnError(io->field("Int5", &obj->Int5));
|
||||
oxReturnError(io->field("Int6", &obj->Int6));
|
||||
oxReturnError(io->field("Int7", &obj->Int7));
|
||||
oxReturnError(io->field("Int8", &obj->Int8));
|
||||
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
|
||||
oxReturnError(io->field("CString", ox::SerStr(&obj->CString)));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
oxReturnError(io->field("List", obj->List, 4));
|
||||
oxReturnError(io->field("Map", &obj->Map));
|
||||
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
|
||||
oxReturnError(io->field("Struct", &obj->Struct));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
std::map<std::string, ox::Error(*)()> tests = {
|
||||
{
|
||||
{
|
||||
"OrganicClawWriter",
|
||||
[] {
|
||||
// This test doesn't confirm much, but it does show that the writer
|
||||
// doesn't segfault
|
||||
TestStruct ts;
|
||||
return ox::writeOC(&ts).error;
|
||||
}
|
||||
},
|
||||
{
|
||||
"OrganicClawReader",
|
||||
[] {
|
||||
TestStruct testIn;
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.Union.Int = 52;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.CString = new char[ox_strlen("c-string") + 1];
|
||||
ox_strcpy(testIn.CString, "c-string");
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Map["asdf"] = 93;
|
||||
testIn.Map["aoeu"] = 94;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
auto [oc, writeErr] = ox::writeOC(&testIn);
|
||||
oxAssert(writeErr, "writeOC failed");
|
||||
std::cout << oc.data() << '\n';
|
||||
auto [testOut, readErr] = ox::readOC<TestStruct>(oc.data());
|
||||
oxAssert(readErr, "readOC failed");
|
||||
|
||||
oxAssert(testIn.Bool == testOut->Bool, "Bool value mismatch");
|
||||
oxAssert(testIn.Int == testOut->Int, "Int value mismatch");
|
||||
oxAssert(testIn.Int1 == testOut->Int1, "Int1 value mismatch");
|
||||
oxAssert(testIn.Int2 == testOut->Int2, "Int2 value mismatch");
|
||||
oxAssert(testIn.Int3 == testOut->Int3, "Int3 value mismatch");
|
||||
oxAssert(testIn.Int4 == testOut->Int4, "Int4 value mismatch");
|
||||
oxAssert(testIn.Int5 == testOut->Int5, "Int5 value mismatch");
|
||||
oxAssert(testIn.Int6 == testOut->Int6, "Int6 value mismatch");
|
||||
oxAssert(testIn.Int7 == testOut->Int7, "Int7 value mismatch");
|
||||
oxAssert(testIn.Int8 == testOut->Int8, "Int8 value mismatch");
|
||||
oxAssert(ox_strcmp(testIn.CString, testOut->CString) == 0, "CString value mismatch");
|
||||
oxAssert(testIn.Union.Int == testOut->Union.Int, "Union.Int value mismatch");
|
||||
oxAssert(testIn.String == testOut->String, "String value mismatch");
|
||||
oxAssert(testIn.List[0] == testOut->List[0], "List[0] value mismatch");
|
||||
oxAssert(testIn.List[1] == testOut->List[1], "List[1] value mismatch");
|
||||
oxAssert(testIn.List[2] == testOut->List[2], "List[2] value mismatch");
|
||||
oxAssert(testIn.List[3] == testOut->List[3], "List[3] value mismatch");
|
||||
oxAssert(testIn.Map["asdf"] == testOut->Map["asdf"], "Map[\"asdf\"] value mismatch");
|
||||
oxAssert(testIn.Map["aoeu"] == testOut->Map["aoeu"], "Map[\"aoeu\"] value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Bool == testOut->EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Int == testOut->EmptyStruct.Int, "EmptyStruct.Int value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.String == testOut->EmptyStruct.String, "EmptyStruct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Int == testOut->Struct.Int, "Struct.Int value mismatch");
|
||||
oxAssert(testIn.Struct.String == testOut->Struct.String, "Struct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Bool == testOut->Struct.Bool, "Struct.Bool value mismatch");
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"OrganicClawDef",
|
||||
[] {
|
||||
TestStruct testIn, testOut;
|
||||
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
auto [oc, ocErr] = ox::writeOC(&testIn);
|
||||
oxAssert(ocErr, "Data generation failed");
|
||||
auto type = ox::buildTypeDef(&testIn);
|
||||
oxAssert(type.error, "Descriptor write failed");
|
||||
ox::walkModel<ox::OrganicClawReader>(type.value, ox::bit_cast<uint8_t*>(oc.data()), oc.size(),
|
||||
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::OrganicClawReader *rdr) -> ox::Error {
|
||||
//std::cout << f.fieldName.c_str() << '\n';
|
||||
auto fieldName = f.fieldName.c_str();
|
||||
switch (f.type->primitiveType) {
|
||||
case ox::PrimitiveType::UnsignedInteger:
|
||||
std::cout << fieldName << ":\tuint" << f.type->length * 8 << "_t:\t";
|
||||
switch (f.type->length) {
|
||||
case 1: {
|
||||
uint8_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
uint16_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
uint32_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
uint64_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::cout << '\n';
|
||||
break;
|
||||
case ox::PrimitiveType::SignedInteger:
|
||||
std::cout << fieldName << ":\tint" << f.type->length * 8 << "_t:\t";
|
||||
switch (f.type->length) {
|
||||
case 1: {
|
||||
int8_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
int16_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int32_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
int64_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::cout << '\n';
|
||||
break;
|
||||
case ox::PrimitiveType::Bool: {
|
||||
bool i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << fieldName << ":\t" << "bool:\t" << (i ? "true" : "false") << '\n';
|
||||
break;
|
||||
}
|
||||
case ox::PrimitiveType::String: {
|
||||
ox::Vector<char> v(rdr->stringLength(fieldName) + 1);
|
||||
//std::cout << rdr->stringLength() << '\n';
|
||||
oxAssert(rdr->field(fieldName, ox::SerStr(v.data(), v.size())), "Walking model failed.");
|
||||
std::cout << fieldName << ":\t" << "string: " << v.data() << '\n';
|
||||
break;
|
||||
}
|
||||
case ox::PrimitiveType::Struct:
|
||||
break;
|
||||
case ox::PrimitiveType::Union:
|
||||
break;
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
);
|
||||
delete type.value;
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
int retval = -1;
|
||||
if (argc > 0) {
|
||||
auto testName = args[1];
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
retval = tests[testName]();
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
118
deps/ox/src/ox/oc/write.cpp
vendored
Normal file
118
deps/ox/src/ox/oc/write.cpp
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 "write.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
OrganicClawWriter::OrganicClawWriter(int unionIdx): m_unionIdx(unionIdx) {
|
||||
}
|
||||
|
||||
OrganicClawWriter::OrganicClawWriter(Json::Value json, int unionIdx):
|
||||
m_json(json),
|
||||
m_unionIdx(unionIdx) {
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, int8_t *val) {
|
||||
if (*val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, int16_t *val) {
|
||||
if (*val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, int32_t *val) {
|
||||
if (*val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, int64_t *val) {
|
||||
if (*val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, uint8_t *val) {
|
||||
if (*val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, uint16_t *val) {
|
||||
if (targetValid() && *val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, uint32_t *val) {
|
||||
if (targetValid() && *val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, uint64_t *val) {
|
||||
if (targetValid() && *val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, bool *val) {
|
||||
if (targetValid() && *val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, ox::String val) {
|
||||
if (targetValid() && val.len()) {
|
||||
value(key) = val.c_str();
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, SerStr val) {
|
||||
if (targetValid() && val.len()) {
|
||||
value(key) = val.c_str();
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Json::Value &OrganicClawWriter::value(const char *key) {
|
||||
if (m_json.isArray()) {
|
||||
return m_json[m_fieldIt];
|
||||
} else {
|
||||
return m_json[key];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
162
deps/ox/src/ox/oc/write.hpp
vendored
Normal file
162
deps/ox/src/ox/oc/write.hpp
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <json/json.h>
|
||||
|
||||
#include <ox/model/optype.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
class OrganicClawWriter {
|
||||
|
||||
template<typename T>
|
||||
friend ValErr<Vector<char>> writeOC(T *val);
|
||||
|
||||
protected:
|
||||
Json::Value m_json;
|
||||
Json::ArrayIndex m_fieldIt = 0;
|
||||
int m_unionIdx = -1;
|
||||
|
||||
public:
|
||||
OrganicClawWriter(int unionIdx = -1);
|
||||
|
||||
OrganicClawWriter(Json::Value json, int unionIdx = -1);
|
||||
|
||||
[[nodiscard]] Error field(const char*, int8_t *val);
|
||||
[[nodiscard]] Error field(const char*, int16_t *val);
|
||||
[[nodiscard]] Error field(const char*, int32_t *val);
|
||||
[[nodiscard]] Error field(const char*, int64_t *val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, uint8_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint16_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint32_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint64_t *val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, bool *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, T *val, std::size_t len);
|
||||
|
||||
template<typename U>
|
||||
[[nodiscard]] Error field(const char*, UnionView<U> val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, ox::Vector<T> *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, HashMap<String, T> *val);
|
||||
|
||||
template<std::size_t L>
|
||||
[[nodiscard]] Error field(const char*, ox::BString<L> *val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, ox::String val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, SerStr val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, T *val);
|
||||
|
||||
template<typename T = void>
|
||||
constexpr void setTypeInfo(const char* = T::TypeName, int = T::Fields) {
|
||||
}
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::Write;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr bool targetValid() noexcept {
|
||||
return static_cast<int>(m_fieldIt) == m_unionIdx || m_unionIdx == -1;
|
||||
}
|
||||
|
||||
Json::Value &value(const char *key);
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Error OrganicClawWriter::field(const char *key, T *val, std::size_t len) {
|
||||
if (targetValid()) {
|
||||
OrganicClawWriter w((Json::Value(Json::arrayValue)));
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
oxReturnError(w.field("", &val[i]));
|
||||
}
|
||||
value(key) = w.m_json;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<std::size_t L>
|
||||
Error OrganicClawWriter::field(const char *key, ox::BString<L> *val) {
|
||||
return field(key, SerStr(val->data(), val->cap()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error OrganicClawWriter::field(const char *key, T *val) {
|
||||
if (val && targetValid()) {
|
||||
OrganicClawWriter w;
|
||||
oxReturnError(model(&w, val));
|
||||
if (!w.m_json.isNull()) {
|
||||
value(key) = w.m_json;
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Error OrganicClawWriter::field(const char *key, UnionView<U> val) {
|
||||
if (targetValid()) {
|
||||
OrganicClawWriter w(val.idx());
|
||||
oxReturnError(model(&w, val.get()));
|
||||
if (!w.m_json.isNull()) {
|
||||
value(key) = w.m_json;
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error OrganicClawWriter::field(const char *key, ox::Vector<T> *val) {
|
||||
return field(key, val->data(), val->size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error OrganicClawWriter::field(const char *key, ox::HashMap<String, T> *val) {
|
||||
if (targetValid()) {
|
||||
auto &keys = val->keys();
|
||||
OrganicClawWriter w;
|
||||
for (std::size_t i = 0; i < keys.size(); ++i) {
|
||||
auto k = keys[i].c_str();
|
||||
oxReturnError(w.field(k, &val->at(k)));
|
||||
}
|
||||
value(key) = w.m_json;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValErr<Vector<char>> writeOC(T *val) {
|
||||
OrganicClawWriter writer;
|
||||
oxReturnError(model(&writer, val));
|
||||
Json::StreamWriterBuilder jsonBuilder;
|
||||
auto str = Json::writeString(jsonBuilder, writer.m_json);
|
||||
Vector<char> buff(str.size() + 1);
|
||||
memcpy(buff.data(), str.c_str(), str.size() + 1);
|
||||
return buff;
|
||||
}
|
||||
|
||||
}
|
11
deps/ox/src/ox/ptrarith/CMakeLists.txt
vendored
Normal file
11
deps/ox/src/ox/ptrarith/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
install(
|
||||
FILES
|
||||
nodebuffer.hpp
|
||||
ptr.hpp
|
||||
DESTINATION
|
||||
include/ox/ptrarith
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
455
deps/ox/src/ox/ptrarith/nodebuffer.hpp
vendored
Normal file
455
deps/ox/src/ox/ptrarith/nodebuffer.hpp
vendored
Normal file
@ -0,0 +1,455 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/stddef.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
|
||||
#include "ptr.hpp"
|
||||
|
||||
namespace ox::ptrarith {
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
class OX_PACKED NodeBuffer {
|
||||
|
||||
public:
|
||||
struct OX_PACKED Header {
|
||||
ox::LittleEndian<size_t> size = sizeof(Header); // capacity
|
||||
ox::LittleEndian<size_t> bytesUsed = sizeof(Header);
|
||||
ox::LittleEndian<size_t> firstItem = 0;
|
||||
};
|
||||
|
||||
using ItemPtr = Ptr<Item, size_t, sizeof(Header)>;
|
||||
|
||||
class Iterator {
|
||||
private:
|
||||
NodeBuffer *m_buffer = nullptr;
|
||||
ItemPtr m_current;
|
||||
size_t m_it = 0;
|
||||
|
||||
public:
|
||||
Iterator(NodeBuffer *buffer, ItemPtr current) {
|
||||
m_buffer = buffer;
|
||||
m_current = current;
|
||||
oxTrace("ox::ptrarith::Iterator::start") << current.offset();
|
||||
}
|
||||
|
||||
operator const Item*() const {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
ItemPtr ptr() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
Item *get() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator ItemPtr() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator Item*() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
const Item *operator->() const {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
Item *operator->() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool valid() const noexcept {
|
||||
return m_current.valid();
|
||||
}
|
||||
|
||||
bool hasNext() {
|
||||
if (m_current.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::Iterator::hasNext::current") << m_current.offset();
|
||||
auto next = m_buffer->next(m_current);
|
||||
return next.valid() && m_buffer->firstItem() != next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void next() {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::Iterator::next") << m_it++;
|
||||
if (hasNext()) {
|
||||
m_current = m_buffer->next(m_current);
|
||||
} else {
|
||||
m_current = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Header m_header;
|
||||
|
||||
public:
|
||||
NodeBuffer();
|
||||
|
||||
NodeBuffer(const NodeBuffer &other, size_t size);
|
||||
|
||||
explicit NodeBuffer(size_t size);
|
||||
|
||||
const Iterator iterator() const;
|
||||
|
||||
Iterator iterator();
|
||||
|
||||
ItemPtr firstItem();
|
||||
|
||||
ItemPtr lastItem();
|
||||
|
||||
/**
|
||||
* @return the data section of the given item
|
||||
*/
|
||||
template<typename T>
|
||||
Ptr<T, size_t, sizeof(Item)> dataOf(ItemPtr);
|
||||
|
||||
[[nodiscard]] ItemPtr prev(Item *item);
|
||||
|
||||
[[nodiscard]] ItemPtr next(Item *item);
|
||||
|
||||
/**
|
||||
* Like pointer but omits checks that assume the memory at the offset has
|
||||
* already been initialed as an Item.
|
||||
*/
|
||||
[[nodiscard]] ItemPtr uninitializedPtr(size_t offset);
|
||||
|
||||
[[nodiscard]] ItemPtr ptr(size_t offset);
|
||||
|
||||
[[nodiscard]] ItemPtr ptr(void *item);
|
||||
|
||||
[[nodiscard]] ItemPtr malloc(size_t size);
|
||||
|
||||
[[nodiscard]] ox::Error free(ItemPtr item);
|
||||
|
||||
[[nodiscard]] bool valid(size_t maxSize);
|
||||
|
||||
/**
|
||||
* Set size, capacity.
|
||||
*/
|
||||
[[nodiscard]] ox::Error setSize(size_t size);
|
||||
|
||||
/**
|
||||
* Get size, capacity.
|
||||
* @return capacity
|
||||
*/
|
||||
size_t size();
|
||||
|
||||
/**
|
||||
* @return the bytes still available in this NodeBuffer
|
||||
*/
|
||||
size_t available();
|
||||
|
||||
/**
|
||||
* @return the actual number a bytes need to store the given number of
|
||||
* bytes
|
||||
*/
|
||||
static size_t spaceNeeded(size_t size);
|
||||
|
||||
template<typename F>
|
||||
[[nodiscard]] ox::Error compact(F cb = [](uint64_t, ItemPtr) {});
|
||||
|
||||
void truncate();
|
||||
|
||||
private:
|
||||
uint8_t *data();
|
||||
|
||||
};
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
NodeBuffer<size_t, Item>::NodeBuffer(size_t size) {
|
||||
m_header.size = size;
|
||||
auto data = reinterpret_cast<uint8_t*>(this) + sizeof(*this);
|
||||
ox_memset(data, 0, size - sizeof(*this));
|
||||
oxTrace("ox::NodeBuffer::constructor") << m_header.firstItem;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
NodeBuffer<size_t, Item>::NodeBuffer(const NodeBuffer &other, size_t size) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::copy") << "other.m_header.firstItem:" << other.m_header.firstItem;
|
||||
auto data = reinterpret_cast<uint8_t*>(this) + sizeof(*this);
|
||||
ox_memset(data, 0, size - sizeof(*this));
|
||||
ox_memcpy(this, &other, size);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
const typename NodeBuffer<size_t, Item>::Iterator NodeBuffer<size_t, Item>::iterator() const {
|
||||
return Iterator(this, firstItem());
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::Iterator NodeBuffer<size_t, Item>::iterator() {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::iterator::size") << m_header.size;
|
||||
return Iterator(this, firstItem());
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::firstItem() {
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::firstItem") << m_header.firstItem;
|
||||
return ptr(m_header.firstItem);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::lastItem() {
|
||||
auto first = ptr(m_header.firstItem);
|
||||
if (first.valid()) {
|
||||
return prev(first);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
template<typename T>
|
||||
Ptr<T, size_t, sizeof(Item)> NodeBuffer<size_t, Item>::dataOf(ItemPtr ip) {
|
||||
auto out = ip.template subPtr<T>(sizeof(Item));
|
||||
oxAssert(out.size() == ip.size() - sizeof(Item), "Sub Ptr has invalid size.");
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::prev(Item *item) {
|
||||
return ptr(item->prev);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::next(Item *item) {
|
||||
return ptr(item->next);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::uninitializedPtr(size_t itemOffset) {
|
||||
// make sure this can be read as an Item, and then use Item::size for the size
|
||||
std::size_t itemSpace = m_header.size - itemOffset;
|
||||
if (itemOffset >= sizeof(Header) &&
|
||||
itemOffset + itemSpace <= size() &&
|
||||
itemSpace >= sizeof(Item)) {
|
||||
return ItemPtr(this, m_header.size, itemOffset, itemSpace);
|
||||
} else {
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset:" << itemOffset;
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset >= sizeof(Header):" << (itemOffset >= sizeof(Header));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= sizeof(Item):" << (itemSpace >= sizeof(Item));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= item->fullSize():" << (itemSpace >= item->fullSize());
|
||||
return ItemPtr(this, m_header.size, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::ptr(size_t itemOffset) {
|
||||
// make sure this can be read as an Item, and then use Item::size for the size
|
||||
std::size_t itemSpace = m_header.size - itemOffset;
|
||||
auto item = reinterpret_cast<Item*>(reinterpret_cast<uint8_t*>(this) + itemOffset);
|
||||
if (itemOffset >= sizeof(Header) &&
|
||||
itemOffset + itemSpace <= size() &&
|
||||
itemSpace >= sizeof(Item) &&
|
||||
itemSpace >= item->fullSize()) {
|
||||
return ItemPtr(this, m_header.size, itemOffset, item->fullSize());
|
||||
} else {
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset:" << itemOffset;
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset >= sizeof(Header):" << (itemOffset >= sizeof(Header));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= sizeof(Item):" << (itemSpace >= sizeof(Item));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= item->fullSize():" << (itemSpace >= item->fullSize());
|
||||
return ItemPtr(this, m_header.size, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::malloc(size_t size) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "Size:" << size;
|
||||
size_t fullSize = size + sizeof(Item);
|
||||
if (m_header.size - m_header.bytesUsed >= fullSize) {
|
||||
auto last = lastItem();
|
||||
size_t addr = 0;
|
||||
if (last.valid()) {
|
||||
addr = last.offset() + last.size();
|
||||
} else {
|
||||
// there is no first item, so this must be the first item
|
||||
if (!m_header.firstItem) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "No first item, initializing.";
|
||||
m_header.firstItem = sizeof(m_header);
|
||||
addr = m_header.firstItem;
|
||||
} else {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "NodeBuffer is in invalid state.";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "buffer size:" << m_header.size
|
||||
<< ";addr:" << addr
|
||||
<< ";fullSize:" << fullSize;
|
||||
auto out = ItemPtr(this, m_header.size, addr, fullSize);
|
||||
if (!out.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "Unknown";
|
||||
return nullptr;
|
||||
}
|
||||
ox_memset(out, 0, fullSize);
|
||||
new (out) Item;
|
||||
out->setSize(size);
|
||||
|
||||
auto first = firstItem();
|
||||
auto oldLast = last;
|
||||
out->next = first.offset();
|
||||
if (first.valid()) {
|
||||
first->prev = out.offset();
|
||||
} else {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "NodeBuffer malloc failed due to invalid first element pointer.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (oldLast.valid()) {
|
||||
out->prev = oldLast.offset();
|
||||
oldLast->next = out.offset();
|
||||
} else { // check to see if this is the first allocation
|
||||
if (out.offset() != first.offset()) {
|
||||
// if this is not the first allocation, there should be an oldLast
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "NodeBuffer malloc failed due to invalid last element pointer.";
|
||||
return nullptr;
|
||||
}
|
||||
out->prev = out.offset();
|
||||
}
|
||||
m_header.bytesUsed += out.size();
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "Offset:" << out.offset();
|
||||
return out;
|
||||
}
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "Insufficient space:" << fullSize << "needed," << available() << "available";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
Error NodeBuffer<size_t, Item>::free(ItemPtr item) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free") << "offset:" << item.offset();
|
||||
auto prev = this->prev(item);
|
||||
auto next = this->next(item);
|
||||
if (prev.valid() && next.valid()) {
|
||||
if (next != item) {
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
if (item.offset() == m_header.firstItem) {
|
||||
m_header.firstItem = next;
|
||||
}
|
||||
} else {
|
||||
// only one item, null out first
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free") << "Nulling out firstItem.";
|
||||
m_header.firstItem = 0;
|
||||
}
|
||||
} else {
|
||||
if (!prev.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free::fail") << "NodeBuffer free failed due to invalid prev element pointer:" << prev.offset();
|
||||
return OxError(1);
|
||||
}
|
||||
if (!next.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free::fail") << "NodeBuffer free failed due to invalid next element pointer:" << next.offset();
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
m_header.bytesUsed -= item.size();
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
Error NodeBuffer<size_t, Item>::setSize(size_t size) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::setSize") << m_header.size << "to" << size;
|
||||
auto last = lastItem();
|
||||
auto end = last.valid() ? last.end() : sizeof(m_header);
|
||||
oxTrace("ox::ptrarith::NodeBuffer::setSize") << "end:" << end;
|
||||
if (end > size) {
|
||||
// resizing to less than buffer size
|
||||
return OxError(1);
|
||||
} else {
|
||||
m_header.size = size;
|
||||
auto data = reinterpret_cast<uint8_t*>(this) + end;
|
||||
ox_memset(data, 0, size - end);
|
||||
return OxError(0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
size_t NodeBuffer<size_t, Item>::size() {
|
||||
return m_header.size;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
bool NodeBuffer<size_t, Item>::valid(size_t maxSize) {
|
||||
return m_header.size <= maxSize;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
size_t NodeBuffer<size_t, Item>::available() {
|
||||
return m_header.size - m_header.bytesUsed;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
size_t NodeBuffer<size_t, Item>::spaceNeeded(size_t size) {
|
||||
return sizeof(Item) + size;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
template<typename F>
|
||||
ox::Error NodeBuffer<size_t, Item>::compact(F cb) {
|
||||
auto src = firstItem();
|
||||
auto dest = ptr(sizeof(*this));
|
||||
while (dest.offset() <= src.offset()) {
|
||||
if (!src.valid()) {
|
||||
return OxError(1);
|
||||
}
|
||||
if (!dest.valid()) {
|
||||
return OxError(2);
|
||||
}
|
||||
// move node
|
||||
ox_memcpy(dest, src, src->fullSize());
|
||||
oxReturnError(cb(src, dest));
|
||||
// update surrounding nodes
|
||||
auto prev = ptr(dest->prev);
|
||||
if (prev.valid()) {
|
||||
prev->next = dest;
|
||||
}
|
||||
auto next = ptr(dest->next);
|
||||
if (next.valid()) {
|
||||
next->prev = dest;
|
||||
}
|
||||
// update iterators
|
||||
src = ptr(dest->next);
|
||||
dest = uninitializedPtr(dest.offset() + dest->fullSize());
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
void NodeBuffer<size_t, Item>::truncate() {
|
||||
m_header.size = m_header.bytesUsed;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
uint8_t *NodeBuffer<size_t, Item>::data() {
|
||||
return reinterpret_cast<uint8_t*>(ptr(sizeof(*this)).get());
|
||||
}
|
||||
|
||||
|
||||
template<typename size_t>
|
||||
struct OX_PACKED Item {
|
||||
public:
|
||||
ox::LittleEndian<size_t> prev = 0;
|
||||
ox::LittleEndian<size_t> next = 0;
|
||||
|
||||
private:
|
||||
ox::LittleEndian<size_t> m_size = sizeof(Item);
|
||||
|
||||
public:
|
||||
size_t size() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
void setSize(size_t size) {
|
||||
m_size = size;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
230
deps/ox/src/ox/ptrarith/ptr.hpp
vendored
Normal file
230
deps/ox/src/ox/ptrarith/ptr.hpp
vendored
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.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 <ox/std/std.hpp>
|
||||
|
||||
namespace ox::ptrarith {
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset = 1>
|
||||
class Ptr {
|
||||
|
||||
private:
|
||||
uint8_t *m_dataStart = nullptr;
|
||||
size_t m_dataSize = 0;
|
||||
size_t m_itemOffset = 0;
|
||||
size_t m_itemSize = 0;
|
||||
// this should be removed later on, but the excessive validation is
|
||||
// desirable during during heavy development
|
||||
mutable uint8_t m_validated = false;
|
||||
|
||||
public:
|
||||
inline Ptr() = default;
|
||||
|
||||
inline Ptr(std::nullptr_t);
|
||||
|
||||
inline Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize = sizeof(T), size_t itemTypeSize = sizeof(T));
|
||||
|
||||
[[nodiscard]] inline bool valid() const;
|
||||
|
||||
inline size_t size() const;
|
||||
|
||||
inline size_t offset() const;
|
||||
|
||||
inline size_t end();
|
||||
|
||||
inline const T *get() const;
|
||||
|
||||
inline T *get();
|
||||
|
||||
inline const T *operator->() const;
|
||||
|
||||
inline T *operator->();
|
||||
|
||||
inline operator const T*() const;
|
||||
|
||||
inline operator T*();
|
||||
|
||||
inline const T &operator*() const;
|
||||
|
||||
inline T &operator*();
|
||||
|
||||
inline operator size_t() const;
|
||||
|
||||
inline bool operator==(const Ptr<T, size_t, minOffset> &other) const;
|
||||
|
||||
inline bool operator!=(const Ptr<T, size_t, minOffset> &other) const;
|
||||
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset, size_t size) const;
|
||||
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset) const;
|
||||
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset, size_t size);
|
||||
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset);
|
||||
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, minOffset> to() const;
|
||||
|
||||
};
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::Ptr(std::nullptr_t) {
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize, size_t itemTypeSize) {
|
||||
// do some sanity checks before assuming this is valid
|
||||
if (itemSize >= itemTypeSize &&
|
||||
dataStart &&
|
||||
itemStart >= minOffset &&
|
||||
itemStart + itemSize <= dataSize) {
|
||||
m_dataStart = reinterpret_cast<uint8_t*>(dataStart);
|
||||
m_dataSize = dataSize;
|
||||
m_itemOffset = itemStart;
|
||||
m_itemSize = itemSize;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline bool Ptr<T, size_t, minOffset>::valid() const {
|
||||
m_validated = m_dataStart != nullptr;
|
||||
return m_validated;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline size_t Ptr<T, size_t, minOffset>::size() const {
|
||||
return m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline size_t Ptr<T, size_t, minOffset>::offset() const {
|
||||
return m_itemOffset;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline size_t Ptr<T, size_t, minOffset>::end() {
|
||||
return m_itemOffset + m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline const T *Ptr<T, size_t, minOffset>::get() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::get())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::get())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline T *Ptr<T, size_t, minOffset>::get() {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::get())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::get())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline const T *Ptr<T, size_t, minOffset>::operator->() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator->())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator->())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline T *Ptr<T, size_t, minOffset>::operator->() {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator->())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator->())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::operator const T*() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator const T*())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator const T*())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::operator T*() {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator T*())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator T*())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline const T &Ptr<T, size_t, minOffset>::operator*() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
oxAssert(valid(), "Invalid pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
return *reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline T &Ptr<T, size_t, minOffset>::operator*() {
|
||||
oxAssert(m_validated, "Unvalidated pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
oxAssert(valid(), "Invalid pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
return *reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::operator size_t() const {
|
||||
if (m_dataStart && m_itemOffset) {
|
||||
return m_itemOffset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline bool Ptr<T, size_t, minOffset>::operator==(const Ptr<T, size_t, minOffset> &other) const {
|
||||
return m_dataStart == other.m_dataStart &&
|
||||
m_itemOffset == other.m_itemOffset &&
|
||||
m_itemSize == other.m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline bool Ptr<T, size_t, minOffset>::operator!=(const Ptr<T, size_t, minOffset> &other) const {
|
||||
return m_dataStart != other.m_dataStart ||
|
||||
m_itemOffset != other.m_itemOffset ||
|
||||
m_itemSize != other.m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset, size_t size) const {
|
||||
return Ptr<SubT, size_t, sizeof(T)>(get(), this->size(), offset, size);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) const {
|
||||
oxTrace("ox::fs::Ptr::subPtr") << m_itemOffset << this->size() << offset << m_itemSize << (m_itemSize - offset);
|
||||
return subPtr<SubT>(offset, m_itemSize - offset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset, size_t size) {
|
||||
return Ptr<SubT, size_t, sizeof(T)>(get(), this->size(), offset, size);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) {
|
||||
oxTrace("ox::fs::Ptr::subPtr") << m_itemOffset << this->size() << offset << m_itemSize << (m_itemSize - offset);
|
||||
return subPtr<SubT>(offset, m_itemSize - offset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, minOffset> Ptr<T, size_t, minOffset>::to() const {
|
||||
return Ptr<SubT, size_t, minOffset>(m_dataStart, m_dataSize, m_itemOffset, m_itemSize);
|
||||
}
|
||||
|
||||
}
|
11
deps/ox/src/ox/ptrarith/test/CMakeLists.txt
vendored
Normal file
11
deps/ox/src/ox/ptrarith/test/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
add_executable(
|
||||
PtrArithTests
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
PtrArithTests
|
||||
OxStd
|
||||
)
|
||||
|
||||
add_test("Test\\ PtrArith::setSize" PtrArithTests PtrArith::setSize)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user