Compare commits

...

82 Commits

Author SHA1 Message Date
a52dc89f9f diagdummy srpr2 wait for device lock 2025-11-24 22:29:59 +01:00
cc2b96f37a qemu_pci_serial device locking/sync 2025-11-24 22:29:32 +01:00
80a29d8ff6 Handle continous jobs via new subsystem - CJob 2025-11-24 21:53:51 +01:00
4f55d765b4 ulib Fix volatile 2025-11-24 17:14:45 +01:00
ec732d4627 Make SpinLock IRQ_CTX irq_flags volatile 2025-11-24 17:14:28 +01:00
3f3795df3c Fix stack alignment 2025-11-24 17:04:33 +01:00
2faad79559 diagdummy Add srpr2 subcommand for contiguous printing to serial (and testing access races) 2025-11-24 01:00:53 +01:00
9b25dcd691 pci ata Print info about falling back to ISA 2025-11-23 23:00:51 +01:00
33b3a641fb qemu_pci_serial driver 2025-11-23 22:56:45 +01:00
d3a91b6438 Move PCI ATA driver to pci/ata 2025-11-23 21:49:49 +01:00
fa152cac4d PCI driver rewrite 2025-11-23 21:37:12 +01:00
e105b2fe35 ulib Remove sync 2025-11-23 19:51:48 +01:00
7f78f20b17 diadummy Testing serial device 2025-11-22 12:22:35 +01:00
b4d6315dea Add FAT32 support 2025-11-19 15:54:17 +01:00
a05e73e69a legal Add fat_io_lib license 2025-11-19 15:51:02 +01:00
0cc78a7247 Port fat_io_lib, mount atasd0mp1 as sys: 2025-11-19 15:50:00 +01:00
5d77974586 Don't clean up backing storedev on mountpoint cleanup 2025-11-19 01:20:18 +01:00
ae6f5d9df0 Fix int8_t cast in sys_ipc_mbusconsume() 2025-11-19 00:13:17 +01:00
ecfe1a7eae Detect ATA driver via PCI 2025-11-18 23:28:45 +01:00
88f9d0e3d4 Spinlock fix small race window 2025-11-18 23:28:11 +01:00
28c95303e9 Fix PIC, add small delays when initializing 2025-11-18 23:27:49 +01:00
638214a0e2 rename ps2kb_intr() to ps2kbdev_keycode() 2025-11-18 21:59:49 +01:00
4fb5448dd9 Change order of sending EOI to PIC, works with -enable-kvm now 2025-11-18 16:56:28 +01:00
2a0dddead3 Fix interrupts not working with -enable-kvm 2025-11-18 14:20:46 +01:00
edcdaa5c60 List PCI devices 2025-11-17 04:43:41 +01:00
77b5a4a153 Modularize interrupt handlers, split up scheduler and PIT interrupt handlers 2025-11-17 01:08:23 +01:00
f2b7c5da57 Avoid deadlock in proc_killself() 2025-11-17 00:52:25 +01:00
58a47edc79 Shorter ata driver and partition dev names 2025-11-16 00:08:31 +01:00
0a43ba36cd Reduce binary sizes for the kernel and userspace apps 2025-11-15 23:56:16 +01:00
e66fe4030d tb Implement "#" comments 2025-11-15 22:25:41 +01:00
55b58bbe22 tb Fix runtime being initialized on every interp_runstring() exec, which causes memory leaks 2025-11-15 22:20:45 +01:00
bc53f9746e Fix mbus skipping other consumers in ipc_mbusconsume() 2025-11-15 01:46:46 +01:00
d7059ac4e3 Fix term_getsizes(), return proper char count 2025-11-15 01:46:17 +01:00
af27592957 tb Print colorful shell prompt and logged cmds, print terminal W/H 2025-11-15 00:58:40 +01:00
7da422fdb6 ulib Add term_getsizes() syscall 2025-11-15 00:58:09 +01:00
871c9cf439 Remove fbdev, add term_getsizes() syscall to get terminal width+height 2025-11-15 00:57:53 +01:00
cf4a6b23c7 init Move to term_XXX() interface 2025-11-15 00:39:27 +01:00
71fa87d7a4 ulib term_write() syscall 2025-11-15 00:39:04 +01:00
ecee481b33 Reimplement the terminal user access via separate syscalls 2025-11-15 00:38:54 +01:00
3726cc49da New font 2025-11-15 00:26:55 +01:00
ef7a45e7cf Remove ps2kbdev dev functions in favour of MBus 2025-11-11 23:50:24 +01:00
a530304e18 tb Use ps2kb MBus to handle C-S 2025-11-11 23:49:51 +01:00
f8863d19bd tb Use MBus for keyboard handling 2025-11-11 23:45:10 +01:00
f9d3fde4ad ulib Add MBus syscalls 2025-11-11 23:44:55 +01:00
c2364fbd48 Add MBus syscalls 2025-11-11 23:44:43 +01:00
4fe907a733 Clean up PS/2 keyboard driver, new IPC mechanism MBus (message bus) 2025-11-11 23:10:38 +01:00
07fc8a5562 Remove sched_ticks, move proc_reaper() out to proc_tick() function 2025-11-11 22:07:58 +01:00
5bd6ca0fa7 Remove extconf and KPRINTF_COLORS 2025-11-11 21:31:17 +01:00
7256fcd818 Prefix backtrace() with intr_ 2025-11-11 21:28:54 +01:00
51e89c8603 Remove atomic.h 2025-11-11 21:27:47 +01:00
566b35f4d5 Big code refactor, get rid of HAL entirely 2025-11-11 21:26:27 +01:00
7015bc9576 Decouple I/O from HAL 2025-11-11 19:59:01 +01:00
344952fb5f Move string functions/utils from HAL to std/string 2025-11-11 19:54:09 +01:00
f5dae4984d Rename base.img.6pack to base.img.6pk 2025-11-11 01:49:49 +01:00
8fc99a5fb1 init Remove useless ref to ps2kbdev device 2025-11-11 01:23:44 +01:00
91ecc2dc6a Break when IpcPipe is full 2025-11-11 00:51:29 +01:00
1f793f287f Clean up kernel/proc, remove devs_spinlock, remove PROC_DIE() macro 2025-11-11 00:32:09 +01:00
44893aeeb0 tb Fix minor leak in 'do' builtin function (ufree args1) 2025-11-10 20:44:54 +01:00
26e5d92947 Use hal_memcpy to propagate new proc interrupt frame 2025-11-10 20:25:55 +01:00
d81d1133dd diagdummy Test concurrent openfs 2025-11-10 20:23:28 +01:00
7e3b162591 Protect busy VfsObjs during opening and deleting 2025-11-10 20:23:03 +01:00
a349154545 ulib Fix uninitialized variables 2025-11-10 18:49:08 +01:00
1f93e8db13 Reduce proc stack size to 1M 2025-11-10 18:48:47 +01:00
81015d600b ulib Non-partitioned umalloc implementation 2025-11-10 18:36:27 +01:00
5c02d4d44a Fix distingishing kernel/user mode cpu exceptions 2025-11-10 18:35:46 +01:00
efaddb970a Remove useless path fiels in VfsObj 2025-11-10 18:19:17 +01:00
f4dbe830db Use FAT16/20iMB for boot partition 2025-11-10 14:16:58 +01:00
6da93cd854 fs Fix bug, check if fs_read() returned < 0 2025-11-09 23:06:18 +01:00
4084336705 ulib Add umallocbig() and ufreebig() for non-fragmented allocations 2025-11-09 22:21:19 +01:00
02d60129b1 Compress base.img using FastLZ library 2025-11-09 21:38:27 +01:00
e4a5c07b3d Change proc state under held spinlock 2025-11-08 21:40:15 +01:00
e0162e9e0b Add dev_delhandle() syscall to delete a device handle from process resources 2025-11-08 16:24:04 +01:00
2fa77d073f Only allow absolute paths 2025-11-06 21:58:24 +01:00
f3fcc92991 README.md add screenshots 2025-11-04 00:53:16 +01:00
0ed10b019a static Add screenshots 2025-11-04 00:51:24 +01:00
da72450d2a add README.md 2025-11-04 00:42:54 +01:00
771bbd1e9a fs lsmount subcommand for listing VFS mountpoint info 2025-11-04 00:25:57 +01:00
95e5d17018 ulib Add vfsavailmounts() and vfsmountstat() 2025-11-04 00:25:24 +01:00
88ac5cf877 New syscalls vfsavailmounts() and vfsmountstat() to get info about current VFS mountpoints 2025-11-04 00:24:58 +01:00
9612e7961e No networking for now 2025-11-02 18:31:51 +01:00
0f93aa2a81 Implement schedsleep() syscall to sleep a process for a given time 2025-11-02 16:46:37 +01:00
179c4b98e2 Only one fb-terminal-based putchar_() 2025-11-02 14:16:10 +01:00
690 changed files with 13612 additions and 236102 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
*.iso *.iso
*.img *.img
*.hdd *.hdd
*.6pk

19
FastLZ/.editorconfig Normal file
View File

@ -0,0 +1,19 @@
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
trim_trailing_whitespace = true
end_of_line = lf
insert_final_newline = true
[*.{c,h}]
indent_size = 2
indent_style = space
[Makefile]
indent_style = tab
[Makefile.win]
indent_style = tab

View File

@ -0,0 +1,32 @@
name: amd64_linux_clang
on: [push, pull_request]
jobs:
amd64_linux_clang:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: clang
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt install -y make clang
- run: clang --version
- run: cd tests && make roundtrip
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,32 @@
name: amd64_linux_gcc
on: [push, pull_request]
jobs:
amd64_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt install -y make gcc
- run: gcc --version
- run: cd tests && make roundtrip
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,32 @@
name: amd64_linux_tcc
on: [push, pull_request]
jobs:
amd64_linux_tcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: tcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt install -y make tcc
- run: tcc -v
- run: cd tests && make roundtrip
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,29 @@
name: amd64_macos_clang
on: [push, pull_request]
jobs:
amd64_macos_clang:
runs-on: macos-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: cc --version
- run: cd tests && make roundtrip
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,32 @@
name: amd64_macos_gcc
on: [push, pull_request]
jobs:
amd64_macos_gcc:
runs-on: macos-12
timeout-minutes: 10
env:
CC: gcc-9
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: brew install gcc@9
- run: gcc-9 --version
- run: cd tests && make roundtrip
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,34 @@
name: amd64_windows_clang
on: [push, pull_request]
jobs:
amd64_windows_clang:
runs-on: windows-2019
timeout-minutes: 10
env:
CC: clang
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- uses: msys2/setup-msys2@v2
with:
install: make mingw-w64-x86_64-clang
- run: clang --version
- run: cd tests && make roundtrip
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,34 @@
name: amd64_windows_gcc
on: [push, pull_request]
jobs:
amd64_windows_gcc:
runs-on: windows-2019
timeout-minutes: 10
env:
CC: gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- uses: msys2/setup-msys2@v2
with:
install: gcc make
- run: gcc --version
- run: cd tests && make roundtrip
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,35 @@
name: amd64_windows_tcc
on: [push, pull_request]
jobs:
amd64_windows_tcc:
runs-on: windows-2019
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- name: Install tcc
run: |
echo "5a3979bd5044b795547a4948a5625a12 tcc.zip" > checksum.md5
dos2unix checksum.md5
curl -L -o tcc.zip https://archive.org/download/tinyccompiler/tcc-0.9.27-win32-bin.zip
md5sum -c checksum.md5 && unzip -q tcc.zip
- run: tcc\x86_64-win32-tcc.exe -v
- run: cd tests && make roundtrip CC=..\tcc\x86_64-win32-tcc.exe
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make CC=..\tcc\x86_64-win32-tcc.exe
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,30 @@
name: amd64_windows_vs2019
on: [push, pull_request]
jobs:
amd64_windows_vs2019:
runs-on: windows-2019
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- uses: ilammy/msvc-dev-cmd@v1
- run: cl
- run: cd tests && mingw32-make -f Makefile.win roundtrip
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make -f Makefile.win
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: arm64_linux_gcc
on: [push, pull_request]
jobs:
arm64_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/aarch64-linux-musl-cross/bin/aarch64-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/aarch64-linux-musl-cross.tgz
tar xzf aarch64-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/aarch64-linux-musl-cross/bin/aarch64-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-aarch64 ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-aarch64 ./6pack -v
qemu-aarch64 ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-aarch64 ./6unpack -v
qemu-aarch64 ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: armhf_linux_gcc
on: [push, pull_request]
jobs:
armhf_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/armel-linux-musleabihf-cross/bin/armel-linux-musleabihf-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O https://musl.cc/armel-linux-musleabihf-cross.tgz
tar xzf armel-linux-musleabihf-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/armel-linux-musleabihf-cross/bin/armel-linux-musleabihf-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-arm ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-arm ./6pack -v
qemu-arm ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-arm ./6unpack -v
qemu-arm ./6unpack archive.6pk

29
FastLZ/.github/workflows/asan.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: Address Sanitizer
on: [push, pull_request]
jobs:
asan:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt install -y make gcc
- run: gcc --version
- run: cd tests && make roundtrip
name: Perform round-trip tests
env:
CFLAGS: "-g -fno-omit-frame-pointer -fsanitize=address"
- run: cd tests && make roundtrip
name: Perform round-trip tests with FASTLZ_USE_MEMMOVE=0
env:
CFLAGS: "-g -fno-omit-frame-pointer -fsanitize=address -DFASTLZ_USE_MEMMOVE=0"

19
FastLZ/.github/workflows/codestyle.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: Code style
on: [push, pull_request]
jobs:
codestyle:
runs-on: ubuntu-20.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- run: sudo apt install -y clang-format-6.0
name: Install clang-format
- run: clang-format-6.0 --version
- run: bash tools/format-code.sh
name: Run code formatter
- run: git diff
- run: git diff --quiet HEAD
name: Check if the styling guide is followed

View File

@ -0,0 +1,52 @@
name: i586_dos_gcc_cross
on: [push, pull_request]
jobs:
i586_dos_gcc_cross:
runs-on: ubuntu-20.04
timeout-minutes: 15
env:
CC: /opt/djgpp/bin/i586-pc-msdosdjgpp-gcc
LDFLAGS: -static
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- name: Prepare cross-compiler
run: |
curl -OL https://github.com/andrewwutw/build-djgpp/releases/download/v3.3/djgpp-linux64-gcc1210.tar.bz2
tar xf djgpp-linux64-gcc1210.tar.bz2 -C /opt
- name: Verify compiler version
run: /opt/djgpp/bin/i586-pc-msdosdjgpp-gcc --version
- name: Install DOSEMU2
run: |
sudo add-apt-repository -y ppa:dosemu2/ppa
sudo apt update -y
sudo apt install -y dosemu2
- run: dosemu --version
- name: Perform round-trip tests
run: |
cd tests
ln -s ../compression-corpus/ corpus
make test_roundtrip TEST_ROUNDTRIP=testrr
file ./testrr.exe
dosemu -dumb -K . -t -E "testrr corpus/"
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
ln -s ../compression-corpus/enwik/enwik8.txt enwik8.txt
make
file ./6pack.exe
dosemu -K . -t -E "6pack.exe -v"
dosemu -K . -t -E "6pack.exe enwik8.txt archive.6pk"
mv enwik8.txt enwik8.txt.orig
dosemu -K . -t -E "6unpack.exe -v"
dosemu -K . -t -E "6unpack.exe archive.6pk"
ls -l enwik8*

View File

@ -0,0 +1,36 @@
name: i686_linux_clang
on: [push, pull_request]
jobs:
i686_linux_clang:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: clang
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y make clang gcc-multilib qemu-user
- run: clang --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS="-static -m32"
file ./test_roundtrip
qemu-i386 ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS="-static -m32"
qemu-i386 ./6pack -v
qemu-i386 ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-i386 ./6unpack -v
qemu-i386 ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: i686_linux_gcc
on: [push, pull_request]
jobs:
i686_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/i686-linux-musl-cross/bin/i686-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O https://musl.cc/i686-linux-musl-cross.tgz
tar xzf i686-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/i686-linux-musl-cross/bin/i686-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-i386 ./test_roundtrip
- name: 'Build and run examples: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-i386 ./6pack -v
qemu-i386 ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-i386 ./6unpack -v
qemu-i386 ./6unpack archive.6pk

View File

@ -0,0 +1,35 @@
name: i686_windows_tcc
on: [push, pull_request]
jobs:
i686_windows_tcc:
runs-on: windows-2019
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- name: Install tcc
run: |
echo "D73CF66CEC8C761DE38C7A3D16C9EB0D tcc.zip" > checksum.md5
dos2unix checksum.md5
curl -L -o tcc.zip https://archive.org/download/tinyccompiler/tcc-0.9.27-win64-bin.zip
md5sum -c checksum.md5 && unzip -q tcc.zip
- run: tcc\i386-win32-tcc.exe -v
- run: cd tests && make roundtrip CC=..\tcc\i386-win32-tcc.exe
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make CC=..\tcc\i386-win32-tcc.exe
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,32 @@
name: i686_windows_vs2019
on: [push, pull_request]
jobs:
i686_windows_vs2019:
runs-on: windows-2019
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: x86
- run: cl
- run: cd tests && mingw32-make -f Makefile.win roundtrip
name: Perform round-trip tests
- name: 'Build examples: 6pack and 6unpack'
run: cd examples && make -f Makefile.win
- name: 'Run examples: 6pack and 6unpack'
run: |
cd examples
./6pack -v
./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
./6unpack -v
./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: mips64_linux_gcc
on: [push, pull_request]
jobs:
mips64_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/mips64-linux-musl-cross/bin/mips64-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/mips64-linux-musl-cross.tgz
tar xzf mips64-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/mips64-linux-musl-cross/bin/mips64-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-mips64 ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-mips64 ./6pack -v
qemu-mips64 ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-mips64 ./6unpack -v
qemu-mips64 ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: mips64el_linux_gcc
on: [push, pull_request]
jobs:
mips64el_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/mips64el-linux-musl-cross/bin/mips64el-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/mips64el-linux-musl-cross.tgz
tar xzf mips64el-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/mips64el-linux-musl-cross/bin/mips64el-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-mips64el ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-mips64el ./6pack -v
qemu-mips64el ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-mips64el ./6unpack -v
qemu-mips64el ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: mips_linux_gcc
on: [push, pull_request]
jobs:
mips_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/mips-linux-musl-cross/bin/mips-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/mips-linux-musl-cross.tgz
tar xzf mips-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/mips-linux-musl-cross/bin/mips-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-mips ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-mips ./6pack -v
qemu-mips ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-mips ./6unpack -v
qemu-mips ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: mipsel_linux_gcc
on: [push, pull_request]
jobs:
mipsel_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/mipsel-linux-musl-cross/bin/mipsel-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/mipsel-linux-musl-cross.tgz
tar xzf mipsel-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/mipsel-linux-musl-cross/bin/mipsel-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-mipsel ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-mipsel ./6pack -v
qemu-mipsel ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-mipsel ./6unpack -v
qemu-mipsel ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: powerpc_linux_gcc
on: [push, pull_request]
jobs:
powerpc_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/powerpc-linux-musl-cross/bin/powerpc-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/powerpc-linux-musl-cross.tgz
tar xzf powerpc-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/powerpc-linux-musl-cross/bin/powerpc-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-ppc ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-ppc ./6pack -v
qemu-ppc ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-ppc ./6unpack -v
qemu-ppc ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: ppc64_linux_gcc
on: [push, pull_request]
jobs:
ppc64_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/powerpc64-linux-musl-cross/bin/powerpc64-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/powerpc64-linux-musl-cross.tgz
tar xzf powerpc64-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/powerpc64-linux-musl-cross/bin/powerpc64-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-ppc64 ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-ppc64 ./6pack -v
qemu-ppc64 ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-ppc64 ./6unpack -v
qemu-ppc64 ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: ppc64le_linux_gcc
on: [push, pull_request]
jobs:
ppc64le_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/powerpc64le-linux-musl-cross/bin/powerpc64le-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/powerpc64le-linux-musl-cross.tgz
tar xzf powerpc64le-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/powerpc64le-linux-musl-cross/bin/powerpc64le-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-ppc64le ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-ppc64le ./6pack -v
qemu-ppc64le ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-ppc64le ./6unpack -v
qemu-ppc64le ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: riscv64_linux_gcc
on: [push, pull_request]
jobs:
riscv64_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/riscv64-linux-musl-cross/bin/riscv64-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/riscv64-linux-musl-cross.tgz
tar xzf riscv64-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/riscv64-linux-musl-cross/bin/riscv64-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-riscv64 ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-riscv64 ./6pack -v
qemu-riscv64 ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-riscv64 ./6unpack -v
qemu-riscv64 ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: riscv_linux_gcc
on: [push, pull_request]
jobs:
riscv_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/riscv32-linux-musl-cross/bin/riscv32-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/riscv32-linux-musl-cross.tgz
tar xzf riscv32-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/riscv32-linux-musl-cross/bin/riscv32-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-riscv32 ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-riscv32 ./6pack -v
qemu-riscv32 ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-riscv32 ./6unpack -v
qemu-riscv32 ./6unpack archive.6pk

View File

@ -0,0 +1,41 @@
name: s390x_linux_gcc
on: [push, pull_request]
jobs:
s390x_linux_gcc:
runs-on: ubuntu-20.04
timeout-minutes: 10
env:
CC: /opt/s390x-linux-musl-cross/bin/s390x-linux-musl-gcc
steps:
- uses: actions/checkout@v3
- name: Retrieve test compression corpus
run: |
git clone https://github.com/ariya/compression-corpus.git
cd compression-corpus
cd enwik
unzip enwik8.zip
- run: sudo apt-get -y -qq update
- run: sudo apt install -y qemu-user
- name: Prepare cross-compiler
run: |
curl -O http://musl.cc/s390x-linux-musl-cross.tgz
tar xzf s390x-linux-musl-cross.tgz -C /opt
- name: Verify compiler version
run: /opt/s390x-linux-musl-cross/bin/s390x-linux-musl-gcc --version
- name: Perform round-trip tests
run: |
cd tests
make test_roundtrip CFLAGS=-static
file ./test_roundtrip
qemu-s390x ./test_roundtrip
- name: 'Build and run example: 6pack and 6unpack'
run: |
cd examples
make CFLAGS=-static
qemu-s390x ./6pack -v
qemu-s390x ./6pack ../compression-corpus/enwik/enwik8.txt archive.6pk
qemu-s390x ./6unpack -v
qemu-s390x ./6unpack archive.6pk

1
FastLZ/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.o

3
FastLZ/.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "compression-corpus"]
path = compression-corpus
url = https://github.com/ariya/compression-corpus.git

8
FastLZ/ChangeLog Normal file
View File

@ -0,0 +1,8 @@
2020-02-02: Version 0.5.0
Minor speed improvement on the decompressor.
Prevent memory violation when decompressing corrupted input.
2020-01-10: Version 0.4.0
Only code & infrastructure clean-up, no new functionality.

21
FastLZ/LICENSE.MIT Normal file
View File

@ -0,0 +1,21 @@
FastLZ - Byte-aligned LZ77 compression library
Copyright (C) 2005-2020 Ariya Hidayat <ariya.hidayat@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

207
FastLZ/README.md Normal file
View File

@ -0,0 +1,207 @@
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Code style](https://github.com/ariya/fastlz/workflows/Code%20style/badge.svg)](https://github.com/ariya/fastlz/actions)
[![Address Sanitizer](https://github.com/ariya/fastlz/workflows/Address%20Sanitizer/badge.svg)](https://github.com/ariya/fastlz/actions)
## Overview
FastLZ (MIT license) is an ANSI C/C90 implementation of [Lempel-Ziv 77 algorithm](https://en.wikipedia.org/wiki/LZ77_and_LZ78#LZ77) (LZ77) of lossless data compression. It is suitable to compress series of text/paragraphs, sequences of raw pixel data, or any other blocks of data with lots of repetition. It is not intended to be used on images, videos, and other formats of data typically already in an optimal compressed form.
The focus for FastLZ is a very fast compression and decompression, doing that at the cost of the compression ratio. As an illustration, the comparison with zlib when compressing [enwik8](http://www.mattmahoney.net/dc/textdata.html) (also in [more details](https://github.com/inikep/lzbench)):
||Ratio|Compression|Decompression
|--|--|--|--|
|FastLZ |54.2%|159 MB/s|305 MB/s|
|zlib -1|42.3%|50 MB/s|184 MB/s|
|zlib -9|36.5%|11 MB/s|185 MB/s|
FastLZ is used by many software products, from a number of games (such as [Death Stranding](https://en.wikipedia.org/wiki/Death_Stranding)) to various open-source projects ([Godot Engine](https://godotengine.org/), [Facebook HHVM](https://hhvm.com/), [Apache Traffic Server](https://trafficserver.apache.org/), [Calligra Office](https://www.calligra.org/), [OSv](http://osv.io/), [Netty](https://netty.io/), etc). It even serves as the basis for other compression projects like [BLOSC](https://blosc.org/).
For other implementations of byte-aligned LZ77, take a look at [LZ4](https://lz4.github.io/lz4/), [Snappy](http://google.github.io/snappy/), [Density](https://github.com/centaurean/density), [LZO](http://www.oberhumer.com/opensource/lzo/), [LZF](http://oldhome.schmorp.de/marc/liblzf.html), [LZJB](https://en.wikipedia.org/wiki/LZJB), [LZRW](http://www.ross.net/compression/lzrw1.html), etc.
## Usage
FastLZ can be used directly in any C/C++ applications. For other programming languages/environments, use the corresponding binding:
* [Rust](https://crates.io/crates/fastlz), available on Crates: `cargo install fastlz`
* [Python](https://pypi.org/project/fastlz/), available on PyPi: `pip install fastlz`
* [JavaScript](https://www.npmjs.com/package/fastlz), available on npm: `npm install fastlz`
* [Ruby](https://rubygems.org/gems/fastlz), available on Rubygems: `gem install fastlz`
* Lua via [github.com/oneoo/lua-fastlz](https://github.com/oneoo/lua-fastlz)
FastLZ consists of only two files: `fastlz.h` and `fastlz.c`. Just add these files to your project in order to use FastLZ. For the detailed information on the API to perform compression and decompression, see `fastlz.h`.
For [Vcpkg](https://github.com/microsoft/vcpkg) users, FastLZ is [already available](https://github.com/microsoft/vcpkg): `vcpkg install fastlz`.
A simple file compressor called `6pack` is included as an example on how to use FastLZ. The corresponding decompressor is `6unpack`.
FastLZ supports any standard-conforming ANSI C/C90 compiler, including the popular ones such as [GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/), [Visual Studio](https://visualstudio.microsoft.com/vs/features/cplusplus/), and even [Tiny CC](https://bellard.org/tcc/). FastLZ works well on a number of architectures (32-bit and 64-bit, big endian and little endian), from Intel/AMD, PowerPC, System z, ARM, MIPS, and RISC-V.
The continuous integration system runs an extensive set of compression-decompression round trips on the following systems:
For more details, check the corresponding [GitHub Actions build logs](https://github.com/ariya/FastLZ/actions).
| | | | |
|----------------------|--------------------------------------------------------------------------------------------------------:|--------------------------------------------------------------------------------------------------:|--------------------------------------------------------------------------------------------:|
| **amd64** | **Linux** | **Windows** | **macOS** |
| GCC | ![amd64_linux_gcc](https://github.com/ariya/FastLZ/workflows/amd64_linux_gcc/badge.svg) | ![amd64_windows_gcc](https://github.com/ariya/FastLZ/workflows/amd64_windows_gcc/badge.svg) | ![amd64_macos_gcc](https://github.com/ariya/FastLZ/workflows/amd64_macos_gcc/badge.svg) |
| Clang | ![amd64_linux_clang](https://github.com/ariya/FastLZ/workflows/amd64_linux_clang/badge.svg) | ![amd64_windows_clang](https://github.com/ariya/FastLZ/workflows/amd64_windows_clang/badge.svg) | ![amd64_macos_clang](https://github.com/ariya/FastLZ/workflows/amd64_macos_clang/badge.svg) |
| TinyCC | ![amd64_linux_tcc](https://github.com/ariya/FastLZ/workflows/amd64_linux_tcc/badge.svg) | ![amd64_windows_tcc](https://github.com/ariya/FastLZ/workflows/amd64_windows_tcc/badge.svg) | |
| VS 2019 | | ![amd64_windows_vs2019](https://github.com/ariya/FastLZ/workflows/amd64_windows_vs2019/badge.svg) | |
| **i686** | **Linux** | **Windows** | **macOS** |
| GCC | ![i686_linux_gcc](https://github.com/ariya/FastLZ/workflows/i686_linux_gcc/badge.svg) | | |
| Clang | ![i686_linux_clang](https://github.com/ariya/FastLZ/workflows/i686_linux_clang/badge.svg) | | |
| TinyCC | | ![i686_windows_tcc](https://github.com/ariya/FastLZ/workflows/i686_windows_tcc/badge.svg) | |
| VS 2019 | | ![i686_windows_vs2019](https://github.com/ariya/FastLZ/workflows/i686_windows_vs2019/badge.svg) | |
| **i586** | **Linux** | **DOS** | |
| GCC | | ![i586_dos_gcc_cross](https://github.com/ariya/FastLZ/workflows/i586_dos_gcc_cross/badge.svg) | |
| | **Linux** | | |
| **powerpc** | | | |
| GCC | ![powerpc_linux_gcc](https://github.com/ariya/FastLZ/workflows/powerpc_linux_gcc/badge.svg) | | |
| **ppc64(le)** | | | |
| GCC | ![ppc64_linux_gcc](https://github.com/ariya/FastLZ/workflows/ppc64_linux_gcc/badge.svg) | | |
| GCC | ![ppc64le_linux_gcc](https://github.com/ariya/FastLZ/workflows/ppc64le_linux_gcc/badge.svg) | | |
| **s390x** | | | |
| GCC | ![s390x_linux_gcc](https://github.com/ariya/FastLZ/workflows/s390x_linux_gcc/badge.svg) | | |
| **armhf** | | | |
| GCC | ![armhf_linux_gcc](https://github.com/ariya/FastLZ/workflows/armhf_linux_gcc/badge.svg) | | |
| **arm64** | | | |
| GCC | ![arm64_linux_gcc](https://github.com/ariya/FastLZ/workflows/arm64_linux_gcc/badge.svg) | | |
| **mips(el)** | | | |
| GCC | ![mipsel_linux_gcc](https://github.com/ariya/FastLZ/workflows/mipsel_linux_gcc/badge.svg) | | |
| GCC | ![mips_linux_gcc](https://github.com/ariya/FastLZ/workflows/mips_linux_gcc/badge.svg) | | |
| **mips64(el)** | | | |
| GCC | ![mips64el_linux_gcc](https://github.com/ariya/FastLZ/workflows/mips64el_linux_gcc/badge.svg) | | |
| GCC | ![mips64_linux_gcc](https://github.com/ariya/FastLZ/workflows/mips64_linux_gcc/badge.svg) | | |
| **riscv** | | | |
| GCC | ![riscv_linux_gcc](https://github.com/ariya/FastLZ/workflows/riscv_linux_gcc/badge.svg) | | |
| **riscv64** | | | |
| GCC | ![riscv64_linux_gcc](https://github.com/ariya/FastLZ/workflows/riscv64_linux_gcc/badge.svg) | | |
## Block Format
Let us assume that FastLZ compresses an array of bytes, called the _uncompressed block_, into another array of bytes, called the _compressed block_. To understand what will be stored in the compressed block, it is illustrative to demonstrate how FastLZ will _decompress_ the block to retrieve the original uncompressed block.
The first 3-bit of the block, i.e. the 3 most-significant bits of the first byte, is the **block tag**. Currently the block tag determines the compression level used to produce the compressed block.
|Block tag|Compression level|
|---------|-----------------|
| 0 | Level 1 |
| 1 | Level 2 |
The content of the block will vary depending on the compression level.
### Block Format for Level 1
FastLZ Level 1 implements LZ77 compression algorithm with 8 KB sliding window and up to 264 bytes of match length.
The compressed block consists of one or more **instructions**.
Each instruction starts with a 1-byte opcode, 2-byte opcode, or 3-byte opcode.
| Instruction type | Opcode[0] | Opcode[1] | Opcode[2]
|-----------|------------------|--------------------|--|
| Literal run | `000`, L&#x2084;-L&#x2080; | -|- |
| Short match | M&#x2082;-M&#x2080;, R&#x2081;&#x2082;-R&#x2088; | R&#x2087;-R&#x2080; | - |
| Long match | `111`, R&#x2081;&#x2082;-R&#x2088; | M&#x2087;-M&#x2080; | R&#x2087;-R&#x2080; |
Note that the _very first_ instruction in a compressed block is always a literal run.
#### Literal run instruction
For the literal run instruction, there is one or more bytes following the code. This is called the literal run.
The 5 least-significant bits of `opcode[0]`, _L_, determines the **number of literals** following the opcode. The value of 0 indicates a 1-byte literal run, 1 indicates a 2-byte literal run, and so on. The minimum literal run is 1 and the maximum literal run is 32.
The decompressor copies (_L + 1_) bytes of literal run, starting from the first one right after opcode.
_Example_: If the compressed block is a 4-byte array of `[0x02, 0x41, 0x42, 0x43]`, then the opcode is `0x02` and that means a literal run of 3 bytes. The decompressor will then copy the subsequent 3 bytes, `[0x41, 0x42, 0x43]`, to the output buffer. The output buffer now represents the (original) uncompressed block, `[0x41, 0x42, 0x43]`.
#### Short match instruction
The 3 most-significant bits of `opcode[0]`, _M_, determines the **match length**. The value of 1 indicates a 3-byte match, 2 indicates a 4-byte match and so on. The minimum match length is 3 and the maximum match length is 8.
The 5 least-significant bits of `opcode[0]` combined with the 8 bits of the `opcode[1]`, _R_, determines the **reference offset**. Since the offset is encoded in 13 bits, the minimum is 0 and the maximum is 8191.
The following C code retrieves the match length and reference offset:
```c
M = opcode[0] >> 5;
R = 256 * (opcode[0] << 5) + opcode[1];
```
The decompressor copies _(M+2)_ bytes, starting from the location offsetted by _R_ in the output buffer. Note that _R_ is a *back reference*, i.e. the value of 0 corresponds the last byte in the output buffer, 1 is the second to last byte, and so forth.
_Example 1_: If the compressed block is a 7-byte array of `[0x03, 0x41, 0x42, 0x43, 0x44, 0x20, 0x02]`, then there are two instructions in the there. The first instruction is the literal run of 4 bytes (due to _L = 3_). Thus, the decompressor copies 4 bytes to the output buffer, resulting in `[0x41, 0x42, 0x43, 0x44]`. The second instruction is the short match of 3 bytes (from _M = 1_, i.e `0x20 >> 5`) and the offset of 2. Therefore, the compressor goes back 2 bytes from the last position, copies 3 bytes (`[0x42, 0x43, 0x44]`), and appends them to the output buffer. The output buffer now represents the complete uncompressed data, `[0x41, 0x42, 0x43, 0x44, 0x42, 0x43, 0x44]`.
_Example 2_: If the compressed block is a 4-byte array of `[0x00, 0x61, 0x40, 0x00]`, then there are two instructions in there. The first instruction is the literal run of just 1 byte (_L = 0_). Thus, the decompressor copies the byte (`0x61`) to the output buffer. The output buffer now becomes `[0x61]`. The second instruction is the short match of 4 bytes (from _M = 2_, i.e. `0x40 >> 5`) and the offset of 0. Therefore, the decompressor copies 4 bytes starting using the back reference of 0 (i.e. the position of `0x61`). The output buffer now represents the complete uncompressed data, `[0x61, 0x61, 0x61, 0x61, 0x61]`.
#### Long match instruction
The value of `opcode[1]`, _M_, determines the **match length**. The value of 0 indicates a 9-byte match, 1 indicates a 10-byte match and so on. The minimum match length is 9 and the maximum match length is 264.
The 5 least-significant bits of `opcode[0]` combined with the 8 bits of `opcode[2]`, _R_, determines the **reference offset**. Since the offset is encoded in 13 bits, the minimum is 0 and the maximum is 8191.
The following C code retrieves the match length and reference offset:
```c
M = opcode[1];
R = 256 * (opcode[0] << 5) + opcode[2];
```
The decompressor copies _(M+9)_ bytes, starting from the location offsetted by _R_ in the output buffer. Note that _R_ is a *back reference*, i.e. the value of 0 corresponds to the last byte in the output buffer, 1 is for the second to last byte, and so forth.
_Example_: If the compressed block is a 4-byte array of `[0x01, 0x44, 0x45, 0xE0, 0x01, 0x01]`, then there are two instructions in there. The first instruction is the literal run with the length of 2 (due to _L = 1_). Thus, the decompressor copies the 2-byte literal run (`[0x44, 0x45]`) to the output buffer. The second instruction is the long match with the match length of 10 (from _M = 1_) and the offset of 1. Therefore, the decompressor copies 10 bytes starting using the back reference of 1 (i.e. the position of `0x44`). The output buffer now represents the complete uncompressed data, `[0x44, 0x45, 0x44, 0x45, 0x44, 0x45, 0x44, 0x45, 0x44, 0x45, 0x44, 0x45]`.
#### Decompressor Reference Implementation
The following 40-line C function implements a fully-functional decompressor for the above block format. Note that it is intended to be educational, e.g. no bound check is implemented, and therefore it is absolutely **unsafe** for production.
```c
void fastlz_level1_decompress(const uint8_t* input, int length, uint8_t* output) {
int src = 0;
int dest = 0;
while (src < length) {
int type = input[src] >> 5;
if (type == 0) {
/* literal run */
int run = 1 + input[src];
src = src + 1;
while (run > 0) {
output[dest] = input[src];
src = src + 1;
dest = dest + 1;
run = run - 1;
}
} else if (type < 7) {
/* short match */
int ofs = 256 * (input[src] & 31) + input[src + 1];
int len = 2 + (input[src] >> 5);
src = src + 2;
int ref = dest - ofs - 1;
while (len > 0) {
output[dest] = output[ref];
ref = ref + 1;
dest = dest + 1;
len = len - 1;
}
} else {
/* long match */
int ofs = 256 * (input[src] & 31) + input[src + 2];
int len = 9 + input[src + 1];
src = src + 3;
int ref = dest - ofs - 1;
while (len > 0) {
output[dest] = output[ref];
ref = ref + 1;
dest = dest + 1;
len = len - 1;
}
}
}
}
```
### Block Format for Level 2
(To be written)

1
FastLZ/_config.yml Normal file
View File

@ -0,0 +1 @@
theme: jekyll-theme-tactile

2
FastLZ/examples/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
6pack
6unpack

586
FastLZ/examples/6pack.c Normal file
View File

@ -0,0 +1,586 @@
/*
6PACK - file compressor using FastLZ (lightning-fast compression library)
Copyright (C) 2007-2020 Ariya Hidayat <ariya.hidayat@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIXPACK_VERSION_MAJOR 0
#define SIXPACK_VERSION_MINOR 1
#define SIXPACK_VERSION_REVISION 0
#define SIXPACK_VERSION_STRING "snapshot 20070615"
#include "fastlz.h"
#undef PATH_SEPARATOR
#if defined(MSDOS) || defined(__MSDOS__) || defined(MSDOS)
#define PATH_SEPARATOR '\\'
#endif
#if defined(WIN32) || defined(__NT__) || defined(_WIN32) || defined(__WIN32__)
#define PATH_SEPARATOR '\\'
#endif
#ifndef PATH_SEPARATOR
#define PATH_SEPARATOR '/'
#endif
#undef SIXPACK_BENCHMARK_WIN32
#if defined(WIN32) || defined(__NT__) || defined(_WIN32) || defined(__WIN32__)
#if defined(_MSC_VER) || defined(__GNUC__)
#define SIXPACK_BENCHMARK_WIN32
#include <windows.h>
#endif
#endif
/* magic identifier for 6pack file */
static unsigned char sixpack_magic[8] = {137, '6', 'P', 'K', 13, 10, 26, 10};
#define BLOCK_SIZE (2 * 64 * 1024)
/* prototypes */
static unsigned long update_adler32(unsigned long checksum, const void* buf, int len);
void usage(void);
int detect_magic(FILE* f);
void write_magic(FILE* f);
void write_chunk_header(FILE* f, int id, int options, unsigned long size, unsigned long checksum, unsigned long extra);
unsigned long block_compress(const unsigned char* input, unsigned long length, unsigned char* output);
int pack_file_compressed(const char* input_file, int method, int level, FILE* f);
int pack_file(int compress_level, const char* input_file, const char* output_file);
/* for Adler-32 checksum algorithm, see RFC 1950 Section 8.2 */
#define ADLER32_BASE 65521
static unsigned long update_adler32(unsigned long checksum, const void* buf, int len) {
const unsigned char* ptr = (const unsigned char*)buf;
unsigned long s1 = checksum & 0xffff;
unsigned long s2 = (checksum >> 16) & 0xffff;
while (len > 0) {
unsigned k = len < 5552 ? len : 5552;
len -= k;
while (k >= 8) {
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
k -= 8;
}
while (k-- > 0) {
s1 += *ptr++;
s2 += s1;
}
s1 = s1 % ADLER32_BASE;
s2 = s2 % ADLER32_BASE;
}
return (s2 << 16) + s1;
}
void usage(void) {
printf("6pack: high-speed file compression tool\n");
printf("Copyright (C) Ariya Hidayat\n");
printf("\n");
printf("Usage: 6pack [options] input-file output-file\n");
printf("\n");
printf("Options:\n");
printf(" -1 compress faster\n");
printf(" -2 compress better\n");
printf(" -v show program version\n");
#ifdef SIXPACK_BENCHMARK_WIN32
printf(" -mem check in-memory compression speed\n");
#endif
printf("\n");
}
/* return non-zero if magic sequence is detected */
/* warning: reset the read pointer to the beginning of the file */
int detect_magic(FILE* f) {
unsigned char buffer[8];
size_t bytes_read;
int c;
fseek(f, SEEK_SET, 0);
bytes_read = fread(buffer, 1, 8, f);
fseek(f, SEEK_SET, 0);
if (bytes_read < 8) return 0;
for (c = 0; c < 8; c++)
if (buffer[c] != sixpack_magic[c]) return 0;
return -1;
}
void write_magic(FILE* f) { fwrite(sixpack_magic, 8, 1, f); }
void write_chunk_header(FILE* f, int id, int options, unsigned long size, unsigned long checksum, unsigned long extra) {
unsigned char buffer[16];
buffer[0] = id & 255;
buffer[1] = id >> 8;
buffer[2] = options & 255;
buffer[3] = options >> 8;
buffer[4] = size & 255;
buffer[5] = (size >> 8) & 255;
buffer[6] = (size >> 16) & 255;
buffer[7] = (size >> 24) & 255;
buffer[8] = checksum & 255;
buffer[9] = (checksum >> 8) & 255;
buffer[10] = (checksum >> 16) & 255;
buffer[11] = (checksum >> 24) & 255;
buffer[12] = extra & 255;
buffer[13] = (extra >> 8) & 255;
buffer[14] = (extra >> 16) & 255;
buffer[15] = (extra >> 24) & 255;
fwrite(buffer, 16, 1, f);
}
int pack_file_compressed(const char* input_file, int method, int level, FILE* f) {
FILE* in;
unsigned long fsize;
unsigned long checksum;
const char* shown_name;
unsigned char buffer[BLOCK_SIZE];
unsigned char result[BLOCK_SIZE * 2]; /* FIXME twice is too large */
unsigned char progress[20];
int c;
unsigned long percent;
unsigned long total_read;
unsigned long total_compressed;
int chunk_size;
/* sanity check */
in = fopen(input_file, "rb");
if (!in) {
printf("Error: could not open %s\n", input_file);
return -1;
}
/* find size of the file */
fseek(in, 0, SEEK_END);
fsize = ftell(in);
fseek(in, 0, SEEK_SET);
/* already a 6pack archive? */
if (detect_magic(in)) {
printf("Error: file %s is already a 6pack archive!\n", input_file);
fclose(in);
return -1;
}
/* truncate directory prefix, e.g. "foo/bar/FILE.txt" becomes "FILE.txt" */
shown_name = input_file + strlen(input_file) - 1;
while (shown_name > input_file)
if (*(shown_name - 1) == PATH_SEPARATOR)
break;
else
shown_name--;
/* chunk for File Entry */
buffer[0] = fsize & 255;
buffer[1] = (fsize >> 8) & 255;
buffer[2] = (fsize >> 16) & 255;
buffer[3] = (fsize >> 24) & 255;
#if 0
buffer[4] = (fsize >> 32) & 255;
buffer[5] = (fsize >> 40) & 255;
buffer[6] = (fsize >> 48) & 255;
buffer[7] = (fsize >> 56) & 255;
#else
/* because fsize is only 32-bit */
buffer[4] = 0;
buffer[5] = 0;
buffer[6] = 0;
buffer[7] = 0;
#endif
buffer[8] = (strlen(shown_name) + 1) & 255;
buffer[9] = (strlen(shown_name) + 1) >> 8;
checksum = 1L;
checksum = update_adler32(checksum, buffer, 10);
checksum = update_adler32(checksum, shown_name, strlen(shown_name) + 1);
write_chunk_header(f, 1, 0, 10 + strlen(shown_name) + 1, checksum, 0);
fwrite(buffer, 10, 1, f);
fwrite(shown_name, strlen(shown_name) + 1, 1, f);
total_compressed = 16 + 10 + strlen(shown_name) + 1;
/* for progress status */
memset(progress, ' ', 20);
if (strlen(shown_name) < 16)
for (c = 0; c < (int)strlen(shown_name); c++) progress[c] = shown_name[c];
else {
for (c = 0; c < 13; c++) progress[c] = shown_name[c];
progress[13] = '.';
progress[14] = '.';
progress[15] = ' ';
}
progress[16] = '[';
progress[17] = 0;
printf("%s", progress);
for (c = 0; c < 50; c++) printf(".");
printf("]\r");
printf("%s", progress);
/* read file and place in archive */
total_read = 0;
percent = 0;
for (;;) {
int compress_method = method;
int last_percent = (int)percent;
size_t bytes_read = fread(buffer, 1, BLOCK_SIZE, in);
if (bytes_read == 0) break;
total_read += bytes_read;
/* for progress */
if (fsize < (1 << 24))
percent = total_read * 100 / fsize;
else
percent = total_read / 256 * 100 / (fsize >> 8);
percent >>= 1;
while (last_percent < (int)percent) {
printf("#");
last_percent++;
}
/* too small, don't bother to compress */
if (bytes_read < 32) compress_method = 0;
/* write to output */
switch (compress_method) {
/* FastLZ */
case 1:
chunk_size = fastlz_compress_level(level, buffer, bytes_read, result);
checksum = update_adler32(1L, result, chunk_size);
write_chunk_header(f, 17, 1, chunk_size, checksum, bytes_read);
fwrite(result, 1, chunk_size, f);
total_compressed += 16;
total_compressed += chunk_size;
break;
/* uncompressed, also fallback method */
case 0:
default:
checksum = 1L;
checksum = update_adler32(checksum, buffer, bytes_read);
write_chunk_header(f, 17, 0, bytes_read, checksum, bytes_read);
fwrite(buffer, 1, bytes_read, f);
total_compressed += 16;
total_compressed += bytes_read;
break;
}
}
fclose(in);
if (total_read != fsize) {
printf("\n");
printf("Error: reading %s failed!\n", input_file);
return -1;
} else {
printf("] ");
if (total_compressed < fsize) {
if (fsize < (1 << 20))
percent = total_compressed * 1000 / fsize;
else
percent = total_compressed / 256 * 1000 / (fsize >> 8);
percent = 1000 - percent;
printf("%2d.%d%% saved", (int)percent / 10, (int)percent % 10);
}
printf("\n");
}
return 0;
}
int pack_file(int compress_level, const char* input_file, const char* output_file) {
FILE* f;
int result;
f = fopen(output_file, "rb");
if (f) {
fclose(f);
printf("Error: file %s already exists. Aborted.\n\n", output_file);
return -1;
}
f = fopen(output_file, "wb");
if (!f) {
printf("Error: could not create %s. Aborted.\n\n", output_file);
return -1;
}
write_magic(f);
result = pack_file_compressed(input_file, 1, compress_level, f);
fclose(f);
return result;
}
#ifdef SIXPACK_BENCHMARK_WIN32
int benchmark_speed(int compress_level, const char* input_file);
int benchmark_speed(int compress_level, const char* input_file) {
FILE* in;
unsigned long fsize;
unsigned long maxout;
const char* shown_name;
unsigned char* buffer;
unsigned char* result;
size_t bytes_read;
/* sanity check */
in = fopen(input_file, "rb");
if (!in) {
printf("Error: could not open %s\n", input_file);
return -1;
}
/* find size of the file */
fseek(in, 0, SEEK_END);
fsize = ftell(in);
fseek(in, 0, SEEK_SET);
/* already a 6pack archive? */
if (detect_magic(in)) {
printf("Error: no benchmark for 6pack archive!\n");
fclose(in);
return -1;
}
/* truncate directory prefix, e.g. "foo/bar/FILE.txt" becomes "FILE.txt" */
shown_name = input_file + strlen(input_file) - 1;
while (shown_name > input_file)
if (*(shown_name - 1) == PATH_SEPARATOR)
break;
else
shown_name--;
maxout = 1.05 * fsize;
maxout = (maxout < 66) ? 66 : maxout;
buffer = (unsigned char*)malloc(fsize);
result = (unsigned char*)malloc(maxout);
if (!buffer || !result) {
printf("Error: not enough memory!\n");
free(buffer);
free(result);
fclose(in);
return -1;
}
printf("Reading source file....\n");
bytes_read = fread(buffer, 1, fsize, in);
if (bytes_read != fsize) {
printf("Error reading file %s!\n", shown_name);
printf("Read %d bytes, expecting %d bytes\n", bytes_read, fsize);
free(buffer);
free(result);
fclose(in);
return -1;
}
/* shamelessly copied from QuickLZ 1.20 test program */
{
unsigned int j, y;
size_t i, u = 0;
double mbs, fastest;
unsigned long compressed_size;
printf("Setting HIGH_PRIORITY_CLASS...\n");
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
printf("Benchmarking FastLZ Level %d, please wait...\n", compress_level);
i = bytes_read;
fastest = 0.0;
for (j = 0; j < 3; j++) {
y = 0;
mbs = GetTickCount();
while (GetTickCount() == mbs)
;
mbs = GetTickCount();
while (GetTickCount() - mbs < 3000) /* 1% accuracy with 18.2 timer */
{
u = fastlz_compress_level(compress_level, buffer, bytes_read, result);
y++;
}
mbs = ((double)i * (double)y) / ((double)(GetTickCount() - mbs) / 1000.) / 1000000.;
/*printf(" %.1f Mbyte/s ", mbs);*/
if (fastest < mbs) fastest = mbs;
}
printf("\nCompressed %d bytes into %d bytes (%.1f%%) at %.1f Mbyte/s.\n", (unsigned int)i, (unsigned int)u,
(double)u / (double)i * 100., fastest);
#if 1
fastest = 0.0;
compressed_size = u;
for (j = 0; j < 3; j++) {
y = 0;
mbs = GetTickCount();
while (GetTickCount() == mbs)
;
mbs = GetTickCount();
while (GetTickCount() - mbs < 3000) /* 1% accuracy with 18.2 timer */
{
u = fastlz_decompress(result, compressed_size, buffer, bytes_read);
y++;
}
mbs = ((double)i * (double)y) / ((double)(GetTickCount() - mbs) / 1000.) / 1000000.;
/*printf(" %.1f Mbyte/s ", mbs);*/
if (fastest < mbs) fastest = mbs;
}
printf("\nDecompressed at %.1f Mbyte/s.\n\n(1 MB = 1000000 byte)\n", fastest);
#endif
}
fclose(in);
return 0;
}
#endif /* SIXPACK_BENCHMARK_WIN32 */
int main(int argc, char** argv) {
int i;
int compress_level;
int benchmark;
char* input_file;
char* output_file;
/* show help with no argument at all*/
if (argc == 1) {
usage();
return 0;
}
/* default compression level, not the fastest */
compress_level = 2;
/* do benchmark only when explicitly specified */
benchmark = 0;
/* no file is specified */
input_file = 0;
output_file = 0;
for (i = 1; i <= argc; i++) {
char* argument = argv[i];
if (!argument) continue;
/* display help on usage */
if (!strcmp(argument, "-h") || !strcmp(argument, "--help")) {
usage();
return 0;
}
/* check for version information */
if (!strcmp(argument, "-v") || !strcmp(argument, "--version")) {
printf("6pack: high-speed file compression tool\n");
printf("Version %s (using FastLZ %s)\n", SIXPACK_VERSION_STRING, FASTLZ_VERSION_STRING);
printf("Copyright (C) Ariya Hidayat\n");
printf("\n");
return 0;
}
/* test compression speed? */
if (!strcmp(argument, "-mem")) {
benchmark = 1;
continue;
}
/* compression level */
if (!strcmp(argument, "-1") || !strcmp(argument, "--fastest")) {
compress_level = 1;
continue;
}
if (!strcmp(argument, "-2")) {
compress_level = 2;
continue;
}
/* unknown option */
if (argument[0] == '-') {
printf("Error: unknown option %s\n\n", argument);
printf("To get help on usage:\n");
printf(" 6pack --help\n\n");
return -1;
}
/* first specified file is input */
if (!input_file) {
input_file = argument;
continue;
}
/* next specified file is output */
if (!output_file) {
output_file = argument;
continue;
}
/* files are already specified */
printf("Error: unknown option %s\n\n", argument);
printf("To get help on usage:\n");
printf(" 6pack --help\n\n");
return -1;
}
if (!input_file) {
printf("Error: input file is not specified.\n\n");
printf("To get help on usage:\n");
printf(" 6pack --help\n\n");
return -1;
}
if (!output_file && !benchmark) {
printf("Error: output file is not specified.\n\n");
printf("To get help on usage:\n");
printf(" 6pack --help\n\n");
return -1;
}
#ifdef SIXPACK_BENCHMARK_WIN32
if (benchmark)
return benchmark_speed(compress_level, input_file);
else
#endif
return pack_file(compress_level, input_file, output_file);
/* unreachable */
return 0;
}

425
FastLZ/examples/6unpack.c Normal file
View File

@ -0,0 +1,425 @@
/*
6PACK - file compressor using FastLZ (lightning-fast compression library)
Copyright (C) 2007-2020 Ariya Hidayat <ariya.hidayat@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIXPACK_VERSION_MAJOR 0
#define SIXPACK_VERSION_MINOR 1
#define SIXPACK_VERSION_REVISION 0
#define SIXPACK_VERSION_STRING "0.1.0"
#include "fastlz.h"
/* magic identifier for 6pack file */
static unsigned char sixpack_magic[8] = {137, '6', 'P', 'K', 13, 10, 26, 10};
#define BLOCK_SIZE 65536
/* prototypes */
static unsigned long update_adler32(unsigned long checksum, const void* buf, int len);
void usage(void);
int detect_magic(FILE* f);
static unsigned long readU16(const unsigned char* ptr);
static unsigned long readU32(const unsigned char* ptr);
void read_chunk_header(FILE* f, int* id, int* options, unsigned long* size, unsigned long* checksum,
unsigned long* extra);
int unpack_file(const char* archive_file);
/* for Adler-32 checksum algorithm, see RFC 1950 Section 8.2 */
#define ADLER32_BASE 65521
static unsigned long update_adler32(unsigned long checksum, const void* buf, int len) {
const unsigned char* ptr = (const unsigned char*)buf;
unsigned long s1 = checksum & 0xffff;
unsigned long s2 = (checksum >> 16) & 0xffff;
while (len > 0) {
unsigned k = len < 5552 ? len : 5552;
len -= k;
while (k >= 8) {
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
s1 += *ptr++;
s2 += s1;
k -= 8;
}
while (k-- > 0) {
s1 += *ptr++;
s2 += s1;
}
s1 = s1 % ADLER32_BASE;
s2 = s2 % ADLER32_BASE;
}
return (s2 << 16) + s1;
}
void usage(void) {
printf("6unpack: uncompress 6pack archive\n");
printf("Copyright (C) Ariya Hidayat\n");
printf("\n");
printf("Usage: 6unpack archive-file\n");
printf("\n");
}
/* return non-zero if magic sequence is detected */
/* warning: reset the read pointer to the beginning of the file */
int detect_magic(FILE* f) {
unsigned char buffer[8];
size_t bytes_read;
int c;
fseek(f, SEEK_SET, 0);
bytes_read = fread(buffer, 1, 8, f);
fseek(f, SEEK_SET, 0);
if (bytes_read < 8) return 0;
for (c = 0; c < 8; c++)
if (buffer[c] != sixpack_magic[c]) return 0;
return -1;
}
static unsigned long readU16(const unsigned char* ptr) { return ptr[0] + (ptr[1] << 8); }
static unsigned long readU32(const unsigned char* ptr) {
return ptr[0] + (ptr[1] << 8) + (ptr[2] << 16) + (ptr[3] << 24);
}
void read_chunk_header(FILE* f, int* id, int* options, unsigned long* size, unsigned long* checksum,
unsigned long* extra) {
unsigned char buffer[16];
fread(buffer, 1, 16, f);
*id = readU16(buffer) & 0xffff;
*options = readU16(buffer + 2) & 0xffff;
*size = readU32(buffer + 4) & 0xffffffff;
*checksum = readU32(buffer + 8) & 0xffffffff;
*extra = readU32(buffer + 12) & 0xffffffff;
}
int unpack_file(const char* input_file) {
FILE* in;
unsigned long fsize;
int c;
unsigned long percent;
unsigned char progress[20];
int chunk_id;
int chunk_options;
unsigned long chunk_size;
unsigned long chunk_checksum;
unsigned long chunk_extra;
unsigned char buffer[BLOCK_SIZE];
unsigned long checksum;
unsigned long decompressed_size;
unsigned long total_extracted;
int name_length;
char* output_file;
FILE* f;
unsigned char* compressed_buffer;
unsigned char* decompressed_buffer;
unsigned long compressed_bufsize;
unsigned long decompressed_bufsize;
/* sanity check */
in = fopen(input_file, "rb");
if (!in) {
printf("Error: could not open %s\n", input_file);
return -1;
}
/* find size of the file */
fseek(in, 0, SEEK_END);
fsize = ftell(in);
fseek(in, 0, SEEK_SET);
/* not a 6pack archive? */
if (!detect_magic(in)) {
fclose(in);
printf("Error: file %s is not a 6pack archive!\n", input_file);
return -1;
}
printf("Archive: %s", input_file);
/* position of first chunk */
fseek(in, 8, SEEK_SET);
/* initialize */
output_file = 0;
f = 0;
total_extracted = 0;
decompressed_size = 0;
percent = 0;
compressed_buffer = 0;
decompressed_buffer = 0;
compressed_bufsize = 0;
decompressed_bufsize = 0;
/* main loop */
for (;;) {
/* end of file? */
size_t pos = ftell(in);
if (pos >= fsize) break;
read_chunk_header(in, &chunk_id, &chunk_options, &chunk_size, &chunk_checksum, &chunk_extra);
if ((chunk_id == 1) && (chunk_size > 10) && (chunk_size < BLOCK_SIZE)) {
/* close current file, if any */
printf("\n");
free(output_file);
output_file = 0;
if (f) fclose(f);
/* file entry */
fread(buffer, 1, chunk_size, in);
checksum = update_adler32(1L, buffer, chunk_size);
if (checksum != chunk_checksum) {
free(output_file);
output_file = 0;
fclose(in);
printf("\nError: checksum mismatch!\n");
printf("Got %08lX Expecting %08lX\n", checksum, chunk_checksum);
return -1;
}
decompressed_size = readU32(buffer);
total_extracted = 0;
percent = 0;
/* get file to extract */
name_length = (int)readU16(buffer + 8);
if (name_length > (int)chunk_size - 10) name_length = chunk_size - 10;
output_file = (char*)malloc(name_length + 1);
memset(output_file, 0, name_length + 1);
for (c = 0; c < name_length; c++) output_file[c] = buffer[10 + c];
/* check if already exists */
f = fopen(output_file, "rb");
if (f) {
fclose(f);
printf("File %s already exists. Skipped.\n", output_file);
free(output_file);
output_file = 0;
f = 0;
} else {
/* create the file */
f = fopen(output_file, "wb");
if (!f) {
printf("Can't create file %s. Skipped.\n", output_file);
free(output_file);
output_file = 0;
f = 0;
} else {
/* for progress status */
printf("\n");
memset(progress, ' ', 20);
if (strlen(output_file) < 16)
for (c = 0; c < (int)strlen(output_file); c++) progress[c] = output_file[c];
else {
for (c = 0; c < 13; c++) progress[c] = output_file[c];
progress[13] = '.';
progress[14] = '.';
progress[15] = ' ';
}
progress[16] = '[';
progress[17] = 0;
printf("%s", progress);
for (c = 0; c < 50; c++) printf(".");
printf("]\r");
printf("%s", progress);
}
}
}
if ((chunk_id == 17) && f && output_file && decompressed_size) {
unsigned long remaining;
/* uncompressed */
switch (chunk_options) {
/* stored, simply copy to output */
case 0:
/* read one block at at time, write and update checksum */
total_extracted += chunk_size;
remaining = chunk_size;
checksum = 1L;
for (;;) {
unsigned long r = (BLOCK_SIZE < remaining) ? BLOCK_SIZE : remaining;
size_t bytes_read = fread(buffer, 1, r, in);
if (bytes_read == 0) break;
fwrite(buffer, 1, bytes_read, f);
checksum = update_adler32(checksum, buffer, bytes_read);
remaining -= bytes_read;
}
/* verify everything is written correctly */
if (checksum != chunk_checksum) {
fclose(f);
f = 0;
free(output_file);
output_file = 0;
printf("\nError: checksum mismatch. Aborted.\n");
printf("Got %08lX Expecting %08lX\n", checksum, chunk_checksum);
}
break;
/* compressed using FastLZ */
case 1:
/* enlarge input buffer if necessary */
if (chunk_size > compressed_bufsize) {
compressed_bufsize = chunk_size;
free(compressed_buffer);
compressed_buffer = (unsigned char*)malloc(compressed_bufsize);
}
/* enlarge output buffer if necessary */
if (chunk_extra > decompressed_bufsize) {
decompressed_bufsize = chunk_extra;
free(decompressed_buffer);
decompressed_buffer = (unsigned char*)malloc(decompressed_bufsize);
}
/* read and check checksum */
fread(compressed_buffer, 1, chunk_size, in);
checksum = update_adler32(1L, compressed_buffer, chunk_size);
total_extracted += chunk_extra;
/* verify that the chunk data is correct */
if (checksum != chunk_checksum) {
fclose(f);
f = 0;
free(output_file);
output_file = 0;
printf("\nError: checksum mismatch. Skipped.\n");
printf("Got %08lX Expecting %08lX\n", checksum, chunk_checksum);
} else {
/* decompress and verify */
remaining = fastlz_decompress(compressed_buffer, chunk_size, decompressed_buffer, chunk_extra);
if (remaining != chunk_extra) {
fclose(f);
f = 0;
free(output_file);
output_file = 0;
printf("\nError: decompression failed. Skipped.\n");
} else
fwrite(decompressed_buffer, 1, chunk_extra, f);
}
break;
default:
printf("\nError: unknown compression method (%d)\n", chunk_options);
fclose(f);
f = 0;
free(output_file);
output_file = 0;
break;
}
/* for progress, if everything is fine */
if (f) {
int last_percent = (int)percent;
if (decompressed_size < (1 << 24))
percent = total_extracted * 100 / decompressed_size;
else
percent = total_extracted / 256 * 100 / (decompressed_size >> 8);
percent >>= 1;
while (last_percent < (int)percent) {
printf("#");
last_percent++;
}
}
}
/* position of next chunk */
fseek(in, pos + 16 + chunk_size, SEEK_SET);
}
printf("\n\n");
/* free allocated stuff */
free(compressed_buffer);
free(decompressed_buffer);
free(output_file);
/* close working files */
if (f) fclose(f);
fclose(in);
/* so far so good */
return 0;
}
int main(int argc, char** argv) {
int i;
const char* archive_file;
/* show help with no argument at all*/
if (argc == 1) {
usage();
return 0;
}
/* check for help on usage */
for (i = 1; i <= argc; i++)
if (argv[i])
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
usage();
return 0;
}
/* check for version information */
for (i = 1; i <= argc; i++)
if (argv[i])
if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
printf("6unpack: high-speed file compression tool\n");
printf("Version %s (using FastLZ %s)\n", SIXPACK_VERSION_STRING, FASTLZ_VERSION_STRING);
printf("Copyright (C) Ariya Hidayat\n");
printf("\n");
return 0;
}
/* needs at least two arguments */
if (argc <= 1) {
usage();
return 0;
}
archive_file = argv[1];
return unpack_file(archive_file);
}

12
FastLZ/examples/Makefile Normal file
View File

@ -0,0 +1,12 @@
CFLAGS?=-Wall -std=c90
all: 6pack 6unpack
6pack: 6pack.c ../fastlz.c
$(CC) -o 6pack $(CFLAGS) -I.. 6pack.c ../fastlz.c
6unpack: 6unpack.c ../fastlz.c
$(CC) -o 6unpack $(CFLAGS) -I.. 6unpack.c ../fastlz.c
clean :
$(RM) 6pack 6unpack *.o

14
FastLZ/examples/Makefile.win Executable file
View File

@ -0,0 +1,14 @@
CC=cl.exe
CFLAGS=/Wall
RM=del
all: 6pack 6unpack
6pack: 6pack.c ../fastlz.c
$(CC) -o 6pack $(CFLAGS) -I.. 6pack.c ../fastlz.c
6unpack: 6unpack.c ../fastlz.c
$(CC) -o 6unpack $(CFLAGS) -I.. 6unpack.c ../fastlz.c
clean :
$(RM) 6pack.exe 6unpack.exe *.obj

508
FastLZ/fastlz.c Normal file
View File

@ -0,0 +1,508 @@
/*
FastLZ - Byte-aligned LZ77 compression library
Copyright (C) 2005-2020 Ariya Hidayat <ariya.hidayat@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "fastlz.h"
#include <stdint.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
/*
* Give hints to the compiler for branch prediction optimization.
*/
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 2))
#define FASTLZ_LIKELY(c) (__builtin_expect(!!(c), 1))
#define FASTLZ_UNLIKELY(c) (__builtin_expect(!!(c), 0))
#else
#define FASTLZ_LIKELY(c) (c)
#define FASTLZ_UNLIKELY(c) (c)
#endif
/*
* Specialize custom 64-bit implementation for speed improvements.
*/
#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)
#define FLZ_ARCH64
#endif
/*
* Workaround for DJGPP to find uint8_t, uint16_t, etc.
*/
#if defined(__MSDOS__) && defined(__GNUC__)
#include <stdint-gcc.h>
#endif
#if defined(FASTLZ_USE_MEMMOVE) && (FASTLZ_USE_MEMMOVE == 0)
static void fastlz_memmove(uint8_t* dest, const uint8_t* src, uint32_t count) {
do {
*dest++ = *src++;
} while (--count);
}
static void fastlz_memcpy(uint8_t* dest, const uint8_t* src, uint32_t count) {
return fastlz_memmove(dest, src, count);
}
#else
#include <string.h>
static void fastlz_memmove(uint8_t* dest, const uint8_t* src, uint32_t count) {
if ((count > 4) && (dest >= src + count)) {
memmove(dest, src, count);
} else {
switch (count) {
default:
do {
*dest++ = *src++;
} while (--count);
break;
case 3:
*dest++ = *src++;
case 2:
*dest++ = *src++;
case 1:
*dest++ = *src++;
case 0:
break;
}
}
}
static void fastlz_memcpy(uint8_t* dest, const uint8_t* src, uint32_t count) { memcpy(dest, src, count); }
#endif
#if defined(FLZ_ARCH64)
static uint32_t flz_readu32(const void* ptr) { return *(const uint32_t*)ptr; }
static uint32_t flz_cmp(const uint8_t* p, const uint8_t* q, const uint8_t* r) {
const uint8_t* start = p;
if (flz_readu32(p) == flz_readu32(q)) {
p += 4;
q += 4;
}
while (q < r)
if (*p++ != *q++) break;
return p - start;
}
#endif /* FLZ_ARCH64 */
#if !defined(FLZ_ARCH64)
static uint32_t flz_readu32(const void* ptr) {
const uint8_t* p = (const uint8_t*)ptr;
return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
}
static uint32_t flz_cmp(const uint8_t* p, const uint8_t* q, const uint8_t* r) {
const uint8_t* start = p;
while (q < r)
if (*p++ != *q++) break;
return p - start;
}
#endif /* !FLZ_ARCH64 */
#define MAX_COPY 32
#define MAX_LEN 264 /* 256 + 8 */
#define MAX_L1_DISTANCE 8192
#define MAX_L2_DISTANCE 8191
#define MAX_FARDISTANCE (65535 + MAX_L2_DISTANCE - 1)
#define HASH_LOG 13
#define HASH_SIZE (1 << HASH_LOG)
#define HASH_MASK (HASH_SIZE - 1)
static uint16_t flz_hash(uint32_t v) {
uint32_t h = (v * 2654435769LL) >> (32 - HASH_LOG);
return h & HASH_MASK;
}
/* special case of memcpy: at most MAX_COPY bytes */
static void flz_smallcopy(uint8_t* dest, const uint8_t* src, uint32_t count) {
#if defined(FLZ_ARCH64)
if (count >= 4) {
const uint32_t* p = (const uint32_t*)src;
uint32_t* q = (uint32_t*)dest;
while (count > 4) {
*q++ = *p++;
count -= 4;
dest += 4;
src += 4;
}
}
#endif
fastlz_memcpy(dest, src, count);
}
/* special case of memcpy: exactly MAX_COPY bytes */
static void flz_maxcopy(void* dest, const void* src) {
#if defined(FLZ_ARCH64)
const uint32_t* p = (const uint32_t*)src;
uint32_t* q = (uint32_t*)dest;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
#else
fastlz_memcpy(dest, src, MAX_COPY);
#endif
}
static uint8_t* flz_literals(uint32_t runs, const uint8_t* src, uint8_t* dest) {
while (runs >= MAX_COPY) {
*dest++ = MAX_COPY - 1;
flz_maxcopy(dest, src);
src += MAX_COPY;
dest += MAX_COPY;
runs -= MAX_COPY;
}
if (runs > 0) {
*dest++ = runs - 1;
flz_smallcopy(dest, src, runs);
dest += runs;
}
return dest;
}
static uint8_t* flz1_match(uint32_t len, uint32_t distance, uint8_t* op) {
--distance;
if (FASTLZ_UNLIKELY(len > MAX_LEN - 2))
while (len > MAX_LEN - 2) {
*op++ = (7 << 5) + (distance >> 8);
*op++ = MAX_LEN - 2 - 7 - 2;
*op++ = (distance & 255);
len -= MAX_LEN - 2;
}
if (len < 7) {
*op++ = (len << 5) + (distance >> 8);
*op++ = (distance & 255);
} else {
*op++ = (7 << 5) + (distance >> 8);
*op++ = len - 7;
*op++ = (distance & 255);
}
return op;
}
#define FASTLZ_BOUND_CHECK(cond) \
if (FASTLZ_UNLIKELY(!(cond))) return 0;
static int fastlz1_compress(const void* input, int length, void* output) {
const uint8_t* ip = (const uint8_t*)input;
const uint8_t* ip_start = ip;
const uint8_t* ip_bound = ip + length - 4; /* because readU32 */
const uint8_t* ip_limit = ip + length - 12 - 1;
uint8_t* op = (uint8_t*)output;
uint32_t htab[HASH_SIZE];
uint32_t seq, hash;
/* initializes hash table */
for (hash = 0; hash < HASH_SIZE; ++hash) htab[hash] = 0;
/* we start with literal copy */
const uint8_t* anchor = ip;
ip += 2;
/* main loop */
while (FASTLZ_LIKELY(ip < ip_limit)) {
const uint8_t* ref;
uint32_t distance, cmp;
/* find potential match */
do {
seq = flz_readu32(ip) & 0xffffff;
hash = flz_hash(seq);
ref = ip_start + htab[hash];
htab[hash] = ip - ip_start;
distance = ip - ref;
cmp = FASTLZ_LIKELY(distance < MAX_L1_DISTANCE) ? flz_readu32(ref) & 0xffffff : 0x1000000;
if (FASTLZ_UNLIKELY(ip >= ip_limit)) break;
++ip;
} while (seq != cmp);
if (FASTLZ_UNLIKELY(ip >= ip_limit)) break;
--ip;
if (FASTLZ_LIKELY(ip > anchor)) {
op = flz_literals(ip - anchor, anchor, op);
}
uint32_t len = flz_cmp(ref + 3, ip + 3, ip_bound);
op = flz1_match(len, distance, op);
/* update the hash at match boundary */
ip += len;
seq = flz_readu32(ip);
hash = flz_hash(seq & 0xffffff);
htab[hash] = ip++ - ip_start;
seq >>= 8;
hash = flz_hash(seq);
htab[hash] = ip++ - ip_start;
anchor = ip;
}
uint32_t copy = (uint8_t*)input + length - anchor;
op = flz_literals(copy, anchor, op);
return op - (uint8_t*)output;
}
static int fastlz1_decompress(const void* input, int length, void* output, int maxout) {
const uint8_t* ip = (const uint8_t*)input;
const uint8_t* ip_limit = ip + length;
const uint8_t* ip_bound = ip_limit - 2;
uint8_t* op = (uint8_t*)output;
uint8_t* op_limit = op + maxout;
uint32_t ctrl = (*ip++) & 31;
while (1) {
if (ctrl >= 32) {
uint32_t len = (ctrl >> 5) - 1;
uint32_t ofs = (ctrl & 31) << 8;
const uint8_t* ref = op - ofs - 1;
if (len == 7 - 1) {
FASTLZ_BOUND_CHECK(ip <= ip_bound);
len += *ip++;
}
ref -= *ip++;
len += 3;
FASTLZ_BOUND_CHECK(op + len <= op_limit);
FASTLZ_BOUND_CHECK(ref >= (uint8_t*)output);
fastlz_memmove(op, ref, len);
op += len;
} else {
ctrl++;
FASTLZ_BOUND_CHECK(op + ctrl <= op_limit);
FASTLZ_BOUND_CHECK(ip + ctrl <= ip_limit);
fastlz_memcpy(op, ip, ctrl);
ip += ctrl;
op += ctrl;
}
if (FASTLZ_UNLIKELY(ip > ip_bound)) break;
ctrl = *ip++;
}
return op - (uint8_t*)output;
}
static uint8_t* flz2_match(uint32_t len, uint32_t distance, uint8_t* op) {
--distance;
if (distance < MAX_L2_DISTANCE) {
if (len < 7) {
*op++ = (len << 5) + (distance >> 8);
*op++ = (distance & 255);
} else {
*op++ = (7 << 5) + (distance >> 8);
for (len -= 7; len >= 255; len -= 255) *op++ = 255;
*op++ = len;
*op++ = (distance & 255);
}
} else {
/* far away, but not yet in the another galaxy... */
if (len < 7) {
distance -= MAX_L2_DISTANCE;
*op++ = (len << 5) + 31;
*op++ = 255;
*op++ = distance >> 8;
*op++ = distance & 255;
} else {
distance -= MAX_L2_DISTANCE;
*op++ = (7 << 5) + 31;
for (len -= 7; len >= 255; len -= 255) *op++ = 255;
*op++ = len;
*op++ = 255;
*op++ = distance >> 8;
*op++ = distance & 255;
}
}
return op;
}
static int fastlz2_compress(const void* input, int length, void* output) {
const uint8_t* ip = (const uint8_t*)input;
const uint8_t* ip_start = ip;
const uint8_t* ip_bound = ip + length - 4; /* because readU32 */
const uint8_t* ip_limit = ip + length - 12 - 1;
uint8_t* op = (uint8_t*)output;
uint32_t htab[HASH_SIZE];
uint32_t seq, hash;
/* initializes hash table */
for (hash = 0; hash < HASH_SIZE; ++hash) htab[hash] = 0;
/* we start with literal copy */
const uint8_t* anchor = ip;
ip += 2;
/* main loop */
while (FASTLZ_LIKELY(ip < ip_limit)) {
const uint8_t* ref;
uint32_t distance, cmp;
/* find potential match */
do {
seq = flz_readu32(ip) & 0xffffff;
hash = flz_hash(seq);
ref = ip_start + htab[hash];
htab[hash] = ip - ip_start;
distance = ip - ref;
cmp = FASTLZ_LIKELY(distance < MAX_FARDISTANCE) ? flz_readu32(ref) & 0xffffff : 0x1000000;
if (FASTLZ_UNLIKELY(ip >= ip_limit)) break;
++ip;
} while (seq != cmp);
if (FASTLZ_UNLIKELY(ip >= ip_limit)) break;
--ip;
/* far, needs at least 5-byte match */
if (distance >= MAX_L2_DISTANCE) {
if (ref[3] != ip[3] || ref[4] != ip[4]) {
++ip;
continue;
}
}
if (FASTLZ_LIKELY(ip > anchor)) {
op = flz_literals(ip - anchor, anchor, op);
}
uint32_t len = flz_cmp(ref + 3, ip + 3, ip_bound);
op = flz2_match(len, distance, op);
/* update the hash at match boundary */
ip += len;
seq = flz_readu32(ip);
hash = flz_hash(seq & 0xffffff);
htab[hash] = ip++ - ip_start;
seq >>= 8;
hash = flz_hash(seq);
htab[hash] = ip++ - ip_start;
anchor = ip;
}
uint32_t copy = (uint8_t*)input + length - anchor;
op = flz_literals(copy, anchor, op);
/* marker for fastlz2 */
*(uint8_t*)output |= (1 << 5);
return op - (uint8_t*)output;
}
static int fastlz2_decompress(const void* input, int length, void* output, int maxout) {
const uint8_t* ip = (const uint8_t*)input;
const uint8_t* ip_limit = ip + length;
const uint8_t* ip_bound = ip_limit - 2;
uint8_t* op = (uint8_t*)output;
uint8_t* op_limit = op + maxout;
uint32_t ctrl = (*ip++) & 31;
while (1) {
if (ctrl >= 32) {
uint32_t len = (ctrl >> 5) - 1;
uint32_t ofs = (ctrl & 31) << 8;
const uint8_t* ref = op - ofs - 1;
uint8_t code;
if (len == 7 - 1) do {
FASTLZ_BOUND_CHECK(ip <= ip_bound);
code = *ip++;
len += code;
} while (code == 255);
code = *ip++;
ref -= code;
len += 3;
/* match from 16-bit distance */
if (FASTLZ_UNLIKELY(code == 255))
if (FASTLZ_LIKELY(ofs == (31 << 8))) {
FASTLZ_BOUND_CHECK(ip < ip_bound);
ofs = (*ip++) << 8;
ofs += *ip++;
ref = op - ofs - MAX_L2_DISTANCE - 1;
}
FASTLZ_BOUND_CHECK(op + len <= op_limit);
FASTLZ_BOUND_CHECK(ref >= (uint8_t*)output);
fastlz_memmove(op, ref, len);
op += len;
} else {
ctrl++;
FASTLZ_BOUND_CHECK(op + ctrl <= op_limit);
FASTLZ_BOUND_CHECK(ip + ctrl <= ip_limit);
fastlz_memcpy(op, ip, ctrl);
ip += ctrl;
op += ctrl;
}
if (FASTLZ_UNLIKELY(ip >= ip_limit)) break;
ctrl = *ip++;
}
return op - (uint8_t*)output;
}
int fastlz_compress(const void* input, int length, void* output) {
/* for short block, choose fastlz1 */
if (length < 65536) return fastlz1_compress(input, length, output);
/* else... */
return fastlz2_compress(input, length, output);
}
int fastlz_decompress(const void* input, int length, void* output, int maxout) {
/* magic identifier for compression level */
int level = ((*(const uint8_t*)input) >> 5) + 1;
if (level == 1) return fastlz1_decompress(input, length, output, maxout);
if (level == 2) return fastlz2_decompress(input, length, output, maxout);
/* unknown level, trigger error */
return 0;
}
int fastlz_compress_level(int level, const void* input, int length, void* output) {
if (level == 1) return fastlz1_compress(input, length, output);
if (level == 2) return fastlz2_compress(input, length, output);
return 0;
}
#pragma GCC diagnostic pop

97
FastLZ/fastlz.h Normal file
View File

@ -0,0 +1,97 @@
/*
FastLZ - Byte-aligned LZ77 compression library
Copyright (C) 2005-2020 Ariya Hidayat <ariya.hidayat@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef FASTLZ_H
#define FASTLZ_H
#define FASTLZ_VERSION 0x000500
#define FASTLZ_VERSION_MAJOR 0
#define FASTLZ_VERSION_MINOR 5
#define FASTLZ_VERSION_REVISION 0
#define FASTLZ_VERSION_STRING "0.5.0"
#if defined(__cplusplus)
extern "C" {
#endif
/**
Compress a block of data in the input buffer and returns the size of
compressed block. The size of input buffer is specified by length. The
minimum input buffer size is 16.
The output buffer must be at least 5% larger than the input buffer
and can not be smaller than 66 bytes.
If the input is not compressible, the return value might be larger than
length (input buffer size).
The input buffer and the output buffer can not overlap.
Compression level can be specified in parameter level. At the moment,
only level 1 and level 2 are supported.
Level 1 is the fastest compression and generally useful for short data.
Level 2 is slightly slower but it gives better compression ratio.
Note that the compressed data, regardless of the level, can always be
decompressed using the function fastlz_decompress below.
*/
int fastlz_compress_level(int level, const void* input, int length, void* output);
/**
Decompress a block of compressed data and returns the size of the
decompressed block. If error occurs, e.g. the compressed data is
corrupted or the output buffer is not large enough, then 0 (zero)
will be returned instead.
The input buffer and the output buffer can not overlap.
Decompression is memory safe and guaranteed not to write the output buffer
more than what is specified in maxout.
Note that the decompression will always work, regardless of the
compression level specified in fastlz_compress_level above (when
producing the compressed block).
*/
int fastlz_decompress(const void* input, int length, void* output, int maxout);
/**
DEPRECATED.
This is similar to fastlz_compress_level above, but with the level
automatically chosen.
This function is deprecated and it will be completely removed in some future
version.
*/
int fastlz_compress(const void* input, int length, void* output);
#if defined(__cplusplus)
}
#endif
#endif /* FASTLZ_H */

13
FastLZ/tests/Makefile Normal file
View File

@ -0,0 +1,13 @@
CFLAGS?=-Wall -std=c90
TEST_ROUNDTRIP?=./test_roundtrip
all: roundtrip
roundtrip: test_roundtrip
$(TEST_ROUNDTRIP)
test_roundtrip: test_roundtrip.c ../fastlz.c refimpl.c
$(CC) -o $(TEST_ROUNDTRIP) $(CFLAGS) -I.. test_roundtrip.c ../fastlz.c refimpl.c
clean :
$(RM) $(TEST_ROUNDTRIP) *.o

14
FastLZ/tests/Makefile.win Executable file
View File

@ -0,0 +1,14 @@
CC=cl.exe
CFLAGS=/Wall /Za
RM=del
TEST_ROUNDTRIP=test_roundtrip.exe
all: roundtrip
roundtrip: test_roundtrip.c ../fastlz.c refimpl.c
$(CC) -o $(TEST_ROUNDTRIP) $(CFLAGS) -I.. test_roundtrip.c ../fastlz.c refimpl.c
$(TEST_ROUNDTRIP)
clean :
$(RM) $(TEST_ROUNDTRIP) *.obj

103
FastLZ/tests/refimpl.c Normal file
View File

@ -0,0 +1,103 @@
#include <stdint.h>
/*
* Workaround for DJGPP to find uint8_t, uint16_t, etc.
*/
#if defined(__MSDOS__) && defined(__GNUC__)
#include <stdint-gcc.h>
#endif
void REF_Level1_decompress(const uint8_t* input, int length, uint8_t* output) {
int src = 0;
int dest = 0;
while (src < length) {
int type = input[src] >> 5;
if (type == 0) {
/* literal run */
int run = 1 + input[src];
src = src + 1;
while (run > 0) {
output[dest] = input[src];
src = src + 1;
dest = dest + 1;
run = run - 1;
}
} else if (type < 7) {
/* short match */
int ofs = 256 * (input[src] & 31) + input[src + 1];
int len = 2 + (input[src] >> 5);
src = src + 2;
int ref = dest - ofs - 1;
while (len > 0) {
output[dest] = output[ref];
ref = ref + 1;
dest = dest + 1;
len = len - 1;
}
} else {
/* long match */
int ofs = 256 * (input[src] & 31) + input[src + 2];
int len = 9 + input[src + 1];
src = src + 3;
int ref = dest - ofs - 1;
while (len > 0) {
output[dest] = output[ref];
ref = ref + 1;
dest = dest + 1;
len = len - 1;
}
}
}
}
void REF_Level2_decompress(const uint8_t* input, int length, uint8_t* output) {
int src = 0;
int dest = 0;
while (src < length) {
int type = input[src] >> 5;
if (type == 0) {
/* literal run */
int run = 1 + input[src];
src = src + 1;
while (run > 0) {
output[dest] = input[src];
src = src + 1;
dest = dest + 1;
run = run - 1;
}
} else {
int next = 2;
int len = 2 + (input[src] >> 5);
if (len == 9) {
/* long match */
next = next + 1;
len = len + input[src + 1];
if (len == 9 + 255) {
/* Gamma code for match length */
int nn = input[src + 1];
while (nn == 255) {
nn = input[src + next - 1];
next = next + 1;
len += nn;
}
}
}
int ofs = 256 * (input[src] & 31) + input[src + next - 1];
if (ofs == 8191) {
/* match from 16-bit distance */
ofs += 256 * input[src + next] + input[src + next + 1];
next = next + 2;
}
src = src + next;
int ref = dest - ofs - 1;
while (len > 0) {
output[dest] = output[ref];
ref = ref + 1;
dest = dest + 1;
len = len - 1;
}
}
}
}

View File

@ -0,0 +1,451 @@
/*
FastLZ - Byte-aligned LZ77 compression library
Copyright (C) 2005-2020 Ariya Hidayat <ariya.hidayat@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fastlz.h"
/*
* Workaround for DJGPP to find uint8_t, uint16_t, etc.
*/
#if defined(__MSDOS__) && defined(__GNUC__)
#include <stdint-gcc.h>
#endif
#define LOG
#undef LOG
int compare(const char* name, const uint8_t* a, const uint8_t* b, int size) {
int bad = 0;
int i;
for (i = 0; i < size; ++i) {
if (a[i] != b[i]) {
bad = 1;
printf("Error on %s!\n", name);
printf("Different at index %d: expecting %02x,actual %02x\n", i, a[i], b[i]);
break;
}
}
return bad;
}
#if !defined(__MSDOS__)
#define MAX_FILE_SIZE (100 * 1024 * 1024)
#else
#define MAX_FILE_SIZE (32 * 1024 * 1024)
#endif
/* prototype, implemented in refimpl.c */
void REF_Level1_decompress(const uint8_t* input, int length, uint8_t* output);
void REF_Level2_decompress(const uint8_t* input, int length, uint8_t* output);
/*
Same as test_roundtrip_level1 EXCEPT that the decompression is carried out
using the highly-simplified, unoptimized vanilla reference decompressor.
*/
void test_ref_decompressor_level1(const char* name, const char* file_name) {
#ifdef LOG
printf("Processing %s...\n", name);
#endif
FILE* f = fopen(file_name, "rb");
if (!f) {
printf("Error: can not open %s!\n", file_name);
exit(1);
}
fseek(f, 0L, SEEK_END);
long file_size = ftell(f);
rewind(f);
#ifdef LOG
printf("Size is %ld bytes.\n", file_size);
#endif
if (file_size > MAX_FILE_SIZE) {
fclose(f);
printf("%25s %10ld [skipped, file too big]\n", name, file_size);
return;
}
uint8_t* file_buffer = malloc(file_size);
long read = fread(file_buffer, 1, file_size, f);
fclose(f);
if (read != file_size) {
free(file_buffer);
printf("Error: only read %ld bytes!\n", read);
exit(1);
}
#ifdef LOG
printf("Compressing. Please wait...\n");
#endif
uint8_t* compressed_buffer = malloc(1.05 * file_size);
int compressed_size = fastlz_compress_level(1, file_buffer, file_size, compressed_buffer);
double ratio = (100.0 * compressed_size) / file_size;
#ifdef LOG
printf("Compressing was completed: %ld -> %ld (%.2f%%)\n", file_size, compressed_size, ratio);
#endif
#ifdef LOG
printf("Decompressing. Please wait...\n");
#endif
uint8_t* uncompressed_buffer = malloc(file_size);
if (uncompressed_buffer == NULL) {
printf("%25s %10ld -> %10d (%.2f%%) skipped, can't decompress\n", name, file_size, compressed_size, ratio);
return;
}
memset(uncompressed_buffer, '-', file_size);
REF_Level1_decompress(compressed_buffer, compressed_size, uncompressed_buffer);
#ifdef LOG
printf("Comparing. Please wait...\n");
#endif
int result = compare(file_name, file_buffer, uncompressed_buffer, file_size);
if (result == 1) {
free(uncompressed_buffer);
exit(1);
}
free(file_buffer);
free(compressed_buffer);
free(uncompressed_buffer);
#ifdef LOG
printf("OK.\n");
#else
printf("%25s %10ld -> %10d (%.2f%%)\n", name, file_size, compressed_size, ratio);
#endif
}
/*
Same as test_roundtrip_level2 EXCEPT that the decompression is carried out
using the highly-simplified, unoptimized vanilla reference decompressor.
*/
void test_ref_decompressor_level2(const char* name, const char* file_name) {
#ifdef LOG
printf("Processing %s...\n", name);
#endif
FILE* f = fopen(file_name, "rb");
if (!f) {
printf("Error: can not open %s!\n", file_name);
exit(1);
}
fseek(f, 0L, SEEK_END);
long file_size = ftell(f);
rewind(f);
#ifdef LOG
printf("Size is %ld bytes.\n", file_size);
#endif
if (file_size > MAX_FILE_SIZE) {
fclose(f);
printf("%25s %10ld [skipped, file too big]\n", name, file_size);
return;
}
uint8_t* file_buffer = malloc(file_size);
long read = fread(file_buffer, 1, file_size, f);
fclose(f);
if (read != file_size) {
free(file_buffer);
printf("Error: only read %ld bytes!\n", read);
exit(1);
}
#ifdef LOG
printf("Compressing. Please wait...\n");
#endif
uint8_t* compressed_buffer = malloc(1.05 * file_size);
int compressed_size = fastlz_compress_level(2, file_buffer, file_size, compressed_buffer);
double ratio = (100.0 * compressed_size) / file_size;
#ifdef LOG
printf("Compressing was completed: %ld -> %ld (%.2f%%)\n", file_size, compressed_size, ratio);
#endif
#ifdef LOG
printf("Decompressing. Please wait...\n");
#endif
uint8_t* uncompressed_buffer = malloc(file_size);
if (uncompressed_buffer == NULL) {
printf("%25s %10ld -> %10d (%.2f%%) skipped, can't decompress\n", name, file_size, compressed_size, ratio);
return;
}
memset(uncompressed_buffer, '-', file_size);
/* intentionally mask out the block tag */
compressed_buffer[0] = compressed_buffer[0] & 31;
REF_Level2_decompress(compressed_buffer, compressed_size, uncompressed_buffer);
#ifdef LOG
printf("Comparing. Please wait...\n");
#endif
int result = compare(file_name, file_buffer, uncompressed_buffer, file_size);
if (result == 1) {
free(uncompressed_buffer);
exit(1);
}
free(file_buffer);
free(compressed_buffer);
free(uncompressed_buffer);
#ifdef LOG
printf("OK.\n");
#else
printf("%25s %10ld -> %10d (%.2f%%)\n", name, file_size, compressed_size, ratio);
#endif
}
/*
Read the content of the file.
Compress it first using the Level 1 compressor.
Decompress the output with Level 1 decompressor.
Compare the result with the original file content.
*/
void test_roundtrip_level1(const char* name, const char* file_name) {
#ifdef LOG
printf("Processing %s...\n", name);
#endif
FILE* f = fopen(file_name, "rb");
if (!f) {
printf("Error: can not open %s!\n", file_name);
exit(1);
}
fseek(f, 0L, SEEK_END);
long file_size = ftell(f);
rewind(f);
#ifdef LOG
printf("Size is %ld bytes.\n", file_size);
#endif
if (file_size > MAX_FILE_SIZE) {
fclose(f);
printf("%25s %10ld [skipped, file too big]\n", name, file_size);
return;
}
uint8_t* file_buffer = malloc(file_size);
long read = fread(file_buffer, 1, file_size, f);
fclose(f);
if (read != file_size) {
free(file_buffer);
printf("Error: only read %ld bytes!\n", read);
exit(1);
}
#ifdef LOG
printf("Compressing. Please wait...\n");
#endif
uint8_t* compressed_buffer = malloc(1.05 * file_size);
int compressed_size = fastlz_compress_level(1, file_buffer, file_size, compressed_buffer);
double ratio = (100.0 * compressed_size) / file_size;
#ifdef LOG
printf("Compressing was completed: %ld -> %ld (%.2f%%)\n", file_size, compressed_size, ratio);
#endif
#ifdef LOG
printf("Decompressing. Please wait...\n");
#endif
uint8_t* uncompressed_buffer = malloc(file_size);
if (uncompressed_buffer == NULL) {
printf("%25s %10ld -> %10d (%.2f%%) skipped, can't decompress\n", name, file_size, compressed_size, ratio);
return;
}
memset(uncompressed_buffer, '-', file_size);
fastlz_decompress(compressed_buffer, compressed_size, uncompressed_buffer, file_size);
#ifdef LOG
printf("Comparing. Please wait...\n");
#endif
int result = compare(file_name, file_buffer, uncompressed_buffer, file_size);
if (result == 1) {
free(uncompressed_buffer);
exit(1);
}
free(file_buffer);
free(compressed_buffer);
free(uncompressed_buffer);
#ifdef LOG
printf("OK.\n");
#else
printf("%25s %10ld -> %10d (%.2f%%)\n", name, file_size, compressed_size, ratio);
#endif
}
/*
Read the content of the file.
Compress it first using the Level 2 compressor.
Decompress the output with Level 2 decompressor.
Compare the result with the original file content.
*/
void test_roundtrip_level2(const char* name, const char* file_name) {
#ifdef LOG
printf("Processing %s...\n", name);
#endif
FILE* f = fopen(file_name, "rb");
if (!f) {
printf("Error: can not open %s!\n", file_name);
exit(1);
}
fseek(f, 0L, SEEK_END);
long file_size = ftell(f);
rewind(f);
#ifdef LOG
printf("Size is %ld bytes.\n", file_size);
#endif
if (file_size > MAX_FILE_SIZE) {
fclose(f);
printf("%25s %10ld [skipped, file too big]\n", name, file_size);
return;
}
uint8_t* file_buffer = malloc(file_size);
long read = fread(file_buffer, 1, file_size, f);
fclose(f);
if (read != file_size) {
free(file_buffer);
printf("Error: only read %ld bytes!\n", read);
exit(1);
}
#ifdef LOG
printf("Compressing. Please wait...\n");
#endif
uint8_t* compressed_buffer = malloc(1.05 * file_size);
int compressed_size = fastlz_compress_level(2, file_buffer, file_size, compressed_buffer);
double ratio = (100.0 * compressed_size) / file_size;
#ifdef LOG
printf("Compressing was completed: %ld -> %ld (%.2f%%)\n", file_size, compressed_size, ratio);
#endif
#ifdef LOG
printf("Decompressing. Please wait...\n");
#endif
uint8_t* uncompressed_buffer = malloc(file_size);
if (uncompressed_buffer == NULL) {
free(file_buffer);
free(compressed_buffer);
printf("%25s %10ld -> %10d (%.2f%%) skipped, can't decompress OOM\n", name, file_size, compressed_size, ratio);
exit(1);
return;
}
memset(uncompressed_buffer, '-', file_size);
fastlz_decompress(compressed_buffer, compressed_size, uncompressed_buffer, file_size);
#ifdef LOG
printf("Comparing. Please wait...\n");
#endif
int result = compare(file_name, file_buffer, uncompressed_buffer, file_size);
if (result == 1) {
free(uncompressed_buffer);
exit(1);
}
free(file_buffer);
free(compressed_buffer);
free(uncompressed_buffer);
#ifdef LOG
printf("OK.\n");
#else
printf("%25s %10ld -> %10d (%.2f%%)\n", name, file_size, compressed_size, ratio);
#endif
}
int main(int argc, char** argv) {
const char* default_prefix = "../compression-corpus/";
const char* names[] = {"canterbury/alice29.txt",
"canterbury/asyoulik.txt",
"canterbury/cp.html",
"canterbury/fields.c",
"canterbury/grammar.lsp",
"canterbury/kennedy.xls",
"canterbury/lcet10.txt",
"canterbury/plrabn12.txt",
"canterbury/ptt5",
"canterbury/sum",
"canterbury/xargs.1",
"silesia/dickens",
"silesia/mozilla",
"silesia/mr",
"silesia/nci",
"silesia/ooffice",
"silesia/osdb",
"silesia/reymont",
"silesia/samba",
"silesia/sao",
"silesia/webster",
"silesia/x-ray",
"silesia/xml",
"enwik/enwik8.txt"};
const char* prefix = (argc == 2) ? argv[1] : default_prefix;
const int count = sizeof(names) / sizeof(names[0]);
int i;
printf("Test reference decompressor for Level 1\n\n");
for (i = 0; i < count; ++i) {
const char* name = names[i];
char* filename = malloc(strlen(prefix) + strlen(name) + 1);
strcpy(filename, prefix);
strcat(filename, name);
test_ref_decompressor_level1(name, filename);
free(filename);
}
printf("\n");
printf("Test reference decompressor for Level 2\n\n");
for (i = 0; i < count; ++i) {
const char* name = names[i];
char* filename = malloc(strlen(prefix) + strlen(name) + 1);
strcpy(filename, prefix);
strcat(filename, name);
test_ref_decompressor_level2(name, filename);
free(filename);
}
printf("\n");
printf("Test round-trip for Level 1\n\n");
for (i = 0; i < count; ++i) {
const char* name = names[i];
char* filename = malloc(strlen(prefix) + strlen(name) + 1);
strcpy(filename, prefix);
strcat(filename, name);
test_roundtrip_level1(name, filename);
free(filename);
}
printf("\n");
printf("Test round-trip for Level 2\n\n");
for (i = 0; i < count; ++i) {
const char* name = names[i];
char* filename = malloc(strlen(prefix) + strlen(name) + 1);
strcpy(filename, prefix);
strcat(filename, name);
test_roundtrip_level2(name, filename);
free(filename);
}
printf("\n");
return 0;
}

4
FastLZ/tools/format-code.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
cwd=$(pwd)
clang-format-6.0 -i --style='{BasedOnStyle: "google", ColumnLimit: 120}' $cwd/*.h $cwd/*.c $cwd/tests/*.c $cwd/examples/*.c

View File

@ -29,6 +29,11 @@ prepare:
$(PWD)/scripts/build-gcc.sh; \ $(PWD)/scripts/build-gcc.sh; \
cd ..; \ cd ..; \
fi fi
if [ ! -e FastLZ/examples/6pack ] || [ ! -e FastLZ/examples/6unpack ]; then \
cd FastLZ/examples; \
make; \
cd ..; \
fi
cleanall: cleanall:
make clean make clean
@ -38,7 +43,7 @@ clean:
make -C kernel ARCH=$(ARCH) ROOT=$(PWD) clean make -C kernel ARCH=$(ARCH) ROOT=$(PWD) clean
make -C user ARCH=$(ARCH) ROOT=$(PWD) clean make -C user ARCH=$(ARCH) ROOT=$(PWD) clean
make -C ulib ARCH=$(ARCH) ROOT=$(PWD) clean make -C ulib ARCH=$(ARCH) ROOT=$(PWD) clean
rm -f mop2.iso base.img disk.hdd rm -f mop2.iso base.img disk.hdd base.img.lz77
base: base:
./scripts/mkbaseimg.sh ./scripts/mkbaseimg.sh

213
README.md Normal file
View File

@ -0,0 +1,213 @@
# MOP2 - My OS project (2)
It's no. 2, because version no. 1 failed...
## Building
### Prepare stuff
```bash
make prepare
```
WARNING: This will take a while, since we're building an entire GCC toolchain + BinUtils.
### For development
```bash
./scripts/devel.sh
```
Will generate an `mop2.iso` image and a `disk.hdd`. You can run both live-iso and drive-installed
versions via `qemu-system-x86_64`.
## Running
There are two variants for the live-iso and drive-installed systems:
- `./run/qemu-x86_64-hdd.sh`
- `./run/qemu-x86_64-iso.sh`
## Blog posts
Sometimes I post updated on my blog regarding the project: [https://www.kamkow1lair.pl/]
## Screenshots
![Screenshot 1](https://git.kamkow1lair.pl/kamkow1/my-os-project2/raw/branch/master/static/MOP2-1.png)
![Screenshot 2](https://git.kamkow1lair.pl/kamkow1/my-os-project2/raw/branch/master/static/MOP2-2.png)
![Screenshot 3](https://git.kamkow1lair.pl/kamkow1/my-os-project2/raw/branch/master/static/MOP2-3.png)
## Legal
See `legal/` for the licenses of projects that where used as refrences. The directory also contains
licenses for used libraries.
LICENSE FOR MOP2:
```text
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
```

View File

@ -1,3 +1,7 @@
print 'Mounting filesystems...\n' print 'Mounting filesystems...\n'
setlogcmds yes setlogcmds yes
$fs mount -mp uhome -fs LittleFS -dev atasd-ch0-M-part2 -fmt no
# MOUNTPOINT FILESYSTEM DEVICE NAME DO FORMATTING
$fs mount -mp uhome -fs LittleFS -dev atasd0mp2 -fmt no
$fs mount -mp sys -fs FAT16 -dev atasd0mp1 -fmt no

View File

@ -1,2 +1,3 @@
# Create an $alias out of basenames of each entry in base:/bin
eachfile !.gitkeep base:/bin \ eachfile !.gitkeep base:/bin \
mkaliasbn &EF-ELEM mkaliasbn &EF-ELEM

115
kernel/FastLZ/6unpack_mem.c Normal file
View File

@ -0,0 +1,115 @@
#include <stdint.h>
#include <stddef.h>
#include "FastLZ/fastlz.h"
#include "std/string.h"
#define SIXPACK_OK 0
#define SIXPACK_ERR_MAGIC -1
#define SIXPACK_ERR_CHECKSUM -2
#define SIXPACK_ERR_DECOMPRESS -3
#define SIXPACK_ERR_BAD_FORMAT -4
#define SIXPACK_ERR_NO_SPACE -5
#define ADLER32_BASE 65521
#define BLOCK_SIZE 65536
static const uint8_t sixpack_magic[8] = {137, '6', 'P', 'K', 13, 10, 26, 10};
static uint32_t update_adler32(uint32_t checksum, const void *buf, int len) {
const uint8_t *ptr = (const uint8_t*)buf;
uint32_t s1 = checksum & 0xffff;
uint32_t s2 = (checksum >> 16) & 0xffff;
while (len > 0) {
unsigned k = len < 5552 ? len : 5552;
len -= k;
while (k--) {
s1 += *ptr++;
if (s1 >= ADLER32_BASE) s1 -= ADLER32_BASE;
s2 += s1;
if (s2 >= ADLER32_BASE) s2 -= ADLER32_BASE;
}
}
return (s2 << 16) + s1;
}
static uint32_t readU16(const uint8_t *p) {
return (uint32_t)p[0] | ((uint32_t)p[1] << 8);
}
static uint32_t readU32(const uint8_t *p) {
return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
}
static void read_chunk_header(const uint8_t *p, int *id, int *opts,
uint32_t *size, uint32_t *checksum, uint32_t *extra) {
*id = (int)readU16(p);
*opts = (int)readU16(p + 2);
*size = readU32(p + 4);
*checksum = readU32(p + 8);
*extra = readU32(p + 12);
}
int sixpack_decompress_mem(const uint8_t *input, size_t in_size,
uint8_t *output, size_t out_cap)
{
if (!input || in_size < 8)
return SIXPACK_ERR_BAD_FORMAT;
/* Check magic */
for (int i = 0; i < 8; i++)
if (input[i] != sixpack_magic[i])
return SIXPACK_ERR_MAGIC;
size_t pos = 8; /* skip magic */
size_t written = 0;
while (pos + 16 <= in_size) {
int chunk_id, opts;
uint32_t size, checksum, extra;
read_chunk_header(input + pos, &chunk_id, &opts, &size, &checksum, &extra);
pos += 16;
if (pos + size > in_size)
return SIXPACK_ERR_BAD_FORMAT;
const uint8_t *chunk_data = input + pos;
pos += size;
/* File header chunk */
if (chunk_id == 1) {
uint32_t decomp_size = readU32(chunk_data);
(void)decomp_size; /* not strictly needed here */
continue;
}
/* Data chunk */
if (chunk_id == 17) {
uint32_t cksum = update_adler32(1L, chunk_data, size);
if (cksum != checksum)
return SIXPACK_ERR_CHECKSUM;
if (opts == 0) {
/* Stored (uncompressed) */
if (written + size > out_cap)
return SIXPACK_ERR_NO_SPACE;
memcpy(output + written, chunk_data, size);
written += size;
} else if (opts == 1) {
/* FastLZ compressed */
if (written + extra > out_cap)
return SIXPACK_ERR_NO_SPACE;
int dec = fastlz_decompress(chunk_data, size, output + written, extra);
if (dec != (int)extra)
return SIXPACK_ERR_DECOMPRESS;
written += extra;
} else {
return SIXPACK_ERR_BAD_FORMAT;
}
}
}
return (int)written;
}

View File

@ -0,0 +1,7 @@
#ifndef SIXUNPACK_MEM_H_
#define SIXUNPACK_MEM_H_
int sixpack_decompress_mem(const uint8_t *input, size_t in_size,
uint8_t *output, size_t out_cap);
#endif // SIXUNPACK_MEM_H_

1
kernel/FastLZ/fastlz.c Symbolic link
View File

@ -0,0 +1 @@
../../FastLZ/fastlz.c

1
kernel/FastLZ/fastlz.h Symbolic link
View File

@ -0,0 +1 @@
../../FastLZ/fastlz.h

View File

@ -4,7 +4,8 @@ include $(ROOT)/mk/grabsrc.mk
PUTCHAR_ ?= fb PUTCHAR_ ?= fb
CFLAGS := -ffreestanding -Wall -Wextra -g -fcommon -nostdinc CFLAGS := -ffreestanding -Wall -Wextra -fcommon -nostdinc \
-fdata-sections -ffunction-sections
CFLAGS += -I. \ CFLAGS += -I. \
-I$(ROOT)/limine \ -I$(ROOT)/limine \
@ -20,24 +21,14 @@ CFLAGS += -I. \
-DLFS_NO_DEBUG \ -DLFS_NO_DEBUG \
-DLFS_NO_WARN \ -DLFS_NO_WARN \
-DLFS_NO_ERROR \ -DLFS_NO_ERROR \
-DPICO_MOP2 \ -DFASTLZ_USE_MEMMOVE=0 \
-DPICO_SUPPORT_TCP \ -DFATFS_MAX_OPEN_FILES=128 \
-DPICO_SUPPORT_UDP \ -D"FAT_PRINTF(a)"
-DPICO_SUPPORT_ETH \
-DPICO_SUPPORT_ICMP4 \
-DPICO_SUPPORT_IPV4 \
-DPICO_SUPPORT_MUTEX \
ifeq ($(PUTCHAR_),fb)
CFLAGS += -DPUTCHAR_=PUTCHAR_FB
else
CFLAGS += -DPUTCHAR_=PUTCHAR_SERIAL
endif
include arch/$(ARCH)/$(ARCH).mk include arch/$(ARCH)/$(ARCH).mk
include extconf/extra.mk
LDFLAGS += -nostdlib -static -T arch/$(ARCH)/link.ld $(shell $(CC) -print-libgcc-file-name) LDFLAGS += -nostdlib -static -T arch/$(ARCH)/link.ld $(shell $(CC) -print-libgcc-file-name) \
--gc-sections --strip-all
SRCFILES := SRCFILES :=
@ -56,10 +47,10 @@ SRCFILES += $(call GRABSRC, \
fs/kvfs \ fs/kvfs \
fs/littlefs \ fs/littlefs \
fs/portlfs \ fs/portlfs \
fs/fatfs \
fs/portfatfs \
baseimg \ baseimg \
proc \ proc \
hal \
hal/$(ARCH) \
std \ std \
flanterm/src \ flanterm/src \
flanterm/src/flanterm_backends \ flanterm/src/flanterm_backends \
@ -67,15 +58,20 @@ SRCFILES += $(call GRABSRC, \
path \ path \
rbuf \ rbuf \
ipc/pipe \ ipc/pipe \
ipc/netsock \ ipc/mbus \
dev \ dev \
randcrypto \ randcrypto \
time \ time \
diskpart \ diskpart \
netdev \ FastLZ \
port_picotcp \ io \
port_picotcp/modules \ intr \
picotcp/stack \ cpu \
vmm \
pci \
pci/ata \
pci/qemu_pci_serial \
cjob \
) )
CFILES := $(call GET_CFILES, $(SRCFILES)) CFILES := $(call GET_CFILES, $(SRCFILES))

View File

@ -1,15 +0,0 @@
#ifndef ASSERT_H_
#define ASSERT_H_
#include "kprintf.h"
#include "hal/hal.h"
#define ASSERT(mod, cond, fmt, ...) \
do { \
if (!(cond)) { \
ERR(mod, fmt, ##__VA_ARGS__); \
hal_hang(); \
} \
} while(0)
#endif // ASSERT_H_

View File

@ -1,6 +0,0 @@
#ifndef ATOMIC_H_
#define ATOMIC_H_
#define ATOMIC(X) _Atomic(X)
#endif // ATOMIC_H_

View File

@ -1,37 +1,46 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <limine.h> #include <limine.h>
#include "baseimg.h" #include "baseimg/baseimg.h"
#include "bootinfo/bootinfo.h" #include "bootinfo/bootinfo.h"
#include "kprintf.h"
#include "util/util.h" #include "util/util.h"
#include "hal/hal.h" #include "dlmalloc/malloc.h"
#include "FastLZ/fastlz.h"
#include "FastLZ/6unpack_mem.h"
#include "std/string.h"
#include "cpu/hang.h"
#include "kprintf.h"
struct limine_file *baseimg = NULL; #define BASEIMG_DECOMPRESSED (1024*1024*4)
size_t BASEIMG_DECOMP_SIZE;
uint8_t *BASEIMG_DECOMP_ADDR;
uint64_t baseimg_getaddr(void) { uint64_t baseimg_getaddr(void) {
return (uint64_t)baseimg->address; return (uint64_t)BASEIMG_DECOMP_ADDR;
} }
uint64_t baseimg_getsize(void) { uint64_t baseimg_getsize(void) {
return baseimg->size; return (uint64_t)BASEIMG_DECOMP_SIZE;
} }
void baseimg_init(void) { void baseimg_init(void) {
struct limine_file *baseimg = NULL;
LOG("baseimg", "looking for base image...\n"); LOG("baseimg", "looking for base image...\n");
for (size_t i = 0; i < BOOT_INFO.modules->module_count; i++) { for (size_t i = 0; i < BOOT_INFO.modules->module_count; i++) {
struct limine_file *module = BOOT_INFO.modules->modules[i]; struct limine_file *module = BOOT_INFO.modules->modules[i];
if (hal_strcmp(util_get_filename(module->path), "base.img") == 0) { if (strcmp(util_get_filename(module->path), "base.img.6pk") == 0) {
baseimg = module; baseimg = module;
break; break;
} }
} }
if (baseimg == NULL) { if (baseimg == NULL) {
ERR("baseimg", "base.img not found\n"); ERR("baseimg", "base.img.6pk not found\n");
hal_hang(); cpu_hang();
} else { } else {
LOG("baseimg", "base.img found\n"); LOG("baseimg", "base.img.6pk found\n");
LOG("baseimg", "addr = %p, size = %lu\n", baseimg->address, baseimg->size); LOG("baseimg", "addr = %p, size = %lu\n", baseimg->address, baseimg->size);
for (size_t i = 0; i < 30; i++) { for (size_t i = 0; i < 30; i++) {
kprintf("%02X ", ((uint8_t *)(baseimg->address))[i]); kprintf("%02X ", ((uint8_t *)(baseimg->address))[i]);
@ -40,4 +49,14 @@ void baseimg_init(void) {
} }
} }
} }
BASEIMG_DECOMP_ADDR = dlmalloc(BASEIMG_DECOMPRESSED);
int res = sixpack_decompress_mem(baseimg->address, baseimg->size,
BASEIMG_DECOMP_ADDR, BASEIMG_DECOMPRESSED);
if (res < 0) {
ERR("baseimg", "could not uncompress base.img.6pk\n");
cpu_hang();
}
BASEIMG_DECOMP_SIZE = res;
kprintf("%p %zu\n", BASEIMG_DECOMP_ADDR, BASEIMG_DECOMP_SIZE);
} }

View File

@ -1,7 +1,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include "bitmap.h" #include "bitmap/bitmap.h"
#include "util/util.h" #include "util/util.h"
#include "kprintf.h" #include "kprintf.h"

View File

@ -4,8 +4,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include "vmm/vmm.h"
#include "hal/hal.h"
typedef struct { typedef struct {
uint8_t *map; uint8_t *map;
@ -17,7 +16,7 @@ typedef struct {
} BitMap; } BitMap;
#define BITMAP_BLOCKS_PER_BYTE 8 #define BITMAP_BLOCKS_PER_BYTE 8
#define BITMAP_BLOCK_SIZE HAL_PAGE_SIZE #define BITMAP_BLOCK_SIZE VMM_PAGE_SIZE
#define BITMAP_INVALID_BLOCK ((size_t)-1) #define BITMAP_INVALID_BLOCK ((size_t)-1)
void *bitmap_toptr(BitMap *bm, size_t block); void *bitmap_toptr(BitMap *bm, size_t block);

View File

@ -1,8 +1,8 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <limine.h> #include <limine.h>
#include "bootinfo.h" #include "bootinfo/bootinfo.h"
#include "hal/hal.h" #include "cpu/hang.h"
BootInfo BOOT_INFO; BootInfo BOOT_INFO;
@ -26,7 +26,7 @@ DEFINE_REQ(module, MODULE);
void bootinfo_init(void) { void bootinfo_init(void) {
if (framebuffer_req.response == NULL || framebuffer_req.response->framebuffer_count < 1) { if (framebuffer_req.response == NULL || framebuffer_req.response->framebuffer_count < 1) {
hal_hang(); cpu_hang();
} }
BOOT_INFO.fb = framebuffer_req.response->framebuffers[0]; BOOT_INFO.fb = framebuffer_req.response->framebuffers[0];
@ -35,7 +35,7 @@ void bootinfo_init(void) {
struct limine_paging_mode_response *pagingres = paging_req.response; struct limine_paging_mode_response *pagingres = paging_req.response;
if (pagingres->mode != LIMINE_PAGING_MODE_X86_64_4LVL) { if (pagingres->mode != LIMINE_PAGING_MODE_X86_64_4LVL) {
hal_hang(); cpu_hang();
} }
struct limine_hhdm_response *hhdmres = hhdm_req.response; struct limine_hhdm_response *hhdmres = hhdm_req.response;
@ -68,7 +68,7 @@ void bootinfo_init(void) {
} }
} }
if (BOOT_INFO.smp_bspindex == (uint64_t)-1) { if (BOOT_INFO.smp_bspindex == (uint64_t)-1) {
hal_hang(); cpu_hang();
} }
struct limine_rsdp_response *rsdpres = rsdp_req.response; struct limine_rsdp_response *rsdpres = rsdp_req.response;

36
kernel/cjob/cjob.c Normal file
View File

@ -0,0 +1,36 @@
#include <stdint.h>
#include <stddef.h>
#include "spinlock/spinlock.h"
#include "cjob/cjob.h"
#include "dlmalloc/malloc.h"
#include "util/util.h"
CJobs CJOBS;
static uint64_t cjobids = 0;
void cjob_init(void) {
spinlock_init(&CJOBS.spinlock);
CJOBS.cjobs = NULL;
}
int32_t cjob_register(CJobFn fn, void *arg) {
CJob *cjob = dlmalloc(sizeof(*cjob));
cjob->fn = fn;
cjob->arg = arg;
int32_t id = cjob->id = cjobids++;
spinlock_acquire(&CJOBS.spinlock);
LL_APPEND(CJOBS.cjobs, cjob);
spinlock_release(&CJOBS.spinlock);
return id;
}
void cjob_runjobs(void) {
CJob *cjob, *cjobtmp;
spinlock_acquire(&CJOBS.spinlock);
LL_FOREACH_SAFE(CJOBS.cjobs, cjob, cjobtmp) {
cjob->fn(cjob->arg);
}
spinlock_release(&CJOBS.spinlock);
}

29
kernel/cjob/cjob.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef CJOB_CJOB_H_
#define CJOB_CJOB_H_
#include <stdint.h>
#include <stddef.h>
#include "spinlock/spinlock.h"
typedef void (*CJobFn)(void *arg);
typedef struct CJob {
struct CJob *next;
CJobFn fn;
void *arg;
int32_t id;
} CJob;
typedef struct {
SpinLock spinlock;
CJob *cjobs;
} CJobs;
extern CJobs CJOBS;
void cjob_init(void);
int32_t cjob_register(CJobFn fn, void *arg);
void cjob_runjobs(void);
#endif // CJOB_CJOB_H_

View File

@ -1,8 +1,8 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "compiler/attr.h" #include "compiler/attr.h"
#include "hal/hal.h" #include "cpu/gdt.h"
#include "gdt.h" #include "std/string.h"
#define GDT_PRESENT 0x80 #define GDT_PRESENT 0x80
#define GDT_TSS 0x89 #define GDT_TSS 0x89
@ -43,7 +43,7 @@ void gdt_setentry(GdtEntry *ent, uint32_t base, uint32_t limit, uint8_t acc, uin
} }
void gdt_init(void) { void gdt_init(void) {
hal_memset(&tss, 0, sizeof(tss)); memset(&tss, 0, sizeof(tss));
tss.iopb_off = sizeof(tss); tss.iopb_off = sizeof(tss);
tss.rsp0 = (uint64_t)(kernelstack + sizeof(kernelstack)); tss.rsp0 = (uint64_t)(kernelstack + sizeof(kernelstack));

View File

@ -1,5 +1,8 @@
#ifndef HAL_GDT_H_ #ifndef CPU_GDT_H_
#define HAL_GDT_H_ #define CPU_GDT_H_
#include <stdint.h>
#include "compiler/attr.h"
#define KCODE 0x08 #define KCODE 0x08
#define KDATA 0x10 #define KDATA 0x10
@ -23,4 +26,4 @@ ALIGNED(16) extern Tss tss;
void gdt_init(void); void gdt_init(void);
#endif // HAL_GDT_H_ #endif // CPU_GDT_H_

10
kernel/cpu/hang.c Normal file
View File

@ -0,0 +1,10 @@
#include "cpu/hang.h"
#include "intr/intr.h"
void cpu_hang(void) {
intr_disable();
for(;;) {
asm("hlt");
}
}

6
kernel/cpu/hang.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef CPU_HANG_H_
#define CPU_HANG_H_
void cpu_hang(void);
#endif // CPU_HANG_H_

View File

@ -1,22 +1,16 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "spinlock/spinlock.h" #include "spinlock/spinlock.h"
#include "dev.h" #include "std/string.h"
#include "dev/dev.h"
#include "dev/ps2kbdev.h"
#include "hshtb.h" #include "hshtb.h"
#include "hal/hal.h"
#include "termdev.h"
#include "ps2kbdev.h"
#include "serialdev.h"
#include "fbdev.h"
DevTable DEVTABLE; DevTable DEVTABLE;
void dev_init(void) { void dev_init(void) {
hal_memset(&DEVTABLE, 0, sizeof(DEVTABLE)); memset(&DEVTABLE, 0, sizeof(DEVTABLE));
spinlock_init(&DEVTABLE.spinlock); spinlock_init(&DEVTABLE.spinlock);
termdev_init();
ps2kbdev_init(); ps2kbdev_init();
serialdev_init();
fbdev_init();
} }

View File

@ -1,35 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include "fbdev.h"
#include "dev.h"
#include "sysdefs/dev.h"
#include "hshtb.h"
#include "spinlock/spinlock.h"
#include "util/util.h"
#include "hal/hal.h"
#include "bootinfo/bootinfo.h"
#include "errors.h"
int32_t fbdev_getinfo(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
(void)dev; (void)pid;
if (len != sizeof(FbDevGetInfo)) {
return E_INVALIDARGUMENT;
}
FbDevGetInfo info = {
.w = BOOT_INFO.fb->width,
.h = BOOT_INFO.fb->height,
.margin = 20,
.fontw = 8,
.fonth = 16,
};
hal_memcpy(buffer, &info, sizeof(info));
return E_OK;
}
void fbdev_init(void) {
Dev *fbdev;
HSHTB_ALLOC(DEVTABLE.devs, ident, "fbdev", fbdev);
fbdev->fns[DEV_FBDEV_GETINFO] = &fbdev_getinfo;
}

View File

@ -1,6 +0,0 @@
#ifndef DEV_FBDEV_H_
#define DEV_FBDEV_H_
void fbdev_init(void);
#endif // DEV_FBDEV_H_

View File

@ -1,15 +1,17 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "kprintf.h" #include "dev/ps2kbdev.h"
#include "hal/hal.h" #include "dev/dev.h"
#include "ps2kbdev.h"
#include "dev.h"
#include "errors.h"
#include "dlmalloc/malloc.h" #include "dlmalloc/malloc.h"
#include "util/util.h" #include "util/util.h"
#include "hshtb.h"
#include "sysdefs/dev.h" #include "sysdefs/dev.h"
#include "proc/proc.h" #include "proc/proc.h"
#include "io/io.h"
#include "ipc/mbus/mbus.h"
#include "intr/intr.h"
#include "errors.h"
#include "hshtb.h"
#include "kprintf.h"
#define KB_CTL_STATUS 0x64 #define KB_CTL_STATUS 0x64
#define KB_DATA_IN_BUF 0x01 #define KB_DATA_IN_BUF 0x01
@ -115,7 +117,7 @@ static uint8_t ctlmap[256] =
[0xc7] KB_HOME, [0xc7] KB_HOME,
}; };
int32_t ps2kb_intr(void) { int32_t ps2kbdev_keycode(void) {
static uint8_t shift; static uint8_t shift;
static uint8_t *charcode[4] = { normalmap, shiftmap, ctlmap, ctlmap }; static uint8_t *charcode[4] = { normalmap, shiftmap, ctlmap, ctlmap };
uint32_t st, data, c; uint32_t st, data, c;
@ -152,110 +154,23 @@ int32_t ps2kb_intr(void) {
return c; return c;
} }
typedef struct Ps2kbEvConsumer { IpcMBus *PS2KB_MBUS;
struct Ps2kbEvConsumer *next;
Proc *proc;
RBuf rbuf;
} Ps2kbEvConsumer;
struct { void ps2kbdev_intr(IntrStackFrame *frame) {
SpinLock spinlock; (void)frame;
Ps2kbEvConsumer *list;
} PS2KB_CONSUMERS = {0};
int32_t ps2kbdev_readch(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { int32_t c = ps2kbdev_keycode();
(void)dev; (void)buffer; (void)len;
Proc *consproc = NULL;
spinlock_acquire(&PROCS.spinlock);
Proc *proc, *proctmp;
LL_FOREACH_SAFE(PROCS.procs, proc, proctmp) {
if (proc->pid == pid) {
consproc = proc;
}
}
spinlock_release(&PROCS.spinlock);
if (consproc == NULL) {
return E_INVALIDOPER;
}
uint8_t b;
int32_t r = -1;
spinlock_acquire(&PS2KB_CONSUMERS.spinlock);
Ps2kbEvConsumer *cons, *constmp;
LL_FOREACH_SAFE(PS2KB_CONSUMERS.list, cons, constmp) {
if (cons->proc == consproc) {
r = rbuf_pop(&cons->rbuf, &b);
break;
}
}
spinlock_release(&PS2KB_CONSUMERS.spinlock);
if (r == 0) {
return b;
} else {
return E_NOTYET;
}
}
#define CONSUMER_RBUF_MAX 0x400
int32_t ps2kbdev_attchcons(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
(void)dev; (void)buffer; (void)len;
spinlock_acquire(&PROCS.spinlock);
Proc *proc, *proctmp;
LL_FOREACH_SAFE(PROCS.procs, proc, proctmp) {
if (proc->pid == pid) {
Ps2kbEvConsumer *cons = dlmalloc(sizeof(*cons));
cons->proc = proc;
uint8_t *buf = dlmalloc(CONSUMER_RBUF_MAX);
rbuf_init(&cons->rbuf, buf, CONSUMER_RBUF_MAX);
spinlock_acquire(&PS2KB_CONSUMERS.spinlock);
LL_APPEND(PS2KB_CONSUMERS.list, cons);
spinlock_release(&PS2KB_CONSUMERS.spinlock);
break;
}
}
spinlock_release(&PROCS.spinlock);
return E_OK;
}
void ps2kbdev_intr(void) {
int32_t c = ps2kb_intr();
if (c >= 0) { if (c >= 0) {
uint8_t b = c; uint8_t b = c;
spinlock_acquire(&PS2KB_CONSUMERS.spinlock); ipc_mbuspublish("ps2kb", &b);
Ps2kbEvConsumer *cons, *constmp;
LL_FOREACH_SAFE(PS2KB_CONSUMERS.list, cons, constmp) {
bool found = false;
spinlock_acquire(&PROCS.spinlock);
Proc *proc, *proctmp;
LL_FOREACH_SAFE(PROCS.procs, proc, proctmp) {
if (proc == cons->proc) {
found = true;
}
}
if (!found) {
LL_REMOVE(PS2KB_CONSUMERS.list, cons);
}
spinlock_release(&PROCS.spinlock);
rbuf_push(&cons->rbuf, b);
}
spinlock_release(&PS2KB_CONSUMERS.spinlock);
} }
} }
void ps2kbdev_init(void) { void ps2kbdev_init(void) {
intr_attchhandler(&ps2kbdev_intr, INTR_IRQBASE+1);
Dev *ps2kbdev; Dev *ps2kbdev;
HSHTB_ALLOC(DEVTABLE.devs, ident, "ps2kbdev", ps2kbdev); HSHTB_ALLOC(DEVTABLE.devs, ident, "ps2kbdev", ps2kbdev);
spinlock_init(&ps2kbdev->spinlock); spinlock_init(&ps2kbdev->spinlock);
spinlock_init(&PS2KB_CONSUMERS.spinlock); PS2KB_MBUS = ipc_mbusmake("ps2kb", 1, 0x100);
ps2kbdev->fns[DEV_PS2KBDEV_READCH] = &ps2kbdev_readch;
ps2kbdev->fns[DEV_PS2KBDEV_ATTCHCONS] = &ps2kbdev_attchcons; intr_attchhandler(&ps2kbdev_intr, INTR_IRQBASE+1);
} }

View File

@ -1,81 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include "dev.h"
#include "serialdev.h"
#include "errors.h"
#include "util/util.h"
#include "hshtb.h"
#include "sysdefs/dev.h"
#include "kprintf.h"
#include "hal/hal.h"
// https://wiki.osdev.org/Serial_Ports
#define PORT 0x3f8
void serial_init(void) {
io_out8(PORT+1, 0x00);
io_out8(PORT+3, 0x80);
io_out8(PORT+0, 0x03);
io_out8(PORT+1, 0x00);
io_out8(PORT+3, 0x03);
io_out8(PORT+2, 0xC7);
io_out8(PORT+4, 0x0B);
io_out8(PORT+4, 0x1E);
io_out8(PORT+0, 0xAE);
if (io_in8(PORT+0) != 0xAE) {
ERR("serial", "serial is faulty!\n");
return;
}
io_out8(PORT+4, 0x0F);
}
int serial_recvready(void) {
return io_in8(PORT+5) & 1;
}
uint8_t serial_recvb(void) {
return io_in8(PORT);
}
int serial_sendready(void) {
return io_in8(PORT+5) & 0x20;
}
void serial_sendb(uint8_t b) {
io_out8(PORT, b);
}
int32_t serialdev_sendb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
(void)dev; (void)len; (void)pid;
serial_sendb(buffer[0]);
return E_OK;
}
int32_t serialdev_sendready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
(void)dev; (void)buffer; (void)len; (void)pid;
return serial_sendready();
}
int32_t serialdev_recvb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
(void)dev; (void)buffer; (void)len; (void)pid;
return serial_recvb();
}
int32_t serialdev_recvready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
(void)dev; (void)buffer; (void)len; (void)pid;
return serial_recvready();
}
void serialdev_init(void) {
Dev *serialdev = NULL;
HSHTB_ALLOC(DEVTABLE.devs, ident, "serialdev", serialdev);
serialdev->fns[DEV_SERIALDEV_SENDB] = &serialdev_sendb;
serialdev->fns[DEV_SERIALDEV_SENDREADY] = &serialdev_sendready;
serialdev->fns[DEV_SERIALDEV_RECVB] = &serialdev_recvb;
serialdev->fns[DEV_SERIALDEV_RECVREADY] = &serialdev_recvready;
spinlock_init(&serialdev->spinlock);
serial_init();
}

View File

@ -1,6 +0,0 @@
#ifndef DEV_SERIALDEV_H_
#define DEV_SERIALDEV_H_
void serialdev_init(void);
#endif // DEV_SERIALDEV_H_

View File

@ -1,23 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include "kprintf.h"
#include "hal/hal.h"
#include "termdev.h"
#include "dev.h"
#include "errors.h"
#include "util/util.h"
#include "hshtb.h"
#include "sysdefs/dev.h"
int32_t termdev_putch(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
(void)dev; (void)pid;
kprintf("%.*s", (int)len, (char *)buffer);
return E_OK;
}
void termdev_init(void) {
Dev *termdev = NULL;
HSHTB_ALLOC(DEVTABLE.devs, ident, "termdev", termdev);
termdev->fns[DEV_TERMDEV_PUTCH] = &termdev_putch;
spinlock_init(&termdev->spinlock);
}

View File

@ -1,10 +0,0 @@
#ifndef DEV_TERMDEV_H_
#define DEV_TERMDEV_H_
#include <stdint.h>
#include <stddef.h>
#include "dev.h"
void termdev_init(void);
#endif // DEV_TERMDEV_H_

View File

@ -1,7 +1,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "storedev/storedev.h" #include "storedev/storedev.h"
#include "mbr.h" #include "diskpart/mbr.h"
#include "util/util.h" #include "util/util.h"
#include "kprintf.h" #include "kprintf.h"

View File

@ -2,14 +2,14 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "storedev/storedev.h" #include "storedev/storedev.h"
#include "mbr.h" #include "diskpart/mbr.h"
#include "diskpart.h" #include "diskpart/diskpart.h"
#include "compiler/attr.h" #include "compiler/attr.h"
#include "errors.h"
#include "kprintf.h"
#include "hal/hal.h"
#include "util/util.h" #include "util/util.h"
#include "dev/dev.h" #include "dev/dev.h"
#include "std/string.h"
#include "errors.h"
#include "kprintf.h"
typedef struct { typedef struct {
uint8_t driveattrs; uint8_t driveattrs;
@ -52,7 +52,7 @@ void diskpart_mbr_expose_partitions(StoreDev *sd, MBR *mbr) {
}; };
char name1[100]; char name1[100];
ksprintf(name1, "%s-part%zu", name, i+1); ksprintf(name1, "%sp%zu", name, i+1);
kprintf("%s\n", name1); kprintf("%s\n", name1);
storedev_create(STOREDEV_PARTSD, name1, &extra); storedev_create(STOREDEV_PARTSD, name1, &extra);
} }
@ -62,7 +62,7 @@ bool diskpart_mbr_probe(StoreDev *sd) {
LOG("diskpart", "probing for MBR\n"); LOG("diskpart", "probing for MBR\n");
MBR mbr; MBR mbr;
hal_memset(&mbr, 0, sizeof(mbr)); memset(&mbr, 0, sizeof(mbr));
sd->read(sd, (uint8_t *const)&mbr, 0, 0, sizeof(mbr)); sd->read(sd, (uint8_t *const)&mbr, 0, 0, sizeof(mbr));
if (!(mbr.validsign[0] == 0x55 && mbr.validsign[1] == 0xAA)) { if (!(mbr.validsign[0] == 0x55 && mbr.validsign[1] == 0xAA)) {

View File

@ -1,14 +1,16 @@
// Config // Config
#include <stddef.h> #include <stddef.h>
#include "hal/hal.h"
#include "spinlock/spinlock.h" #include "spinlock/spinlock.h"
#include "kprintf.h"
#include "bitmap/bitmap.h" #include "bitmap/bitmap.h"
#include "util/util.h" #include "util/util.h"
#include "pmm/pmm.h" #include "pmm/pmm.h"
#include "malloc.h" #include "dlmalloc/malloc.h"
#include "bootinfo/bootinfo.h" #include "bootinfo/bootinfo.h"
#include "std/string.h"
#include "vmm/vmm.h"
#include "cpu/hang.h"
#include "kprintf.h"
#define USE_DL_PREFIX 1 #define USE_DL_PREFIX 1
#define LACKS_SYS_TYPES_H 1 #define LACKS_SYS_TYPES_H 1
@ -26,7 +28,7 @@
#define ABORT \ #define ABORT \
do { \ do { \
ERR("dlmalloc", "Aborting..."); \ ERR("dlmalloc", "Aborting..."); \
hal_hang(); \ cpu_hang(); \
} while(0) } while(0)
#define MALLOC_FAILURE_ACTION #define MALLOC_FAILURE_ACTION
#define HAVE_MORECORE 1 #define HAVE_MORECORE 1
@ -67,7 +69,7 @@ void *sbrk(long inc) {
uint64_t blocks = _DIV_ROUNDUP(inc, BITMAP_BLOCK_SIZE); uint64_t blocks = _DIV_ROUNDUP(inc, BITMAP_BLOCK_SIZE);
uint8_t *virt = VIRT(pmm_alloc(blocks)); uint8_t *virt = VIRT(pmm_alloc(blocks));
hal_memset(virt, 0, blocks * BITMAP_BLOCK_SIZE); memset(virt, 0, blocks * BITMAP_BLOCK_SIZE);
_last = (void *)(virt + inc); _last = (void *)(virt + inc);
return virt; return virt;
} }

View File

@ -1 +0,0 @@
CFLAGS += -DKPRINTF_COLORS

View File

@ -1,345 +0,0 @@
unsigned char FM_T_437_F16[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0x81, 0xa5, 0xa5, 0x81, 0x81,
0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x7e, 0xff, 0xff,
0xdb, 0xdb, 0xff, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00,
0x00, 0x22, 0x22, 0x77, 0x7f, 0x7f, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c,
0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f,
0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x1c,
0x1c, 0x08, 0x6b, 0x7f, 0x7f, 0x6b, 0x08, 0x1c, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x08, 0x08, 0x1c, 0x3e, 0x7f, 0x7f, 0x7f, 0x7f, 0x2a, 0x08, 0x1c,
0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x7e, 0x7e, 0x7e,
0x7e, 0x7e, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe7, 0xc3,
0xc3, 0x81, 0x81, 0x81, 0x81, 0x81, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff,
0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24,
0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe7, 0xdb, 0xdb, 0xbd, 0xbd, 0xbd,
0xbd, 0xbd, 0xdb, 0xdb, 0xe7, 0xff, 0xff, 0xff, 0x00, 0x0f, 0x03, 0x05,
0x05, 0x08, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00,
0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x08, 0x08, 0x3e,
0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x0c, 0x0a, 0x0a, 0x09, 0x09, 0x09,
0x08, 0x08, 0x38, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00, 0x3f, 0x21, 0x3f,
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x67, 0xe7, 0xe2, 0x40, 0x00,
0x00, 0x49, 0x49, 0x2a, 0x36, 0x14, 0x22, 0xe3, 0x22, 0x14, 0x36, 0x2a,
0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e,
0x7c, 0x78, 0x70, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06,
0x0e, 0x1e, 0x3e, 0x7e, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x2a,
0x1c, 0x08, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x00, 0x3f, 0x49, 0x49,
0x49, 0x49, 0x39, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x00, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x40, 0x20, 0x58, 0x44, 0x22, 0x1a, 0x04, 0x02,
0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x2a,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x2a, 0x1c, 0x08, 0x3e, 0x00, 0x00,
0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x2a, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x02, 0x7f, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x7f, 0x20, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40,
0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x3e, 0x3e,
0x1c, 0x1c, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
0x08, 0x08, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24,
0x7e, 0x24, 0x24, 0x24, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x24, 0x00, 0x00,
0x00, 0x08, 0x1e, 0x2b, 0x28, 0x28, 0x28, 0x1c, 0x0a, 0x0a, 0x0a, 0x6a,
0x3c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x32, 0x52, 0x54, 0x64, 0x08, 0x08,
0x10, 0x10, 0x26, 0x2a, 0x4a, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44,
0x44, 0x44, 0x28, 0x18, 0x24, 0x45, 0x42, 0x42, 0x42, 0x3d, 0x00, 0x00,
0x00, 0x00, 0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x20, 0x10, 0x10,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00,
0x00, 0x00, 0x08, 0x49, 0x2a, 0x1c, 0x1c, 0x7f, 0x1c, 0x1c, 0x2a, 0x49,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x3e,
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02,
0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00,
0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24,
0x24, 0x18, 0x00, 0x00, 0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42,
0x42, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x02, 0x02, 0x02, 0x1c, 0x02, 0x02, 0x02, 0x42,
0x42, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x0c, 0x14, 0x14, 0x24, 0x24,
0x44, 0x44, 0x44, 0x7e, 0x04, 0x04, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40,
0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x3c, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x42, 0x42, 0x04, 0x04, 0x04,
0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42,
0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x42,
0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x18, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x10, 0x20, 0x00, 0x00,
0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00,
0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20,
0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x42, 0x02, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00,
0x08, 0x08, 0x00, 0x00, 0x00, 0x1e, 0x22, 0x41, 0x49, 0x55, 0x55, 0x55,
0x55, 0x55, 0x57, 0x4b, 0x20, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x24, 0x42,
0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
0x00, 0x7c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3c, 0x22, 0x22, 0x22, 0x22,
0x22, 0x7c, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x42, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x42, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x78, 0x24, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x78, 0x00, 0x00,
0x00, 0x7e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40,
0x40, 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x42,
0x40, 0x40, 0x40, 0x40, 0x4e, 0x42, 0x42, 0x42, 0x22, 0x1c, 0x00, 0x00,
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00,
0x00, 0x42, 0x42, 0x44, 0x44, 0x48, 0x50, 0x50, 0x68, 0x48, 0x44, 0x44,
0x42, 0x42, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x41, 0x63, 0x63,
0x55, 0x55, 0x49, 0x49, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00,
0x00, 0x42, 0x42, 0x62, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x46, 0x42,
0x42, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x78, 0x44, 0x42,
0x42, 0x42, 0x44, 0x78, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x52, 0x4a, 0x44,
0x44, 0x3a, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7c,
0x48, 0x48, 0x44, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42,
0x40, 0x40, 0x40, 0x3c, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00,
0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x22, 0x22, 0x22, 0x14, 0x1c, 0x08, 0x00, 0x00,
0x00, 0x41, 0x41, 0x41, 0x41, 0x49, 0x49, 0x49, 0x49, 0x55, 0x55, 0x55,
0x22, 0x22, 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x36, 0x14, 0x08, 0x08,
0x08, 0x14, 0x36, 0x22, 0x41, 0x41, 0x00, 0x00, 0x00, 0x41, 0x41, 0x22,
0x22, 0x14, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
0x00, 0x7e, 0x02, 0x02, 0x04, 0x04, 0x08, 0x18, 0x10, 0x20, 0x20, 0x40,
0x40, 0x7e, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00,
0x00, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
0x00, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x04,
0x3c, 0x44, 0x44, 0x44, 0x48, 0x36, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40,
0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40,
0x42, 0x3c, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x3a, 0x46, 0x42,
0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00,
0x00, 0x0c, 0x12, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42,
0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x3c, 0x00, 0x40, 0x40, 0x40,
0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
0x00, 0x08, 0x08, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x0c, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, 0x00, 0x40, 0x40, 0x40,
0x40, 0x42, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x42, 0x00, 0x00,
0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x6d, 0x49,
0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42,
0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40,
0x40, 0x3c, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10,
0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x12, 0x0c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41,
0x41, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x66, 0x24, 0x18, 0x24, 0x66,
0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7e, 0x02, 0x04, 0x04, 0x18, 0x20, 0x20, 0x40, 0x7e, 0x00, 0x00,
0x00, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x08, 0x08, 0x08, 0x08,
0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x10,
0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, 0x00,
0x00, 0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28,
0x44, 0x82, 0x82, 0x82, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x42,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x22, 0x1c, 0x08, 0x38,
0x00, 0x42, 0x42, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x46, 0x3a, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x00, 0x3c, 0x42, 0x42,
0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x10, 0x28, 0x44,
0x00, 0x38, 0x44, 0x04, 0x3c, 0x44, 0x44, 0x44, 0x48, 0x36, 0x00, 0x00,
0x00, 0x44, 0x44, 0x00, 0x00, 0x38, 0x44, 0x04, 0x3c, 0x44, 0x44, 0x44,
0x48, 0x36, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x00, 0x38, 0x44, 0x04,
0x3c, 0x44, 0x44, 0x44, 0x48, 0x36, 0x00, 0x00, 0x00, 0x18, 0x24, 0x18,
0x00, 0x38, 0x44, 0x04, 0x3c, 0x44, 0x44, 0x44, 0x48, 0x36, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40,
0x42, 0x3c, 0x08, 0x38, 0x00, 0x18, 0x24, 0x42, 0x00, 0x3c, 0x42, 0x42,
0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x42, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00,
0x00, 0x20, 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x40, 0x40,
0x42, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x18, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22,
0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00,
0x00, 0x20, 0x10, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x1c, 0x00, 0x00, 0x00, 0x42, 0x42, 0x18, 0x24, 0x42, 0x42, 0x42,
0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x18, 0x24, 0x18,
0x24, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
0x04, 0x08, 0x7e, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40,
0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x49, 0x09,
0x39, 0x4f, 0x48, 0x48, 0x49, 0x36, 0x00, 0x00, 0x00, 0x1f, 0x28, 0x48,
0x48, 0x48, 0x48, 0x7f, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x00, 0x00,
0x00, 0x18, 0x24, 0x42, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x3c, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00,
0x00, 0x18, 0x24, 0x42, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x46, 0x3a, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x00, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x42, 0x42, 0x00,
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x3c,
0x42, 0x42, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x3c, 0x00, 0x00, 0x42, 0x42, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x08, 0x3e, 0x49, 0x48, 0x48, 0x48, 0x48, 0x49, 0x3e, 0x08, 0x08, 0x00,
0x00, 0x0c, 0x12, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x08, 0x38, 0x49,
0x49, 0x36, 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x22, 0x14, 0x7f, 0x08,
0x08, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x78, 0x44, 0x42,
0x42, 0x44, 0x78, 0x40, 0x44, 0x5f, 0x44, 0x44, 0x45, 0x42, 0x00, 0x00,
0x00, 0x06, 0x09, 0x09, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x48,
0x48, 0x30, 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x00, 0x38, 0x44, 0x04,
0x3c, 0x44, 0x44, 0x44, 0x48, 0x36, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10,
0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00,
0x00, 0x04, 0x08, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x00, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00,
0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
0x32, 0x4c, 0x00, 0x42, 0x62, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x46,
0x42, 0x42, 0x00, 0x00, 0x00, 0x38, 0x48, 0x48, 0x34, 0x00, 0x7c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, 0x48,
0x30, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x20, 0x40, 0x42, 0x42,
0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x30, 0x10, 0x10, 0x11, 0x3a, 0x04, 0x08, 0x16, 0x29, 0x42,
0x04, 0x08, 0x0f, 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x11, 0x3a, 0x04,
0x08, 0x12, 0x26, 0x4a, 0x1f, 0x02, 0x02, 0x00, 0x00, 0x00, 0x08, 0x08,
0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x24, 0x48, 0x24, 0x12, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x24, 0x12,
0x24, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
0x55, 0xaa, 0x55, 0xaa, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb,
0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08,
0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0xe4, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08,
0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0xe4, 0x04, 0xe4, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x04,
0xe4, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0xe4, 0x04, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0xfc, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08,
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x27, 0x20, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x20, 0x27, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0xe7, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0xe7, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x27, 0x20, 0x27, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0xe7, 0x00, 0xe7, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x0f, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x0f, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3f, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0xff, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0xff, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x32, 0x4a, 0x4a, 0x44, 0x44, 0x44, 0x44, 0x4a, 0x32, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x48, 0x44, 0x42, 0x42,
0x42, 0x4c, 0x40, 0x40, 0x00, 0x7e, 0x42, 0x42, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00,
0x00, 0x7f, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x40,
0x40, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x48, 0x44,
0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5d, 0x40, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x4e, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x00, 0x00, 0x00, 0x7f, 0x08, 0x08, 0x1c, 0x22, 0x41, 0x41,
0x41, 0x22, 0x1c, 0x08, 0x08, 0x7f, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24,
0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18, 0x00, 0x00,
0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24,
0x24, 0x66, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x08, 0x04, 0x1c, 0x22, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x02, 0x04, 0x3c, 0x4a, 0x4a, 0x52, 0x52, 0x3c, 0x20,
0x40, 0x40, 0x00, 0x00, 0x00, 0x0e, 0x10, 0x20, 0x20, 0x40, 0x40, 0x7c,
0x40, 0x40, 0x20, 0x20, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x3e,
0x08, 0x08, 0x08, 0x08, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x7e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04,
0x00, 0x7e, 0x00, 0x00, 0x00, 0x06, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x48, 0x48, 0x48, 0x30, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00,
0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, 0x48,
0x48, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x28, 0x68, 0x28, 0x18, 0x18, 0x08, 0x00, 0x00,
0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x18, 0x20, 0x3c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
unsigned int FM_T_437_F16_len = 4096;

345
kernel/font.h Normal file
View File

@ -0,0 +1,345 @@
unsigned char FLORI_F16[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xc3, 0x81, 0xe7, 0x81, 0xe7,
0xbd, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
0xff, 0x99, 0xff, 0xbd, 0x99, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x36, 0x7f, 0x7f, 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x3e,
0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd,
0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x07,
0x0d, 0x19, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0x81, 0x99, 0xbd, 0xff, 0x99, 0x99, 0x99, 0x99, 0x81, 0x81,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30,
0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63,
0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3, 0xc6,
0xcc, 0xd8, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0f, 0x1b,
0x33, 0x63, 0xc3, 0x63, 0x33, 0x1b, 0x0f, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x3c, 0x7e, 0xff, 0x18, 0x18, 0x18, 0xff, 0x7e, 0x3c, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0x00, 0x00, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x30, 0x7c, 0x66, 0x33, 0x1f, 0x06, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e,
0xff, 0x18, 0x18, 0x18, 0xff, 0x7e, 0x3c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x3c, 0x7e, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x0c, 0x0e, 0xff, 0x0e, 0x0c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x30, 0x70, 0xff, 0x70, 0x30, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60,
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc3, 0xc3, 0x66, 0x66,
0x3c, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x08, 0x3e, 0x6b, 0x68, 0x68, 0x3e, 0x0b, 0x0b, 0x6b, 0x3e,
0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xdb, 0x76, 0x0c, 0x18,
0x30, 0x6e, 0xdb, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
0x36, 0x3c, 0x18, 0x3b, 0x6e, 0x66, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x6b, 0x3e, 0x7f, 0x3e, 0x6b, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff,
0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x67, 0x6f, 0x7b, 0x73, 0x63, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63,
0x43, 0x03, 0x0e, 0x38, 0x60, 0x60, 0x61, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x43, 0x03, 0x1e, 0x03, 0x03, 0x03, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x33, 0x63, 0x63,
0x7f, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x61,
0x60, 0x60, 0x7e, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x30, 0x60, 0x60, 0x7e, 0x63, 0x63, 0x63, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, 0x03, 0x03, 0x06, 0x0c,
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63,
0x63, 0x63, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3f, 0x03, 0x03, 0x06, 0x3c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00,
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x03, 0x0e, 0x18, 0x18, 0x00, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x6f, 0x6b, 0x6b,
0x6b, 0x6e, 0x60, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33,
0x63, 0x63, 0x63, 0xff, 0x63, 0x63, 0x63, 0xe3, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0xe3, 0x63, 0x7e, 0x63, 0x63, 0x63, 0x63, 0xfe,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33, 0x63, 0x60, 0x60, 0x60,
0x60, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63,
0xe3, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0xfe, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3f, 0x61, 0xe0, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x61, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x61, 0xe0, 0x60, 0x7c, 0x60,
0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33,
0x63, 0x60, 0x60, 0x6f, 0x63, 0x63, 0x63, 0x3f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0xe3, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0xe3,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x38, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0e,
0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0xe3, 0x66, 0x6c, 0x78, 0x7c, 0x66, 0x63, 0x63, 0xe3,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x70, 0xe0, 0x60, 0x60, 0x60,
0x60, 0x60, 0x61, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7,
0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0xf3, 0x7b, 0x6f, 0x67, 0x63, 0x63, 0x63, 0x63, 0xe3,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63,
0xe3, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x33, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7b, 0x6f, 0x3e,
0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0xe3, 0x63, 0x63, 0x7e,
0x6c, 0x66, 0x63, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33,
0x63, 0x60, 0x78, 0x1e, 0x03, 0x63, 0x63, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xd9, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3, 0x63, 0x3e, 0x1c, 0x3e,
0x63, 0x63, 0x63, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3f, 0x63, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x61, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,
0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x3f,
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xe0,
0x60, 0x6e, 0x73, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x60, 0x60, 0x60, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x03, 0x3f, 0x63, 0x63,
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x63, 0x63, 0x6e, 0x78, 0x73, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x33, 0x30, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x30, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x63, 0x63,
0x63, 0x67, 0x3b, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x60, 0xe0,
0x60, 0x6e, 0x73, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x38, 0x18, 0x18, 0x18, 0x1b, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x06, 0x0e, 0x06,
0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x60, 0xe0,
0x60, 0x66, 0x66, 0x7c, 0x78, 0x6c, 0x66, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdb, 0xdb,
0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x6e, 0xf3, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xf3, 0x63,
0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x67, 0x3b, 0x03, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xf3, 0x63, 0x60, 0x60, 0x60, 0x60,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x60,
0x3e, 0x03, 0x63, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x18,
0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3, 0x63, 0x63, 0x63, 0x67, 0x3b,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3, 0x63,
0x63, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x36, 0x1c, 0x1c, 0x1c, 0x36, 0x63,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3, 0x63,
0x63, 0x67, 0x3b, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3f, 0x66, 0x0c, 0x18, 0x30, 0x61, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3b, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36,
0x63, 0x63, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33,
0x63, 0x60, 0x60, 0x60, 0x60, 0x63, 0x63, 0x3e, 0x03, 0x0e, 0x00, 0x00,
0x00, 0x00, 0x63, 0x63, 0x00, 0x63, 0xe3, 0x63, 0x63, 0x63, 0x67, 0x3b,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x3e, 0x63, 0x63,
0x7f, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1e, 0x33,
0x00, 0x3e, 0x03, 0x3f, 0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x33, 0x33, 0x00, 0x3e, 0x03, 0x3f, 0x63, 0x63, 0x67, 0x3b,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x06, 0x00, 0x3e, 0x03, 0x3f,
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x1c,
0x00, 0x3e, 0x03, 0x3f, 0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x60, 0x60, 0x60, 0x63, 0x3e,
0x03, 0x0e, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x63,
0x7f, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33,
0x00, 0x3e, 0x63, 0x63, 0x7f, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x0c, 0x06, 0x00, 0x3e, 0x63, 0x63, 0x7f, 0x60, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x00, 0x18, 0x18, 0x18,
0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36,
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x18, 0x0c, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x1e, 0x33, 0x63, 0x63, 0xff,
0x63, 0x63, 0x63, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33, 0x1e,
0x33, 0x63, 0x63, 0xff, 0x63, 0x63, 0x63, 0xe3, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x30, 0x3f, 0x61, 0xe0, 0x7c, 0x60, 0x60, 0x60, 0x61, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x1b, 0x1b,
0xfb, 0xdf, 0xd8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x36,
0x66, 0x66, 0x66, 0xff, 0x66, 0x66, 0x66, 0xe7, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x3e, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c,
0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x1c, 0x36, 0x00, 0x63, 0xe3, 0x63, 0x63, 0x63, 0x67, 0x3b,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x00, 0x63, 0xe3, 0x63,
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63,
0x00, 0x63, 0xe3, 0x63, 0x63, 0x63, 0x3f, 0x03, 0x63, 0x3e, 0x00, 0x00,
0x00, 0x63, 0x63, 0x00, 0x1e, 0x33, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x63, 0xe3, 0x63, 0x63,
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x78, 0x30, 0x30, 0x30, 0x73, 0x7e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66,
0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x77, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8,
0x70, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x03, 0x3f,
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0c, 0x18, 0x30, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x63, 0xe3, 0x63,
0x63, 0x63, 0x63, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e,
0x00, 0x6e, 0xf3, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3b, 0x6e, 0x00, 0x63, 0xf3, 0x7b, 0x6f, 0x67, 0x63, 0x63, 0xe3,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3c, 0x00, 0x7e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x3c, 0x60, 0x63, 0x63, 0x3e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60,
0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0xe1, 0x63, 0x66, 0x6c, 0x18, 0x36, 0x6b, 0xdb, 0x86, 0x0c,
0x1f, 0x00, 0x00, 0x00, 0x00, 0x60, 0xe1, 0x63, 0x66, 0x6c, 0x18, 0x33,
0x67, 0xcb, 0x9b, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x36, 0x6c, 0x36, 0x1b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x36, 0x1b,
0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x41, 0x63, 0x36,
0x14, 0x41, 0x63, 0x36, 0x14, 0x41, 0x63, 0x36, 0x14, 0x41, 0x63, 0x36,
0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00,
0xdb, 0x00, 0xdb, 0x00, 0x00, 0x1c, 0x63, 0x14, 0x63, 0x1c, 0x00, 0x00,
0x00, 0x1c, 0x63, 0x14, 0x63, 0x1c, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x00, 0xf0,
0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0e, 0xe6,
0x76, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x76, 0xe6, 0x0e, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x00, 0x0f, 0x1c, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x33, 0x38, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x38, 0x33, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xe3,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0xf0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3b, 0x6e, 0x6c, 0x6c, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x6e, 0x63, 0x63, 0x63, 0x6e,
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 0x63, 0x60, 0x60, 0x60,
0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xc3, 0x60, 0x30, 0x18, 0x18, 0x30, 0x60, 0xc3, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x6c,
0x6c, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x70, 0x70, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e, 0x0c, 0x0c, 0x0c, 0x0c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x7e, 0xe7, 0xc3, 0xc3,
0xe7, 0x7e, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
0x66, 0xc3, 0xff, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x66, 0xe7,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66,
0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60,
0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x38, 0x60, 0x60, 0x7e, 0x60,
0x60, 0x60, 0x38, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18,
0x18, 0x18, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x7e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e, 0x00, 0x3b,
0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x0c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x18, 0x70, 0xc0, 0xf8, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
unsigned int FLORI_F16_len = 4096;

View File

@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail. Also add information on how to contact you by electronic and paper mail.
@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school, You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary. if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>. <https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>. <https://www.gnu.org/licenses/why-not-lgpl.html>.

167
kernel/fs/fatfs/README.md Normal file
View File

@ -0,0 +1,167 @@
### FAT16/32 File System Library
Github: [http://github.com/ultraembedded/fat_io_lib](https://github.com/ultraembedded/fat_io_lib)
#### Intro
Designed for low memory embedded systems back in 2003, this project is a multi-purpose platform independent C code implementation of a FAT16 & FAT32 driver with read & write support.
The library provides stdio like interface functions such as fopen(), fgetc(), fputc(), fread(), fwrite() etc, allowing existing applications to be ported easily using a familiar API.
The project is aimed at applications which require file system support such as MP3 players, data loggers, etc and has a low memory footprint with customizable build options to enable it to run on platforms such as the Atmel AVR, ARM & PIC microcontrollers.
The source code is available for free under GPL license, or alternatively, with a commercial compatible license for a small donation.
This library has been used in many open source projects including;
* Aleph - Open source sound computer.
* IV:MP - Grand Theft Auto: IV multiplayer game mod.
* hxcfloppyemu - HxC Floppy Drive Emulator.
#### Features
* Standard file I/O API (fopen(), fread(), fwrite(), etc)
* FAT16/FAT32 support (read + write)
* Long filename support (optional)
* Format function (optional)
* Directory listing (optional)
* Buffering & caching for higher performance (optional)
#### API
The following file IO API is provided:
* fopen
* fclose
* fread
* fwrite
* fputc
* fputs
* fgetc
* fflush
* fgetpos
* fseek
* ftell
* feof
* remove
Just add sector read & write functions for the media/platform you are using for a complete file system!
#### Testing
Each release of the project is tested using self verifying test benches to ensure validity and to protect against regressions (not currently released).
#### Commercial
If you would like to use this code in a commercial project with a closed source compatible license, please contact me.
#### Configuration
See the following defines in src/fat_opts.h:
```
FATFS_IS_LITTLE_ENDIAN [1/0]
Which endian is your system? Set to 1 for little endian, 0 for big endian.
FATFS_MAX_LONG_FILENAME [260]
By default, 260 characters (max LFN length). Increase this to support greater path depths.
FATFS_MAX_OPEN_FILES
The more files you wish to have concurrently open, the greater this number should be.
This increases the number of FL_FILE file structures in the library, each of these is around 1K in size (assuming 512 byte sectors).
FAT_BUFFER_SECTORS
Minimum is 1, more increases performance.
This defines how many FAT sectors can be buffered per FAT_BUFFER entry.
FAT_BUFFERS
Minimum is 1, more increases performance.
This defines how many FAT buffer entries are available.
Memory usage is FAT_BUFFERS * FAT_BUFFER_SECTORS * FAT_SECTOR_SIZE
FATFS_INC_WRITE_SUPPORT
Support file write functionality.
FAT_SECTOR_SIZE
Sector size used by buffers. Most likely to be 512 bytes (standard for ATA/IDE).
FAT_PRINTF
A define that allows the File IO library to print to console/stdout.
Provide your own printf function if printf not available.
FAT_CLUSTER_CACHE_ENTRIES
Size of cluster chain cache (can be undefined if not required).
Mem used = FAT_CLUSTER_CACHE_ENTRIES * 4 * 2
Improves access speed considerably.
FATFS_INC_LFN_SUPPORT [1/0]
Enable/Disable support for long filenames.
FATFS_DIR_LIST_SUPPORT [1/0]
Include support for directory listing.
FATFS_INC_TIME_DATE_SUPPORT [1/0]
Use time/date functions provided by time.h to update creation & modification timestamps.
FATFS_INC_FORMAT_SUPPORT
Include support for formatting disks (FAT16 only).
FAT_PRINTF_NOINC_STDIO
Disable use of printf & inclusion of stdio.h
```
#### Interfacing to storage media
```
-----------------------------------------------------------------
int media_read(uint32 sector, uint8 *buffer, uint32 sector_count)
-----------------------------------------------------------------
Params:
Sector: 32-bit sector number
Buffer: Target buffer to read n sectors of data into.
Sector_count: Number of sectors to read
Return:
int, 1 = success, 0 = failure.
Description:
Application/target specific disk/media read function.
Sector number (sectors are usually 512 byte pages) to read.
-----------------------------------------------------------------
int media_write(uint32 sector, uint8 *buffer, uint32 sector_count)
-----------------------------------------------------------------
Params:
Sector: 32-bit sector number
Buffer: Target buffer to write n sectors of data from.
Sector_count: Number of sectors to write.
Return:
int, 1 = success, 0 = failure.
Description:
Application/target specific disk/media write function.
Sector number (sectors are usually 512 byte pages) to write to.
-----------------------------------------------------------------
Use the following API to attach the media IO functions to the File IO library;
fl_attach_media(media_read, media_write);
```
#### History
* v2.6.11 - Fix compilation with GCC on 64-bit machines
* v2.6.10 - Added support for FAT32 format.
* v2.6.9 - Added support for time & date handling.
* v2.6.8 - Fixed error with FSINFO sector write.
* v2.6.7 - Added fgets(). Fixed C warnings, removed dependency on some string.h functions.
* v2.6.6 - Massive read + write performance improvements.
* v2.6.5 - Bug fixes for big endian systems.
* v2.6.4 - Further bug fixes and performance improvements for write operations.
* v2.6.3 - Performance improvements, FAT16 formatting support. Various bug fixes
* v2.6 - Basic support for FAT16 added
* v2.5 - Code cleaned up. Many bugs fixed. Thread safety functions added.
* v2.x - Write support added as well as better stdio like API.
* v1.0 - Rewrite of all code to enable multiple files to be opened and provides a better file API.
* v0.1b - fopen(), fgetc(), fopenDIR() using new software stack for IDE drives and FAT32 access.
* v0.1a - First release; fopen(), fgetc() unbuffered reads.... (27/12/03)

View File

@ -0,0 +1,905 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// FAT File IO Library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include "fat_defs.h"
#include "fat_access.h"
#include "fat_table.h"
#include "fat_write.h"
#include "fat_string.h"
#include "fat_misc.h"
#include "fat_context.h"
//-----------------------------------------------------------------------------
// fatfs_init: Load FAT Parameters
//-----------------------------------------------------------------------------
int fatfs_init(struct fat_ctx *ctx, struct fatfs *fs)
{
uint8 num_of_fats;
uint16 reserved_sectors;
uint32 FATSz;
uint32 root_dir_sectors;
uint32 total_sectors;
uint32 data_sectors;
uint32 count_of_clusters;
uint8 valid_partition = 0;
fs->currentsector.address = FAT32_INVALID_CLUSTER;
fs->currentsector.dirty = 0;
fs->next_free_cluster = 0; // Invalid
fatfs_fat_init(fs);
// Make sure we have a read function (write function is optional)
if (!fs->disk_io.read_media)
return FAT_INIT_MEDIA_ACCESS_ERROR;
// MBR: Sector 0 on the disk
// NOTE: Some removeable media does not have this.
// Load MBR (LBA 0) into the 512 byte buffer
if (!fs->disk_io.read_media(ctx, 0, fs->currentsector.sector, 1))
return FAT_INIT_MEDIA_ACCESS_ERROR;
// Make Sure 0x55 and 0xAA are at end of sector
// (this should be the case regardless of the MBR or boot sector)
if (fs->currentsector.sector[SIGNATURE_POSITION] != 0x55 || fs->currentsector.sector[SIGNATURE_POSITION+1] != 0xAA)
return FAT_INIT_INVALID_SIGNATURE;
// Now check again using the access function to prove endian conversion function
if (GET_16BIT_WORD(fs->currentsector.sector, SIGNATURE_POSITION) != SIGNATURE_VALUE)
return FAT_INIT_ENDIAN_ERROR;
// Verify packed structures
if (sizeof(struct fat_dir_entry) != FAT_DIR_ENTRY_SIZE)
return FAT_INIT_STRUCT_PACKING;
// Check the partition type code
switch(fs->currentsector.sector[PARTITION1_TYPECODE_LOCATION])
{
case 0x0B:
case 0x06:
case 0x0C:
case 0x0E:
case 0x0F:
case 0x05:
valid_partition = 1;
break;
case 0x00:
valid_partition = 0;
break;
default:
if (fs->currentsector.sector[PARTITION1_TYPECODE_LOCATION] <= 0x06)
valid_partition = 1;
break;
}
// Read LBA Begin for the file system
if (valid_partition)
fs->lba_begin = GET_32BIT_WORD(fs->currentsector.sector, PARTITION1_LBA_BEGIN_LOCATION);
// Else possibly MBR less disk
else
fs->lba_begin = 0;
// Load Volume 1 table into sector buffer
// (We may already have this in the buffer if MBR less drive!)
if (!fs->disk_io.read_media(ctx, fs->lba_begin, fs->currentsector.sector, 1))
return FAT_INIT_MEDIA_ACCESS_ERROR;
// Make sure there are 512 bytes per cluster
if (GET_16BIT_WORD(fs->currentsector.sector, 0x0B) != FAT_SECTOR_SIZE)
return FAT_INIT_INVALID_SECTOR_SIZE;
// Load Parameters of FAT partition
fs->sectors_per_cluster = fs->currentsector.sector[BPB_SECPERCLUS];
reserved_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_RSVDSECCNT);
num_of_fats = fs->currentsector.sector[BPB_NUMFATS];
fs->root_entry_count = GET_16BIT_WORD(fs->currentsector.sector, BPB_ROOTENTCNT);
if(GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16) != 0)
fs->fat_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16);
else
fs->fat_sectors = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_FATSZ32);
// For FAT32 (which this may be)
fs->rootdir_first_cluster = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_ROOTCLUS);
fs->fs_info_sector = GET_16BIT_WORD(fs->currentsector.sector, BPB_FAT32_FSINFO);
// For FAT16 (which this may be), rootdir_first_cluster is actuall rootdir_first_sector
fs->rootdir_first_sector = reserved_sectors + (num_of_fats * fs->fat_sectors);
fs->rootdir_sectors = ((fs->root_entry_count * 32) + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
// First FAT LBA address
fs->fat_begin_lba = fs->lba_begin + reserved_sectors;
// The address of the first data cluster on this volume
fs->cluster_begin_lba = fs->fat_begin_lba + (num_of_fats * fs->fat_sectors);
if (GET_16BIT_WORD(fs->currentsector.sector, 0x1FE) != 0xAA55) // This signature should be AA55
return FAT_INIT_INVALID_SIGNATURE;
// Calculate the root dir sectors
root_dir_sectors = ((GET_16BIT_WORD(fs->currentsector.sector, BPB_ROOTENTCNT) * 32) + (GET_16BIT_WORD(fs->currentsector.sector, BPB_BYTSPERSEC) - 1)) / GET_16BIT_WORD(fs->currentsector.sector, BPB_BYTSPERSEC);
if(GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16) != 0)
FATSz = GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16);
else
FATSz = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_FATSZ32);
if(GET_16BIT_WORD(fs->currentsector.sector, BPB_TOTSEC16) != 0)
total_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_TOTSEC16);
else
total_sectors = GET_32BIT_WORD(fs->currentsector.sector, BPB_TOTSEC32);
data_sectors = total_sectors - (GET_16BIT_WORD(fs->currentsector.sector, BPB_RSVDSECCNT) + (fs->currentsector.sector[BPB_NUMFATS] * FATSz) + root_dir_sectors);
// Find out which version of FAT this is...
if (fs->sectors_per_cluster != 0)
{
count_of_clusters = data_sectors / fs->sectors_per_cluster;
if(count_of_clusters < 4085)
// Volume is FAT12
return FAT_INIT_WRONG_FILESYS_TYPE;
else if(count_of_clusters < 65525)
{
// Clear this FAT32 specific param
fs->rootdir_first_cluster = 0;
// Volume is FAT16
fs->fat_type = FAT_TYPE_16;
return FAT_INIT_OK;
}
else
{
// Volume is FAT32
fs->fat_type = FAT_TYPE_32;
return FAT_INIT_OK;
}
}
else
return FAT_INIT_WRONG_FILESYS_TYPE;
}
//-----------------------------------------------------------------------------
// fatfs_lba_of_cluster: This function converts a cluster number into a sector /
// LBA number.
//-----------------------------------------------------------------------------
uint32 fatfs_lba_of_cluster(struct fatfs *fs, uint32 Cluster_Number)
{
if (fs->fat_type == FAT_TYPE_16)
return (fs->cluster_begin_lba + (fs->root_entry_count * 32 / FAT_SECTOR_SIZE) + ((Cluster_Number-2) * fs->sectors_per_cluster));
else
return ((fs->cluster_begin_lba + ((Cluster_Number-2)*fs->sectors_per_cluster)));
}
//-----------------------------------------------------------------------------
// fatfs_sector_read:
//-----------------------------------------------------------------------------
int fatfs_sector_read(struct fat_ctx *ctx, struct fatfs *fs, uint32 lba, uint8 *target, uint32 count)
{
return fs->disk_io.read_media(ctx, lba, target, count);
}
//-----------------------------------------------------------------------------
// fatfs_sector_write:
//-----------------------------------------------------------------------------
int fatfs_sector_write(struct fat_ctx *ctx, struct fatfs *fs, uint32 lba, uint8 *target, uint32 count)
{
return fs->disk_io.write_media(ctx, lba, target, count);
}
//-----------------------------------------------------------------------------
// fatfs_sector_reader: From the provided startcluster and sector offset
// Returns True if success, returns False if not (including if read out of range)
//-----------------------------------------------------------------------------
int fatfs_sector_reader(struct fat_ctx *ctx, struct fatfs *fs, uint32 start_cluster, uint32 offset, uint8 *target)
{
uint32 sector_to_read = 0;
uint32 cluster_to_read = 0;
uint32 cluster_chain = 0;
uint32 i;
uint32 lba;
// FAT16 Root directory
if (fs->fat_type == FAT_TYPE_16 && start_cluster == 0)
{
if (offset < fs->rootdir_sectors)
lba = fs->lba_begin + fs->rootdir_first_sector + offset;
else
return 0;
}
// FAT16/32 Other
else
{
// Set start of cluster chain to initial value
cluster_chain = start_cluster;
// Find parameters
cluster_to_read = offset / fs->sectors_per_cluster;
sector_to_read = offset - (cluster_to_read*fs->sectors_per_cluster);
// Follow chain to find cluster to read
for (i=0; i<cluster_to_read; i++)
cluster_chain = fatfs_find_next_cluster(ctx, fs, cluster_chain);
// If end of cluster chain then return false
if (cluster_chain == FAT32_LAST_CLUSTER)
return 0;
// Calculate sector address
lba = fatfs_lba_of_cluster(fs, cluster_chain)+sector_to_read;
}
// User provided target array
if (target)
return fs->disk_io.read_media(ctx, lba, target, 1);
// Else read sector if not already loaded
else if (lba != fs->currentsector.address)
{
fs->currentsector.address = lba;
return fs->disk_io.read_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
else
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_read_sector: Read from the provided cluster and sector offset
// Returns True if success, returns False if not
//-----------------------------------------------------------------------------
int fatfs_read_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target)
{
// FAT16 Root directory
if (fs->fat_type == FAT_TYPE_16 && cluster == 0)
{
uint32 lba;
// In FAT16, there are a limited amount of sectors in root dir!
if (sector < fs->rootdir_sectors)
lba = fs->lba_begin + fs->rootdir_first_sector + sector;
else
return 0;
// User target buffer passed in
if (target)
{
// Read from disk
return fs->disk_io.read_media(ctx, lba, target, 1);
}
else
{
// Calculate read address
fs->currentsector.address = lba;
// Read from disk
return fs->disk_io.read_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
}
// FAT16/32 Other
else
{
// User target buffer passed in
if (target)
{
// Calculate read address
uint32 lba = fatfs_lba_of_cluster(fs, cluster) + sector;
// Read from disk
return fs->disk_io.read_media(ctx, lba, target, 1);
}
else
{
// Calculate write address
fs->currentsector.address = fatfs_lba_of_cluster(fs, cluster)+sector;
// Read from disk
return fs->disk_io.read_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
}
}
//-----------------------------------------------------------------------------
// fatfs_write_sector: Write to the provided cluster and sector offset
// Returns True if success, returns False if not
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_write_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target)
{
// No write access?
if (!fs->disk_io.write_media)
return 0;
// FAT16 Root directory
if (fs->fat_type == FAT_TYPE_16 && cluster == 0)
{
uint32 lba;
// In FAT16 we cannot extend the root dir!
if (sector < fs->rootdir_sectors)
lba = fs->lba_begin + fs->rootdir_first_sector + sector;
else
return 0;
// User target buffer passed in
if (target)
{
// Write to disk
return fs->disk_io.write_media(ctx, lba, target, 1);
}
else
{
// Calculate write address
fs->currentsector.address = lba;
// Write to disk
return fs->disk_io.write_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
}
// FAT16/32 Other
else
{
// User target buffer passed in
if (target)
{
// Calculate write address
uint32 lba = fatfs_lba_of_cluster(fs, cluster) + sector;
// Write to disk
return fs->disk_io.write_media(ctx, lba, target, 1);
}
else
{
// Calculate write address
fs->currentsector.address = fatfs_lba_of_cluster(fs, cluster)+sector;
// Write to disk
return fs->disk_io.write_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
}
}
#endif
//-----------------------------------------------------------------------------
// fatfs_show_details: Show the details about the filesystem
//-----------------------------------------------------------------------------
void fatfs_show_details(struct fatfs *fs)
{
FAT_PRINTF(("FAT details:\r\n"));
FAT_PRINTF((" Type =%s", (fs->fat_type == FAT_TYPE_32) ? "FAT32": "FAT16"));
FAT_PRINTF((" Root Dir First Cluster = %x\r\n", fs->rootdir_first_cluster));
FAT_PRINTF((" FAT Begin LBA = 0x%x\r\n",fs->fat_begin_lba));
FAT_PRINTF((" Cluster Begin LBA = 0x%x\r\n",fs->cluster_begin_lba));
FAT_PRINTF((" Sectors Per Cluster = %d\r\n", fs->sectors_per_cluster));
}
//-----------------------------------------------------------------------------
// fatfs_get_root_cluster: Get the root dir cluster
//-----------------------------------------------------------------------------
uint32 fatfs_get_root_cluster(struct fatfs *fs)
{
// NOTE: On FAT16 this will be 0 which has a special meaning...
return fs->rootdir_first_cluster;
}
//-------------------------------------------------------------
// fatfs_get_file_entry: Find the file entry for a filename
//-------------------------------------------------------------
uint32 fatfs_get_file_entry(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *name_to_find, struct fat_dir_entry *sfEntry)
{
uint8 item=0;
uint16 recordoffset = 0;
uint8 i=0;
int x=0;
char *long_filename = NULL;
char short_filename[13];
struct lfn_cache lfn;
int dotRequired = 0;
struct fat_dir_entry *directoryEntry;
fatfs_lfn_cache_init(&lfn, 1);
// Main cluster following loop
while (1)
{
// Read sector
if (fatfs_sector_reader(ctx, fs, Cluster, x++, 0)) // If sector read was successfull
{
// Analyse Sector
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Create the multiplier for sector access
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
#if FATFS_INC_LFN_SUPPORT
// Long File Name Text Found
if (fatfs_entry_lfn_text(directoryEntry) )
fatfs_lfn_cache_entry(&lfn, fs->currentsector.sector+recordoffset);
// If Invalid record found delete any long file name information collated
else if (fatfs_entry_lfn_invalid(directoryEntry) )
fatfs_lfn_cache_init(&lfn, 0);
// Normal SFN Entry and Long text exists
else if (fatfs_entry_lfn_exists(&lfn, directoryEntry) )
{
long_filename = fatfs_lfn_cache_get(&lfn);
// Compare names to see if they match
if (fatfs_compare_names(long_filename, name_to_find))
{
memcpy(sfEntry,directoryEntry,sizeof(struct fat_dir_entry));
return 1;
}
fatfs_lfn_cache_init(&lfn, 0);
}
else
#endif
// Normal Entry, only 8.3 Text
if (fatfs_entry_sfn_only(directoryEntry) )
{
memset(short_filename, 0, sizeof(short_filename));
// Copy name to string
for (i=0; i<8; i++)
short_filename[i] = directoryEntry->Name[i];
// Extension
dotRequired = 0;
for (i=8; i<11; i++)
{
short_filename[i+1] = directoryEntry->Name[i];
if (directoryEntry->Name[i] != ' ')
dotRequired = 1;
}
// Dot only required if extension present
if (dotRequired)
{
// If not . or .. entry
if (short_filename[0]!='.')
short_filename[8] = '.';
else
short_filename[8] = ' ';
}
else
short_filename[8] = ' ';
// Compare names to see if they match
if (fatfs_compare_names(short_filename, name_to_find))
{
memcpy(sfEntry,directoryEntry,sizeof(struct fat_dir_entry));
return 1;
}
fatfs_lfn_cache_init(&lfn, 0);
}
} // End of if
}
else
break;
} // End of while loop
return 0;
}
//-------------------------------------------------------------
// fatfs_sfn_exists: Check if a short filename exists.
// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY
//-------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_sfn_exists(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname)
{
uint8 item=0;
uint16 recordoffset = 0;
int x=0;
struct fat_dir_entry *directoryEntry;
// Main cluster following loop
while (1)
{
// Read sector
if (fatfs_sector_reader(ctx, fs, Cluster, x++, 0)) // If sector read was successfull
{
// Analyse Sector
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Create the multiplier for sector access
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
#if FATFS_INC_LFN_SUPPORT
// Long File Name Text Found
if (fatfs_entry_lfn_text(directoryEntry) )
;
// If Invalid record found delete any long file name information collated
else if (fatfs_entry_lfn_invalid(directoryEntry) )
;
else
#endif
// Normal Entry, only 8.3 Text
if (fatfs_entry_sfn_only(directoryEntry) )
{
if (strncmp((const char*)directoryEntry->Name, shortname, 11)==0)
return 1;
}
} // End of if
}
else
break;
} // End of while loop
return 0;
}
#endif
//-------------------------------------------------------------
// fatfs_update_timestamps: Update date/time details
//-------------------------------------------------------------
#if FATFS_INC_TIME_DATE_SUPPORT
int fatfs_update_timestamps(struct fat_dir_entry *directoryEntry, int create, int modify, int access)
{
time_t time_now;
struct tm * time_info;
uint16 fat_time;
uint16 fat_date;
// Get system time
time(&time_now);
// Convert to local time
time_info = localtime(&time_now);
// Convert time to FAT format
fat_time = fatfs_convert_to_fat_time(time_info->tm_hour, time_info->tm_min, time_info->tm_sec);
// Convert date to FAT format
fat_date = fatfs_convert_to_fat_date(time_info->tm_mday, time_info->tm_mon + 1, time_info->tm_year + 1900);
// Update requested fields
if (create)
{
directoryEntry->CrtTime[1] = fat_time >> 8;
directoryEntry->CrtTime[0] = fat_time >> 0;
directoryEntry->CrtDate[1] = fat_date >> 8;
directoryEntry->CrtDate[0] = fat_date >> 0;
}
if (modify)
{
directoryEntry->WrtTime[1] = fat_time >> 8;
directoryEntry->WrtTime[0] = fat_time >> 0;
directoryEntry->WrtDate[1] = fat_date >> 8;
directoryEntry->WrtDate[0] = fat_date >> 0;
}
if (access)
{
directoryEntry->LstAccDate[1] = fat_time >> 8;
directoryEntry->LstAccDate[0] = fat_time >> 0;
directoryEntry->LstAccDate[1] = fat_date >> 8;
directoryEntry->LstAccDate[0] = fat_date >> 0;
}
return 1;
}
#endif
//-------------------------------------------------------------
// fatfs_update_file_length: Find a SFN entry and update it
// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY
//-------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_update_file_length(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname, uint32 fileLength)
{
uint8 item=0;
uint16 recordoffset = 0;
int x=0;
struct fat_dir_entry *directoryEntry;
// No write access?
if (!fs->disk_io.write_media)
return 0;
// Main cluster following loop
while (1)
{
// Read sector
if (fatfs_sector_reader(ctx, fs, Cluster, x++, 0)) // If sector read was successfull
{
// Analyse Sector
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Create the multiplier for sector access
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
#if FATFS_INC_LFN_SUPPORT
// Long File Name Text Found
if (fatfs_entry_lfn_text(directoryEntry) )
;
// If Invalid record found delete any long file name information collated
else if (fatfs_entry_lfn_invalid(directoryEntry) )
;
// Normal Entry, only 8.3 Text
else
#endif
if (fatfs_entry_sfn_only(directoryEntry) )
{
if (strncmp((const char*)directoryEntry->Name, shortname, 11)==0)
{
directoryEntry->FileSize = FAT_HTONL(fileLength);
#if FATFS_INC_TIME_DATE_SUPPORT
// Update access / modify time & date
fatfs_update_timestamps(directoryEntry, 0, 1, 1);
#endif
// Update sfn entry
memcpy((uint8*)(fs->currentsector.sector+recordoffset), (uint8*)directoryEntry, sizeof(struct fat_dir_entry));
// Write sector back
return fs->disk_io.write_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
}
} // End of if
}
else
break;
} // End of while loop
return 0;
}
#endif
//-------------------------------------------------------------
// fatfs_mark_file_deleted: Find a SFN entry and mark if as deleted
// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY
//-------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_mark_file_deleted(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname)
{
uint8 item=0;
uint16 recordoffset = 0;
int x=0;
struct fat_dir_entry *directoryEntry;
// No write access?
if (!fs->disk_io.write_media)
return 0;
// Main cluster following loop
while (1)
{
// Read sector
if (fatfs_sector_reader(ctx, fs, Cluster, x++, 0)) // If sector read was successfull
{
// Analyse Sector
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Create the multiplier for sector access
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
#if FATFS_INC_LFN_SUPPORT
// Long File Name Text Found
if (fatfs_entry_lfn_text(directoryEntry) )
;
// If Invalid record found delete any long file name information collated
else if (fatfs_entry_lfn_invalid(directoryEntry) )
;
// Normal Entry, only 8.3 Text
else
#endif
if (fatfs_entry_sfn_only(directoryEntry) )
{
if (strncmp((const char *)directoryEntry->Name, shortname, 11)==0)
{
// Mark as deleted
directoryEntry->Name[0] = FILE_HEADER_DELETED;
#if FATFS_INC_TIME_DATE_SUPPORT
// Update access / modify time & date
fatfs_update_timestamps(directoryEntry, 0, 1, 1);
#endif
// Update sfn entry
memcpy((uint8*)(fs->currentsector.sector+recordoffset), (uint8*)directoryEntry, sizeof(struct fat_dir_entry));
// Write sector back
return fs->disk_io.write_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
}
} // End of if
}
else
break;
} // End of while loop
return 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_list_directory_start: Initialise a directory listing procedure
//-----------------------------------------------------------------------------
#if FATFS_DIR_LIST_SUPPORT
void fatfs_list_directory_start(struct fatfs *fs, struct fs_dir_list_status *dirls, uint32 StartCluster)
{
dirls->cluster = StartCluster;
dirls->sector = 0;
dirls->offset = 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_list_directory_next: Get the next entry in the directory.
// Returns: 1 = found, 0 = end of listing
//-----------------------------------------------------------------------------
#if FATFS_DIR_LIST_SUPPORT
int fatfs_list_directory_next(struct fat_ctx *ctx, struct fatfs *fs, struct fs_dir_list_status *dirls, struct fs_dir_ent *entry)
{
uint8 i,item;
uint16 recordoffset;
struct fat_dir_entry *directoryEntry;
char *long_filename = NULL;
char short_filename[13];
struct lfn_cache lfn;
int dotRequired = 0;
int result = 0;
// Initialise LFN cache first
fatfs_lfn_cache_init(&lfn, 0);
while (1)
{
// If data read OK
if (fatfs_sector_reader(ctx, fs, dirls->cluster, dirls->sector, 0))
{
// Maximum of 16 directory entries
for (item = dirls->offset; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Increase directory offset
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
#if FATFS_INC_LFN_SUPPORT
// Long File Name Text Found
if ( fatfs_entry_lfn_text(directoryEntry) )
fatfs_lfn_cache_entry(&lfn, fs->currentsector.sector+recordoffset);
// If Invalid record found delete any long file name information collated
else if ( fatfs_entry_lfn_invalid(directoryEntry) )
fatfs_lfn_cache_init(&lfn, 0);
// Normal SFN Entry and Long text exists
else if (fatfs_entry_lfn_exists(&lfn, directoryEntry) )
{
// Get text
long_filename = fatfs_lfn_cache_get(&lfn);
strncpy(entry->filename, long_filename, FATFS_MAX_LONG_FILENAME-1);
if (fatfs_entry_is_dir(directoryEntry))
entry->is_dir = 1;
else
entry->is_dir = 0;
#if FATFS_INC_TIME_DATE_SUPPORT
// Get time / dates
entry->create_time = ((uint16)directoryEntry->CrtTime[1] << 8) | directoryEntry->CrtTime[0];
entry->create_date = ((uint16)directoryEntry->CrtDate[1] << 8) | directoryEntry->CrtDate[0];
entry->access_date = ((uint16)directoryEntry->LstAccDate[1] << 8) | directoryEntry->LstAccDate[0];
entry->write_time = ((uint16)directoryEntry->WrtTime[1] << 8) | directoryEntry->WrtTime[0];
entry->write_date = ((uint16)directoryEntry->WrtDate[1] << 8) | directoryEntry->WrtDate[0];
#endif
entry->size = FAT_HTONL(directoryEntry->FileSize);
entry->cluster = (FAT_HTONS(directoryEntry->FstClusHI)<<16) | FAT_HTONS(directoryEntry->FstClusLO);
// Next starting position
dirls->offset = item + 1;
result = 1;
return 1;
}
// Normal Entry, only 8.3 Text
else
#endif
if ( fatfs_entry_sfn_only(directoryEntry) )
{
fatfs_lfn_cache_init(&lfn, 0);
memset(short_filename, 0, sizeof(short_filename));
// Copy name to string
for (i=0; i<8; i++)
short_filename[i] = directoryEntry->Name[i];
// Extension
dotRequired = 0;
for (i=8; i<11; i++)
{
short_filename[i+1] = directoryEntry->Name[i];
if (directoryEntry->Name[i] != ' ')
dotRequired = 1;
}
// Dot only required if extension present
if (dotRequired)
{
// If not . or .. entry
if (short_filename[0]!='.')
short_filename[8] = '.';
else
short_filename[8] = ' ';
}
else
short_filename[8] = ' ';
fatfs_get_sfn_display_name(entry->filename, short_filename);
if (fatfs_entry_is_dir(directoryEntry))
entry->is_dir = 1;
else
entry->is_dir = 0;
#if FATFS_INC_TIME_DATE_SUPPORT
// Get time / dates
entry->create_time = ((uint16)directoryEntry->CrtTime[1] << 8) | directoryEntry->CrtTime[0];
entry->create_date = ((uint16)directoryEntry->CrtDate[1] << 8) | directoryEntry->CrtDate[0];
entry->access_date = ((uint16)directoryEntry->LstAccDate[1] << 8) | directoryEntry->LstAccDate[0];
entry->write_time = ((uint16)directoryEntry->WrtTime[1] << 8) | directoryEntry->WrtTime[0];
entry->write_date = ((uint16)directoryEntry->WrtDate[1] << 8) | directoryEntry->WrtDate[0];
#endif
entry->size = FAT_HTONL(directoryEntry->FileSize);
entry->cluster = (FAT_HTONS(directoryEntry->FstClusHI)<<16) | FAT_HTONS(directoryEntry->FstClusLO);
// Next starting position
dirls->offset = item + 1;
result = 1;
return 1;
}
}// end of for
// If reached end of the dir move onto next sector
dirls->sector++;
dirls->offset = 0;
}
else
break;
}
return result;
}
#endif

View File

@ -0,0 +1,135 @@
#ifndef __FAT_ACCESS_H__
#define __FAT_ACCESS_H__
#include "fat_defs.h"
#include "fat_opts.h"
struct fat_ctx;
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#define FAT_INIT_OK 0
#define FAT_INIT_MEDIA_ACCESS_ERROR (-1)
#define FAT_INIT_INVALID_SECTOR_SIZE (-2)
#define FAT_INIT_INVALID_SIGNATURE (-3)
#define FAT_INIT_ENDIAN_ERROR (-4)
#define FAT_INIT_WRONG_FILESYS_TYPE (-5)
#define FAT_INIT_WRONG_PARTITION_TYPE (-6)
#define FAT_INIT_STRUCT_PACKING (-7)
#define FAT_DIR_ENTRIES_PER_SECTOR (FAT_SECTOR_SIZE / FAT_DIR_ENTRY_SIZE)
//-----------------------------------------------------------------------------
// Function Pointers
//-----------------------------------------------------------------------------
typedef int (*fn_diskio_read) (struct fat_ctx *ctx, uint32 sector, uint8 *buffer, uint32 sector_count);
typedef int (*fn_diskio_write)(struct fat_ctx *ctx, uint32 sector, uint8 *buffer, uint32 sector_count);
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct disk_if
{
// User supplied function pointers for disk IO
fn_diskio_read read_media;
fn_diskio_write write_media;
};
// Forward declaration
struct fat_buffer;
struct fat_buffer
{
uint8 sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
uint32 address;
int dirty;
uint8 * ptr;
// Next in chain of sector buffers
struct fat_buffer *next;
};
typedef enum eFatType
{
FAT_TYPE_16,
FAT_TYPE_32
} tFatType;
struct fatfs
{
// Filesystem globals
uint8 sectors_per_cluster;
uint32 cluster_begin_lba;
uint32 rootdir_first_cluster;
uint32 rootdir_first_sector;
uint32 rootdir_sectors;
uint32 fat_begin_lba;
uint16 fs_info_sector;
uint32 lba_begin;
uint32 fat_sectors;
uint32 next_free_cluster;
uint16 root_entry_count;
uint16 reserved_sectors;
uint8 num_of_fats;
tFatType fat_type;
// Disk/Media API
struct disk_if disk_io;
// [Optional] Thread Safety
void (*fl_lock)(void);
void (*fl_unlock)(void);
// Working buffer
struct fat_buffer currentsector;
// FAT Buffer
struct fat_buffer *fat_buffer_head;
struct fat_buffer fat_buffers[FAT_BUFFERS];
};
struct fs_dir_list_status
{
uint32 sector;
uint32 cluster;
uint8 offset;
};
struct fs_dir_ent
{
char filename[FATFS_MAX_LONG_FILENAME];
uint8 is_dir;
uint32 cluster;
uint32 size;
#if FATFS_INC_TIME_DATE_SUPPORT
uint16 access_date;
uint16 write_time;
uint16 write_date;
uint16 create_date;
uint16 create_time;
#endif
};
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_init(struct fat_ctx *ctx, struct fatfs *fs);
uint32 fatfs_lba_of_cluster(struct fatfs *fs, uint32 Cluster_Number);
int fatfs_sector_reader(struct fat_ctx *ctx, struct fatfs *fs, uint32 Startcluster, uint32 offset, uint8 *target);
int fatfs_sector_read(struct fat_ctx *ctx, struct fatfs *fs, uint32 lba, uint8 *target, uint32 count);
int fatfs_sector_write(struct fat_ctx *ctx, struct fatfs *fs, uint32 lba, uint8 *target, uint32 count);
int fatfs_read_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target);
int fatfs_write_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target);
void fatfs_show_details(struct fatfs *fs);
uint32 fatfs_get_root_cluster(struct fatfs *fs);
uint32 fatfs_get_file_entry(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *nametofind, struct fat_dir_entry *sfEntry);
int fatfs_sfn_exists(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname);
int fatfs_update_file_length(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname, uint32 fileLength);
int fatfs_mark_file_deleted(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname);
void fatfs_list_directory_start(struct fatfs *fs, struct fs_dir_list_status *dirls, uint32 StartCluster);
int fatfs_list_directory_next(struct fat_ctx *ctx, struct fatfs *fs, struct fs_dir_list_status *dirls, struct fs_dir_ent *entry);
int fatfs_update_timestamps(struct fat_dir_entry *directoryEntry, int create, int modify, int access);
#endif

View File

@ -0,0 +1,91 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// FAT File IO Library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include "fat_cache.h"
// Per file cluster chain caching used to improve performance.
// This does not have to be enabled for architectures with low
// memory space.
//-----------------------------------------------------------------------------
// fatfs_cache_init:
//-----------------------------------------------------------------------------
int fatfs_cache_init(struct fatfs *fs, FL_FILE *file)
{
#ifdef FAT_CLUSTER_CACHE_ENTRIES
int i;
for (i=0;i<FAT_CLUSTER_CACHE_ENTRIES;i++)
{
file->cluster_cache_idx[i] = 0xFFFFFFFF; // Not used
file->cluster_cache_data[i] = 0;
}
#endif
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_cache_get_next_cluster:
//-----------------------------------------------------------------------------
int fatfs_cache_get_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 *pNextCluster)
{
#ifdef FAT_CLUSTER_CACHE_ENTRIES
uint32 slot = clusterIdx % FAT_CLUSTER_CACHE_ENTRIES;
if (file->cluster_cache_idx[slot] == clusterIdx)
{
*pNextCluster = file->cluster_cache_data[slot];
return 1;
}
#endif
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_cache_set_next_cluster:
//-----------------------------------------------------------------------------
int fatfs_cache_set_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 nextCluster)
{
#ifdef FAT_CLUSTER_CACHE_ENTRIES
uint32 slot = clusterIdx % FAT_CLUSTER_CACHE_ENTRIES;
if (file->cluster_cache_idx[slot] == clusterIdx)
file->cluster_cache_data[slot] = nextCluster;
else
{
file->cluster_cache_idx[slot] = clusterIdx;
file->cluster_cache_data[slot] = nextCluster;
}
#endif
return 1;
}

View File

@ -0,0 +1,13 @@
#ifndef __FAT_CACHE_H__
#define __FAT_CACHE_H__
#include "fat_filelib.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_cache_init(struct fatfs *fs, FL_FILE *file);
int fatfs_cache_get_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 *pNextCluster);
int fatfs_cache_set_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 nextCluster);
#endif

View File

@ -0,0 +1,17 @@
#ifndef FAT_CONTEXT_H_
#define FAT_CONTEXT_H_
#include "fat_defs.h"
#include "fat_filelib.h"
struct fat_ctx {
FL_FILE _files[FATFS_MAX_OPEN_FILES];
int _filelib_init;
int _filelib_valid;
struct fatfs _fs;
struct fat_list _open_file_list;
struct fat_list _free_file_list;
void *extra;
};
#endif // FAT_CONTEXT_H_

128
kernel/fs/fatfs/fat_defs.h Normal file
View File

@ -0,0 +1,128 @@
#ifndef __FAT_DEFS_H__
#define __FAT_DEFS_H__
#include "fat_opts.h"
#include "fat_types.h"
//-----------------------------------------------------------------------------
// FAT32 Offsets
// Name Offset
//-----------------------------------------------------------------------------
// Boot Sector
#define BS_JMPBOOT 0 // Length = 3
#define BS_OEMNAME 3 // Length = 8
#define BPB_BYTSPERSEC 11 // Length = 2
#define BPB_SECPERCLUS 13 // Length = 1
#define BPB_RSVDSECCNT 14 // Length = 2
#define BPB_NUMFATS 16 // Length = 1
#define BPB_ROOTENTCNT 17 // Length = 2
#define BPB_TOTSEC16 19 // Length = 2
#define BPB_MEDIA 21 // Length = 1
#define BPB_FATSZ16 22 // Length = 2
#define BPB_SECPERTRK 24 // Length = 2
#define BPB_NUMHEADS 26 // Length = 2
#define BPB_HIDDSEC 28 // Length = 4
#define BPB_TOTSEC32 32 // Length = 4
// FAT 12/16
#define BS_FAT_DRVNUM 36 // Length = 1
#define BS_FAT_BOOTSIG 38 // Length = 1
#define BS_FAT_VOLID 39 // Length = 4
#define BS_FAT_VOLLAB 43 // Length = 11
#define BS_FAT_FILSYSTYPE 54 // Length = 8
// FAT 32
#define BPB_FAT32_FATSZ32 36 // Length = 4
#define BPB_FAT32_EXTFLAGS 40 // Length = 2
#define BPB_FAT32_FSVER 42 // Length = 2
#define BPB_FAT32_ROOTCLUS 44 // Length = 4
#define BPB_FAT32_FSINFO 48 // Length = 2
#define BPB_FAT32_BKBOOTSEC 50 // Length = 2
#define BS_FAT32_DRVNUM 64 // Length = 1
#define BS_FAT32_BOOTSIG 66 // Length = 1
#define BS_FAT32_VOLID 67 // Length = 4
#define BS_FAT32_VOLLAB 71 // Length = 11
#define BS_FAT32_FILSYSTYPE 82 // Length = 8
//-----------------------------------------------------------------------------
// FAT Types
//-----------------------------------------------------------------------------
#define FAT_TYPE_FAT12 1
#define FAT_TYPE_FAT16 2
#define FAT_TYPE_FAT32 3
//-----------------------------------------------------------------------------
// FAT32 Specific Statics
//-----------------------------------------------------------------------------
#define SIGNATURE_POSITION 510
#define SIGNATURE_VALUE 0xAA55
#define PARTITION1_TYPECODE_LOCATION 450
#define FAT32_TYPECODE1 0x0B
#define FAT32_TYPECODE2 0x0C
#define PARTITION1_LBA_BEGIN_LOCATION 454
#define PARTITION1_SIZE_LOCATION 458
#define FAT_DIR_ENTRY_SIZE 32
#define FAT_SFN_SIZE_FULL 11
#define FAT_SFN_SIZE_PARTIAL 8
//-----------------------------------------------------------------------------
// FAT32 File Attributes and Types
//-----------------------------------------------------------------------------
#define FILE_ATTR_READ_ONLY 0x01
#define FILE_ATTR_HIDDEN 0x02
#define FILE_ATTR_SYSTEM 0x04
#define FILE_ATTR_SYSHID 0x06
#define FILE_ATTR_VOLUME_ID 0x08
#define FILE_ATTR_DIRECTORY 0x10
#define FILE_ATTR_ARCHIVE 0x20
#define FILE_ATTR_LFN_TEXT 0x0F
#define FILE_HEADER_BLANK 0x00
#define FILE_HEADER_DELETED 0xE5
#define FILE_TYPE_DIR 0x10
#define FILE_TYPE_FILE 0x20
//-----------------------------------------------------------------------------
// Time / Date details
//-----------------------------------------------------------------------------
#define FAT_TIME_HOURS_SHIFT 11
#define FAT_TIME_HOURS_MASK 0x1F
#define FAT_TIME_MINUTES_SHIFT 5
#define FAT_TIME_MINUTES_MASK 0x3F
#define FAT_TIME_SECONDS_SHIFT 0
#define FAT_TIME_SECONDS_MASK 0x1F
#define FAT_TIME_SECONDS_SCALE 2
#define FAT_DATE_YEAR_SHIFT 9
#define FAT_DATE_YEAR_MASK 0x7F
#define FAT_DATE_MONTH_SHIFT 5
#define FAT_DATE_MONTH_MASK 0xF
#define FAT_DATE_DAY_SHIFT 0
#define FAT_DATE_DAY_MASK 0x1F
#define FAT_DATE_YEAR_OFFSET 1980
//-----------------------------------------------------------------------------
// Other Defines
//-----------------------------------------------------------------------------
#define FAT32_LAST_CLUSTER 0xFFFFFFFF
#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
STRUCT_PACK_BEGIN
struct fat_dir_entry STRUCT_PACK
{
uint8 Name[11];
uint8 Attr;
uint8 NTRes;
uint8 CrtTimeTenth;
uint8 CrtTime[2];
uint8 CrtDate[2];
uint8 LstAccDate[2];
uint16 FstClusHI;
uint8 WrtTime[2];
uint8 WrtDate[2];
uint16 FstClusLO;
uint32 FileSize;
} STRUCT_PACKED;
STRUCT_PACK_END
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,148 @@
#ifndef __FAT_FILELIB_H__
#define __FAT_FILELIB_H__
#include "fat_opts.h"
#include "fat_access.h"
#include "fat_list.h"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef EOF
#define EOF (-1)
#endif
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct sFL_FILE;
struct fat_ctx;
struct cluster_lookup
{
uint32 ClusterIdx;
uint32 CurrentCluster;
};
typedef struct sFL_FILE
{
uint32 parentcluster;
uint32 startcluster;
uint32 bytenum;
uint32 filelength;
int filelength_changed;
char path[FATFS_MAX_LONG_FILENAME];
char filename[FATFS_MAX_LONG_FILENAME];
uint8 shortfilename[11];
#ifdef FAT_CLUSTER_CACHE_ENTRIES
uint32 cluster_cache_idx[FAT_CLUSTER_CACHE_ENTRIES];
uint32 cluster_cache_data[FAT_CLUSTER_CACHE_ENTRIES];
#endif
// Cluster Lookup
struct cluster_lookup last_fat_lookup;
// Read/Write sector buffer
uint8 file_data_sector[FAT_SECTOR_SIZE];
uint32 file_data_address;
int file_data_dirty;
// File fopen flags
uint8 flags;
#define FILE_READ (1 << 0)
#define FILE_WRITE (1 << 1)
#define FILE_APPEND (1 << 2)
#define FILE_BINARY (1 << 3)
#define FILE_ERASE (1 << 4)
#define FILE_CREATE (1 << 5)
struct fat_node list_node;
} FL_FILE;
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
// External
void fl_init(struct fat_ctx *ctx);
void fl_attach_locks(struct fat_ctx *ctx, void (*lock)(void), void (*unlock)(void));
int fl_attach_media(struct fat_ctx *ctx, fn_diskio_read rd, fn_diskio_write wr);
void fl_shutdown(struct fat_ctx *ctx);
// Standard API
void* fl_fopen(struct fat_ctx *ctx, const char *path, const char *modifiers);
void fl_fclose(struct fat_ctx *ctx, void *file);
int fl_fflush(struct fat_ctx *ctx, void *file);
int fl_fgetc(struct fat_ctx *ctx, void *file);
char * fl_fgets(struct fat_ctx *ctx, char *s, int n, void *f);
int fl_fputc(struct fat_ctx *ctx, int c, void *file);
int fl_fputs(struct fat_ctx *ctx, const char * str, void *file);
int fl_fwrite(struct fat_ctx *ctx, const void * data, int size, int count, void *file );
int fl_fread(struct fat_ctx *ctx, void * data, int size, int count, void *file );
int fl_fseek(struct fat_ctx *ctx, void *file , long offset , int origin );
int fl_fgetpos(struct fat_ctx *ctx, void *file , uint32 * position);
long fl_ftell(struct fat_ctx *ctx, void *f);
int fl_feof(struct fat_ctx *ctx, void *f);
int fl_remove(struct fat_ctx *ctx, const char * filename);
// Equivelant dirent.h
typedef struct fs_dir_list_status FL_DIR;
typedef struct fs_dir_ent fl_dirent;
FL_DIR* fl_opendir(struct fat_ctx *ctx, const char* path, FL_DIR *dir);
int fl_readdir(struct fat_ctx *ctx, FL_DIR *dirls, fl_dirent *entry);
int fl_closedir(struct fat_ctx *ctx, FL_DIR* dir);
// Extensions
void fl_listdirectory(struct fat_ctx *ctx, const char *path);
int fl_createdirectory(struct fat_ctx *ctx, const char *path);
int fl_is_dir(struct fat_ctx *ctx, const char *path);
int fl_format(struct fat_ctx *ctx, uint32 volume_sectors, const char *name);
// Test hooks
#ifdef FATFS_INC_TEST_HOOKS
struct fatfs* fl_get_fs(struct fat_ctx *ctx);
#endif
//-----------------------------------------------------------------------------
// Stdio file I/O names
//-----------------------------------------------------------------------------
#ifdef USE_FILELIB_STDIO_COMPAT_NAMES
#define FILE FL_FILE
#define fopen(a,b) fl_fopen(a, b)
#define fclose(a) fl_fclose(a)
#define fflush(a) fl_fflush(a)
#define fgetc(a) fl_fgetc(a)
#define fgets(a,b,c) fl_fgets(a, b, c)
#define fputc(a,b) fl_fputc(a, b)
#define fputs(a,b) fl_fputs(a, b)
#define fwrite(a,b,c,d) fl_fwrite(a, b, c, d)
#define fread(a,b,c,d) fl_fread(a, b, c, d)
#define fseek(a,b,c) fl_fseek(a, b, c)
#define fgetpos(a,b) fl_fgetpos(a, b)
#define ftell(a) fl_ftell(a)
#define feof(a) fl_feof(a)
#define remove(a) fl_remove(a)
#define mkdir(a) fl_createdirectory(a)
#define rmdir(a) 0
#endif
#endif

View File

@ -0,0 +1,532 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// FAT File IO Library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include "fat_defs.h"
#include "fat_access.h"
#include "fat_table.h"
#include "fat_write.h"
#include "fat_string.h"
#include "fat_misc.h"
#include "fat_format.h"
#if FATFS_INC_FORMAT_SUPPORT
//-----------------------------------------------------------------------------
// Tables
//-----------------------------------------------------------------------------
struct sec_per_clus_table
{
uint32 sectors;
uint8 sectors_per_cluster;
};
struct sec_per_clus_table _cluster_size_table16[] =
{
{ 32680, 2}, // 16MB - 1K
{ 262144, 4}, // 128MB - 2K
{ 524288, 8}, // 256MB - 4K
{ 1048576, 16}, // 512MB - 8K
{ 2097152, 32}, // 1GB - 16K
{ 4194304, 64}, // 2GB - 32K
{ 8388608, 128},// 2GB - 64K [Warning only supported by Windows XP onwards]
{ 0 , 0 } // Invalid
};
struct sec_per_clus_table _cluster_size_table32[] =
{
{ 532480, 1}, // 260MB - 512b
{ 16777216, 8}, // 8GB - 4K
{ 33554432, 16}, // 16GB - 8K
{ 67108864, 32}, // 32GB - 16K
{ 0xFFFFFFFF, 64},// >32GB - 32K
{ 0 , 0 } // Invalid
};
//-----------------------------------------------------------------------------
// fatfs_calc_cluster_size: Calculate what cluster size should be used
//-----------------------------------------------------------------------------
static uint8 fatfs_calc_cluster_size(uint32 sectors, int is_fat32)
{
int i;
if (!is_fat32)
{
for (i=0; _cluster_size_table16[i].sectors_per_cluster != 0;i++)
if (sectors <= _cluster_size_table16[i].sectors)
return _cluster_size_table16[i].sectors_per_cluster;
}
else
{
for (i=0; _cluster_size_table32[i].sectors_per_cluster != 0;i++)
if (sectors <= _cluster_size_table32[i].sectors)
return _cluster_size_table32[i].sectors_per_cluster;
}
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_erase_sectors: Erase a number of sectors
//-----------------------------------------------------------------------------
static int fatfs_erase_sectors(struct fat_ctx *ctx, struct fatfs *fs, uint32 lba, int count)
{
int i;
// Zero sector first
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
for (i=0;i<count;i++)
if (!fs->disk_io.write_media(ctx, lba + i, fs->currentsector.sector, 1))
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_create_boot_sector: Create the boot sector
//-----------------------------------------------------------------------------
static int fatfs_create_boot_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 boot_sector_lba, uint32 vol_sectors, const char *name, int is_fat32)
{
uint32 total_clusters;
int i;
// Zero sector initially
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
// OEM Name & Jump Code
fs->currentsector.sector[0] = 0xEB;
fs->currentsector.sector[1] = 0x3C;
fs->currentsector.sector[2] = 0x90;
fs->currentsector.sector[3] = 0x4D;
fs->currentsector.sector[4] = 0x53;
fs->currentsector.sector[5] = 0x44;
fs->currentsector.sector[6] = 0x4F;
fs->currentsector.sector[7] = 0x53;
fs->currentsector.sector[8] = 0x35;
fs->currentsector.sector[9] = 0x2E;
fs->currentsector.sector[10] = 0x30;
// Bytes per sector
fs->currentsector.sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
fs->currentsector.sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
// Get sectors per cluster size for the disk
fs->sectors_per_cluster = fatfs_calc_cluster_size(vol_sectors, is_fat32);
if (!fs->sectors_per_cluster)
return 0; // Invalid disk size
// Sectors per cluster
fs->currentsector.sector[13] = fs->sectors_per_cluster;
// Reserved Sectors
if (!is_fat32)
fs->reserved_sectors = 8;
else
fs->reserved_sectors = 32;
fs->currentsector.sector[14] = (fs->reserved_sectors >> 0) & 0xFF;
fs->currentsector.sector[15] = (fs->reserved_sectors >> 8) & 0xFF;
// Number of FATS
fs->num_of_fats = 2;
fs->currentsector.sector[16] = fs->num_of_fats;
// Max entries in root dir (FAT16 only)
if (!is_fat32)
{
fs->root_entry_count = 512;
fs->currentsector.sector[17] = (fs->root_entry_count >> 0) & 0xFF;
fs->currentsector.sector[18] = (fs->root_entry_count >> 8) & 0xFF;
}
else
{
fs->root_entry_count = 0;
fs->currentsector.sector[17] = 0;
fs->currentsector.sector[18] = 0;
}
// [FAT16] Total sectors (use FAT32 count instead)
fs->currentsector.sector[19] = 0x00;
fs->currentsector.sector[20] = 0x00;
// Media type
fs->currentsector.sector[21] = 0xF8;
// FAT16 BS Details
if (!is_fat32)
{
// Count of sectors used by the FAT table (FAT16 only)
total_clusters = (vol_sectors / fs->sectors_per_cluster) + 1;
fs->fat_sectors = (total_clusters/(FAT_SECTOR_SIZE/2)) + 1;
fs->currentsector.sector[22] = (uint8)((fs->fat_sectors >> 0) & 0xFF);
fs->currentsector.sector[23] = (uint8)((fs->fat_sectors >> 8) & 0xFF);
// Sectors per track
fs->currentsector.sector[24] = 0x00;
fs->currentsector.sector[25] = 0x00;
// Heads
fs->currentsector.sector[26] = 0x00;
fs->currentsector.sector[27] = 0x00;
// Hidden sectors
fs->currentsector.sector[28] = 0x20;
fs->currentsector.sector[29] = 0x00;
fs->currentsector.sector[30] = 0x00;
fs->currentsector.sector[31] = 0x00;
// Total sectors for this volume
fs->currentsector.sector[32] = (uint8)((vol_sectors>>0)&0xFF);
fs->currentsector.sector[33] = (uint8)((vol_sectors>>8)&0xFF);
fs->currentsector.sector[34] = (uint8)((vol_sectors>>16)&0xFF);
fs->currentsector.sector[35] = (uint8)((vol_sectors>>24)&0xFF);
// Drive number
fs->currentsector.sector[36] = 0x00;
// Reserved
fs->currentsector.sector[37] = 0x00;
// Boot signature
fs->currentsector.sector[38] = 0x29;
// Volume ID
fs->currentsector.sector[39] = 0x12;
fs->currentsector.sector[40] = 0x34;
fs->currentsector.sector[41] = 0x56;
fs->currentsector.sector[42] = 0x78;
// Volume name
for (i=0;i<11;i++)
{
if (i < (int)strlen(name))
fs->currentsector.sector[i+43] = name[i];
else
fs->currentsector.sector[i+43] = ' ';
}
// File sys type
fs->currentsector.sector[54] = 'F';
fs->currentsector.sector[55] = 'A';
fs->currentsector.sector[56] = 'T';
fs->currentsector.sector[57] = '1';
fs->currentsector.sector[58] = '6';
fs->currentsector.sector[59] = ' ';
fs->currentsector.sector[60] = ' ';
fs->currentsector.sector[61] = ' ';
// Signature
fs->currentsector.sector[510] = 0x55;
fs->currentsector.sector[511] = 0xAA;
}
// FAT32 BS Details
else
{
// Count of sectors used by the FAT table (FAT16 only)
fs->currentsector.sector[22] = 0;
fs->currentsector.sector[23] = 0;
// Sectors per track (default)
fs->currentsector.sector[24] = 0x3F;
fs->currentsector.sector[25] = 0x00;
// Heads (default)
fs->currentsector.sector[26] = 0xFF;
fs->currentsector.sector[27] = 0x00;
// Hidden sectors
fs->currentsector.sector[28] = 0x00;
fs->currentsector.sector[29] = 0x00;
fs->currentsector.sector[30] = 0x00;
fs->currentsector.sector[31] = 0x00;
// Total sectors for this volume
fs->currentsector.sector[32] = (uint8)((vol_sectors>>0)&0xFF);
fs->currentsector.sector[33] = (uint8)((vol_sectors>>8)&0xFF);
fs->currentsector.sector[34] = (uint8)((vol_sectors>>16)&0xFF);
fs->currentsector.sector[35] = (uint8)((vol_sectors>>24)&0xFF);
total_clusters = (vol_sectors / fs->sectors_per_cluster) + 1;
fs->fat_sectors = (total_clusters/(FAT_SECTOR_SIZE/4)) + 1;
// BPB_FATSz32
fs->currentsector.sector[36] = (uint8)((fs->fat_sectors>>0)&0xFF);
fs->currentsector.sector[37] = (uint8)((fs->fat_sectors>>8)&0xFF);
fs->currentsector.sector[38] = (uint8)((fs->fat_sectors>>16)&0xFF);
fs->currentsector.sector[39] = (uint8)((fs->fat_sectors>>24)&0xFF);
// BPB_ExtFlags
fs->currentsector.sector[40] = 0;
fs->currentsector.sector[41] = 0;
// BPB_FSVer
fs->currentsector.sector[42] = 0;
fs->currentsector.sector[43] = 0;
// BPB_RootClus
fs->currentsector.sector[44] = (uint8)((fs->rootdir_first_cluster>>0)&0xFF);
fs->currentsector.sector[45] = (uint8)((fs->rootdir_first_cluster>>8)&0xFF);
fs->currentsector.sector[46] = (uint8)((fs->rootdir_first_cluster>>16)&0xFF);
fs->currentsector.sector[47] = (uint8)((fs->rootdir_first_cluster>>24)&0xFF);
// BPB_FSInfo
fs->currentsector.sector[48] = (uint8)((fs->fs_info_sector>>0)&0xFF);
fs->currentsector.sector[49] = (uint8)((fs->fs_info_sector>>8)&0xFF);
// BPB_BkBootSec
fs->currentsector.sector[50] = 6;
fs->currentsector.sector[51] = 0;
// Drive number
fs->currentsector.sector[64] = 0x00;
// Boot signature
fs->currentsector.sector[66] = 0x29;
// Volume ID
fs->currentsector.sector[67] = 0x12;
fs->currentsector.sector[68] = 0x34;
fs->currentsector.sector[69] = 0x56;
fs->currentsector.sector[70] = 0x78;
// Volume name
for (i=0;i<11;i++)
{
if (i < (int)strlen(name))
fs->currentsector.sector[i+71] = name[i];
else
fs->currentsector.sector[i+71] = ' ';
}
// File sys type
fs->currentsector.sector[82] = 'F';
fs->currentsector.sector[83] = 'A';
fs->currentsector.sector[84] = 'T';
fs->currentsector.sector[85] = '3';
fs->currentsector.sector[86] = '2';
fs->currentsector.sector[87] = ' ';
fs->currentsector.sector[88] = ' ';
fs->currentsector.sector[89] = ' ';
// Signature
fs->currentsector.sector[510] = 0x55;
fs->currentsector.sector[511] = 0xAA;
}
if (fs->disk_io.write_media(ctx, boot_sector_lba, fs->currentsector.sector, 1))
return 1;
else
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_create_fsinfo_sector: Create the FSInfo sector (FAT32)
//-----------------------------------------------------------------------------
static int fatfs_create_fsinfo_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 sector_lba)
{
// Zero sector initially
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
// FSI_LeadSig
fs->currentsector.sector[0] = 0x52;
fs->currentsector.sector[1] = 0x52;
fs->currentsector.sector[2] = 0x61;
fs->currentsector.sector[3] = 0x41;
// FSI_StrucSig
fs->currentsector.sector[484] = 0x72;
fs->currentsector.sector[485] = 0x72;
fs->currentsector.sector[486] = 0x41;
fs->currentsector.sector[487] = 0x61;
// FSI_Free_Count
fs->currentsector.sector[488] = 0xFF;
fs->currentsector.sector[489] = 0xFF;
fs->currentsector.sector[490] = 0xFF;
fs->currentsector.sector[491] = 0xFF;
// FSI_Nxt_Free
fs->currentsector.sector[492] = 0xFF;
fs->currentsector.sector[493] = 0xFF;
fs->currentsector.sector[494] = 0xFF;
fs->currentsector.sector[495] = 0xFF;
// Signature
fs->currentsector.sector[510] = 0x55;
fs->currentsector.sector[511] = 0xAA;
if (fs->disk_io.write_media(ctx, sector_lba, fs->currentsector.sector, 1))
return 1;
else
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_erase_fat: Erase FAT table using fs details in fs struct
//-----------------------------------------------------------------------------
static int fatfs_erase_fat(struct fat_ctx *ctx, struct fatfs *fs, int is_fat32)
{
uint32 i;
// Zero sector initially
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
// Initialise default allocate / reserved clusters
if (!is_fat32)
{
SET_16BIT_WORD(fs->currentsector.sector, 0, 0xFFF8);
SET_16BIT_WORD(fs->currentsector.sector, 2, 0xFFFF);
}
else
{
SET_32BIT_WORD(fs->currentsector.sector, 0, 0x0FFFFFF8);
SET_32BIT_WORD(fs->currentsector.sector, 4, 0xFFFFFFFF);
SET_32BIT_WORD(fs->currentsector.sector, 8, 0x0FFFFFFF);
}
if (!fs->disk_io.write_media(ctx, fs->fat_begin_lba + 0, fs->currentsector.sector, 1))
return 0;
// Zero remaining FAT sectors
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
for (i=1;i<fs->fat_sectors*fs->num_of_fats;i++)
if (!fs->disk_io.write_media(ctx, fs->fat_begin_lba + i, fs->currentsector.sector, 1))
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_format_fat16: Format a FAT16 partition
//-----------------------------------------------------------------------------
int fatfs_format_fat16(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name)
{
fs->currentsector.address = FAT32_INVALID_CLUSTER;
fs->currentsector.dirty = 0;
fs->next_free_cluster = 0; // Invalid
fatfs_fat_init(fs);
// Make sure we have read + write functions
if (!fs->disk_io.read_media || !fs->disk_io.write_media)
return FAT_INIT_MEDIA_ACCESS_ERROR;
// Volume is FAT16
fs->fat_type = FAT_TYPE_16;
// Not valid for FAT16
fs->fs_info_sector = 0;
fs->rootdir_first_cluster = 0;
// Sector 0: Boot sector
// NOTE: We don't need an MBR, it is a waste of a good sector!
fs->lba_begin = 0;
if (!fatfs_create_boot_sector(ctx, fs, fs->lba_begin, volume_sectors, name, 0))
return 0;
// For FAT16 (which this may be), rootdir_first_cluster is actuall rootdir_first_sector
fs->rootdir_first_sector = fs->reserved_sectors + (fs->num_of_fats * fs->fat_sectors);
fs->rootdir_sectors = ((fs->root_entry_count * 32) + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
// First FAT LBA address
fs->fat_begin_lba = fs->lba_begin + fs->reserved_sectors;
// The address of the first data cluster on this volume
fs->cluster_begin_lba = fs->fat_begin_lba + (fs->num_of_fats * fs->fat_sectors);
// Initialise FAT sectors
if (!fatfs_erase_fat(ctx, fs, 0))
return 0;
// Erase Root directory
if (!fatfs_erase_sectors(ctx, fs, fs->lba_begin + fs->rootdir_first_sector, fs->rootdir_sectors))
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_format_fat32: Format a FAT32 partition
//-----------------------------------------------------------------------------
int fatfs_format_fat32(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name)
{
fs->currentsector.address = FAT32_INVALID_CLUSTER;
fs->currentsector.dirty = 0;
fs->next_free_cluster = 0; // Invalid
fatfs_fat_init(fs);
// Make sure we have read + write functions
if (!fs->disk_io.read_media || !fs->disk_io.write_media)
return FAT_INIT_MEDIA_ACCESS_ERROR;
// Volume is FAT32
fs->fat_type = FAT_TYPE_32;
// Basic defaults for normal FAT32 partitions
fs->fs_info_sector = 1;
fs->rootdir_first_cluster = 2;
// Sector 0: Boot sector
// NOTE: We don't need an MBR, it is a waste of a good sector!
fs->lba_begin = 0;
if (!fatfs_create_boot_sector(ctx, fs, fs->lba_begin, volume_sectors, name, 1))
return 0;
// First FAT LBA address
fs->fat_begin_lba = fs->lba_begin + fs->reserved_sectors;
// The address of the first data cluster on this volume
fs->cluster_begin_lba = fs->fat_begin_lba + (fs->num_of_fats * fs->fat_sectors);
// Initialise FSInfo sector
if (!fatfs_create_fsinfo_sector(ctx, fs, fs->fs_info_sector))
return 0;
// Initialise FAT sectors
if (!fatfs_erase_fat(ctx, fs, 1))
return 0;
// Erase Root directory
if (!fatfs_erase_sectors(ctx, fs, fatfs_lba_of_cluster(fs, fs->rootdir_first_cluster), fs->sectors_per_cluster))
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_format: Format a partition with either FAT16 or FAT32 based on size
//-----------------------------------------------------------------------------
int fatfs_format(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name)
{
// 2GB - 32K limit for safe behaviour for FAT16
if (volume_sectors <= 4194304)
return fatfs_format_fat16(ctx, fs, volume_sectors, name);
else
return fatfs_format_fat32(ctx, fs, volume_sectors, name);
}
#endif /*FATFS_INC_FORMAT_SUPPORT*/

View File

@ -0,0 +1,17 @@
#ifndef __FAT_FORMAT_H__
#define __FAT_FORMAT_H__
#include "fat_defs.h"
#include "fat_opts.h"
#include "fat_access.h"
struct fat_ctx;
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_format(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name);
int fatfs_format_fat16(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name);
int fatfs_format_fat32(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name);
#endif

161
kernel/fs/fatfs/fat_list.h Normal file
View File

@ -0,0 +1,161 @@
#ifndef __FAT_LIST_H__
#define __FAT_LIST_H__
#ifndef FAT_ASSERT
#define FAT_ASSERT(x)
#endif
#ifndef FAT_INLINE
#define FAT_INLINE
#endif
//-----------------------------------------------------------------
// Types
//-----------------------------------------------------------------
struct fat_list;
struct fat_node
{
struct fat_node *previous;
struct fat_node *next;
};
struct fat_list
{
struct fat_node *head;
struct fat_node *tail;
};
//-----------------------------------------------------------------
// Macros
//-----------------------------------------------------------------
#define fat_list_entry(p, t, m) p ? ((t *)((char *)(p)-(char*)(&((t *)0)->m))) : 0
#define fat_list_next(l, p) (p)->next
#define fat_list_prev(l, p) (p)->previous
#define fat_list_first(l) (l)->head
#define fat_list_last(l) (l)->tail
#define fat_list_for_each(l, p) for ((p) = (l)->head; (p); (p) = (p)->next)
//-----------------------------------------------------------------
// Inline Functions
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// fat_list_init:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_init(struct fat_list *list)
{
FAT_ASSERT(list);
list->head = list->tail = 0;
}
//-----------------------------------------------------------------
// fat_list_remove:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_remove(struct fat_list *list, struct fat_node *node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
if(!node->previous)
list->head = node->next;
else
node->previous->next = node->next;
if(!node->next)
list->tail = node->previous;
else
node->next->previous = node->previous;
}
//-----------------------------------------------------------------
// fat_list_insert_after:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_after(struct fat_list *list, struct fat_node *node, struct fat_node *new_node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
FAT_ASSERT(new_node);
new_node->previous = node;
new_node->next = node->next;
if (!node->next)
list->tail = new_node;
else
node->next->previous = new_node;
node->next = new_node;
}
//-----------------------------------------------------------------
// fat_list_insert_before:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_before(struct fat_list *list, struct fat_node *node, struct fat_node *new_node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
FAT_ASSERT(new_node);
new_node->previous = node->previous;
new_node->next = node;
if (!node->previous)
list->head = new_node;
else
node->previous->next = new_node;
node->previous = new_node;
}
//-----------------------------------------------------------------
// fat_list_insert_first:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_first(struct fat_list *list, struct fat_node *node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
if (!list->head)
{
list->head = node;
list->tail = node;
node->previous = 0;
node->next = 0;
}
else
fat_list_insert_before(list, list->head, node);
}
//-----------------------------------------------------------------
// fat_list_insert_last:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_last(struct fat_list *list, struct fat_node *node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
if (!list->tail)
fat_list_insert_first(list, node);
else
fat_list_insert_after(list, list->tail, node);
}
//-----------------------------------------------------------------
// fat_list_is_empty:
//-----------------------------------------------------------------
static FAT_INLINE int fat_list_is_empty(struct fat_list *list)
{
FAT_ASSERT(list);
return !list->head;
}
//-----------------------------------------------------------------
// fat_list_pop_head:
//-----------------------------------------------------------------
static FAT_INLINE struct fat_node * fat_list_pop_head(struct fat_list *list)
{
struct fat_node * node;
FAT_ASSERT(list);
node = fat_list_first(list);
if (node)
fat_list_remove(list, node);
return node;
}
#endif

505
kernel/fs/fatfs/fat_misc.c Normal file
View File

@ -0,0 +1,505 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// FAT File IO Library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
#include "fat_misc.h"
//-----------------------------------------------------------------------------
// fatfs_lfn_cache_init: Clear long file name cache
//-----------------------------------------------------------------------------
void fatfs_lfn_cache_init(struct lfn_cache *lfn, int wipeTable)
{
int i = 0;
lfn->no_of_strings = 0;
#if FATFS_INC_LFN_SUPPORT
// Zero out buffer also
if (wipeTable)
for (i=0;i<MAX_LONGFILENAME_ENTRIES;i++)
memset(lfn->String[i], 0x00, MAX_LFN_ENTRY_LENGTH);
#endif
}
//-----------------------------------------------------------------------------
// fatfs_lfn_cache_entry - Function extracts long file name text from sector
// at a specific offset
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
void fatfs_lfn_cache_entry(struct lfn_cache *lfn, uint8 *entryBuffer)
{
uint8 LFNIndex, i;
LFNIndex = entryBuffer[0] & 0x1F;
// Limit file name to cache size!
if (LFNIndex > MAX_LONGFILENAME_ENTRIES)
return ;
// This is an error condition
if (LFNIndex == 0)
return ;
if (lfn->no_of_strings == 0)
lfn->no_of_strings = LFNIndex;
lfn->String[LFNIndex-1][0] = entryBuffer[1];
lfn->String[LFNIndex-1][1] = entryBuffer[3];
lfn->String[LFNIndex-1][2] = entryBuffer[5];
lfn->String[LFNIndex-1][3] = entryBuffer[7];
lfn->String[LFNIndex-1][4] = entryBuffer[9];
lfn->String[LFNIndex-1][5] = entryBuffer[0x0E];
lfn->String[LFNIndex-1][6] = entryBuffer[0x10];
lfn->String[LFNIndex-1][7] = entryBuffer[0x12];
lfn->String[LFNIndex-1][8] = entryBuffer[0x14];
lfn->String[LFNIndex-1][9] = entryBuffer[0x16];
lfn->String[LFNIndex-1][10] = entryBuffer[0x18];
lfn->String[LFNIndex-1][11] = entryBuffer[0x1C];
lfn->String[LFNIndex-1][12] = entryBuffer[0x1E];
for (i=0; i<MAX_LFN_ENTRY_LENGTH; i++)
if (lfn->String[LFNIndex-1][i]==0xFF)
lfn->String[LFNIndex-1][i] = 0x20; // Replace with spaces
}
#endif
//-----------------------------------------------------------------------------
// fatfs_lfn_cache_get: Get a reference to the long filename
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
char* fatfs_lfn_cache_get(struct lfn_cache *lfn)
{
// Null terminate long filename
if (lfn->no_of_strings == MAX_LONGFILENAME_ENTRIES)
lfn->Null = '\0';
else if (lfn->no_of_strings)
lfn->String[lfn->no_of_strings][0] = '\0';
else
lfn->String[0][0] = '\0';
return (char*)&lfn->String[0][0];
}
#endif
//-----------------------------------------------------------------------------
// fatfs_entry_lfn_text: If LFN text entry found
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
int fatfs_entry_lfn_text(struct fat_dir_entry *entry)
{
if ((entry->Attr & FILE_ATTR_LFN_TEXT) == FILE_ATTR_LFN_TEXT)
return 1;
else
return 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_entry_lfn_invalid: If SFN found not relating to LFN
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
int fatfs_entry_lfn_invalid(struct fat_dir_entry *entry)
{
if ( (entry->Name[0]==FILE_HEADER_BLANK) ||
(entry->Name[0]==FILE_HEADER_DELETED)||
(entry->Attr==FILE_ATTR_VOLUME_ID) ||
(entry->Attr & FILE_ATTR_SYSHID) )
return 1;
else
return 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_entry_lfn_exists: If LFN exists and correlation SFN found
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
int fatfs_entry_lfn_exists(struct lfn_cache *lfn, struct fat_dir_entry *entry)
{
if ( (entry->Attr!=FILE_ATTR_LFN_TEXT) &&
(entry->Name[0]!=FILE_HEADER_BLANK) &&
(entry->Name[0]!=FILE_HEADER_DELETED) &&
(entry->Attr!=FILE_ATTR_VOLUME_ID) &&
(!(entry->Attr&FILE_ATTR_SYSHID)) &&
(lfn->no_of_strings) )
return 1;
else
return 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_entry_sfn_only: If SFN only exists
//-----------------------------------------------------------------------------
int fatfs_entry_sfn_only(struct fat_dir_entry *entry)
{
if ( (entry->Attr!=FILE_ATTR_LFN_TEXT) &&
(entry->Name[0]!=FILE_HEADER_BLANK) &&
(entry->Name[0]!=FILE_HEADER_DELETED) &&
(entry->Attr!=FILE_ATTR_VOLUME_ID) &&
(!(entry->Attr&FILE_ATTR_SYSHID)) )
return 1;
else
return 0;
}
// TODO: FILE_ATTR_SYSHID ?!?!??!
//-----------------------------------------------------------------------------
// fatfs_entry_is_dir: Returns 1 if a directory
//-----------------------------------------------------------------------------
int fatfs_entry_is_dir(struct fat_dir_entry *entry)
{
if (entry->Attr & FILE_TYPE_DIR)
return 1;
else
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_entry_is_file: Returns 1 is a file entry
//-----------------------------------------------------------------------------
int fatfs_entry_is_file(struct fat_dir_entry *entry)
{
if (entry->Attr & FILE_TYPE_FILE)
return 1;
else
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_lfn_entries_required: Calculate number of 13 characters entries
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
int fatfs_lfn_entries_required(char *filename)
{
int length = (int)strlen(filename);
if (length)
return (length + MAX_LFN_ENTRY_LENGTH - 1) / MAX_LFN_ENTRY_LENGTH;
else
return 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_filename_to_lfn:
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk)
{
int i;
int nameIndexes[MAX_LFN_ENTRY_LENGTH] = {1,3,5,7,9,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E};
// 13 characters entries
int length = (int)strlen(filename);
int entriesRequired = fatfs_lfn_entries_required(filename);
// Filename offset
int start = entry * MAX_LFN_ENTRY_LENGTH;
// Initialise to zeros
memset(buffer, 0x00, FAT_DIR_ENTRY_SIZE);
// LFN entry number
buffer[0] = (uint8)(((entriesRequired-1)==entry)?(0x40|(entry+1)):(entry+1));
// LFN flag
buffer[11] = 0x0F;
// Checksum of short filename
buffer[13] = sfnChk;
// Copy to buffer
for (i=0;i<MAX_LFN_ENTRY_LENGTH;i++)
{
if ( (start+i) < length )
buffer[nameIndexes[i]] = filename[start+i];
else if ( (start+i) == length )
buffer[nameIndexes[i]] = 0x00;
else
{
buffer[nameIndexes[i]] = 0xFF;
buffer[nameIndexes[i]+1] = 0xFF;
}
}
}
#endif
//-----------------------------------------------------------------------------
// fatfs_sfn_create_entry: Create the short filename directory entry
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
void fatfs_sfn_create_entry(char *shortfilename, uint32 size, uint32 startCluster, struct fat_dir_entry *entry, int dir)
{
int i;
// Copy short filename
for (i=0;i<FAT_SFN_SIZE_FULL;i++)
entry->Name[i] = shortfilename[i];
// Unless we have a RTC we might as well set these to 1980
entry->CrtTimeTenth = 0x00;
entry->CrtTime[1] = entry->CrtTime[0] = 0x00;
entry->CrtDate[1] = 0x00;
entry->CrtDate[0] = 0x20;
entry->LstAccDate[1] = 0x00;
entry->LstAccDate[0] = 0x20;
entry->WrtTime[1] = entry->WrtTime[0] = 0x00;
entry->WrtDate[1] = 0x00;
entry->WrtDate[0] = 0x20;
if (!dir)
entry->Attr = FILE_TYPE_FILE;
else
entry->Attr = FILE_TYPE_DIR;
entry->NTRes = 0x00;
entry->FstClusHI = FAT_HTONS((uint16)((startCluster>>16) & 0xFFFF));
entry->FstClusLO = FAT_HTONS((uint16)((startCluster>>0) & 0xFFFF));
entry->FileSize = FAT_HTONL(size);
}
#endif
//-----------------------------------------------------------------------------
// fatfs_lfn_create_sfn: Create a padded SFN
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_lfn_create_sfn(char *sfn_output, char *filename)
{
int i;
int dotPos = -1;
char ext[3];
int pos;
int len = (int)strlen(filename);
// Invalid to start with .
if (filename[0]=='.')
return 0;
memset(sfn_output, ' ', FAT_SFN_SIZE_FULL);
memset(ext, ' ', 3);
// Find dot seperator
for (i = 0; i< len; i++)
{
if (filename[i]=='.')
dotPos = i;
}
// Extract extensions
if (dotPos!=-1)
{
// Copy first three chars of extension
for (i = (dotPos+1); i < (dotPos+1+3); i++)
if (i<len)
ext[i-(dotPos+1)] = filename[i];
// Shorten the length to the dot position
len = dotPos;
}
// Add filename part
pos = 0;
for (i=0;i<len;i++)
{
if ( (filename[i]!=' ') && (filename[i]!='.') )
{
if (filename[i] >= 'a' && filename[i] <= 'z')
sfn_output[pos++] = filename[i] - 'a' + 'A';
else
sfn_output[pos++] = filename[i];
}
// Fill upto 8 characters
if (pos==FAT_SFN_SIZE_PARTIAL)
break;
}
// Add extension part
for (i=FAT_SFN_SIZE_PARTIAL;i<FAT_SFN_SIZE_FULL;i++)
{
if (ext[i-FAT_SFN_SIZE_PARTIAL] >= 'a' && ext[i-FAT_SFN_SIZE_PARTIAL] <= 'z')
sfn_output[i] = ext[i-FAT_SFN_SIZE_PARTIAL] - 'a' + 'A';
else
sfn_output[i] = ext[i-FAT_SFN_SIZE_PARTIAL];
}
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_itoa:
//-----------------------------------------------------------------------------
static void fatfs_itoa(uint32 num, char *s)
{
char* cp;
char outbuf[12];
const char digits[] = "0123456789ABCDEF";
// Build string backwards
cp = outbuf;
do
{
*cp++ = digits[(int)(num % 10)];
}
while ((num /= 10) > 0);
*cp-- = 0;
// Copy in forwards
while (cp >= outbuf)
*s++ = *cp--;
*s = 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_lfn_generate_tail:
// sfn_input = Input short filename, spaced format & in upper case
// sfn_output = Output short filename with tail
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
#if FATFS_INC_WRITE_SUPPORT
int fatfs_lfn_generate_tail(char *sfn_output, char *sfn_input, uint32 tailNum)
{
int tail_chars;
char tail_str[12];
if (tailNum > 99999)
return 0;
// Convert to number
memset(tail_str, 0x00, sizeof(tail_str));
tail_str[0] = '~';
fatfs_itoa(tailNum, tail_str+1);
// Copy in base filename
memcpy(sfn_output, sfn_input, FAT_SFN_SIZE_FULL);
// Overwrite with tail
tail_chars = (int)strlen(tail_str);
memcpy(sfn_output+(FAT_SFN_SIZE_PARTIAL-tail_chars), tail_str, tail_chars);
return 1;
}
#endif
#endif
//-----------------------------------------------------------------------------
// fatfs_convert_from_fat_time: Convert FAT time to h/m/s
//-----------------------------------------------------------------------------
#if FATFS_INC_TIME_DATE_SUPPORT
void fatfs_convert_from_fat_time(uint16 fat_time, int *hours, int *minutes, int *seconds)
{
*hours = (fat_time >> FAT_TIME_HOURS_SHIFT) & FAT_TIME_HOURS_MASK;
*minutes = (fat_time >> FAT_TIME_MINUTES_SHIFT) & FAT_TIME_MINUTES_MASK;
*seconds = (fat_time >> FAT_TIME_SECONDS_SHIFT) & FAT_TIME_SECONDS_MASK;
*seconds = *seconds * FAT_TIME_SECONDS_SCALE;
}
//-----------------------------------------------------------------------------
// fatfs_convert_from_fat_date: Convert FAT date to d/m/y
//-----------------------------------------------------------------------------
void fatfs_convert_from_fat_date(uint16 fat_date, int *day, int *month, int *year)
{
*day = (fat_date >> FAT_DATE_DAY_SHIFT) & FAT_DATE_DAY_MASK;
*month = (fat_date >> FAT_DATE_MONTH_SHIFT) & FAT_DATE_MONTH_MASK;
*year = (fat_date >> FAT_DATE_YEAR_SHIFT) & FAT_DATE_YEAR_MASK;
*year = *year + FAT_DATE_YEAR_OFFSET;
}
//-----------------------------------------------------------------------------
// fatfs_convert_to_fat_time: Convert h/m/s to FAT time
//-----------------------------------------------------------------------------
uint16 fatfs_convert_to_fat_time(int hours, int minutes, int seconds)
{
uint16 fat_time = 0;
// Most FAT times are to a resolution of 2 seconds
seconds /= FAT_TIME_SECONDS_SCALE;
fat_time = (hours & FAT_TIME_HOURS_MASK) << FAT_TIME_HOURS_SHIFT;
fat_time|= (minutes & FAT_TIME_MINUTES_MASK) << FAT_TIME_MINUTES_SHIFT;
fat_time|= (seconds & FAT_TIME_SECONDS_MASK) << FAT_TIME_SECONDS_SHIFT;
return fat_time;
}
//-----------------------------------------------------------------------------
// fatfs_convert_to_fat_date: Convert d/m/y to FAT date
//-----------------------------------------------------------------------------
uint16 fatfs_convert_to_fat_date(int day, int month, int year)
{
uint16 fat_date = 0;
// FAT dates are relative to 1980
if (year >= FAT_DATE_YEAR_OFFSET)
year -= FAT_DATE_YEAR_OFFSET;
fat_date = (day & FAT_DATE_DAY_MASK) << FAT_DATE_DAY_SHIFT;
fat_date|= (month & FAT_DATE_MONTH_MASK) << FAT_DATE_MONTH_SHIFT;
fat_date|= (year & FAT_DATE_YEAR_MASK) << FAT_DATE_YEAR_SHIFT;
return fat_date;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_print_sector:
//-----------------------------------------------------------------------------
#ifdef FATFS_DEBUG
void fatfs_print_sector(uint32 sector, uint8 *data)
{
int i;
int j;
FAT_PRINTF(("Sector %d:\n", sector));
for (i=0;i<FAT_SECTOR_SIZE;i++)
{
if (!((i) % 16))
{
FAT_PRINTF((" %04d: ", i));
}
FAT_PRINTF(("%02x", data[i]));
if (!((i+1) % 4))
{
FAT_PRINTF((" "));
}
if (!((i+1) % 16))
{
FAT_PRINTF((" "));
for (j=0;j<16;j++)
{
char ch = data[i-15+j];
// Is printable?
if (ch > 31 && ch < 127)
{
FAT_PRINTF(("%c", ch));
}
else
{
FAT_PRINTF(("."));
}
}
FAT_PRINTF(("\n"));
}
}
}
#endif

View File

@ -0,0 +1,63 @@
#ifndef __FAT_MISC_H__
#define __FAT_MISC_H__
#include "fat_defs.h"
#include "fat_opts.h"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#define MAX_LONGFILENAME_ENTRIES 20
#define MAX_LFN_ENTRY_LENGTH 13
//-----------------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------------
#define GET_32BIT_WORD(buffer, location) ( ((uint32)buffer[location+3]<<24) + ((uint32)buffer[location+2]<<16) + ((uint32)buffer[location+1]<<8) + (uint32)buffer[location+0] )
#define GET_16BIT_WORD(buffer, location) ( ((uint16)buffer[location+1]<<8) + (uint16)buffer[location+0] )
#define SET_32BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
buffer[location+1] = (uint8)((value>>8)&0xFF); \
buffer[location+2] = (uint8)((value>>16)&0xFF); \
buffer[location+3] = (uint8)((value>>24)&0xFF); }
#define SET_16BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
buffer[location+1] = (uint8)((value>>8)&0xFF); }
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct lfn_cache
{
#if FATFS_INC_LFN_SUPPORT
// Long File Name Structure (max 260 LFN length)
uint8 String[MAX_LONGFILENAME_ENTRIES][MAX_LFN_ENTRY_LENGTH];
uint8 Null;
#endif
uint8 no_of_strings;
};
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
void fatfs_lfn_cache_init(struct lfn_cache *lfn, int wipeTable);
void fatfs_lfn_cache_entry(struct lfn_cache *lfn, uint8 *entryBuffer);
char* fatfs_lfn_cache_get(struct lfn_cache *lfn);
int fatfs_entry_lfn_text(struct fat_dir_entry *entry);
int fatfs_entry_lfn_invalid(struct fat_dir_entry *entry);
int fatfs_entry_lfn_exists(struct lfn_cache *lfn, struct fat_dir_entry *entry);
int fatfs_entry_sfn_only(struct fat_dir_entry *entry);
int fatfs_entry_is_dir(struct fat_dir_entry *entry);
int fatfs_entry_is_file(struct fat_dir_entry *entry);
int fatfs_lfn_entries_required(char *filename);
void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk);
void fatfs_sfn_create_entry(char *shortfilename, uint32 size, uint32 startCluster, struct fat_dir_entry *entry, int dir);
int fatfs_lfn_create_sfn(char *sfn_output, char *filename);
int fatfs_lfn_generate_tail(char *sfn_output, char *sfn_input, uint32 tailNum);
void fatfs_convert_from_fat_time(uint16 fat_time, int *hours, int *minutes, int *seconds);
void fatfs_convert_from_fat_date(uint16 fat_date, int *day, int *month, int *year);
uint16 fatfs_convert_to_fat_time(int hours, int minutes, int seconds);
uint16 fatfs_convert_to_fat_date(int day, int month, int year);
void fatfs_print_sector(uint32 sector, uint8 *data);
#endif

View File

@ -0,0 +1,90 @@
#ifndef __FAT_OPTS_H__
#define __FAT_OPTS_H__
#ifdef FATFS_USE_CUSTOM_OPTS_FILE
#include "fat_custom.h"
#endif
//-------------------------------------------------------------
// Configuration
//-------------------------------------------------------------
// Is the processor little endian (1) or big endian (0)
#ifndef FATFS_IS_LITTLE_ENDIAN
#define FATFS_IS_LITTLE_ENDIAN 1
#endif
// Max filename Length
#ifndef FATFS_MAX_LONG_FILENAME
#define FATFS_MAX_LONG_FILENAME 260
#endif
// Max open files (reduce to lower memory requirements)
#ifndef FATFS_MAX_OPEN_FILES
#define FATFS_MAX_OPEN_FILES 2
#endif
// Number of sectors per FAT_BUFFER (min 1)
#ifndef FAT_BUFFER_SECTORS
#define FAT_BUFFER_SECTORS 1
#endif
// Max FAT sectors to buffer (min 1)
// (mem used is FAT_BUFFERS * FAT_BUFFER_SECTORS * FAT_SECTOR_SIZE)
#ifndef FAT_BUFFERS
#define FAT_BUFFERS 1
#endif
// Size of cluster chain cache (can be undefined)
// Mem used = FAT_CLUSTER_CACHE_ENTRIES * 4 * 2
// Improves access speed considerably
//#define FAT_CLUSTER_CACHE_ENTRIES 128
// Include support for writing files (1 / 0)?
#ifndef FATFS_INC_WRITE_SUPPORT
#define FATFS_INC_WRITE_SUPPORT 1
#endif
// Support long filenames (1 / 0)?
// (if not (0) only 8.3 format is supported)
#ifndef FATFS_INC_LFN_SUPPORT
#define FATFS_INC_LFN_SUPPORT 1
#endif
// Support directory listing (1 / 0)?
#ifndef FATFS_DIR_LIST_SUPPORT
#define FATFS_DIR_LIST_SUPPORT 1
#endif
// Support time/date (1 / 0)?
#ifndef FATFS_INC_TIME_DATE_SUPPORT
#define FATFS_INC_TIME_DATE_SUPPORT 0
#endif
// Include support for formatting disks (1 / 0)?
#ifndef FATFS_INC_FORMAT_SUPPORT
#define FATFS_INC_FORMAT_SUPPORT 1
#endif
// Sector size used
#define FAT_SECTOR_SIZE 512
// Printf output (directory listing / debug)
#ifndef FAT_PRINTF
// Don't include stdio, but there is a printf function available
#ifdef FAT_PRINTF_NOINC_STDIO
extern int printf(const char* ctrl1, ... );
#define FAT_PRINTF(a) printf a
// Include stdio to use printf
#else
#include <stdio.h>
#define FAT_PRINTF(a) printf a
#endif
#endif
// Time/Date support requires time.h
#if FATFS_INC_TIME_DATE_SUPPORT
#include <time.h>
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More