Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a8971fc20 | ||
|
|
e2cba5be83 | ||
|
|
52a0b5bbe9 | ||
|
|
3abcd0d05d | ||
|
|
03f0ce04cc | ||
|
|
be1b5bad21 | ||
|
|
3dd52f30fa | ||
|
|
e43fec79be | ||
|
|
bf7bffd506 | ||
|
|
9f31f80c80 | ||
|
|
fb5fc32c5d | ||
|
|
d4bd119950 | ||
|
|
85d76da967 | ||
|
|
e4ac90f5c1 | ||
|
|
278b056bd0 | ||
|
|
b01eb50325 | ||
|
|
1bfe694807 | ||
|
|
7b32a87596 | ||
|
|
071ccb9d1b | ||
|
|
d7f4bd54f5 | ||
|
|
2437943c94 | ||
|
|
140d8749a6 | ||
|
|
534504cf7a | ||
|
|
b1763821b5 | ||
|
|
c0b83b626e | ||
|
|
f8c0b1acea | ||
|
|
f9b604f04e | ||
|
|
3dc5f6fec4 | ||
|
|
41c93e4eba | ||
|
|
1c33162368 | ||
|
|
27d42fbef3 | ||
|
|
dd280bdc97 | ||
|
|
bf031fd999 | ||
|
|
02350c6a9f | ||
|
|
9023b262a1 | ||
|
|
eabd149371 | ||
|
|
838246d147 | ||
|
|
f96b6ab29c | ||
|
|
e3d0201365 | ||
|
|
286b47f489 | ||
|
|
aff4dc6628 | ||
|
|
98a39374e8 | ||
|
|
e8c0fb42d4 | ||
|
|
b77af16caa | ||
|
|
e3c1e28b8f | ||
|
|
dc7544d944 | ||
|
|
504c7b307d | ||
|
|
b6bc1f7ed3 | ||
|
|
ea0abaf351 | ||
|
|
2771579007 | ||
|
|
27035b2b91 | ||
|
|
1107590b56 | ||
|
|
66ddb52103 | ||
|
|
9f4f71fabe | ||
|
|
d23020e268 | ||
|
|
f4491875ab |
@@ -12,12 +12,6 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.platformio/.cache
|
||||
key: ${{ runner.os }}-pio
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.14'
|
||||
|
||||
@@ -98,9 +98,9 @@ CrossPoint Reader is pretty aggressive about caching data down to the SD card to
|
||||
has ~380KB of usable RAM, so we have to be careful. A lot of the decisions made in the design of the firmware were based
|
||||
on this constraint.
|
||||
|
||||
### EPUB caching
|
||||
### Data caching
|
||||
|
||||
The first time chapters of an EPUB are loaded, they are cached to the SD card. Subsequent loads are served from the
|
||||
The first time chapters of a book are loaded, they are cached to the SD card. Subsequent loads are served from the
|
||||
cache. This cache directory exists at `.crosspoint` on the SD card. The structure is as follows:
|
||||
|
||||
|
||||
@@ -108,25 +108,22 @@ cache. This cache directory exists at `.crosspoint` on the SD card. The structur
|
||||
.crosspoint/
|
||||
├── epub_12471232/ # Each EPUB is cached to a subdirectory named `epub_<hash>`
|
||||
│ ├── progress.bin # Stores reading progress (chapter, page, etc.)
|
||||
│ ├── 0/ # Each chapter is stored in a subdirectory named by its index (based on the spine order)
|
||||
│ │ ├── section.bin # Section metadata (page count)
|
||||
│ │ ├── page_0.bin # Each page is stored in a separate file, it
|
||||
│ │ ├── page_1.bin # contains the position (x, y) and text for each word
|
||||
│ │ └── ...
|
||||
│ ├── 1/
|
||||
│ │ ├── section.bin
|
||||
│ │ ├── page_0.bin
|
||||
│ │ ├── page_1.bin
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
│ ├── cover.bmp # Book cover image (once generated)
|
||||
│ ├── book.bin # Book metadata (title, author, spine, table of contents, etc.)
|
||||
│ └── sections/ # All chapter data is stored in the sections subdirectory
|
||||
│ ├── 0.bin # Chapter data (screen count, all text layout info, etc.)
|
||||
│ ├── 1.bin # files are named by their index in the spine
|
||||
│ └── ...
|
||||
│
|
||||
└── epub_189013891/
|
||||
```
|
||||
|
||||
Deleting the `.crosspoint` directory will clear the cache.
|
||||
Deleting the `.crosspoint` directory will clear the entire cache.
|
||||
|
||||
Due the way it's currently implemented, the cache is not automatically cleared when the EPUB is deleted and moving an
|
||||
EPUB file will reset the reading progress.
|
||||
Due the way it's currently implemented, the cache is not automatically cleared when a book is deleted and moving a book
|
||||
file will use a new cache directory, resetting the reading progress.
|
||||
|
||||
For more details on the internal file structures, see the [file formats document](./docs/file-formats.md).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ The Settings screen allows you to configure the device's behavior. There are a f
|
||||
- **Extra Paragraph Spacing**: If enabled, vertical space will be added between paragraphs in the book, if disabled,
|
||||
paragraphs will not have vertical space between them, but will have first word indentation.
|
||||
- **Short Power Button Click**: Whether to trigger the power button on a short press or a long press.
|
||||
- **Front Button Layout**: Swap the order of the bottom edge buttons from Back/Confirm/Left/Right to Left/Right/Back/Confirm.
|
||||
|
||||
### 3.6 Sleep Screen
|
||||
|
||||
|
||||
+17
-1
@@ -1,3 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
find src lib \( -name "*.c" -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" \) -exec clang-format -style=file -i {} +
|
||||
GIT_LS_FILES_FLAGS=""
|
||||
if [[ "$1" == "-g" ]]; then
|
||||
GIT_LS_FILES_FLAGS="--modified"
|
||||
fi
|
||||
|
||||
# --- Main Logic ---
|
||||
|
||||
# Format all files (or only modified files if -g is passed)
|
||||
|
||||
# Use 'git ls-files' to get a list of all files tracked by git:
|
||||
# --modified: files tracked by git that have been modified (staged or unstaged)
|
||||
# --exclude-standard: ignores files in .gitignore
|
||||
# Additionally exclude files in 'lib/EpdFont/builtinFonts/' as they are script-generated.
|
||||
git ls-files --exclude-standard ${GIT_LS_FILES_FLAGS} \
|
||||
| grep -E '\.(c|cpp|h|hpp)$' \
|
||||
| grep -v -E '^lib/EpdFont/builtinFonts/' \
|
||||
| xargs -r clang-format -style=file -i
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# File Formats
|
||||
|
||||
## `book.bin`
|
||||
|
||||

|
||||
|
||||
## `section.bin`
|
||||
|
||||

|
||||
Binary file not shown.
|
After Width: | Height: | Size: 539 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 296 KiB |
+25
-12
@@ -2,8 +2,7 @@
|
||||
|
||||
#include <Utf8.h>
|
||||
|
||||
inline int min(const int a, const int b) { return a < b ? a : b; }
|
||||
inline int max(const int a, const int b) { return a < b ? b : a; }
|
||||
#include <algorithm>
|
||||
|
||||
void EpdFont::getTextBounds(const char* string, const int startX, const int startY, int* minX, int* minY, int* maxX,
|
||||
int* maxY) const {
|
||||
@@ -32,10 +31,10 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
||||
continue;
|
||||
}
|
||||
|
||||
*minX = min(*minX, cursorX + glyph->left);
|
||||
*maxX = max(*maxX, cursorX + glyph->left + glyph->width);
|
||||
*minY = min(*minY, cursorY + glyph->top - glyph->height);
|
||||
*maxY = max(*maxY, cursorY + glyph->top);
|
||||
*minX = std::min(*minX, cursorX + glyph->left);
|
||||
*maxX = std::max(*maxX, cursorX + glyph->left + glyph->width);
|
||||
*minY = std::min(*minY, cursorY + glyph->top - glyph->height);
|
||||
*maxY = std::max(*maxY, cursorY + glyph->top);
|
||||
cursorX += glyph->advanceX;
|
||||
}
|
||||
}
|
||||
@@ -59,14 +58,28 @@ bool EpdFont::hasPrintableChars(const char* string) const {
|
||||
|
||||
const EpdGlyph* EpdFont::getGlyph(const uint32_t cp) const {
|
||||
const EpdUnicodeInterval* intervals = data->intervals;
|
||||
for (int i = 0; i < data->intervalCount; i++) {
|
||||
const EpdUnicodeInterval* interval = &intervals[i];
|
||||
if (cp >= interval->first && cp <= interval->last) {
|
||||
const int count = data->intervalCount;
|
||||
|
||||
if (count == 0) return nullptr;
|
||||
|
||||
// Binary search for O(log n) lookup instead of O(n)
|
||||
// Critical for Korean fonts with many unicode intervals
|
||||
int left = 0;
|
||||
int right = count - 1;
|
||||
|
||||
while (left <= right) {
|
||||
const int mid = left + (right - left) / 2;
|
||||
const EpdUnicodeInterval* interval = &intervals[mid];
|
||||
|
||||
if (cp < interval->first) {
|
||||
right = mid - 1;
|
||||
} else if (cp > interval->last) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
// Found: cp >= interval->first && cp <= interval->last
|
||||
return &data->glyph[interval->offset + (cp - interval->first)];
|
||||
}
|
||||
if (cp < interval->first) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <builtinFonts/aleo_12_bold.h>
|
||||
#include <builtinFonts/aleo_12_bolditalic.h>
|
||||
#include <builtinFonts/aleo_12_italic.h>
|
||||
#include <builtinFonts/aleo_12_regular.h>
|
||||
#include <builtinFonts/aleo_14_bold.h>
|
||||
#include <builtinFonts/aleo_14_bolditalic.h>
|
||||
#include <builtinFonts/aleo_14_italic.h>
|
||||
#include <builtinFonts/aleo_14_regular.h>
|
||||
#include <builtinFonts/aleo_16_bold.h>
|
||||
#include <builtinFonts/aleo_16_bolditalic.h>
|
||||
#include <builtinFonts/aleo_16_italic.h>
|
||||
#include <builtinFonts/aleo_16_regular.h>
|
||||
#include <builtinFonts/aleo_18_bold.h>
|
||||
#include <builtinFonts/aleo_18_bolditalic.h>
|
||||
#include <builtinFonts/aleo_18_italic.h>
|
||||
#include <builtinFonts/aleo_18_regular.h>
|
||||
#include <builtinFonts/notosans_12_bold.h>
|
||||
#include <builtinFonts/notosans_12_bolditalic.h>
|
||||
#include <builtinFonts/notosans_12_italic.h>
|
||||
#include <builtinFonts/notosans_12_regular.h>
|
||||
#include <builtinFonts/notosans_14_bold.h>
|
||||
#include <builtinFonts/notosans_14_bolditalic.h>
|
||||
#include <builtinFonts/notosans_14_italic.h>
|
||||
#include <builtinFonts/notosans_14_regular.h>
|
||||
#include <builtinFonts/notosans_16_bold.h>
|
||||
#include <builtinFonts/notosans_16_bolditalic.h>
|
||||
#include <builtinFonts/notosans_16_italic.h>
|
||||
#include <builtinFonts/notosans_16_regular.h>
|
||||
#include <builtinFonts/notosans_18_bold.h>
|
||||
#include <builtinFonts/notosans_18_bolditalic.h>
|
||||
#include <builtinFonts/notosans_18_italic.h>
|
||||
#include <builtinFonts/notosans_18_regular.h>
|
||||
#include <builtinFonts/opendyslexic_10_bold.h>
|
||||
#include <builtinFonts/opendyslexic_10_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_10_italic.h>
|
||||
#include <builtinFonts/opendyslexic_10_regular.h>
|
||||
#include <builtinFonts/opendyslexic_12_bold.h>
|
||||
#include <builtinFonts/opendyslexic_12_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_12_italic.h>
|
||||
#include <builtinFonts/opendyslexic_12_regular.h>
|
||||
#include <builtinFonts/opendyslexic_14_bold.h>
|
||||
#include <builtinFonts/opendyslexic_14_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_14_italic.h>
|
||||
#include <builtinFonts/opendyslexic_14_regular.h>
|
||||
#include <builtinFonts/opendyslexic_8_bold.h>
|
||||
#include <builtinFonts/opendyslexic_8_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_8_italic.h>
|
||||
#include <builtinFonts/opendyslexic_8_regular.h>
|
||||
#include <builtinFonts/spacegrotesk.h>
|
||||
#include <builtinFonts/ubuntu_10_bold.h>
|
||||
#include <builtinFonts/ubuntu_10_regular.h>
|
||||
#include <builtinFonts/ubuntu_12_bold.h>
|
||||
#include <builtinFonts/ubuntu_12_regular.h>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,93 @@
|
||||
Copyright 2018 The Aleo Project Authors (https://github.com/AlessioLaiso/aleo)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,93 @@
|
||||
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,94 @@
|
||||
Copyright (c) 2019-07-29, Abbie Gonzalez (https://abbiecod.es|support@abbiecod.es),
|
||||
with Reserved Font Name OpenDyslexic.
|
||||
Copyright (c) 12/2012 - 2019
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The Space Grotesk Project Authors (https://github.com/floriankarsten/space-grotesk)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
@@ -0,0 +1,96 @@
|
||||
-------------------------------
|
||||
UBUNTU FONT LICENCE Version 1.0
|
||||
-------------------------------
|
||||
|
||||
PREAMBLE
|
||||
This licence allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely. The fonts, including any derivative works, can be
|
||||
bundled, embedded, and redistributed provided the terms of this licence
|
||||
are met. The fonts and derivatives, however, cannot be released under
|
||||
any other licence. The requirement for fonts to remain under this
|
||||
licence does not require any document created using the fonts or their
|
||||
derivatives to be published under this licence, as long as the primary
|
||||
purpose of the document is not to be a vehicle for the distribution of
|
||||
the fonts.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this licence and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Original Version" refers to the collection of Font Software components
|
||||
as received under this licence.
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to
|
||||
a new environment.
|
||||
|
||||
"Copyright Holder(s)" refers to all individuals and companies who have a
|
||||
copyright ownership of the Font Software.
|
||||
|
||||
"Substantially Changed" refers to Modified Versions which can be easily
|
||||
identified as dissimilar to the Font Software by users of the Font
|
||||
Software comparing the Original Version with the Modified Version.
|
||||
|
||||
To "Propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification and with or without charging
|
||||
a redistribution fee), making available to the public, and in some
|
||||
countries other activities as well.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
This licence does not grant any rights under trademark law and all such
|
||||
rights are reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of the Font Software, to propagate the Font Software, subject to
|
||||
the below conditions:
|
||||
|
||||
1) Each copy of the Font Software must contain the above copyright
|
||||
notice and this licence. These can be included either as stand-alone
|
||||
text files, human-readable headers or in the appropriate machine-
|
||||
readable metadata fields within text or binary files as long as those
|
||||
fields can be easily viewed by the user.
|
||||
|
||||
2) The font name complies with the following:
|
||||
(a) The Original Version must retain its name, unmodified.
|
||||
(b) Modified Versions which are Substantially Changed must be renamed to
|
||||
avoid use of the name of the Original Version or similar names entirely.
|
||||
(c) Modified Versions which are not Substantially Changed must be
|
||||
renamed to both (i) retain the name of the Original Version and (ii) add
|
||||
additional naming elements to distinguish the Modified Version from the
|
||||
Original Version. The name of such Modified Versions must be the name of
|
||||
the Original Version, with "derivative X" where X represents the name of
|
||||
the new work, appended to that name.
|
||||
|
||||
3) The name(s) of the Copyright Holder(s) and any contributor to the
|
||||
Font Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except (i) as required by this licence, (ii) to
|
||||
acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
|
||||
their explicit written permission.
|
||||
|
||||
4) The Font Software, modified or unmodified, in part or in whole, must
|
||||
be distributed entirely under this licence, and must not be distributed
|
||||
under any other licence. The requirement for fonts to remain under this
|
||||
licence does not affect any document created using the Font Software,
|
||||
except any version of the Font Software extracted from a document
|
||||
created using the Font Software may only be distributed under this
|
||||
licence.
|
||||
|
||||
TERMINATION
|
||||
This licence becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
|
||||
DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,826 @@
|
||||
/**
|
||||
* generated by fontconvert.py
|
||||
* name: spacegrotesk
|
||||
* size: 8
|
||||
* mode: 1-bit
|
||||
*/
|
||||
#pragma once
|
||||
#include "EpdFontData.h"
|
||||
|
||||
static const uint8_t spacegroteskBitmaps[5331] = {
|
||||
0x66, 0x66, 0x66, 0x66, 0x60, 0x67, 0x20, 0x00, 0xF9, 0xF1, 0xA6, 0xC0, 0x00, 0x33, 0x0C, 0xC3,
|
||||
0x31, 0xFF, 0xFF, 0xCC, 0xC3, 0x33, 0xFF, 0xFF, 0xCC, 0xC3, 0x30, 0xCC, 0x0C, 0x03, 0x03, 0xF1,
|
||||
0xFE, 0x6D, 0x9B, 0x77, 0xC8, 0xF8, 0x1F, 0x93, 0x7E, 0xCD, 0xB3, 0x7F, 0x8F, 0xE0, 0xC0, 0x30,
|
||||
0x78, 0x37, 0xE3, 0x33, 0x39, 0x9B, 0x87, 0xD8, 0x1D, 0x80, 0x19, 0x01, 0xFE, 0x1D, 0xB8, 0xCC,
|
||||
0xCC, 0x66, 0xC3, 0xE0, 0x04, 0x00, 0x3E, 0x1F, 0x86, 0x03, 0x84, 0x63, 0x1F, 0xF7, 0xFD, 0x8C,
|
||||
0xC3, 0x38, 0xC7, 0xF0, 0xFC, 0x06, 0x73, 0x60, 0x19, 0xEE, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C,
|
||||
0x30, 0xC3, 0x0E, 0x1E, 0x3C, 0xC3, 0xC3, 0x86, 0x1C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x61,
|
||||
0xBC, 0xE0, 0x08, 0x6A, 0x3E, 0xFF, 0x7F, 0x3E, 0x6A, 0x08, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18,
|
||||
0x18, 0x18, 0x06, 0x73, 0x60, 0xFF, 0xE0, 0x06, 0x72, 0x0C, 0x18, 0x30, 0xE1, 0x83, 0x06, 0x18,
|
||||
0x30, 0x61, 0x83, 0x06, 0x18, 0x30, 0x40, 0x3E, 0x3F, 0xB0, 0xF8, 0x3C, 0x1E, 0x0F, 0x07, 0x83,
|
||||
0xC1, 0xE0, 0xF9, 0xCF, 0xE1, 0x80, 0x1C, 0xF7, 0xDB, 0xEF, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x3F,
|
||||
0x1F, 0xE6, 0x19, 0x87, 0x41, 0xC0, 0x60, 0xF8, 0xF8, 0x70, 0x18, 0x07, 0xF9, 0xFF, 0x7F, 0x9F,
|
||||
0xF0, 0x38, 0x3C, 0x1C, 0x07, 0xC1, 0xF8, 0x06, 0xC1, 0xD8, 0x67, 0x38, 0xFC, 0x0C, 0x00, 0x07,
|
||||
0x03, 0xC0, 0xF0, 0x6C, 0x3B, 0x0C, 0xC6, 0x33, 0x8C, 0xFF, 0xFF, 0xF0, 0x30, 0x0C, 0x7F, 0x9F,
|
||||
0xE6, 0x01, 0x80, 0x7F, 0x1F, 0xE7, 0x18, 0x07, 0x61, 0xD8, 0x67, 0x38, 0xFC, 0x0C, 0x00, 0x7E,
|
||||
0x7F, 0xB0, 0xD8, 0x3F, 0xE7, 0xFB, 0x0D, 0x83, 0xC1, 0xE1, 0xF9, 0xCF, 0xC1, 0x80, 0xFF, 0xFF,
|
||||
0xC0, 0x60, 0x60, 0x30, 0x30, 0x38, 0x18, 0x1C, 0x0C, 0x0E, 0x06, 0x00, 0x3F, 0x1F, 0xE6, 0x1D,
|
||||
0x83, 0x61, 0xCF, 0xE7, 0xF9, 0x87, 0xE0, 0xF8, 0x37, 0x3C, 0xFE, 0x0C, 0x00, 0x3F, 0x1F, 0xE6,
|
||||
0x19, 0x87, 0xE1, 0xD8, 0x77, 0xFC, 0xFF, 0x41, 0xD8, 0x67, 0x38, 0xFC, 0x0C, 0x00, 0x06, 0x72,
|
||||
0x00, 0x06, 0x72, 0x06, 0x72, 0x00, 0x06, 0x73, 0x60, 0x01, 0x0F, 0x3E, 0xF0, 0xF0, 0x7C, 0x1F,
|
||||
0x03, 0xFF, 0xFF, 0x7F, 0xFF, 0x00, 0xC0, 0xF0, 0x7E, 0x0F, 0x07, 0x3E, 0xF8, 0xC0, 0x3F, 0x3F,
|
||||
0xD8, 0x78, 0x34, 0x18, 0x3C, 0x3C, 0x18, 0x0C, 0x00, 0x07, 0x03, 0x80, 0x80, 0x0F, 0xE0, 0x3F,
|
||||
0xF0, 0xE0, 0x73, 0x18, 0x6E, 0x7F, 0x79, 0xDE, 0xF3, 0x1D, 0xEE, 0x1B, 0xDC, 0x37, 0x98, 0xEF,
|
||||
0x3B, 0xFB, 0x3F, 0xE7, 0x10, 0x07, 0x80, 0x07, 0xFC, 0x01, 0xF0, 0x0E, 0x03, 0xC0, 0x7C, 0x0D,
|
||||
0x83, 0xB0, 0x66, 0x0C, 0x63, 0xFC, 0x7F, 0x8C, 0x39, 0x83, 0x60, 0x60, 0xFF, 0x9F, 0xF8, 0xC3,
|
||||
0x18, 0x63, 0x0C, 0x7F, 0x8F, 0xE1, 0x86, 0x30, 0xC6, 0x19, 0xFF, 0x7F, 0xC0, 0x3E, 0x3F, 0xB8,
|
||||
0x78, 0x3C, 0x1E, 0x03, 0x01, 0x83, 0xC1, 0xE0, 0xFD, 0xEF, 0xE1, 0xC0, 0xFF, 0x1F, 0xF0, 0xC7,
|
||||
0x18, 0x63, 0x0E, 0x61, 0xCC, 0x39, 0x87, 0x30, 0xC6, 0x19, 0xFF, 0x7F, 0xC0, 0xFF, 0xFF, 0xC0,
|
||||
0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xFE,
|
||||
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x3E, 0x3F, 0xB8, 0x78, 0x3C, 0x1E, 0x03, 0x3F, 0x9F, 0xC1, 0xE0,
|
||||
0xFD, 0xEF, 0xF1, 0x80, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0xFF, 0xFF, 0x83, 0xC1, 0xE0, 0xF0,
|
||||
0x78, 0x30, 0xFF, 0xFF, 0xFF, 0x0F, 0x83, 0xE0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x33, 0x0C, 0xC3,
|
||||
0x38, 0xC7, 0x71, 0xF8, 0x18, 0x00, 0xC3, 0xE3, 0xB3, 0x9B, 0x8F, 0x87, 0x83, 0xC1, 0xF0, 0xDC,
|
||||
0x67, 0x31, 0xD8, 0x70, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF,
|
||||
0xE0, 0x77, 0x83, 0xBC, 0x3D, 0xE1, 0xEF, 0x8F, 0x6C, 0x7B, 0x66, 0xDB, 0x36, 0xCD, 0xB6, 0x7D,
|
||||
0xB3, 0xCD, 0x9E, 0x60, 0xE1, 0xF8, 0xFC, 0x7F, 0x3D, 0x9E, 0xCF, 0x37, 0x9B, 0xCF, 0xE3, 0xF1,
|
||||
0xF8, 0xF0, 0x3E, 0x1F, 0xEE, 0x1B, 0x06, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xB0, 0x6F, 0x79,
|
||||
0xFC, 0x1C, 0x00, 0xFE, 0x7F, 0xB0, 0xF8, 0x3C, 0x1E, 0x1B, 0xFD, 0xF8, 0xC0, 0x60, 0x30, 0x18,
|
||||
0x00, 0x3E, 0x1F, 0xEE, 0x1B, 0x06, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xB0, 0x6F, 0x79, 0xFC,
|
||||
0x1C, 0x03, 0x80, 0xE0, 0xFE, 0x7F, 0xB0, 0x78, 0x3C, 0x1E, 0x1F, 0xFD, 0xFF, 0xC3, 0xE1, 0xF0,
|
||||
0xF8, 0x70, 0x3F, 0x1F, 0xE6, 0x19, 0x87, 0x70, 0x8F, 0x81, 0xF9, 0x07, 0xE0, 0xD8, 0x37, 0x38,
|
||||
0xFE, 0x0C, 0x00, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00,
|
||||
0xC0, 0x30, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xFD, 0xEF, 0xE1,
|
||||
0xC0, 0xC0, 0xF8, 0x36, 0x1D, 0x86, 0x61, 0x8C, 0x63, 0x30, 0xCC, 0x1B, 0x07, 0xC1, 0xE0, 0x78,
|
||||
0xC3, 0x8F, 0x9E, 0x36, 0x78, 0xD9, 0xB3, 0x66, 0xCD, 0x9B, 0x76, 0xED, 0x9B, 0x36, 0x3C, 0xF8,
|
||||
0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0xE0, 0xCC, 0x38, 0xC6, 0x1D, 0x81, 0xF0, 0x3C, 0x03, 0x80, 0xF8,
|
||||
0x3B, 0x06, 0x31, 0xC7, 0x70, 0x60, 0xC0, 0xF8, 0x76, 0x18, 0xCE, 0x3B, 0x07, 0x81, 0xE0, 0x30,
|
||||
0x0C, 0x03, 0x00, 0xC0, 0x30, 0x7F, 0xBF, 0xC0, 0xE0, 0x60, 0x60, 0x70, 0x70, 0x70, 0x30, 0x30,
|
||||
0x3F, 0xFF, 0xF0, 0x77, 0xF1, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1E, 0xF8, 0x60, 0x60,
|
||||
0x60, 0x30, 0x30, 0x30, 0x18, 0x18, 0x18, 0x0C, 0x0C, 0x0C, 0x06, 0x06, 0x06, 0x02, 0xF7, 0xC6,
|
||||
0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7F, 0xF0, 0x1C, 0x1E, 0x1D, 0x8C, 0xEC, 0x30, 0xFF,
|
||||
0x7F, 0x80, 0x00, 0x67, 0x30, 0x1C, 0x0F, 0xC6, 0x31, 0x8C, 0x3F, 0x1F, 0xCE, 0x31, 0x9E, 0x7F,
|
||||
0xC6, 0x00, 0xC0, 0x60, 0x30, 0x1B, 0x8F, 0xF7, 0x1F, 0x07, 0x83, 0xC1, 0xE0, 0xFC, 0xFF, 0xE0,
|
||||
0xC0, 0x0E, 0x0F, 0xC7, 0x39, 0x86, 0x60, 0x18, 0x06, 0x19, 0xCE, 0x3F, 0x03, 0x00, 0x00, 0xC0,
|
||||
0x30, 0x0C, 0x73, 0x3F, 0xDC, 0x76, 0x1D, 0x83, 0x60, 0xD8, 0x77, 0x3C, 0xFF, 0x0C, 0x00, 0x0E,
|
||||
0x1F, 0x9C, 0xEC, 0x37, 0xFB, 0xFD, 0x86, 0xE7, 0x3F, 0x06, 0x00, 0x1E, 0x3C, 0x63, 0xFF, 0xE3,
|
||||
0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x1C, 0x8F, 0xF7, 0x1D, 0x87, 0x60, 0xD8, 0x36, 0x1D, 0xEF,
|
||||
0x3F, 0xC0, 0x30, 0x0C, 0xFF, 0x3F, 0x80, 0xC0, 0xC0, 0xC0, 0xDC, 0xFE, 0xE3, 0xC3, 0xC3, 0xC3,
|
||||
0xC3, 0xC3, 0xC3, 0xDB, 0x0D, 0xB6, 0xDB, 0x60, 0x31, 0x8C, 0x03, 0x18, 0xC6, 0x31, 0x8C, 0x63,
|
||||
0x1B, 0xCC, 0xC0, 0xC0, 0xC0, 0xC2, 0xCE, 0xDC, 0xF8, 0xF0, 0xF0, 0xD8, 0xCE, 0xC7, 0xFF, 0xFF,
|
||||
0xFF, 0x18, 0xC7, 0xFF, 0xB9, 0xCD, 0x8C, 0x6C, 0x63, 0x63, 0x1B, 0x18, 0xD8, 0xC6, 0xC6, 0x30,
|
||||
0x1C, 0xFE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x0E, 0x0F, 0xC7, 0x39, 0x87, 0x60, 0xD8,
|
||||
0x36, 0x19, 0xCE, 0x3F, 0x03, 0x00, 0x1C, 0x7F, 0xB8, 0xF8, 0x3C, 0x1E, 0x0F, 0x07, 0xE7, 0xFF,
|
||||
0x66, 0x30, 0x18, 0x0C, 0x00, 0x1C, 0x8F, 0xF7, 0x1D, 0x87, 0x60, 0xD8, 0x36, 0x1D, 0xCF, 0x3F,
|
||||
0xC3, 0x30, 0x0C, 0x03, 0x00, 0x80, 0x1F, 0xF9, 0x8C, 0x63, 0x18, 0xC0, 0x1C, 0x7E, 0x63, 0x62,
|
||||
0x7E, 0x1F, 0x63, 0x63, 0x3F, 0x0C, 0x00, 0x30, 0x63, 0xFF, 0xE3, 0x06, 0x0C, 0x18, 0x30, 0x70,
|
||||
0xF0, 0x01, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x10, 0x41, 0x71, 0xD8, 0xCC, 0x67,
|
||||
0x71, 0xB0, 0xD8, 0x38, 0x1C, 0x00, 0x42, 0x13, 0x38, 0xD9, 0xEE, 0xCF, 0x66, 0xDB, 0x36, 0xD8,
|
||||
0xF3, 0xC7, 0x9E, 0x38, 0xE0, 0x40, 0x98, 0x63, 0x30, 0xF8, 0x1E, 0x07, 0x83, 0xF1, 0xCC, 0x61,
|
||||
0x80, 0x01, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x13, 0x03, 0x7F, 0x7E, 0xFD, 0xFC,
|
||||
0x38, 0xE3, 0x8E, 0x38, 0x7E, 0xFE, 0x1E, 0x3C, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0xF1, 0xE0, 0x60,
|
||||
0xC1, 0x83, 0x06, 0x0F, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF1, 0xF0, 0x60, 0xC1, 0x83, 0x06,
|
||||
0x0C, 0x1E, 0x3C, 0x60, 0xC1, 0x83, 0x06, 0x7C, 0xF0, 0x10, 0x7B, 0xFF, 0x4C, 0x67, 0x60, 0x66,
|
||||
0x66, 0x66, 0x66, 0x60, 0x08, 0x0C, 0x07, 0x0F, 0xCF, 0xF6, 0xDB, 0x61, 0xB0, 0xDB, 0x7F, 0x9F,
|
||||
0x83, 0x01, 0x80, 0x1F, 0x0F, 0xE3, 0x1C, 0xC3, 0x30, 0xDF, 0x07, 0xC0, 0xC0, 0x30, 0x0C, 0x07,
|
||||
0xF9, 0xFF, 0x00, 0x1F, 0xF7, 0xF9, 0x86, 0x60, 0xD8, 0x36, 0x19, 0xCE, 0x7F, 0xD3, 0x20, 0xC0,
|
||||
0xCC, 0x39, 0xC6, 0x19, 0xC3, 0xB0, 0x3C, 0x1F, 0xE1, 0xFC, 0x7F, 0x87, 0xF0, 0x30, 0x06, 0x00,
|
||||
0xFF, 0xFF, 0x0F, 0xFF, 0xF0, 0x3E, 0x7E, 0x63, 0x62, 0x7C, 0x7E, 0x7B, 0x3F, 0x47, 0xC3, 0x67,
|
||||
0x7E, 0x18, 0x6C, 0xD9, 0xB0, 0x3F, 0x1F, 0xEC, 0xDF, 0x7B, 0xF3, 0xFC, 0xBF, 0x0F, 0xCF, 0xFE,
|
||||
0xF7, 0xB6, 0x39, 0xFC, 0x0C, 0x00, 0x78, 0xD8, 0xF3, 0xEC, 0xCF, 0xCC, 0x00, 0x0C, 0x63, 0xBD,
|
||||
0xEE, 0x73, 0x87, 0x70, 0x77, 0x87, 0x38, 0x23, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xE0, 0x3E, 0x7F,
|
||||
0x5D, 0x5D, 0x55, 0x77, 0x3E, 0x00, 0x7C, 0xF8, 0x7B, 0xFC, 0xF3, 0x78, 0x40, 0x08, 0x18, 0x18,
|
||||
0xFF, 0xFF, 0x18, 0x18, 0x18, 0x7F, 0xFF, 0x01, 0xEC, 0xC3, 0x7B, 0x8F, 0xC0, 0xFC, 0x73, 0x8F,
|
||||
0xCD, 0xF3, 0x00, 0x36, 0x60, 0x00, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x1B, 0x0D, 0xCE, 0xFF, 0xE8,
|
||||
0x30, 0x18, 0x0C, 0x00, 0x3F, 0xBF, 0xF3, 0x79, 0xBC, 0xDB, 0xED, 0xF6, 0x1B, 0x0D, 0x86, 0xC3,
|
||||
0x61, 0xB0, 0x1F, 0xA0, 0x21, 0x8E, 0xF7, 0x00, 0x77, 0xF3, 0x33, 0x3C, 0xFF, 0x1E, 0x3C, 0x6F,
|
||||
0x8E, 0x00, 0xCC, 0x3B, 0xC7, 0xB8, 0x67, 0x39, 0xDD, 0xEE, 0xE2, 0x30, 0x70, 0x21, 0xC1, 0x8F,
|
||||
0x0C, 0x0C, 0x60, 0x33, 0x80, 0xCC, 0x00, 0x67, 0x03, 0x1C, 0x18, 0xD0, 0xE7, 0xE3, 0x1F, 0xD8,
|
||||
0x04, 0x00, 0x00, 0x70, 0x21, 0xC1, 0x8F, 0x0C, 0x0C, 0x60, 0x33, 0x80, 0xCC, 0x00, 0x6F, 0x83,
|
||||
0x33, 0x18, 0x18, 0xE1, 0xE3, 0x0C, 0x18, 0x3F, 0x00, 0x00, 0xFC, 0x18, 0x38, 0x60, 0xE1, 0xC1,
|
||||
0xE3, 0x0C, 0xCC, 0x0F, 0xB0, 0x0C, 0xC7, 0x03, 0x9E, 0x0E, 0x6C, 0x19, 0xFC, 0x63, 0xF9, 0x80,
|
||||
0x60, 0x00, 0x00, 0x0C, 0x06, 0x03, 0x00, 0x00, 0xC0, 0xE0, 0xE0, 0xE0, 0xE1, 0xF0, 0xD8, 0x6F,
|
||||
0xE1, 0xE0, 0x1C, 0x01, 0x80, 0x10, 0x07, 0x01, 0xE0, 0x3E, 0x06, 0xC1, 0xD8, 0x33, 0x06, 0x31,
|
||||
0xFE, 0x3F, 0xC6, 0x1C, 0xC1, 0xB0, 0x30, 0x06, 0x01, 0xC0, 0x30, 0x07, 0x01, 0xE0, 0x3E, 0x06,
|
||||
0xC1, 0xD8, 0x33, 0x06, 0x31, 0xFE, 0x3F, 0xC6, 0x1C, 0xC1, 0xB0, 0x30, 0x0E, 0x03, 0xE0, 0xCC,
|
||||
0x07, 0x01, 0xE0, 0x3E, 0x06, 0xC1, 0xD8, 0x33, 0x06, 0x31, 0xFE, 0x3F, 0xC6, 0x1C, 0xC1, 0xB0,
|
||||
0x30, 0x1D, 0x07, 0xE0, 0x18, 0x07, 0x01, 0xE0, 0x3E, 0x06, 0xC1, 0xD8, 0x33, 0x06, 0x31, 0xFE,
|
||||
0x3F, 0xC6, 0x1C, 0xC1, 0xB0, 0x30, 0x1B, 0x07, 0x60, 0x4C, 0x07, 0x01, 0xE0, 0x3E, 0x06, 0xC1,
|
||||
0xD8, 0x33, 0x06, 0x31, 0xFE, 0x3F, 0xC6, 0x1C, 0xC1, 0xB0, 0x30, 0x0E, 0x03, 0xC0, 0x78, 0x06,
|
||||
0x00, 0xE0, 0x3C, 0x07, 0xC0, 0xD8, 0x3B, 0x06, 0x60, 0xC6, 0x3F, 0xC7, 0xF8, 0xC3, 0x98, 0x36,
|
||||
0x06, 0x07, 0xF8, 0x3F, 0xE0, 0xF0, 0x07, 0xC0, 0x1B, 0x00, 0x6F, 0xE3, 0x3F, 0x8F, 0xC0, 0x7F,
|
||||
0x01, 0x8C, 0x06, 0x3F, 0xB0, 0xFE, 0x3E, 0x3F, 0xB8, 0x78, 0x3C, 0x1E, 0x03, 0x01, 0x83, 0xC1,
|
||||
0xE0, 0xFD, 0xEF, 0xE1, 0xC0, 0x70, 0x78, 0x38, 0x30, 0x18, 0x18, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0,
|
||||
0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x0C, 0x18, 0x18, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE,
|
||||
0xFE, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x18, 0x3E, 0x66, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xFE,
|
||||
0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x66, 0x7E, 0x24, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0,
|
||||
0xC0, 0xC0, 0xFF, 0xFF, 0xCD, 0xB6, 0xDB, 0x6D, 0xB6, 0xD8, 0x7B, 0x6D, 0xB6, 0xDB, 0x6D, 0xB0,
|
||||
0x39, 0xFC, 0xCC, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x00, 0xCF, 0xF4, 0x8C, 0x30,
|
||||
0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x00, 0xFF, 0x1F, 0xF0, 0xC7, 0x18, 0x63, 0x0E, 0xF9,
|
||||
0xFF, 0x39, 0x87, 0x30, 0xC6, 0x19, 0xFF, 0x7F, 0xC0, 0x3A, 0x1F, 0x09, 0x1C, 0x3F, 0x1F, 0x8F,
|
||||
0xE7, 0xB3, 0xD9, 0xE6, 0xF3, 0x79, 0xFC, 0x7E, 0x3F, 0x1E, 0x18, 0x06, 0x00, 0xC0, 0xF8, 0x7F,
|
||||
0xB8, 0x6C, 0x1B, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x06, 0xC1, 0xBD, 0xE7, 0xF0, 0x70, 0x0C, 0x03,
|
||||
0x00, 0x80, 0xF8, 0x7F, 0xB8, 0x6C, 0x1B, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x06, 0xC1, 0xBD, 0xE7,
|
||||
0xF0, 0x70, 0x1C, 0x0F, 0x83, 0x20, 0xF8, 0x7F, 0xB8, 0x6C, 0x1B, 0x07, 0xC1, 0xF0, 0x7C, 0x1F,
|
||||
0x06, 0xC1, 0xBD, 0xE7, 0xF0, 0x70, 0x3A, 0x0F, 0x82, 0x40, 0xF8, 0x7F, 0xB8, 0x6C, 0x1B, 0x07,
|
||||
0xC1, 0xF0, 0x7C, 0x1F, 0x06, 0xC1, 0xBD, 0xE7, 0xF0, 0x70, 0x36, 0x0D, 0xC3, 0x20, 0xF8, 0x7F,
|
||||
0xB8, 0x6C, 0x1B, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x06, 0xC1, 0xBD, 0xE7, 0xF0, 0x70, 0x00, 0x67,
|
||||
0x7E, 0x3C, 0x3C, 0x7E, 0x67, 0x42, 0x03, 0x0F, 0xC7, 0xFB, 0x9E, 0xC7, 0xB3, 0x7C, 0xDF, 0x27,
|
||||
0xD9, 0xF6, 0x6F, 0x1B, 0xDE, 0x7F, 0x1F, 0x06, 0x00, 0x18, 0x0C, 0x02, 0x18, 0x3C, 0x1E, 0x0F,
|
||||
0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0xBD, 0xFC, 0x38, 0x0C, 0x06, 0x02, 0x18, 0x3C,
|
||||
0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0xBD, 0xFC, 0x38, 0x1C, 0x1F, 0x0C,
|
||||
0x98, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0xBD, 0xFC, 0x38, 0x36,
|
||||
0x1B, 0x8C, 0x98, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0xBD, 0xFC,
|
||||
0x38, 0x06, 0x03, 0x80, 0xC3, 0x03, 0xE1, 0xD8, 0x63, 0x38, 0xEC, 0x1E, 0x07, 0x80, 0xC0, 0x30,
|
||||
0x0C, 0x03, 0x00, 0xC0, 0xC0, 0x60, 0x3F, 0x9F, 0xEC, 0x3E, 0x0F, 0x07, 0x87, 0xFF, 0x7F, 0x30,
|
||||
0x18, 0x00, 0x3E, 0x3F, 0xB8, 0xD8, 0x6C, 0x66, 0x63, 0x39, 0x9E, 0xC3, 0xF8, 0xFE, 0x7B, 0xF0,
|
||||
0x60, 0x18, 0x06, 0x00, 0xC0, 0x70, 0x3F, 0x18, 0xC6, 0x30, 0xFC, 0x7F, 0x38, 0xC6, 0x79, 0xFF,
|
||||
0x18, 0x00, 0x06, 0x03, 0x00, 0xC0, 0x70, 0x3F, 0x18, 0xC6, 0x30, 0xFC, 0x7F, 0x38, 0xC6, 0x79,
|
||||
0xFF, 0x18, 0x00, 0x1C, 0x0F, 0x83, 0x70, 0x70, 0x3F, 0x18, 0xC6, 0x30, 0xFC, 0x7F, 0x38, 0xC6,
|
||||
0x79, 0xFF, 0x18, 0x00, 0x10, 0x0F, 0xC2, 0xE0, 0x70, 0x3F, 0x18, 0xC6, 0x30, 0xFC, 0x7F, 0x38,
|
||||
0xC6, 0x79, 0xFF, 0x18, 0x00, 0x36, 0x0D, 0xC3, 0x60, 0x70, 0x3F, 0x18, 0xC6, 0x30, 0xFC, 0x7F,
|
||||
0x38, 0xC6, 0x79, 0xFF, 0x18, 0x00, 0x08, 0x07, 0x81, 0x60, 0x70, 0x1C, 0x0F, 0xC6, 0x31, 0x8C,
|
||||
0x3F, 0x1F, 0xCE, 0x31, 0x9E, 0x7F, 0xC6, 0x00, 0x1C, 0x70, 0x7F, 0xF9, 0x8E, 0x33, 0x1C, 0x33,
|
||||
0xFF, 0xEF, 0xFF, 0xF8, 0xE1, 0x33, 0xE6, 0x7E, 0xFC, 0x30, 0x60, 0x0E, 0x0F, 0xC7, 0x39, 0x86,
|
||||
0x60, 0x18, 0x06, 0x19, 0xCE, 0x3F, 0x03, 0x00, 0xE0, 0x78, 0x0C, 0x00, 0x18, 0x0E, 0x03, 0x01,
|
||||
0xC3, 0xF3, 0x9D, 0x86, 0xFF, 0x7F, 0xB0, 0xDC, 0xE7, 0xE0, 0xC0, 0x06, 0x07, 0x03, 0x01, 0xC3,
|
||||
0xF3, 0x9D, 0x86, 0xFF, 0x7F, 0xB0, 0xDC, 0xE7, 0xE0, 0xC0, 0x0C, 0x0F, 0x0C, 0xC1, 0xC3, 0xF3,
|
||||
0x9D, 0x86, 0xFF, 0x7F, 0xB0, 0xDC, 0xE7, 0xE0, 0xC0, 0x12, 0x1F, 0x8C, 0xC1, 0xC3, 0xF3, 0x9D,
|
||||
0x86, 0xFF, 0x7F, 0xB0, 0xDC, 0xE7, 0xE0, 0xC0, 0xDD, 0x86, 0xDB, 0x6D, 0xB0, 0x6E, 0xC0, 0xCC,
|
||||
0xCC, 0xCC, 0xCC, 0x31, 0xEC, 0xC0, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x4B, 0xFC, 0xC0, 0x30,
|
||||
0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x02, 0x07, 0x80, 0xE0, 0x3C, 0x0D, 0x8F, 0xE7, 0x39, 0x87, 0x60,
|
||||
0xD8, 0x36, 0x19, 0xCE, 0x3F, 0x03, 0x00, 0x10, 0x3E, 0x6C, 0x1C, 0xFE, 0xE3, 0xC3, 0xC3, 0xC3,
|
||||
0xC3, 0xC3, 0xC3, 0x18, 0x03, 0x00, 0xC0, 0x38, 0x3F, 0x1C, 0xE6, 0x1D, 0x83, 0x60, 0xD8, 0x67,
|
||||
0x38, 0xFC, 0x0C, 0x00, 0x06, 0x01, 0x80, 0xC0, 0x38, 0x3F, 0x1C, 0xE6, 0x1D, 0x83, 0x60, 0xD8,
|
||||
0x67, 0x38, 0xFC, 0x0C, 0x00, 0x0C, 0x07, 0x83, 0x30, 0x38, 0x3F, 0x1C, 0xE6, 0x1D, 0x83, 0x60,
|
||||
0xD8, 0x67, 0x38, 0xFC, 0x0C, 0x00, 0x08, 0x07, 0xC3, 0x70, 0x38, 0x3F, 0x1C, 0xE6, 0x1D, 0x83,
|
||||
0x60, 0xD8, 0x67, 0x38, 0xFC, 0x0C, 0x00, 0x12, 0x0F, 0xC1, 0xB0, 0x38, 0x3F, 0x1C, 0xE6, 0x1D,
|
||||
0x83, 0x60, 0xD8, 0x67, 0x38, 0xFC, 0x0C, 0x00, 0x18, 0x1C, 0x18, 0xFF, 0xFF, 0x00, 0x1C, 0x18,
|
||||
0x00, 0x03, 0xE3, 0xF1, 0xCE, 0x67, 0xDB, 0x36, 0xCD, 0xE6, 0x7B, 0x8F, 0xC2, 0xC0, 0x00, 0x30,
|
||||
0x38, 0x18, 0x01, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x10, 0x0C, 0x1C, 0x18, 0x01,
|
||||
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x10, 0x18, 0x3C, 0x66, 0x01, 0xC3, 0xC3, 0xC3,
|
||||
0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x10, 0x24, 0x7E, 0x66, 0x01, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
||||
0xE7, 0x7F, 0x10, 0x0C, 0x1C, 0x18, 0x01, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x13,
|
||||
0x03, 0x7F, 0x7E, 0xC0, 0x60, 0x30, 0x1B, 0x8F, 0xF7, 0x1F, 0x07, 0x83, 0xC1, 0xE0, 0xFC, 0xDF,
|
||||
0xEC, 0xC6, 0x03, 0x01, 0x80, 0x24, 0x7E, 0x76, 0x01, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7,
|
||||
0x7F, 0x13, 0x03, 0x7F, 0x7E, 0x3F, 0x03, 0xC0, 0x38, 0x0F, 0x01, 0xF0, 0x36, 0x0E, 0xC1, 0x98,
|
||||
0x31, 0x8F, 0xF1, 0xFE, 0x30, 0xE6, 0x0D, 0x81, 0x80, 0x3F, 0x0F, 0x81, 0xC0, 0xFC, 0x63, 0x18,
|
||||
0xC3, 0xF1, 0xFC, 0xE3, 0x19, 0xE7, 0xFC, 0x60, 0x33, 0x03, 0xE0, 0x38, 0x07, 0x01, 0xE0, 0x3E,
|
||||
0x06, 0xC1, 0xD8, 0x33, 0x06, 0x31, 0xFE, 0x3F, 0xC6, 0x1C, 0xC1, 0xB0, 0x30, 0x32, 0x0F, 0x81,
|
||||
0xE0, 0x70, 0x3F, 0x18, 0xC6, 0x30, 0xFC, 0x7F, 0x38, 0xC6, 0x79, 0xFF, 0x18, 0x00, 0x0E, 0x03,
|
||||
0xC0, 0x7C, 0x0D, 0x83, 0xB0, 0x66, 0x0C, 0x63, 0xFC, 0x7F, 0x8C, 0x39, 0x83, 0x60, 0x60, 0x0C,
|
||||
0x01, 0xC0, 0x38, 0x1C, 0x0F, 0xC6, 0x31, 0x8C, 0x3F, 0x1F, 0xCE, 0x31, 0x9E, 0x7F, 0xC6, 0x60,
|
||||
0x18, 0x07, 0x0C, 0x06, 0x02, 0x07, 0xC7, 0xF7, 0x0F, 0x07, 0x83, 0xC0, 0x60, 0x30, 0x78, 0x3C,
|
||||
0x1F, 0xBD, 0xFC, 0x38, 0x06, 0x01, 0x80, 0xC0, 0x38, 0x3F, 0x1C, 0xE6, 0x19, 0x80, 0x60, 0x18,
|
||||
0x67, 0x38, 0xFC, 0x0C, 0x00, 0x1C, 0x1F, 0x0C, 0x87, 0xC7, 0xF7, 0x0F, 0x07, 0x83, 0xC0, 0x60,
|
||||
0x30, 0x78, 0x3C, 0x1F, 0xBD, 0xFC, 0x38, 0x0C, 0x07, 0x83, 0x30, 0x38, 0x3F, 0x1C, 0xE6, 0x19,
|
||||
0x80, 0x60, 0x18, 0x67, 0x38, 0xFC, 0x0C, 0x00, 0x1C, 0x0E, 0x02, 0x07, 0xC7, 0xF7, 0x0F, 0x07,
|
||||
0x83, 0xC0, 0x60, 0x30, 0x78, 0x3C, 0x1F, 0xBD, 0xFC, 0x38, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x3F,
|
||||
0x1C, 0xE6, 0x19, 0x80, 0x60, 0x18, 0x67, 0x38, 0xFC, 0x0C, 0x00, 0x36, 0x1F, 0x07, 0x07, 0xC7,
|
||||
0xF7, 0x0F, 0x07, 0x83, 0xC0, 0x60, 0x30, 0x78, 0x3C, 0x1F, 0xBD, 0xFC, 0x38, 0x33, 0x07, 0xC0,
|
||||
0xE0, 0x38, 0x3F, 0x1C, 0xE6, 0x19, 0x80, 0x60, 0x18, 0x67, 0x38, 0xFC, 0x0C, 0x00, 0x3B, 0x03,
|
||||
0xC0, 0x30, 0x7F, 0x8F, 0xF8, 0x63, 0x8C, 0x31, 0x87, 0x30, 0xE6, 0x1C, 0xC3, 0x98, 0x63, 0x0C,
|
||||
0xFF, 0xBF, 0xE0, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x39, 0xE3, 0xFC, 0x38, 0xE1, 0x87, 0x0C, 0x18,
|
||||
0x60, 0xC3, 0x0E, 0x1C, 0xF0, 0x7F, 0x80, 0xC0, 0x00, 0xFF, 0x1F, 0xF0, 0xC7, 0x18, 0x63, 0x0E,
|
||||
0xF9, 0xFF, 0x39, 0x87, 0x30, 0xC6, 0x19, 0xFF, 0x7F, 0xC0, 0x00, 0xC0, 0xFC, 0x1F, 0x8E, 0x63,
|
||||
0xFC, 0xE3, 0x98, 0x73, 0x06, 0x60, 0xCC, 0x39, 0xCF, 0x1F, 0xE0, 0xC0, 0x7E, 0x3C, 0xFF, 0xFF,
|
||||
0xC0, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x3F, 0x1F, 0x83, 0x87, 0xE7, 0x3B,
|
||||
0x0D, 0xFE, 0xFF, 0x61, 0xB9, 0xCF, 0xC1, 0x80, 0x66, 0x7E, 0x1C, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0,
|
||||
0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x33, 0x1F, 0x87, 0x81, 0xC3, 0xF3, 0x9D, 0x86, 0xFF,
|
||||
0x7F, 0xB0, 0xDC, 0xE7, 0xE0, 0xC0, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xFE,
|
||||
0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x0C, 0x06, 0x03, 0x01, 0xC3, 0xF3, 0x9D, 0x86, 0xFF, 0x7F, 0xB0,
|
||||
0xDC, 0xE7, 0xE0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF,
|
||||
0x06, 0x07, 0x07, 0x0E, 0x1F, 0x9C, 0xEC, 0x37, 0xFB, 0xFD, 0x86, 0xE7, 0x3F, 0x07, 0x01, 0xC0,
|
||||
0xE0, 0x66, 0x3C, 0x18, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF,
|
||||
0x33, 0x0F, 0x03, 0x81, 0xC3, 0xF3, 0x9D, 0x86, 0xFF, 0x7F, 0xB0, 0xDC, 0xE7, 0xE0, 0xC0, 0x1C,
|
||||
0x1F, 0x0C, 0x87, 0xC7, 0xF7, 0x0F, 0x07, 0x83, 0xC0, 0x67, 0xF3, 0xF8, 0x3C, 0x1F, 0xBD, 0xFE,
|
||||
0x30, 0x0E, 0x07, 0xC1, 0xB0, 0x72, 0x3F, 0xDC, 0x76, 0x1D, 0x83, 0x60, 0xD8, 0x77, 0xBC, 0xFF,
|
||||
0x00, 0xC0, 0x33, 0xFC, 0xFE, 0x32, 0x1F, 0x07, 0x07, 0xC7, 0xF7, 0x0F, 0x07, 0x83, 0xC0, 0x67,
|
||||
0xF3, 0xF8, 0x3C, 0x1F, 0xBD, 0xFE, 0x30, 0x19, 0x07, 0xC0, 0xE0, 0x72, 0x3F, 0xDC, 0x76, 0x1D,
|
||||
0x83, 0x60, 0xD8, 0x77, 0xBC, 0xFF, 0x00, 0xC0, 0x33, 0xFC, 0xFE, 0x0C, 0x0E, 0x02, 0x07, 0xC7,
|
||||
0xF7, 0x0F, 0x07, 0x83, 0xC0, 0x67, 0xF3, 0xF8, 0x3C, 0x1F, 0xBD, 0xFE, 0x30, 0x04, 0x03, 0x80,
|
||||
0x40, 0x72, 0x3F, 0xDC, 0x76, 0x1D, 0x83, 0x60, 0xD8, 0x77, 0xBC, 0xFF, 0x00, 0xC0, 0x33, 0xFC,
|
||||
0xFE, 0x3E, 0x3F, 0xB8, 0x78, 0x3C, 0x1E, 0x03, 0x3F, 0x9F, 0xC1, 0xE0, 0xFD, 0xEF, 0xF1, 0x80,
|
||||
0xE0, 0x70, 0x18, 0x08, 0x00, 0x06, 0x03, 0x00, 0xE0, 0x38, 0x1C, 0x8F, 0xF7, 0x1D, 0x87, 0x60,
|
||||
0xD8, 0x36, 0x1D, 0xEF, 0x3F, 0xC0, 0x30, 0x0C, 0xFF, 0x3F, 0x80, 0x1C, 0x1F, 0x0D, 0x98, 0x3C,
|
||||
0x1E, 0x0F, 0x07, 0x83, 0xFF, 0xFF, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x06, 0x38, 0x1F, 0x0C, 0xC0,
|
||||
0xC0, 0x30, 0x0C, 0x03, 0x70, 0xFE, 0x38, 0xCC, 0x33, 0x0C, 0xC3, 0x30, 0xCC, 0x33, 0x0C, 0x60,
|
||||
0xCC, 0x1B, 0xFF, 0xFF, 0xF6, 0x0C, 0xFF, 0x9F, 0xF3, 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0x60,
|
||||
0x60, 0x7E, 0x3F, 0x0D, 0xC7, 0xF3, 0x8D, 0x86, 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x30, 0x6F, 0xF1,
|
||||
0x8C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x00, 0x23, 0xFD, 0x80, 0x30, 0xC3, 0x0C,
|
||||
0x30, 0xC3, 0x0C, 0xFD, 0xE3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, 0xFF, 0xF0,
|
||||
0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x00, 0xCF, 0xF3, 0x8C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C,
|
||||
0x30, 0xC3, 0x00, 0xCF, 0xF7, 0x80, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0xDB, 0x6D, 0xB6, 0xDB,
|
||||
0x6D, 0xB8, 0xDB, 0x0D, 0xB6, 0xDB, 0x6D, 0xB8, 0xDB, 0x6D, 0xB6, 0xDB, 0x6D, 0xB0, 0x3F, 0xFF,
|
||||
0xC0, 0xF9, 0xFF, 0x9F, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x20, 0xC0, 0x0C, 0x30, 0xC3, 0x0C,
|
||||
0x39, 0xC1, 0xF8, 0x06, 0x00, 0xCD, 0x9F, 0x30, 0x2C, 0xD9, 0xB3, 0x66, 0xCD, 0x9B, 0x36, 0x60,
|
||||
0xC1, 0x87, 0x0C, 0x07, 0x03, 0xE0, 0xCC, 0x3E, 0x0F, 0x80, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xCC,
|
||||
0x33, 0x0C, 0xE3, 0x1D, 0xC7, 0xE0, 0x60, 0x31, 0xEC, 0xC0, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C,
|
||||
0x30, 0xCF, 0x18, 0xC3, 0xE3, 0xB3, 0x9B, 0x8F, 0x87, 0x83, 0xC1, 0xF0, 0xDC, 0x67, 0x31, 0xD8,
|
||||
0x70, 0x00, 0xC0, 0x70, 0x30, 0x18, 0x00, 0xC0, 0xC0, 0xC0, 0xC2, 0xCE, 0xDC, 0xF8, 0xF0, 0xF0,
|
||||
0xD8, 0xCE, 0xC7, 0x00, 0x38, 0x38, 0x18, 0x10, 0x02, 0xCE, 0xDC, 0xF8, 0xF0, 0xF0, 0xD8, 0xCE,
|
||||
0xC7, 0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF,
|
||||
0x7B, 0x6D, 0xB6, 0xDB, 0x6D, 0xB0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
|
||||
0xFF, 0xFF, 0x00, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0xFF, 0x3F, 0xC0, 0xD8, 0xD8, 0xD0, 0xD0,
|
||||
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xDE, 0xF5, 0xAC, 0x63, 0x18, 0xC6, 0x31, 0x80,
|
||||
0xC0, 0xC0, 0xC0, 0xC0, 0xC4, 0xCE, 0xC4, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC3, 0x0C, 0x30, 0xC3,
|
||||
0x0C, 0xB7, 0xCB, 0x0C, 0x30, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x0F, 0x07, 0x03, 0xC0, 0x30,
|
||||
0x0C, 0x03, 0xFC, 0xFF, 0x30, 0xC3, 0x0C, 0x30, 0xF3, 0xFC, 0xF0, 0xC3, 0x0C, 0x0C, 0x06, 0x02,
|
||||
0x1C, 0x3F, 0x1F, 0x8F, 0xE7, 0xB3, 0xD9, 0xE6, 0xF3, 0x79, 0xFC, 0x7E, 0x3F, 0x1E, 0x0C, 0x0C,
|
||||
0x18, 0x1C, 0xFE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE1, 0xF8, 0xFC, 0x7F, 0x3D, 0x9E,
|
||||
0xCF, 0x37, 0x9B, 0xCF, 0xE3, 0xF1, 0xF8, 0xF0, 0x00, 0xE0, 0x70, 0x18, 0x08, 0x00, 0x1C, 0xFE,
|
||||
0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x00, 0x18, 0x18, 0x18, 0x18, 0x36, 0x1F, 0x07, 0x1C,
|
||||
0x3F, 0x1F, 0x8F, 0xE7, 0xB3, 0xD9, 0xE6, 0xF3, 0x79, 0xFC, 0x7E, 0x3F, 0x1E, 0x66, 0x3E, 0x1C,
|
||||
0x1C, 0xFE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xE0, 0x60, 0xC0, 0x1C, 0xFE, 0xE3,
|
||||
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE1, 0xF8, 0xFC, 0x7F, 0x3D, 0x9E, 0xCF, 0x37, 0x9B, 0xCF,
|
||||
0xE3, 0xF1, 0xF8, 0xF0, 0x18, 0x0C, 0x1E, 0x0E, 0x1C, 0xFE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
||||
0xC3, 0x03, 0x03, 0x0F, 0x0E, 0x3E, 0x0F, 0x83, 0xE1, 0xFE, 0xE1, 0xB0, 0x6C, 0x1F, 0x07, 0xC1,
|
||||
0xF0, 0x7C, 0x1B, 0x06, 0xF7, 0x9F, 0xC1, 0xC0, 0x3F, 0x0F, 0xC0, 0xE0, 0xFC, 0x73, 0x98, 0x76,
|
||||
0x0D, 0x83, 0x61, 0x9C, 0xE3, 0xF0, 0x30, 0x32, 0x0F, 0x81, 0xC0, 0xF8, 0x7F, 0xB8, 0x6C, 0x1B,
|
||||
0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x06, 0xC1, 0xBD, 0xE7, 0xF0, 0x70, 0x33, 0x07, 0xC1, 0xE0, 0x38,
|
||||
0x3F, 0x1C, 0xE6, 0x1D, 0x83, 0x60, 0xD8, 0x67, 0x38, 0xFC, 0x0C, 0x00, 0x1F, 0x0F, 0x83, 0x40,
|
||||
0xF8, 0x7F, 0xB8, 0x6C, 0x1B, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x06, 0xC1, 0xBD, 0xE7, 0xF0, 0x70,
|
||||
0x0F, 0x06, 0xC1, 0xE0, 0x38, 0x3F, 0x1C, 0xE6, 0x1D, 0x83, 0x60, 0xD8, 0x67, 0x38, 0xFC, 0x0C,
|
||||
0x00, 0x1F, 0xF3, 0xFF, 0xB9, 0x81, 0x8C, 0x0C, 0x60, 0x63, 0xFB, 0x1F, 0xD8, 0xC0, 0xC6, 0x07,
|
||||
0x30, 0x1F, 0xFC, 0x7F, 0xF0, 0x0E, 0x1C, 0x1F, 0xBF, 0x1C, 0xF8, 0xCC, 0x38, 0x66, 0x0F, 0xF3,
|
||||
0x07, 0xF9, 0x87, 0x0C, 0xE7, 0xCE, 0x3F, 0x7E, 0x06, 0x0C, 0x00, 0x0C, 0x0E, 0x06, 0x1F, 0xCF,
|
||||
0xF6, 0x0F, 0x07, 0x83, 0xC3, 0xFF, 0xBF, 0xF8, 0x7C, 0x3E, 0x1F, 0x0E, 0x19, 0x8C, 0x3F, 0xF3,
|
||||
0x18, 0xC6, 0x31, 0x80, 0xFE, 0x7F, 0xB0, 0x78, 0x3C, 0x1E, 0x1F, 0xFD, 0xFF, 0xC3, 0xE1, 0xF0,
|
||||
0xF8, 0x70, 0x00, 0xC0, 0x70, 0x38, 0x18, 0x00, 0x1F, 0xF9, 0x8C, 0x63, 0x18, 0xC0, 0x31, 0x8C,
|
||||
0x60, 0x66, 0x1E, 0x06, 0x1F, 0xCF, 0xF6, 0x0F, 0x07, 0x83, 0xC3, 0xFF, 0xBF, 0xF8, 0x7C, 0x3E,
|
||||
0x1F, 0x0E, 0x6C, 0xF8, 0xE0, 0x67, 0xCE, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x00, 0x06, 0x03, 0x80,
|
||||
0xC0, 0xFC, 0x7F, 0x98, 0x66, 0x1D, 0xC2, 0x3E, 0x07, 0xE4, 0x1F, 0x83, 0x60, 0xDC, 0xE3, 0xF8,
|
||||
0x30, 0x0C, 0x0C, 0x18, 0x1C, 0x7E, 0x63, 0x62, 0x7E, 0x1F, 0x63, 0x63, 0x3F, 0x0C, 0x0E, 0x07,
|
||||
0xC3, 0x30, 0xFC, 0x7F, 0x98, 0x66, 0x1D, 0xC2, 0x3E, 0x07, 0xE4, 0x1F, 0x83, 0x60, 0xDC, 0xE3,
|
||||
0xF8, 0x30, 0x1C, 0x3E, 0x76, 0x1C, 0x7E, 0x63, 0x62, 0x7E, 0x1F, 0x63, 0x63, 0x3F, 0x0C, 0x3F,
|
||||
0x1F, 0xE6, 0x19, 0x87, 0x70, 0x8F, 0x81, 0xF9, 0x07, 0xE0, 0xD8, 0x37, 0x38, 0xFE, 0x0E, 0x01,
|
||||
0x81, 0xE0, 0x38, 0x1C, 0x7E, 0x63, 0x62, 0x7E, 0x1F, 0x63, 0x63, 0x3F, 0x0C, 0x0E, 0x1E, 0x1C,
|
||||
0x33, 0x07, 0x80, 0xC0, 0xFC, 0x7F, 0x98, 0x66, 0x1D, 0xC2, 0x3E, 0x07, 0xE4, 0x1F, 0x83, 0x60,
|
||||
0xDC, 0xE3, 0xF8, 0x30, 0x66, 0x3E, 0x1C, 0x1C, 0x7E, 0x63, 0x62, 0x7E, 0x1F, 0x63, 0x63, 0x3F,
|
||||
0x0C, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30,
|
||||
0x0C, 0x03, 0x81, 0xE0, 0x30, 0x00, 0x30, 0x63, 0xFF, 0xE3, 0x06, 0x0C, 0x18, 0x30, 0x70, 0xF1,
|
||||
0x83, 0x8F, 0x0C, 0x33, 0x07, 0x80, 0xC3, 0xFF, 0xFF, 0xC3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00,
|
||||
0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x06, 0x06, 0x1E, 0x1E, 0x7E, 0xFE, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x1C, 0x1E, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x0F, 0xC3, 0xF0, 0x30, 0x0C, 0x03, 0x00,
|
||||
0xC0, 0x30, 0x00, 0x30, 0x63, 0xFF, 0xE3, 0x06, 0x7F, 0xFE, 0x30, 0x70, 0xF0, 0x3A, 0x1F, 0x09,
|
||||
0x18, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0xBD, 0xFC, 0x38, 0x10,
|
||||
0x7E, 0x6C, 0x01, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x10, 0x3E, 0x1F, 0x30, 0x78,
|
||||
0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3F, 0x7B, 0xF8, 0x70, 0x7E, 0x7E, 0x01,
|
||||
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x10, 0x32, 0x1F, 0x07, 0x18, 0x3C, 0x1E, 0x0F,
|
||||
0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0xBD, 0xFC, 0x38, 0x66, 0x7E, 0x3C, 0x01, 0xC3,
|
||||
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x10, 0x1C, 0x0F, 0x07, 0x03, 0x8C, 0x1E, 0x0F, 0x07,
|
||||
0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0xDE, 0xFE, 0x1C, 0x00, 0x08, 0x3C, 0x3C, 0x3C,
|
||||
0x01, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x10, 0x1F, 0x1B, 0x0D, 0x18, 0x3C, 0x1E,
|
||||
0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0xBD, 0xFC, 0x38, 0x16, 0x36, 0x3C, 0x01,
|
||||
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x10, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F,
|
||||
0x07, 0x83, 0xC1, 0xE0, 0xFD, 0xEF, 0xE1, 0xE0, 0x30, 0x18, 0x01, 0x61, 0xB0, 0xD8, 0x6C, 0x36,
|
||||
0x1B, 0x0D, 0xCE, 0x7F, 0x09, 0x80, 0xE0, 0x70, 0x03, 0x80, 0x1F, 0x00, 0xCC, 0x30, 0xE3, 0xE7,
|
||||
0x8D, 0x9E, 0x36, 0x6C, 0xD9, 0xB3, 0x66, 0xDD, 0xBB, 0x66, 0xCD, 0x8F, 0x3E, 0x3C, 0x78, 0xF1,
|
||||
0xE3, 0xC7, 0x80, 0x07, 0x00, 0x7C, 0x03, 0x70, 0x84, 0x26, 0x71, 0xB3, 0xDD, 0x9E, 0xCD, 0xB6,
|
||||
0x6D, 0xB1, 0xE7, 0x8F, 0x3C, 0x71, 0xC0, 0x0E, 0x07, 0xC3, 0x33, 0x03, 0xE1, 0xD8, 0x63, 0x38,
|
||||
0xEC, 0x1E, 0x07, 0x80, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x18, 0x3C, 0x66, 0x01, 0xC3, 0xC3,
|
||||
0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7F, 0x13, 0x03, 0x7F, 0x7E, 0x33, 0x0F, 0xC1, 0x23, 0x03, 0xE1,
|
||||
0xD8, 0x63, 0x38, 0xEC, 0x1E, 0x07, 0x80, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x0E, 0x06, 0x02,
|
||||
0x0F, 0xF7, 0xF8, 0x1C, 0x0C, 0x0C, 0x0E, 0x0E, 0x0E, 0x06, 0x06, 0x07, 0xFF, 0xFE, 0x18, 0x30,
|
||||
0xC7, 0xEF, 0xE1, 0xC7, 0x1C, 0x71, 0xC3, 0xF7, 0xF0, 0x0C, 0x0E, 0x02, 0x0F, 0xF7, 0xF8, 0x1C,
|
||||
0x0C, 0x0C, 0x0E, 0x0E, 0x0E, 0x06, 0x06, 0x07, 0xFF, 0xFE, 0x30, 0x70, 0xC7, 0xEF, 0xE1, 0xC7,
|
||||
0x1C, 0x71, 0xC3, 0xF7, 0xF0, 0x37, 0x0F, 0x03, 0x0F, 0xF7, 0xF8, 0x1C, 0x0C, 0x0C, 0x0E, 0x0E,
|
||||
0x0E, 0x06, 0x06, 0x07, 0xFF, 0xFE, 0xCC, 0xF8, 0xE7, 0xEF, 0xE1, 0xC7, 0x1C, 0x71, 0xC3, 0xF7,
|
||||
0xF0, 0x3C, 0xF3, 0x1C, 0xF0, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x67, 0x30, 0x36, 0x60, 0x38, 0x79,
|
||||
0xB8, 0x20, 0xF9, 0x70, 0x7C, 0xF8, 0x4D, 0xF7, 0x80, 0x6D, 0x80, 0x6C, 0xD9, 0xB0, 0x73, 0xCE,
|
||||
0x60, 0x23, 0x96, 0xE0, 0x6D, 0xB7, 0x80, 0x66, 0xF8, 0xE0, 0x79, 0xB3, 0xC0, 0x39, 0xF4, 0xC0,
|
||||
0x69, 0xB0, 0x66, 0x60, 0x6D, 0x00, 0x6C, 0xD9, 0x00, 0x6D, 0xA0, 0x21, 0x8E, 0xF7, 0x00, 0x44,
|
||||
0x66, 0x4D, 0xF3, 0x80, 0x7C, 0xF8, 0x7C, 0xFC, 0x7F, 0xF7, 0xFF, 0x00, 0x03, 0x06, 0x06, 0x0C,
|
||||
0x18, 0x18, 0x30, 0x30, 0x60, 0x40, 0x00, 0x03, 0x06, 0x06, 0x06, 0x0C, 0x0C, 0x08, 0x18, 0x18,
|
||||
0x30, 0x30, 0x20, 0x60, 0x60, 0x40, 0xFF, 0xE0, 0xFF, 0x7F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC0, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0x46, 0x60, 0x06, 0x73, 0x60, 0x06, 0x73, 0x60, 0x00, 0xD9,
|
||||
0x63, 0xE7, 0xC0, 0x00, 0x00, 0xF9, 0xF1, 0xA6, 0xC0, 0x00, 0x00, 0xF9, 0xF1, 0xA6, 0xC0, 0x00,
|
||||
0x18, 0x18, 0x18, 0x7E, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFE,
|
||||
0xFF, 0x18, 0x18, 0xFE, 0xFF, 0x18, 0x18, 0x18, 0x6F, 0xFF, 0xF0, 0x00, 0x0D, 0xDD, 0xFB, 0x92,
|
||||
0x20, 0x78, 0x30, 0xFC, 0x60, 0xCC, 0xE0, 0xCD, 0xC0, 0x7D, 0x80, 0x3B, 0x00, 0x06, 0x44, 0x0F,
|
||||
0xFF, 0x1D, 0xBB, 0x19, 0x33, 0x31, 0xBB, 0x61, 0xFF, 0x00, 0x44, 0x6D, 0xA4, 0x6D, 0xE7, 0x96,
|
||||
0x58, 0x06, 0x3D, 0xE7, 0x07, 0x07, 0x83, 0x83, 0xC3, 0xC7, 0x87, 0x1D, 0xEE, 0x20, 0x00, 0x60,
|
||||
0x18, 0x07, 0x01, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x06, 0x01, 0x80, 0x60, 0x00, 0x00,
|
||||
0x70, 0x6E, 0x1D, 0xC3, 0x00, 0xC0, 0x30, 0x0E, 0x03, 0x80, 0x60, 0x18, 0x06, 0x19, 0x87, 0xB0,
|
||||
0xF0, 0x04, 0x0F, 0x05, 0x0F, 0x8F, 0xEF, 0xFE, 0xFF, 0x7F, 0xA8, 0xFC, 0x7E, 0xFF, 0x7F, 0xBF,
|
||||
0xFB, 0xF9, 0xF0, 0xF0, 0x3F, 0x8F, 0xE3, 0x00, 0xC0, 0x30, 0x0F, 0xE3, 0xF8, 0xC0, 0x7C, 0x3F,
|
||||
0x83, 0x00, 0xC0, 0x1F, 0x0F, 0xE3, 0x1C, 0xC3, 0x30, 0xDF, 0x03, 0x01, 0xF0, 0x30, 0x0C, 0x07,
|
||||
0xF9, 0xFF, 0x38, 0x63, 0xC6, 0x3C, 0x63, 0xC6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x33, 0x63,
|
||||
0x3E, 0x31, 0xE3, 0x1E, 0x3F, 0x83, 0xFC, 0x30, 0xCF, 0xFF, 0xFF, 0xF3, 0x1C, 0x3F, 0xC3, 0xF0,
|
||||
0x30, 0x03, 0x00, 0x30, 0x03, 0x00, 0x63, 0xC6, 0x63, 0xC6, 0x63, 0xCE, 0x63, 0xCC, 0xFF, 0xFE,
|
||||
0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0x36, 0x6C, 0x3C, 0x78, 0x3C, 0x78, 0x1C, 0x38, 0x00, 0xC0,
|
||||
0xFC, 0x1F, 0x8E, 0x63, 0xFC, 0xE3, 0x98, 0x73, 0x06, 0x60, 0xCC, 0x39, 0xCF, 0x1F, 0xE0, 0xC0,
|
||||
0xFF, 0x80, 0x1F, 0x87, 0xF8, 0xC3, 0x98, 0x3F, 0xC7, 0xFC, 0x3F, 0x07, 0xF3, 0x70, 0x66, 0x1C,
|
||||
0xF7, 0x0F, 0xE0, 0x60, 0x30, 0xC6, 0x38, 0xCE, 0x1B, 0x83, 0xE1, 0xFF, 0x3F, 0xE1, 0xF0, 0x37,
|
||||
0x06, 0x70, 0xC7, 0x18, 0x70, 0x3F, 0x83, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x3F, 0xC3,
|
||||
0xF0, 0x30, 0x03, 0x00, 0x30, 0x03, 0x00, 0x08, 0x06, 0x0F, 0x8F, 0xEE, 0xDE, 0x6F, 0x37, 0x98,
|
||||
0xCF, 0xE7, 0xF3, 0x79, 0xBF, 0xFB, 0xFC, 0x70, 0x18, 0x08, 0x06, 0x0F, 0x8F, 0xEE, 0xDE, 0x6F,
|
||||
0x37, 0x98, 0xCC, 0x66, 0xF3, 0x79, 0xBF, 0xFB, 0xF8, 0x70, 0x18, 0xFF, 0xFF, 0xE0, 0x63, 0xFF,
|
||||
0xFF, 0x81, 0x8F, 0xE3, 0xF8, 0x06, 0x01, 0x80, 0x60, 0x18, 0x30, 0x18, 0x0F, 0x0F, 0x8F, 0x01,
|
||||
0xE3, 0xE7, 0x63, 0x31, 0x99, 0x8F, 0xC7, 0xC0, 0x0C, 0x03, 0x03, 0xF1, 0xFE, 0xED, 0xB3, 0x7C,
|
||||
0xCF, 0x33, 0xCC, 0xF3, 0x3C, 0xCF, 0x33, 0xC0, 0xF0, 0x30, 0x3F, 0x87, 0xF8, 0xC3, 0x18, 0x73,
|
||||
0x0C, 0xFF, 0xBF, 0xE1, 0x80, 0xFF, 0x06, 0x00, 0xC0, 0x18, 0x00, 0x1E, 0x07, 0x8F, 0xF3, 0xFE,
|
||||
0x30, 0xCC, 0x33, 0x0C, 0xFE, 0x3F, 0x8C, 0x73, 0x0C, 0xC3, 0xFF, 0xFF, 0xE1, 0xE0, 0x78, 0x08,
|
||||
0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0F, 0xFF, 0xBF, 0xFC, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00,
|
||||
0x0C, 0x07, 0x83, 0xF1, 0xF6, 0x6C, 0xC3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x00,
|
||||
0x80, 0x06, 0x00, 0x18, 0x00, 0x6F, 0xFF, 0xBF, 0xFC, 0x01, 0xC0, 0x1C, 0x00, 0xC0, 0x00, 0x00,
|
||||
0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC1, 0x32, 0x6D, 0xCF, 0xE1, 0xF0, 0x38, 0x00,
|
||||
0x00, 0x08, 0x80, 0xE6, 0x0E, 0x18, 0xE0, 0x6F, 0xFF, 0xBF, 0xFC, 0xC1, 0xC3, 0x1C, 0x0C, 0xC0,
|
||||
0x00, 0x00, 0x0C, 0x07, 0x83, 0xF1, 0xF6, 0x6C, 0xC3, 0x00, 0xC1, 0x32, 0x6D, 0xCF, 0xE1, 0xF0,
|
||||
0x38, 0x00, 0x00, 0x7C, 0x7F, 0x38, 0x1E, 0x0F, 0x86, 0xE3, 0x38, 0x0E, 0x03, 0x80, 0x00, 0x1F,
|
||||
0x1F, 0xC0, 0xE0, 0xF0, 0xF8, 0xEC, 0xE6, 0xE0, 0xE0, 0x00, 0x00, 0x00, 0x70, 0x1C, 0x27, 0x31,
|
||||
0xD8, 0x7C, 0x1E, 0x3F, 0x3F, 0x80, 0x00, 0x01, 0xE1, 0xD9, 0xCD, 0xC7, 0xC3, 0xC1, 0xF8, 0xFE,
|
||||
0x00, 0x38, 0x1E, 0x03, 0x87, 0xE7, 0xF7, 0x3B, 0x0F, 0x83, 0xC1, 0xE1, 0xB9, 0xCF, 0xC1, 0x80,
|
||||
0x01, 0x03, 0xC3, 0xF9, 0xDE, 0x66, 0xDB, 0xB6, 0xCD, 0xB3, 0x7B, 0x8F, 0xC3, 0xC0, 0xC0, 0x0E,
|
||||
0x07, 0x81, 0xE0, 0x6C, 0x33, 0x0C, 0xC3, 0x39, 0xC6, 0x61, 0x98, 0x67, 0xFF, 0xFF, 0xFF, 0x7F,
|
||||
0xB0, 0xD8, 0x6C, 0x36, 0x1B, 0x0D, 0x86, 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x1B, 0x0D, 0x82,
|
||||
0x7F, 0xDF, 0xF6, 0x00, 0xC0, 0x38, 0x07, 0x00, 0xC0, 0x18, 0x0E, 0x03, 0x01, 0x80, 0xE0, 0x70,
|
||||
0x18, 0x07, 0xFD, 0xFF, 0xFF, 0xFF, 0x06, 0x0C, 0x30, 0x60, 0xC3, 0x06, 0x0C, 0x30, 0x60, 0xC3,
|
||||
0x06, 0x0C, 0x30, 0x60, 0xC0, 0x77, 0xBF, 0xE0, 0x00, 0x00, 0xC0, 0x30, 0x0C, 0x06, 0x01, 0x80,
|
||||
0x60, 0x18, 0x0C, 0x73, 0x3C, 0xC3, 0x30, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x13, 0x1F, 0xE6, 0xCD,
|
||||
0xB3, 0x7F, 0x8E, 0xE0, 0x1C, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xCF, 0x38,
|
||||
0x3B, 0x7F, 0xCE, 0x3B, 0x7F, 0xCE, 0x00, 0x0C, 0x0C, 0xFF, 0xFF, 0x7F, 0xFF, 0x30, 0x30, 0x01,
|
||||
0x0F, 0x3E, 0xF0, 0xF0, 0x7C, 0x1F, 0x03, 0x7F, 0xFF, 0xC0, 0xF0, 0x7E, 0x0F, 0x07, 0x3E, 0xF8,
|
||||
0xC0, 0x7F, 0xFF,
|
||||
};
|
||||
|
||||
static const EpdGlyph spacegroteskGlyphs[] = {
|
||||
{ 0, 0, 10, 0, 0, 0, 0 }, //
|
||||
{ 0, 0, 4, 0, 0, 0, 0 }, //
|
||||
{ 4, 13, 4, 0, 12, 7, 0 }, // !
|
||||
{ 7, 6, 7, 0, 13, 6, 7 }, // "
|
||||
{ 10, 12, 10, 0, 12, 15, 13 }, // #
|
||||
{ 10, 16, 10, 0, 14, 20, 28 }, // $
|
||||
{ 13, 13, 13, 0, 12, 22, 48 }, // %
|
||||
{ 10, 12, 10, 0, 12, 15, 70 }, // &
|
||||
{ 4, 6, 4, 0, 13, 3, 85 }, // '
|
||||
{ 6, 17, 6, 1, 13, 13, 88 }, // (
|
||||
{ 6, 17, 6, 0, 13, 13, 101 }, // )
|
||||
{ 8, 8, 9, 0, 12, 8, 114 }, // *
|
||||
{ 8, 8, 10, 1, 10, 8, 122 }, // +
|
||||
{ 4, 6, 4, 0, 3, 3, 130 }, // ,
|
||||
{ 6, 2, 8, 1, 5, 2, 133 }, // -
|
||||
{ 4, 4, 4, 0, 3, 2, 135 }, // .
|
||||
{ 7, 16, 6, 0, 12, 14, 137 }, // /
|
||||
{ 9, 13, 11, 1, 12, 15, 151 }, // 0
|
||||
{ 6, 12, 7, 0, 12, 9, 166 }, // 1
|
||||
{ 10, 12, 10, 0, 12, 15, 175 }, // 2
|
||||
{ 10, 13, 10, 0, 12, 17, 190 }, // 3
|
||||
{ 10, 12, 10, 0, 12, 15, 207 }, // 4
|
||||
{ 10, 13, 10, 0, 12, 17, 222 }, // 5
|
||||
{ 9, 13, 10, 1, 12, 15, 239 }, // 6
|
||||
{ 9, 12, 9, 0, 12, 14, 254 }, // 7
|
||||
{ 10, 13, 10, 0, 12, 17, 268 }, // 8
|
||||
{ 10, 13, 10, 0, 12, 17, 285 }, // 9
|
||||
{ 4, 10, 4, 0, 9, 5, 302 }, // :
|
||||
{ 4, 12, 4, 0, 9, 6, 307 }, // ;
|
||||
{ 8, 8, 10, 1, 10, 8, 313 }, // <
|
||||
{ 8, 5, 10, 1, 8, 5, 321 }, // =
|
||||
{ 8, 8, 10, 1, 10, 8, 326 }, // >
|
||||
{ 9, 13, 10, 0, 12, 15, 334 }, // ?
|
||||
{ 15, 16, 17, 1, 12, 30, 349 }, // @
|
||||
{ 11, 12, 11, 0, 12, 17, 379 }, // A
|
||||
{ 11, 12, 11, 0, 12, 17, 396 }, // B
|
||||
{ 9, 13, 11, 1, 12, 15, 413 }, // C
|
||||
{ 11, 12, 11, 0, 12, 17, 428 }, // D
|
||||
{ 8, 12, 9, 1, 12, 12, 445 }, // E
|
||||
{ 8, 12, 9, 1, 12, 12, 457 }, // F
|
||||
{ 9, 13, 11, 1, 12, 15, 469 }, // G
|
||||
{ 9, 12, 11, 1, 12, 14, 484 }, // H
|
||||
{ 2, 12, 4, 1, 12, 3, 498 }, // I
|
||||
{ 10, 13, 10, 0, 12, 17, 501 }, // J
|
||||
{ 9, 12, 10, 1, 12, 14, 518 }, // K
|
||||
{ 8, 12, 9, 1, 12, 12, 532 }, // L
|
||||
{ 13, 12, 14, 1, 12, 20, 544 }, // M
|
||||
{ 9, 12, 11, 1, 12, 14, 564 }, // N
|
||||
{ 10, 13, 11, 1, 12, 17, 578 }, // O
|
||||
{ 9, 12, 10, 1, 12, 14, 595 }, // P
|
||||
{ 10, 15, 11, 1, 12, 19, 609 }, // Q
|
||||
{ 9, 12, 11, 1, 12, 14, 628 }, // R
|
||||
{ 10, 13, 10, 0, 12, 17, 642 }, // S
|
||||
{ 10, 12, 10, 0, 12, 15, 659 }, // T
|
||||
{ 9, 13, 11, 1, 12, 15, 674 }, // U
|
||||
{ 10, 12, 10, 0, 12, 15, 689 }, // V
|
||||
{ 14, 12, 15, 0, 12, 21, 704 }, // W
|
||||
{ 11, 12, 11, 0, 12, 17, 725 }, // X
|
||||
{ 10, 12, 10, 0, 12, 15, 742 }, // Y
|
||||
{ 9, 12, 10, 0, 12, 14, 757 }, // Z
|
||||
{ 5, 17, 6, 1, 13, 11, 771 }, // [
|
||||
{ 8, 16, 6, -1, 12, 16, 782 }, // <backslash>
|
||||
{ 5, 17, 6, 0, 13, 11, 798 }, // ]
|
||||
{ 9, 5, 10, 1, 12, 6, 809 }, // ^
|
||||
{ 9, 3, 10, 1, 0, 4, 815 }, // _
|
||||
{ 4, 3, 5, 0, 12, 2, 819 }, // `
|
||||
{ 10, 10, 10, 0, 9, 13, 821 }, // a
|
||||
{ 9, 13, 11, 1, 12, 15, 834 }, // b
|
||||
{ 10, 10, 10, 0, 9, 13, 849 }, // c
|
||||
{ 10, 13, 11, 0, 12, 17, 862 }, // d
|
||||
{ 9, 10, 10, 0, 9, 12, 879 }, // e
|
||||
{ 7, 12, 7, 0, 12, 11, 891 }, // f
|
||||
{ 10, 13, 11, 0, 9, 17, 902 }, // g
|
||||
{ 8, 12, 10, 1, 12, 12, 919 }, // h
|
||||
{ 3, 12, 4, 1, 12, 5, 931 }, // i
|
||||
{ 5, 16, 4, -1, 12, 10, 936 }, // j
|
||||
{ 8, 12, 9, 1, 12, 12, 946 }, // k
|
||||
{ 2, 12, 4, 1, 12, 3, 958 }, // l
|
||||
{ 13, 9, 14, 1, 9, 15, 961 }, // m
|
||||
{ 8, 9, 10, 1, 9, 9, 976 }, // n
|
||||
{ 10, 10, 10, 0, 9, 13, 985 }, // o
|
||||
{ 9, 13, 11, 1, 9, 15, 998 }, // p
|
||||
{ 10, 13, 11, 0, 9, 17, 1013 }, // q
|
||||
{ 5, 9, 6, 1, 9, 6, 1030 }, // r
|
||||
{ 8, 10, 9, 0, 9, 10, 1036 }, // s
|
||||
{ 7, 12, 8, 0, 12, 11, 1046 }, // t
|
||||
{ 8, 10, 10, 1, 9, 10, 1057 }, // u
|
||||
{ 9, 9, 9, 0, 9, 11, 1067 }, // v
|
||||
{ 13, 9, 13, 0, 9, 15, 1078 }, // w
|
||||
{ 10, 9, 10, 0, 9, 12, 1093 }, // x
|
||||
{ 8, 13, 10, 1, 9, 13, 1105 }, // y
|
||||
{ 7, 9, 9, 1, 9, 8, 1118 }, // z
|
||||
{ 7, 17, 7, 0, 13, 15, 1126 }, // {
|
||||
{ 2, 19, 4, 1, 14, 5, 1141 }, // |
|
||||
{ 7, 17, 7, 0, 13, 15, 1146 }, // }
|
||||
{ 8, 4, 10, 1, 8, 4, 1161 }, // ~
|
||||
{ 0, 0, 4, 0, 0, 0, 1165 }, //
|
||||
{ 4, 13, 4, 0, 9, 7, 1165 }, // ¡
|
||||
{ 9, 13, 10, 1, 11, 15, 1172 }, // ¢
|
||||
{ 10, 12, 10, 0, 12, 15, 1187 }, // £
|
||||
{ 10, 10, 10, 0, 11, 13, 1202 }, // ¤
|
||||
{ 11, 12, 10, 0, 12, 17, 1215 }, // ¥
|
||||
{ 2, 19, 4, 1, 14, 5, 1232 }, // ¦
|
||||
{ 8, 13, 8, 0, 12, 13, 1237 }, // §
|
||||
{ 7, 3, 7, 0, 12, 3, 1250 }, // ¨
|
||||
{ 10, 13, 12, 1, 12, 17, 1253 }, // ©
|
||||
{ 7, 7, 7, 0, 12, 7, 1270 }, // ª
|
||||
{ 11, 8, 11, 0, 8, 11, 1277 }, // «
|
||||
{ 8, 4, 10, 1, 7, 4, 1288 }, // ¬
|
||||
{ 6, 2, 8, 1, 5, 2, 1292 }, //
|
||||
{ 8, 8, 9, 0, 12, 8, 1294 }, // ®
|
||||
{ 7, 2, 7, 0, 11, 2, 1302 }, // ¯
|
||||
{ 6, 6, 6, 0, 12, 5, 1304 }, // °
|
||||
{ 8, 10, 10, 1, 10, 10, 1309 }, // ±
|
||||
{ 6, 7, 6, 0, 13, 6, 1319 }, // ²
|
||||
{ 6, 7, 6, 0, 12, 6, 1325 }, // ³
|
||||
{ 4, 3, 5, 0, 12, 2, 1331 }, // ´
|
||||
{ 9, 13, 10, 1, 9, 15, 1333 }, // µ
|
||||
{ 9, 12, 10, 0, 12, 14, 1348 }, // ¶
|
||||
{ 3, 4, 3, 0, 7, 2, 1362 }, // ·
|
||||
{ 5, 5, 5, 0, 1, 4, 1364 }, // ¸
|
||||
{ 4, 6, 4, 0, 12, 3, 1368 }, // ¹
|
||||
{ 7, 7, 7, 0, 12, 7, 1371 }, // º
|
||||
{ 10, 8, 11, 1, 8, 10, 1378 }, // »
|
||||
{ 14, 13, 14, 0, 12, 23, 1388 }, // ¼
|
||||
{ 14, 13, 14, 0, 12, 23, 1411 }, // ½
|
||||
{ 15, 13, 15, 0, 12, 25, 1434 }, // ¾
|
||||
{ 9, 13, 10, 0, 9, 15, 1459 }, // ¿
|
||||
{ 11, 15, 11, 0, 15, 21, 1474 }, // À
|
||||
{ 11, 15, 11, 0, 15, 21, 1495 }, // Á
|
||||
{ 11, 15, 11, 0, 15, 21, 1516 }, // Â
|
||||
{ 11, 15, 11, 0, 15, 21, 1537 }, // Ã
|
||||
{ 11, 15, 11, 0, 15, 21, 1558 }, // Ä
|
||||
{ 11, 16, 11, 0, 16, 22, 1579 }, // Å
|
||||
{ 14, 12, 14, 0, 12, 21, 1601 }, // Æ
|
||||
{ 9, 16, 11, 1, 12, 18, 1622 }, // Ç
|
||||
{ 8, 15, 9, 1, 15, 15, 1640 }, // È
|
||||
{ 8, 15, 9, 1, 15, 15, 1655 }, // É
|
||||
{ 8, 15, 9, 1, 15, 15, 1670 }, // Ê
|
||||
{ 8, 15, 9, 1, 15, 15, 1685 }, // Ë
|
||||
{ 3, 15, 4, 0, 15, 6, 1700 }, // Ì
|
||||
{ 3, 15, 4, 1, 15, 6, 1706 }, // Í
|
||||
{ 6, 15, 4, -1, 15, 12, 1712 }, // Î
|
||||
{ 6, 15, 4, -1, 15, 12, 1724 }, // Ï
|
||||
{ 11, 12, 11, 0, 12, 17, 1736 }, // Ð
|
||||
{ 9, 15, 11, 1, 15, 17, 1753 }, // Ñ
|
||||
{ 10, 16, 11, 1, 15, 20, 1770 }, // Ò
|
||||
{ 10, 16, 11, 1, 15, 20, 1790 }, // Ó
|
||||
{ 10, 16, 11, 1, 15, 20, 1810 }, // Ô
|
||||
{ 10, 16, 11, 1, 15, 20, 1830 }, // Õ
|
||||
{ 10, 16, 11, 1, 15, 20, 1850 }, // Ö
|
||||
{ 8, 8, 10, 1, 10, 8, 1870 }, // ×
|
||||
{ 10, 15, 11, 1, 13, 19, 1878 }, // Ø
|
||||
{ 9, 16, 11, 1, 15, 18, 1897 }, // Ù
|
||||
{ 9, 16, 11, 1, 15, 18, 1915 }, // Ú
|
||||
{ 9, 16, 11, 1, 15, 18, 1933 }, // Û
|
||||
{ 9, 16, 11, 1, 15, 18, 1951 }, // Ü
|
||||
{ 10, 15, 10, 0, 15, 19, 1969 }, // Ý
|
||||
{ 9, 12, 10, 1, 12, 14, 1988 }, // Þ
|
||||
{ 9, 13, 10, 1, 12, 15, 2002 }, // ß
|
||||
{ 10, 13, 10, 0, 12, 17, 2017 }, // à
|
||||
{ 10, 13, 10, 0, 12, 17, 2034 }, // á
|
||||
{ 10, 13, 10, 0, 12, 17, 2051 }, // â
|
||||
{ 10, 13, 10, 0, 12, 17, 2068 }, // ã
|
||||
{ 10, 13, 10, 0, 12, 17, 2085 }, // ä
|
||||
{ 10, 14, 10, 0, 13, 18, 2102 }, // å
|
||||
{ 15, 10, 15, 0, 9, 19, 2120 }, // æ
|
||||
{ 10, 13, 10, 0, 9, 17, 2139 }, // ç
|
||||
{ 9, 13, 10, 0, 12, 15, 2156 }, // è
|
||||
{ 9, 13, 10, 0, 12, 15, 2171 }, // é
|
||||
{ 9, 13, 10, 0, 12, 15, 2186 }, // ê
|
||||
{ 9, 13, 10, 0, 12, 15, 2201 }, // ë
|
||||
{ 3, 12, 4, 0, 12, 5, 2216 }, // ì
|
||||
{ 4, 12, 4, 1, 12, 6, 2221 }, // í
|
||||
{ 6, 12, 4, -1, 12, 9, 2227 }, // î
|
||||
{ 6, 12, 4, -1, 12, 9, 2236 }, // ï
|
||||
{ 10, 14, 10, 0, 13, 18, 2245 }, // ð
|
||||
{ 8, 12, 10, 1, 12, 12, 2263 }, // ñ
|
||||
{ 10, 13, 10, 0, 12, 17, 2275 }, // ò
|
||||
{ 10, 13, 10, 0, 12, 17, 2292 }, // ó
|
||||
{ 10, 13, 10, 0, 12, 17, 2309 }, // ô
|
||||
{ 10, 13, 10, 0, 12, 17, 2326 }, // õ
|
||||
{ 10, 13, 10, 0, 12, 17, 2343 }, // ö
|
||||
{ 8, 8, 10, 1, 10, 8, 2360 }, // ÷
|
||||
{ 10, 12, 10, 0, 10, 15, 2368 }, // ø
|
||||
{ 8, 13, 10, 1, 12, 13, 2383 }, // ù
|
||||
{ 8, 13, 10, 1, 12, 13, 2396 }, // ú
|
||||
{ 8, 13, 10, 1, 12, 13, 2409 }, // û
|
||||
{ 8, 13, 10, 1, 12, 13, 2422 }, // ü
|
||||
{ 8, 16, 10, 1, 12, 16, 2435 }, // ý
|
||||
{ 9, 16, 11, 1, 12, 18, 2451 }, // þ
|
||||
{ 8, 16, 10, 1, 12, 16, 2469 }, // ÿ
|
||||
{ 11, 14, 11, 0, 14, 20, 2485 }, // Ā
|
||||
{ 10, 12, 10, 0, 11, 15, 2505 }, // ā
|
||||
{ 11, 15, 11, 0, 15, 21, 2520 }, // Ă
|
||||
{ 10, 13, 10, 0, 12, 17, 2541 }, // ă
|
||||
{ 11, 15, 11, 0, 12, 21, 2558 }, // Ą
|
||||
{ 10, 12, 10, 0, 9, 15, 2579 }, // ą
|
||||
{ 9, 16, 11, 1, 15, 18, 2594 }, // Ć
|
||||
{ 10, 13, 10, 0, 12, 17, 2612 }, // ć
|
||||
{ 9, 16, 11, 1, 15, 18, 2629 }, // Ĉ
|
||||
{ 10, 13, 10, 0, 12, 17, 2647 }, // ĉ
|
||||
{ 9, 16, 11, 1, 15, 18, 2664 }, // Ċ
|
||||
{ 10, 13, 10, 0, 12, 17, 2682 }, // ċ
|
||||
{ 9, 16, 11, 1, 15, 18, 2699 }, // Č
|
||||
{ 10, 13, 10, 0, 12, 17, 2717 }, // č
|
||||
{ 11, 15, 11, 0, 15, 21, 2734 }, // Ď
|
||||
{ 13, 13, 12, 0, 12, 22, 2755 }, // ď
|
||||
{ 11, 12, 11, 0, 12, 17, 2777 }, // Đ
|
||||
{ 11, 13, 11, 0, 12, 18, 2794 }, // đ
|
||||
{ 8, 14, 9, 1, 14, 14, 2812 }, // Ē
|
||||
{ 9, 12, 10, 0, 11, 14, 2826 }, // ē
|
||||
{ 8, 15, 9, 1, 15, 15, 2840 }, // Ĕ
|
||||
{ 9, 13, 10, 0, 12, 15, 2855 }, // ĕ
|
||||
{ 8, 15, 9, 1, 15, 15, 2870 }, // Ė
|
||||
{ 9, 13, 10, 0, 12, 15, 2885 }, // ė
|
||||
{ 8, 15, 9, 1, 12, 15, 2900 }, // Ę
|
||||
{ 9, 12, 10, 0, 9, 14, 2915 }, // ę
|
||||
{ 8, 15, 9, 1, 15, 15, 2929 }, // Ě
|
||||
{ 9, 13, 10, 0, 12, 15, 2944 }, // ě
|
||||
{ 9, 16, 11, 1, 15, 18, 2959 }, // Ĝ
|
||||
{ 10, 16, 11, 0, 12, 20, 2977 }, // ĝ
|
||||
{ 9, 16, 11, 1, 15, 18, 2997 }, // Ğ
|
||||
{ 10, 16, 11, 0, 12, 20, 3015 }, // ğ
|
||||
{ 9, 16, 11, 1, 15, 18, 3035 }, // Ġ
|
||||
{ 10, 16, 11, 0, 12, 20, 3053 }, // ġ
|
||||
{ 9, 17, 11, 1, 12, 20, 3073 }, // Ģ
|
||||
{ 10, 17, 11, 0, 13, 22, 3093 }, // ģ
|
||||
{ 9, 15, 11, 1, 15, 17, 3115 }, // Ĥ
|
||||
{ 10, 15, 10, -1, 15, 19, 3132 }, // ĥ
|
||||
{ 11, 12, 11, 0, 12, 17, 3151 }, // Ħ
|
||||
{ 9, 12, 10, 0, 12, 14, 3168 }, // ħ
|
||||
{ 6, 15, 4, -1, 15, 12, 3182 }, // Ĩ
|
||||
{ 6, 12, 4, -1, 12, 9, 3194 }, // ĩ
|
||||
{ 6, 14, 4, -1, 14, 11, 3203 }, // Ī
|
||||
{ 6, 11, 4, -1, 11, 9, 3214 }, // ī
|
||||
{ 6, 15, 4, -1, 15, 12, 3223 }, // Ĭ
|
||||
{ 6, 12, 4, -1, 12, 9, 3235 }, // ĭ
|
||||
{ 3, 15, 4, 1, 12, 6, 3244 }, // Į
|
||||
{ 3, 15, 4, 1, 12, 6, 3250 }, // į
|
||||
{ 3, 15, 4, 1, 15, 6, 3256 }, // İ
|
||||
{ 2, 9, 4, 1, 9, 3, 3262 }, // ı
|
||||
{ 12, 13, 12, 0, 12, 20, 3265 }, // IJ
|
||||
{ 7, 16, 8, 1, 12, 14, 3285 }, // ij
|
||||
{ 10, 16, 10, 0, 15, 20, 3299 }, // Ĵ
|
||||
{ 6, 16, 4, -1, 12, 12, 3319 }, // ĵ
|
||||
{ 9, 17, 10, 1, 12, 20, 3331 }, // Ķ
|
||||
{ 8, 17, 9, 1, 12, 17, 3351 }, // ķ
|
||||
{ 8, 9, 9, 1, 9, 9, 3368 }, // ĸ
|
||||
{ 8, 15, 9, 1, 15, 15, 3377 }, // Ĺ
|
||||
{ 3, 15, 4, 1, 15, 6, 3392 }, // ĺ
|
||||
{ 8, 17, 9, 1, 12, 17, 3398 }, // Ļ
|
||||
{ 2, 17, 4, 1, 12, 5, 3415 }, // ļ
|
||||
{ 8, 12, 9, 1, 12, 12, 3420 }, // Ľ
|
||||
{ 5, 12, 5, 1, 12, 8, 3432 }, // ľ
|
||||
{ 8, 12, 9, 1, 12, 12, 3440 }, // Ŀ
|
||||
{ 6, 12, 7, 1, 12, 9, 3452 }, // ŀ
|
||||
{ 10, 12, 10, 0, 12, 15, 3461 }, // Ł
|
||||
{ 6, 12, 6, 0, 12, 9, 3476 }, // ł
|
||||
{ 9, 15, 11, 1, 15, 17, 3485 }, // Ń
|
||||
{ 8, 12, 10, 1, 12, 12, 3502 }, // ń
|
||||
{ 9, 17, 11, 1, 12, 20, 3514 }, // Ņ
|
||||
{ 8, 14, 10, 1, 9, 14, 3534 }, // ņ
|
||||
{ 9, 15, 11, 1, 15, 17, 3548 }, // Ň
|
||||
{ 8, 12, 10, 1, 12, 12, 3565 }, // ň
|
||||
{ 8, 13, 10, 1, 13, 13, 3577 }, // ʼn
|
||||
{ 9, 16, 11, 1, 12, 18, 3590 }, // Ŋ
|
||||
{ 8, 13, 10, 1, 9, 13, 3608 }, // ŋ
|
||||
{ 10, 15, 11, 1, 14, 19, 3621 }, // Ō
|
||||
{ 10, 12, 10, 0, 11, 15, 3640 }, // ō
|
||||
{ 10, 16, 11, 1, 15, 20, 3655 }, // Ŏ
|
||||
{ 10, 13, 10, 0, 12, 17, 3675 }, // ŏ
|
||||
{ 10, 16, 11, 1, 15, 20, 3692 }, // Ő
|
||||
{ 10, 13, 10, 0, 12, 17, 3712 }, // ő
|
||||
{ 13, 12, 14, 1, 12, 20, 3729 }, // Œ
|
||||
{ 17, 10, 17, 0, 9, 22, 3749 }, // œ
|
||||
{ 9, 15, 11, 1, 15, 17, 3771 }, // Ŕ
|
||||
{ 5, 12, 6, 1, 12, 8, 3788 }, // ŕ
|
||||
{ 9, 17, 11, 1, 12, 20, 3796 }, // Ŗ
|
||||
{ 5, 14, 6, 1, 9, 9, 3816 }, // ŗ
|
||||
{ 9, 15, 11, 1, 15, 17, 3825 }, // Ř
|
||||
{ 7, 12, 6, 0, 12, 11, 3842 }, // ř
|
||||
{ 10, 16, 10, 0, 15, 20, 3853 }, // Ś
|
||||
{ 8, 13, 9, 0, 12, 13, 3873 }, // ś
|
||||
{ 10, 16, 10, 0, 15, 20, 3886 }, // Ŝ
|
||||
{ 8, 13, 9, 0, 12, 13, 3906 }, // ŝ
|
||||
{ 10, 16, 10, 0, 12, 20, 3919 }, // Ş
|
||||
{ 8, 13, 9, 0, 9, 13, 3939 }, // ş
|
||||
{ 10, 16, 10, 0, 15, 20, 3952 }, // Š
|
||||
{ 8, 13, 9, 0, 12, 13, 3972 }, // š
|
||||
{ 10, 16, 10, 0, 12, 20, 3985 }, // Ţ
|
||||
{ 7, 16, 8, 0, 12, 14, 4005 }, // ţ
|
||||
{ 10, 15, 10, 0, 15, 19, 4019 }, // Ť
|
||||
{ 8, 13, 8, 0, 13, 13, 4038 }, // ť
|
||||
{ 10, 12, 10, 0, 12, 15, 4051 }, // Ŧ
|
||||
{ 7, 12, 8, 0, 12, 11, 4066 }, // ŧ
|
||||
{ 9, 16, 11, 1, 15, 18, 4077 }, // Ũ
|
||||
{ 8, 13, 10, 1, 12, 13, 4095 }, // ũ
|
||||
{ 9, 15, 11, 1, 14, 17, 4108 }, // Ū
|
||||
{ 8, 12, 10, 1, 11, 12, 4125 }, // ū
|
||||
{ 9, 16, 11, 1, 15, 18, 4137 }, // Ŭ
|
||||
{ 8, 13, 10, 1, 12, 13, 4155 }, // ŭ
|
||||
{ 9, 17, 11, 1, 16, 20, 4168 }, // Ů
|
||||
{ 8, 14, 10, 1, 13, 14, 4188 }, // ů
|
||||
{ 9, 16, 11, 1, 15, 18, 4202 }, // Ű
|
||||
{ 8, 13, 10, 1, 12, 13, 4220 }, // ű
|
||||
{ 9, 15, 11, 1, 12, 17, 4233 }, // Ų
|
||||
{ 9, 12, 10, 1, 9, 14, 4250 }, // ų
|
||||
{ 14, 15, 15, 0, 15, 27, 4264 }, // Ŵ
|
||||
{ 13, 12, 13, 0, 12, 20, 4291 }, // ŵ
|
||||
{ 10, 15, 10, 0, 15, 19, 4311 }, // Ŷ
|
||||
{ 8, 16, 10, 1, 12, 16, 4330 }, // ŷ
|
||||
{ 10, 15, 10, 0, 15, 19, 4346 }, // Ÿ
|
||||
{ 9, 15, 10, 0, 15, 17, 4365 }, // Ź
|
||||
{ 7, 12, 9, 1, 12, 11, 4382 }, // ź
|
||||
{ 9, 15, 10, 0, 15, 17, 4393 }, // Ż
|
||||
{ 7, 12, 9, 1, 12, 11, 4410 }, // ż
|
||||
{ 9, 15, 10, 0, 15, 17, 4421 }, // Ž
|
||||
{ 7, 12, 9, 1, 12, 11, 4438 }, // ž
|
||||
{ 6, 12, 6, 0, 12, 9, 4449 }, // ſ
|
||||
{ 4, 3, 0, 0, 12, 2, 4458 }, // ̀
|
||||
{ 4, 3, 0, 0, 12, 2, 4460 }, // ́
|
||||
{ 7, 3, 0, 0, 12, 3, 4462 }, // ̂
|
||||
{ 7, 3, 0, 0, 12, 3, 4465 }, // ̃
|
||||
{ 7, 2, 0, 0, 11, 2, 4468 }, // ̄
|
||||
{ 6, 3, 0, 0, 12, 3, 4470 }, // ̆
|
||||
{ 3, 3, 0, 0, 12, 2, 4473 }, // ̇
|
||||
{ 7, 3, 0, 0, 12, 3, 4475 }, // ̈
|
||||
{ 5, 4, 0, 0, 13, 3, 4478 }, // ̉
|
||||
{ 5, 4, 0, 0, 13, 3, 4481 }, // ̊
|
||||
{ 6, 3, 0, 0, 12, 3, 4484 }, // ̋
|
||||
{ 7, 3, 0, 0, 12, 3, 4487 }, // ̌
|
||||
{ 6, 3, 0, 0, 12, 3, 4490 }, // ̏
|
||||
{ 6, 3, 0, 0, 12, 3, 4493 }, // ̑
|
||||
{ 3, 4, 0, 0, 13, 2, 4496 }, // ̒
|
||||
{ 4, 3, 0, 0, 10, 2, 4498 }, // ̛
|
||||
{ 3, 3, 0, 0, -1, 2, 4500 }, // ̣
|
||||
{ 7, 3, 0, 0, -1, 3, 4502 }, // ̤
|
||||
{ 3, 4, 0, 0, -1, 2, 4505 }, // ̦
|
||||
{ 5, 5, 0, 0, 1, 4, 4507 }, // ̧
|
||||
{ 4, 4, 0, 0, 1, 2, 4511 }, // ̨
|
||||
{ 6, 3, 0, 0, -1, 3, 4513 }, // ̮
|
||||
{ 7, 2, 0, 0, -1, 2, 4516 }, // ̱
|
||||
{ 7, 2, 0, 0, 11, 2, 4518 }, // ̵
|
||||
{ 12, 2, 0, 0, 10, 3, 4520 }, // ̶
|
||||
{ 8, 12, 0, 0, 10, 12, 4523 }, // ̷
|
||||
{ 8, 15, 0, 0, 13, 15, 4535 }, // ̸
|
||||
{ 0, 0, 10, 0, 0, 0, 4550 }, //
|
||||
{ 0, 0, 4, 0, 0, 0, 4550 }, //
|
||||
{ 0, 0, 3, 0, 0, 0, 4550 }, //
|
||||
{ 0, 0, 1, 0, 0, 0, 4550 }, //
|
||||
{ 0, 0, 0, 0, 0, 0, 4550 }, //
|
||||
{ 6, 2, 8, 1, 5, 2, 4550 }, // ‐
|
||||
{ 9, 2, 10, 1, 5, 3, 4552 }, // ‒
|
||||
{ 8, 2, 10, 1, 5, 2, 4555 }, // –
|
||||
{ 13, 2, 15, 1, 5, 4, 4557 }, // —
|
||||
{ 13, 2, 15, 1, 5, 4, 4561 }, // ―
|
||||
{ 4, 6, 4, 0, 13, 3, 4565 }, // ‘
|
||||
{ 4, 6, 4, 0, 13, 3, 4568 }, // ’
|
||||
{ 4, 6, 4, 0, 3, 3, 4571 }, // ‚
|
||||
{ 7, 6, 7, 0, 13, 6, 4574 }, // “
|
||||
{ 7, 6, 7, 0, 13, 6, 4580 }, // ”
|
||||
{ 7, 6, 7, 0, 3, 6, 4586 }, // „
|
||||
{ 8, 12, 10, 1, 12, 12, 4592 }, // †
|
||||
{ 8, 12, 10, 1, 12, 12, 4604 }, // ‡
|
||||
{ 4, 5, 6, 1, 7, 3, 4616 }, // •
|
||||
{ 11, 4, 11, 0, 3, 6, 4619 }, // …
|
||||
{ 16, 13, 16, 0, 12, 26, 4625 }, // ‰
|
||||
{ 3, 5, 3, 0, 12, 2, 4651 }, // ′
|
||||
{ 6, 5, 6, 0, 12, 4, 4653 }, // ″
|
||||
{ 7, 8, 8, 0, 8, 7, 4657 }, // ‹
|
||||
{ 6, 8, 8, 1, 8, 6, 4664 }, // ›
|
||||
{ 11, 13, 11, 0, 12, 18, 4670 }, // ⁄
|
||||
{ 11, 13, 12, 0, 12, 18, 4688 }, // ⁒
|
||||
{ 9, 16, 11, 1, 14, 18, 4706 }, // ₡
|
||||
{ 10, 12, 10, 0, 12, 15, 4724 }, // ₣
|
||||
{ 10, 12, 10, 0, 12, 15, 4739 }, // ₤
|
||||
{ 12, 12, 13, 0, 12, 18, 4754 }, // ₦
|
||||
{ 12, 12, 12, 0, 12, 18, 4772 }, // ₧
|
||||
{ 16, 12, 16, 0, 12, 24, 4790 }, // ₩
|
||||
{ 11, 14, 12, 0, 12, 20, 4814 }, // ₫
|
||||
{ 11, 13, 11, 0, 12, 18, 4834 }, // €
|
||||
{ 11, 12, 11, 0, 12, 17, 4852 }, // ₭
|
||||
{ 12, 12, 12, 0, 12, 18, 4869 }, // ₱
|
||||
{ 9, 16, 11, 1, 14, 18, 4887 }, // ₲
|
||||
{ 9, 16, 11, 1, 14, 18, 4905 }, // ₵
|
||||
{ 10, 12, 11, 1, 12, 15, 4923 }, // ₹
|
||||
{ 9, 12, 9, 0, 12, 14, 4938 }, // ₺
|
||||
{ 10, 14, 12, 1, 14, 18, 4952 }, // ₼
|
||||
{ 11, 12, 11, 0, 12, 17, 4970 }, // ₽
|
||||
{ 10, 16, 12, 1, 14, 20, 4987 }, // ₿
|
||||
{ 13, 10, 13, 0, 9, 17, 5007 }, // ←
|
||||
{ 10, 12, 10, 0, 12, 15, 5024 }, // ↑
|
||||
{ 13, 10, 13, 0, 9, 17, 5039 }, // →
|
||||
{ 10, 13, 10, 0, 12, 17, 5056 }, // ↓
|
||||
{ 13, 10, 13, 0, 9, 17, 5073 }, // ↔
|
||||
{ 10, 13, 10, 0, 12, 17, 5090 }, // ↕
|
||||
{ 9, 10, 10, 1, 9, 12, 5107 }, // ↖
|
||||
{ 9, 10, 10, 0, 9, 12, 5119 }, // ↗
|
||||
{ 9, 9, 10, 0, 9, 11, 5131 }, // ↘
|
||||
{ 9, 9, 10, 1, 9, 11, 5142 }, // ↙
|
||||
{ 9, 13, 10, 1, 12, 15, 5153 }, // ∂
|
||||
{ 10, 12, 11, 0, 10, 15, 5168 }, // ∅
|
||||
{ 10, 12, 10, 0, 12, 15, 5183 }, // ∆
|
||||
{ 9, 16, 10, 1, 12, 18, 5198 }, // ∏
|
||||
{ 10, 16, 10, 0, 12, 20, 5216 }, // ∑
|
||||
{ 8, 2, 10, 1, 7, 2, 5236 }, // −
|
||||
{ 7, 17, 6, 0, 14, 15, 5238 }, // ∕
|
||||
{ 5, 5, 10, 3, 8, 4, 5253 }, // ∙
|
||||
{ 10, 15, 10, 0, 15, 19, 5257 }, // √
|
||||
{ 10, 6, 10, 0, 9, 8, 5276 }, // ∞
|
||||
{ 6, 16, 10, 2, 12, 12, 5284 }, // ∫
|
||||
{ 8, 7, 10, 1, 9, 7, 5296 }, // ≈
|
||||
{ 8, 8, 10, 1, 10, 8, 5303 }, // ≠
|
||||
{ 8, 10, 10, 1, 10, 10, 5311 }, // ≤
|
||||
{ 8, 10, 10, 1, 10, 10, 5321 }, // ≥
|
||||
};
|
||||
|
||||
static const EpdUnicodeInterval spacegroteskIntervals[] = {
|
||||
{ 0xD, 0xD, 0x0 },
|
||||
{ 0x20, 0x7E, 0x1 },
|
||||
{ 0xA0, 0xFF, 0x60 },
|
||||
{ 0x100, 0x17F, 0xC0 },
|
||||
{ 0x300, 0x304, 0x140 },
|
||||
{ 0x306, 0x30C, 0x145 },
|
||||
{ 0x30F, 0x30F, 0x14C },
|
||||
{ 0x311, 0x312, 0x14D },
|
||||
{ 0x31B, 0x31B, 0x14F },
|
||||
{ 0x323, 0x324, 0x150 },
|
||||
{ 0x326, 0x328, 0x152 },
|
||||
{ 0x32E, 0x32E, 0x155 },
|
||||
{ 0x331, 0x331, 0x156 },
|
||||
{ 0x335, 0x338, 0x157 },
|
||||
{ 0x2007, 0x200B, 0x15B },
|
||||
{ 0x2010, 0x2010, 0x160 },
|
||||
{ 0x2012, 0x2015, 0x161 },
|
||||
{ 0x2018, 0x201A, 0x165 },
|
||||
{ 0x201C, 0x201E, 0x168 },
|
||||
{ 0x2020, 0x2022, 0x16B },
|
||||
{ 0x2026, 0x2026, 0x16E },
|
||||
{ 0x2030, 0x2030, 0x16F },
|
||||
{ 0x2032, 0x2033, 0x170 },
|
||||
{ 0x2039, 0x203A, 0x172 },
|
||||
{ 0x2044, 0x2044, 0x174 },
|
||||
{ 0x2052, 0x2052, 0x175 },
|
||||
{ 0x20A1, 0x20A1, 0x176 },
|
||||
{ 0x20A3, 0x20A4, 0x177 },
|
||||
{ 0x20A6, 0x20A7, 0x179 },
|
||||
{ 0x20A9, 0x20A9, 0x17B },
|
||||
{ 0x20AB, 0x20AD, 0x17C },
|
||||
{ 0x20B1, 0x20B2, 0x17F },
|
||||
{ 0x20B5, 0x20B5, 0x181 },
|
||||
{ 0x20B9, 0x20BA, 0x182 },
|
||||
{ 0x20BC, 0x20BD, 0x184 },
|
||||
{ 0x20BF, 0x20BF, 0x186 },
|
||||
{ 0x2190, 0x2199, 0x187 },
|
||||
{ 0x2202, 0x2202, 0x191 },
|
||||
{ 0x2205, 0x2206, 0x192 },
|
||||
{ 0x220F, 0x220F, 0x194 },
|
||||
{ 0x2211, 0x2212, 0x195 },
|
||||
{ 0x2215, 0x2215, 0x197 },
|
||||
{ 0x2219, 0x221A, 0x198 },
|
||||
{ 0x221E, 0x221E, 0x19A },
|
||||
{ 0x222B, 0x222B, 0x19B },
|
||||
{ 0x2248, 0x2248, 0x19C },
|
||||
{ 0x2260, 0x2260, 0x19D },
|
||||
{ 0x2264, 0x2265, 0x19E },
|
||||
};
|
||||
|
||||
static const EpdFontData spacegrotesk = {
|
||||
spacegroteskBitmaps,
|
||||
spacegroteskGlyphs,
|
||||
spacegroteskIntervals,
|
||||
48,
|
||||
21,
|
||||
17,
|
||||
-5,
|
||||
false,
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Executable
+137
@@ -0,0 +1,137 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/../builtinFonts"
|
||||
|
||||
echo "// The contents of this file are generated by ./lib/EpdFont/scripts/build-font-ids.sh"
|
||||
echo "#pragma once"
|
||||
echo ""
|
||||
|
||||
echo "#define ALEO_12_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./aleo_12_regular.h",
|
||||
"./aleo_12_bold.h",
|
||||
"./aleo_12_bolditalic.h",
|
||||
"./aleo_12_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define ALEO_14_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./aleo_14_regular.h",
|
||||
"./aleo_14_bold.h",
|
||||
"./aleo_14_bolditalic.h",
|
||||
"./aleo_14_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define ALEO_16_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./aleo_16_regular.h",
|
||||
"./aleo_16_bold.h",
|
||||
"./aleo_16_bolditalic.h",
|
||||
"./aleo_16_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define ALEO_18_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./aleo_18_regular.h",
|
||||
"./aleo_18_bold.h",
|
||||
"./aleo_18_bolditalic.h",
|
||||
"./aleo_18_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define NOTOSANS_12_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./notosans_12_regular.h",
|
||||
"./notosans_12_bold.h",
|
||||
"./notosans_12_bolditalic.h",
|
||||
"./notosans_12_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define NOTOSANS_14_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./notosans_14_regular.h",
|
||||
"./notosans_14_bold.h",
|
||||
"./notosans_14_bolditalic.h",
|
||||
"./notosans_14_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define NOTOSANS_16_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./notosans_16_regular.h",
|
||||
"./notosans_16_bold.h",
|
||||
"./notosans_16_bolditalic.h",
|
||||
"./notosans_16_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define NOTOSANS_18_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./notosans_18_regular.h",
|
||||
"./notosans_18_bold.h",
|
||||
"./notosans_18_bolditalic.h",
|
||||
"./notosans_18_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define OPENDYSLEXIC_8_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./opendyslexic_8_regular.h",
|
||||
"./opendyslexic_8_bold.h",
|
||||
"./opendyslexic_8_bolditalic.h",
|
||||
"./opendyslexic_8_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define OPENDYSLEXIC_10_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./opendyslexic_10_regular.h",
|
||||
"./opendyslexic_10_bold.h",
|
||||
"./opendyslexic_10_bolditalic.h",
|
||||
"./opendyslexic_10_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define OPENDYSLEXIC_12_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./opendyslexic_12_regular.h",
|
||||
"./opendyslexic_12_bold.h",
|
||||
"./opendyslexic_12_bolditalic.h",
|
||||
"./opendyslexic_12_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define OPENDYSLEXIC_14_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./opendyslexic_14_regular.h",
|
||||
"./opendyslexic_14_bold.h",
|
||||
"./opendyslexic_14_bolditalic.h",
|
||||
"./opendyslexic_14_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define UI_10_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./ubuntu_10_regular.h",
|
||||
"./ubuntu_10_bold.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define UI_12_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./ubuntu_12_regular.h",
|
||||
"./ubuntu_12_bold.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define SMALL_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./spacegrotesk.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
READER_FONT_STYLES=("Regular" "Italic" "Bold" "BoldItalic")
|
||||
ALEO_FONT_SIZES=(12 14 16 18)
|
||||
NOTOSANS_FONT_SIZES=(12 14 16 18)
|
||||
OPENDYSLEXIC_FONT_SIZES=(8 10 12 14)
|
||||
|
||||
for size in ${ALEO_FONT_SIZES[@]}; do
|
||||
for style in ${READER_FONT_STYLES[@]}; do
|
||||
font_name="aleo_${size}_$(echo $style | tr '[:upper:]' '[:lower:]')"
|
||||
font_path="../builtinFonts/source/Aleo/Aleo-${style}.ttf"
|
||||
output_path="../builtinFonts/${font_name}.h"
|
||||
python fontconvert.py $font_name $size $font_path --2bit > $output_path
|
||||
echo "Generated $output_path"
|
||||
done
|
||||
done
|
||||
|
||||
for size in ${NOTOSANS_FONT_SIZES[@]}; do
|
||||
for style in ${READER_FONT_STYLES[@]}; do
|
||||
font_name="notosans_${size}_$(echo $style | tr '[:upper:]' '[:lower:]')"
|
||||
font_path="../builtinFonts/source/NotoSans/NotoSans-${style}.ttf"
|
||||
output_path="../builtinFonts/${font_name}.h"
|
||||
python fontconvert.py $font_name $size $font_path --2bit > $output_path
|
||||
echo "Generated $output_path"
|
||||
done
|
||||
done
|
||||
|
||||
for size in ${OPENDYSLEXIC_FONT_SIZES[@]}; do
|
||||
for style in ${READER_FONT_STYLES[@]}; do
|
||||
font_name="opendyslexic_${size}_$(echo $style | tr '[:upper:]' '[:lower:]')"
|
||||
font_path="../builtinFonts/source/OpenDyslexic/OpenDyslexic-${style}.otf"
|
||||
output_path="../builtinFonts/${font_name}.h"
|
||||
python fontconvert.py $font_name $size $font_path --2bit > $output_path
|
||||
echo "Generated $output_path"
|
||||
done
|
||||
done
|
||||
|
||||
UI_FONT_SIZES=(10 12)
|
||||
UI_FONT_STYLES=("Regular" "Bold")
|
||||
|
||||
for size in ${UI_FONT_SIZES[@]}; do
|
||||
for style in ${UI_FONT_STYLES[@]}; do
|
||||
font_name="ubuntu_${size}_$(echo $style | tr '[:upper:]' '[:lower:]')"
|
||||
font_path="../builtinFonts/source/Ubuntu/Ubuntu-${style}.ttf"
|
||||
output_path="../builtinFonts/${font_name}.h"
|
||||
python fontconvert.py $font_name $size $font_path > $output_path
|
||||
echo "Generated $output_path"
|
||||
done
|
||||
done
|
||||
|
||||
python fontconvert.py spacegrotesk 8 ../builtinFonts/source/SpaceGrotesk/SpaceGrotesk-Regular.ttf > ../builtinFonts/spacegrotesk.h
|
||||
+233
-179
@@ -1,13 +1,11 @@
|
||||
#include "Epub.h"
|
||||
|
||||
#include <FsHelpers.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <JpegToBmpConverter.h>
|
||||
#include <SD.h>
|
||||
#include <SDCardManager.h>
|
||||
#include <ZipFile.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Epub/FsHelpers.h"
|
||||
#include "Epub/parsers/ContainerParser.h"
|
||||
#include "Epub/parsers/ContentOpfParser.h"
|
||||
#include "Epub/parsers/TocNcxParser.h"
|
||||
@@ -44,7 +42,15 @@ bool Epub::findContentOpfFile(std::string* contentOpfFile) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Epub::parseContentOpf(const std::string& contentOpfFilePath) {
|
||||
bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata) {
|
||||
std::string contentOpfFilePath;
|
||||
if (!findContentOpfFile(&contentOpfFilePath)) {
|
||||
Serial.printf("[%lu] [EBP] Could not find content.opf in zip\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
contentBasePath = contentOpfFilePath.substr(0, contentOpfFilePath.find_last_of('/') + 1);
|
||||
|
||||
Serial.printf("[%lu] [EBP] Parsing content.opf: %s\n", millis(), contentOpfFilePath.c_str());
|
||||
|
||||
size_t contentOpfSize;
|
||||
@@ -53,8 +59,7 @@ bool Epub::parseContentOpf(const std::string& contentOpfFilePath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ContentOpfParser opfParser(getBasePath(), contentOpfSize);
|
||||
|
||||
ContentOpfParser opfParser(getCachePath(), getBasePath(), contentOpfSize, bookMetadataCache.get());
|
||||
if (!opfParser.setup()) {
|
||||
Serial.printf("[%lu] [EBP] Could not setup content.opf parser\n", millis());
|
||||
return false;
|
||||
@@ -66,26 +71,20 @@ bool Epub::parseContentOpf(const std::string& contentOpfFilePath) {
|
||||
}
|
||||
|
||||
// Grab data from opfParser into epub
|
||||
title = opfParser.title;
|
||||
if (!opfParser.coverItemId.empty() && opfParser.items.count(opfParser.coverItemId) > 0) {
|
||||
coverImageItem = opfParser.items.at(opfParser.coverItemId);
|
||||
}
|
||||
bookMetadata.title = opfParser.title;
|
||||
bookMetadata.author = opfParser.author;
|
||||
bookMetadata.coverItemHref = opfParser.coverItemHref;
|
||||
bookMetadata.textReferenceHref = opfParser.textReferenceHref;
|
||||
|
||||
if (!opfParser.tocNcxPath.empty()) {
|
||||
tocNcxItem = opfParser.tocNcxPath;
|
||||
}
|
||||
|
||||
for (auto& spineRef : opfParser.spineRefs) {
|
||||
if (opfParser.items.count(spineRef)) {
|
||||
spine.emplace_back(spineRef, opfParser.items.at(spineRef));
|
||||
}
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EBP] Successfully parsed content.opf\n", millis());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Epub::parseTocNcxFile() {
|
||||
bool Epub::parseTocNcxFile() const {
|
||||
// the ncx file should have been specified in the content.opf file
|
||||
if (tocNcxItem.empty()) {
|
||||
Serial.printf("[%lu] [EBP] No ncx file specified\n", millis());
|
||||
@@ -95,27 +94,35 @@ bool Epub::parseTocNcxFile() {
|
||||
Serial.printf("[%lu] [EBP] Parsing toc ncx file: %s\n", millis(), tocNcxItem.c_str());
|
||||
|
||||
const auto tmpNcxPath = getCachePath() + "/toc.ncx";
|
||||
File tempNcxFile = SD.open(tmpNcxPath.c_str(), FILE_WRITE);
|
||||
FsFile tempNcxFile;
|
||||
if (!SdMan.openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) {
|
||||
return false;
|
||||
}
|
||||
readItemContentsToStream(tocNcxItem, tempNcxFile, 1024);
|
||||
tempNcxFile.close();
|
||||
tempNcxFile = SD.open(tmpNcxPath.c_str(), FILE_READ);
|
||||
if (!SdMan.openFileForRead("EBP", tmpNcxPath, tempNcxFile)) {
|
||||
return false;
|
||||
}
|
||||
const auto ncxSize = tempNcxFile.size();
|
||||
|
||||
TocNcxParser ncxParser(contentBasePath, ncxSize);
|
||||
TocNcxParser ncxParser(contentBasePath, ncxSize, bookMetadataCache.get());
|
||||
|
||||
if (!ncxParser.setup()) {
|
||||
Serial.printf("[%lu] [EBP] Could not setup toc ncx parser\n", millis());
|
||||
tempNcxFile.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto ncxBuffer = static_cast<uint8_t*>(malloc(1024));
|
||||
if (!ncxBuffer) {
|
||||
Serial.printf("[%lu] [EBP] Could not allocate memory for toc ncx parser\n", millis());
|
||||
tempNcxFile.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
while (tempNcxFile.available()) {
|
||||
const auto readSize = tempNcxFile.read(ncxBuffer, 1024);
|
||||
if (readSize == 0) break;
|
||||
const auto processedSize = ncxParser.write(ncxBuffer, readSize);
|
||||
|
||||
if (processedSize != readSize) {
|
||||
@@ -128,69 +135,103 @@ bool Epub::parseTocNcxFile() {
|
||||
|
||||
free(ncxBuffer);
|
||||
tempNcxFile.close();
|
||||
SD.remove(tmpNcxPath.c_str());
|
||||
SdMan.remove(tmpNcxPath.c_str());
|
||||
|
||||
this->toc = std::move(ncxParser.toc);
|
||||
|
||||
Serial.printf("[%lu] [EBP] Parsed %d TOC items\n", millis(), this->toc.size());
|
||||
Serial.printf("[%lu] [EBP] Parsed TOC items\n", millis());
|
||||
return true;
|
||||
}
|
||||
|
||||
// load in the meta data for the epub file
|
||||
bool Epub::load() {
|
||||
bool Epub::load(const bool buildIfMissing) {
|
||||
Serial.printf("[%lu] [EBP] Loading ePub: %s\n", millis(), filepath.c_str());
|
||||
|
||||
std::string contentOpfFilePath;
|
||||
if (!findContentOpfFile(&contentOpfFilePath)) {
|
||||
Serial.printf("[%lu] [EBP] Could not find content.opf in zip\n", millis());
|
||||
// Initialize spine/TOC cache
|
||||
bookMetadataCache.reset(new BookMetadataCache(cachePath));
|
||||
|
||||
// Try to load existing cache first
|
||||
if (bookMetadataCache->load()) {
|
||||
Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we didn't load from cache above and we aren't allowed to build, fail now
|
||||
if (!buildIfMissing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EBP] Found content.opf at: %s\n", millis(), contentOpfFilePath.c_str());
|
||||
// Cache doesn't exist or is invalid, build it
|
||||
Serial.printf("[%lu] [EBP] Cache not found, building spine/TOC cache\n", millis());
|
||||
setupCacheDir();
|
||||
|
||||
contentBasePath = contentOpfFilePath.substr(0, contentOpfFilePath.find_last_of('/') + 1);
|
||||
// Begin building cache - stream entries to disk immediately
|
||||
if (!bookMetadataCache->beginWrite()) {
|
||||
Serial.printf("[%lu] [EBP] Could not begin writing cache\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parseContentOpf(contentOpfFilePath)) {
|
||||
// OPF Pass
|
||||
BookMetadataCache::BookMetadata bookMetadata;
|
||||
if (!bookMetadataCache->beginContentOpfPass()) {
|
||||
Serial.printf("[%lu] [EBP] Could not begin writing content.opf pass\n", millis());
|
||||
return false;
|
||||
}
|
||||
if (!parseContentOpf(bookMetadata)) {
|
||||
Serial.printf("[%lu] [EBP] Could not parse content.opf\n", millis());
|
||||
return false;
|
||||
}
|
||||
if (!bookMetadataCache->endContentOpfPass()) {
|
||||
Serial.printf("[%lu] [EBP] Could not end writing content.opf pass\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
// TOC Pass
|
||||
if (!bookMetadataCache->beginTocPass()) {
|
||||
Serial.printf("[%lu] [EBP] Could not begin writing toc pass\n", millis());
|
||||
return false;
|
||||
}
|
||||
if (!parseTocNcxFile()) {
|
||||
Serial.printf("[%lu] [EBP] Could not parse toc\n", millis());
|
||||
return false;
|
||||
}
|
||||
if (!bookMetadataCache->endTocPass()) {
|
||||
Serial.printf("[%lu] [EBP] Could not end writing toc pass\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Close the cache files
|
||||
if (!bookMetadataCache->endWrite()) {
|
||||
Serial.printf("[%lu] [EBP] Could not end writing cache\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build final book.bin
|
||||
if (!bookMetadataCache->buildBookBin(filepath, bookMetadata)) {
|
||||
Serial.printf("[%lu] [EBP] Could not update mappings and sizes\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bookMetadataCache->cleanupTmpFiles()) {
|
||||
Serial.printf("[%lu] [EBP] Could not cleanup tmp files - ignoring\n", millis());
|
||||
}
|
||||
|
||||
// Reload the cache from disk so it's in the correct state
|
||||
bookMetadataCache.reset(new BookMetadataCache(cachePath));
|
||||
if (!bookMetadataCache->load()) {
|
||||
Serial.printf("[%lu] [EBP] Failed to reload cache after writing\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
initializeSpineItemSizes();
|
||||
Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Epub::initializeSpineItemSizes() {
|
||||
Serial.printf("[%lu] [EBP] Calculating book size\n", millis());
|
||||
|
||||
const size_t spineItemsCount = getSpineItemsCount();
|
||||
size_t cumSpineItemSize = 0;
|
||||
const ZipFile zip("/sd" + filepath);
|
||||
|
||||
for (size_t i = 0; i < spineItemsCount; i++) {
|
||||
std::string spineItem = getSpineItem(i);
|
||||
size_t s = 0;
|
||||
getItemSize(zip, spineItem, &s);
|
||||
cumSpineItemSize += s;
|
||||
cumulativeSpineItemSize.emplace_back(cumSpineItemSize);
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EBP] Book size: %lu\n", millis(), cumSpineItemSize);
|
||||
}
|
||||
|
||||
bool Epub::clearCache() const {
|
||||
if (!SD.exists(cachePath.c_str())) {
|
||||
if (!SdMan.exists(cachePath.c_str())) {
|
||||
Serial.printf("[%lu] [EPB] Cache does not exist, no action needed\n", millis());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!FsHelpers::removeDir(cachePath.c_str())) {
|
||||
if (!SdMan.removeDir(cachePath.c_str())) {
|
||||
Serial.printf("[%lu] [EPB] Failed to clear cache\n", millis());
|
||||
return false;
|
||||
}
|
||||
@@ -200,55 +241,83 @@ bool Epub::clearCache() const {
|
||||
}
|
||||
|
||||
void Epub::setupCacheDir() const {
|
||||
if (SD.exists(cachePath.c_str())) {
|
||||
if (SdMan.exists(cachePath.c_str())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop over each segment of the cache path and create directories as needed
|
||||
for (size_t i = 1; i < cachePath.length(); i++) {
|
||||
if (cachePath[i] == '/') {
|
||||
SD.mkdir(cachePath.substr(0, i).c_str());
|
||||
}
|
||||
}
|
||||
SD.mkdir(cachePath.c_str());
|
||||
SdMan.mkdir(cachePath.c_str());
|
||||
}
|
||||
|
||||
const std::string& Epub::getCachePath() const { return cachePath; }
|
||||
|
||||
const std::string& Epub::getPath() const { return filepath; }
|
||||
|
||||
const std::string& Epub::getTitle() const { return title; }
|
||||
const std::string& Epub::getTitle() const {
|
||||
static std::string blank;
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
return blank;
|
||||
}
|
||||
|
||||
return bookMetadataCache->coreMetadata.title;
|
||||
}
|
||||
|
||||
const std::string& Epub::getAuthor() const {
|
||||
static std::string blank;
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
return blank;
|
||||
}
|
||||
|
||||
return bookMetadataCache->coreMetadata.author;
|
||||
}
|
||||
|
||||
std::string Epub::getCoverBmpPath() const { return cachePath + "/cover.bmp"; }
|
||||
|
||||
bool Epub::generateCoverBmp() const {
|
||||
// Already generated, return true
|
||||
if (SD.exists(getCoverBmpPath().c_str())) {
|
||||
if (SdMan.exists(getCoverBmpPath().c_str())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (coverImageItem.empty()) {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] Cannot generate cover BMP, cache not loaded\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto coverImageHref = bookMetadataCache->coreMetadata.coverItemHref;
|
||||
if (coverImageHref.empty()) {
|
||||
Serial.printf("[%lu] [EBP] No known cover image\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (coverImageItem.substr(coverImageItem.length() - 4) == ".jpg" ||
|
||||
coverImageItem.substr(coverImageItem.length() - 5) == ".jpeg") {
|
||||
if (coverImageHref.substr(coverImageHref.length() - 4) == ".jpg" ||
|
||||
coverImageHref.substr(coverImageHref.length() - 5) == ".jpeg") {
|
||||
Serial.printf("[%lu] [EBP] Generating BMP from JPG cover image\n", millis());
|
||||
File coverJpg = SD.open((getCachePath() + "/.cover.jpg").c_str(), FILE_WRITE, true);
|
||||
readItemContentsToStream(coverImageItem, coverJpg, 1024);
|
||||
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
|
||||
|
||||
FsFile coverJpg;
|
||||
if (!SdMan.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) {
|
||||
return false;
|
||||
}
|
||||
readItemContentsToStream(coverImageHref, coverJpg, 1024);
|
||||
coverJpg.close();
|
||||
|
||||
coverJpg = SD.open((getCachePath() + "/.cover.jpg").c_str(), FILE_READ);
|
||||
File coverBmp = SD.open(getCoverBmpPath().c_str(), FILE_WRITE, true);
|
||||
if (!SdMan.openFileForRead("EBP", coverJpgTempPath, coverJpg)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile coverBmp;
|
||||
if (!SdMan.openFileForWrite("EBP", getCoverBmpPath(), coverBmp)) {
|
||||
coverJpg.close();
|
||||
return false;
|
||||
}
|
||||
const bool success = JpegToBmpConverter::jpegFileToBmpStream(coverJpg, coverBmp);
|
||||
coverJpg.close();
|
||||
coverBmp.close();
|
||||
SD.remove((getCachePath() + "/.cover.jpg").c_str());
|
||||
SdMan.remove(coverJpgTempPath.c_str());
|
||||
|
||||
if (!success) {
|
||||
Serial.printf("[%lu] [EBP] Failed to generate BMP from JPG cover image\n", millis());
|
||||
SD.remove(getCoverBmpPath().c_str());
|
||||
SdMan.remove(getCoverBmpPath().c_str());
|
||||
}
|
||||
Serial.printf("[%lu] [EBP] Generated BMP from JPG cover image, success: %s\n", millis(), success ? "yes" : "no");
|
||||
return success;
|
||||
@@ -259,47 +328,15 @@ bool Epub::generateCoverBmp() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string normalisePath(const std::string& path) {
|
||||
std::vector<std::string> components;
|
||||
std::string component;
|
||||
|
||||
for (const auto c : path) {
|
||||
if (c == '/') {
|
||||
if (!component.empty()) {
|
||||
if (component == "..") {
|
||||
if (!components.empty()) {
|
||||
components.pop_back();
|
||||
}
|
||||
} else {
|
||||
components.push_back(component);
|
||||
}
|
||||
component.clear();
|
||||
}
|
||||
} else {
|
||||
component += c;
|
||||
}
|
||||
uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size, const bool trailingNullByte) const {
|
||||
if (itemHref.empty()) {
|
||||
Serial.printf("[%lu] [EBP] Failed to read item, empty href\n", millis());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!component.empty()) {
|
||||
components.push_back(component);
|
||||
}
|
||||
const std::string path = FsHelpers::normalisePath(itemHref);
|
||||
|
||||
std::string result;
|
||||
for (const auto& c : components) {
|
||||
if (!result.empty()) {
|
||||
result += "/";
|
||||
}
|
||||
result += c;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size, bool trailingNullByte) const {
|
||||
const ZipFile zip("/sd" + filepath);
|
||||
const std::string path = normalisePath(itemHref);
|
||||
|
||||
const auto content = zip.readFileToMemory(path.c_str(), size, trailingNullByte);
|
||||
const auto content = ZipFile(filepath).readFileToMemory(path.c_str(), size, trailingNullByte);
|
||||
if (!content) {
|
||||
Serial.printf("[%lu] [EBP] Failed to read item %s\n", millis(), path.c_str());
|
||||
return nullptr;
|
||||
@@ -309,115 +346,132 @@ uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size
|
||||
}
|
||||
|
||||
bool Epub::readItemContentsToStream(const std::string& itemHref, Print& out, const size_t chunkSize) const {
|
||||
const ZipFile zip("/sd" + filepath);
|
||||
const std::string path = normalisePath(itemHref);
|
||||
if (itemHref.empty()) {
|
||||
Serial.printf("[%lu] [EBP] Failed to read item, empty href\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
return zip.readFileToStream(path.c_str(), out, chunkSize);
|
||||
const std::string path = FsHelpers::normalisePath(itemHref);
|
||||
return ZipFile(filepath).readFileToStream(path.c_str(), out, chunkSize);
|
||||
}
|
||||
|
||||
bool Epub::getItemSize(const std::string& itemHref, size_t* size) const {
|
||||
const ZipFile zip("/sd" + filepath);
|
||||
return getItemSize(zip, itemHref, size);
|
||||
const std::string path = FsHelpers::normalisePath(itemHref);
|
||||
return ZipFile(filepath).getInflatedFileSize(path.c_str(), size);
|
||||
}
|
||||
|
||||
bool Epub::getItemSize(const ZipFile& zip, const std::string& itemHref, size_t* size) {
|
||||
const std::string path = normalisePath(itemHref);
|
||||
return zip.getInflatedFileSize(path.c_str(), size);
|
||||
}
|
||||
|
||||
int Epub::getSpineItemsCount() const { return spine.size(); }
|
||||
|
||||
size_t Epub::getCumulativeSpineItemSize(const int spineIndex) const {
|
||||
if (spineIndex < 0 || spineIndex >= static_cast<int>(cumulativeSpineItemSize.size())) {
|
||||
Serial.printf("[%lu] [EBP] getCumulativeSpineItemSize index:%d is out of range\n", millis(), spineIndex);
|
||||
int Epub::getSpineItemsCount() const {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
return 0;
|
||||
}
|
||||
return cumulativeSpineItemSize.at(spineIndex);
|
||||
return bookMetadataCache->getSpineCount();
|
||||
}
|
||||
|
||||
std::string& Epub::getSpineItem(const int spineIndex) {
|
||||
static std::string emptyString;
|
||||
if (spine.empty()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineItem called but spine is empty\n", millis());
|
||||
return emptyString;
|
||||
size_t Epub::getCumulativeSpineItemSize(const int spineIndex) const { return getSpineItem(spineIndex).cumulativeSize; }
|
||||
|
||||
BookMetadataCache::SpineEntry Epub::getSpineItem(const int spineIndex) const {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineItem called but cache not loaded\n", millis());
|
||||
return {};
|
||||
}
|
||||
if (spineIndex < 0 || spineIndex >= static_cast<int>(spine.size())) {
|
||||
|
||||
if (spineIndex < 0 || spineIndex >= bookMetadataCache->getSpineCount()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineItem index:%d is out of range\n", millis(), spineIndex);
|
||||
return spine.at(0).second;
|
||||
return bookMetadataCache->getSpineEntry(0);
|
||||
}
|
||||
|
||||
return spine.at(spineIndex).second;
|
||||
return bookMetadataCache->getSpineEntry(spineIndex);
|
||||
}
|
||||
|
||||
EpubTocEntry& Epub::getTocItem(const int tocTndex) {
|
||||
static EpubTocEntry emptyEntry = {};
|
||||
if (toc.empty()) {
|
||||
Serial.printf("[%lu] [EBP] getTocItem called but toc is empty\n", millis());
|
||||
return emptyEntry;
|
||||
}
|
||||
if (tocTndex < 0 || tocTndex >= static_cast<int>(toc.size())) {
|
||||
Serial.printf("[%lu] [EBP] getTocItem index:%d is out of range\n", millis(), tocTndex);
|
||||
return toc.at(0);
|
||||
BookMetadataCache::TocEntry Epub::getTocItem(const int tocIndex) const {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] getTocItem called but cache not loaded\n", millis());
|
||||
return {};
|
||||
}
|
||||
|
||||
return toc.at(tocTndex);
|
||||
if (tocIndex < 0 || tocIndex >= bookMetadataCache->getTocCount()) {
|
||||
Serial.printf("[%lu] [EBP] getTocItem index:%d is out of range\n", millis(), tocIndex);
|
||||
return {};
|
||||
}
|
||||
|
||||
return bookMetadataCache->getTocEntry(tocIndex);
|
||||
}
|
||||
|
||||
int Epub::getTocItemsCount() const { return toc.size(); }
|
||||
int Epub::getTocItemsCount() const {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bookMetadataCache->getTocCount();
|
||||
}
|
||||
|
||||
// work out the section index for a toc index
|
||||
int Epub::getSpineIndexForTocIndex(const int tocIndex) const {
|
||||
if (tocIndex < 0 || tocIndex >= toc.size()) {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineIndexForTocIndex called but cache not loaded\n", millis());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tocIndex < 0 || tocIndex >= bookMetadataCache->getTocCount()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineIndexForTocIndex: tocIndex %d out of range\n", millis(), tocIndex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// the toc entry should have an href that matches the spine item
|
||||
// so we can find the spine index by looking for the href
|
||||
for (int i = 0; i < spine.size(); i++) {
|
||||
if (spine[i].second == toc[tocIndex].href) {
|
||||
return i;
|
||||
}
|
||||
const int spineIndex = bookMetadataCache->getTocEntry(tocIndex).spineIndex;
|
||||
if (spineIndex < 0) {
|
||||
Serial.printf("[%lu] [EBP] Section not found for TOC index %d\n", millis(), tocIndex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EBP] Section not found\n", millis());
|
||||
// not found - default to the start of the book
|
||||
return 0;
|
||||
return spineIndex;
|
||||
}
|
||||
|
||||
int Epub::getTocIndexForSpineIndex(const int spineIndex) const {
|
||||
if (spineIndex < 0 || spineIndex >= spine.size()) {
|
||||
Serial.printf("[%lu] [EBP] getTocIndexForSpineIndex: spineIndex %d out of range\n", millis(), spineIndex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// the toc entry should have an href that matches the spine item
|
||||
// so we can find the toc index by looking for the href
|
||||
for (int i = 0; i < toc.size(); i++) {
|
||||
if (toc[i].href == spine[spineIndex].second) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EBP] TOC item not found\n", millis());
|
||||
return -1;
|
||||
}
|
||||
int Epub::getTocIndexForSpineIndex(const int spineIndex) const { return getSpineItem(spineIndex).tocIndex; }
|
||||
|
||||
size_t Epub::getBookSize() const {
|
||||
if (spine.empty()) {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded() || bookMetadataCache->getSpineCount() == 0) {
|
||||
return 0;
|
||||
}
|
||||
return getCumulativeSpineItemSize(getSpineItemsCount() - 1);
|
||||
}
|
||||
|
||||
int Epub::getSpineIndexForTextReference() const {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineIndexForTextReference called but cache not loaded\n", millis());
|
||||
return 0;
|
||||
}
|
||||
Serial.printf("[%lu] [ERS] Core Metadata: cover(%d)=%s, textReference(%d)=%s\n", millis(),
|
||||
bookMetadataCache->coreMetadata.coverItemHref.size(),
|
||||
bookMetadataCache->coreMetadata.coverItemHref.c_str(),
|
||||
bookMetadataCache->coreMetadata.textReferenceHref.size(),
|
||||
bookMetadataCache->coreMetadata.textReferenceHref.c_str());
|
||||
|
||||
if (bookMetadataCache->coreMetadata.textReferenceHref.empty()) {
|
||||
// there was no textReference in epub, so we return 0 (the first chapter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// loop through spine items to get the correct index matching the text href
|
||||
for (size_t i = 0; i < getSpineItemsCount(); i++) {
|
||||
if (getSpineItem(i).href == bookMetadataCache->coreMetadata.textReferenceHref) {
|
||||
Serial.printf("[%lu] [ERS] Text reference %s found at index %d\n", millis(),
|
||||
bookMetadataCache->coreMetadata.textReferenceHref.c_str(), i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// This should not happen, as we checked for empty textReferenceHref earlier
|
||||
Serial.printf("[%lu] [EBP] Section not found for text reference\n", millis());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate progress in book
|
||||
uint8_t Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) {
|
||||
size_t bookSize = getBookSize();
|
||||
uint8_t Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) const {
|
||||
const size_t bookSize = getBookSize();
|
||||
if (bookSize == 0) {
|
||||
return 0;
|
||||
}
|
||||
size_t prevChapterSize = (currentSpineIndex >= 1) ? getCumulativeSpineItemSize(currentSpineIndex - 1) : 0;
|
||||
size_t curChapterSize = getCumulativeSpineItemSize(currentSpineIndex) - prevChapterSize;
|
||||
size_t sectionProgSize = currentSpineRead * curChapterSize;
|
||||
const size_t prevChapterSize = (currentSpineIndex >= 1) ? getCumulativeSpineItemSize(currentSpineIndex - 1) : 0;
|
||||
const size_t curChapterSize = getCumulativeSpineItemSize(currentSpineIndex) - prevChapterSize;
|
||||
const size_t sectionProgSize = currentSpineRead * curChapterSize;
|
||||
return round(static_cast<float>(prevChapterSize + sectionProgSize) / bookSize * 100.0);
|
||||
}
|
||||
|
||||
+14
-20
@@ -1,39 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <Print.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Epub/EpubTocEntry.h"
|
||||
#include "Epub/BookMetadataCache.h"
|
||||
|
||||
class ZipFile;
|
||||
|
||||
class Epub {
|
||||
// the title read from the EPUB meta data
|
||||
std::string title;
|
||||
// the cover image
|
||||
std::string coverImageItem;
|
||||
// the ncx file
|
||||
std::string tocNcxItem;
|
||||
// where is the EPUBfile?
|
||||
std::string filepath;
|
||||
// the spine of the EPUB file
|
||||
std::vector<std::pair<std::string, std::string>> spine;
|
||||
// the file size of the spine items (proxy to book progress)
|
||||
std::vector<size_t> cumulativeSpineItemSize;
|
||||
// the toc of the EPUB file
|
||||
std::vector<EpubTocEntry> toc;
|
||||
// the base path for items in the EPUB file
|
||||
std::string contentBasePath;
|
||||
// Uniq cache key based on filepath
|
||||
std::string cachePath;
|
||||
// Spine and TOC cache
|
||||
std::unique_ptr<BookMetadataCache> bookMetadataCache;
|
||||
|
||||
bool findContentOpfFile(std::string* contentOpfFile) const;
|
||||
bool parseContentOpf(const std::string& contentOpfFilePath);
|
||||
bool parseTocNcxFile();
|
||||
void initializeSpineItemSizes();
|
||||
static bool getItemSize(const ZipFile& zip, const std::string& itemHref, size_t* size);
|
||||
bool parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata);
|
||||
bool parseTocNcxFile() const;
|
||||
|
||||
public:
|
||||
explicit Epub(std::string filepath, const std::string& cacheDir) : filepath(std::move(filepath)) {
|
||||
@@ -42,26 +34,28 @@ class Epub {
|
||||
}
|
||||
~Epub() = default;
|
||||
std::string& getBasePath() { return contentBasePath; }
|
||||
bool load();
|
||||
bool load(bool buildIfMissing = true);
|
||||
bool clearCache() const;
|
||||
void setupCacheDir() const;
|
||||
const std::string& getCachePath() const;
|
||||
const std::string& getPath() const;
|
||||
const std::string& getTitle() const;
|
||||
const std::string& getAuthor() const;
|
||||
std::string getCoverBmpPath() const;
|
||||
bool generateCoverBmp() const;
|
||||
uint8_t* readItemContentsToBytes(const std::string& itemHref, size_t* size = nullptr,
|
||||
bool trailingNullByte = false) const;
|
||||
bool readItemContentsToStream(const std::string& itemHref, Print& out, size_t chunkSize) const;
|
||||
bool getItemSize(const std::string& itemHref, size_t* size) const;
|
||||
std::string& getSpineItem(int spineIndex);
|
||||
BookMetadataCache::SpineEntry getSpineItem(int spineIndex) const;
|
||||
BookMetadataCache::TocEntry getTocItem(int tocIndex) const;
|
||||
int getSpineItemsCount() const;
|
||||
size_t getCumulativeSpineItemSize(const int spineIndex) const;
|
||||
EpubTocEntry& getTocItem(int tocIndex);
|
||||
int getTocItemsCount() const;
|
||||
int getSpineIndexForTocIndex(int tocIndex) const;
|
||||
int getTocIndexForSpineIndex(int spineIndex) const;
|
||||
size_t getCumulativeSpineItemSize(int spineIndex) const;
|
||||
int getSpineIndexForTextReference() const;
|
||||
|
||||
size_t getBookSize() const;
|
||||
uint8_t calculateProgress(const int currentSpineIndex, const float currentSpineRead);
|
||||
uint8_t calculateProgress(int currentSpineIndex, float currentSpineRead) const;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
#include "BookMetadataCache.h"
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
#include <Serialization.h>
|
||||
#include <ZipFile.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "FsHelpers.h"
|
||||
|
||||
namespace {
|
||||
constexpr uint8_t BOOK_CACHE_VERSION = 3;
|
||||
constexpr char bookBinFile[] = "/book.bin";
|
||||
constexpr char tmpSpineBinFile[] = "/spine.bin.tmp";
|
||||
constexpr char tmpTocBinFile[] = "/toc.bin.tmp";
|
||||
} // namespace
|
||||
|
||||
/* ============= WRITING / BUILDING FUNCTIONS ================ */
|
||||
|
||||
bool BookMetadataCache::beginWrite() {
|
||||
buildMode = true;
|
||||
spineCount = 0;
|
||||
tocCount = 0;
|
||||
Serial.printf("[%lu] [BMC] Entering write mode\n", millis());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BookMetadataCache::beginContentOpfPass() {
|
||||
Serial.printf("[%lu] [BMC] Beginning content opf pass\n", millis());
|
||||
|
||||
// Open spine file for writing
|
||||
return SdMan.openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile);
|
||||
}
|
||||
|
||||
bool BookMetadataCache::endContentOpfPass() {
|
||||
spineFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BookMetadataCache::beginTocPass() {
|
||||
Serial.printf("[%lu] [BMC] Beginning toc pass\n", millis());
|
||||
|
||||
// Open spine file for reading
|
||||
if (!SdMan.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
|
||||
return false;
|
||||
}
|
||||
if (!SdMan.openFileForWrite("BMC", cachePath + tmpTocBinFile, tocFile)) {
|
||||
spineFile.close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BookMetadataCache::endTocPass() {
|
||||
tocFile.close();
|
||||
spineFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BookMetadataCache::endWrite() {
|
||||
if (!buildMode) {
|
||||
Serial.printf("[%lu] [BMC] endWrite called but not in build mode\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
buildMode = false;
|
||||
Serial.printf("[%lu] [BMC] Wrote %d spine, %d TOC entries\n", millis(), spineCount, tocCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMetadata& metadata) {
|
||||
// Open all three files, writing to meta, reading from spine and toc
|
||||
if (!SdMan.openFileForWrite("BMC", cachePath + bookBinFile, bookFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SdMan.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
|
||||
bookFile.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SdMan.openFileForRead("BMC", cachePath + tmpTocBinFile, tocFile)) {
|
||||
bookFile.close();
|
||||
spineFile.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr uint32_t headerASize =
|
||||
sizeof(BOOK_CACHE_VERSION) + /* LUT Offset */ sizeof(uint32_t) + sizeof(spineCount) + sizeof(tocCount);
|
||||
const uint32_t metadataSize = metadata.title.size() + metadata.author.size() + metadata.coverItemHref.size() +
|
||||
metadata.textReferenceHref.size() + sizeof(uint32_t) * 4;
|
||||
const uint32_t lutSize = sizeof(uint32_t) * spineCount + sizeof(uint32_t) * tocCount;
|
||||
const uint32_t lutOffset = headerASize + metadataSize;
|
||||
|
||||
// Header A
|
||||
serialization::writePod(bookFile, BOOK_CACHE_VERSION);
|
||||
serialization::writePod(bookFile, lutOffset);
|
||||
serialization::writePod(bookFile, spineCount);
|
||||
serialization::writePod(bookFile, tocCount);
|
||||
// Metadata
|
||||
serialization::writeString(bookFile, metadata.title);
|
||||
serialization::writeString(bookFile, metadata.author);
|
||||
serialization::writeString(bookFile, metadata.coverItemHref);
|
||||
serialization::writeString(bookFile, metadata.textReferenceHref);
|
||||
|
||||
// Loop through spine entries, writing LUT positions
|
||||
spineFile.seek(0);
|
||||
for (int i = 0; i < spineCount; i++) {
|
||||
uint32_t pos = spineFile.position();
|
||||
auto spineEntry = readSpineEntry(spineFile);
|
||||
serialization::writePod(bookFile, pos + lutOffset + lutSize);
|
||||
}
|
||||
|
||||
// Loop through toc entries, writing LUT positions
|
||||
tocFile.seek(0);
|
||||
for (int i = 0; i < tocCount; i++) {
|
||||
uint32_t pos = tocFile.position();
|
||||
auto tocEntry = readTocEntry(tocFile);
|
||||
serialization::writePod(bookFile, pos + lutOffset + lutSize + static_cast<uint32_t>(spineFile.position()));
|
||||
}
|
||||
|
||||
// LUTs complete
|
||||
// Loop through spines from spine file matching up TOC indexes, calculating cumulative size and writing to book.bin
|
||||
|
||||
ZipFile zip(epubPath);
|
||||
// Pre-open zip file to speed up size calculations
|
||||
if (!zip.open()) {
|
||||
Serial.printf("[%lu] [BMC] Could not open EPUB zip for size calculations\n", millis());
|
||||
bookFile.close();
|
||||
spineFile.close();
|
||||
tocFile.close();
|
||||
return false;
|
||||
}
|
||||
// TODO: For large ZIPs loading the all localHeaderOffsets will crash.
|
||||
// However not having them loaded is extremely slow. Need a better solution here.
|
||||
// Perhaps only a cache of spine items or a better way to speedup lookups?
|
||||
if (!zip.loadAllFileStatSlims()) {
|
||||
Serial.printf("[%lu] [BMC] Could not load zip local header offsets for size calculations\n", millis());
|
||||
bookFile.close();
|
||||
spineFile.close();
|
||||
tocFile.close();
|
||||
zip.close();
|
||||
return false;
|
||||
}
|
||||
uint32_t cumSize = 0;
|
||||
spineFile.seek(0);
|
||||
int lastSpineTocIndex = -1;
|
||||
for (int i = 0; i < spineCount; i++) {
|
||||
auto spineEntry = readSpineEntry(spineFile);
|
||||
|
||||
tocFile.seek(0);
|
||||
for (int j = 0; j < tocCount; j++) {
|
||||
auto tocEntry = readTocEntry(tocFile);
|
||||
if (tocEntry.spineIndex == i) {
|
||||
spineEntry.tocIndex = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Not a huge deal if we don't fine a TOC entry for the spine entry, this is expected behaviour for EPUBs
|
||||
// Logging here is for debugging
|
||||
if (spineEntry.tocIndex == -1) {
|
||||
Serial.printf(
|
||||
"[%lu] [BMC] Warning: Could not find TOC entry for spine item %d: %s, using title from last section\n",
|
||||
millis(), i, spineEntry.href.c_str());
|
||||
spineEntry.tocIndex = lastSpineTocIndex;
|
||||
}
|
||||
lastSpineTocIndex = spineEntry.tocIndex;
|
||||
|
||||
// Calculate size for cumulative size
|
||||
size_t itemSize = 0;
|
||||
const std::string path = FsHelpers::normalisePath(spineEntry.href);
|
||||
if (zip.getInflatedFileSize(path.c_str(), &itemSize)) {
|
||||
cumSize += itemSize;
|
||||
spineEntry.cumulativeSize = cumSize;
|
||||
} else {
|
||||
Serial.printf("[%lu] [BMC] Warning: Could not get size for spine item: %s\n", millis(), path.c_str());
|
||||
}
|
||||
|
||||
// Write out spine data to book.bin
|
||||
writeSpineEntry(bookFile, spineEntry);
|
||||
}
|
||||
// Close opened zip file
|
||||
zip.close();
|
||||
|
||||
// Loop through toc entries from toc file writing to book.bin
|
||||
tocFile.seek(0);
|
||||
for (int i = 0; i < tocCount; i++) {
|
||||
auto tocEntry = readTocEntry(tocFile);
|
||||
writeTocEntry(bookFile, tocEntry);
|
||||
}
|
||||
|
||||
bookFile.close();
|
||||
spineFile.close();
|
||||
tocFile.close();
|
||||
|
||||
Serial.printf("[%lu] [BMC] Successfully built book.bin\n", millis());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BookMetadataCache::cleanupTmpFiles() const {
|
||||
if (SdMan.exists((cachePath + tmpSpineBinFile).c_str())) {
|
||||
SdMan.remove((cachePath + tmpSpineBinFile).c_str());
|
||||
}
|
||||
if (SdMan.exists((cachePath + tmpTocBinFile).c_str())) {
|
||||
SdMan.remove((cachePath + tmpTocBinFile).c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t BookMetadataCache::writeSpineEntry(FsFile& file, const SpineEntry& entry) const {
|
||||
const uint32_t pos = file.position();
|
||||
serialization::writeString(file, entry.href);
|
||||
serialization::writePod(file, entry.cumulativeSize);
|
||||
serialization::writePod(file, entry.tocIndex);
|
||||
return pos;
|
||||
}
|
||||
|
||||
uint32_t BookMetadataCache::writeTocEntry(FsFile& file, const TocEntry& entry) const {
|
||||
const uint32_t pos = file.position();
|
||||
serialization::writeString(file, entry.title);
|
||||
serialization::writeString(file, entry.href);
|
||||
serialization::writeString(file, entry.anchor);
|
||||
serialization::writePod(file, entry.level);
|
||||
serialization::writePod(file, entry.spineIndex);
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Note: for the LUT to be accurate, this **MUST** be called for all spine items before `addTocEntry` is ever called
|
||||
// this is because in this function we're marking positions of the items
|
||||
void BookMetadataCache::createSpineEntry(const std::string& href) {
|
||||
if (!buildMode || !spineFile) {
|
||||
Serial.printf("[%lu] [BMC] createSpineEntry called but not in build mode\n", millis());
|
||||
return;
|
||||
}
|
||||
|
||||
const SpineEntry entry(href, 0, -1);
|
||||
writeSpineEntry(spineFile, entry);
|
||||
spineCount++;
|
||||
}
|
||||
|
||||
void BookMetadataCache::createTocEntry(const std::string& title, const std::string& href, const std::string& anchor,
|
||||
const uint8_t level) {
|
||||
if (!buildMode || !tocFile || !spineFile) {
|
||||
Serial.printf("[%lu] [BMC] createTocEntry called but not in build mode\n", millis());
|
||||
return;
|
||||
}
|
||||
|
||||
int spineIndex = -1;
|
||||
// find spine index
|
||||
// TODO: This lookup is slow as need to scan through all items each time. We can't hold it all in memory due to size.
|
||||
// But perhaps we can load just the hrefs in a vector/list to do an index lookup?
|
||||
spineFile.seek(0);
|
||||
for (int i = 0; i < spineCount; i++) {
|
||||
auto spineEntry = readSpineEntry(spineFile);
|
||||
if (spineEntry.href == href) {
|
||||
spineIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (spineIndex == -1) {
|
||||
Serial.printf("[%lu] [BMC] addTocEntry: Could not find spine item for TOC href %s\n", millis(), href.c_str());
|
||||
}
|
||||
|
||||
const TocEntry entry(title, href, anchor, level, spineIndex);
|
||||
writeTocEntry(tocFile, entry);
|
||||
tocCount++;
|
||||
}
|
||||
|
||||
/* ============= READING / LOADING FUNCTIONS ================ */
|
||||
|
||||
bool BookMetadataCache::load() {
|
||||
if (!SdMan.openFileForRead("BMC", cachePath + bookBinFile, bookFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t version;
|
||||
serialization::readPod(bookFile, version);
|
||||
if (version != BOOK_CACHE_VERSION) {
|
||||
Serial.printf("[%lu] [BMC] Cache version mismatch: expected %d, got %d\n", millis(), BOOK_CACHE_VERSION, version);
|
||||
bookFile.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
serialization::readPod(bookFile, lutOffset);
|
||||
serialization::readPod(bookFile, spineCount);
|
||||
serialization::readPod(bookFile, tocCount);
|
||||
|
||||
serialization::readString(bookFile, coreMetadata.title);
|
||||
serialization::readString(bookFile, coreMetadata.author);
|
||||
serialization::readString(bookFile, coreMetadata.coverItemHref);
|
||||
serialization::readString(bookFile, coreMetadata.textReferenceHref);
|
||||
|
||||
loaded = true;
|
||||
Serial.printf("[%lu] [BMC] Loaded cache data: %d spine, %d TOC entries\n", millis(), spineCount, tocCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
BookMetadataCache::SpineEntry BookMetadataCache::getSpineEntry(const int index) {
|
||||
if (!loaded) {
|
||||
Serial.printf("[%lu] [BMC] getSpineEntry called but cache not loaded\n", millis());
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index < 0 || index >= static_cast<int>(spineCount)) {
|
||||
Serial.printf("[%lu] [BMC] getSpineEntry index %d out of range\n", millis(), index);
|
||||
return {};
|
||||
}
|
||||
|
||||
// Seek to spine LUT item, read from LUT and get out data
|
||||
bookFile.seek(lutOffset + sizeof(uint32_t) * index);
|
||||
uint32_t spineEntryPos;
|
||||
serialization::readPod(bookFile, spineEntryPos);
|
||||
bookFile.seek(spineEntryPos);
|
||||
return readSpineEntry(bookFile);
|
||||
}
|
||||
|
||||
BookMetadataCache::TocEntry BookMetadataCache::getTocEntry(const int index) {
|
||||
if (!loaded) {
|
||||
Serial.printf("[%lu] [BMC] getTocEntry called but cache not loaded\n", millis());
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index < 0 || index >= static_cast<int>(tocCount)) {
|
||||
Serial.printf("[%lu] [BMC] getTocEntry index %d out of range\n", millis(), index);
|
||||
return {};
|
||||
}
|
||||
|
||||
// Seek to TOC LUT item, read from LUT and get out data
|
||||
bookFile.seek(lutOffset + sizeof(uint32_t) * spineCount + sizeof(uint32_t) * index);
|
||||
uint32_t tocEntryPos;
|
||||
serialization::readPod(bookFile, tocEntryPos);
|
||||
bookFile.seek(tocEntryPos);
|
||||
return readTocEntry(bookFile);
|
||||
}
|
||||
|
||||
BookMetadataCache::SpineEntry BookMetadataCache::readSpineEntry(FsFile& file) const {
|
||||
SpineEntry entry;
|
||||
serialization::readString(file, entry.href);
|
||||
serialization::readPod(file, entry.cumulativeSize);
|
||||
serialization::readPod(file, entry.tocIndex);
|
||||
return entry;
|
||||
}
|
||||
|
||||
BookMetadataCache::TocEntry BookMetadataCache::readTocEntry(FsFile& file) const {
|
||||
TocEntry entry;
|
||||
serialization::readString(file, entry.title);
|
||||
serialization::readString(file, entry.href);
|
||||
serialization::readString(file, entry.anchor);
|
||||
serialization::readPod(file, entry.level);
|
||||
serialization::readPod(file, entry.spineIndex);
|
||||
return entry;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDCardManager.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
class BookMetadataCache {
|
||||
public:
|
||||
struct BookMetadata {
|
||||
std::string title;
|
||||
std::string author;
|
||||
std::string coverItemHref;
|
||||
std::string textReferenceHref;
|
||||
};
|
||||
|
||||
struct SpineEntry {
|
||||
std::string href;
|
||||
size_t cumulativeSize;
|
||||
int16_t tocIndex;
|
||||
|
||||
SpineEntry() : cumulativeSize(0), tocIndex(-1) {}
|
||||
SpineEntry(std::string href, const size_t cumulativeSize, const int16_t tocIndex)
|
||||
: href(std::move(href)), cumulativeSize(cumulativeSize), tocIndex(tocIndex) {}
|
||||
};
|
||||
|
||||
struct TocEntry {
|
||||
std::string title;
|
||||
std::string href;
|
||||
std::string anchor;
|
||||
uint8_t level;
|
||||
int16_t spineIndex;
|
||||
|
||||
TocEntry() : level(0), spineIndex(-1) {}
|
||||
TocEntry(std::string title, std::string href, std::string anchor, const uint8_t level, const int16_t spineIndex)
|
||||
: title(std::move(title)),
|
||||
href(std::move(href)),
|
||||
anchor(std::move(anchor)),
|
||||
level(level),
|
||||
spineIndex(spineIndex) {}
|
||||
};
|
||||
|
||||
private:
|
||||
std::string cachePath;
|
||||
size_t lutOffset;
|
||||
uint16_t spineCount;
|
||||
uint16_t tocCount;
|
||||
bool loaded;
|
||||
bool buildMode;
|
||||
|
||||
FsFile bookFile;
|
||||
// Temp file handles during build
|
||||
FsFile spineFile;
|
||||
FsFile tocFile;
|
||||
|
||||
uint32_t writeSpineEntry(FsFile& file, const SpineEntry& entry) const;
|
||||
uint32_t writeTocEntry(FsFile& file, const TocEntry& entry) const;
|
||||
SpineEntry readSpineEntry(FsFile& file) const;
|
||||
TocEntry readTocEntry(FsFile& file) const;
|
||||
|
||||
public:
|
||||
BookMetadata coreMetadata;
|
||||
|
||||
explicit BookMetadataCache(std::string cachePath)
|
||||
: cachePath(std::move(cachePath)), lutOffset(0), spineCount(0), tocCount(0), loaded(false), buildMode(false) {}
|
||||
~BookMetadataCache() = default;
|
||||
|
||||
// Building phase (stream to disk immediately)
|
||||
bool beginWrite();
|
||||
bool beginContentOpfPass();
|
||||
void createSpineEntry(const std::string& href);
|
||||
bool endContentOpfPass();
|
||||
bool beginTocPass();
|
||||
void createTocEntry(const std::string& title, const std::string& href, const std::string& anchor, uint8_t level);
|
||||
bool endTocPass();
|
||||
bool endWrite();
|
||||
bool cleanupTmpFiles() const;
|
||||
|
||||
// Post-processing to update mappings and sizes
|
||||
bool buildBookBin(const std::string& epubPath, const BookMetadata& metadata);
|
||||
|
||||
// Reading phase (read mode)
|
||||
bool load();
|
||||
SpineEntry getSpineEntry(int index);
|
||||
TocEntry getTocEntry(int index);
|
||||
int getSpineCount() const { return spineCount; }
|
||||
int getTocCount() const { return tocCount; }
|
||||
bool isLoaded() const { return loaded; }
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
struct EpubTocEntry {
|
||||
std::string title;
|
||||
std::string href;
|
||||
std::string anchor;
|
||||
uint8_t level;
|
||||
};
|
||||
@@ -1,36 +0,0 @@
|
||||
#include "FsHelpers.h"
|
||||
|
||||
#include <SD.h>
|
||||
|
||||
bool FsHelpers::removeDir(const char* path) {
|
||||
// 1. Open the directory
|
||||
File dir = SD.open(path);
|
||||
if (!dir) {
|
||||
return false;
|
||||
}
|
||||
if (!dir.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File file = dir.openNextFile();
|
||||
while (file) {
|
||||
String filePath = path;
|
||||
if (!filePath.endsWith("/")) {
|
||||
filePath += "/";
|
||||
}
|
||||
filePath += file.name();
|
||||
|
||||
if (file.isDirectory()) {
|
||||
if (!removeDir(filePath.c_str())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!SD.remove(filePath.c_str())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
file = dir.openNextFile();
|
||||
}
|
||||
|
||||
return SD.rmdir(path);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
class FsHelpers {
|
||||
public:
|
||||
static bool removeDir(const char* path);
|
||||
};
|
||||
+24
-31
@@ -3,68 +3,61 @@
|
||||
#include <HardwareSerial.h>
|
||||
#include <Serialization.h>
|
||||
|
||||
namespace {
|
||||
constexpr uint8_t PAGE_FILE_VERSION = 3;
|
||||
void PageLine::render(GfxRenderer& renderer, const int fontId, const int xOffset, const int yOffset) {
|
||||
block->render(renderer, fontId, xPos + xOffset, yPos + yOffset);
|
||||
}
|
||||
|
||||
void PageLine::render(GfxRenderer& renderer, const int fontId) { block->render(renderer, fontId, xPos, yPos); }
|
||||
|
||||
void PageLine::serialize(std::ostream& os) {
|
||||
serialization::writePod(os, xPos);
|
||||
serialization::writePod(os, yPos);
|
||||
bool PageLine::serialize(FsFile& file) {
|
||||
serialization::writePod(file, xPos);
|
||||
serialization::writePod(file, yPos);
|
||||
|
||||
// serialize TextBlock pointed to by PageLine
|
||||
block->serialize(os);
|
||||
return block->serialize(file);
|
||||
}
|
||||
|
||||
std::unique_ptr<PageLine> PageLine::deserialize(std::istream& is) {
|
||||
std::unique_ptr<PageLine> PageLine::deserialize(FsFile& file) {
|
||||
int16_t xPos;
|
||||
int16_t yPos;
|
||||
serialization::readPod(is, xPos);
|
||||
serialization::readPod(is, yPos);
|
||||
serialization::readPod(file, xPos);
|
||||
serialization::readPod(file, yPos);
|
||||
|
||||
auto tb = TextBlock::deserialize(is);
|
||||
auto tb = TextBlock::deserialize(file);
|
||||
return std::unique_ptr<PageLine>(new PageLine(std::move(tb), xPos, yPos));
|
||||
}
|
||||
|
||||
void Page::render(GfxRenderer& renderer, const int fontId) const {
|
||||
void Page::render(GfxRenderer& renderer, const int fontId, const int xOffset, const int yOffset) const {
|
||||
for (auto& element : elements) {
|
||||
element->render(renderer, fontId);
|
||||
element->render(renderer, fontId, xOffset, yOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void Page::serialize(std::ostream& os) const {
|
||||
serialization::writePod(os, PAGE_FILE_VERSION);
|
||||
|
||||
bool Page::serialize(FsFile& file) const {
|
||||
const uint32_t count = elements.size();
|
||||
serialization::writePod(os, count);
|
||||
serialization::writePod(file, count);
|
||||
|
||||
for (const auto& el : elements) {
|
||||
// Only PageLine exists currently
|
||||
serialization::writePod(os, static_cast<uint8_t>(TAG_PageLine));
|
||||
el->serialize(os);
|
||||
serialization::writePod(file, static_cast<uint8_t>(TAG_PageLine));
|
||||
if (!el->serialize(file)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Page> Page::deserialize(std::istream& is) {
|
||||
uint8_t version;
|
||||
serialization::readPod(is, version);
|
||||
if (version != PAGE_FILE_VERSION) {
|
||||
Serial.printf("[%lu] [PGE] Deserialization failed: Unknown version %u\n", millis(), version);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Page> Page::deserialize(FsFile& file) {
|
||||
auto page = std::unique_ptr<Page>(new Page());
|
||||
|
||||
uint32_t count;
|
||||
serialization::readPod(is, count);
|
||||
serialization::readPod(file, count);
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
uint8_t tag;
|
||||
serialization::readPod(is, tag);
|
||||
serialization::readPod(file, tag);
|
||||
|
||||
if (tag == TAG_PageLine) {
|
||||
auto pl = PageLine::deserialize(is);
|
||||
auto pl = PageLine::deserialize(file);
|
||||
page->elements.push_back(std::move(pl));
|
||||
} else {
|
||||
Serial.printf("[%lu] [PGE] Deserialization failed: Unknown tag %u\n", millis(), tag);
|
||||
|
||||
+10
-8
@@ -1,4 +1,6 @@
|
||||
#pragma once
|
||||
#include <SdFat.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -15,8 +17,8 @@ class PageElement {
|
||||
int16_t yPos;
|
||||
explicit PageElement(const int16_t xPos, const int16_t yPos) : xPos(xPos), yPos(yPos) {}
|
||||
virtual ~PageElement() = default;
|
||||
virtual void render(GfxRenderer& renderer, int fontId) = 0;
|
||||
virtual void serialize(std::ostream& os) = 0;
|
||||
virtual void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) = 0;
|
||||
virtual bool serialize(FsFile& file) = 0;
|
||||
};
|
||||
|
||||
// a line from a block element
|
||||
@@ -26,16 +28,16 @@ class PageLine final : public PageElement {
|
||||
public:
|
||||
PageLine(std::shared_ptr<TextBlock> block, const int16_t xPos, const int16_t yPos)
|
||||
: PageElement(xPos, yPos), block(std::move(block)) {}
|
||||
void render(GfxRenderer& renderer, int fontId) override;
|
||||
void serialize(std::ostream& os) override;
|
||||
static std::unique_ptr<PageLine> deserialize(std::istream& is);
|
||||
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override;
|
||||
bool serialize(FsFile& file) override;
|
||||
static std::unique_ptr<PageLine> deserialize(FsFile& file);
|
||||
};
|
||||
|
||||
class Page {
|
||||
public:
|
||||
// the list of block index and line numbers on this page
|
||||
std::vector<std::shared_ptr<PageElement>> elements;
|
||||
void render(GfxRenderer& renderer, int fontId) const;
|
||||
void serialize(std::ostream& os) const;
|
||||
static std::unique_ptr<Page> deserialize(std::istream& is);
|
||||
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) const;
|
||||
bool serialize(FsFile& file) const;
|
||||
static std::unique_ptr<Page> deserialize(FsFile& file);
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user