Introduce >2GB compatible PR 1424 from fdkekin0

This commit is contained in:
jpirnay
2026-03-31 22:06:21 +02:00
parent 3f6d31b966
commit fd8fcbfd50
9 changed files with 801 additions and 389 deletions
-3
View File
@@ -353,7 +353,6 @@ enum class StrId : uint16_t {
STR_OPDS_BROWSER, STR_OPDS_BROWSER,
STR_COVER_CUSTOM, STR_COVER_CUSTOM,
STR_PAGE_OVERLAY, STR_PAGE_OVERLAY,
STR_RECENTS,
STR_MENU_RECENT_BOOKS, STR_MENU_RECENT_BOOKS,
STR_NO_RECENT_BOOKS, STR_NO_RECENT_BOOKS,
STR_CALIBRE_DESC, STR_CALIBRE_DESC,
@@ -418,8 +417,6 @@ enum class StrId : uint16_t {
STR_AUTO_TURN_ENABLED, STR_AUTO_TURN_ENABLED,
STR_AUTO_TURN_PAGES_PER_MIN, STR_AUTO_TURN_PAGES_PER_MIN,
STR_INFO, STR_INFO,
STR_AUTHOR,
STR_SERIES,
STR_FILE_SIZE, STR_FILE_SIZE,
STR_SLEEP_COVER_OVERLAY, STR_SLEEP_COVER_OVERLAY,
STR_OVERLAY_WHITE, STR_OVERLAY_WHITE,
+186 -265
View File
@@ -1,4 +1,5 @@
#include "I18nStrings.h" #include "I18nStrings.h"
#include <cstddef> #include <cstddef>
// THIS FILE IS AUTO-GENERATED BY gen_i18n.py. DO NOT EDIT. // THIS FILE IS AUTO-GENERATED BY gen_i18n.py. DO NOT EDIT.
@@ -1224,7 +1225,6 @@ const char STRINGS_EN_DATA[] =
"OPDS Browser\0" "OPDS Browser\0"
"Cover + Custom\0" "Cover + Custom\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Recent Books\0" "Recent Books\0"
"No recent books\0" "No recent books\0"
"Use Calibre wireless device transfers\0" "Use Calibre wireless device transfers\0"
@@ -1289,8 +1289,6 @@ const char STRINGS_EN_DATA[] =
"Auto Turn Enabled: \0" "Auto Turn Enabled: \0"
"Auto Turn (Pages Per Minute)\0" "Auto Turn (Pages Per Minute)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -1340,15 +1338,14 @@ const uint16_t OFFSETS_EN[] = {
3526, 3534, 3541, 3549, 3554, 3563, 3569, 3573, 3576, 3581, 3586, 3589, 3526, 3534, 3541, 3549, 3554, 3563, 3569, 3573, 3576, 3581, 3586, 3589,
3593, 3601, 3606, 3612, 3615, 3620, 3623, 3649, 3658, 3679, 3698, 3723, 3593, 3601, 3606, 3612, 3615, 3620, 3623, 3649, 3658, 3679, 3698, 3723,
3736, 3759, 3764, 3771, 3777, 3782, 3790, 3801, 3812, 3820, 3826, 3834, 3736, 3759, 3764, 3771, 3777, 3782, 3790, 3801, 3812, 3820, 3826, 3834,
3843, 3851, 3856, 3870, 3890, 3910, 3923, 3938, 3951, 3959, 3972, 3988, 3843, 3851, 3856, 3870, 3890, 3910, 3923, 3938, 3951, 3964, 3980, 4018,
4026, 4068, 4075, 4095, 4101, 4108, 4114, 4122, 4157, 4168, 4185, 4225, 4060, 4067, 4087, 4093, 4100, 4106, 4114, 4149, 4160, 4177, 4217, 4252,
4260, 4278, 4299, 4317, 4336, 4344, 4352, 4366, 4384, 4391, 4398, 4414, 4270, 4291, 4309, 4328, 4336, 4344, 4358, 4376, 4383, 4390, 4406, 4416,
4424, 4436, 4443, 4478, 4507, 4523, 4552, 4586, 4614, 4641, 4671, 4693, 4428, 4435, 4470, 4499, 4515, 4544, 4578, 4606, 4633, 4663, 4685, 4711,
4719, 4755, 4771, 4779, 4786, 4810, 4837, 4848, 4870, 4892, 4917, 4942, 4747, 4763, 4771, 4778, 4802, 4829, 4840, 4862, 4884, 4909, 4934, 4953,
4961, 4973, 4982, 4989, 5002, 5017, 5033, 5043, 5069, 5076, 5092, 5112, 4965, 4974, 4981, 4994, 5009, 5025, 5035, 5061, 5068, 5084, 5104, 5133,
5141, 5146, 5153, 5160, 5165, 5191, 5197, 5202, 5208, 5212, 5251, 5278, 5138, 5143, 5169, 5175, 5180, 5186, 5190, 5229, 5256, 5284, 5303, 5327,
5306, 5325, 5349, 5374, 5385, 5390, 5394, 5398, 5407, 5416, 5426, 5437, 5352, 5363, 5368, 5372, 5376, 5385, 5394, 5404, 5415, 5422, 5431, 5449,
5444, 5453, 5471,
}; };
const char STRINGS_ES_DATA[] = const char STRINGS_ES_DATA[] =
@@ -1796,7 +1793,6 @@ const char STRINGS_ES_DATA[] =
"Navegador OPDS\0" "Navegador OPDS\0"
"Portada + Pers.\0" "Portada + Pers.\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Libros recientes\0" "Libros recientes\0"
"No hay libros recientes\0" "No hay libros recientes\0"
"Transferir contenido a este dispositivo\0" "Transferir contenido a este dispositivo\0"
@@ -1925,8 +1921,6 @@ const char STRINGS_ES_DATA[] =
"\xA1" "\xA1"
"ginas por minuto\0" "ginas por minuto\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -1976,15 +1970,14 @@ const uint16_t OFFSETS_ES[] = {
4131, 4141, 4150, 4159, 4165, 4175, 4186, 4190, 4193, 4201, 4209, 4218, 4131, 4141, 4150, 4159, 4165, 4175, 4186, 4190, 4193, 4201, 4209, 4218,
4230, 4245, 4250, 4256, 4262, 4268, 4271, 4305, 4315, 4344, 4371, 4397, 4230, 4245, 4250, 4256, 4262, 4268, 4271, 4305, 4315, 4344, 4371, 4397,
4415, 4443, 4448, 4454, 4460, 4466, 4476, 4489, 4507, 4525, 4533, 4542, 4415, 4443, 4448, 4454, 4460, 4466, 4476, 4489, 4507, 4525, 4533, 4542,
4551, 4560, 4565, 4580, 4611, 4642, 4657, 4673, 4686, 4694, 4711, 4735, 4551, 4560, 4565, 4580, 4611, 4642, 4657, 4673, 4686, 4703, 4727, 4767,
4775, 4825, 4833, 4854, 4869, 4876, 4883, 4898, 4941, 4953, 4965, 5015, 4817, 4825, 4846, 4861, 4868, 4875, 4890, 4933, 4945, 4957, 5007, 5053,
5061, 5084, 5111, 5132, 5154, 5161, 5184, 5216, 5240, 5247, 5254, 5278, 5076, 5103, 5124, 5146, 5153, 5176, 5208, 5232, 5239, 5246, 5270, 5277,
5285, 5297, 5305, 5342, 5378, 5407, 5440, 5482, 5513, 5540, 5570, 5591, 5289, 5297, 5334, 5370, 5399, 5432, 5474, 5505, 5532, 5562, 5583, 5618,
5626, 5680, 5703, 5711, 5718, 5748, 5783, 5792, 5816, 5837, 5869, 5895, 5672, 5695, 5703, 5710, 5740, 5775, 5784, 5808, 5829, 5861, 5887, 5906,
5914, 5939, 5946, 5952, 5969, 5986, 6008, 6023, 6059, 6068, 6094, 6116, 5931, 5938, 5944, 5961, 5978, 6000, 6015, 6051, 6060, 6086, 6108, 6133,
6141, 6146, 6153, 6160, 6165, 6191, 6197, 6202, 6208, 6212, 6251, 6278, 6138, 6143, 6169, 6175, 6180, 6186, 6190, 6229, 6256, 6284, 6303, 6327,
6306, 6325, 6349, 6374, 6385, 6390, 6394, 6398, 6407, 6416, 6426, 6437, 6352, 6363, 6368, 6372, 6376, 6385, 6394, 6404, 6415, 6422, 6431, 6449,
6444, 6453, 6471,
}; };
const char STRINGS_FR_DATA[] = const char STRINGS_FR_DATA[] =
@@ -2547,7 +2540,6 @@ const char STRINGS_FR_DATA[] =
"Navigateur OPDS\0" "Navigateur OPDS\0"
"Couverture + Perso\0" "Couverture + Perso\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Livres r\xC3" "Livres r\xC3"
"\xA9" "\xA9"
"cents\0" "cents\0"
@@ -2683,8 +2675,6 @@ const char STRINGS_FR_DATA[] =
"Tourne-page auto : \0" "Tourne-page auto : \0"
"Tourne-page auto (pages par minute)\0" "Tourne-page auto (pages par minute)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -2734,15 +2724,14 @@ const uint16_t OFFSETS_FR[] = {
3905, 3915, 3923, 3933, 3940, 3954, 3965, 3969, 3973, 3982, 3990, 3993, 3905, 3915, 3923, 3933, 3940, 3954, 3965, 3969, 3973, 3982, 3990, 3993,
3997, 4009, 4016, 4023, 4028, 4032, 4035, 4059, 4069, 4100, 4128, 4155, 3997, 4009, 4016, 4023, 4028, 4032, 4035, 4059, 4069, 4100, 4128, 4155,
4176, 4199, 4204, 4212, 4221, 4227, 4236, 4248, 4263, 4271, 4277, 4286, 4176, 4199, 4204, 4212, 4221, 4227, 4236, 4248, 4263, 4271, 4277, 4286,
4303, 4313, 4318, 4332, 4365, 4392, 4408, 4427, 4440, 4448, 4464, 4484, 4303, 4313, 4318, 4332, 4365, 4392, 4408, 4427, 4440, 4456, 4476, 4512,
4520, 4560, 4568, 4590, 4604, 4611, 4619, 4627, 4657, 4670, 4686, 4717, 4552, 4560, 4582, 4596, 4603, 4611, 4619, 4649, 4662, 4678, 4709, 4732,
4740, 4758, 4772, 4790, 4808, 4819, 4834, 4854, 4876, 4886, 4893, 4916, 4750, 4764, 4782, 4800, 4811, 4826, 4846, 4868, 4878, 4885, 4908, 4920,
4928, 4940, 4949, 4988, 5023, 5047, 5066, 5085, 5117, 5144, 5174, 5195, 4932, 4941, 4980, 5015, 5039, 5058, 5077, 5109, 5136, 5166, 5187, 5205,
5213, 5255, 5278, 5289, 5297, 5319, 5344, 5354, 5385, 5412, 5440, 5468, 5247, 5270, 5281, 5289, 5311, 5336, 5346, 5377, 5404, 5432, 5460, 5483,
5491, 5512, 5521, 5529, 5544, 5560, 5577, 5598, 5625, 5632, 5649, 5669, 5504, 5513, 5521, 5536, 5552, 5569, 5590, 5617, 5624, 5641, 5661, 5697,
5705, 5710, 5717, 5724, 5729, 5755, 5761, 5766, 5772, 5776, 5815, 5842, 5702, 5707, 5733, 5739, 5744, 5750, 5754, 5793, 5820, 5848, 5867, 5891,
5870, 5889, 5913, 5938, 5949, 5954, 5958, 5962, 5971, 5980, 5990, 6001, 5916, 5927, 5932, 5936, 5940, 5949, 5958, 5968, 5979, 5986, 5995, 6013,
6008, 6017, 6035,
}; };
const char STRINGS_DE_DATA[] = const char STRINGS_DE_DATA[] =
@@ -3130,7 +3119,6 @@ const char STRINGS_DE_DATA[] =
"OPDS-Browser\0" "OPDS-Browser\0"
"Umschlag + Eigenes\0" "Umschlag + Eigenes\0"
"Seiten-Overlay\0" "Seiten-Overlay\0"
"Zuletzt\0"
"Zuletzt gelesen\0" "Zuletzt gelesen\0"
"Keine B\xC3" "Keine B\xC3"
"\xBC" "\xBC"
@@ -3233,8 +3221,6 @@ const char STRINGS_DE_DATA[] =
"\xA4" "\xA4"
"ttern (Seiten/Min.)\0" "ttern (Seiten/Min.)\0"
"Info\0" "Info\0"
"Autor\0"
"Reihe\0"
"Gr\xC3" "Gr\xC3"
"\xB6" "\xB6"
"\xC3" "\xC3"
@@ -3290,15 +3276,14 @@ const uint16_t OFFSETS_DE[] = {
3641, 3653, 3663, 3673, 3681, 3695, 3704, 3707, 3712, 3719, 3730, 3733, 3641, 3653, 3663, 3673, 3681, 3695, 3704, 3707, 3712, 3719, 3730, 3733,
3737, 3742, 3748, 3755, 3760, 3767, 3770, 3790, 3799, 3821, 3842, 3863, 3737, 3742, 3748, 3755, 3760, 3767, 3770, 3790, 3799, 3821, 3842, 3863,
3882, 3896, 3902, 3909, 3914, 3919, 3927, 3938, 3948, 3957, 3963, 3972, 3882, 3896, 3902, 3909, 3914, 3919, 3927, 3938, 3948, 3957, 3963, 3972,
3986, 3996, 4001, 4015, 4031, 4054, 4067, 4086, 4101, 4109, 4125, 4139, 3986, 3996, 4001, 4015, 4031, 4054, 4067, 4086, 4101, 4117, 4131, 4159,
4167, 4203, 4213, 4232, 4245, 4252, 4259, 4268, 4303, 4308, 4327, 4354, 4195, 4205, 4224, 4237, 4244, 4251, 4260, 4295, 4300, 4319, 4346, 4376,
4384, 4403, 4426, 4443, 4461, 4471, 4482, 4510, 4528, 4537, 4547, 4569, 4395, 4418, 4435, 4453, 4463, 4474, 4502, 4520, 4529, 4539, 4561, 4570,
4578, 4591, 4598, 4630, 4664, 4688, 4715, 4744, 4776, 4805, 4834, 4859, 4583, 4590, 4622, 4656, 4680, 4707, 4736, 4768, 4797, 4826, 4851, 4871,
4879, 4915, 4925, 4933, 4940, 4969, 5001, 5011, 5044, 5074, 5100, 5129, 4907, 4917, 4925, 4932, 4961, 4993, 5003, 5036, 5066, 5092, 5121, 5134,
5142, 5157, 5167, 5177, 5187, 5206, 5222, 5232, 5265, 5272, 5293, 5318, 5149, 5159, 5169, 5179, 5198, 5214, 5224, 5257, 5264, 5285, 5310, 5341,
5349, 5354, 5360, 5366, 5374, 5395, 5401, 5406, 5412, 5416, 5455, 5482, 5346, 5354, 5375, 5381, 5386, 5392, 5396, 5435, 5462, 5490, 5510, 5548,
5510, 5530, 5568, 5607, 5618, 5623, 5627, 5631, 5642, 5652, 5663, 5676, 5587, 5598, 5603, 5607, 5611, 5622, 5632, 5643, 5656, 5665, 5671, 5697,
5685, 5691, 5717,
}; };
const char STRINGS_CS_DATA[] = const char STRINGS_CS_DATA[] =
@@ -4373,7 +4358,6 @@ const char STRINGS_CS_DATA[] =
"\xAD" "\xAD"
"\0" "\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Ned\xC3" "Ned\xC3"
"\xA1" "\xA1"
"vn\xC3" "vn\xC3"
@@ -4704,8 +4688,6 @@ const char STRINGS_CS_DATA[] =
"Auto Turn Enabled: \0" "Auto Turn Enabled: \0"
"Auto Turn (Pages Per Minute)\0" "Auto Turn (Pages Per Minute)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -4755,15 +4737,14 @@ const uint16_t OFFSETS_CS[] = {
4344, 4353, 4361, 4371, 4381, 4391, 4404, 4408, 4411, 4416, 4421, 4425, 4344, 4353, 4361, 4371, 4381, 4391, 4404, 4408, 4411, 4416, 4421, 4425,
4429, 4441, 4447, 4454, 4461, 4467, 4470, 4494, 4503, 4524, 4543, 4568, 4429, 4441, 4447, 4454, 4461, 4467, 4470, 4494, 4503, 4524, 4543, 4568,
4581, 4604, 4609, 4616, 4622, 4627, 4635, 4646, 4657, 4665, 4671, 4679, 4581, 4604, 4609, 4616, 4622, 4627, 4635, 4646, 4657, 4665, 4671, 4679,
4698, 4708, 4713, 4727, 4754, 4786, 4804, 4823, 4836, 4844, 4860, 4885, 4698, 4708, 4713, 4727, 4754, 4786, 4804, 4823, 4836, 4852, 4877, 4932,
4940, 4986, 4997, 5020, 5031, 5036, 5044, 5054, 5102, 5116, 5133, 5190, 4978, 4989, 5012, 5023, 5028, 5036, 5046, 5094, 5108, 5125, 5182, 5231,
5239, 5261, 5286, 5308, 5331, 5345, 5360, 5383, 5408, 5415, 5422, 5438, 5253, 5278, 5300, 5323, 5337, 5352, 5375, 5400, 5407, 5414, 5430, 5440,
5448, 5459, 5466, 5508, 5545, 5567, 5596, 5638, 5677, 5704, 5734, 5759, 5451, 5458, 5500, 5537, 5559, 5588, 5630, 5669, 5696, 5726, 5751, 5798,
5806, 5844, 5862, 5874, 5885, 5914, 5946, 5955, 5982, 6007, 6044, 6071, 5836, 5854, 5866, 5877, 5906, 5938, 5947, 5974, 5999, 6036, 6063, 6079,
6087, 6115, 6121, 6129, 6140, 6155, 6172, 6182, 6208, 6215, 6241, 6261, 6107, 6113, 6121, 6132, 6147, 6164, 6174, 6200, 6207, 6233, 6253, 6282,
6290, 6295, 6302, 6309, 6314, 6340, 6346, 6351, 6357, 6361, 6400, 6427, 6287, 6292, 6318, 6324, 6329, 6335, 6339, 6378, 6405, 6433, 6452, 6476,
6455, 6474, 6498, 6523, 6534, 6539, 6543, 6547, 6556, 6565, 6575, 6586, 6501, 6512, 6517, 6521, 6525, 6534, 6543, 6553, 6564, 6571, 6580, 6598,
6593, 6602, 6620,
}; };
const char STRINGS_PO_DATA[] = const char STRINGS_PO_DATA[] =
@@ -5239,7 +5220,6 @@ const char STRINGS_PO_DATA[] =
"Navegador OPDS\0" "Navegador OPDS\0"
"Capa + personalizado\0" "Capa + personalizado\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Livros recentes\0" "Livros recentes\0"
"Sem livros recentes\0" "Sem livros recentes\0"
"Usar transfer\xC3" "Usar transfer\xC3"
@@ -5380,8 +5360,6 @@ const char STRINGS_PO_DATA[] =
"Auto Turn Enabled: \0" "Auto Turn Enabled: \0"
"Auto Turn (Pages Per Minute)\0" "Auto Turn (Pages Per Minute)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -5431,15 +5409,14 @@ const uint16_t OFFSETS_PO[] = {
4090, 4100, 4109, 4118, 4124, 4131, 4148, 4152, 4157, 4162, 4167, 4172, 4090, 4100, 4109, 4118, 4124, 4131, 4148, 4152, 4157, 4162, 4167, 4172,
4178, 4192, 4201, 4209, 4214, 4220, 4223, 4257, 4267, 4288, 4307, 4332, 4178, 4192, 4201, 4209, 4214, 4220, 4223, 4257, 4267, 4288, 4307, 4332,
4345, 4368, 4373, 4380, 4386, 4391, 4399, 4410, 4421, 4429, 4435, 4443, 4345, 4368, 4373, 4380, 4386, 4391, 4399, 4410, 4421, 4429, 4435, 4443,
4461, 4471, 4476, 4490, 4517, 4543, 4558, 4579, 4592, 4600, 4616, 4636, 4461, 4471, 4476, 4490, 4517, 4543, 4558, 4579, 4592, 4608, 4628, 4668,
4676, 4717, 4726, 4749, 4764, 4771, 4778, 4786, 4833, 4849, 4864, 4921, 4709, 4718, 4741, 4756, 4763, 4770, 4778, 4825, 4841, 4856, 4913, 4962,
4970, 4990, 5013, 5035, 5056, 5066, 5084, 5106, 5129, 5137, 5144, 5160, 4982, 5005, 5027, 5048, 5058, 5076, 5098, 5121, 5129, 5136, 5152, 5163,
5171, 5183, 5190, 5232, 5261, 5289, 5321, 5359, 5388, 5415, 5445, 5467, 5175, 5182, 5224, 5253, 5281, 5313, 5351, 5380, 5407, 5437, 5459, 5490,
5498, 5548, 5570, 5578, 5585, 5610, 5638, 5645, 5670, 5693, 5728, 5752, 5540, 5562, 5570, 5577, 5602, 5630, 5637, 5662, 5685, 5720, 5744, 5763,
5771, 5796, 5804, 5811, 5827, 5843, 5864, 5874, 5900, 5907, 5921, 5941, 5788, 5796, 5803, 5819, 5835, 5856, 5866, 5892, 5899, 5913, 5933, 5962,
5970, 5975, 5982, 5989, 5994, 6020, 6026, 6031, 6037, 6041, 6080, 6107, 5967, 5972, 5998, 6004, 6009, 6015, 6019, 6058, 6085, 6113, 6132, 6156,
6135, 6154, 6178, 6203, 6214, 6219, 6223, 6227, 6236, 6245, 6255, 6266, 6181, 6192, 6197, 6201, 6205, 6214, 6223, 6233, 6244, 6251, 6260, 6278,
6273, 6282, 6300,
}; };
const char STRINGS_RU_DATA[] = const char STRINGS_RU_DATA[] =
@@ -10999,7 +10976,6 @@ const char STRINGS_RU_DATA[] =
"\xB9" "\xB9"
"\0" "\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"\xD0" "\xD0"
"\x9D" "\x9D"
"\xD0" "\xD0"
@@ -12998,8 +12974,6 @@ const char STRINGS_RU_DATA[] =
"\x83" "\x83"
")\0" ")\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -13049,15 +13023,14 @@ const uint16_t OFFSETS_RU[] = {
5973, 5985, 5998, 6010, 6025, 6040, 6059, 6064, 6071, 6088, 6101, 6108, 5973, 5985, 5998, 6010, 6025, 6040, 6059, 6064, 6071, 6088, 6101, 6108,
6117, 6145, 6156, 6169, 6180, 6189, 6192, 6225, 6242, 6293, 6340, 6372, 6117, 6145, 6156, 6169, 6180, 6189, 6192, 6225, 6242, 6293, 6340, 6372,
6404, 6459, 6472, 6487, 6502, 6513, 6524, 6538, 6566, 6591, 6608, 6623, 6404, 6459, 6472, 6487, 6502, 6513, 6524, 6538, 6566, 6591, 6608, 6623,
6653, 6678, 6683, 6697, 6741, 6798, 6818, 6844, 6857, 6865, 6893, 6926, 6653, 6678, 6683, 6697, 6741, 6798, 6818, 6844, 6857, 6885, 6918, 6993,
7001, 7078, 7091, 7115, 7134, 7147, 7164, 7188, 7249, 7273, 7299, 7380, 7070, 7083, 7107, 7126, 7139, 7156, 7180, 7241, 7265, 7291, 7372, 7456,
7464, 7495, 7538, 7569, 7602, 7622, 7642, 7692, 7725, 7740, 7747, 7805, 7487, 7530, 7561, 7594, 7614, 7634, 7684, 7717, 7732, 7739, 7797, 7809,
7817, 7828, 7840, 7885, 7939, 7984, 8028, 8093, 8155, 8182, 8212, 8251, 7820, 7832, 7877, 7931, 7976, 8020, 8085, 8147, 8174, 8204, 8243, 8298,
8306, 8373, 8404, 8424, 8444, 8483, 8506, 8515, 8570, 8625, 8679, 8729, 8365, 8396, 8416, 8436, 8475, 8498, 8507, 8562, 8617, 8671, 8721, 8758,
8766, 8806, 8819, 8838, 8860, 8892, 8916, 8937, 9000, 9015, 9056, 9097, 8798, 8811, 8830, 8852, 8884, 8908, 8929, 8992, 9007, 9048, 9089, 9146,
9154, 9159, 9166, 9173, 9178, 9204, 9210, 9215, 9221, 9225, 9264, 9291, 9151, 9156, 9182, 9188, 9193, 9199, 9203, 9242, 9269, 9297, 9316, 9340,
9319, 9338, 9362, 9387, 9398, 9403, 9407, 9411, 9420, 9429, 9439, 9450, 9365, 9376, 9381, 9385, 9389, 9398, 9407, 9417, 9428, 9435, 9444, 9462,
9457, 9466, 9484,
}; };
const char STRINGS_SV_DATA[] = const char STRINGS_SV_DATA[] =
@@ -13662,7 +13635,6 @@ const char STRINGS_SV_DATA[] =
"sare\0" "sare\0"
"Omslag + Valfri\0" "Omslag + Valfri\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Senaste b\xC3" "Senaste b\xC3"
"\xB6" "\xB6"
"ckerna\0" "ckerna\0"
@@ -13825,8 +13797,6 @@ const char STRINGS_SV_DATA[] =
"\xA4" "\xA4"
"ndning (sidor per minut)\0" "ndning (sidor per minut)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -13876,15 +13846,14 @@ const uint16_t OFFSETS_SV[] = {
3961, 3971, 3978, 3985, 3992, 4002, 4016, 4019, 4023, 4028, 4034, 4038, 3961, 3971, 3978, 3985, 3992, 4002, 4016, 4019, 4023, 4028, 4034, 4038,
4041, 4056, 4065, 4072, 4076, 4080, 4085, 4113, 4122, 4142, 4164, 4189, 4041, 4056, 4065, 4072, 4076, 4080, 4085, 4113, 4122, 4142, 4164, 4189,
4208, 4240, 4245, 4252, 4258, 4262, 4270, 4281, 4290, 4310, 4316, 4324, 4208, 4240, 4245, 4252, 4258, 4262, 4270, 4281, 4290, 4310, 4316, 4324,
4350, 4359, 4364, 4377, 4403, 4423, 4440, 4456, 4469, 4477, 4495, 4516, 4350, 4359, 4364, 4377, 4403, 4423, 4440, 4456, 4469, 4487, 4508, 4555,
4563, 4608, 4614, 4632, 4645, 4652, 4658, 4667, 4705, 4716, 4732, 4781, 4600, 4606, 4624, 4637, 4644, 4650, 4659, 4697, 4708, 4724, 4773, 4811,
4819, 4841, 4867, 4893, 4918, 4929, 4937, 4961, 4977, 4984, 4991, 5012, 4833, 4859, 4885, 4910, 4921, 4929, 4953, 4969, 4976, 4983, 5004, 5013,
5021, 5033, 5038, 5082, 5114, 5135, 5158, 5197, 5220, 5247, 5277, 5297, 5025, 5030, 5074, 5106, 5127, 5150, 5189, 5212, 5239, 5269, 5289, 5315,
5323, 5364, 5380, 5388, 5396, 5419, 5445, 5457, 5480, 5506, 5532, 5562, 5356, 5372, 5380, 5388, 5411, 5437, 5449, 5472, 5498, 5524, 5554, 5575,
5583, 5611, 5619, 5631, 5639, 5654, 5672, 5681, 5714, 5722, 5739, 5772, 5603, 5611, 5623, 5631, 5646, 5664, 5673, 5706, 5714, 5731, 5764, 5803,
5811, 5816, 5823, 5830, 5835, 5861, 5867, 5872, 5878, 5882, 5921, 5948, 5808, 5813, 5839, 5845, 5850, 5856, 5860, 5899, 5926, 5954, 5973, 5997,
5976, 5995, 6019, 6044, 6055, 6060, 6064, 6068, 6077, 6086, 6096, 6107, 6022, 6033, 6038, 6042, 6046, 6055, 6064, 6074, 6085, 6092, 6101, 6119,
6114, 6123, 6141,
}; };
const char STRINGS_RO_DATA[] = const char STRINGS_RO_DATA[] =
@@ -14598,7 +14567,6 @@ const char STRINGS_RO_DATA[] =
"\x83" "\x83"
" + Personalizat\0" " + Personalizat\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"C\xC4" "C\xC4"
"\x83" "\x83"
"r\xC5" "r\xC5"
@@ -14791,8 +14759,6 @@ const char STRINGS_RO_DATA[] =
": \0" ": \0"
"Pagini pe minut\0" "Pagini pe minut\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -14842,15 +14808,14 @@ const uint16_t OFFSETS_RO[] = {
4235, 4245, 4253, 4263, 4274, 4284, 4297, 4300, 4303, 4314, 4322, 4329, 4235, 4245, 4253, 4263, 4274, 4284, 4297, 4300, 4303, 4314, 4322, 4329,
4335, 4348, 4356, 4364, 4368, 4372, 4375, 4398, 4407, 4434, 4463, 4488, 4335, 4348, 4356, 4364, 4368, 4372, 4375, 4398, 4407, 4434, 4463, 4488,
4505, 4530, 4539, 4545, 4553, 4559, 4567, 4580, 4596, 4611, 4617, 4625, 4505, 4530, 4539, 4545, 4553, 4559, 4567, 4580, 4596, 4611, 4617, 4625,
4633, 4640, 4645, 4659, 4687, 4713, 4726, 4750, 4763, 4771, 4787, 4808, 4633, 4640, 4645, 4659, 4687, 4713, 4726, 4750, 4763, 4779, 4800, 4861,
4869, 4918, 4926, 4946, 4958, 4964, 4974, 4983, 5029, 5040, 5054, 5104, 4910, 4918, 4938, 4950, 4956, 4966, 4975, 5021, 5032, 5046, 5096, 5134,
5142, 5162, 5185, 5205, 5225, 5239, 5246, 5267, 5291, 5302, 5309, 5336, 5154, 5177, 5197, 5217, 5231, 5238, 5259, 5283, 5294, 5301, 5328, 5338,
5346, 5359, 5367, 5407, 5441, 5465, 5502, 5545, 5587, 5614, 5644, 5672, 5351, 5359, 5399, 5433, 5457, 5494, 5537, 5579, 5606, 5636, 5664, 5694,
5702, 5743, 5759, 5767, 5774, 5802, 5833, 5845, 5870, 5899, 5928, 5960, 5735, 5751, 5759, 5766, 5794, 5825, 5837, 5862, 5891, 5920, 5952, 5972,
5980, 6002, 6013, 6025, 6041, 6058, 6074, 6089, 6111, 6118, 6133, 6155, 5994, 6005, 6017, 6033, 6050, 6066, 6081, 6103, 6110, 6125, 6147, 6163,
6171, 6176, 6183, 6190, 6195, 6221, 6227, 6232, 6238, 6242, 6281, 6308, 6168, 6173, 6199, 6205, 6210, 6216, 6220, 6259, 6286, 6314, 6333, 6357,
6336, 6355, 6379, 6404, 6415, 6420, 6424, 6428, 6437, 6446, 6456, 6467, 6382, 6393, 6398, 6402, 6406, 6415, 6424, 6434, 6445, 6452, 6461, 6479,
6474, 6483, 6501,
}; };
const char STRINGS_CA_DATA[] = const char STRINGS_CA_DATA[] =
@@ -15336,7 +15301,6 @@ const char STRINGS_CA_DATA[] =
"Navegador OPDS\0" "Navegador OPDS\0"
"Portada + Personalitzat\0" "Portada + Personalitzat\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Llibres recents\0" "Llibres recents\0"
"No hi ha llibres recents\0" "No hi ha llibres recents\0"
"Usa les transfer\xC3" "Usa les transfer\xC3"
@@ -15479,8 +15443,6 @@ const char STRINGS_CA_DATA[] =
"\xA0" "\xA0"
"gines per minut)\0" "gines per minut)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -15530,15 +15492,14 @@ const uint16_t OFFSETS_CA[] = {
4469, 4478, 4489, 4498, 4503, 4514, 4525, 4529, 4532, 4540, 4547, 4550, 4469, 4478, 4489, 4498, 4503, 4514, 4525, 4529, 4532, 4540, 4547, 4550,
4554, 4567, 4576, 4582, 4588, 4594, 4597, 4626, 4635, 4665, 4700, 4735, 4554, 4567, 4576, 4582, 4588, 4594, 4597, 4626, 4635, 4665, 4700, 4735,
4753, 4783, 4788, 4796, 4805, 4812, 4821, 4833, 4851, 4865, 4872, 4880, 4753, 4783, 4788, 4796, 4805, 4812, 4821, 4833, 4851, 4865, 4872, 4880,
4903, 4912, 4917, 4930, 4965, 4995, 5010, 5034, 5047, 5055, 5071, 5096, 4903, 4912, 4917, 4930, 4965, 4995, 5010, 5034, 5047, 5063, 5088, 5134,
5142, 5180, 5187, 5218, 5228, 5234, 5242, 5254, 5293, 5305, 5317, 5376, 5172, 5179, 5210, 5220, 5226, 5234, 5246, 5285, 5297, 5309, 5368, 5417,
5425, 5443, 5463, 5483, 5500, 5509, 5523, 5547, 5582, 5590, 5597, 5624, 5435, 5455, 5475, 5492, 5501, 5515, 5539, 5574, 5582, 5589, 5616, 5627,
5635, 5650, 5659, 5697, 5733, 5767, 5809, 5853, 5891, 5918, 5948, 5978, 5642, 5651, 5689, 5725, 5759, 5801, 5845, 5883, 5910, 5940, 5970, 6002,
6010, 6062, 6084, 6091, 6098, 6123, 6151, 6160, 6185, 6208, 6238, 6270, 6054, 6076, 6083, 6090, 6115, 6143, 6152, 6177, 6200, 6230, 6262, 6278,
6286, 6310, 6319, 6324, 6341, 6357, 6379, 6392, 6433, 6443, 6471, 6499, 6302, 6311, 6316, 6333, 6349, 6371, 6384, 6425, 6435, 6463, 6491, 6530,
6538, 6543, 6550, 6557, 6562, 6588, 6594, 6599, 6605, 6609, 6648, 6675, 6535, 6540, 6566, 6572, 6577, 6583, 6587, 6626, 6653, 6681, 6700, 6724,
6703, 6722, 6746, 6771, 6782, 6787, 6791, 6795, 6804, 6813, 6823, 6834, 6749, 6760, 6765, 6769, 6773, 6782, 6791, 6801, 6812, 6819, 6828, 6846,
6841, 6850, 6868,
}; };
const char STRINGS_UK_DATA[] = const char STRINGS_UK_DATA[] =
@@ -21816,7 +21777,6 @@ const char STRINGS_UK_DATA[] =
"\xB0" "\xB0"
"\0" "\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"\xD0" "\xD0"
"\x9E" "\x9E"
"\xD1" "\xD1"
@@ -23933,8 +23893,6 @@ const char STRINGS_UK_DATA[] =
"\xB2" "\xB2"
")\0" ")\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -23984,15 +23942,14 @@ const uint16_t OFFSETS_UK[] = {
6651, 6674, 6693, 6707, 6724, 6738, 6752, 6759, 6764, 6781, 6796, 6807, 6651, 6674, 6693, 6707, 6724, 6738, 6752, 6759, 6764, 6781, 6796, 6807,
6816, 6844, 6853, 6864, 6875, 6884, 6887, 6941, 6958, 7003, 7054, 7094, 6816, 6844, 6853, 6864, 6875, 6884, 6887, 6941, 6958, 7003, 7054, 7094,
7122, 7165, 7178, 7195, 7208, 7219, 7232, 7248, 7270, 7287, 7298, 7319, 7122, 7165, 7178, 7195, 7208, 7219, 7232, 7248, 7270, 7287, 7298, 7319,
7349, 7366, 7371, 7385, 7445, 7496, 7516, 7566, 7579, 7587, 7613, 7650, 7349, 7366, 7371, 7385, 7445, 7496, 7516, 7566, 7579, 7605, 7642, 7738,
7746, 7829, 7842, 7866, 7891, 7904, 7921, 7953, 8029, 8055, 8083, 8162, 7821, 7834, 7858, 7883, 7896, 7913, 7945, 8021, 8047, 8075, 8154, 8232,
8240, 8273, 8318, 8349, 8382, 8404, 8424, 8466, 8501, 8518, 8525, 8574, 8265, 8310, 8341, 8374, 8396, 8416, 8458, 8493, 8510, 8517, 8566, 8581,
8589, 8612, 8625, 8681, 8731, 8770, 8822, 8887, 8949, 8976, 9006, 9051, 8604, 8617, 8673, 8723, 8762, 8814, 8879, 8941, 8968, 8998, 9043, 9097,
9105, 9195, 9228, 9250, 9270, 9313, 9359, 9372, 9431, 9488, 9550, 9604, 9187, 9220, 9242, 9262, 9305, 9351, 9364, 9423, 9480, 9542, 9596, 9635,
9643, 9690, 9704, 9727, 9749, 9781, 9805, 9818, 9871, 9892, 9918, 9964, 9682, 9696, 9719, 9741, 9773, 9797, 9810, 9863, 9884, 9910, 9956, 10001,
10009, 10014, 10021, 10028, 10033, 10059, 10065, 10070, 10076, 10080, 10119, 10146, 10006, 10011, 10037, 10043, 10048, 10054, 10058, 10097, 10124, 10152, 10171, 10195,
10174, 10193, 10217, 10242, 10253, 10258, 10262, 10266, 10275, 10284, 10294, 10305, 10220, 10231, 10236, 10240, 10244, 10253, 10262, 10272, 10283, 10290, 10299, 10317,
10312, 10321, 10339,
}; };
const char STRINGS_BE_DATA[] = const char STRINGS_BE_DATA[] =
@@ -29182,7 +29139,6 @@ const char STRINGS_BE_DATA[] =
"\xB9" "\xB9"
"\0" "\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"\xD0" "\xD0"
"\x9D" "\x9D"
"\xD1" "\xD1"
@@ -30947,8 +30903,6 @@ const char STRINGS_BE_DATA[] =
"Auto Turn Enabled: \0" "Auto Turn Enabled: \0"
"Auto Turn (Pages Per Minute)\0" "Auto Turn (Pages Per Minute)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -30998,15 +30952,14 @@ const uint16_t OFFSETS_BE[] = {
6034, 6044, 6057, 6069, 6084, 6105, 6124, 6131, 6136, 6141, 6146, 6153, 6034, 6044, 6057, 6069, 6084, 6105, 6124, 6131, 6136, 6141, 6146, 6153,
6162, 6190, 6201, 6214, 6225, 6234, 6237, 6270, 6287, 6308, 6327, 6352, 6162, 6190, 6201, 6214, 6225, 6234, 6237, 6270, 6287, 6308, 6327, 6352,
6365, 6388, 6393, 6400, 6406, 6411, 6419, 6430, 6441, 6449, 6455, 6463, 6365, 6388, 6393, 6400, 6406, 6411, 6419, 6430, 6441, 6449, 6455, 6463,
6493, 6512, 6517, 6531, 6575, 6632, 6652, 6680, 6693, 6701, 6729, 6764, 6493, 6512, 6517, 6531, 6575, 6632, 6652, 6680, 6693, 6721, 6756, 6835,
6843, 6918, 6931, 6955, 6970, 6983, 7000, 7024, 7085, 7111, 7139, 7218, 6910, 6923, 6947, 6962, 6975, 6992, 7016, 7077, 7103, 7131, 7210, 7294,
7302, 7333, 7376, 7407, 7440, 7464, 7486, 7530, 7565, 7572, 7579, 7595, 7325, 7368, 7399, 7432, 7456, 7478, 7522, 7557, 7564, 7571, 7587, 7603,
7611, 7624, 7636, 7681, 7735, 7774, 7824, 7887, 7947, 7974, 8004, 8041, 7616, 7628, 7673, 7727, 7766, 7816, 7879, 7939, 7966, 7996, 8033, 8090,
8098, 8170, 8205, 8223, 8241, 8280, 8303, 8312, 8363, 8414, 8470, 8520, 8162, 8197, 8215, 8233, 8272, 8295, 8304, 8355, 8406, 8462, 8512, 8549,
8557, 8599, 8614, 8633, 8655, 8685, 8709, 8719, 8745, 8752, 8793, 8813, 8591, 8606, 8625, 8647, 8677, 8701, 8711, 8737, 8744, 8785, 8805, 8834,
8842, 8847, 8854, 8861, 8866, 8892, 8898, 8903, 8909, 8913, 8952, 8979, 8839, 8844, 8870, 8876, 8881, 8887, 8891, 8930, 8957, 8985, 9004, 9028,
9007, 9026, 9050, 9075, 9086, 9091, 9095, 9099, 9108, 9117, 9127, 9138, 9053, 9064, 9069, 9073, 9077, 9086, 9095, 9105, 9116, 9123, 9132, 9150,
9145, 9154, 9172,
}; };
const char STRINGS_IT_DATA[] = const char STRINGS_IT_DATA[] =
@@ -31310,7 +31263,6 @@ const char STRINGS_IT_DATA[] =
"Browser OPDS\0" "Browser OPDS\0"
"Copertina + Personalizzato\0" "Copertina + Personalizzato\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Libri Recenti\0" "Libri Recenti\0"
"Nessun libro recente\0" "Nessun libro recente\0"
"Usa i trasferimenti wireless del dispositivo di Calibre\0" "Usa i trasferimenti wireless del dispositivo di Calibre\0"
@@ -31389,8 +31341,6 @@ const char STRINGS_IT_DATA[] =
"Auto Turn Enabled: \0" "Auto Turn Enabled: \0"
"Auto Turn (Pages Per Minute)\0" "Auto Turn (Pages Per Minute)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -31440,15 +31390,14 @@ const uint16_t OFFSETS_IT[] = {
4219, 4228, 4236, 4245, 4250, 4258, 4266, 4270, 4273, 4278, 4283, 4286, 4219, 4228, 4236, 4245, 4250, 4258, 4266, 4270, 4273, 4278, 4283, 4286,
4290, 4304, 4312, 4318, 4321, 4326, 4329, 4362, 4372, 4393, 4412, 4437, 4290, 4304, 4312, 4318, 4321, 4326, 4329, 4362, 4372, 4393, 4412, 4437,
4450, 4473, 4478, 4485, 4491, 4496, 4504, 4515, 4526, 4534, 4540, 4548, 4450, 4473, 4478, 4485, 4491, 4496, 4504, 4515, 4526, 4534, 4540, 4548,
4556, 4565, 4570, 4582, 4613, 4639, 4652, 4679, 4692, 4700, 4714, 4735, 4556, 4565, 4570, 4582, 4613, 4639, 4652, 4679, 4692, 4706, 4727, 4783,
4791, 4844, 4854, 4880, 4895, 4901, 4909, 4921, 4966, 4980, 4995, 5047, 4836, 4846, 4872, 4887, 4893, 4901, 4913, 4958, 4972, 4987, 5039, 5081,
5089, 5113, 5137, 5161, 5183, 5192, 5206, 5228, 5248, 5255, 5262, 5278, 5105, 5129, 5153, 5175, 5184, 5198, 5220, 5240, 5247, 5254, 5270, 5281,
5289, 5302, 5310, 5346, 5380, 5407, 5442, 5483, 5512, 5539, 5569, 5594, 5294, 5302, 5338, 5372, 5399, 5434, 5475, 5504, 5531, 5561, 5586, 5618,
5626, 5672, 5691, 5699, 5707, 5735, 5766, 5775, 5800, 5824, 5856, 5887, 5664, 5683, 5691, 5699, 5727, 5758, 5767, 5792, 5816, 5848, 5879, 5899,
5907, 5932, 5941, 5948, 5964, 5980, 6000, 6010, 6036, 6043, 6061, 6081, 5924, 5933, 5940, 5956, 5972, 5992, 6002, 6028, 6035, 6053, 6073, 6102,
6110, 6115, 6122, 6129, 6134, 6160, 6166, 6171, 6177, 6181, 6220, 6247, 6107, 6112, 6138, 6144, 6149, 6155, 6159, 6198, 6225, 6253, 6272, 6296,
6275, 6294, 6318, 6343, 6354, 6359, 6363, 6367, 6376, 6385, 6395, 6406, 6321, 6332, 6337, 6341, 6345, 6354, 6363, 6373, 6384, 6391, 6400, 6418,
6413, 6422, 6440,
}; };
const char STRINGS_PL_DATA[] = const char STRINGS_PL_DATA[] =
@@ -32172,7 +32121,6 @@ const char STRINGS_PL_DATA[] =
"\x82" "\x82"
"asne\0" "asne\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Ostatnio czytane\0" "Ostatnio czytane\0"
"Brak ostatnio czytanych\0" "Brak ostatnio czytanych\0"
"Przesy\xC5" "Przesy\xC5"
@@ -32371,8 +32319,6 @@ const char STRINGS_PL_DATA[] =
"Auto-kartkowanie: \0" "Auto-kartkowanie: \0"
"Auto-kartkowanie (str./min)\0" "Auto-kartkowanie (str./min)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -32422,15 +32368,14 @@ const uint16_t OFFSETS_PL[] = {
4101, 4112, 4119, 4128, 4136, 4144, 4151, 4155, 4159, 4166, 4172, 4177, 4101, 4112, 4119, 4128, 4136, 4144, 4151, 4155, 4159, 4166, 4172, 4177,
4183, 4197, 4202, 4208, 4214, 4220, 4223, 4249, 4258, 4285, 4303, 4321, 4183, 4197, 4202, 4208, 4214, 4220, 4223, 4249, 4258, 4285, 4303, 4321,
4336, 4361, 4368, 4376, 4382, 4392, 4402, 4415, 4432, 4441, 4448, 4456, 4336, 4361, 4368, 4376, 4382, 4392, 4402, 4415, 4432, 4441, 4448, 4456,
4467, 4475, 4480, 4494, 4536, 4567, 4580, 4599, 4612, 4620, 4637, 4661, 4467, 4475, 4480, 4494, 4536, 4567, 4580, 4599, 4612, 4629, 4653, 4689,
4697, 4736, 4745, 4768, 4774, 4781, 4791, 4802, 4851, 4865, 4881, 4925, 4728, 4737, 4760, 4766, 4773, 4783, 4794, 4843, 4857, 4873, 4917, 4961,
4969, 4989, 5013, 5031, 5050, 5060, 5088, 5111, 5148, 5154, 5161, 5188, 4981, 5005, 5023, 5042, 5052, 5080, 5103, 5140, 5146, 5153, 5180, 5192,
5200, 5212, 5224, 5263, 5296, 5320, 5350, 5384, 5415, 5442, 5472, 5494, 5204, 5216, 5255, 5288, 5312, 5342, 5376, 5407, 5434, 5464, 5486, 5519,
5527, 5563, 5583, 5591, 5600, 5628, 5659, 5668, 5692, 5718, 5751, 5778, 5555, 5575, 5583, 5592, 5620, 5651, 5660, 5684, 5710, 5743, 5770, 5788,
5796, 5820, 5828, 5836, 5851, 5874, 5891, 5900, 5931, 5938, 5957, 5976, 5812, 5820, 5828, 5843, 5866, 5883, 5892, 5923, 5930, 5949, 5968, 5996,
6004, 6009, 6016, 6023, 6028, 6054, 6060, 6065, 6071, 6075, 6114, 6141, 6001, 6006, 6032, 6038, 6043, 6049, 6053, 6092, 6119, 6147, 6166, 6190,
6169, 6188, 6212, 6237, 6248, 6253, 6257, 6261, 6270, 6279, 6289, 6300, 6215, 6226, 6231, 6235, 6239, 6248, 6257, 6267, 6278, 6285, 6294, 6312,
6307, 6316, 6334,
}; };
const char STRINGS_FI_DATA[] = const char STRINGS_FI_DATA[] =
@@ -33004,7 +32949,6 @@ const char STRINGS_FI_DATA[] =
"OPDS-selain\0" "OPDS-selain\0"
"Kansi + mukautettu\0" "Kansi + mukautettu\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Viimeisimm\xC3" "Viimeisimm\xC3"
"\xA4" "\xA4"
"t kirjat\0" "t kirjat\0"
@@ -33169,8 +33113,6 @@ const char STRINGS_FI_DATA[] =
"Auto Turn Enabled: \0" "Auto Turn Enabled: \0"
"Auto Turn (Pages Per Minute)\0" "Auto Turn (Pages Per Minute)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -33220,15 +33162,14 @@ const uint16_t OFFSETS_FI[] = {
4076, 4085, 4093, 4102, 4107, 4113, 4130, 4137, 4140, 4145, 4150, 4160, 4076, 4085, 4093, 4102, 4107, 4113, 4130, 4137, 4140, 4145, 4150, 4160,
4165, 4177, 4183, 4189, 4195, 4200, 4203, 4234, 4244, 4265, 4284, 4309, 4165, 4177, 4183, 4189, 4195, 4200, 4203, 4234, 4244, 4265, 4284, 4309,
4322, 4345, 4350, 4357, 4363, 4368, 4376, 4387, 4398, 4406, 4412, 4420, 4322, 4345, 4350, 4357, 4363, 4368, 4376, 4387, 4398, 4406, 4412, 4420,
4443, 4453, 4458, 4472, 4505, 4539, 4551, 4570, 4583, 4591, 4612, 4637, 4443, 4453, 4458, 4472, 4505, 4539, 4551, 4570, 4583, 4604, 4629, 4672,
4680, 4726, 4733, 4762, 4772, 4777, 4787, 4794, 4835, 4851, 4867, 4909, 4718, 4725, 4754, 4764, 4769, 4779, 4786, 4827, 4843, 4859, 4901, 4947,
4955, 4977, 4999, 5018, 5037, 5054, 5068, 5090, 5116, 5123, 5130, 5146, 4969, 4991, 5010, 5029, 5046, 5060, 5082, 5108, 5115, 5122, 5138, 5145,
5153, 5165, 5173, 5211, 5244, 5267, 5307, 5351, 5379, 5406, 5436, 5470, 5157, 5165, 5203, 5236, 5259, 5299, 5343, 5371, 5398, 5428, 5462, 5492,
5500, 5537, 5558, 5564, 5577, 5609, 5644, 5657, 5682, 5715, 5745, 5773, 5529, 5550, 5556, 5569, 5601, 5636, 5649, 5674, 5707, 5737, 5765, 5789,
5797, 5823, 5829, 5838, 5851, 5866, 5889, 5899, 5925, 5932, 5949, 5969, 5815, 5821, 5830, 5843, 5858, 5881, 5891, 5917, 5924, 5941, 5961, 5990,
5998, 6003, 6010, 6017, 6022, 6048, 6054, 6059, 6065, 6069, 6108, 6135, 5995, 6000, 6026, 6032, 6037, 6043, 6047, 6086, 6113, 6141, 6160, 6184,
6163, 6182, 6206, 6231, 6242, 6247, 6251, 6255, 6264, 6273, 6283, 6294, 6209, 6220, 6225, 6229, 6233, 6242, 6251, 6261, 6272, 6279, 6288, 6306,
6301, 6310, 6328,
}; };
const char STRINGS_DA_DATA[] = const char STRINGS_DA_DATA[] =
@@ -33666,7 +33607,6 @@ const char STRINGS_DA_DATA[] =
"OPDS Browser\0" "OPDS Browser\0"
"Omslag + Brugerdefineret\0" "Omslag + Brugerdefineret\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Seneste b\xC3" "Seneste b\xC3"
"\xB8" "\xB8"
"ger\0" "ger\0"
@@ -33765,8 +33705,6 @@ const char STRINGS_DA_DATA[] =
"Auto Turn Enabled: \0" "Auto Turn Enabled: \0"
"Auto Turn (Pages Per Minute)\0" "Auto Turn (Pages Per Minute)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -33816,15 +33754,14 @@ const uint16_t OFFSETS_DA[] = {
3824, 3833, 3842, 3850, 3855, 3864, 3875, 3878, 3882, 3887, 3892, 3899, 3824, 3833, 3842, 3850, 3855, 3864, 3875, 3878, 3882, 3887, 3892, 3899,
3907, 3923, 3931, 3938, 3941, 3945, 3948, 3975, 3984, 4005, 4024, 4049, 3907, 3923, 3931, 3938, 3941, 3945, 3948, 3975, 3984, 4005, 4024, 4049,
4062, 4085, 4090, 4097, 4103, 4108, 4116, 4127, 4138, 4146, 4152, 4160, 4062, 4085, 4090, 4097, 4103, 4108, 4116, 4127, 4138, 4146, 4152, 4160,
4184, 4193, 4198, 4212, 4234, 4256, 4269, 4294, 4307, 4315, 4330, 4351, 4184, 4193, 4198, 4212, 4234, 4256, 4269, 4294, 4307, 4322, 4343, 4385,
4393, 4434, 4439, 4458, 4469, 4476, 4480, 4489, 4526, 4539, 4556, 4596, 4426, 4431, 4450, 4461, 4468, 4472, 4481, 4518, 4531, 4548, 4588, 4623,
4631, 4649, 4668, 4686, 4703, 4713, 4727, 4750, 4764, 4771, 4778, 4794, 4641, 4660, 4678, 4695, 4705, 4719, 4742, 4756, 4763, 4770, 4786, 4796,
4804, 4816, 4822, 4860, 4892, 4913, 4939, 4972, 4998, 5025, 5055, 5078, 4808, 4814, 4852, 4884, 4905, 4931, 4964, 4990, 5017, 5047, 5070, 5114,
5122, 5160, 5179, 5188, 5195, 5218, 5244, 5254, 5277, 5302, 5331, 5359, 5152, 5171, 5180, 5187, 5210, 5236, 5246, 5269, 5294, 5323, 5351, 5372,
5380, 5407, 5415, 5422, 5434, 5449, 5465, 5475, 5501, 5508, 5526, 5546, 5399, 5407, 5414, 5426, 5441, 5457, 5467, 5493, 5500, 5518, 5538, 5567,
5575, 5580, 5587, 5594, 5599, 5625, 5631, 5636, 5642, 5646, 5685, 5712, 5572, 5577, 5603, 5609, 5614, 5620, 5624, 5663, 5690, 5718, 5737, 5761,
5740, 5759, 5783, 5808, 5819, 5824, 5828, 5832, 5841, 5850, 5860, 5871, 5786, 5797, 5802, 5806, 5810, 5819, 5828, 5838, 5849, 5856, 5865, 5883,
5878, 5887, 5905,
}; };
const char STRINGS_NL_DATA[] = const char STRINGS_NL_DATA[] =
@@ -33892,10 +33829,10 @@ const char STRINGS_NL_DATA[] =
"Batterij % verbergen\0" "Batterij % verbergen\0"
"Extra regelafstand alinea\0" "Extra regelafstand alinea\0"
"Tekst Anti-Aliasing\0" "Tekst Anti-Aliasing\0"
"Images\0" "Afbeeldingen\0"
"Display\0" "Weergave\0"
"Placeholder\0" "Placeholder\0"
"Suppress\0" "Verbergen\0"
"Create fallback for invalid TOC\0" "Create fallback for invalid TOC\0"
"Korte klik aan/uit-knop\0" "Korte klik aan/uit-knop\0"
"Leesstand\0" "Leesstand\0"
@@ -33908,7 +33845,7 @@ const char STRINGS_NL_DATA[] =
"Uitlijning alinea lezer\0" "Uitlijning alinea lezer\0"
"Woordafbreking\0" "Woordafbreking\0"
"Tijd tot slaapstand\0" "Tijd tot slaapstand\0"
"Show Hidden Files\0" "Toon verborgen bestanden\0"
"Use Clock\0" "Use Clock\0"
"Clock Settings\0" "Clock Settings\0"
"Uses more battery; clock may drift\0" "Uses more battery; clock may drift\0"
@@ -34064,7 +34001,7 @@ const char STRINGS_NL_DATA[] =
"\xAB" "\xAB"
" Home\0" " Home\0"
"Kies\0" "Kies\0"
"Selected\0" "Geselecteerd\0"
"Wissel\0" "Wissel\0"
"Bevestig\0" "Bevestig\0"
"Annuleer\0" "Annuleer\0"
@@ -34110,7 +34047,6 @@ const char STRINGS_NL_DATA[] =
"OPDS-browser\0" "OPDS-browser\0"
"Omslag + Aangepast\0" "Omslag + Aangepast\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Recente boeken\0" "Recente boeken\0"
"Geen recente boeken\0" "Geen recente boeken\0"
"Gebruik Calibre draadloze overdracht\0" "Gebruik Calibre draadloze overdracht\0"
@@ -34134,7 +34070,7 @@ const char STRINGS_NL_DATA[] =
"Naar Home\0" "Naar Home\0"
"Voortgang synchroniseren\0" "Voortgang synchroniseren\0"
"Boekcache verwijderen\0" "Boekcache verwijderen\0"
"Delete\0" "Verwijder\0"
"Remove\0" "Remove\0"
"Pagina als QR tonen\0" "Pagina als QR tonen\0"
"Hoofdstuk: \0" "Hoofdstuk: \0"
@@ -34174,11 +34110,9 @@ const char STRINGS_NL_DATA[] =
"Geen voetnoten op deze pagina\0" "Geen voetnoten op deze pagina\0"
"[link]\0" "[link]\0"
"Screenshot maken\0" "Screenshot maken\0"
"Auto Turn Enabled: \0" "Automatisch omslaan ingeschakeld: \0"
"Auto Turn (Pages Per Minute)\0" "Autom. omslaan (pagina's per minuut)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -34211,32 +34145,31 @@ const uint16_t OFFSETS_NL[] = {
377, 400, 411, 424, 435, 454, 472, 511, 544, 564, 578, 616, 377, 400, 411, 424, 435, 454, 472, 511, 544, 564, 578, 616,
672, 691, 705, 746, 774, 785, 821, 838, 854, 885, 896, 916, 672, 691, 705, 746, 774, 785, 821, 838, 854, 885, 896, 916,
940, 945, 967, 979, 1018, 1052, 1084, 1125, 1132, 1138, 1148, 1156, 940, 945, 967, 979, 1018, 1052, 1084, 1125, 1132, 1138, 1148, 1156,
1168, 1193, 1214, 1240, 1260, 1267, 1275, 1287, 1296, 1328, 1352, 1362, 1168, 1193, 1214, 1240, 1260, 1273, 1282, 1294, 1304, 1336, 1360, 1370,
1390, 1427, 1444, 1464, 1483, 1501, 1525, 1540, 1560, 1578, 1588, 1603, 1398, 1435, 1452, 1472, 1491, 1509, 1533, 1548, 1568, 1593, 1603, 1618,
1638, 1644, 1657, 1666, 1670, 1674, 1688, 1714, 1740, 1761, 1782, 1804, 1653, 1659, 1672, 1681, 1685, 1689, 1703, 1729, 1755, 1776, 1797, 1819,
1825, 1855, 1879, 1892, 1914, 1927, 1944, 1960, 1982, 2002, 2012, 2028, 1840, 1870, 1894, 1907, 1929, 1942, 1959, 1975, 1997, 2017, 2027, 2043,
2045, 2067, 2079, 2096, 2106, 2120, 2138, 2161, 2173, 2187, 2200, 2222, 2060, 2082, 2094, 2111, 2121, 2135, 2153, 2176, 2188, 2202, 2215, 2237,
2236, 2259, 2264, 2281, 2296, 2307, 2323, 2341, 2355, 2379, 2399, 2412, 2251, 2274, 2279, 2296, 2311, 2322, 2338, 2356, 2370, 2394, 2414, 2427,
2419, 2447, 2471, 2488, 2512, 2535, 2571, 2593, 2602, 2617, 2647, 2667, 2434, 2462, 2486, 2503, 2527, 2550, 2586, 2608, 2617, 2632, 2662, 2682,
2690, 2696, 2733, 2767, 2809, 2841, 2857, 2870, 2887, 2895, 2916, 2951, 2705, 2711, 2748, 2782, 2824, 2856, 2872, 2885, 2902, 2910, 2931, 2966,
2958, 2964, 2974, 2981, 2986, 2994, 3005, 3011, 3020, 3027, 3035, 3041, 2973, 2979, 2989, 2996, 3001, 3009, 3020, 3026, 3035, 3042, 3050, 3056,
3056, 3063, 3082, 3092, 3110, 3126, 3142, 3151, 3161, 3175, 3181, 3191, 3071, 3078, 3097, 3107, 3125, 3141, 3157, 3166, 3176, 3190, 3196, 3206,
3197, 3209, 3214, 3222, 3228, 3238, 3244, 3254, 3261, 3267, 3273, 3280, 3212, 3224, 3229, 3237, 3243, 3253, 3259, 3269, 3276, 3282, 3288, 3295,
3287, 3294, 3303, 3314, 3326, 3338, 3350, 3357, 3382, 3409, 3426, 3442, 3302, 3309, 3318, 3329, 3341, 3353, 3365, 3372, 3397, 3424, 3441, 3457,
3453, 3477, 3492, 3508, 3558, 3578, 3592, 3609, 3615, 3624, 3650, 3671, 3468, 3492, 3507, 3523, 3573, 3593, 3607, 3624, 3630, 3639, 3665, 3686,
3694, 3704, 3715, 3735, 3763, 3789, 3798, 3807, 3816, 3824, 3829, 3838, 3709, 3719, 3730, 3750, 3778, 3804, 3813, 3822, 3831, 3839, 3844, 3857,
3845, 3854, 3863, 3871, 3876, 3885, 3893, 3896, 3900, 3905, 3913, 3917, 3864, 3873, 3882, 3890, 3895, 3904, 3912, 3915, 3919, 3924, 3932, 3936,
3921, 3936, 3942, 3949, 3956, 3963, 3966, 3992, 4001, 4022, 4048, 4074, 3940, 3955, 3961, 3968, 3975, 3982, 3985, 4011, 4020, 4041, 4067, 4093,
4089, 4110, 4114, 4124, 4128, 4133, 4143, 4156, 4166, 4176, 4182, 4191, 4108, 4129, 4133, 4143, 4147, 4152, 4162, 4175, 4185, 4195, 4201, 4210,
4200, 4209, 4214, 4230, 4253, 4280, 4293, 4312, 4325, 4333, 4348, 4368, 4219, 4228, 4233, 4249, 4272, 4299, 4312, 4331, 4344, 4359, 4379, 4416,
4405, 4449, 4457, 4476, 4488, 4495, 4499, 4509, 4551, 4567, 4581, 4626, 4460, 4468, 4487, 4499, 4506, 4510, 4520, 4562, 4578, 4592, 4637, 4673,
4662, 4678, 4697, 4713, 4730, 4740, 4750, 4775, 4797, 4804, 4811, 4831, 4689, 4708, 4724, 4741, 4751, 4761, 4786, 4808, 4818, 4825, 4845, 4857,
4843, 4858, 4865, 4904, 4941, 4964, 4991, 5023, 5044, 5071, 5101, 5123, 4872, 4879, 4918, 4955, 4978, 5005, 5037, 5058, 5085, 5115, 5137, 5166,
5152, 5194, 5214, 5222, 5230, 5255, 5283, 5293, 5321, 5347, 5379, 5405, 5208, 5228, 5236, 5244, 5269, 5297, 5307, 5335, 5361, 5393, 5419, 5440,
5426, 5439, 5447, 5456, 5471, 5487, 5503, 5513, 5543, 5550, 5567, 5587, 5453, 5461, 5470, 5485, 5501, 5517, 5527, 5557, 5564, 5581, 5616, 5653,
5616, 5621, 5628, 5635, 5640, 5666, 5672, 5677, 5683, 5687, 5726, 5753, 5658, 5663, 5689, 5695, 5700, 5706, 5710, 5749, 5776, 5804, 5823, 5847,
5781, 5800, 5824, 5849, 5860, 5865, 5869, 5873, 5882, 5891, 5901, 5912, 5872, 5883, 5888, 5892, 5896, 5905, 5914, 5924, 5935, 5942, 5951, 5969,
5919, 5928, 5946,
}; };
const char STRINGS_TR_DATA[] = const char STRINGS_TR_DATA[] =
@@ -35242,7 +35175,6 @@ const char STRINGS_TR_DATA[] =
"\x96" "\x96"
"zel\0" "zel\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Son Kitaplar\0" "Son Kitaplar\0"
"Son okunan kitap yok\0" "Son okunan kitap yok\0"
"Calibre kablosuz cihaz transferini kullan\0" "Calibre kablosuz cihaz transferini kullan\0"
@@ -35469,8 +35401,6 @@ const char STRINGS_TR_DATA[] =
"\x87" "\x87"
"evirme (Dakikada Sayfa)\0" "evirme (Dakikada Sayfa)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -35520,15 +35450,14 @@ const uint16_t OFFSETS_TR[] = {
4044, 4051, 4058, 4066, 4070, 4077, 4089, 4094, 4101, 4109, 4115, 4121, 4044, 4051, 4058, 4066, 4070, 4077, 4089, 4094, 4101, 4109, 4115, 4121,
4128, 4141, 4145, 4150, 4158, 4167, 4173, 4201, 4210, 4240, 4263, 4288, 4128, 4141, 4145, 4150, 4158, 4167, 4173, 4201, 4210, 4240, 4263, 4288,
4307, 4340, 4346, 4351, 4358, 4364, 4372, 4383, 4401, 4411, 4420, 4424, 4307, 4340, 4346, 4351, 4358, 4364, 4372, 4383, 4401, 4411, 4420, 4424,
4440, 4447, 4452, 4473, 4509, 4535, 4551, 4565, 4578, 4586, 4599, 4620, 4440, 4447, 4452, 4473, 4509, 4535, 4551, 4565, 4578, 4591, 4612, 4654,
4662, 4700, 4705, 4732, 4740, 4746, 4754, 4766, 4801, 4813, 4829, 4873, 4692, 4697, 4724, 4732, 4738, 4746, 4758, 4793, 4805, 4821, 4865, 4902,
4910, 4925, 4942, 4956, 4971, 4980, 4996, 5030, 5054, 5058, 5065, 5092, 4917, 4934, 4948, 4963, 4972, 4988, 5022, 5046, 5050, 5057, 5084, 5094,
5102, 5114, 5122, 5159, 5195, 5224, 5254, 5282, 5310, 5337, 5367, 5392, 5106, 5114, 5151, 5187, 5216, 5246, 5274, 5302, 5329, 5359, 5384, 5414,
5422, 5459, 5478, 5484, 5491, 5514, 5540, 5555, 5578, 5602, 5628, 5650, 5451, 5470, 5476, 5483, 5506, 5532, 5547, 5570, 5594, 5620, 5642, 5663,
5671, 5699, 5708, 5715, 5730, 5745, 5764, 5774, 5796, 5809, 5832, 5858, 5691, 5700, 5707, 5722, 5737, 5756, 5766, 5788, 5801, 5824, 5850, 5885,
5893, 5898, 5905, 5912, 5917, 5943, 5949, 5954, 5960, 5964, 6003, 6030, 5890, 5895, 5921, 5927, 5932, 5938, 5942, 5981, 6008, 6036, 6055, 6079,
6058, 6077, 6101, 6126, 6137, 6142, 6146, 6150, 6159, 6168, 6178, 6189, 6104, 6115, 6120, 6124, 6128, 6137, 6146, 6156, 6167, 6174, 6183, 6201,
6196, 6205, 6223,
}; };
const char STRINGS_KK_DATA[] = const char STRINGS_KK_DATA[] =
@@ -41178,7 +41107,6 @@ const char STRINGS_KK_DATA[] =
"\xBD" "\xBD"
"\0" "\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"\xD0" "\xD0"
"\x96" "\x96"
"\xD1" "\xD1"
@@ -43289,8 +43217,6 @@ const char STRINGS_KK_DATA[] =
"\x8B" "\x8B"
")\0" ")\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -43340,15 +43266,14 @@ const uint16_t OFFSETS_KK[] = {
6037, 6050, 6069, 6082, 6089, 6109, 6126, 6131, 6138, 6153, 6166, 6179, 6037, 6050, 6069, 6082, 6089, 6109, 6126, 6131, 6138, 6153, 6166, 6179,
6194, 6219, 6226, 6231, 6244, 6255, 6260, 6310, 6327, 6362, 6395, 6436, 6194, 6219, 6226, 6231, 6244, 6255, 6260, 6310, 6327, 6362, 6395, 6436,
6464, 6517, 6532, 6545, 6556, 6567, 6578, 6592, 6614, 6643, 6652, 6667, 6464, 6517, 6532, 6545, 6556, 6567, 6578, 6592, 6614, 6643, 6652, 6667,
6703, 6726, 6731, 6759, 6809, 6869, 6889, 6927, 6940, 6948, 6993, 7045, 6703, 6726, 6731, 6759, 6809, 6869, 6889, 6927, 6940, 6985, 7037, 7102,
7110, 7208, 7219, 7256, 7269, 7276, 7291, 7304, 7370, 7401, 7458, 7564, 7200, 7211, 7248, 7261, 7268, 7283, 7296, 7362, 7393, 7450, 7556, 7643,
7651, 7682, 7715, 7742, 7767, 7781, 7810, 7850, 7879, 7886, 7893, 7937, 7674, 7707, 7734, 7759, 7773, 7802, 7842, 7871, 7878, 7885, 7929, 7942,
7950, 7963, 7976, 8023, 8069, 8110, 8154, 8204, 8256, 8283, 8313, 8361, 7955, 7968, 8015, 8061, 8102, 8146, 8196, 8248, 8275, 8305, 8353, 8430,
8438, 8514, 8545, 8565, 8587, 8616, 8648, 8667, 8720, 8782, 8835, 8904, 8506, 8537, 8557, 8579, 8608, 8640, 8659, 8712, 8774, 8827, 8896, 8940,
8948, 8982, 8994, 9016, 9038, 9076, 9100, 9138, 9201, 9218, 9248, 9302, 8974, 8986, 9008, 9030, 9068, 9092, 9130, 9193, 9210, 9240, 9294, 9368,
9376, 9381, 9388, 9395, 9400, 9426, 9432, 9437, 9443, 9447, 9486, 9513, 9373, 9378, 9404, 9410, 9415, 9421, 9425, 9464, 9491, 9519, 9538, 9562,
9541, 9560, 9584, 9609, 9620, 9625, 9629, 9633, 9642, 9651, 9661, 9672, 9587, 9598, 9603, 9607, 9611, 9620, 9629, 9639, 9650, 9657, 9666, 9684,
9679, 9688, 9706,
}; };
const char STRINGS_PT_DATA[] = const char STRINGS_PT_DATA[] =
@@ -43864,7 +43789,6 @@ const char STRINGS_PT_DATA[] =
"Navegador OPDS\0" "Navegador OPDS\0"
"Capa + personalizado\0" "Capa + personalizado\0"
"Page overlay\0" "Page overlay\0"
"Recents\0"
"Livros recentes\0" "Livros recentes\0"
"Sem livros recentes\0" "Sem livros recentes\0"
"Usar transfer\xC3" "Usar transfer\xC3"
@@ -44013,8 +43937,6 @@ const char STRINGS_PT_DATA[] =
"Auto Turn Enabled: \0" "Auto Turn Enabled: \0"
"Auto Turn (Pages Per Minute)\0" "Auto Turn (Pages Per Minute)\0"
"Info\0" "Info\0"
"Author\0"
"Series\0"
"Size\0" "Size\0"
"Sleep Screen Info Overlay\0" "Sleep Screen Info Overlay\0"
"White\0" "White\0"
@@ -44064,15 +43986,14 @@ const uint16_t OFFSETS_PT[] = {
4185, 4195, 4204, 4210, 4216, 4227, 4242, 4246, 4251, 4256, 4261, 4266, 4185, 4195, 4204, 4210, 4216, 4227, 4242, 4246, 4251, 4256, 4261, 4266,
4272, 4286, 4295, 4303, 4308, 4314, 4317, 4352, 4362, 4383, 4402, 4427, 4272, 4286, 4295, 4303, 4308, 4314, 4317, 4352, 4362, 4383, 4402, 4427,
4440, 4463, 4468, 4475, 4481, 4486, 4494, 4505, 4516, 4524, 4530, 4538, 4440, 4463, 4468, 4475, 4481, 4486, 4494, 4505, 4516, 4524, 4530, 4538,
4556, 4566, 4571, 4585, 4612, 4640, 4655, 4676, 4689, 4697, 4713, 4733, 4556, 4566, 4571, 4585, 4612, 4640, 4655, 4676, 4689, 4705, 4725, 4766,
4774, 4826, 4835, 4858, 4873, 4880, 4887, 4902, 4945, 4961, 4976, 5034, 4818, 4827, 4850, 4865, 4872, 4879, 4894, 4937, 4953, 4968, 5026, 5075,
5083, 5103, 5126, 5148, 5169, 5179, 5197, 5219, 5243, 5252, 5259, 5275, 5095, 5118, 5140, 5161, 5171, 5189, 5211, 5235, 5244, 5251, 5267, 5278,
5286, 5298, 5305, 5343, 5372, 5394, 5426, 5464, 5492, 5519, 5549, 5571, 5290, 5297, 5335, 5364, 5386, 5418, 5456, 5484, 5511, 5541, 5563, 5597,
5605, 5652, 5674, 5682, 5689, 5717, 5748, 5755, 5780, 5803, 5838, 5862, 5644, 5666, 5674, 5681, 5709, 5740, 5747, 5772, 5795, 5830, 5854, 5873,
5881, 5906, 5915, 5922, 5938, 5957, 5978, 5988, 6014, 6021, 6036, 6056, 5898, 5907, 5914, 5930, 5949, 5970, 5980, 6006, 6013, 6028, 6048, 6077,
6085, 6090, 6097, 6104, 6109, 6135, 6141, 6146, 6152, 6156, 6195, 6222, 6082, 6087, 6113, 6119, 6124, 6130, 6134, 6173, 6200, 6228, 6247, 6271,
6250, 6269, 6293, 6318, 6329, 6334, 6338, 6342, 6351, 6360, 6370, 6381, 6296, 6307, 6312, 6316, 6320, 6329, 6338, 6348, 6359, 6366, 6375, 6393,
6388, 6397, 6415,
}; };
} // namespace i18n_strings } // namespace i18n_strings
+12 -2
View File
@@ -13,11 +13,14 @@
bool Xtc::load() { bool Xtc::load() {
LOG_DBG("XTC", "Loading XTC: %s", filepath.c_str()); LOG_DBG("XTC", "Loading XTC: %s", filepath.c_str());
// Ensure the per-book cache exists before the parser tries to create page_table.bin.
setupCacheDir();
// Initialize parser // Initialize parser
parser.reset(new xtc::XtcParser()); parser.reset(new xtc::XtcParser());
// Open XTC file // Open XTC file and initialize its cache-backed page table
xtc::XtcError err = parser->open(filepath.c_str()); xtc::XtcError err = parser->open(filepath.c_str(), cachePath.c_str());
if (err != xtc::XtcError::OK) { if (err != xtc::XtcError::OK) {
LOG_ERR("XTC", "Failed to load: %s", xtc::errorToString(err)); LOG_ERR("XTC", "Failed to load: %s", xtc::errorToString(err));
parser.reset(); parser.reset();
@@ -619,3 +622,10 @@ xtc::XtcError Xtc::getLastError() const {
} }
return parser->getLastError(); return parser->getLastError();
} }
void Xtc::prefetchPages(uint32_t pageIndex) const {
if (!loaded || !parser) {
return;
}
parser->prefetchWindow(pageIndex);
}
+5
View File
@@ -50,6 +50,11 @@ class Xtc {
*/ */
void setupCacheDir() const; void setupCacheDir() const;
/**
* Preload window around specified page (for page turn optimization)
*/
void prefetchPages(uint32_t pageIndex) const;
// Path accessors // Path accessors
const std::string& getCachePath() const { return cachePath; } const std::string& getCachePath() const { return cachePath; }
const std::string& getPath() const { return filepath; } const std::string& getPath() const { return filepath; }
+507 -93
View File
@@ -10,6 +10,7 @@
#include <FsHelpers.h> #include <FsHelpers.h>
#include <HalStorage.h> #include <HalStorage.h>
#include <Logging.h> #include <Logging.h>
#include <esp_heap_caps.h>
#include <cstring> #include <cstring>
#include <limits> #include <limits>
@@ -18,6 +19,8 @@ namespace xtc {
namespace { namespace {
constexpr size_t MAX_CHAPTERS = 4096;
bool canSeekToOffset(const uint64_t offset) { bool canSeekToOffset(const uint64_t offset) {
return offset <= static_cast<uint64_t>(std::numeric_limits<size_t>::max()); return offset <= static_cast<uint64_t>(std::numeric_limits<size_t>::max());
} }
@@ -31,6 +34,26 @@ bool seekToOffset(FsFile& file, const uint64_t offset) {
} // namespace } // namespace
void XtcParser::safeDeserializeHeader(const uint8_t* buf, PageTableCacheHeader& header) {
memcpy(&header.magic, buf + 0, 4);
memcpy(&header.version, buf + 4, 4);
memcpy(&header.pageCount, buf + 8, 4);
memcpy(&header.originalHash, buf + 12, 4);
memcpy(&header.originalSize, buf + 16, 8);
memcpy(&header.entrySize, buf + 24, 4);
memcpy(&header.reserved, buf + 28, 4);
}
void XtcParser::safeSerializeHeader(uint8_t* buf, const PageTableCacheHeader& header) {
memcpy(buf + 0, &header.magic, 4);
memcpy(buf + 4, &header.version, 4);
memcpy(buf + 8, &header.pageCount, 4);
memcpy(buf + 12, &header.originalHash, 4);
memcpy(buf + 16, &header.originalSize, 8);
memcpy(buf + 24, &header.entrySize, 4);
memcpy(buf + 28, &header.reserved, 4);
}
XtcParser::XtcParser() XtcParser::XtcParser()
: m_isOpen(false), : m_isOpen(false),
m_defaultWidth(DISPLAY_WIDTH), m_defaultWidth(DISPLAY_WIDTH),
@@ -39,17 +62,28 @@ XtcParser::XtcParser()
m_hasChapters(false), m_hasChapters(false),
m_lastError(XtcError::OK) { m_lastError(XtcError::OK) {
memset(&m_header, 0, sizeof(m_header)); memset(&m_header, 0, sizeof(m_header));
for (auto& entry : m_l1Cache) {
entry.pageIndex = 0xFFFFFFFF;
entry.lastAccess = 0;
}
} }
XtcParser::~XtcParser() { close(); } XtcParser::~XtcParser() { close(); }
XtcError XtcParser::open(const char* filepath) { XtcError XtcParser::open(const char* filepath, const char* cacheDir) {
// Close if already open // Close any previous file state before reopening
if (m_isOpen) { if (m_isOpen) {
close(); close();
} }
// Open file m_originalPath = filepath;
m_cacheDir = cacheDir;
uint32_t fileHash = calculateFileHash(filepath);
m_cacheFilePath = std::string(cacheDir) + "/xtc_" + std::to_string(fileHash) + "/page_table.bin";
// Open the original XTC file just long enough to read metadata and validate the header.
if (!Storage.openFileForRead("XTC", filepath, m_file)) { if (!Storage.openFileForRead("XTC", filepath, m_file)) {
m_lastError = XtcError::FILE_NOT_FOUND; m_lastError = XtcError::FILE_NOT_FOUND;
return m_lastError; return m_lastError;
@@ -63,57 +97,416 @@ XtcError XtcParser::open(const char* filepath) {
return m_lastError; return m_lastError;
} }
// Read title & author if available if (m_header.pageCount == 0) {
LOG_ERR("XTC", "File has no pages");
m_file.close();
m_lastError = XtcError::CORRUPTED_HEADER;
return m_lastError;
}
// Metadata strings are small, so keep them in memory even when the page table is moved to cache.
if (m_header.hasMetadata) { if (m_header.hasMetadata) {
m_lastError = readTitle(); readTitle();
readAuthor();
m_title.shrink_to_fit();
m_author.shrink_to_fit();
LOG_INF("XTC", "Metadata strings: titleLen=%u cap=%u, authorLen=%u cap=%u",
static_cast<unsigned int>(m_title.size()), static_cast<unsigned int>(m_title.capacity()),
static_cast<unsigned int>(m_author.size()), static_cast<unsigned int>(m_author.capacity()));
}
// Defer chapter parsing until the reader actually needs the table of contents.
m_pageTableOffset = m_header.pageTableOffset;
m_hasChapters = (m_header.hasChapters == 1) && (m_header.chapterOffset != 0);
LOG_INF("XTC", "Chapter metadata deferred: available=%s", m_hasChapters ? "yes" : "no");
m_file.close();
// Build or reuse the on-disk page table cache before marking the parser open.
if (!isPageTableCacheValid()) {
LOG_INF("XTC", "Building page table cache for %u pages", m_header.pageCount);
m_lastError = buildPageTableCache();
if (m_lastError != XtcError::OK) { if (m_lastError != XtcError::OK) {
LOG_DBG("XTC", "Failed to read title: %s", errorToString(m_lastError)); LOG_ERR("XTC", "Failed to build page table cache");
m_file.close();
return m_lastError; return m_lastError;
} }
m_lastError = readAuthor(); const size_t heapBefore = ESP.getMaxAllocHeap();
if (m_lastError != XtcError::OK) { LOG_DBG("XTC", "Cache built, heap before defrag: free=%zu, maxAlloc=%zu", ESP.getFreeHeap(), heapBefore);
LOG_DBG("XTC", "Failed to read author: %s", errorToString(m_lastError));
m_file.close(); // Defragment heap: small delay allows heap coalescing after file handles are closed
return m_lastError; // This typically improves MaxAlloc by 10-20KB, enabling 96KB page buffer for grayscale
LOG_DBG("XTC", "Defragmenting heap (waiting 50ms)...");
vTaskDelay(pdMS_TO_TICKS(50));
const size_t heapAfter = ESP.getMaxAllocHeap();
const size_t heapGain = heapAfter > heapBefore ? (heapAfter - heapBefore) : 0;
if (heapGain > 0) {
LOG_INF("XTC", "Heap defragmented: +%zu bytes contiguous (now %zu)", heapGain, heapAfter);
} else {
LOG_DBG("XTC", "Heap after defrag: free=%zu, maxAlloc=%zu", ESP.getFreeHeap(), heapAfter);
} }
} }
// Read page table if (!openCacheFile()) {
m_lastError = readPageTable(); LOG_ERR("XTC", "Failed to open cache file");
if (m_lastError != XtcError::OK) { m_lastError = XtcError::FILE_NOT_FOUND;
LOG_DBG("XTC", "Failed to read page table: %s", errorToString(m_lastError));
m_file.close();
return m_lastError; return m_lastError;
} }
// Read chapters if present // Prime the sliding L2 window with the first chunk of page metadata.
m_lastError = readChapters(); loadL2Window(0);
if (m_lastError != XtcError::OK) {
LOG_DBG("XTC", "Failed to read chapters: %s", errorToString(m_lastError)); LOG_DBG("XTC", "File opened, heap: free=%zu, maxAlloc=%zu", ESP.getFreeHeap(), ESP.getMaxAllocHeap());
m_file.close();
return m_lastError;
}
m_isOpen = true; m_isOpen = true;
LOG_DBG("XTC", "Opened file: %s (%u pages, %dx%d)", filepath, m_header.pageCount, m_defaultWidth, m_defaultHeight); LOG_DBG("XTC", "Opened file: %s (%u pages, cache: %s)", filepath, m_header.pageCount, m_cacheFilePath.c_str());
return XtcError::OK; return XtcError::OK;
} }
void XtcParser::close() { void XtcParser::close() {
if (m_isOpen) { closeCacheFile();
if (m_isOpen && m_file.isOpen()) {
m_file.close(); m_file.close();
m_isOpen = false;
} }
m_pageTable.clear(); m_isOpen = false;
m_l2Valid = false;
m_l2WindowCount = 0;
m_chaptersLoaded = false;
for (auto& entry : m_l1Cache) {
entry.pageIndex = 0xFFFFFFFF;
}
m_chapters.clear(); m_chapters.clear();
m_title.clear(); m_title.clear();
m_hasChapters = false; m_author.clear();
memset(&m_header, 0, sizeof(m_header)); memset(&m_header, 0, sizeof(m_header));
} }
void XtcParser::ensureChaptersLoaded() {
if (m_chaptersLoaded || !m_hasChapters) {
return;
}
// Chapter parsing allocates variable-length strings, so keep it lazy.
const XtcError err = readChapters();
if (err != XtcError::OK) {
LOG_ERR("XTC", "Failed to lazy-load chapters: %s", errorToString(err));
m_hasChapters = false;
m_chapters.clear();
m_chapters.shrink_to_fit();
}
m_chaptersLoaded = true;
}
bool XtcParser::openCacheFile() {
if (m_cacheFile.isOpen()) {
return true;
}
return Storage.openFileForRead("XTC", m_cacheFilePath.c_str(), m_cacheFile);
}
void XtcParser::closeCacheFile() {
if (m_cacheFile.isOpen()) {
m_cacheFile.close();
}
}
bool XtcParser::getPageInfo(uint32_t pageIndex, PageInfo& info) {
if (pageIndex >= m_header.pageCount) {
return false;
}
// L1 is the hot cache for the most recently used pages.
if (lookupL1(pageIndex, info)) {
LOG_DBG("XTC", "L1 hit: page %u", pageIndex);
return true;
}
// L2 is the sliding window around the reader's current position.
if (lookupL2(pageIndex, info)) {
updateL1(pageIndex, info);
LOG_DBG("XTC", "L2 hit: page %u", pageIndex);
return true;
}
// Fall back to the SD-backed cache file, then refresh L2/L1.
LOG_DBG("XTC", "L3 load: page %u", pageIndex);
loadL2Window(pageIndex);
if (lookupL2(pageIndex, info)) {
updateL1(pageIndex, info);
return true;
}
return false;
}
void XtcParser::prefetchWindow(uint32_t pageIndex) {
if (pageIndex >= m_header.pageCount) {
return;
}
// Avoid reloading the same window when the requested page is already covered.
if (m_l2Valid && pageIndex >= m_l2WindowStart && pageIndex < m_l2WindowStart + m_l2WindowCount) {
return;
}
loadL2Window(pageIndex);
}
bool XtcParser::lookupL1(uint32_t pageIndex, PageInfo& info) {
for (const auto& entry : m_l1Cache) {
if (entry.pageIndex == pageIndex) {
info = entry.info;
return true;
}
}
return false;
}
void XtcParser::updateL1(uint32_t pageIndex, const PageInfo& info) {
for (auto& entry : m_l1Cache) {
if (entry.pageIndex == pageIndex) {
entry.lastAccess = ++m_accessCounter;
return;
}
}
// Replace the least-recently-used entry, or fill the first empty slot.
uint32_t oldestAccess = m_accessCounter;
size_t oldestIndex = 0;
bool foundEmpty = false;
for (size_t i = 0; i < m_l1Cache.size(); i++) {
if (m_l1Cache[i].pageIndex == 0xFFFFFFFF) {
oldestIndex = i;
foundEmpty = true;
break;
}
if (m_l1Cache[i].lastAccess < oldestAccess) {
oldestAccess = m_l1Cache[i].lastAccess;
oldestIndex = i;
}
}
m_l1Cache[oldestIndex].pageIndex = pageIndex;
m_l1Cache[oldestIndex].info = info;
m_l1Cache[oldestIndex].lastAccess = ++m_accessCounter;
}
bool XtcParser::lookupL2(uint32_t pageIndex, PageInfo& info) {
if (!m_l2Valid) {
return false;
}
if (pageIndex >= m_l2WindowStart && pageIndex < m_l2WindowStart + m_l2WindowCount) {
size_t idx = pageIndex - m_l2WindowStart;
info = m_l2Window[idx];
return true;
}
return false;
}
void XtcParser::loadL2Window(uint32_t centerPage) {
// Center the sliding window around the requested page when possible.
uint32_t halfWindow = L2_WINDOW_SIZE / 2;
uint32_t windowStart = (centerPage > halfWindow) ? centerPage - halfWindow : 0;
uint32_t windowEnd = windowStart + L2_WINDOW_SIZE;
if (windowEnd > m_header.pageCount) {
windowEnd = m_header.pageCount;
windowStart = (windowEnd > L2_WINDOW_SIZE) ? windowEnd - L2_WINDOW_SIZE : 0;
}
size_t windowSize = windowEnd - windowStart;
if (windowSize == 0) {
m_l2Valid = false;
m_l2WindowCount = 0;
return;
}
if (!m_cacheFile.isOpen() && !openCacheFile()) {
LOG_ERR("XTC", "Cache file not available");
m_l2Valid = false;
m_l2WindowCount = 0;
return;
}
size_t entryOffset = sizeof(PageTableCacheHeader) + windowStart * sizeof(PageInfo);
if (!m_cacheFile.seek(entryOffset)) {
LOG_ERR("XTC", "Failed to seek in page table cache");
m_l2Valid = false;
m_l2WindowCount = 0;
return;
}
size_t readCount = 0;
for (size_t i = 0; i < windowSize; i++) {
PageInfo info;
if (m_cacheFile.read(reinterpret_cast<uint8_t*>(&info), sizeof(PageInfo)) != sizeof(PageInfo)) {
LOG_ERR("XTC", "Failed to read page info %zu", windowStart + i);
break;
}
m_l2Window[i] = info;
readCount++;
}
m_l2WindowStart = windowStart;
m_l2WindowCount = readCount;
m_l2Valid = (readCount > 0);
LOG_DBG("XTC", "L2 window loaded: [%u, %u] (%zu pages)", windowStart, windowStart + readCount - 1, readCount);
}
bool XtcParser::isPageTableCacheValid() const {
if (!Storage.exists(m_cacheFilePath.c_str())) {
return false;
}
FsFile cacheFile;
if (!Storage.openFileForRead("XTC", m_cacheFilePath.c_str(), cacheFile)) {
return false;
}
uint8_t headerBuf[sizeof(PageTableCacheHeader)];
if (cacheFile.read(headerBuf, sizeof(headerBuf)) != sizeof(headerBuf)) {
cacheFile.close();
return false;
}
PageTableCacheHeader header;
safeDeserializeHeader(headerBuf, header);
if (header.magic != PAGE_TABLE_CACHE_MAGIC || header.version != PAGE_TABLE_CACHE_VERSION) {
cacheFile.close();
return false;
}
// The cache must match both the page count and the original file size.
if (header.pageCount != m_header.pageCount) {
cacheFile.close();
return false;
}
uint32_t expectedSize = sizeof(PageTableCacheHeader) + header.pageCount * sizeof(PageInfo);
if (cacheFile.size() < expectedSize) {
cacheFile.close();
return false;
}
if (header.originalSize > 0) {
FsFile originalFile;
if (Storage.openFileForRead("XTC", m_originalPath.c_str(), originalFile)) {
uint64_t currentSize = originalFile.size();
originalFile.close();
if (currentSize != header.originalSize) {
LOG_INF("XTC", "Cache invalidated: file size changed");
cacheFile.close();
return false;
}
}
}
cacheFile.close();
return true;
}
XtcError XtcParser::buildPageTableCache() {
FsFile originalFile;
if (!Storage.openFileForRead("XTC", m_originalPath.c_str(), originalFile)) {
return XtcError::FILE_NOT_FOUND;
}
size_t lastSlash = m_cacheFilePath.find_last_of('/');
if (lastSlash != std::string::npos) {
std::string cacheDir = m_cacheFilePath.substr(0, lastSlash);
Storage.mkdir(cacheDir.c_str());
}
FsFile cacheFile;
if (!Storage.openFileForWrite("XTC", m_cacheFilePath.c_str(), cacheFile)) {
originalFile.close();
return XtcError::WRITE_ERROR;
}
// Persist a compact PageInfo array so we do not need to hold the full table in RAM.
PageTableCacheHeader header;
header.magic = PAGE_TABLE_CACHE_MAGIC;
header.version = PAGE_TABLE_CACHE_VERSION;
header.pageCount = m_header.pageCount;
header.originalHash = calculateFileHash(m_originalPath.c_str());
header.originalSize = originalFile.size();
header.entrySize = sizeof(PageInfo);
header.reserved = 0;
uint8_t headerBuf[sizeof(PageTableCacheHeader)];
safeSerializeHeader(headerBuf, header);
if (cacheFile.write(headerBuf, sizeof(headerBuf)) != sizeof(headerBuf)) {
cacheFile.close();
originalFile.close();
return XtcError::WRITE_ERROR;
}
if (!seekToOffset(originalFile, m_pageTableOffset)) {
cacheFile.close();
originalFile.close();
return XtcError::READ_ERROR;
}
// Convert the source page table entries into the cached PageInfo layout.
for (uint16_t i = 0; i < m_header.pageCount; i++) {
PageTableEntry entry;
if (originalFile.read(reinterpret_cast<uint8_t*>(&entry), sizeof(PageTableEntry)) != sizeof(PageTableEntry)) {
LOG_ERR("XTC", "Failed to read page table entry %u", i);
cacheFile.close();
originalFile.close();
return XtcError::READ_ERROR;
}
PageInfo info;
info.offset = entry.dataOffset;
info.size = entry.dataSize;
info.width = entry.width;
info.height = entry.height;
info.bitDepth = m_bitDepth;
info.padding = 0;
if (cacheFile.write(reinterpret_cast<const uint8_t*>(&info), sizeof(info)) != sizeof(info)) {
cacheFile.close();
originalFile.close();
return XtcError::WRITE_ERROR;
}
}
cacheFile.close();
originalFile.close();
LOG_INF("XTC", "Page table cache built: %u entries", m_header.pageCount);
return XtcError::OK;
}
uint32_t XtcParser::calculateFileHash(const char* filepath) const {
uint32_t hash = 0;
size_t len = strlen(filepath);
for (size_t i = 0; i < len; i++) {
hash = hash * 31 + static_cast<uint8_t>(filepath[i]);
}
FsFile file;
if (Storage.openFileForRead("XTC", filepath, file)) {
uint64_t size = file.size();
hash ^= static_cast<uint32_t>(size);
hash ^= static_cast<uint32_t>(size >> 32);
file.close();
}
return hash;
}
XtcError XtcParser::readHeader() { XtcError XtcParser::readHeader() {
// Read first 56 bytes of header // Read the fixed-size XTC header first.
size_t bytesRead = m_file.read(reinterpret_cast<uint8_t*>(&m_header), sizeof(XtcHeader)); size_t bytesRead = m_file.read(reinterpret_cast<uint8_t*>(&m_header), sizeof(XtcHeader));
if (bytesRead != sizeof(XtcHeader)) { if (bytesRead != sizeof(XtcHeader)) {
return XtcError::READ_ERROR; return XtcError::READ_ERROR;
@@ -179,49 +572,17 @@ XtcError XtcParser::readAuthor() {
return XtcError::OK; return XtcError::OK;
} }
XtcError XtcParser::readPageTable() {
if (m_header.pageTableOffset == 0) {
LOG_DBG("XTC", "Page table offset is 0, cannot read");
return XtcError::CORRUPTED_HEADER;
}
// Seek to page table
if (!seekToOffset(m_file, m_header.pageTableOffset)) {
LOG_DBG("XTC", "Failed to seek to page table at %llu", m_header.pageTableOffset);
return XtcError::READ_ERROR;
}
m_pageTable.resize(m_header.pageCount);
// Read page table entries
for (uint16_t i = 0; i < m_header.pageCount; i++) {
PageTableEntry entry;
size_t bytesRead = m_file.read(reinterpret_cast<uint8_t*>(&entry), sizeof(PageTableEntry));
if (bytesRead != sizeof(PageTableEntry)) {
LOG_DBG("XTC", "Failed to read page table entry %u", i);
return XtcError::READ_ERROR;
}
m_pageTable[i].offset = entry.dataOffset;
m_pageTable[i].size = entry.dataSize;
m_pageTable[i].width = entry.width;
m_pageTable[i].height = entry.height;
m_pageTable[i].bitDepth = m_bitDepth;
// Update default dimensions from first page
if (i == 0) {
m_defaultWidth = entry.width;
m_defaultHeight = entry.height;
}
}
LOG_DBG("XTC", "Read %u page table entries", m_header.pageCount);
return XtcError::OK;
}
XtcError XtcParser::readChapters() { XtcError XtcParser::readChapters() {
m_hasChapters = false; m_hasChapters = false;
m_chapters.clear(); m_chapters.clear();
m_chapters.shrink_to_fit();
// Reopen the original file on demand because open() closes it after cache initialization.
if (!m_file.isOpen()) {
if (!Storage.openFileForRead("XTC", m_originalPath.c_str(), m_file)) {
return XtcError::FILE_NOT_FOUND;
}
}
uint8_t hasChaptersFlag = 0; uint8_t hasChaptersFlag = 0;
if (!m_file.seek(0x0B)) { if (!m_file.seek(0x0B)) {
@@ -248,7 +609,13 @@ XtcError XtcParser::readChapters() {
} }
const uint64_t fileSize = m_file.size(); const uint64_t fileSize = m_file.size();
if (chapterOffset < sizeof(XtcHeader) || chapterOffset >= fileSize || chapterOffset + 96 > fileSize) { constexpr size_t chapterSize = 96;
if (chapterOffset < sizeof(XtcHeader) || chapterOffset >= fileSize) {
return XtcError::OK;
}
if (fileSize - chapterOffset < chapterSize) {
return XtcError::OK; return XtcError::OK;
} }
@@ -265,18 +632,32 @@ XtcError XtcParser::readChapters() {
return XtcError::OK; return XtcError::OK;
} }
constexpr size_t chapterSize = 96;
const uint64_t available = maxOffset - chapterOffset; const uint64_t available = maxOffset - chapterOffset;
const size_t chapterCount = static_cast<size_t>(available / chapterSize); const uint64_t chapterCount64 = available / chapterSize;
if (chapterCount64 == 0) {
return XtcError::OK;
}
if (chapterCount64 > MAX_CHAPTERS || chapterCount64 > std::numeric_limits<size_t>::max()) {
LOG_ERR("XTC", "Chapter table too large: available=%llu chapterCount=%llu",
static_cast<unsigned long long>(available), static_cast<unsigned long long>(chapterCount64));
return XtcError::CORRUPTED_HEADER;
}
const size_t chapterCount = static_cast<size_t>(chapterCount64);
if (chapterCount == 0) { if (chapterCount == 0) {
return XtcError::OK; return XtcError::OK;
} }
const size_t freeHeapBefore = ESP.getFreeHeap();
const size_t maxAllocBefore = ESP.getMaxAllocHeap();
if (!seekToOffset(m_file, chapterOffset)) { if (!seekToOffset(m_file, chapterOffset)) {
return XtcError::READ_ERROR; return XtcError::READ_ERROR;
} }
std::vector<uint8_t> chapterBuf(chapterSize); std::vector<uint8_t> chapterBuf(chapterSize);
m_chapters.reserve(chapterCount);
for (size_t i = 0; i < chapterCount; i++) { for (size_t i = 0; i < chapterCount; i++) {
if (m_file.read(chapterBuf.data(), chapterSize) != chapterSize) { if (m_file.read(chapterBuf.data(), chapterSize) != chapterSize) {
return XtcError::READ_ERROR; return XtcError::READ_ERROR;
@@ -320,17 +701,27 @@ XtcError XtcParser::readChapters() {
m_chapters.push_back(std::move(chapter)); m_chapters.push_back(std::move(chapter));
} }
m_chapters.shrink_to_fit();
m_hasChapters = !m_chapters.empty(); m_hasChapters = !m_chapters.empty();
LOG_DBG("XTC", "Chapters: %u", static_cast<unsigned int>(m_chapters.size())); size_t chapterNameBytes = 0;
for (const auto& chapter : m_chapters) {
chapterNameBytes += chapter.name.capacity() + 1;
}
const size_t chapterVectorBytes = m_chapters.capacity() * sizeof(ChapterInfo);
const size_t totalChapterBytes = chapterVectorBytes + chapterNameBytes;
const size_t freeHeapAfter = ESP.getFreeHeap();
const size_t maxAllocAfter = ESP.getMaxAllocHeap();
const int heapDelta = static_cast<int>(freeHeapBefore) - static_cast<int>(freeHeapAfter);
const int maxAllocDelta = static_cast<int>(maxAllocBefore) - static_cast<int>(maxAllocAfter);
LOG_INF("XTC", "Chapter metadata: count=%u, vector~=%zu, names~=%zu, total~=%zu, heapDelta=%d, maxAllocDelta=%d",
static_cast<unsigned int>(m_chapters.size()), chapterVectorBytes, chapterNameBytes, totalChapterBytes,
heapDelta, maxAllocDelta);
return XtcError::OK; return XtcError::OK;
} }
bool XtcParser::getPageInfo(uint32_t pageIndex, PageInfo& info) const { const std::vector<ChapterInfo>& XtcParser::getChapters() {
if (pageIndex >= m_pageTable.size()) { ensureChaptersLoaded();
return false; return m_chapters;
}
info = m_pageTable[pageIndex];
return true;
} }
size_t XtcParser::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize) { size_t XtcParser::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize) {
@@ -344,11 +735,23 @@ size_t XtcParser::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSiz
return 0; return 0;
} }
const PageInfo& page = m_pageTable[pageIndex]; // Resolve the page location through the cache hierarchy before touching the data file.
PageInfo info;
if (!getPageInfo(pageIndex, info)) {
m_lastError = XtcError::READ_ERROR;
return 0;
}
// Seek to page data // Reopen the source file lazily because normal parser open() does not keep it pinned.
if (!seekToOffset(m_file, page.offset)) { if (!m_file.isOpen()) {
LOG_DBG("XTC", "Failed to seek to page %u at offset %llu", pageIndex, static_cast<unsigned long long>(page.offset)); if (!Storage.openFileForRead("XTC", m_originalPath.c_str(), m_file)) {
m_lastError = XtcError::FILE_NOT_FOUND;
return 0;
}
}
if (!seekToOffset(m_file, info.offset)) {
LOG_DBG("XTC", "Failed to seek to page %u at offset %llu", pageIndex, static_cast<unsigned long long>(info.offset));
m_lastError = XtcError::READ_ERROR; m_lastError = XtcError::READ_ERROR;
return 0; return 0;
} }
@@ -382,14 +785,14 @@ size_t XtcParser::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSiz
bitmapSize = ((pageHeader.width + 7) / 8) * pageHeader.height; bitmapSize = ((pageHeader.width + 7) / 8) * pageHeader.height;
} }
// Check buffer size // The caller owns the buffer, so fail early if it is too small.
if (bufferSize < bitmapSize) { if (bufferSize < bitmapSize) {
LOG_DBG("XTC", "Buffer too small: need %u, have %u", bitmapSize, bufferSize); LOG_DBG("XTC", "Buffer too small: need %u, have %u", bitmapSize, bufferSize);
m_lastError = XtcError::MEMORY_ERROR; m_lastError = XtcError::MEMORY_ERROR;
return 0; return 0;
} }
// Read bitmap data // Read the bitmap payload into the caller-provided buffer.
size_t bytesRead = m_file.read(buffer, bitmapSize); size_t bytesRead = m_file.read(buffer, bitmapSize);
if (bytesRead != bitmapSize) { if (bytesRead != bitmapSize) {
LOG_DBG("XTC", "Page read error: expected %u, got %u", bitmapSize, bytesRead); LOG_DBG("XTC", "Page read error: expected %u, got %u", bitmapSize, bytesRead);
@@ -412,15 +815,25 @@ XtcError XtcParser::loadPageStreaming(uint32_t pageIndex,
return XtcError::PAGE_OUT_OF_RANGE; return XtcError::PAGE_OUT_OF_RANGE;
} }
const PageInfo& page = m_pageTable[pageIndex]; // Streaming uses the same cache lookup path but reads the payload in chunks.
PageInfo info;
// Seek to page data if (!getPageInfo(pageIndex, info)) {
if (!seekToOffset(m_file, page.offset)) {
LOG_DBG("XTC", "Failed to seek to page %u at offset %llu", pageIndex, static_cast<unsigned long long>(page.offset));
return XtcError::READ_ERROR; return XtcError::READ_ERROR;
} }
// Read and skip page header (XTG for 1-bit, XTH for 2-bit) // Reopen the source file on demand for streaming reads as well.
if (!m_file.isOpen()) {
if (!Storage.openFileForRead("XTC", m_originalPath.c_str(), m_file)) {
return XtcError::FILE_NOT_FOUND;
}
}
if (!seekToOffset(m_file, info.offset)) {
LOG_DBG("XTC", "Failed to seek to page %u at offset %llu", pageIndex, static_cast<unsigned long long>(info.offset));
return XtcError::READ_ERROR;
}
// Read and validate the page header before yielding any bitmap bytes.
XtgPageHeader pageHeader; XtgPageHeader pageHeader;
size_t headerRead = m_file.read(reinterpret_cast<uint8_t*>(&pageHeader), sizeof(XtgPageHeader)); size_t headerRead = m_file.read(reinterpret_cast<uint8_t*>(&pageHeader), sizeof(XtgPageHeader));
const uint32_t expectedMagic = (m_bitDepth == 2) ? XTH_MAGIC : XTG_MAGIC; const uint32_t expectedMagic = (m_bitDepth == 2) ? XTH_MAGIC : XTG_MAGIC;
@@ -431,6 +844,7 @@ XtcError XtcParser::loadPageStreaming(uint32_t pageIndex,
// Calculate bitmap size based on bit depth // Calculate bitmap size based on bit depth
// XTG (1-bit): Row-major, ((width+7)/8) * height bytes // XTG (1-bit): Row-major, ((width+7)/8) * height bytes
// XTH (2-bit): Two bit planes, ((width * height + 7) / 8) * 2 bytes // XTH (2-bit): Two bit planes, ((width * height + 7) / 8) * 2 bytes
// Match the bitmap sizing rules used by the non-streaming path.
size_t bitmapSize; size_t bitmapSize;
if (m_bitDepth == 2) { if (m_bitDepth == 2) {
bitmapSize = ((static_cast<size_t>(pageHeader.width) * pageHeader.height + 7) / 8) * 2; bitmapSize = ((static_cast<size_t>(pageHeader.width) * pageHeader.height + 7) / 8) * 2;
@@ -438,7 +852,7 @@ XtcError XtcParser::loadPageStreaming(uint32_t pageIndex,
bitmapSize = ((pageHeader.width + 7) / 8) * pageHeader.height; bitmapSize = ((pageHeader.width + 7) / 8) * pageHeader.height;
} }
// Read in chunks // Feed the bitmap to the callback in bounded chunks to keep peak memory low.
std::vector<uint8_t> chunk(chunkSize); std::vector<uint8_t> chunk(chunkSize);
size_t totalRead = 0; size_t totalRead = 0;
+52 -26
View File
@@ -9,6 +9,8 @@
#include <HalStorage.h> #include <HalStorage.h>
#include <array>
#include <cstring>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
@@ -30,7 +32,7 @@ class XtcParser {
~XtcParser(); ~XtcParser();
// File open/close // File open/close
XtcError open(const char* filepath); XtcError open(const char* filepath, const char* cacheDir);
void close(); void close();
bool isOpen() const { return m_isOpen; } bool isOpen() const { return m_isOpen; }
@@ -41,28 +43,14 @@ class XtcParser {
uint16_t getHeight() const { return m_defaultHeight; } uint16_t getHeight() const { return m_defaultHeight; }
uint8_t getBitDepth() const { return m_bitDepth; } // 1 = XTC/XTG, 2 = XTCH/XTH uint8_t getBitDepth() const { return m_bitDepth; } // 1 = XTC/XTG, 2 = XTCH/XTH
// Page information // Page information - three-tier cache interface
bool getPageInfo(uint32_t pageIndex, PageInfo& info) const; bool getPageInfo(uint32_t pageIndex, PageInfo& info);
/** // Preload window around specified page (optimize sequential page turns)
* Load page bitmap (raw 1-bit data, skipping XTG header) void prefetchWindow(uint32_t pageIndex);
*
* @param pageIndex Page index (0-based) // Load page bitmap (unchanged)
* @param buffer Output buffer (caller allocated)
* @param bufferSize Buffer size
* @return Number of bytes read on success, 0 on failure
*/
size_t loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize); size_t loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize);
/**
* Streaming page load
* Memory-efficient method that reads page data in chunks.
*
* @param pageIndex Page index
* @param callback Callback function to receive data chunks
* @param chunkSize Chunk size (default: 1024 bytes)
* @return Error code
*/
XtcError loadPageStreaming(uint32_t pageIndex, XtcError loadPageStreaming(uint32_t pageIndex,
std::function<void(const uint8_t* data, size_t size, size_t offset)> callback, std::function<void(const uint8_t* data, size_t size, size_t offset)> callback,
size_t chunkSize = 1024); size_t chunkSize = 1024);
@@ -72,7 +60,7 @@ class XtcParser {
std::string getAuthor() const { return m_author; } std::string getAuthor() const { return m_author; }
bool hasChapters() const { return m_hasChapters; } bool hasChapters() const { return m_hasChapters; }
const std::vector<ChapterInfo>& getChapters() const { return m_chapters; } const std::vector<ChapterInfo>& getChapters();
// Validation // Validation
static bool isValidXtcFile(const char* filepath); static bool isValidXtcFile(const char* filepath);
@@ -82,24 +70,62 @@ class XtcParser {
private: private:
FsFile m_file; FsFile m_file;
FsFile m_cacheFile;
bool m_isOpen; bool m_isOpen;
XtcHeader m_header; XtcHeader m_header;
std::vector<PageInfo> m_pageTable; std::string m_cacheDir;
std::vector<ChapterInfo> m_chapters; std::string m_cacheFilePath;
std::string m_originalPath;
std::string m_title; std::string m_title;
std::string m_author; std::string m_author;
uint16_t m_defaultWidth; uint16_t m_defaultWidth;
uint16_t m_defaultHeight; uint16_t m_defaultHeight;
uint8_t m_bitDepth; // 1 = XTC/XTG (1-bit), 2 = XTCH/XTH (2-bit) uint8_t m_bitDepth;
bool m_hasChapters; bool m_hasChapters;
bool m_chaptersLoaded = false;
XtcError m_lastError; XtcError m_lastError;
uint32_t m_accessCounter = 0;
// L1: Hot cache (fixed 4 entries)
std::array<L1CacheEntry, L1_CACHE_SIZE> m_l1Cache;
// L2: Sliding window (fixed size array)
std::array<PageInfo, L2_WINDOW_SIZE> m_l2Window;
uint32_t m_l2WindowStart = 0;
size_t m_l2WindowCount = 0;
bool m_l2Valid = false;
// Chapters (usually few, keep in memory)
std::vector<ChapterInfo> m_chapters;
// Original Page Table offset (for rebuilding cache)
uint64_t m_pageTableOffset = 0;
// Internal helper functions // Internal helper functions
XtcError readHeader(); XtcError readHeader();
XtcError readPageTable();
XtcError readTitle(); XtcError readTitle();
XtcError readAuthor(); XtcError readAuthor();
XtcError readChapters(); XtcError readChapters();
void ensureChaptersLoaded();
// L3 cache management
bool isPageTableCacheValid() const;
XtcError buildPageTableCache();
bool openCacheFile();
void closeCacheFile();
// L1/L2 cache operations
bool lookupL1(uint32_t pageIndex, PageInfo& info);
void updateL1(uint32_t pageIndex, const PageInfo& info);
bool lookupL2(uint32_t pageIndex, PageInfo& info);
void loadL2Window(uint32_t centerPage);
// Safe deserialization (alignment-safe for ESP32-C3)
static void safeDeserializeHeader(const uint8_t* buf, PageTableCacheHeader& header);
static void safeSerializeHeader(uint8_t* buf, const PageTableCacheHeader& header);
// Utility functions
uint32_t calculateFileHash(const char* filepath) const;
}; };
} // namespace xtc } // namespace xtc
+27
View File
@@ -102,6 +102,33 @@ struct ChapterInfo {
uint16_t endPage; uint16_t endPage;
}; };
// Cache configuration
constexpr size_t L1_CACHE_SIZE = 4; // L1 cache entries
constexpr size_t L2_WINDOW_SIZE = 100; // L2 window size (reduced for 2-bit memory)
constexpr uint32_t PAGE_TABLE_CACHE_VERSION = 1; // Cache file version
// Cache magic number
constexpr uint32_t PAGE_TABLE_CACHE_MAGIC = 0x50435458; // "XTCP"
// Cache file header - NOTE: Do NOT read directly from file buffer!
// Use safeDeserializeHeader() function for alignment-safe access.
struct PageTableCacheHeader {
uint32_t magic; // 'XTCP' = 0x50435458
uint32_t version; // Cache version
uint32_t pageCount; // Total pages
uint32_t originalHash; // Original file hash (for validation)
uint64_t originalSize; // Original file size (for validation)
uint32_t entrySize; // PageInfo size (16)
uint32_t reserved; // Reserved
};
// L1 cache entry
struct L1CacheEntry {
uint32_t pageIndex = 0xFFFFFFFF; // 0xFFFFFFFF = invalid
PageInfo info{};
uint32_t lastAccess = 0; // Timestamp for LRU
};
// Error codes // Error codes
enum class XtcError { enum class XtcError {
OK = 0, OK = 0,
+7
View File
@@ -2,6 +2,7 @@
#include <FsHelpers.h> #include <FsHelpers.h>
#include <HalStorage.h> #include <HalStorage.h>
#include <I18n.h>
#include "CrossPointSettings.h" #include "CrossPointSettings.h"
#include "Epub.h" #include "Epub.h"
@@ -12,6 +13,8 @@
#include "XtcReaderActivity.h" #include "XtcReaderActivity.h"
#include "activities/util/BmpViewerActivity.h" #include "activities/util/BmpViewerActivity.h"
#include "activities/util/FullScreenMessageActivity.h" #include "activities/util/FullScreenMessageActivity.h"
#include "components/UITheme.h"
#include "fontIds.h"
std::string ReaderActivity::extractFolderPath(const std::string& filePath) { std::string ReaderActivity::extractFolderPath(const std::string& filePath) {
const auto lastSlash = filePath.find_last_of('/'); const auto lastSlash = filePath.find_last_of('/');
@@ -116,6 +119,10 @@ void ReaderActivity::onEnter() {
if (isBmpFile(initialBookPath)) { if (isBmpFile(initialBookPath)) {
onGoToBmpViewer(initialBookPath); onGoToBmpViewer(initialBookPath);
} else if (isXtcFile(initialBookPath)) { } else if (isXtcFile(initialBookPath)) {
renderer.clearScreen();
renderer.drawCenteredText(UI_12_FONT_ID, 300, tr(STR_LOADING), true, EpdFontFamily::BOLD);
renderer.displayBuffer();
auto xtc = loadXtc(initialBookPath); auto xtc = loadXtc(initialBookPath);
if (!xtc) { if (!xtc) {
onGoBack(); onGoBack();
@@ -42,6 +42,8 @@ void XtcReaderActivity::onEnter() {
APP_STATE.saveToFile(); APP_STATE.saveToFile();
RECENT_BOOKS.addBook(xtc->getPath(), xtc->getTitle(), xtc->getAuthor(), "", xtc->getThumbBmpPath()); RECENT_BOOKS.addBook(xtc->getPath(), xtc->getTitle(), xtc->getAuthor(), "", xtc->getThumbBmpPath());
xtc->prefetchPages(currentPage);
// Trigger first update // Trigger first update
requestUpdate(); requestUpdate();
} }
@@ -63,6 +65,7 @@ void XtcReaderActivity::loop() {
[this](const ActivityResult& result) { [this](const ActivityResult& result) {
if (!result.isCancelled) { if (!result.isCancelled) {
currentPage = std::get<PageResult>(result.data).page; currentPage = std::get<PageResult>(result.data).page;
xtc->prefetchPages(currentPage);
} }
}); });
} }
@@ -118,12 +121,14 @@ void XtcReaderActivity::loop() {
} else { } else {
currentPage = 0; currentPage = 0;
} }
xtc->prefetchPages(currentPage);
requestUpdate(); requestUpdate();
} else if (nextTriggered) { } else if (nextTriggered) {
currentPage += skipAmount; currentPage += skipAmount;
if (currentPage >= xtc->getPageCount()) { if (currentPage >= xtc->getPageCount()) {
currentPage = xtc->getPageCount(); // Allow showing "End of book" currentPage = xtc->getPageCount(); // Allow showing "End of book"
} }
xtc->prefetchPages(currentPage);
requestUpdate(); requestUpdate();
} }
} }