From 4c20c082c148c2d7573397c77550204c57a5332a Mon Sep 17 00:00:00 2001 From: Anton Krotov Date: Sun, 22 Jan 2023 14:20:23 +0000 Subject: [PATCH] FB2 Reader: upload source, small changes git-svn-id: svn://kolibrios.org@9896 a494cfbc-eb01-0410-851d-a64ba20cac60 --- data/common/fb2read | Bin 24997 -> 24753 bytes programs/develop/cedit/BUILD.SH | 2 +- programs/develop/cedit/RUN.SH | 2 +- programs/other/fb2reader/BUILD.SH | 3 + programs/other/fb2reader/FB2READ.INI | 16 + programs/other/fb2reader/RUN.SH | 3 + programs/other/fb2reader/SRC/API.ob07 | 290 +++ programs/other/fb2reader/SRC/ColorDlg.ob07 | 87 + programs/other/fb2reader/SRC/Conv.ob07 | 84 + programs/other/fb2reader/SRC/Cursor.ob07 | 364 ++++ programs/other/fb2reader/SRC/DOM.ob07 | 1756 ++++++++++++++++++ programs/other/fb2reader/SRC/FB2READ.ob07 | 366 ++++ programs/other/fb2reader/SRC/File.ob07 | 255 +++ programs/other/fb2reader/SRC/Font.ob07 | 176 ++ programs/other/fb2reader/SRC/Graph.ob07 | 310 ++++ programs/other/fb2reader/SRC/Icons.ob07 | 106 ++ programs/other/fb2reader/SRC/Ini.ob07 | 149 ++ programs/other/fb2reader/SRC/KOSAPI.ob07 | 436 +++++ programs/other/fb2reader/SRC/LISTS.ob07 | 135 ++ programs/other/fb2reader/SRC/Libimg.ob07 | 81 + programs/other/fb2reader/SRC/OpenDlg.ob07 | 134 ++ programs/other/fb2reader/SRC/RTL.ob07 | 543 ++++++ programs/other/fb2reader/SRC/Read.ob07 | 42 + programs/other/fb2reader/SRC/ReadFile.ob07 | 159 ++ programs/other/fb2reader/SRC/Search.ob07 | 645 +++++++ programs/other/fb2reader/SRC/SearchForm.ob07 | 199 ++ programs/other/fb2reader/SRC/SelEnc.ob07 | 163 ++ programs/other/fb2reader/SRC/Settings.ob07 | 420 +++++ programs/other/fb2reader/SRC/Strings.ob07 | 414 +++++ programs/other/fb2reader/SRC/SysUtils.ob07 | 365 ++++ programs/other/fb2reader/SRC/Toolbar.ob07 | 167 ++ programs/other/fb2reader/SRC/Txt2fb2.ob07 | 129 ++ programs/other/fb2reader/SRC/Vector.ob07 | 105 ++ programs/other/fb2reader/SRC/Window.ob07 | 58 + programs/other/fb2reader/SRC/Write.ob07 | 42 + programs/other/fb2reader/SRC/XML.ob07 | 755 ++++++++ programs/other/fb2reader/SRC/box_lib.ob07 | 236 +++ programs/other/fb2reader/SRC/encode.ob07 | 149 ++ programs/other/fb2reader/SRC/kfonts.ob07 | 466 +++++ programs/other/fb2reader/SRC/tables.ob07 | 256 +++ 40 files changed, 10066 insertions(+), 2 deletions(-) create mode 100644 programs/other/fb2reader/BUILD.SH create mode 100644 programs/other/fb2reader/FB2READ.INI create mode 100644 programs/other/fb2reader/RUN.SH create mode 100644 programs/other/fb2reader/SRC/API.ob07 create mode 100644 programs/other/fb2reader/SRC/ColorDlg.ob07 create mode 100644 programs/other/fb2reader/SRC/Conv.ob07 create mode 100644 programs/other/fb2reader/SRC/Cursor.ob07 create mode 100644 programs/other/fb2reader/SRC/DOM.ob07 create mode 100644 programs/other/fb2reader/SRC/FB2READ.ob07 create mode 100644 programs/other/fb2reader/SRC/File.ob07 create mode 100644 programs/other/fb2reader/SRC/Font.ob07 create mode 100644 programs/other/fb2reader/SRC/Graph.ob07 create mode 100644 programs/other/fb2reader/SRC/Icons.ob07 create mode 100644 programs/other/fb2reader/SRC/Ini.ob07 create mode 100644 programs/other/fb2reader/SRC/KOSAPI.ob07 create mode 100644 programs/other/fb2reader/SRC/LISTS.ob07 create mode 100644 programs/other/fb2reader/SRC/Libimg.ob07 create mode 100644 programs/other/fb2reader/SRC/OpenDlg.ob07 create mode 100644 programs/other/fb2reader/SRC/RTL.ob07 create mode 100644 programs/other/fb2reader/SRC/Read.ob07 create mode 100644 programs/other/fb2reader/SRC/ReadFile.ob07 create mode 100644 programs/other/fb2reader/SRC/Search.ob07 create mode 100644 programs/other/fb2reader/SRC/SearchForm.ob07 create mode 100644 programs/other/fb2reader/SRC/SelEnc.ob07 create mode 100644 programs/other/fb2reader/SRC/Settings.ob07 create mode 100644 programs/other/fb2reader/SRC/Strings.ob07 create mode 100644 programs/other/fb2reader/SRC/SysUtils.ob07 create mode 100644 programs/other/fb2reader/SRC/Toolbar.ob07 create mode 100644 programs/other/fb2reader/SRC/Txt2fb2.ob07 create mode 100644 programs/other/fb2reader/SRC/Vector.ob07 create mode 100644 programs/other/fb2reader/SRC/Window.ob07 create mode 100644 programs/other/fb2reader/SRC/Write.ob07 create mode 100644 programs/other/fb2reader/SRC/XML.ob07 create mode 100644 programs/other/fb2reader/SRC/box_lib.ob07 create mode 100644 programs/other/fb2reader/SRC/encode.ob07 create mode 100644 programs/other/fb2reader/SRC/kfonts.ob07 create mode 100644 programs/other/fb2reader/SRC/tables.ob07 diff --git a/data/common/fb2read b/data/common/fb2read index da36129bddc95dec2d0a4568ba5ae7b8d2391939..bbcdee4e75d8695b22f5703f1d5b996818cc4d66 100644 GIT binary patch literal 24753 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

TMPk4a0$}d&wHgzJf2(FgH@<@1^v~|Wg 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 Q$jgkkAGbOHMhE}^1AKu0BLDyZ literal 24997 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 endheap THEN + IF K.sysfunc2(18, 16) > ASR(HEAP_SIZE, 10) THEN + temp := K.sysfunc3(68, 12, HEAP_SIZE) + ELSE + temp := 0 + END; + IF temp # 0 THEN + mem_commit(temp, HEAP_SIZE); + heap := temp; + endheap := heap + HEAP_SIZE + ELSE + temp := -1 + END + END; + IF (heap # 0) & (temp # -1) THEN + SYSTEM.PUT(heap, size); + res := heap + 4; + heap := heap + size + ELSE + res := 0 + END + END + ELSE + IF K.sysfunc2(18, 16) > ASR(size, 10) THEN + res := K.sysfunc3(68, 12, size); + IF res # 0 THEN + mem_commit(res, size); + SYSTEM.PUT(res, size); + INC(res, 4) + END + ELSE + res := 0 + END + END; + IF (res # 0) & (size <= MAX_SIZE) THEN + zeromem(ASR(size, 2) - 1, res) + END + RETURN res +END __NEW; + + +PROCEDURE __DISPOSE (ptr: INTEGER): INTEGER; +VAR + size, idx: INTEGER; +BEGIN + DEC(ptr, 4); + SYSTEM.GET(ptr, size); + IF size <= MAX_SIZE THEN + idx := ASR(size, 5); + SYSTEM.PUT(ptr, pockets[idx]); + pockets[idx] := ptr + ELSE + size := K.sysfunc3(68, 13, ptr) + END + RETURN 0 +END __DISPOSE; + + +PROCEDURE NEW_DISPOSE (func, arg: INTEGER): INTEGER; +VAR + res: INTEGER; + +BEGIN + IF multi THEN + EnterCriticalSection(CriticalSection) + END; + + IF func = _new THEN + res := __NEW(arg) + ELSIF func = _dispose THEN + res := __DISPOSE(arg) + END; + + IF multi THEN + LeaveCriticalSection(CriticalSection) + END + + RETURN res +END NEW_DISPOSE; + + +PROCEDURE _NEW* (size: INTEGER): INTEGER; + RETURN NEW_DISPOSE(_new, size) +END _NEW; + + +PROCEDURE _DISPOSE* (ptr: INTEGER): INTEGER; + RETURN NEW_DISPOSE(_dispose, ptr) +END _DISPOSE; + + +PROCEDURE exit* (p1: INTEGER); +BEGIN + K.sysfunc1(-1) +END exit; + + +PROCEDURE exit_thread* (p1: INTEGER); +BEGIN + K.sysfunc1(-1) +END exit_thread; + + +PROCEDURE OutStr (pchar: INTEGER); +VAR + c: CHAR; +BEGIN + IF pchar # 0 THEN + REPEAT + SYSTEM.GET(pchar, c); + IF c # 0X THEN + K.OutChar(c) + END; + INC(pchar) + UNTIL c = 0X + END +END OutStr; + + +PROCEDURE DebugMsg* (lpText, lpCaption: INTEGER); +BEGIN + IF lpCaption # 0 THEN + K.OutLn; + OutStr(lpCaption); + K.OutChar(":"); + K.OutLn + END; + OutStr(lpText); + IF lpCaption # 0 THEN + K.OutLn + END +END DebugMsg; + + +PROCEDURE init* (import_, code: INTEGER); +BEGIN + multi := FALSE; + base := code - SizeOfHeader; + K.sysfunc2(68, 11); + InitializeCriticalSection(CriticalSection); + K._init(import_) +END init; + + +PROCEDURE SetMultiThr* (value: BOOLEAN); +BEGIN + multi := value +END SetMultiThr; + + +PROCEDURE GetTickCount* (): INTEGER; + RETURN K.sysfunc2(26, 9) * 10 +END GetTickCount; + + +PROCEDURE dllentry* (hinstDLL, fdwReason, lpvReserved: INTEGER): INTEGER; + RETURN 0 +END dllentry; + + +PROCEDURE sofinit*; +END sofinit; + + +END API. \ No newline at end of file diff --git a/programs/other/fb2reader/SRC/ColorDlg.ob07 b/programs/other/fb2reader/SRC/ColorDlg.ob07 new file mode 100644 index 0000000000..0091ef2572 --- /dev/null +++ b/programs/other/fb2reader/SRC/ColorDlg.ob07 @@ -0,0 +1,87 @@ +(* + Copyright 2016, 2022 Anton Krotov + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*) + +MODULE ColorDlg; + +IMPORT sys := SYSTEM, KOSAPI; + +TYPE + + DRAW_WINDOW = PROCEDURE; + + TDialog = RECORD + type, + procinfo, + com_area_name, + com_area, + start_path: INTEGER; + draw_window: DRAW_WINDOW; + status*, + X, Y, + color_type, + color*: INTEGER; + + procinf: ARRAY 1024 OF CHAR; + s_com_area_name: ARRAY 32 OF CHAR + END; + + Dialog* = POINTER TO TDialog; + + +PROCEDURE [stdcall, "Proc_lib.obj", ""] ColorDialog_start (cd: Dialog); END; +PROCEDURE [stdcall, "Proc_lib.obj", ""] ColorDialog_init (cd: Dialog); END; + +PROCEDURE Show*(cd: Dialog); +BEGIN + IF cd # NIL THEN + cd.X := 0; + cd.Y := 0; + ColorDialog_start(cd) + END +END Show; + +PROCEDURE Create*(draw_window: DRAW_WINDOW): Dialog; +VAR res: Dialog; +BEGIN + NEW(res); + IF res # NIL THEN + res.s_com_area_name := "FFFFFFFF_color_dlg"; + res.com_area := 0; + res.type := 0; + res.color_type := 0; + res.procinfo := sys.ADR(res.procinf[0]); + res.com_area_name := sys.ADR(res.s_com_area_name[0]); + res.start_path := sys.SADR("/sys/colrdial"); + res.draw_window := draw_window; + res.status := 0; + res.X := 0; + res.Y := 0; + res.color := 0; + ColorDialog_init(res) + END + RETURN res +END Create; + +PROCEDURE Destroy*(VAR cd: Dialog); +BEGIN + IF cd # NIL THEN + DISPOSE(cd) + END +END Destroy; + + +END ColorDlg. diff --git a/programs/other/fb2reader/SRC/Conv.ob07 b/programs/other/fb2reader/SRC/Conv.ob07 new file mode 100644 index 0000000000..46111e1381 --- /dev/null +++ b/programs/other/fb2reader/SRC/Conv.ob07 @@ -0,0 +1,84 @@ +(* + Copyright 2016 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Conv; + +IMPORT sys := SYSTEM, Encode; + +VAR table: ARRAY 65536 OF CHAR; + +PROCEDURE GetUtf8 (str: INTEGER; VAR val, idx: INTEGER); +VAR ch: CHAR; +BEGIN + sys.GET(str + idx, ch); INC(idx); + IF ch < 80X THEN + val := ORD(ch) + ELSIF ch < 0E0X THEN + val := ORD(ch) - 192; + sys.GET(str + idx, ch); INC(idx); + val := val * 64 + ORD(ch) - 128 + ELSE + val := ORD(ch) - 224; + sys.GET(str + idx, ch); INC(idx); val := val * 64 + ORD(ch) - 128; + sys.GET(str + idx, ch); INC(idx); val := val * 64 + ORD(ch) - 128 + END +END GetUtf8; + +PROCEDURE convert*(adr, adr2: INTEGER; len: INTEGER); +VAR val, idx: INTEGER; +BEGIN + idx := 0; + WHILE len > 0 DO + GetUtf8(adr, val, idx); + IF (0 <= val) & (val < LEN(table)) THEN + sys.PUT(adr2, table[val]) + ELSE + sys.PUT(adr2, "?") + END; + INC(adr2); + DEC(len) + END +END convert; + +PROCEDURE utf8to1251(code: INTEGER): CHAR; +VAR res: CHAR; i: INTEGER; +BEGIN + res := "?"; + i := 0; + WHILE i <= 255 DO + IF Encode.W1251[i].code = code THEN + res := CHR(i); + i := 255 + END; + INC(i) + END + RETURN res +END utf8to1251; + +PROCEDURE main; +VAR i: INTEGER; +BEGIN + FOR i := 0 TO LEN(table) - 1 DO + table[i] := utf8to1251(i) + END +END main; + +BEGIN + main +END Conv. diff --git a/programs/other/fb2reader/SRC/Cursor.ob07 b/programs/other/fb2reader/SRC/Cursor.ob07 new file mode 100644 index 0000000000..581c1fda51 --- /dev/null +++ b/programs/other/fb2reader/SRC/Cursor.ob07 @@ -0,0 +1,364 @@ +(* + Copyright 2016 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Cursor; + + +IMPORT sys := SYSTEM; + + +PROCEDURE [stdcall] cur; +BEGIN +sys.CODE( +000H, 000H, 002H, 000H, 001H, 000H, 020H, 020H, 000H, 000H, +005H, 000H, 000H, 000H, 0A8H, 00CH, 000H, 000H, 016H, 000H, +000H, 000H, 028H, 000H, 000H, 000H, 020H, 000H, 000H, 000H, +040H, 000H, 000H, 000H, 001H, 000H, 018H, 000H, 000H, 000H, +000H, 000H, 080H, 00CH, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 033H, 033H, 033H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 055H, 055H, 055H, 0BBH, 0BBH, 0BBH, 0BBH, 0BBH, 0BBH, +0BBH, 0BBH, 0BBH, 0AAH, 0AAH, 0AAH, 033H, 033H, 033H, 0AAH, +0AAH, 0AAH, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 033H, 033H, 033H, 0BBH, 0BBH, 0BBH, +0EEH, 0EEH, 0EEH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0EEH, +0EEH, 0EEH, 0AAH, 0AAH, 0AAH, 0EEH, 0EEH, 0EEH, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 033H, 033H, 033H, +0BBH, 0BBH, 0BBH, 0EEH, 0EEH, 0EEH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0EEH, 0EEH, +0EEH, 0FFH, 0FFH, 0FFH, 0AAH, 0AAH, 0AAH, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +033H, 033H, 033H, 0BBH, 0BBH, 0BBH, 0EEH, 0EEH, 0EEH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0CCH, 0CCH, 0CCH, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 055H, 055H, 055H, 0EEH, +0EEH, 0EEH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0E5H, 0E5H, 0E5H, 088H, +088H, 088H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 055H, 055H, 055H, 0EEH, 0EEH, 0EEH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0E5H, 0E5H, 0E5H, 088H, 088H, 088H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 033H, 033H, 033H, 0DDH, 0DDH, +0DDH, 0FFH, 0FFH, 0FFH, 0DDH, 0DDH, 0DDH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0EEH, 0EEH, +0EEH, 0BBH, 0BBH, 0BBH, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 033H, 033H, +033H, 0DDH, 0DDH, 0DDH, 0FFH, 0FFH, 0FFH, 0E5H, 0E5H, 0E5H, +000H, 000H, 000H, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0CCH, 0CCH, 0CCH, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 033H, 033H, 033H, 0DDH, 0DDH, 0DDH, +0FFH, 0FFH, 0FFH, 0E5H, 0E5H, 0E5H, 000H, 000H, 000H, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0CCH, 0CCH, 0CCH, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +055H, 055H, 055H, 0FFH, 0FFH, 0FFH, 0BBH, 0BBH, 0BBH, 000H, +000H, 000H, 033H, 033H, 033H, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0CCH, +0CCH, 0CCH, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 055H, +055H, 055H, 022H, 022H, 022H, 000H, 000H, 000H, 033H, 033H, +033H, 0FFH, 0FFH, 0FFH, 0EEH, 0EEH, 0EEH, 088H, 088H, 088H, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 088H, 088H, 088H, 0E5H, +0E5H, 0E5H, 044H, 044H, 044H, 0E5H, 0E5H, 0E5H, 033H, 033H, +033H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 033H, 033H, 033H, 0FFH, 0FFH, 0FFH, +0E5H, 0E5H, 0E5H, 044H, 044H, 044H, 0F4H, 0F4H, 0F4H, 0E5H, +0E5H, 0E5H, 044H, 044H, 044H, 0E5H, 0E5H, 0E5H, 000H, 000H, +000H, 033H, 033H, 033H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +033H, 033H, 033H, 0FFH, 0FFH, 0FFH, 0E5H, 0E5H, 0E5H, 000H, +000H, 000H, 0AAH, 0AAH, 0AAH, 022H, 022H, 022H, 000H, 000H, +000H, 033H, 033H, 033H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 033H, 033H, 033H, 0FFH, +0FFH, 0FFH, 0E5H, 0E5H, 0E5H, 000H, 000H, 000H, 033H, 033H, +033H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 033H, 033H, 033H, 0FFH, 0FFH, 0FFH, 0E5H, 0E5H, +0E5H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 033H, 033H, +033H, 0FFH, 0FFH, 0FFH, 0E5H, 0E5H, 0E5H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 044H, 044H, 044H, 0EEH, 0EEH, 0EEH, +0E5H, 0E5H, 0E5H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 044H, 044H, 044H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H, +000H, 000H, 000H, 000H, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, +0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0F8H, 027H, 0FFH, 0FFH, +0F8H, 007H, 0FFH, 0FFH, 0F0H, 007H, 0FFH, 0FFH, 0E0H, 003H, +0FFH, 0FFH, 0C0H, 003H, 0FFH, 0FFH, 0C0H, 001H, 0FFH, 0FFH, +0C0H, 001H, 0FFH, 0FFH, 080H, 001H, 0FFH, 0FFH, 000H, 001H, +0FFH, 0FFH, 000H, 001H, 0FFH, 0FFH, 000H, 001H, 0FFH, 0FFH, +090H, 001H, 0FFH, 0FFH, 0F0H, 003H, 0FFH, 0FFH, 0F0H, 00FH, +0FFH, 0FFH, 0F0H, 07FH, 0FFH, 0FFH, 0F0H, 0FFH, 0FFH, 0FFH, +0F0H, 0FFH, 0FFH, 0FFH, 0F0H, 0FFH, 0FFH, 0FFH, 0F9H, 0FFH, +0FFH, 0FFH) +END cur; + + +PROCEDURE GetCursor* (): INTEGER; + RETURN sys.ADR(cur) + 3 +END GetCursor; + + +END Cursor. diff --git a/programs/other/fb2reader/SRC/DOM.ob07 b/programs/other/fb2reader/SRC/DOM.ob07 new file mode 100644 index 0000000000..45ba0bcea5 --- /dev/null +++ b/programs/other/fb2reader/SRC/DOM.ob07 @@ -0,0 +1,1756 @@ +(* + Copyright 2016-2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE DOM; + +IMPORT XML, SU := SysUtils, S := Strings, Font, Window, G := Graph, LibImg, + RF := ReadFile, File, Write, Read, Ini, K := KOSAPI, sys := SYSTEM, + V := Vector, Cursor, box_lib, tables, Search; + + +CONST + + BACK_COLOR* = 0; + TEXT_COLOR* = 1; + ITALIC_COLOR* = 2; + LINK_COLOR* = 3; + VISITED_COLOR* = 4; + CLICKED_COLOR* = 5; + + CellPadding = 5; + + +TYPE + + TSettings* = RECORD + + Colors* : ARRAY 6 OF INTEGER; + FontSize* : INTEGER; + TwoCol* : BOOLEAN; + b_pict* : BOOLEAN; + + PADDING* : RECORD Left, Right, Top*, Bottom, ColInter, LRpc*, CInt*: INTEGER END; + + PARAGRAPH*, + EPIGRAPH*, + LEVEL, + SUB, + SUP, + InterLin*, + Picture*, + SpaceW: INTEGER + + END; + + StackItem = POINTER TO TStackItem; + + TStackItem = RECORD (XML.DESC_ELEMENT) + + body : XML.TAG; + Ycur : INTEGER; + d : REAL + + END; + + +VAR + + Settings* : TSettings; + Canvas_X, Canvas_Y: INTEGER; + ColLeft : Window.TRect; + ColRight : Window.TRect; + + Ymin, Ymax, Ycur : INTEGER; + + X, Y, W, LineH, W1, W2: INTEGER; + + epigraph : INTEGER; + sup, sub : INTEGER; + ref_depth : INTEGER; + align : INTEGER; + code : INTEGER; + strong : INTEGER; + italic : INTEGER; + strike : INTEGER; + refer : INTEGER; + + Text : ARRAY 100000 OF XML.TEXT; + TextCount : INTEGER; + + Lines: INTEGER; + + description, contents, mainbody, body, ref, cover, clickRef, hoverRef: XML.TAG; + + MainBody: BOOLEAN; + + f_stk, b_stk, vis_ref: XML.LIST; + + FilePath, FileName: S.STRING; + + done, last, resized, loaded*, mouseDown: BOOLEAN; + + Stack*: ARRAY 1000000 OF CHAR; + + Ycont: INTEGER; + + history: File.FS; + + references: V.VECTOR; + cursor: INTEGER; + + fsize2, chksum: INTEGER; + + sb: box_lib.scrollbar; + urlstr* : S.STRING; + DrawStatus, DrawToolbar: PROCEDURE; + + +PROCEDURE PushRef(ref: XML.TAG); +VAR item: StackItem; +BEGIN + NEW(item); + item.body := ref; + XML.AddItem(vis_ref, item); +END PushRef; + + +PROCEDURE Push(VAR stk: XML.LIST); +VAR item: StackItem; +BEGIN + NEW(item); + item.body := body; + item.Ycur := Ycur; + XML.AddItem(stk, item); + IF body = contents THEN + Ycont := Ycur + END +END Push; + + +PROCEDURE Pop(VAR stk: XML.LIST); +VAR item : StackItem; +BEGIN + item := stk.last(StackItem); + IF item # NIL THEN + body := item.body; + Ymin := body.Ymin; + Ymax := body.Ymax; + Ycur := item.Ycur; + XML.DelLastItem(stk) + END +END Pop; + + +PROCEDURE Clear(VAR stk: XML.LIST); +BEGIN + REPEAT + XML.DelLastItem(stk) + UNTIL stk.last = NIL +END Clear; + + +PROCEDURE AddToLine(text: XML.TEXT); +BEGIN + Text[TextCount] := text; + INC(TextCount) +END AddToLine; + + +PROCEDURE Epigraph(): INTEGER; + RETURN ORD(epigraph > 0) * Settings.EPIGRAPH +END Epigraph; + + +PROCEDURE SpaceWidth(): INTEGER; +VAR Result: INTEGER; +BEGIN + IF code > 0 THEN + Result := Font.MonoWidth() + ELSE + Result := Settings.SpaceW + END + RETURN Result +END SpaceWidth; + + +PROCEDURE Trim; +VAR n: INTEGER; +BEGIN + IF TextCount > 0 THEN + n := TextCount - 1; + WHILE (n >= 0) & (Text[n] IS XML.SPACE) DO + Text[n].width := -1; + DEC(n) + END; + TextCount := n + 1 + END +END Trim; + + +PROCEDURE Align; +VAR + i, n, sp, d, quo, rem, x: INTEGER; + text: XML.TEXT; +BEGIN + IF (TextCount > 0) & (code = 0) & (align # 3) THEN + sp := 0; + Trim; + n := TextCount - 1; + IF n >= 0 THEN + d := W - Text[n].X - Text[n].width + END; + IF align = 1 THEN + x := (d + Text[0].X) DIV 2 + ELSIF align = 2 THEN + x := d + Text[0].X + ELSIF align = 0 THEN + x := Text[0].X; + FOR i := 0 TO n DO + IF Text[i] IS XML.SPACE THEN + INC(sp) + END + END; + IF sp > 0 THEN + quo := d DIV sp; + rem := d MOD sp; + FOR i := 0 TO n DO + IF Text[i] IS XML.SPACE THEN + text := Text[i]; + text.width := text.width + quo + ORD(rem > 0); + DEC(rem) + END + END + END + END; + FOR i := 0 TO n DO + text := Text[i]; + text.X := x; + INC(x, text.width) + END + END +END Align; + + +PROCEDURE NewLine; +BEGIN + IF align # 0 THEN + Align + END; + X := Epigraph(); + INC(Y, LineH); + TextCount := 0 +END NewLine; + + +PROCEDURE Sup(open: BOOLEAN); +BEGIN + IF open THEN + IF sup = 0 THEN + DEC(Y, Settings.SUP) + END; + INC(sup) + ELSE + DEC(sup); + IF sup = 0 THEN + INC(Y, Settings.SUP) + END + END +END Sup; + + +PROCEDURE Sub(open: BOOLEAN); +BEGIN + IF open THEN + IF sub = 0 THEN + INC(Y, Settings.SUB) + END; + INC(sub) + ELSE + DEC(sub); + IF sub = 0 THEN + DEC(Y, Settings.SUB) + END + END +END Sub; + + +PROCEDURE Split(word: XML.WORD); +VAR + i, n, max, len: INTEGER; + c: CHAR; + rem: XML.WORD; +BEGIN + WHILE Font.TextWidth(word.value, max) <= W DO + INC(max) + END; + DEC(max); + IF max = 0 THEN + max := 1 + END; + i := 0; + n := 0; + len := word.value.last - word.value.first + 1; + WHILE (n <= max) & (i < len) DO + c := S.GetChar(word.value, i); + INC(n); + IF (80X <= c) & (c <= 0BFX) THEN + DEC(n) + END; + INC(i) + END; + IF n > max THEN + DEC(i); + rem := XML.CreateWord(); + rem^ := word^; + rem.value.first := word.value.first + i; + word.next := rem; + word.value.last := rem.value.first - 1; + word.length := S.Utf8Length(word.value); + word.width := Font.TextWidth(word.value, word.length) + END +END Split; + + +PROCEDURE Depth(tag: XML.ELEMENT): INTEGER; +VAR n: INTEGER; +BEGIN + n := 0; + WHILE tag # NIL DO + IF tag(XML.TAG).value = XML.tag_section THEN + INC(n) + END; + tag := tag.parent + END + RETURN n +END Depth; + + +PROCEDURE shift(tag: XML.TAG; shx, shy: INTEGER); +VAR cur: XML.ELEMENT; t: XML.TAG; +BEGIN + cur := tag.child.first; + WHILE cur # NIL DO + IF cur IS XML.TAG THEN + t := cur(XML.TAG); + INC(t.X, shx); + INC(t.Ymin, shy); + INC(t.Ymax, shy); + shift(t, shx, shy) + ELSIF cur IS XML.TEXT THEN + INC(cur(XML.TEXT).X, shx); + INC(cur(XML.TEXT).Y, shy) + END; + cur := cur.next + END +END shift; + + +PROCEDURE getspan(td: XML.TAG; span: S.STRING): INTEGER; +VAR res: INTEGER; + attr_value: S.CHARS; + err: BOOLEAN; +BEGIN + IF XML.GetAttr(td, span, attr_value) THEN + res := S.CharsToInt(attr_value, err); + IF err OR (res <= 0) THEN + res := 1 + END + ELSE + res := 1 + END + RETURN res +END getspan; + + +PROCEDURE td(t: tables.Table; tag: XML.TAG); +BEGIN + tag.cell := t.cells.count; + tables.td(t, getspan(tag, "colspan"), getspan(tag, "rowspan")) +END td; + + +PROCEDURE tr(t: tables.Table; tag: XML.TAG); +VAR + cur : XML.ELEMENT; + cell : XML.TAG; +BEGIN + tables.tr(t); + cur := tag.child.first; + WHILE cur # NIL DO + IF cur IS XML.TAG THEN + cell := cur(XML.TAG); + IF (cell.value = XML.tag_td) OR (cell.value = XML.tag_th) THEN + cell.table := t; + td(t, cell) + END + END; + cur := cur.next + END +END tr; + + +PROCEDURE table(t: tables.Table; tag: XML.TAG; open: BOOLEAN); +VAR + cur : XML.ELEMENT; + row : XML.TAG; +BEGIN + IF open THEN + tables.table(t, W, TRUE); + cur := tag.child.first; + WHILE cur # NIL DO + IF cur IS XML.TAG THEN + row := cur(XML.TAG); + IF row.value = XML.tag_tr THEN + row.table := t; + tr(t, row) + END + END; + cur := cur.next + END; + tables.table(t, W, FALSE) + END +END table; + + +PROCEDURE layout(body: XML.ELEMENT); +VAR + cur : XML.ELEMENT; + tag : XML.TAG; + word : XML.WORD; + text : XML.TEXT; + tag_value : INTEGER; + _align : INTEGER; + title : XML.ELEMENT; + width : INTEGER; + height1 : INTEGER; + height2 : INTEGER; + + + PROCEDURE Image (VAR tag: XML.TAG); + VAR + note : BOOLEAN; + img : XML.TAG; + URL : INTEGER; + chars : S.CHARS; + sizeY : INTEGER; + FName : S.STRING; + path : S.STRING; + BEGIN + IF tag.img # 0 THEN + LibImg.img_destroy(tag.img) + END; + img := XML.GetRef(tag, note, URL); + IF img # NIL THEN + IF img.child.first IS XML.WORD THEN + chars := img.child.first(XML.WORD).value; + tag.img := LibImg.GetImg(chars.first, chars.last - chars.first + 1, W, sizeY); + IF tag.img # 0 THEN + INC(Y, (sizeY DIV LineH) * LineH); + NewLine; + tag.Ymax := Y - Y MOD LineH + END + END + ELSIF URL # 0 THEN + S.PtrToString(URL, FName); + tag.img := LibImg.LoadFromFile(FName, W, sizeY); + IF tag.img = 0 THEN + path := FilePath; + IF FName[0] # "/" THEN + S.Append(path, "/") + END; + S.Append(path, FName); + tag.img := LibImg.LoadFromFile(path, W, sizeY); + END; + IF tag.img # 0 THEN + INC(Y, (sizeY DIV LineH) * LineH); + NewLine; + tag.Ymax := Y - Y MOD LineH + END + END + END Image; + + +BEGIN + cur := body; + WHILE cur # NIL DO + IF cur IS XML.TAG THEN + tag := cur(XML.TAG); + tag_value := tag.value; + CASE tag_value OF + |XML.tag_p, XML.tag_v: + Trim; + IF TextCount > 0 THEN + NewLine + END; + X := Settings.PARAGRAPH + Epigraph() + |XML.tag_epigraph: + NewLine; + INC(epigraph) + |XML.tag_contents_item: + INC(ref_depth); + Settings.EPIGRAPH := Settings.LEVEL * Depth(tag); + _align := align; + align := 3 + |XML.tag_title: + INC(strong); + Font.Bold(TRUE); + _align := align; + align := 1; + IF MainBody THEN + tag.value := XML.tag_contents_item; + title := XML.Copy(tag); + XML.AddChild(contents, title); + title.parent := tag.parent; + tag.value := XML.tag_title + END + |XML.tag_subtitle: + NewLine; + _align := align; + align := 1 + |XML.tag_text_author, XML.tag_date: + _align := align; + align := 2 + |XML.tag_section, XML.tag_body, XML.tag_empty_line, XML.tag_poem, XML.tag_stanza, XML.tag_annotation, XML.tag_cite: + NewLine + |XML.tag_a: + INC(ref_depth); + IF XML.IsNote(tag) THEN + Sup(TRUE) + END + |XML.tag_sup: + Sup(TRUE) + |XML.tag_sub: + Sub(TRUE) + |XML.tag_code: + Font.sysfont(TRUE); + INC(code) + |XML.tag_image: + tag.X := 0; + NewLine; + NewLine + |XML.tag_coverpage: + cover := tag + + |XML.tag_table: + NewLine; + tables.destroy(tag.table); + NEW(tag.table); + table(tag.table, tag, TRUE) + |XML.tag_td, XML.tag_th: + IF tag_value = XML.tag_th THEN + INC(strong); + Font.Bold(TRUE); + END; + SU.ErrorIf(tag.parent(XML.TAG).value # XML.tag_tr, 21); + NewLine; DEC(Y, LineH); + tag.Width := tables.get_width(tag.table, tag.cell); + tag.X := tables.get_x(tag.table, tag.cell); + width := W; + W := tag.Width - 2 * CellPadding; + IF W <= 0 THEN + W := 1 + END + |XML.tag_tr: + SU.ErrorIf(tag.parent(XML.TAG).value # XML.tag_table, 20) + + |XML.tag_strong: + INC(strong); + Font.Bold(TRUE) + ELSE + END; + + tag.Ymin := Y - Y MOD LineH; + layout(tag.child.first); + tag.Ymax := Y - Y MOD LineH; + + CASE tag_value OF + |XML.tag_epigraph: + NewLine; + DEC(epigraph) + |XML.tag_subtitle: + NewLine; + NewLine; + align := _align + |XML.tag_title, XML.tag_text_author, XML.tag_date: + DEC(strong); + Font.Bold(strong > 0); + NewLine; + align := _align + |XML.tag_contents_item: + DEC(ref_depth); + align := _align; + |XML.tag_section, XML.tag_poem, XML.tag_v, XML.tag_p, XML.tag_annotation, XML.tag_cite: + NewLine + |XML.tag_a: + DEC(ref_depth); + IF XML.IsNote(tag) THEN + Sup(FALSE) + END + |XML.tag_sup: + Sup(FALSE) + |XML.tag_sub: + Sub(FALSE) + |XML.tag_code: + DEC(code); + Font.sysfont(code > 0) + |XML.tag_image: + Image(tag) + + |XML.tag_table: + Y := tag.Ymin + tables.get_table_height(tag.table); + tag.Ymax := Y - Y MOD LineH; + NewLine; + |XML.tag_td, XML.tag_th: + IF tag_value = XML.tag_th THEN + DEC(strong); + Font.Bold(strong > 0) + END; + W := width; + NewLine; + Y := tag.Ymin + Settings.SUP; //!!! + height1 := tables.get_height(tag.table, tag.cell); + height2 := tag.Ymax - tag.Ymin + LineH; + IF height2 > height1 THEN + tables.set_height(tag.table, tag.cell, height2) + END; + INC(tag.Ymin, tables.get_y(tag.table, tag.cell)); + INC(tag.Ymax, tables.get_height(tag.table, tag.cell)); + shift(tag, tag.X + CellPadding, tables.get_y(tag.table, tag.cell)); + + |XML.tag_strong: + DEC(strong); + Font.Bold(strong > 0) + ELSE + END + ELSIF cur IS XML.WORD THEN + word := cur(XML.WORD); + word.length := S.Utf8Length(word.value); + word.width := Font.TextWidth(word.value, word.length); + IF W - X < word.width THEN + Align; + NewLine + END; + IF W < word.width THEN + Split(word) + END + ELSIF cur IS XML.SPACE THEN + IF W - X < SpaceWidth() THEN + cur(XML.SPACE).width := 0 + ELSE + cur(XML.SPACE).width := SpaceWidth() + END + END; + IF cur IS XML.TEXT THEN + IF ref_depth > 0 THEN + V.push(references, cur) + END; + text := cur(XML.TEXT); + text.X := X; + text.Y := Y; + INC(X, text.width); + AddToLine(text) + END; + cur := cur.next + END +END layout; + + +PROCEDURE layout2(body: XML.ELEMENT); +VAR + color : INTEGER; + cur : XML.ELEMENT; + text : XML.TEXT; + tag : XML.TAG; + y, y0 : INTEGER; + value : INTEGER; + + PROCEDURE DrawText(Col: Window.TRect; min, max, y0, y: INTEGER; right: BOOLEAN; VAR text: XML.TEXT); + VAR word: XML.WORD; + BEGIN + IF (min <= y0) & (y0 <= max) THEN + Font.sysfont(code > 0); + IF text IS XML.WORD THEN + word := text(XML.WORD); + Font.Text(Col, word.X, y - Col.Height * ORD(right), word.value.first, word.length); + END; + Font.StrikeText(Col, text.X, y - Col.Height * ORD(right), text.width) + END + END DrawText; + + PROCEDURE Image(VAR tag: XML.TAG); + VAR sizeX, sizeY, img, y: INTEGER; + BEGIN + IF tag.img # 0 THEN + y := Ycur; + LibImg.GetInf(tag.img, sizeX, sizeY, img); + IF (y <= tag.Ymax) & (tag.Ymin <= y + ColLeft.Height) THEN + G.Image(ColLeft.Left + tag.X, tag.Ymin - y + ColLeft.Top, sizeX, sizeY, img, ColLeft.Top, ColLeft.Top + ColLeft.Height - 1) + END; + IF Settings.TwoCol THEN + y := Ycur + ColLeft.Height; + IF (y <= tag.Ymax) & (tag.Ymin <= y + ColRight.Height) THEN + G.Image(ColRight.Left + tag.X, tag.Ymin - y + ColLeft.Top, sizeX, sizeY, img, ColRight.Top, ColRight.Top + ColRight.Height - 1) + END + END + END + END Image; + + PROCEDURE td(VAR tag: XML.TAG); + VAR x1, y1, x2, y2, cl: INTEGER; + BEGIN + x1 := tag.X + ColLeft.Left; + y1 := tag.Ymin - Ycur + ColLeft.Top; + x2 := x1 + tag.Width; + y2 := y1 + tables.get_height(tag.table, tag.cell); + cl := G.GetColor(); + G.SetColor(Settings.Colors[TEXT_COLOR]); + G.Rect(x1, y1, x2, y2); + IF Settings.TwoCol THEN + x1 := x1 - ColLeft.Left + ColRight.Left; + x2 := x2 - ColLeft.Left + ColRight.Left; + y1 := y1 - ColLeft.Height; + y2 := y2 - ColLeft.Height; + G.Rect(x1, y1, x2, y2) + END; + G.SetColor(cl) + END td; + +BEGIN + cur := body; + WHILE cur # NIL DO + IF cur IS XML.TAG THEN + tag := cur(XML.TAG); + IF (tag.value = XML.tag_td) OR (tag.value = XML.tag_th) THEN + tag.Ymax := tag.Ymin + tables.get_height(tag.table, tag.cell) + END; + + IF (tag.Ymin < Ycur + LineH * Lines * (ORD(Settings.TwoCol) + 1)) & (tag.Ymax >= Ycur) OR (tag.value = XML.tag_tr) THEN + + value := tag.value; + CASE value OF + |XML.tag_a: + INC(refer); + color := Font.Font.color; + IF tag.Clicked THEN + Font.SetFontColor(Settings.Colors[CLICKED_COLOR]) + ELSE + IF tag.Visited THEN + Font.SetFontColor(Settings.Colors[VISITED_COLOR]) + ELSE + Font.SetFontColor(Settings.Colors[LINK_COLOR]) + END + END + |XML.tag_contents_item: + IF tag.Clicked THEN + INC(refer); + color := Font.Font.color; + Font.SetFontColor(Settings.Colors[CLICKED_COLOR]) + ELSIF tag.Visited THEN + INC(refer); + color := Font.Font.color; + Font.SetFontColor(Settings.Colors[VISITED_COLOR]) + END + |XML.tag_title, XML.tag_strong, XML.tag_th: + INC(strong); + Font.Bold(TRUE) + |XML.tag_strikethrough: + INC(strike); + Font.Strike(TRUE) + |XML.tag_epigraph, XML.tag_cite, XML.tag_emphasis: + INC(italic); + Font.Italic(TRUE, refer = 0) + |XML.tag_image: + Image(tag) + |XML.tag_code: + INC(code) + ELSE + END; + layout2(tag.child.first); + CASE value OF + |XML.tag_a: + DEC(refer); + Font.SetFontColor(color) + |XML.tag_contents_item: + IF tag.Clicked OR tag.Visited THEN + DEC(refer); + Font.SetFontColor(color) + END + |XML.tag_title, XML.tag_strong: + DEC(strong); + Font.Bold(strong > 0) + |XML.tag_strikethrough: + DEC(strike); + Font.Strike(strike > 0) + |XML.tag_epigraph, XML.tag_cite, XML.tag_emphasis: + DEC(italic); + Font.Italic(italic > 0, refer = 0) + |XML.tag_td: + td(tag) + |XML.tag_th: + DEC(strong); + Font.Bold(strong > 0); + td(tag) + |XML.tag_code: + DEC(code) + ELSE + END + + END + ELSIF cur IS XML.TEXT THEN + text := cur(XML.TEXT); + y := text.Y - Ycur; + y0 := y - y MOD LineH; + DrawText(ColLeft, 0, ColLeft.Height - LineH, y0, y, FALSE, text); + IF Settings.TwoCol THEN + DrawText(ColRight, ColLeft.Height, ColLeft.Height + ColRight.Height - LineH, y0, y, TRUE, text) + END + END; + cur := cur.next + END +END layout2; + + +PROCEDURE DrawProgress(progress_color: INTEGER); +VAR max_X, max_Y: INTEGER; +BEGIN + max_X := G.Buffer.Width - 1; + max_Y := G.Buffer.Height - 1; + G.SetColor(0); + G.HLine(0, max_X, 0); + G.HLine(0, max_X, max_Y); + G.VLine(0, 0, max_Y); + sb.max_area := (Ymax - Ymin) DIV LineH + 50; + sb.cur_area := 50; + sb.position := (Ycur - Ymin) DIV LineH; + box_lib.scrollbar_v_draw(sb) +END DrawProgress; + + +PROCEDURE Draw*; +VAR back, max_X, max_Y: INTEGER; +BEGIN + back := Settings.Colors[BACK_COLOR]; + max_X := G.Buffer.Width - 1; + max_Y := G.Buffer.Height - 1; + G.Copy(G.Buffer3, G.Buffer, 0, G.Buffer.Height, 0); + Font.SetFontColor(Settings.Colors[TEXT_COLOR]); + IF ((body = description) OR (body = contents)) & Settings.TwoCol THEN + Settings.TwoCol := FALSE; + layout2(body.child.first); + Settings.TwoCol := TRUE; + Search.draw(body, ColLeft, ColRight, Ycur, LineH, FALSE) + ELSE + layout2(body.child.first); + Search.draw(body, ColLeft, ColRight, Ycur, LineH, Settings.TwoCol) + END; + G.Copy(G.Buffer3, G.Buffer, 0, ColLeft.Top + 1, 0); + G.Copy(G.Buffer3, G.Buffer, max_Y - ColLeft.Top, ColLeft.Top + 1, max_Y - ColLeft.Top); + DrawProgress(0); + G.Draw(Canvas_X, Canvas_Y); + DrawToolbar; + DrawStatus +END Draw; + + +PROCEDURE BackEnabled* (): BOOLEAN; + RETURN b_stk.first # NIL +END BackEnabled; + + +PROCEDURE FrwEnabled* (): BOOLEAN; + RETURN f_stk.first # NIL +END FrwEnabled; + + +PROCEDURE ContentsEnabled* (): BOOLEAN; + RETURN (contents # NIL) (*& (body # contents)*) +END ContentsEnabled; + + +PROCEDURE DescrEnabled* (): BOOLEAN; + RETURN (description # NIL) (*& (body # description)*) +END DescrEnabled; + + +PROCEDURE Back*; +BEGIN + IF b_stk.first # NIL THEN + Push(f_stk); + Pop(b_stk) + END +END Back; + + +PROCEDURE Forward*; +BEGIN + IF f_stk.first # NIL THEN + Push(b_stk); + Pop(f_stk) + END +END Forward; + + +PROCEDURE Contents*; +BEGIN + IF (contents # NIL) & (body # contents) THEN + Push(b_stk); + Clear(f_stk); + body := contents; + Ycur := Ycont; + Ymin := 0; + Ymax := body.Ymax + END +END Contents; + + +PROCEDURE Descr*; +BEGIN + IF (description # NIL) & (body # description) THEN + Push(b_stk); + Clear(f_stk); + body := description; + Ycur := 0; + Ymin := 0; + Ymax := body.Ymax + END +END Descr; + + +PROCEDURE Up*; +BEGIN + DEC(Ycur, LineH); + SU.MinMax(Ycur, Ymin, Ymax) +END Up; + + +PROCEDURE Down*; +BEGIN + INC(Ycur, LineH); + SU.MinMax(Ycur, Ymin, Ymax) +END Down; + + +PROCEDURE PageUp*; +VAR i: INTEGER; +BEGIN + FOR i := 1 TO Lines * (ORD(Settings.TwoCol) + 1) DO + Up + END +END PageUp; + + +PROCEDURE PageDown*; +VAR i: INTEGER; +BEGIN + FOR i := 1 TO Lines * (ORD(Settings.TwoCol) + 1) DO + Down + END +END PageDown; + + +PROCEDURE Home*; +BEGIN + IF Ycur # Ymin THEN + Push(b_stk); + Clear(f_stk); + Ycur := Ymin + END +END Home; + + +PROCEDURE End*; +BEGIN + IF Ycur # Ymax THEN + Push(b_stk); + Clear(f_stk); + Ycur := Ymax + END +END End; + + +PROCEDURE ScrollBar*; +BEGIN + Ycur := sb.position * LineH + Ymin +END ScrollBar; + + +PROCEDURE GetBody(tag: XML.TAG): XML.TAG; +BEGIN + WHILE (tag # NIL) & (tag.value # XML.tag_body) DO + tag := tag.parent(XML.TAG) + END + RETURN tag +END GetBody; + + +PROCEDURE layout3(Body: XML.ELEMENT; X, Y: INTEGER); +VAR + ptr : V.ANYPTR; + text : XML.TEXT; + sect : XML.TAG; + y : INTEGER; + i : INTEGER; +BEGIN + i := 0; + WHILE i < references.count DO + ptr := V.get(references, i); + text := ptr(XML.TEXT); + y := text.Y - Ycur; + IF (y <= Y) & (Y <= y + Font.FontH()) & (text.X <= X) & (X <= text.X + text.width) THEN + sect := text.parent(XML.TAG); + IF Body = contents THEN + WHILE (sect # NIL) & (sect.value # XML.tag_contents_item) DO + sect := sect.parent(XML.TAG) + END + ELSE + WHILE (sect # NIL) & (sect # Body) DO + IF sect.value = XML.tag_contents_item THEN + sect := NIL + ELSE + sect := sect.parent(XML.TAG) + END + END + END; + + IF sect # NIL THEN + sect := text.parent(XML.TAG); + WHILE sect # NIL DO + IF (sect.value = XML.tag_contents_item) & (Body = contents) OR (sect.value = XML.tag_a) THEN + ref := sect; + sect := NIL; + i := references.count + ELSE + sect := sect.parent(XML.TAG) + END + END + END + END; + INC(i) + END +END layout3; + + +PROCEDURE MouseDown; +BEGIN + IF ~mouseDown THEN + mouseDown := TRUE; + clickRef := ref; + ref.Clicked := TRUE; + Draw + END +END MouseDown; + + +PROCEDURE MouseUp; +VAR + note : BOOLEAN; + URL : INTEGER; + redraw: BOOLEAN; +BEGIN + redraw := FALSE; + mouseDown := FALSE; + IF (ref # NIL) & (clickRef = ref) & ref.Clicked THEN + redraw := TRUE; + ref.Clicked := FALSE; + note := FALSE; + URL := 0; + IF ref.value = XML.tag_a THEN + ref := XML.GetRef(ref, note, URL) + ELSE + ref := ref.parent(XML.TAG) + END; + IF ref # NIL THEN + Push(b_stk); + Clear(f_stk); + Ycur := ref.Ymin; + IF note THEN + body := ref + ELSE + body := GetBody(ref) + END; + Ymax := body.Ymax; + Ymin := body.Ymin; + + IF ~clickRef.Visited THEN + clickRef.Visited := TRUE; + PushRef(clickRef) + END + ELSIF URL # 0 THEN + SU.Run(Ini.Browser, URL); + IF ~clickRef.Visited THEN + clickRef.Visited := TRUE; + PushRef(clickRef) + END + END; + + END; + IF clickRef # NIL THEN + clickRef.Clicked := FALSE; + clickRef := NIL; + redraw := TRUE + END; + IF hoverRef # NIL THEN + hoverRef.Clicked := FALSE; + hoverRef := NIL; + redraw := TRUE + END; + IF redraw THEN + Draw + END +END MouseUp; + + +PROCEDURE Click*(X, Y: INTEGER; clicked: BOOLEAN); +VAR + note : BOOLEAN; + URL : INTEGER; + urlchars: S.CHARS; + urlstr1 : S.STRING; +BEGIN + DEC(Y, Settings.PADDING.Top); + DEC(X, Settings.PADDING.Left); + IF (0 <= Y) & (Y <= Lines * LineH) THEN + ref := NIL; + layout3(body, X, Y); + IF (ref = NIL) & Settings.TwoCol THEN + layout3(body, X - ColLeft.Width - Settings.PADDING.ColInter, Y + Lines * LineH); + END; + hoverRef := ref; + IF clicked THEN + MouseDown + ELSE + MouseUp + END; + IF ref # NIL THEN + SU.SetCursor(cursor); + note := FALSE; + URL := 0; + IF ref.value = XML.tag_a THEN + ref := XML.GetRef(ref, note, URL) + END; + IF URL # 0 THEN + S.PtrToString(URL, urlstr1); + S.StrToChars(urlstr1, urlchars) + END + ELSE + SU.SetCursor(0); + urlstr1 := "" + END; + IF urlstr1 # urlstr THEN + urlstr := urlstr1; + DrawStatus + END + ELSE + SU.SetCursor(0); + urlstr := ""; + ref := NIL; + DrawStatus + END +END Click; + + +PROCEDURE Scroll*(value: INTEGER); +BEGIN + value := 2 * value; + WHILE value > 0 DO + Down; + DEC(value) + ELSIF value < 0 DO + Up; + INC(value) + END +END Scroll; + + +PROCEDURE main(fb: XML.ELEMENT; Contents: BOOLEAN); +VAR + cur: XML.ELEMENT; + tag: XML.TAG; + par, epi: INTEGER; + + + PROCEDURE lout(body: XML.ELEMENT); + BEGIN + TextCount := 0; + X := 0; + Y := Settings.SUP; + layout(body(XML.TAG).child.first); + body(XML.TAG).Ymax := Y - Settings.SUP + END lout; + + PROCEDURE lout_one_col(body: XML.ELEMENT); + BEGIN + IF body # NIL THEN + IF Settings.TwoCol THEN + W := W2; + Settings.TwoCol := FALSE; + lout(body); + Settings.TwoCol := TRUE; + W := W1 + ELSE + lout(body) + END + END + END lout_one_col; + +BEGIN + TextCount := 0; + sup := 0; + sub := 0; + epigraph := 0; + align := 0; + code := 0; + strong := 0; + italic := 0; + strike := 0; + refer := 0; + SU.ErrorIf(fb = NIL, 11); + MainBody := FALSE; + description := NIL; + mainbody := NIL; + cover := NIL; + cur := fb; + cur := cur(XML.TAG).child.first; + WHILE (cur # NIL) & (mainbody = NIL) DO + IF cur IS XML.TAG THEN + tag := cur(XML.TAG); + IF tag.value = XML.tag_description THEN + description := tag + ELSIF tag.value = XML.tag_body THEN + mainbody := tag + END + END; + cur := cur.next + END; + SU.ErrorIf(mainbody = NIL, 12); + + WHILE cur # NIL DO + IF (cur IS XML.TAG) & (cur(XML.TAG).value = XML.tag_body) THEN + lout(cur) + END; + cur := cur.next + END; + + IF Contents THEN + contents := XML.CreateTag(); + MainBody := TRUE; + END; + lout(mainbody); + IF Contents & (contents.child.first = NIL) THEN + DISPOSE(contents) + END; + MainBody := FALSE; + epigraph := 1; + par := Settings.PARAGRAPH; + epi := Settings.EPIGRAPH; + Settings.PARAGRAPH := 0; + Settings.EPIGRAPH := 0; + lout_one_col(contents); + Settings.EPIGRAPH := epi; + Settings.PARAGRAPH := par; + epigraph := 0; + lout_one_col(description); + body := mainbody; + Ymax := body.Ymax; + Ycur := 0; + Ymin := 0; + Ycont := 0 +END main; + + +PROCEDURE Find* (d: INTEGER); +VAR + y, min, max: INTEGER; + +BEGIN + Search.fnext(body, y, d); + IF y >= 0 THEN + DEC(y, y MOD LineH); + min := Ycur; + IF Settings.TwoCol THEN + max := min + ColLeft.Height + ColRight.Height - LineH + ELSE + max := min + ColLeft.Height - LineH + END; + + IF (y < min) OR (y > max) THEN + Ycur := MAX(y - ColLeft.Height DIV 2, 0) + END; + + DEC(Ycur, Ycur MOD LineH) + END +END Find; + + +PROCEDURE OpenSearch*; +BEGIN + Search.open(Find) +END OpenSearch; + + +PROCEDURE CloseSearch*; +BEGIN + Search.close +END CloseSearch; + + +PROCEDURE found* (): BOOLEAN; + RETURN Search.found(body) +END found; + + +PROCEDURE FontSizeChange(fs: INTEGER); +BEGIN + Settings.SUP := fs DIV 4; + Settings.SUB := fs DIV 4; + Settings.SpaceW := fs DIV 2; + Settings.LEVEL := Settings.PARAGRAPH; + Settings.PADDING.Bottom := Settings.PADDING.Top; + Settings.PADDING.Left := G.Buffer.Width * Settings.PADDING.LRpc DIV 100; + IF Settings.PADDING.Left = 0 THEN + Settings.PADDING.Left := 1 + END; + Settings.PADDING.Right := Settings.PADDING.Left; + Settings.PADDING.ColInter := G.Buffer.Width * Settings.PADDING.CInt DIV 100; + + LineH := Font.FontH() + Settings.SUP + Settings.SUB + Settings.InterLin; + Window.InitRect( + ColLeft, Settings.PADDING.Left, Settings.PADDING.Top, + G.Buffer.Width - Settings.PADDING.Left - Settings.PADDING.Right, + G.Buffer.Height - Settings.PADDING.Top - Settings.PADDING.Bottom); + IF Settings.TwoCol THEN + ColLeft.Width := (ColLeft.Width - Settings.PADDING.ColInter) DIV 2; + ColRight := ColLeft; + ColRight.Left := ColLeft.Left + ColLeft.Width + Settings.PADDING.ColInter + END; + W := ColLeft.Width; + Lines := ColLeft.Height DIV LineH; + ColLeft.Height := Lines * LineH; + ColRight.Height := ColLeft.Height; +END FontSizeChange; + + +PROCEDURE Resize*(Width, Height: INTEGER); +VAR d: REAL; resize: BOOLEAN; sizeX, sizeY, data: INTEGER; + + PROCEDURE stk1(stk: XML.LIST); + VAR cur: StackItem; + BEGIN + cur := stk.first(StackItem); + WHILE cur # NIL DO + cur.d := FLT(cur.Ycur - cur.body.Ymin) / FLT(cur.body.Ymax - cur.body.Ymin); + cur := cur.next(StackItem) + END + END stk1; + + PROCEDURE stk2(stk: XML.LIST); + VAR cur: StackItem; + BEGIN + cur := stk.first(StackItem); + WHILE cur # NIL DO + cur.Ycur := FLOOR(FLT(cur.body.Ymax - cur.body.Ymin) * cur.d) + cur.body.Ymin; + cur.Ycur := cur.Ycur - cur.Ycur MOD LineH; + SU.MinMax(cur.Ycur, cur.body.Ymin, cur.body.Ymax); + cur := cur.next(StackItem) + END + END stk2; + +BEGIN + resize := (Width # G.Buffer.Width) OR resized; + G.Resize(Width, Height); + G.SetColor(Settings.Colors[BACK_COLOR]); + IF (Settings.Picture # 0) & Settings.b_pict THEN + LibImg.GetInf(Settings.Picture, sizeX, sizeY, data); + G.BackImage(sizeX, sizeY, data); + ELSE + G.Clear; + G.Copy(G.Buffer, G.Buffer3, 0, G.Buffer.Height, 0) + END; + + IF Font.FontH() # 0 THEN + FontSizeChange(Font.FontH()); + ELSE + FontSizeChange(Settings.FontSize); + END; + + ColLeft.Width := G.Buffer.Width - Settings.PADDING.Left - Settings.PADDING.Right; + IF Settings.TwoCol THEN + ColLeft.Width := (ColLeft.Width - Settings.PADDING.ColInter) DIV 2; + ColRight.Width := ColLeft.Width; + ColRight.Left := ColLeft.Left + ColLeft.Width + Settings.PADDING.ColInter + END; + ColLeft.Height := G.Buffer.Height - Settings.PADDING.Top - Settings.PADDING.Bottom; + Lines := ColLeft.Height DIV LineH; + ColLeft.Height := Lines * LineH; + ColRight.Height := ColLeft.Height; + + IF done & resize THEN + resized := FALSE; + Push(b_stk); + stk1(b_stk); + stk1(f_stk); + IF contents # NIL THEN + d := FLT(Ycont) / FLT(contents.Ymax) + END; + W := ColLeft.Width; + W2 := ColLeft.Width + ColRight.Width + Settings.PADDING.ColInter; + W1 := W; + main(XML.FB, FALSE); + Search.resize; + stk2(b_stk); + stk2(f_stk); + IF contents # NIL THEN + Ycont := FLOOR(FLT(contents.Ymax) * d); + Ycont := Ycont - Ycont MOD LineH; + SU.MinMax(Ycont, 0, contents.Ymax) + END; + Pop(b_stk); + END +END Resize; + + +PROCEDURE SetColors*; +BEGIN + Settings.Colors[BACK_COLOR] := Ini.GetColor("back", Settings.Colors[BACK_COLOR]); + Settings.Colors[TEXT_COLOR] := Ini.GetColor("text", Settings.Colors[TEXT_COLOR]); + Settings.Colors[ITALIC_COLOR] := Ini.GetColor("italic", Settings.Colors[ITALIC_COLOR]); + Settings.Colors[LINK_COLOR] := Ini.GetColor("link", Settings.Colors[LINK_COLOR]); + Settings.Colors[VISITED_COLOR] := Ini.GetColor("visited", Settings.Colors[LINK_COLOR]); +END SetColors; + + +PROCEDURE Resized(set1, set2: TSettings): BOOLEAN; + RETURN (set1.FontSize # set2.FontSize) OR (set1.TwoCol # set2.TwoCol) OR + (set1.PARAGRAPH # set2.PARAGRAPH) OR (set1.EPIGRAPH # set2.EPIGRAPH) OR + (set1.PADDING.LRpc # set2.PADDING.LRpc) OR (set1.PADDING.CInt # set2.PADDING.CInt) + OR (set1.InterLin # set2.InterLin) +END Resized; + + +PROCEDURE SetSettings*(NewSet: TSettings); +BEGIN + resized := Resized(Settings, NewSet) OR resized; + Settings := NewSet; + Font.Init(Settings.Colors[ITALIC_COLOR], Settings.Colors[TEXT_COLOR], Settings.FontSize); + Resize(G.Buffer.Width, G.Buffer.Height) +END SetSettings; + + +PROCEDURE Init*(Left, Top, Width, Height: INTEGER); +BEGIN + G.Resize(Width, Height); + Canvas_X := Left; + Canvas_Y := Top +END Init; + + +PROCEDURE Start; +BEGIN + XML.Open(FileName); + main(XML.FB, TRUE); + done := TRUE; + SU.Halt +END Start; + + +PROCEDURE CleanHistory*(fname: S.STRING); +VAR F: File.FS; pos, pos2, fsize, size, buf, buf2: INTEGER; c: CHAR; +BEGIN + F := File.Open(fname); + IF F # NIL THEN + fsize := File.Seek(F, 0, 2); + pos := File.Seek(F, 0, 0); + buf := K.malloc(fsize + 1024); + buf2 := K.malloc(fsize + 1024); + pos := File.Read(F, buf, fsize); + File.Close(F); + pos := 0; + pos2 := 0; + WHILE pos < fsize DO + sys.GET(buf + pos, size); + sys.GET(buf + pos + 4, c); + IF c = 0X THEN + sys.MOVE(buf + pos, buf2 + pos2, size); + pos2 := pos2 + size + END; + pos := pos + size + END; + F := File.Create(fname); + pos := File.Write(F, buf2, pos2); + File.Close(F); + buf := K.free(buf); + buf2 := K.free(buf2) + END +END CleanHistory; + + +PROCEDURE Save; +VAR history: File.FS; win_size_x, win_size_y, size, pos: INTEGER; + + PROCEDURE WriteInt(history: File.FS; x: INTEGER); + BEGIN + IF Write.Int(history, x) THEN END + END WriteInt; + + PROCEDURE WriteStk(history: File.FS; VAR stk: XML.LIST; links: BOOLEAN); + VAR + cur: StackItem; + BEGIN + WriteInt(history, XML.ListCount(stk)); + cur := stk.first(StackItem); + WHILE cur # NIL DO + WriteInt(history, cur.body.num); + IF ~links THEN + WriteInt(history, cur.Ycur) + END; + cur := cur.next(StackItem) + END + END WriteStk; + +BEGIN + Ini.Save(Settings.Colors, Settings.b_pict); + history := File.Open(Ini.History); + IF history = NIL THEN + history := File.Create(Ini.History) + ELSE + pos := File.Seek(history, 0 , 2) + END; + size := 1 + 18*4 + 1 + 8*(XML.ListCount(b_stk) + XML.ListCount(f_stk)) + 4*XML.ListCount(vis_ref) + 12; + WriteInt(history, size); + IF Write.Char(history, 0X) THEN END; + WriteInt(history, fsize2); + WriteInt(history, chksum); + SU.GetWindowSize(win_size_x, win_size_y); + WriteInt(history, win_size_x); + WriteInt(history, win_size_y); + WriteInt(history, Settings.PADDING.LRpc); + WriteInt(history, Settings.PADDING.Top); + WriteInt(history, Settings.PADDING.CInt); + WriteInt(history, Settings.PARAGRAPH); + WriteInt(history, Settings.EPIGRAPH); + WriteInt(history, Settings.InterLin); + + IF Write.Boolean(history, Settings.TwoCol) THEN END; + + WriteInt(history, Settings.FontSize); + WriteInt(history, body.num); + WriteInt(history, Ymin); + WriteInt(history, Ymax); + WriteInt(history, Ycur); + WriteInt(history, Ycont); + + WriteStk(history, b_stk, FALSE); + WriteStk(history, f_stk, FALSE); + WriteStk(history, vis_ref, TRUE); + + WriteInt(history, size); + + File.Close(history); + CleanHistory(Ini.History) +END Save; + + +PROCEDURE ReadInt(VAR x: INTEGER); +BEGIN + IF Read.Int(history, x) THEN END +END ReadInt; + + +PROCEDURE Load; +VAR body_num, ycur, size, pos: INTEGER; + + PROCEDURE ReadStk(VAR stk: XML.LIST); + VAR n, num: INTEGER; + BEGIN + ReadInt(n); + WHILE n > 0 DO + ReadInt(num); + body := XML.GetTagByNum(num); + ReadInt(Ycur); + Push(stk); + DEC(n) + END + END ReadStk; + + PROCEDURE ReadRef; + VAR + n, num: INTEGER; + ref: XML.TAG; + BEGIN + ReadInt(n); + WHILE n > 0 DO + ReadInt(num); + ref := XML.GetTagByNum(num); + IF ref # NIL THEN + PushRef(ref); + ref.Visited := TRUE + END; + DEC(n) + END + END ReadRef; + +BEGIN + ReadInt(Settings.PADDING.LRpc); + ReadInt(Settings.PADDING.Top); + ReadInt(Settings.PADDING.CInt); + ReadInt(Settings.PARAGRAPH); + ReadInt(Settings.EPIGRAPH); + ReadInt(Settings.InterLin); + IF Read.Boolean(history, Settings.TwoCol) THEN END; + ReadInt(Settings.FontSize); + + SetSettings(Settings); + + ReadInt(body_num); + ReadInt(Ymin); + ReadInt(Ymax); + ReadInt(ycur); + ReadInt(Ycont); + + ReadStk(b_stk); + ReadStk(f_stk); + ReadRef; + + ReadInt(size); + pos := File.Seek(history, -size, 1); + pos := File.Seek(history, 4, 1); + IF Write.Char(history, 1X) THEN END; + + Ycur := ycur; + body := XML.GetTagByNum(body_num); + File.Close(history) +END Load; + + +PROCEDURE GetWinSize*(hist_fn: S.STRING; VAR win_size_x, win_size_y: INTEGER); +VAR c: CHAR; size, pos, x, y, fsize, _chksum: INTEGER; found: BOOLEAN; +BEGIN + fsize2 := RF.FileSize(hist_fn); + chksum := RF.ChkSum(hist_fn); + found := FALSE; + history := File.Open(Ini.History); + pos := File.Seek(history, -4, 2); + last := FALSE; + WHILE pos >= 0 DO + IF Read.Int(history, size) THEN + pos := File.Seek(history, -size + 4, 1); + END; + IF Read.Char(history, c) THEN END; + ReadInt(fsize); + ReadInt(_chksum); + IF (c = 0X) & (fsize = fsize2) & (_chksum = chksum) THEN + found := TRUE; + IF Read.Int(history, x) & Read.Int(history, y) THEN + win_size_x := x; + win_size_y := y; + ELSE + found := FALSE + END; + pos := -1 + ELSE + IF ~last THEN + last := TRUE; + ReadInt(x); + ReadInt(y); + ReadInt(Settings.PADDING.LRpc); + ReadInt(Settings.PADDING.Top); + ReadInt(Settings.PADDING.CInt); + ReadInt(Settings.PARAGRAPH); + ReadInt(Settings.EPIGRAPH); + ReadInt(Settings.InterLin); + IF Read.Boolean(history, Settings.TwoCol) THEN END; + ReadInt(Settings.FontSize); + END; + pos := File.Seek(history, pos - 8, 0) + END + END; + IF ~found THEN + File.Close(history) + END +END GetWinSize; + + +PROCEDURE Open*(FName: S.STRING; DrawWindow, _DrawStatus, _DrawToolbar: SU.ENTRY); +VAR PID, event: INTEGER; +BEGIN + DrawStatus := _DrawStatus; + DrawToolbar := _DrawToolbar; + cursor := SU.LoadCursor(Cursor.GetCursor()); + references := V.create(1024); + ref_depth := 0; + done := FALSE; + loaded := FALSE; + FilePath := FName; + FileName := FName; + S.GetPath(FilePath); + W := ColLeft.Width; + W1 := W; + W2 := ColLeft.Width + ColRight.Width + Settings.PADDING.ColInter; + Lines := ColLeft.Height DIV LineH; + ColLeft.Height := Lines * LineH; + PID := SU.NewThread(Start, Stack); + WHILE ~SU.IsTerminated(PID) DO + event := SU.CheckEvent(); + IF event = 3 THEN + SU.TerminateThreadId(PID); + SU.Halt + END; + G.Progress(RF.Progress()); + G.Draw(Canvas_X, Canvas_Y); + DrawWindow; + SU.Pause(30) + END; + IF ~done THEN + SU.Halt + END; + loaded := TRUE; + resized := TRUE; + IF history # NIL THEN + Load + ELSE + SetSettings(Settings) + END +END Open; + + +PROCEDURE Close*; +BEGIN + SU.DelCursor(cursor); + Save; + SU.Halt +END Close; + + +PROCEDURE SetScrollBar*(_sb: box_lib.scrollbar); +BEGIN + sb := _sb +END SetScrollBar; + + +PROCEDURE Set_b_pict*(b_pict: BOOLEAN); +BEGIN + Settings.b_pict := b_pict +END Set_b_pict; + + +BEGIN + clickRef := NIL; + hoverRef := NIL; + mouseDown := FALSE +END DOM. diff --git a/programs/other/fb2reader/SRC/FB2READ.ob07 b/programs/other/fb2reader/SRC/FB2READ.ob07 new file mode 100644 index 0000000000..8e19474be1 --- /dev/null +++ b/programs/other/fb2reader/SRC/FB2READ.ob07 @@ -0,0 +1,366 @@ +(* + Copyright 2016-2023 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE FB2READ; + +IMPORT + + DOM, SU := SysUtils, S := Strings, W := Window, Settings, OpenDlg, + G := Graph, SelEnc, Ini, File, box_lib, Font, SearchForm, Toolbar; + + +CONST + + CLOSE = 1; + BACK = 16; + FORWARD = 17; + CONTENTS = 18; + DESCR = 19; + SETTINGS = 20; + SEARCH = 21; + + KEY_DOWN_CODE = 177; + KEY_UP_CODE = 178; + KEY_PG_DOWN_CODE = 183; + KEY_PG_UP_CODE = 184; + KEY_HOME_CODE = 180; + KEY_END_CODE = 181; + KEY_F2_CODE = 51; + KEY_F3_CODE = 52; + KEY_F4_CODE = 53; + KEY_F10_CODE = 49; + + TOOLBAR_LEFT = 5; + TOOLBAR_TOP = 6; + BUTTON_HEIGHT = 24; + + CANVAS_LEFT = 1; + CANVAS_TOP = 2 * TOOLBAR_TOP + Toolbar.BtnSize; + + WINDOW_BEVEL = 4; + + SCROLLBAR_WIDTH = 20; + STATUSBAR_HEIGHT = 18; + +VAR + + Window : W.TWindow; + toolbar : Toolbar.tToolbar; + SkinHeight : INTEGER; + Open : OpenDlg.Dialog; + FileName : S.STRING; + sb : box_lib.scrollbar; + + +PROCEDURE ToolbarEnable; +BEGIN + Toolbar.enable(toolbar, BACK, DOM.BackEnabled()); + Toolbar.enable(toolbar, FORWARD, DOM.FrwEnabled()); + Toolbar.enable(toolbar, CONTENTS, DOM.ContentsEnabled()); + Toolbar.enable(toolbar, DESCR, DOM.DescrEnabled()); +END ToolbarEnable; + + +PROCEDURE ToolBar; +BEGIN + sb := box_lib.kolibri_scrollbar(sb, (G.Buffer.Width + CANVAS_LEFT) * 65536 + SCROLLBAR_WIDTH + 1, + CANVAS_TOP * 65536 + G.Buffer.Height, SCROLLBAR_WIDTH, sb.max_area, sb.cur_area, sb.position, SU.lightColor, SU.btnColor, 0, 0); + box_lib.scrollbar_v_draw(sb); + ToolbarEnable; + Toolbar.draw(toolbar); +END ToolBar; + + +PROCEDURE Resize; +VAR Width, Height: INTEGER; +BEGIN + SU.GetWindowPos(Window.Left, Window.Top); + SU.GetWindowSize(Width, Height); + IF (Window.Width # Width) OR (Window.Height # Height) OR (SkinHeight # SU.SkinHeight()) THEN + SU.MinMax(Width, 640, 65535); + SU.MinMax(Height, 400, 65535); + Window.dWidth := Width - Window.Width; + Window.dHeight := Height - Window.Height; + Window.Width := Width; + Window.Height := Height; + SU.SetWindowSize(Width, Height); + DOM.Resize(G.Buffer.Width + Window.dWidth, G.Buffer.Height + Window.dHeight + (SkinHeight - SU.SkinHeight())); + SkinHeight := SU.SkinHeight() + END +END Resize; + + +PROCEDURE DrawStatus; +BEGIN + SU.DrawRect(0, Window.Height - SkinHeight - WINDOW_BEVEL - STATUSBAR_HEIGHT + 1, Window.Width - 2 * WINDOW_BEVEL - 1, STATUSBAR_HEIGHT, SU.winColor); + IF DOM.urlstr # "" THEN + SU.OutText(CANVAS_LEFT, Window.Height - SkinHeight - WINDOW_BEVEL - STATUSBAR_HEIGHT + 2, DOM.urlstr, + MIN(LENGTH(DOM.urlstr), (Window.Width - 2 * WINDOW_BEVEL - 1 - CANVAS_LEFT * 2) DIV 8), SU.textColor) + ELSIF DOM.found() THEN + SU.OutText(CANVAS_LEFT, Window.Height - SkinHeight - WINDOW_BEVEL - STATUSBAR_HEIGHT + 2, + "F2 - first | F3 - next | F4 - prev. | F10 - exit", 48, SU.textColor) + END +END DrawStatus; + + +PROCEDURE DrawWindow; +BEGIN + SU.GetSystemColors; + SU.WindowRedrawStatus(1); + IF Window.Created THEN + Resize + ELSE + Window.Created := TRUE + END; + SU.DefineAndDrawWindow(Window.Left, Window.Top, Window.Width, Window.Height, + SU.winColor, LSL(ORD({0, 1, 2}), 4) + 4 - ORD(DOM.loaded), Window.Caption); + SU.DrawRect(0, 0, Window.Width - 2 * WINDOW_BEVEL - 1, CANVAS_TOP, SU.winColor); + SU.DrawRect(0, Window.Height - SkinHeight - WINDOW_BEVEL - STATUSBAR_HEIGHT + 1, Window.Width - 2 * WINDOW_BEVEL - 1, STATUSBAR_HEIGHT, SU.winColor); + SU.DrawRect(0, 0, CANVAS_LEFT, Window.Height - SkinHeight - WINDOW_BEVEL, SU.winColor); + SU.DrawRect(Window.Width - 2 * WINDOW_BEVEL - CANVAS_LEFT - 1 - SCROLLBAR_WIDTH - 2, 0, CANVAS_LEFT + SCROLLBAR_WIDTH + 2, Window.Height - SkinHeight - WINDOW_BEVEL, SU.winColor); + IF DOM.loaded THEN + ToolBar; + DOM.Draw; + DrawStatus + END; + SU.WindowRedrawStatus(2) +END DrawWindow; + + +PROCEDURE ConvMousePos(VAR X, Y: INTEGER); +BEGIN + X := X - Window.Left - WINDOW_BEVEL - 1; + Y := Y - Window.Top - SkinHeight +END ConvMousePos; + + +PROCEDURE DrawToolbar; +BEGIN + ToolbarEnable; + Toolbar.drawIcons(toolbar) +END DrawToolbar; + + +PROCEDURE ButtonClick; +BEGIN + CASE SU.GetButtonCode() OF + |0 : + |CLOSE : SearchForm.close(FALSE); + Settings.Close; + DOM.Close + |BACK : DOM.Back + |FORWARD : DOM.Forward + |CONTENTS : DOM.Contents + |DESCR : DOM.Descr + |SEARCH : DOM.OpenSearch + |SETTINGS : Settings.Open + END; + DOM.Draw; + DrawStatus +END ButtonClick; + + +PROCEDURE KeyDown; +BEGIN + CASE SU.GetKeyCode() OF + |KEY_DOWN_CODE : DOM.Down + |KEY_UP_CODE : DOM.Up + |KEY_PG_DOWN_CODE : DOM.PageDown + |KEY_PG_UP_CODE : DOM.PageUp + |KEY_HOME_CODE : DOM.Home + |KEY_END_CODE : DOM.End + |KEY_F2_CODE : DOM.Find(0) + |KEY_F3_CODE : DOM.Find(1) + |KEY_F4_CODE : DOM.Find(-1) + |KEY_F10_CODE : DOM.CloseSearch + ELSE + END; + DOM.Draw; + DrawStatus +END KeyDown; + + +PROCEDURE CanvasIsClicked(X, Y: INTEGER): BOOLEAN; + RETURN + (CANVAS_LEFT <= X) & (X < CANVAS_LEFT + G.Buffer.Width) & + (CANVAS_TOP <= Y) & (Y < CANVAS_TOP + G.Buffer.Height) +END CanvasIsClicked; + + +PROCEDURE MouseEvent; + +VAR + + mouse_status : SET; + X, Y : INTEGER; + scroll : INTEGER; + +BEGIN + SU.MousePos(X, Y); + mouse_status := SU.MouseStatus(); + scroll := SU.MouseVScroll(); + IF SU.L_BUTTON IN mouse_status THEN + ConvMousePos(X, Y); + IF CanvasIsClicked(X, Y) THEN + X := X - CANVAS_LEFT; + Y := Y - CANVAS_TOP; + DOM.Click(X, Y, TRUE) + END + ELSIF scroll # 0 THEN + DOM.Scroll(scroll); + DOM.Draw + ELSE + ConvMousePos(X, Y); + IF CanvasIsClicked(X, Y) THEN + X := X - CANVAS_LEFT; + Y := Y - CANVAS_TOP; + DOM.Click(X, Y, FALSE) + END + END +END MouseEvent; + + +PROCEDURE Empty; +END Empty; + + +PROCEDURE OpenFile; +BEGIN + Open := OpenDlg.Create(Empty, 0, Ini.Default, Ini.Files); + OpenDlg.Show(Open, 500, 400); + WHILE Open.status = 2 DO + SU.Pause(30) + END; + IF Open.status = 0 THEN + SU.Halt + END; + COPY(Open.FilePath, FileName); + OpenDlg.Destroy(Open) +END OpenFile; + + +PROCEDURE IsFB2(FileName: S.STRING): BOOLEAN; +VAR temp: S.STRING; +BEGIN + temp := FileName; + S.Reverse(temp); + temp[4] := 0X; + S.UCase(temp) + RETURN temp = "2BF." +END IsFB2; + + +PROCEDURE main(title: ARRAY OF CHAR); +VAR WinW, X1, Y1, X2, Y2, scr_pos: INTEGER; Win2: W.TWindow; resize: BOOLEAN; FilePath: S.STRING; defpath: BOOLEAN; +BEGIN + SkinHeight := SU.SkinHeight(); + sb := box_lib.kolibri_new_scrollbar(10 * 65536 + 200, 10 * 65536 + 30, 25, 15, 10, 0, 0, 0, 0, 0); + DOM.SetScrollBar(sb); + defpath := TRUE; + SU.GetParam(FileName); + IF FileName = "" THEN + OpenFile + END; + + IF FileName[0] = "!" THEN + FileName[0] := "/"; + defpath := FALSE + END; + + IF defpath THEN + FilePath := FileName; + S.GetPath(FilePath); + Ini.SetDefaultPath(FilePath); + DOM.SetColors; + DOM.Set_b_pict(Ini.b_pict); + Ini.Save(DOM.Settings.Colors, DOM.Settings.b_pict) + END; + + IF ~IsFB2(FileName) THEN + SelEnc.Show(FileName) + END; + + SU.SetEventsMask({0, 1, 2, 5, 31}); + SU.GetScreenArea(X1, Y1, X2, Y2); + WinW := (X2 - X1) DIV 2; + W.InitWindow(Window, WinW DIV 2, Y1, WinW, Y2 - Y1, title); + Settings.Default; + DOM.GetWinSize(FileName, Window.Width, Window.Height); + + Win2 := Window; + resize := FALSE; + IF Win2.Width > X2 - X1 THEN + Win2.Width := X2 - X1; + resize := TRUE + END; + + IF Win2.Height > Y2 - Y1 THEN + Win2.Height := Y2 - Y1; + resize := TRUE + END; + + DOM.Init(CANVAS_LEFT, CANVAS_TOP, + Window.Width - 2 * CANVAS_LEFT - 2 * WINDOW_BEVEL - 1 - SCROLLBAR_WIDTH - 2, + Window.Height - SkinHeight - CANVAS_TOP - WINDOW_BEVEL - STATUSBAR_HEIGHT + 1); + DOM.SetColors; + DOM.Set_b_pict(Ini.b_pict); + Window := Win2; + G.Resize2(Window.Width - 2 * CANVAS_LEFT - 2 * WINDOW_BEVEL - 1 - SCROLLBAR_WIDTH, Window.Height - SkinHeight - CANVAS_TOP - WINDOW_BEVEL + 1 - STATUSBAR_HEIGHT); + S.Append(Window.Caption, " - "); + S.Append(Window.Caption, FileName); + + Toolbar.create(toolbar, TOOLBAR_LEFT, TOOLBAR_TOP); + Toolbar.add(toolbar, BACK, 30, ""); + Toolbar.add(toolbar, FORWARD, 31, ""); + Toolbar.delimiter(toolbar); + Toolbar.add(toolbar, CONTENTS, 3, ""); + Toolbar.delimiter(toolbar); + Toolbar.add(toolbar, SEARCH, 49, ""); + Toolbar.delimiter(toolbar); + Toolbar.add(toolbar, DESCR, 66, ""); + Toolbar.delimiter(toolbar); + Toolbar.add(toolbar, SETTINGS, 60, ""); + + DOM.Open(FileName, DrawWindow, DrawStatus, DrawToolbar); + IF resize THEN + DOM.Resize(Window.Width - 2 * CANVAS_LEFT - 2 * WINDOW_BEVEL - 1 - SCROLLBAR_WIDTH, Window.Height - SkinHeight - CANVAS_TOP - WINDOW_BEVEL + 1 - STATUSBAR_HEIGHT) + END; + + DrawWindow; + scr_pos := sb.position; + WHILE TRUE DO + CASE SU.WaitForEvent() OF + |1 : DrawWindow + |2 : KeyDown + |3 : ButtonClick + |6 : box_lib.scrollbar_v_mouse(sb); + IF sb.position # scr_pos THEN + DOM.ScrollBar; + DOM.Draw; + scr_pos := sb.position; + END; + MouseEvent + END + END +END main; + + +BEGIN + main("FB2 Reader v0.97") +END FB2READ. diff --git a/programs/other/fb2reader/SRC/File.ob07 b/programs/other/fb2reader/SRC/File.ob07 new file mode 100644 index 0000000000..b906546776 --- /dev/null +++ b/programs/other/fb2reader/SRC/File.ob07 @@ -0,0 +1,255 @@ +(* + Copyright 2016, 2019 Anton Krotov + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*) + +MODULE File; + +IMPORT sys := SYSTEM, KOSAPI; + +CONST + + SEEK_BEG* = 0; SEEK_CUR* = 1; SEEK_END* = 2; + +TYPE + + FNAME* = ARRAY 520 OF CHAR; + + FS* = POINTER TO rFS; + + rFS* = RECORD + subfunc*, pos*, hpos*, bytes*, buffer*: INTEGER; + name*: FNAME + END; + + FD* = POINTER TO rFD; + + rFD* = RECORD + attr*: INTEGER; + ntyp*: CHAR; + reserved: ARRAY 3 OF CHAR; + time_create*, date_create*, + time_access*, date_access*, + time_modif*, date_modif*, + size*, hsize*: INTEGER; + name*: FNAME + END; + +PROCEDURE [stdcall] f_68_27(file_name: INTEGER; VAR size: INTEGER): INTEGER; +BEGIN + sys.CODE(053H); (* push ebx *) + sys.CODE(06AH, 044H); (* push 68 *) + sys.CODE(058H); (* pop eax *) + sys.CODE(06AH, 01BH); (* push 27 *) + sys.CODE(05BH); (* pop ebx *) + sys.CODE(08BH, 04DH, 008H); (* mov ecx, [ebp + 08h] *) + sys.CODE(0CDH, 040H); (* int 40h *) + sys.CODE(08BH, 04DH, 00CH); (* mov ecx, [ebp + 0Ch] *) + sys.CODE(089H, 011H); (* mov [ecx], edx *) + sys.CODE(05BH); (* pop ebx *) + sys.CODE(0C9H); (* leave *) + sys.CODE(0C2H, 008H, 000H); (* ret 08h *) + RETURN 0 +END f_68_27; + +PROCEDURE Load*(FName: ARRAY OF CHAR; VAR size: INTEGER): INTEGER; + RETURN f_68_27(sys.ADR(FName[0]), size) +END Load; + +PROCEDURE GetFileInfo*(FName: ARRAY OF CHAR; VAR Info: rFD): BOOLEAN; +VAR res2: INTEGER; fs: rFS; +BEGIN + fs.subfunc := 5; + fs.pos := 0; + fs.hpos := 0; + fs.bytes := 0; + fs.buffer := sys.ADR(Info); + COPY(FName, fs.name) + RETURN KOSAPI.sysfunc22(70, sys.ADR(fs), res2) = 0 +END GetFileInfo; + +PROCEDURE Exists*(FName: ARRAY OF CHAR): BOOLEAN; +VAR fd: rFD; +BEGIN + RETURN GetFileInfo(FName, fd) & ~(4 IN BITS(fd.attr)) +END Exists; + +PROCEDURE Close*(VAR F: FS); +BEGIN + IF F # NIL THEN + DISPOSE(F) + END +END Close; + +PROCEDURE Open*(FName: ARRAY OF CHAR): FS; +VAR F: FS; +BEGIN + IF Exists(FName) THEN + NEW(F); + IF F # NIL THEN + F.subfunc := 0; + F.pos := 0; + F.hpos := 0; + F.bytes := 0; + F.buffer := 0; + COPY(FName, F.name) + END + ELSE + F := NIL + END + RETURN F +END Open; + +PROCEDURE Delete*(FName: ARRAY OF CHAR): BOOLEAN; +VAR F: FS; res, res2: INTEGER; +BEGIN + IF Exists(FName) THEN + NEW(F); + IF F # NIL THEN + F.subfunc := 8; + F.pos := 0; + F.hpos := 0; + F.bytes := 0; + F.buffer := 0; + COPY(FName, F.name); + res := KOSAPI.sysfunc22(70, sys.ADR(F^), res2); + DISPOSE(F) + ELSE + res := -1 + END + ELSE + res := -1 + END + RETURN res = 0 +END Delete; + +PROCEDURE Seek*(F: FS; Offset, Origin: INTEGER): INTEGER; +VAR res: INTEGER; fd: rFD; +BEGIN + IF (F # NIL) & GetFileInfo(F.name, fd) & (BITS(fd.attr) * {4} = {}) THEN + CASE Origin OF + |SEEK_BEG: F.pos := Offset + |SEEK_CUR: INC(F.pos, Offset) + |SEEK_END: F.pos := fd.size + Offset + ELSE + END; + res := F.pos + ELSE + res := -1 + END + RETURN res +END Seek; + +PROCEDURE Read*(F: FS; Buffer, Count: INTEGER): INTEGER; +VAR res, res2: INTEGER; +BEGIN + IF F # NIL THEN + F.subfunc := 0; + F.bytes := Count; + F.buffer := Buffer; + res := KOSAPI.sysfunc22(70, sys.ADR(F^), res2); + IF res2 > 0 THEN + INC(F.pos, res2) + END + ELSE + res2 := 0 + END + RETURN res2 +END Read; + +PROCEDURE Write*(F: FS; Buffer, Count: INTEGER): INTEGER; +VAR res, res2: INTEGER; +BEGIN + IF F # NIL THEN + F.subfunc := 3; + F.bytes := Count; + F.buffer := Buffer; + res := KOSAPI.sysfunc22(70, sys.ADR(F^), res2); + IF res2 > 0 THEN + INC(F.pos, res2) + END + ELSE + res2 := 0 + END + RETURN res2 +END Write; + +PROCEDURE Create*(FName: ARRAY OF CHAR): FS; +VAR F: FS; res2: INTEGER; +BEGIN + NEW(F); + IF F # NIL THEN + F.subfunc := 2; + F.pos := 0; + F.hpos := 0; + F.bytes := 0; + F.buffer := 0; + COPY(FName, F.name); + IF KOSAPI.sysfunc22(70, sys.ADR(F^), res2) # 0 THEN + DISPOSE(F) + END + END + RETURN F +END Create; + +PROCEDURE DirExists*(FName: ARRAY OF CHAR): BOOLEAN; +VAR fd: rFD; +BEGIN + RETURN GetFileInfo(FName, fd) & (4 IN BITS(fd.attr)) +END DirExists; + +PROCEDURE CreateDir*(DirName: ARRAY OF CHAR): BOOLEAN; +VAR F: FS; res, res2: INTEGER; +BEGIN + NEW(F); + IF F # NIL THEN + F.subfunc := 9; + F.pos := 0; + F.hpos := 0; + F.bytes := 0; + F.buffer := 0; + COPY(DirName, F.name); + res := KOSAPI.sysfunc22(70, sys.ADR(F^), res2); + DISPOSE(F) + ELSE + res := -1 + END + RETURN res = 0 +END CreateDir; + +PROCEDURE DeleteDir*(DirName: ARRAY OF CHAR): BOOLEAN; +VAR F: FS; res, res2: INTEGER; +BEGIN + IF DirExists(DirName) THEN + NEW(F); + IF F # NIL THEN + F.subfunc := 8; + F.pos := 0; + F.hpos := 0; + F.bytes := 0; + F.buffer := 0; + COPY(DirName, F.name); + res := KOSAPI.sysfunc22(70, sys.ADR(F^), res2); + DISPOSE(F) + ELSE + res := -1 + END + ELSE + res := -1 + END + RETURN res = 0 +END DeleteDir; + +END File. diff --git a/programs/other/fb2reader/SRC/Font.ob07 b/programs/other/fb2reader/SRC/Font.ob07 new file mode 100644 index 0000000000..3513bda6b2 --- /dev/null +++ b/programs/other/fb2reader/SRC/Font.ob07 @@ -0,0 +1,176 @@ +(* + Copyright 2016, 2018, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Font; + +IMPORT W := Window, S := Strings, G := Graph, sys := SYSTEM, K := KOSAPI, Conv, Ini, KF := kfonts; + +VAR + + kf_font, kf_loaded, kf_enabled: BOOLEAN; + cp1251buf: ARRAY 102400 OF CHAR; + + KFont*: KF.TFont; + + Font*: RECORD + color* : INTEGER; + size : INTEGER; + bold : BOOLEAN; + italic : BOOLEAN; + strike : BOOLEAN + END; + + ItalicColor, NormalColor: INTEGER; + + +PROCEDURE KFText(X, Y: INTEGER; first, quantity: INTEGER; canvas: G.PBuffer); +BEGIN + KF.TextOut(KFont, canvas.adr - 8, X, Y, first, quantity, Font.color, ORD(Font.bold) + ORD(Font.italic) * 2 + ORD(Font.strike) * 8) +END KFText; + + +PROCEDURE sysfont*(sf: BOOLEAN); +BEGIN + kf_font := ~sf & kf_enabled; +END sysfont; + + +PROCEDURE params*(): INTEGER; + RETURN Font.size + 0 + LSL(3, 16) + LSL(ORD(Font.bold) + ORD(Font.italic) * 2 + 128, 24) +END params; + + +PROCEDURE SetFontColor*(color: INTEGER); +BEGIN + Font.color := color +END SetFontColor; + + +PROCEDURE Bold*(bold: BOOLEAN); +BEGIN + Font.bold := bold +END Bold; + + +PROCEDURE Italic*(italic, notLink: BOOLEAN); +BEGIN + Font.italic := italic; + IF italic THEN + IF notLink THEN + SetFontColor(ItalicColor) + END + ELSE + IF notLink THEN + SetFontColor(NormalColor) + END + END +END Italic; + + +PROCEDURE Strike*(strike: BOOLEAN); +BEGIN + Font.strike := strike +END Strike; + + +PROCEDURE FontW(): INTEGER; + RETURN ASR(Font.size, 1) +END FontW; + + +PROCEDURE FontH*(): INTEGER; +VAR res: INTEGER; +BEGIN + IF kf_font THEN + res := KF.TextHeight(KFont) + ELSE + res := Font.size + END + RETURN res +END FontH; + + +PROCEDURE TextWidth*(text: S.CHARS; length: INTEGER): INTEGER; +VAR res: INTEGER; +BEGIN + IF kf_font THEN + Conv.convert(text.first, sys.ADR(cp1251buf[0]), length); + res := KF.TextWidth(KFont, sys.ADR(cp1251buf[0]), length, ORD(Font.bold) + ORD(Font.italic) * 2) + ELSE + res := length * FontW() + END + RETURN res +END TextWidth; + + +PROCEDURE MonoWidth*(): INTEGER; + RETURN FontW() +END MonoWidth; + + +PROCEDURE StrikeText*(Rect: W.TRect; X, Y: INTEGER; width: INTEGER); +VAR y: INTEGER; +BEGIN + IF Font.strike THEN + y := Y + FontH() DIV 2; +// X := X + ORD(Font.italic & kf_font) * ((KF.TextHeight(KFont) DIV 2) DIV 3); + G.SetColor(Font.color); + G.HLine(X + Rect.Left, X + Rect.Left + width, y + Rect.Top); + IF Font.size >= 28 THEN + INC(y); + G.HLine(X + Rect.Left, X + Rect.Left + width, y + Rect.Top); + END + END +END StrikeText; + + +PROCEDURE Text*(Rect: W.TRect; X, Y: INTEGER; adr: INTEGER; length: INTEGER); +BEGIN + IF kf_font THEN + Conv.convert(adr, sys.ADR(cp1251buf[0]), length); + KFText(X + Rect.Left, Y + Rect.Top, sys.ADR(cp1251buf[0]), length, G.Buffer) + ELSE + G.SetColor(Font.color); + G.TextOut(X + Rect.Left, Y + Rect.Top, adr, length, Font.size, params()) + END +END Text; + + +PROCEDURE Init*(italic, normal, fs: INTEGER); +BEGIN + ItalicColor := italic; + NormalColor := normal; + IF KF.SetSize(KFont, fs) THEN + Font.size := KF.TextHeight(KFont); + kf_font := TRUE; + kf_enabled := TRUE + ELSE + Font.size := fs; + kf_font := FALSE; + kf_enabled := FALSE + END +END Init; + + +BEGIN + KFont := KF.LoadFont(Ini.Font); + kf_loaded := KFont # NIL; + kf_font := kf_loaded; + kf_enabled := kf_loaded +END Font. diff --git a/programs/other/fb2reader/SRC/Graph.ob07 b/programs/other/fb2reader/SRC/Graph.ob07 new file mode 100644 index 0000000000..db3a7728bb --- /dev/null +++ b/programs/other/fb2reader/SRC/Graph.ob07 @@ -0,0 +1,310 @@ +(* + Copyright 2016-2020, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Graph; + +IMPORT K := KOSAPI, sys := SYSTEM, SU := SysUtils, LibImg; + + +TYPE + + TBuffer = RECORD Width*, Height*, adr*, Color: INTEGER END; + PBuffer* = POINTER TO TBuffer; + + +VAR + + Buffer*, Buffer2, Buffer3*: PBuffer; + + +PROCEDURE [stdcall-, "rasterworks.obj", ""] drawText (canvas, x, y, string, charQuantity, fontColor, params: INTEGER): INTEGER; END; + +PROCEDURE Destroy*(VAR Buffer: PBuffer); +BEGIN + IF Buffer # NIL THEN + IF Buffer.adr # 0 THEN + DEC(Buffer.adr, 8); + Buffer.adr := K.free(Buffer.adr) + END; + DISPOSE(Buffer) + END +END Destroy; + + +PROCEDURE Create*(Width, Height: INTEGER): PBuffer; +VAR res: PBuffer; +BEGIN + NEW(res); + res.adr := K.malloc(Width * Height * 4 + 8); + sys.PUT(res.adr, Width); + sys.PUT(res.adr + 4, Height); + res.Width := Width; + res.Height := Height; + INC(res.adr, 8); + RETURN res +END Create; + + +PROCEDURE getRGB* (color: INTEGER; VAR r, g, b: BYTE); +BEGIN + b := color MOD 256; + g := color DIV 256 MOD 256; + r := color DIV 65536 MOD 256 +END getRGB; + + +PROCEDURE Fill*(Buffer: PBuffer; Color: INTEGER); +VAR p, n, i: INTEGER; +BEGIN + p := Buffer.adr; + n := Buffer.Width * Buffer.Height; + FOR i := 1 TO n DO + sys.PUT(p, Color); + INC(p, 4) + END +END Fill; + + +PROCEDURE HLine*(X1, X2, Y: INTEGER); +VAR + p1, p2, i, color: INTEGER; + +BEGIN + IF X1 <= X2 THEN + SU.MinMax(Y, 0, Buffer.Height - 1); + color := Buffer.Color; + p1 := Buffer.adr + 4 * (Y * Buffer.Width + X1); + p2 := p1 + (X2 - X1) * 4; + FOR i := p1 TO p2 BY 4 DO + sys.PUT(i, color) + END + END +END HLine; + + +PROCEDURE HLineNotXOR (X1, X2, Y, color: INTEGER); +VAR + p1, p2, i: INTEGER; + pix: SET; + +BEGIN + IF X1 <= X2 THEN + SU.MinMax(Y, 0, Buffer.Height - 1); + p1 := Buffer.adr + 4 * (Y * Buffer.Width + X1); + p2 := p1 + (X2 - X1) * 4; + FOR i := p1 TO p2 BY 4 DO + sys.GET(i, pix); + pix := (-pix) / BITS(color) - {24..31}; + sys.PUT(i, pix) + END + END +END HLineNotXOR; + + +PROCEDURE VLine*(X, Y1, Y2: INTEGER); +VAR p1, p2, line_size, color: INTEGER; +BEGIN + ASSERT(Y1 <= Y2); + SU.MinMax(Y1, 0, Buffer.Height - 1); + SU.MinMax(Y2, 0, Buffer.Height - 1); + color := Buffer.Color; + line_size := Buffer.Width * 4; + p1 := Buffer.adr + line_size * Y1 + 4 * X; + p2 := p1 + (Y2 - Y1) * line_size; + WHILE p1 <= p2 DO + sys.PUT(p1, color); + p1 := p1 + line_size + END +END VLine; + + +PROCEDURE Box(X1, Y1, X2, Y2: INTEGER); +VAR y: INTEGER; +BEGIN + FOR y := Y1 TO Y2 DO + HLine(X1, X2, y) + END +END Box; + + +PROCEDURE BoxNotXOR* (X1, Y1, X2, Y2, color: INTEGER); +VAR y: INTEGER; +BEGIN + FOR y := Y1 TO Y2 DO + HLineNotXOR(X1, X2, y, color) + END +END BoxNotXOR; + + +PROCEDURE SetColor*(color: INTEGER); +BEGIN + Buffer.Color := color +END SetColor; + + +PROCEDURE GetColor*(): INTEGER; + RETURN Buffer.Color +END GetColor; + + +PROCEDURE TextOut*(X, Y: INTEGER; Text: INTEGER; length: INTEGER; size, params: INTEGER); +BEGIN + drawText(Buffer.adr - 8, X, Y, Text, length, 0FF000000H + Buffer.Color, params) +END TextOut; + + +PROCEDURE Resize2*(Width, Height: INTEGER); +BEGIN + Buffer2.Width := Width; + Buffer2.Height := Height; +END Resize2; + + +PROCEDURE Image* (X, Y, sizeX, sizeY, ptr, Ymin, Ymax: INTEGER); +VAR + y: INTEGER; +BEGIN + ASSERT(sizeX <= Buffer.Width); + FOR y := 0 TO sizeY - 1 DO + IF (Ymin <= Y) & (Y < Ymax) THEN + sys.MOVE(ptr + sizeX*4*y, Buffer.adr + (Buffer.Width*Y + X)*4, sizeX*4) + END; + INC(Y) + END +END Image; + + +PROCEDURE Image2(Buffer: PBuffer; X, Y, sizeX, sizeY, ptr: INTEGER); +VAR x, y, pix, left: INTEGER; +BEGIN + left := X; + FOR y := 0 TO sizeY - 1 DO + X := left; + FOR x := 0 TO sizeX - 1 DO + sys.GET32(ptr + (y*sizeX + x)*4, pix); + IF (X < Buffer.Width) & (Y < Buffer.Height) THEN + sys.PUT32(Buffer.adr + (Buffer.Width*Y + X)*4, pix) + END; + INC(X) + END; + INC(Y) + END +END Image2; + + +PROCEDURE BackImage*(sizeX, sizeY, ptr: INTEGER); +VAR x, y: INTEGER; +BEGIN + IF ptr # 0 THEN + y := 0; + WHILE y < Buffer3.Height DO + x := 0; + WHILE x < Buffer3.Width DO + Image2(Buffer3, x, y, sizeX, sizeY, ptr); + INC(x, sizeX) + END; + INC(y, sizeY) + END + END +END BackImage; + + +PROCEDURE Copy*(src, dst: PBuffer; y_src, lines, y_dst: INTEGER); +BEGIN + sys.MOVE(src.adr + y_src * src.Width * 4, dst.adr + y_dst * dst.Width * 4, lines * dst.Width * 4) +END Copy; + + +PROCEDURE Clear*; +VAR p, color: INTEGER; +BEGIN + color := Buffer.Color; + FOR p := Buffer.adr TO Buffer.adr + Buffer.Width * Buffer.Height * 4 - 4 BY 4 DO + sys.PUT(p, color) + END +END Clear; + + +PROCEDURE Draw*(X, Y: INTEGER); +BEGIN + K.sysfunc7(65, Buffer.adr, Buffer.Width * 65536 + Buffer.Height, X * 65536 + Y, 32, 0, 0) +END Draw; + + +PROCEDURE Rect*(X1, Y1, X2, Y2: INTEGER); +BEGIN + VLine(X1, Y1, Y2); + VLine(X2, Y1, Y2); + HLine(X1, X2, Y1); + HLine(X1, X2, Y2) +END Rect; + + +PROCEDURE Progress*(value: REAL); +VAR W4, W2, H2: INTEGER; +BEGIN + W4 := Buffer2.Width DIV 4; + W2 := Buffer2.Width DIV 2; + H2 := Buffer2.Height DIV 2; + SetColor(0FFFFFFH); + Clear; + SetColor(0); + Rect(W4, H2 - 50, 3 * W4, H2 + 30); + TextOut(W2 - 10 * 8 DIV 2, H2 - 50 + 15, sys.SADR("Loading..."), 10, 1, 16 + 0 + LSL(3, 16) + LSL(128, 24)); + SetColor(000000FFH); + Box(W4 + 10, H2, W4 + 10 + FLOOR( FLT(W2 - 20) * value ), H2 + 15); +END Progress; + + +PROCEDURE Resize3(Buffer: PBuffer; Width, Height: INTEGER); +BEGIN + IF Buffer.adr # 0 THEN + DEC(Buffer.adr, 8) + END; + Buffer.adr := K.realloc(Buffer.adr, Width * Height * 4 + 8); + SU.MemError(Buffer.adr = 0); + sys.PUT(Buffer.adr, Width); + sys.PUT(Buffer.adr + 4, Height); + INC(Buffer.adr, 8); + Buffer.Width := Width; + Buffer.Height := Height +END Resize3; + + +PROCEDURE Resize*(Width, Height: INTEGER); +BEGIN + Resize3(Buffer, Width, Height); + Resize3(Buffer3, Width, Height); +END Resize; + + +PROCEDURE Init; +VAR Width, Height: INTEGER; +BEGIN + NEW(Buffer); + NEW(Buffer2); + NEW(Buffer3); + SU.GetScreenSize(Width, Height); + Resize(Width, Height) +END Init; + + +BEGIN + Init +END Graph. diff --git a/programs/other/fb2reader/SRC/Icons.ob07 b/programs/other/fb2reader/SRC/Icons.ob07 new file mode 100644 index 0000000000..eafb5191dd --- /dev/null +++ b/programs/other/fb2reader/SRC/Icons.ob07 @@ -0,0 +1,106 @@ +(* + Copyright 2021, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Icons; + +IMPORT + LibImg, K := SysUtils, Graph, File, KOSAPI, SYSTEM; + +CONST + fileName = "/sys/Icons16.png"; + SIZE* = 18; + +VAR + source: INTEGER; + +(* +PROCEDURE copy (src, dst: INTEGER); +VAR + src_width, src_height, + dst_width, dst_height, + src_data, dst_data: INTEGER; +BEGIN + LibImg.GetInf(src, src_width, src_height, src_data); + LibImg.GetInf(dst, dst_width, dst_height, dst_data); + ASSERT(src_width = dst_width); + ASSERT(src_height = dst_height); + SYSTEM.MOVE(src_data, dst_data, src_width*src_height*4) +END copy; +*) + + +PROCEDURE load (): INTEGER; +VAR + height: INTEGER; +BEGIN + RETURN LibImg.LoadFromFile(fileName, SIZE, height) +END load; + + +PROCEDURE draw* (icons, n, x, y: INTEGER); +VAR + width, height, data: INTEGER; +BEGIN + LibImg.GetInf(icons, width, height, data); + KOSAPI.sysfunc7(65, data + SIZE*SIZE*4*n, SIZE*65536 + SIZE, x*65536 + y, 32, 0, 0) +END draw; + + +PROCEDURE iconsBackColor (icons: INTEGER; BackColor: INTEGER); +VAR + width, height, data, x, y, pix: INTEGER; + b, g, r, gr: BYTE; +BEGIN + LibImg.GetInf(icons, width, height, data); + FOR y := 0 TO height - 1 DO + FOR x := 0 TO width - 1 DO + SYSTEM.GET32(data, pix); + Graph.getRGB(pix, r, g, b); + gr := (r + g + b) DIV 3; + IF BackColor = -1 THEN + pix := gr + 256*gr + 65536*gr + ELSIF gr = 255 THEN + pix := BackColor + END; + SYSTEM.PUT32(data, pix); + INC(data, 4) + END + END +END iconsBackColor; + + +PROCEDURE get* (VAR icons, grayIcons: INTEGER; BackColor: INTEGER); +BEGIN + IF source = 0 THEN + source := load(); + icons := load(); + grayIcons := load(); + iconsBackColor(grayIcons, -1); + iconsBackColor(grayIcons, BackColor); + iconsBackColor(icons, BackColor) + (*ELSE + copy(source, icons); + copy(source, grayIcons)*) + END; +END get; + + +BEGIN + source := 0 +END Icons. \ No newline at end of file diff --git a/programs/other/fb2reader/SRC/Ini.ob07 b/programs/other/fb2reader/SRC/Ini.ob07 new file mode 100644 index 0000000000..44fd745914 --- /dev/null +++ b/programs/other/fb2reader/SRC/Ini.ob07 @@ -0,0 +1,149 @@ +(* + Copyright 2016, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Ini; + +IMPORT KOSAPI, sys := SYSTEM, S := Strings, File; + + +CONST + + IniFileName = "/sys/settings/fb2read.ini"; + + +VAR + + History*, Browser*, Default*, Font*, Files*, Picture* : S.STRING; + b_pict*: BOOLEAN; + buffer: ARRAY 5000 OF CHAR; + + +PROCEDURE [stdcall, "libini.obj", "ini_enum_keys"] enum_keys (f_name, sec_name: S.STRING; callback: INTEGER); END; +PROCEDURE [stdcall, "libini.obj", "ini_get_color"] get_color (f_name, sec_name, key_name: S.STRING; def_val: INTEGER): INTEGER; END; + +PROCEDURE Save* (Colors: ARRAY OF INTEGER; b_pict: BOOLEAN); +VAR F: File.FS; pos: INTEGER; + + PROCEDURE WriteStr(str: S.STRING; VAR pos: INTEGER); + BEGIN + sys.MOVE(sys.ADR(str[0]), pos, LENGTH(str)); + pos := pos + LENGTH(str) + END WriteStr; + + PROCEDURE WriteLn (VAR pos: INTEGER); + BEGIN + WriteStr(0DX, pos); + WriteStr(0AX, pos) + END WriteLn; + + PROCEDURE GetRGB(color: INTEGER; VAR r, g, b: INTEGER); + BEGIN + b := ORD(BITS(color) * {0..7}); + g := ORD(BITS(LSR(color, 8)) * {0..7}); + r := ORD(BITS(LSR(color, 16)) * {0..7}) + END GetRGB; + + PROCEDURE WriteColor(color: INTEGER; VAR pos: INTEGER); + VAR r, g, b: INTEGER; s: S.STRING; + BEGIN + GetRGB(color, r, g, b); + S.IntToString(r, s); WriteStr(s, pos); WriteStr(",", pos); + S.IntToString(g, s); WriteStr(s, pos); WriteStr(",", pos); + S.IntToString(b, s); WriteStr(s, pos); + END WriteColor; + +BEGIN + pos := sys.ADR(buffer[0]); + F := File.Create(IniFileName); + WriteStr("[Paths]", pos); WriteLn(pos); + WriteStr("history=", pos); WriteStr(History, pos); WriteLn(pos); + WriteStr("browser=", pos); WriteStr(Browser, pos); WriteLn(pos); + WriteStr("default=", pos); WriteStr(Default, pos); WriteLn(pos); + WriteStr("font=", pos); WriteStr(Font, pos); WriteLn(pos); + WriteStr("picture=", pos); WriteStr(Picture, pos); WriteLn(pos); + WriteStr("[Files]", pos); WriteLn(pos); + WriteStr("files=", pos); WriteStr(Files, pos); WriteLn(pos); + WriteStr("[Flags]", pos); WriteLn(pos); + WriteStr("picture=", pos); + IF b_pict THEN + WriteStr("on", pos) + ELSE + WriteStr("off", pos) + END; + WriteLn(pos); + WriteStr("[Colors]", pos); WriteLn(pos); + WriteStr("back=", pos); WriteColor(Colors[0], pos); WriteLn(pos); + WriteStr("text=", pos); WriteColor(Colors[1], pos); WriteLn(pos); + WriteStr("italic=", pos); WriteColor(Colors[2], pos); WriteLn(pos); + WriteStr("link=", pos); WriteColor(Colors[3], pos); WriteLn(pos); + WriteStr("visited=", pos); WriteColor(Colors[4], pos); WriteLn(pos); + pos := File.Write(F, sys.ADR(buffer[0]), pos - sys.ADR(buffer[0])); + File.Close(F) +END Save; + + +PROCEDURE [stdcall] callback(f_name, sec_name, key_name, key_value: S.STRING): INTEGER; +BEGIN + IF sec_name = "Paths" THEN + IF key_name = "history" THEN + History := key_value + ELSIF key_name = "browser" THEN + Browser := key_value + ELSIF key_name = "default" THEN + Default := key_value + ELSIF key_name = "font" THEN + Font := key_value + ELSIF key_name = "picture" THEN + Picture := key_value + END + ELSIF sec_name = "Files" THEN + IF key_name = "files" THEN + Files := key_value + END + ELSIF sec_name = "Flags" THEN + IF key_name = "picture" THEN + b_pict := key_value = "on" + END + END + RETURN 1 +END callback; + + +PROCEDURE GetColor*(key: S.STRING; def: INTEGER): INTEGER; + RETURN get_color(IniFileName, "Colors", key, def) +END GetColor; + + +PROCEDURE SetDefaultPath*(Path: S.STRING); +BEGIN + Default := Path; +END SetDefaultPath; + + +PROCEDURE SetPicturePath*(Path: S.STRING); +BEGIN + Picture := Path; +END SetPicturePath; + + +BEGIN + enum_keys(IniFileName, "Paths", sys.ADR(callback)); + enum_keys(IniFileName, "Files", sys.ADR(callback)); + enum_keys(IniFileName, "Flags", sys.ADR(callback)); +END Ini. diff --git a/programs/other/fb2reader/SRC/KOSAPI.ob07 b/programs/other/fb2reader/SRC/KOSAPI.ob07 new file mode 100644 index 0000000000..57fed1dc17 --- /dev/null +++ b/programs/other/fb2reader/SRC/KOSAPI.ob07 @@ -0,0 +1,436 @@ +(* + BSD 2-Clause License + + Copyright (c) 2018-2019, 2022 Anton Krotov + All rights reserved. +*) + +MODULE KOSAPI; + +IMPORT SYSTEM; + + +TYPE + + STRING = ARRAY 1024 OF CHAR; + + +VAR + + DLL_INIT: PROCEDURE [stdcall] (entry: INTEGER); + + +PROCEDURE [stdcall-] sysfunc1* (arg1: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE( + 08BH, 045H, 008H, (* mov eax, dword [ebp + 8] *) + 0CDH, 040H, (* int 64 *) + 0C9H, (* leave *) + 0C2H, 004H, 000H (* ret 4 *) + ) + RETURN 0 +END sysfunc1; + + +PROCEDURE [stdcall-] sysfunc2* (arg1, arg2: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE( + 053H, (* push ebx *) + 08BH, 045H, 008H, (* mov eax, dword [ebp + 8] *) + 08BH, 05DH, 00CH, (* mov ebx, dword [ebp + 12] *) + 0CDH, 040H, (* int 64 *) + 05BH, (* pop ebx *) + 0C9H, (* leave *) + 0C2H, 008H, 000H (* ret 8 *) + ) + RETURN 0 +END sysfunc2; + + +PROCEDURE [stdcall-] sysfunc3* (arg1, arg2, arg3: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE( + 053H, (* push ebx *) + 08BH, 045H, 008H, (* mov eax, dword [ebp + 8] *) + 08BH, 05DH, 00CH, (* mov ebx, dword [ebp + 12] *) + 08BH, 04DH, 010H, (* mov ecx, dword [ebp + 16] *) + 0CDH, 040H, (* int 64 *) + 05BH, (* pop ebx *) + 0C9H, (* leave *) + 0C2H, 00CH, 000H (* ret 12 *) + ) + RETURN 0 +END sysfunc3; + + +PROCEDURE [stdcall-] sysfunc4* (arg1, arg2, arg3, arg4: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE( + 053H, (* push ebx *) + 08BH, 045H, 008H, (* mov eax, dword [ebp + 8] *) + 08BH, 05DH, 00CH, (* mov ebx, dword [ebp + 12] *) + 08BH, 04DH, 010H, (* mov ecx, dword [ebp + 16] *) + 08BH, 055H, 014H, (* mov edx, dword [ebp + 20] *) + 0CDH, 040H, (* int 64 *) + 05BH, (* pop ebx *) + 0C9H, (* leave *) + 0C2H, 010H, 000H (* ret 16 *) + ) + RETURN 0 +END sysfunc4; + + +PROCEDURE [stdcall-] sysfunc5* (arg1, arg2, arg3, arg4, arg5: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE( + 053H, (* push ebx *) + 056H, (* push esi *) + 08BH, 045H, 008H, (* mov eax, dword [ebp + 8] *) + 08BH, 05DH, 00CH, (* mov ebx, dword [ebp + 12] *) + 08BH, 04DH, 010H, (* mov ecx, dword [ebp + 16] *) + 08BH, 055H, 014H, (* mov edx, dword [ebp + 20] *) + 08BH, 075H, 018H, (* mov esi, dword [ebp + 24] *) + 0CDH, 040H, (* int 64 *) + 05EH, (* pop esi *) + 05BH, (* pop ebx *) + 0C9H, (* leave *) + 0C2H, 014H, 000H (* ret 20 *) + ) + RETURN 0 +END sysfunc5; + + +PROCEDURE [stdcall-] sysfunc6* (arg1, arg2, arg3, arg4, arg5, arg6: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE( + 053H, (* push ebx *) + 056H, (* push esi *) + 057H, (* push edi *) + 08BH, 045H, 008H, (* mov eax, dword [ebp + 8] *) + 08BH, 05DH, 00CH, (* mov ebx, dword [ebp + 12] *) + 08BH, 04DH, 010H, (* mov ecx, dword [ebp + 16] *) + 08BH, 055H, 014H, (* mov edx, dword [ebp + 20] *) + 08BH, 075H, 018H, (* mov esi, dword [ebp + 24] *) + 08BH, 07DH, 01CH, (* mov edi, dword [ebp + 28] *) + 0CDH, 040H, (* int 64 *) + 05FH, (* pop edi *) + 05EH, (* pop esi *) + 05BH, (* pop ebx *) + 0C9H, (* leave *) + 0C2H, 018H, 000H (* ret 24 *) + ) + RETURN 0 +END sysfunc6; + + +PROCEDURE [stdcall-] sysfunc7* (arg1, arg2, arg3, arg4, arg5, arg6, arg7: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE( + 053H, (* push ebx *) + 056H, (* push esi *) + 057H, (* push edi *) + 055H, (* push ebp *) + 08BH, 045H, 008H, (* mov eax, dword [ebp + 8] *) + 08BH, 05DH, 00CH, (* mov ebx, dword [ebp + 12] *) + 08BH, 04DH, 010H, (* mov ecx, dword [ebp + 16] *) + 08BH, 055H, 014H, (* mov edx, dword [ebp + 20] *) + 08BH, 075H, 018H, (* mov esi, dword [ebp + 24] *) + 08BH, 07DH, 01CH, (* mov edi, dword [ebp + 28] *) + 08BH, 06DH, 020H, (* mov ebp, dword [ebp + 32] *) + 0CDH, 040H, (* int 64 *) + 05DH, (* pop ebp *) + 05FH, (* pop edi *) + 05EH, (* pop esi *) + 05BH, (* pop ebx *) + 0C9H, (* leave *) + 0C2H, 01CH, 000H (* ret 28 *) + ) + RETURN 0 +END sysfunc7; + + +PROCEDURE [stdcall-] sysfunc22* (arg1, arg2: INTEGER; VAR res2: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE( + 053H, (* push ebx *) + 08BH, 045H, 008H, (* mov eax, dword [ebp + 8] *) + 08BH, 05DH, 00CH, (* mov ebx, dword [ebp + 12] *) + 0CDH, 040H, (* int 64 *) + 08BH, 04DH, 010H, (* mov ecx, dword [ebp + 16] *) + 089H, 019H, (* mov dword [ecx], ebx *) + 05BH, (* pop ebx *) + 0C9H, (* leave *) + 0C2H, 00CH, 000H (* ret 12 *) + ) + RETURN 0 +END sysfunc22; + + +PROCEDURE mem_commit (adr, size: INTEGER); +VAR + tmp: INTEGER; +BEGIN + FOR tmp := adr TO adr + size - 1 BY 4096 DO + SYSTEM.PUT(tmp, 0) + END +END mem_commit; + + +PROCEDURE [stdcall] malloc* (size: INTEGER): INTEGER; +VAR + ptr: INTEGER; +BEGIN + SYSTEM.CODE(060H); (* pusha *) + IF sysfunc2(18, 16) > ASR(size, 10) THEN + ptr := sysfunc3(68, 12, size); + IF ptr # 0 THEN + mem_commit(ptr, size) + END + ELSE + ptr := 0 + END; + SYSTEM.CODE(061H) (* popa *) + RETURN ptr +END malloc; + + +PROCEDURE [stdcall] free* (ptr: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE(060H); (* pusha *) + IF ptr # 0 THEN + ptr := sysfunc3(68, 13, ptr) + END; + SYSTEM.CODE(061H) (* popa *) + RETURN 0 +END free; + + +PROCEDURE [stdcall] realloc* (ptr, size: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE(060H); (* pusha *) + ptr := sysfunc4(68, 20, size, ptr); + SYSTEM.CODE(061H) (* popa *) + RETURN ptr +END realloc; + + +PROCEDURE AppAdr (): INTEGER; +VAR + buf: ARRAY 1024 OF CHAR; + a: INTEGER; +BEGIN + a := sysfunc3(9, SYSTEM.ADR(buf), -1); + SYSTEM.GET(SYSTEM.ADR(buf) + 22, a) + RETURN a +END AppAdr; + + +PROCEDURE GetCommandLine* (): INTEGER; +VAR + param: INTEGER; +BEGIN + SYSTEM.GET(28 + AppAdr(), param) + RETURN param +END GetCommandLine; + + +PROCEDURE GetName* (): INTEGER; +VAR + name: INTEGER; +BEGIN + SYSTEM.GET(32 + AppAdr(), name) + RETURN name +END GetName; + + +PROCEDURE [stdcall] dll_init2 (arg1, arg2, arg3, arg4, arg5: INTEGER); +BEGIN + SYSTEM.CODE( + 060H, (* pusha *) + 08BH, 045H, 008H, (* mov eax, dword [ebp + 8] *) + 08BH, 05DH, 00CH, (* mov ebx, dword [ebp + 12] *) + 08BH, 04DH, 010H, (* mov ecx, dword [ebp + 16] *) + 08BH, 055H, 014H, (* mov edx, dword [ebp + 20] *) + 08BH, 075H, 018H, (* mov esi, dword [ebp + 24] *) + 0FFH, 0D6H, (* call esi *) + 061H, (* popa *) + 0C9H, (* leave *) + 0C2H, 014H, 000H (* ret 20 *) + ) +END dll_init2; + + +PROCEDURE GetProcAdr* (name: ARRAY OF CHAR; lib: INTEGER): INTEGER; +VAR + cur, procname, adr: INTEGER; + + PROCEDURE streq (str1, str2: INTEGER): BOOLEAN; + VAR + c1, c2: CHAR; + BEGIN + REPEAT + SYSTEM.GET(str1, c1); + SYSTEM.GET(str2, c2); + INC(str1); + INC(str2) + UNTIL (c1 # c2) OR (c1 = 0X) + + RETURN c1 = c2 + END streq; + +BEGIN + adr := 0; + IF (lib # 0) & (name # "") THEN + cur := lib; + REPEAT + SYSTEM.GET(cur, procname); + INC(cur, 8) + UNTIL (procname = 0) OR streq(procname, SYSTEM.ADR(name[0])); + IF procname # 0 THEN + SYSTEM.GET(cur - 4, adr) + END + END + + RETURN adr +END GetProcAdr; + + +PROCEDURE init (dll: INTEGER); +VAR + lib_init: INTEGER; +BEGIN + lib_init := GetProcAdr("lib_init", dll); + IF lib_init # 0 THEN + DLL_INIT(lib_init) + END; + lib_init := GetProcAdr("START", dll); + IF lib_init # 0 THEN + DLL_INIT(lib_init) + END +END init; + + +PROCEDURE OutChar* (c: CHAR); +BEGIN + sysfunc3(63, 1, ORD(c)) +END OutChar; + + +PROCEDURE OutLn*; +BEGIN + OutChar(0DX); + OutChar(0AX) +END OutLn; + + +PROCEDURE OutString (s: ARRAY OF CHAR); +VAR + i: INTEGER; +BEGIN + i := 0; + WHILE (i < LEN(s)) & (s[i] # 0X) DO + OutChar(s[i]); + INC(i) + END +END OutString; + + +PROCEDURE imp_error (lib, proc: STRING); +BEGIN + OutString("import error: "); + IF proc = "" THEN + OutString("can't load '") + ELSE + OutString("not found '"); OutString(proc); OutString("' in '") + END; + OutString(lib); + OutString("'" + 0DX + 0AX) +END imp_error; + + +PROCEDURE GetStr (adr, i: INTEGER; VAR str: STRING); +VAR + c: CHAR; +BEGIN + REPEAT + SYSTEM.GET(adr, c); INC(adr); + str[i] := c; INC(i) + UNTIL c = 0X +END GetStr; + + +PROCEDURE [stdcall-] dll_Load* (import_table: INTEGER): INTEGER; +CONST + path = "/sys/lib/"; +VAR + imp, lib, exp, proc, pathLen: INTEGER; + procname, libname: STRING; +BEGIN + SYSTEM.CODE(060H); (* pusha *) + libname := path; + pathLen := LENGTH(libname); + + SYSTEM.GET(import_table, imp); + WHILE imp # 0 DO + SYSTEM.GET(import_table + 4, lib); + GetStr(lib, pathLen, libname); + exp := sysfunc3(68, 19, SYSTEM.ADR(libname[0])); + IF exp = 0 THEN + imp_error(libname, "") + ELSE + REPEAT + SYSTEM.GET(imp, proc); + IF proc # 0 THEN + GetStr(proc, 0, procname); + proc := GetProcAdr(procname, exp); + IF proc # 0 THEN + SYSTEM.PUT(imp, proc) + ELSE + proc := 1; + imp_error(libname, procname) + END; + INC(imp, 4) + END + UNTIL proc = 0; + init(exp) + END; + INC(import_table, 8); + SYSTEM.GET(import_table, imp); + END; + + SYSTEM.CODE(061H) (* popa *) + RETURN 0 +END dll_Load; + + +PROCEDURE [stdcall] dll_Init (entry: INTEGER); +BEGIN + SYSTEM.CODE(060H); (* pusha *) + IF entry # 0 THEN + dll_init2(SYSTEM.ADR(malloc), SYSTEM.ADR(free), SYSTEM.ADR(realloc), SYSTEM.ADR(dll_Load), entry) + END; + SYSTEM.CODE(061H); (* popa *) +END dll_Init; + + +PROCEDURE LoadLib* (name: ARRAY OF CHAR): INTEGER; +VAR + Lib: INTEGER; +BEGIN + DLL_INIT := dll_Init; + Lib := sysfunc3(68, 19, SYSTEM.ADR(name[0])); + IF Lib # 0 THEN + init(Lib) + END + RETURN Lib +END LoadLib; + + +PROCEDURE _init* (import_table: INTEGER); +BEGIN + DLL_INIT := dll_Init; + dll_Load(import_table) +END _init; + + +END KOSAPI. \ No newline at end of file diff --git a/programs/other/fb2reader/SRC/LISTS.ob07 b/programs/other/fb2reader/SRC/LISTS.ob07 new file mode 100644 index 0000000000..89e4d802a2 --- /dev/null +++ b/programs/other/fb2reader/SRC/LISTS.ob07 @@ -0,0 +1,135 @@ +(* + Copyright 2018, 2020 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE LISTS; + + +TYPE + + LIST* = POINTER TO rLIST; + + ITEM* = POINTER TO rITEM; + + rITEM* = RECORD + + prev*, next*: ITEM; + + destroy*: PROCEDURE (VAR item: ITEM) + + END; + + rLIST* = RECORD + + first*, last*: ITEM + + END; + + +PROCEDURE push* (list: LIST; item: ITEM); +BEGIN + ASSERT(list # NIL); + ASSERT(item # NIL); + + IF list.first = NIL THEN + list.first := item; + list.last := item; + item.prev := NIL; + item.next := NIL + ELSE + ASSERT(list.last # NIL); + item.prev := list.last; + list.last.next := item; + item.next := NIL; + list.last := item + END +END push; + + +PROCEDURE get* (list: LIST; n: INTEGER): ITEM; +VAR + cur: ITEM; + +BEGIN + cur := list.first; + WHILE (cur # NIL) & (n > 0) DO + cur := cur.next; + DEC(n) + END + + RETURN cur +END get; + + +PROCEDURE idx* (list: LIST; item: ITEM): INTEGER; +VAR + cur: ITEM; + n: INTEGER; + +BEGIN + ASSERT(item # NIL); + n := 0; + cur := list.first; + WHILE (cur # NIL) & (cur # item) DO + cur := cur.next; + INC(n) + END; + + IF cur = NIL THEN + n := -1 + END + + RETURN n +END idx; + + +PROCEDURE create* (list: LIST): LIST; +BEGIN + IF list = NIL THEN + NEW(list) + END; + + list.first := NIL; + list.last := NIL + + RETURN list +END create; + + +PROCEDURE destroy* (VAR list: LIST); +VAR + item, next: ITEM; + +BEGIN + IF list # NIL THEN + item := list.first; + WHILE item # NIL DO + next := item.next; + IF item.destroy # NIL THEN + item.destroy(item) + ELSE + DISPOSE(item) + END; + item := next + END; + DISPOSE(list) + END +END destroy; + + +END LISTS. \ No newline at end of file diff --git a/programs/other/fb2reader/SRC/Libimg.ob07 b/programs/other/fb2reader/SRC/Libimg.ob07 new file mode 100644 index 0000000000..ecc2b79c9f --- /dev/null +++ b/programs/other/fb2reader/SRC/Libimg.ob07 @@ -0,0 +1,81 @@ +(* + Copyright 2016, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE LibImg; + +IMPORT sys := SYSTEM, KOSAPI, File, S := Strings; + + +PROCEDURE [stdcall, "Libimg.obj", ""] img_decode (data, size, options: INTEGER): INTEGER; END; +PROCEDURE [stdcall, "Libimg.obj", ""] img_to_rgb2 (data, data_rgb: INTEGER); END; +PROCEDURE [stdcall, "Libimg.obj", ""] img_scale (src, crop_x, crop_y, crop_width, crop_height, dst, scale, inter, param1, param2: INTEGER): INTEGER; END; +PROCEDURE [stdcall, "Libimg.obj", ""] img_destroy* (img: INTEGER); END; +PROCEDURE [stdcall, "Libimg.obj", ""] img_convert (src, dst, dst_type, flags, param: INTEGER): INTEGER; END; + + +PROCEDURE GetInf* (img: INTEGER; VAR sizeX, sizeY, data: INTEGER); +BEGIN + sys.GET(img + 4, sizeX); + sys.GET(img + 8, sizeY); + sys.GET(img + 24, data) +END GetInf; + + +PROCEDURE GetImg* (ptr, size, Width: INTEGER; VAR sizeY: INTEGER): INTEGER; +VAR + image_data, dst, x, y, type: INTEGER; +BEGIN + image_data := img_decode(ptr, size, 0); + IF image_data # 0 THEN + sys.GET(image_data + 4, x); + sys.GET(image_data + 8, y); + sys.GET(image_data + 20, type); + IF type # 3 THEN + dst := img_convert(image_data, 0, 3, 0, 0); + img_destroy(image_data); + image_data := dst + END; + IF (x > Width) & (image_data # 0) THEN + dst := img_scale(image_data, 0, 0, x, y, 0, 3, 1, Width, (y * Width) DIV x); + img_destroy(image_data); + image_data := dst + END; + IF image_data # 0 THEN + sys.GET(image_data + 8, sizeY) + END + END + RETURN image_data +END GetImg; + + +PROCEDURE LoadFromFile* (fileName: S.STRING; width: INTEGER; VAR height: INTEGER): INTEGER; +VAR + size, res, ptr: INTEGER; +BEGIN + res := 0; + ptr := File.Load(fileName, size); + IF ptr # 0 THEN + res := GetImg(ptr, size, width, height); + ptr := KOSAPI.free(ptr) + END + RETURN res +END LoadFromFile; + + +END LibImg. diff --git a/programs/other/fb2reader/SRC/OpenDlg.ob07 b/programs/other/fb2reader/SRC/OpenDlg.ob07 new file mode 100644 index 0000000000..b5af638204 --- /dev/null +++ b/programs/other/fb2reader/SRC/OpenDlg.ob07 @@ -0,0 +1,134 @@ +(* + Copyright 2016, 2022 Anton Krotov + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*) + +MODULE OpenDlg; + +IMPORT sys := SYSTEM, KOSAPI, S := Strings; + +TYPE + + DRAW_WINDOW = PROCEDURE; + + TDialog = RECORD + type, + procinfo, + com_area_name, + com_area, + opendir_path, + dir_default_path, + start_path: INTEGER; + draw_window: DRAW_WINDOW; + status*, + openfile_path, + filename_area: INTEGER; + filter_area: + POINTER TO RECORD + size: INTEGER; + filter: ARRAY 4096 OF CHAR + END; + X, Y: INTEGER; + + procinf: ARRAY 1024 OF CHAR; + s_com_area_name: ARRAY 32 OF CHAR; + s_opendir_path, + s_dir_default_path, + FilePath*, + FileName*: ARRAY 4096 OF CHAR + END; + + Dialog* = POINTER TO TDialog; + + +PROCEDURE [stdcall, "Proc_lib.obj", ""] OpenDialog_start (od: Dialog); END; +PROCEDURE [stdcall, "Proc_lib.obj", ""] OpenDialog_init (od: Dialog); END; + +PROCEDURE Show*(od: Dialog; Width, Height: INTEGER); +BEGIN + IF od # NIL THEN + od.X := Width; + od.Y := Height; + OpenDialog_start(od) + END +END Show; + +PROCEDURE Create*(draw_window: DRAW_WINDOW; type: INTEGER; def_path, filter: ARRAY OF CHAR): Dialog; +VAR res: Dialog; n, i: INTEGER; + + PROCEDURE replace(VAR str: ARRAY OF CHAR; c1, c2: CHAR); + VAR i: INTEGER; + BEGIN + i := LENGTH(str) - 1; + WHILE i >= 0 DO + IF str[i] = c1 THEN + str[i] := c2 + END; + DEC(i) + END + END replace; + +BEGIN + NEW(res); + IF res # NIL THEN + NEW(res.filter_area); + IF res.filter_area # NIL THEN + res.s_com_area_name := "FFFFFFFF_open_dialog"; + res.com_area := 0; + res.type := type; + res.draw_window := draw_window; + COPY(def_path, res.s_dir_default_path); + COPY(filter, res.filter_area.filter); + + n := LENGTH(res.filter_area.filter); + FOR i := 0 TO 3 DO + res.filter_area.filter[n + i] := "|" + END; + res.filter_area.filter[n + 4] := 0X; + + res.X := 0; + res.Y := 0; + res.s_opendir_path := res.s_dir_default_path; + res.FilePath := ""; + res.FileName := ""; + res.status := 0; + res.filter_area.size := LENGTH(res.filter_area.filter); + res.procinfo := sys.ADR(res.procinf[0]); + res.com_area_name := sys.ADR(res.s_com_area_name[0]); + res.start_path := sys.SADR("/sys/File managers/opendial"); + res.opendir_path := sys.ADR(res.s_opendir_path[0]); + res.dir_default_path := sys.ADR(res.s_dir_default_path[0]); + res.openfile_path := sys.ADR(res.FilePath[0]); + res.filename_area := sys.ADR(res.FileName[0]); + + replace(res.filter_area.filter, "|", 0X); + OpenDialog_init(res) + ELSE + DISPOSE(res) + END + END + RETURN res +END Create; + +PROCEDURE Destroy*(VAR od: Dialog); +BEGIN + IF od # NIL THEN + DISPOSE(od.filter_area); + DISPOSE(od) + END +END Destroy; + + +END OpenDlg. diff --git a/programs/other/fb2reader/SRC/RTL.ob07 b/programs/other/fb2reader/SRC/RTL.ob07 new file mode 100644 index 0000000000..0818bca97d --- /dev/null +++ b/programs/other/fb2reader/SRC/RTL.ob07 @@ -0,0 +1,543 @@ +(* + BSD 2-Clause License + + Copyright (c) 2018-2021, Anton Krotov + All rights reserved. +*) + +MODULE RTL; + +IMPORT SYSTEM, API; + + +CONST + + minint = ROR(1, 1); + + WORD = API.BIT_DEPTH DIV 8; + + +VAR + + name: INTEGER; + types: INTEGER; + + +PROCEDURE [stdcall] _move* (bytes, dest, source: INTEGER); +BEGIN + SYSTEM.CODE( + 08BH, 045H, 008H, (* mov eax, dword [ebp + 8] *) + 085H, 0C0H, (* test eax, eax *) + 07EH, 019H, (* jle L *) + 0FCH, (* cld *) + 057H, (* push edi *) + 056H, (* push esi *) + 08BH, 075H, 010H, (* mov esi, dword [ebp + 16] *) + 08BH, 07DH, 00CH, (* mov edi, dword [ebp + 12] *) + 089H, 0C1H, (* mov ecx, eax *) + 0C1H, 0E9H, 002H, (* shr ecx, 2 *) + 0F3H, 0A5H, (* rep movsd *) + 089H, 0C1H, (* mov ecx, eax *) + 083H, 0E1H, 003H, (* and ecx, 3 *) + 0F3H, 0A4H, (* rep movsb *) + 05EH, (* pop esi *) + 05FH (* pop edi *) + (* L: *) + ) +END _move; + + +PROCEDURE [stdcall] _arrcpy* (base_size, len_dst, dst, len_src, src: INTEGER): BOOLEAN; +VAR + res: BOOLEAN; + +BEGIN + IF len_src > len_dst THEN + res := FALSE + ELSE + _move(len_src * base_size, dst, src); + res := TRUE + END + + RETURN res +END _arrcpy; + + +PROCEDURE [stdcall] _strcpy* (chr_size, len_src, src, len_dst, dst: INTEGER); +BEGIN + _move(MIN(len_dst, len_src) * chr_size, dst, src) +END _strcpy; + + +PROCEDURE [stdcall] _rot* (Len, Ptr: INTEGER); +BEGIN + SYSTEM.CODE( + 08BH, 04DH, 008H, (* mov ecx, dword [ebp + 8] *) (* ecx <- Len *) + 08BH, 045H, 00CH, (* mov eax, dword [ebp + 12] *) (* eax <- Ptr *) + 049H, (* dec ecx *) + 053H, (* push ebx *) + 08BH, 018H, (* mov ebx, dword [eax] *) + (* L: *) + 08BH, 050H, 004H, (* mov edx, dword [eax + 4] *) + 089H, 010H, (* mov dword [eax], edx *) + 083H, 0C0H, 004H, (* add eax, 4 *) + 049H, (* dec ecx *) + 075H, 0F5H, (* jnz L *) + 089H, 018H, (* mov dword [eax], ebx *) + 05BH, (* pop ebx *) + 05DH, (* pop ebp *) + 0C2H, 008H, 000H (* ret 8 *) + ) +END _rot; + + +PROCEDURE [stdcall] _set* (b, a: INTEGER); (* {a..b} -> eax *) +BEGIN + SYSTEM.CODE( + 08BH, 04DH, 008H, (* mov ecx, dword [ebp + 8] *) (* ecx <- b *) + 08BH, 045H, 00CH, (* mov eax, dword [ebp + 12] *) (* eax <- a *) + 039H, 0C8H, (* cmp eax, ecx *) + 07FH, 033H, (* jg L1 *) + 083H, 0F8H, 01FH, (* cmp eax, 31 *) + 07FH, 02EH, (* jg L1 *) + 085H, 0C9H, (* test ecx, ecx *) + 07CH, 02AH, (* jl L1 *) + 083H, 0F9H, 01FH, (* cmp ecx, 31 *) + 07EH, 005H, (* jle L3 *) + 0B9H, 01FH, 000H, 000H, 000H, (* mov ecx, 31 *) + (* L3: *) + 085H, 0C0H, (* test eax, eax *) + 07DH, 002H, (* jge L2 *) + 031H, 0C0H, (* xor eax, eax *) + (* L2: *) + 089H, 0CAH, (* mov edx, ecx *) + 029H, 0C2H, (* sub edx, eax *) + 0B8H, 000H, 000H, 000H, 080H, (* mov eax, 0x80000000 *) + 087H, 0CAH, (* xchg edx, ecx *) + 0D3H, 0F8H, (* sar eax, cl *) + 087H, 0CAH, (* xchg edx, ecx *) + 083H, 0E9H, 01FH, (* sub ecx, 31 *) + 0F7H, 0D9H, (* neg ecx *) + 0D3H, 0E8H, (* shr eax, cl *) + 05DH, (* pop ebp *) + 0C2H, 008H, 000H, (* ret 8 *) + (* L1: *) + 031H, 0C0H, (* xor eax, eax *) + 05DH, (* pop ebp *) + 0C2H, 008H, 000H (* ret 8 *) + ) +END _set; + + +PROCEDURE [stdcall] _set1* (a: INTEGER); (* {a} -> eax *) +BEGIN + SYSTEM.CODE( + 031H, 0C0H, (* xor eax, eax *) + 08BH, 04DH, 008H, (* mov ecx, dword [ebp + 8] *) (* ecx <- a *) + 083H, 0F9H, 01FH, (* cmp ecx, 31 *) + 077H, 003H, (* ja L *) + 00FH, 0ABH, 0C8H (* bts eax, ecx *) + (* L: *) + ) +END _set1; + + +PROCEDURE [stdcall] _divmod* (y, x: INTEGER); (* (x div y) -> eax; (x mod y) -> edx *) +BEGIN + SYSTEM.CODE( + 053H, (* push ebx *) + 08BH, 045H, 00CH, (* mov eax, dword [ebp + 12] *) (* eax <- x *) + 031H, 0D2H, (* xor edx, edx *) + 085H, 0C0H, (* test eax, eax *) + 074H, 018H, (* je L2 *) + 07FH, 002H, (* jg L1 *) + 0F7H, 0D2H, (* not edx *) + (* L1: *) + 089H, 0C3H, (* mov ebx, eax *) + 08BH, 04DH, 008H, (* mov ecx, dword [ebp + 8] *) (* ecx <- y *) + 0F7H, 0F9H, (* idiv ecx *) + 085H, 0D2H, (* test edx, edx *) + 074H, 009H, (* je L2 *) + 031H, 0CBH, (* xor ebx, ecx *) + 085H, 0DBH, (* test ebx, ebx *) + 07DH, 003H, (* jge L2 *) + 048H, (* dec eax *) + 001H, 0CAH, (* add edx, ecx *) + (* L2: *) + 05BH (* pop ebx *) + ) +END _divmod; + + +PROCEDURE [stdcall] _new* (t, size: INTEGER; VAR ptr: INTEGER); +BEGIN + ptr := API._NEW(size); + IF ptr # 0 THEN + SYSTEM.PUT(ptr, t); + INC(ptr, WORD) + END +END _new; + + +PROCEDURE [stdcall] _dispose* (VAR ptr: INTEGER); +BEGIN + IF ptr # 0 THEN + ptr := API._DISPOSE(ptr - WORD) + END +END _dispose; + + +PROCEDURE [stdcall] _length* (len, str: INTEGER); +BEGIN + SYSTEM.CODE( + 08BH, 045H, 00CH, (* mov eax, dword [ebp + 0Ch] *) + 08BH, 04DH, 008H, (* mov ecx, dword [ebp + 08h] *) + 048H, (* dec eax *) + (* L1: *) + 040H, (* inc eax *) + 080H, 038H, 000H, (* cmp byte [eax], 0 *) + 074H, 003H, (* jz L2 *) + 0E2H, 0F8H, (* loop L1 *) + 040H, (* inc eax *) + (* L2: *) + 02BH, 045H, 00CH (* sub eax, dword [ebp + 0Ch] *) + ) +END _length; + + +PROCEDURE [stdcall] _lengthw* (len, str: INTEGER); +BEGIN + SYSTEM.CODE( + 08BH, 045H, 00CH, (* mov eax, dword [ebp + 0Ch] *) + 08BH, 04DH, 008H, (* mov ecx, dword [ebp + 08h] *) + 048H, (* dec eax *) + 048H, (* dec eax *) + (* L1: *) + 040H, (* inc eax *) + 040H, (* inc eax *) + 066H, 083H, 038H, 000H, (* cmp word [eax], 0 *) + 074H, 004H, (* jz L2 *) + 0E2H, 0F6H, (* loop L1 *) + 040H, (* inc eax *) + 040H, (* inc eax *) + (* L2: *) + 02BH, 045H, 00CH, (* sub eax, dword [ebp + 0Ch] *) + 0D1H, 0E8H (* shr eax, 1 *) + ) +END _lengthw; + + +PROCEDURE [stdcall] strncmp (a, b, n: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE( + 056H, (* push esi *) + 057H, (* push edi *) + 053H, (* push ebx *) + 08BH, 075H, 008H, (* mov esi, dword[ebp + 8]; esi <- a *) + 08BH, 07DH, 00CH, (* mov edi, dword[ebp + 12]; edi <- b *) + 08BH, 05DH, 010H, (* mov ebx, dword[ebp + 16]; ebx <- n *) + 031H, 0C9H, (* xor ecx, ecx *) + 031H, 0D2H, (* xor edx, edx *) + 0B8H, + 000H, 000H, 000H, 080H, (* mov eax, minint *) + (* L1: *) + 085H, 0DBH, (* test ebx, ebx *) + 07EH, 017H, (* jle L3 *) + 08AH, 00EH, (* mov cl, byte[esi] *) + 08AH, 017H, (* mov dl, byte[edi] *) + 046H, (* inc esi *) + 047H, (* inc edi *) + 04BH, (* dec ebx *) + 039H, 0D1H, (* cmp ecx, edx *) + 074H, 006H, (* je L2 *) + 089H, 0C8H, (* mov eax, ecx *) + 029H, 0D0H, (* sub eax, edx *) + 0EBH, 006H, (* jmp L3 *) + (* L2: *) + 085H, 0C9H, (* test ecx, ecx *) + 075H, 0E7H, (* jne L1 *) + 031H, 0C0H, (* xor eax, eax *) + (* L3: *) + 05BH, (* pop ebx *) + 05FH, (* pop edi *) + 05EH, (* pop esi *) + 05DH, (* pop ebp *) + 0C2H, 00CH, 000H (* ret 12 *) + ) + RETURN 0 +END strncmp; + + +PROCEDURE [stdcall] strncmpw (a, b, n: INTEGER): INTEGER; +BEGIN + SYSTEM.CODE( + 056H, (* push esi *) + 057H, (* push edi *) + 053H, (* push ebx *) + 08BH, 075H, 008H, (* mov esi, dword[ebp + 8]; esi <- a *) + 08BH, 07DH, 00CH, (* mov edi, dword[ebp + 12]; edi <- b *) + 08BH, 05DH, 010H, (* mov ebx, dword[ebp + 16]; ebx <- n *) + 031H, 0C9H, (* xor ecx, ecx *) + 031H, 0D2H, (* xor edx, edx *) + 0B8H, + 000H, 000H, 000H, 080H, (* mov eax, minint *) + (* L1: *) + 085H, 0DBH, (* test ebx, ebx *) + 07EH, 01BH, (* jle L3 *) + 066H, 08BH, 00EH, (* mov cx, word[esi] *) + 066H, 08BH, 017H, (* mov dx, word[edi] *) + 046H, (* inc esi *) + 046H, (* inc esi *) + 047H, (* inc edi *) + 047H, (* inc edi *) + 04BH, (* dec ebx *) + 039H, 0D1H, (* cmp ecx, edx *) + 074H, 006H, (* je L2 *) + 089H, 0C8H, (* mov eax, ecx *) + 029H, 0D0H, (* sub eax, edx *) + 0EBH, 006H, (* jmp L3 *) + (* L2: *) + 085H, 0C9H, (* test ecx, ecx *) + 075H, 0E3H, (* jne L1 *) + 031H, 0C0H, (* xor eax, eax *) + (* L3: *) + 05BH, (* pop ebx *) + 05FH, (* pop edi *) + 05EH, (* pop esi *) + 05DH, (* pop ebp *) + 0C2H, 00CH, 000H (* ret 12 *) + ) + RETURN 0 +END strncmpw; + + +PROCEDURE [stdcall] _strcmp* (op, len2, str2, len1, str1: INTEGER): BOOLEAN; +VAR + res: INTEGER; + bRes: BOOLEAN; + c: CHAR; + +BEGIN + res := strncmp(str1, str2, MIN(len1, len2)); + IF res = minint THEN + IF len1 > len2 THEN + SYSTEM.GET(str1 + len2, c); + res := ORD(c) + ELSIF len1 < len2 THEN + SYSTEM.GET(str2 + len1, c); + res := -ORD(c) + ELSE + res := 0 + END + END; + + CASE op OF + |0: bRes := res = 0 + |1: bRes := res # 0 + |2: bRes := res < 0 + |3: bRes := res <= 0 + |4: bRes := res > 0 + |5: bRes := res >= 0 + END + + RETURN bRes +END _strcmp; + + +PROCEDURE [stdcall] _strcmpw* (op, len2, str2, len1, str1: INTEGER): BOOLEAN; +VAR + res: INTEGER; + bRes: BOOLEAN; + c: WCHAR; + +BEGIN + res := strncmpw(str1, str2, MIN(len1, len2)); + IF res = minint THEN + IF len1 > len2 THEN + SYSTEM.GET(str1 + len2 * 2, c); + res := ORD(c) + ELSIF len1 < len2 THEN + SYSTEM.GET(str2 + len1 * 2, c); + res := -ORD(c) + ELSE + res := 0 + END + END; + + CASE op OF + |0: bRes := res = 0 + |1: bRes := res # 0 + |2: bRes := res < 0 + |3: bRes := res <= 0 + |4: bRes := res > 0 + |5: bRes := res >= 0 + END + + RETURN bRes +END _strcmpw; + + +PROCEDURE PCharToStr (pchar: INTEGER; VAR s: ARRAY OF CHAR); +VAR + c: CHAR; + i: INTEGER; + +BEGIN + i := 0; + REPEAT + SYSTEM.GET(pchar, c); + s[i] := c; + INC(pchar); + INC(i) + UNTIL c = 0X +END PCharToStr; + + +PROCEDURE IntToStr (x: INTEGER; VAR str: ARRAY OF CHAR); +VAR + i, a: INTEGER; + +BEGIN + i := 0; + a := x; + REPEAT + INC(i); + a := a DIV 10 + UNTIL a = 0; + + str[i] := 0X; + + REPEAT + DEC(i); + str[i] := CHR(x MOD 10 + ORD("0")); + x := x DIV 10 + UNTIL x = 0 +END IntToStr; + + +PROCEDURE append (VAR s1: ARRAY OF CHAR; s2: ARRAY OF CHAR); +VAR + n1, n2: INTEGER; + +BEGIN + n1 := LENGTH(s1); + n2 := LENGTH(s2); + + ASSERT(n1 + n2 < LEN(s1)); + + SYSTEM.MOVE(SYSTEM.ADR(s2[0]), SYSTEM.ADR(s1[n1]), n2); + s1[n1 + n2] := 0X +END append; + + +PROCEDURE [stdcall] _error* (modnum, _module, err, line: INTEGER); +VAR + s, temp: ARRAY 1024 OF CHAR; + +BEGIN + CASE err OF + | 1: s := "assertion failure" + | 2: s := "NIL dereference" + | 3: s := "bad divisor" + | 4: s := "NIL procedure call" + | 5: s := "type guard error" + | 6: s := "index out of range" + | 7: s := "invalid CASE" + | 8: s := "array assignment error" + | 9: s := "CHR out of range" + |10: s := "WCHR out of range" + |11: s := "BYTE out of range" + END; + + append(s, API.eol + "module: "); PCharToStr(_module, temp); append(s, temp); + append(s, API.eol + "line: "); IntToStr(line, temp); append(s, temp); + + API.DebugMsg(SYSTEM.ADR(s[0]), name); + + API.exit_thread(0) +END _error; + + +PROCEDURE [stdcall] _isrec* (t0, t1, r: INTEGER): INTEGER; +BEGIN + SYSTEM.GET(t0 + t1 + types, t0) + RETURN t0 MOD 2 +END _isrec; + + +PROCEDURE [stdcall] _is* (t0, p: INTEGER): INTEGER; +BEGIN + IF p # 0 THEN + SYSTEM.GET(p - WORD, p); + SYSTEM.GET(t0 + p + types, p) + END + + RETURN p MOD 2 +END _is; + + +PROCEDURE [stdcall] _guardrec* (t0, t1: INTEGER): INTEGER; +BEGIN + SYSTEM.GET(t0 + t1 + types, t0) + RETURN t0 MOD 2 +END _guardrec; + + +PROCEDURE [stdcall] _guard* (t0, p: INTEGER): INTEGER; +BEGIN + SYSTEM.GET(p, p); + IF p # 0 THEN + SYSTEM.GET(p - WORD, p); + SYSTEM.GET(t0 + p + types, p) + ELSE + p := 1 + END + + RETURN p MOD 2 +END _guard; + + +PROCEDURE [stdcall] _dllentry* (hinstDLL, fdwReason, lpvReserved: INTEGER): INTEGER; + RETURN API.dllentry(hinstDLL, fdwReason, lpvReserved) +END _dllentry; + + +PROCEDURE [stdcall] _sofinit*; +BEGIN + API.sofinit +END _sofinit; + + +PROCEDURE [stdcall] _exit* (code: INTEGER); +BEGIN + API.exit(code) +END _exit; + + +PROCEDURE [stdcall] _init* (modname: INTEGER; tcount, _types: INTEGER; code, param: INTEGER); +VAR + t0, t1, i, j: INTEGER; + +BEGIN + SYSTEM.CODE(09BH, 0DBH, 0E3H); (* finit *) + API.init(param, code); + + types := API._NEW(tcount * tcount + SYSTEM.SIZE(INTEGER)); + ASSERT(types # 0); + FOR i := 0 TO tcount - 1 DO + FOR j := 0 TO tcount - 1 DO + t0 := i; t1 := j; + + WHILE (t1 # 0) & (t1 # t0) DO + SYSTEM.GET(_types + t1 * WORD, t1) + END; + + SYSTEM.PUT8(i * tcount + j + types, ORD(t0 = t1)) + END + END; + + name := modname +END _init; + + +END RTL. \ No newline at end of file diff --git a/programs/other/fb2reader/SRC/Read.ob07 b/programs/other/fb2reader/SRC/Read.ob07 new file mode 100644 index 0000000000..cf6c0fc922 --- /dev/null +++ b/programs/other/fb2reader/SRC/Read.ob07 @@ -0,0 +1,42 @@ +(* + Copyright 2016 Anton Krotov + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*) + +MODULE Read; + +IMPORT File, sys := SYSTEM; + +PROCEDURE Char*(F: File.FS; VAR x: CHAR): BOOLEAN; + RETURN File.Read(F, sys.ADR(x), sys.SIZE(CHAR)) = sys.SIZE(CHAR) +END Char; + +PROCEDURE Int*(F: File.FS; VAR x: INTEGER): BOOLEAN; + RETURN File.Read(F, sys.ADR(x), sys.SIZE(INTEGER)) = sys.SIZE(INTEGER) +END Int; + +PROCEDURE Real*(F: File.FS; VAR x: REAL): BOOLEAN; + RETURN File.Read(F, sys.ADR(x), sys.SIZE(REAL)) = sys.SIZE(REAL) +END Real; + +PROCEDURE Boolean*(F: File.FS; VAR x: BOOLEAN): BOOLEAN; + RETURN File.Read(F, sys.ADR(x), sys.SIZE(BOOLEAN)) = sys.SIZE(BOOLEAN) +END Boolean; + +PROCEDURE Set*(F: File.FS; VAR x: SET): BOOLEAN; + RETURN File.Read(F, sys.ADR(x), sys.SIZE(SET)) = sys.SIZE(SET) +END Set; + +END Read. diff --git a/programs/other/fb2reader/SRC/ReadFile.ob07 b/programs/other/fb2reader/SRC/ReadFile.ob07 new file mode 100644 index 0000000000..81ccc562d4 --- /dev/null +++ b/programs/other/fb2reader/SRC/ReadFile.ob07 @@ -0,0 +1,159 @@ +(* + Copyright 2016, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE ReadFile; + +IMPORT sys := SYSTEM, K := KOSAPI, S := Strings, File, SU := SysUtils, Encode; + + +VAR + + Mem, Pos, Size, FSize*: INTEGER; + + Error*: BOOLEAN; + + +PROCEDURE Adr*(): INTEGER; + RETURN Mem + Pos +END Adr; + + +PROCEDURE Next*(VAR ch: CHAR); +BEGIN + INC(Pos); + sys.GET(Mem + Pos, ch) +END Next; + + +PROCEDURE Progress*(): REAL; +VAR res: REAL; +BEGIN + res := FLT(Pos) / FLT(Size); + IF res < 0.0 THEN + res := 0.0 + END; + IF res > 1.0 THEN + res := 1.0 + END + RETURN res +END Progress; + + +PROCEDURE Load*(FileName: S.STRING); +VAR F: File.FS; pos, FileSize: INTEGER; +BEGIN + Error := TRUE; + Mem := 0; + F := File.Open(FileName); + SU.ErrorIf(F = NIL, 1); + FileSize := File.Seek(F, 0, File.SEEK_END); + Size := FileSize; + SU.ErrorIf(FileSize <= 0, 1); + pos := File.Seek(F, 0, File.SEEK_BEG); + SU.ErrorIf(pos # 0, 1); + Mem := K.malloc(FileSize + 1024); + SU.MemError(Mem = 0); + pos := File.Read(F, Mem, FileSize); + SU.ErrorIf(pos # FileSize, 1); + sys.PUT(Mem + FileSize, 0X); + File.Close(F); + Pos := -1; + Error := FALSE; + FSize := FileSize +END Load; + + +PROCEDURE Free*; +BEGIN + IF Mem # 0 THEN + Mem := K.free(Mem) + END +END Free; + + +PROCEDURE Conv*(cp: Encode.CP); +VAR m, nov, mem2, k: INTEGER; c: CHAR; +BEGIN + m := Mem; + k := 0; + REPEAT + sys.GET(m, c); INC(m); + k := k + cp[ORD(c)].len + UNTIL c = 0X; + nov := K.malloc(k + 1024); + SU.MemError(nov = 0); + Size := k; + mem2 := nov; + m := Mem; + REPEAT + sys.GET(m, c); INC(m); + sys.MOVE(sys.ADR(cp[ORD(c)].utf8), nov, cp[ORD(c)].len); + nov := nov + cp[ORD(c)].len + UNTIL c = 0X; + Pos := -1; + Mem := K.free(Mem); + Mem := mem2; +END Conv; + + +PROCEDURE SeekBeg*; +BEGIN + Pos := -1 +END SeekBeg; + + +PROCEDURE Int*(): INTEGER; +VAR i: INTEGER; +BEGIN + sys.GET(Mem + Pos, i) + RETURN i +END Int; + + +PROCEDURE FileSize*(name: S.STRING): INTEGER; +VAR F: File.FS; res: INTEGER; +BEGIN + F := File.Open(name); + res := File.Seek(F, 0, 2); + File.Close(F) + RETURN res +END FileSize; + + +PROCEDURE ChkSum* (name: S.STRING): INTEGER; +VAR + ptr, size, res: INTEGER; + b: BYTE; +BEGIN + res := 0; + ptr := File.Load(name, size); + IF ptr # 0 THEN + WHILE size > 0 DO + sys.GET(ptr, b); + INC(res, b); + INC(ptr); + DEC(size) + END; + ptr := K.free(ptr) + END + RETURN res +END ChkSum; + + +END ReadFile. diff --git a/programs/other/fb2reader/SRC/Search.ob07 b/programs/other/fb2reader/SRC/Search.ob07 new file mode 100644 index 0000000000..c4f4de1c6c --- /dev/null +++ b/programs/other/fb2reader/SRC/Search.ob07 @@ -0,0 +1,645 @@ +(* + Copyright 2020, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Search; + +IMPORT + + XML, G := Graph, Window, Font, S := Strings, LISTS, SYSTEM, + SU := SysUtils, K := KOSAPI, SearchForm; + + +TYPE + + STRING* = SearchForm.STRING; + + PFind = PROCEDURE (d: INTEGER); + + TRect = POINTER TO RECORD (LISTS.ITEM) + + x1, y1, x2, y2: INTEGER + + END; + + TPos = POINTER TO RECORD (LISTS.ITEM) + + n, first, last: INTEGER; + RectList: LISTS.LIST + + END; + + TextIdx = POINTER TO RECORD + + cnt, offs: ARRAY 256 OF INTEGER; + table: INTEGER; + data, size: INTEGER + + END; + + Text = POINTER TO RECORD (LISTS.ITEM) + + case: BOOLEAN; + idx0, idx1: TextIdx; + str0, str1: STRING; + PosList: LISTS.LIST; + curPos: TPos; + found: INTEGER; + body: XML.TAG + + END; + + +VAR + + TextList: LISTS.LIST; + Body: XML.TAG; + Find: PFind; + + +PROCEDURE SelText (Col: Window.TRect; min, max, Ycur, LineH: INTEGER; right: BOOLEAN; rect: TRect; cur: BOOLEAN); +VAR + y, y0, color: INTEGER; + +BEGIN + y := rect.y1 - Ycur; + y0 := y - y MOD LineH; + IF (min <= y0) & (y0 <= max) THEN + IF cur THEN + color := 0FF0000H + ELSE + color := 0 + END; + G.BoxNotXOR(Col.Left + rect.x1 + 1, Col.Top + y - Col.Height * ORD(right), Col.Left + rect.x2, Col.Top + y - Col.Height * ORD(right) + Font.FontH(), color) + END +END SelText; + + +PROCEDURE draw* (body: XML.TAG; ColLeft, ColRight: Window.TRect; Ycur, LineH: INTEGER; TwoCol: BOOLEAN); +VAR + rect: TRect; + pos, cur: TPos; + +BEGIN + Body := body; + IF body.text # NIL THEN + pos := body.text(Text).PosList.first(TPos); + cur := body.text(Text).curPos + ELSE + pos := NIL; + cur := NIL + END; + WHILE pos # NIL DO + rect := pos.RectList.first(TRect); + WHILE rect # NIL DO + SelText(ColLeft, 0, ColLeft.Height - LineH, Ycur, LineH, FALSE, rect, pos = cur); + IF TwoCol THEN + SelText(ColRight, ColLeft.Height, ColLeft.Height + ColRight.Height - LineH, Ycur, LineH, TRUE, rect, pos = cur) + END; + rect := rect.next(TRect) + END; + pos := pos.next(TPos) + END +END draw; + + +PROCEDURE getc_utf8 (VAR text, size, code: INTEGER); +VAR + c: BYTE; + n, k: INTEGER; + end: BOOLEAN; + +BEGIN + ASSERT(size > 0); + code := 0; + end := FALSE; + REPEAT + SYSTEM.GET(text, c); + INC(text); + DEC(size); + CASE c OF + | 0..127: + code := c; + end := TRUE + + |128..191: + code := code * 64 + c MOD 64; + DEC(n); + end := n <= 0 + + |192..255: + k := LSL(c, 24); + n := -2; + REPEAT + k := ROR(k, -1); + INC(n) + UNTIL ~ODD(k); + k := LSL(c, n + 25); + code := LSR(k, n + 25) + + END + UNTIL (size = 0) OR end +END getc_utf8; + + +PROCEDURE textlen (body: XML.ELEMENT; VAR length: INTEGER); +VAR + cur: XML.ELEMENT; + +BEGIN + cur := body; + WHILE (cur # NIL) DO + IF cur IS XML.TAG THEN + textlen(cur(XML.TAG).child.first, length) + ELSIF cur IS XML.WORD THEN + INC(length, cur(XML.WORD).value.last - cur(XML.WORD).value.first + 1) + ELSIF cur IS XML.SPACE THEN + INC(length) + END; + cur := cur.next + END +END textlen; + + +PROCEDURE puttext (body: XML.ELEMENT; VAR buf: INTEGER); +VAR + cur: XML.ELEMENT; + len: INTEGER; + +BEGIN + cur := body; + WHILE (cur # NIL) DO + IF cur IS XML.TAG THEN + puttext(cur(XML.TAG).child.first, buf) + ELSIF cur IS XML.WORD THEN + len := cur(XML.WORD).value.last - cur(XML.WORD).value.first + 1; + SYSTEM.MOVE(cur(XML.WORD).value.first, buf, len); + INC(buf, len) + ELSIF cur IS XML.SPACE THEN + SYSTEM.PUT(buf, 20X); + INC(buf) + END; + cur := cur.next + END +END puttext; + + +PROCEDURE cap (code: INTEGER): INTEGER; +BEGIN + CASE code OF + |61H..7AH, 430H..44FH: + DEC(code, 32) + |451H..45FH: + DEC(code, 80) + |491H: + code := 490H + ELSE + END + RETURN code +END cap; + + +PROCEDURE UpCase (s1, s2, length: INTEGER); +VAR + code, n: INTEGER; + u: S.UTF8; + +BEGIN + WHILE length > 0 DO + getc_utf8(s1, length, code); + S.utf8(cap(code), u); + n := LENGTH(u); + SYSTEM.MOVE(SYSTEM.ADR(u[0]), s2, n); + INC(s2, n) + END +END UpCase; + + +PROCEDURE create (body: XML.ELEMENT); +VAR + length, buf, buf1, temp: INTEGER; + text: Text; + xml: XML.ELEMENT; + + + PROCEDURE index (idx: TextIdx; buf, length: INTEGER); + VAR + i: INTEGER; + c: CHAR; + offs, temp: INTEGER; + + BEGIN + idx.data := buf; + idx.size := length; + + FOR i := 0 TO 255 DO + idx.offs[i] := 0; + idx.cnt[i] := 0 + END; + + i := length; + + WHILE i > 0 DO + SYSTEM.GET(buf, c); + INC(idx.offs[ORD(c)]); + DEC(i); + INC(buf) + END; + + offs := 0; + + FOR i := 0 TO 255 DO + temp := offs; + INC(offs, idx.offs[i]); + idx.offs[i] := temp * 4 + END; + + idx.table := K.malloc(offs * 4); + SU.MemError(idx.table = 0); + + i := length; + buf := idx.data; + + WHILE i > 0 DO + SYSTEM.GET(buf, c); + SYSTEM.PUT(idx.table + idx.offs[ORD(c)] + idx.cnt[ORD(c)] * 4, length - i); + INC(idx.cnt[ORD(c)]); + DEC(i); + INC(buf) + END + END index; + + +BEGIN + NEW(text); + text.body := body(XML.TAG); + text.PosList := LISTS.create(NIL); + + xml := body; + body := body(XML.TAG).child.first; + textlen(body, length); + buf := K.malloc(length); + SU.MemError(buf = 0); + temp := buf; + puttext(body, temp); + + NEW(text.idx0); + index(text.idx0, buf, length); + + buf1 := K.malloc(length); + SU.MemError(buf1 = 0); + + UpCase(buf, buf1, length); + + NEW(text.idx1); + index(text.idx1, buf1, text.idx0.size); + + text.case := FALSE; + + text.str0 := ""; + text.str1 := ""; + xml(XML.TAG).text := text; + LISTS.push(TextList, text) +END create; + + +PROCEDURE select (body: XML.ELEMENT; VAR pos: TPos; VAR curpos, strong, italic, code: INTEGER); +VAR + cur : XML.ELEMENT; + word : XML.WORD; + space : XML.SPACE; + + tag_value, len, wbeg, wend, selbeg, selend, + a, b, z, x, w: INTEGER; + + + PROCEDURE New (RectList: LISTS.LIST; x1, y1, x2, y2: INTEGER); + VAR rect: TRect; + BEGIN + NEW(rect); + rect.x1 := x1; rect.y1 := y1; + rect.x2 := x2; rect.y2 := y2; + LISTS.push(RectList, rect) + END New; + + +BEGIN + cur := body; + WHILE (cur # NIL) & (pos # NIL) DO + selbeg := pos.first; + selend := pos.last; + IF cur IS XML.TAG THEN + tag_value := cur(XML.TAG).value; + + CASE tag_value OF + |XML.tag_title, XML.tag_strong, XML.tag_th: + INC(strong); + Font.Bold(TRUE) + |XML.tag_epigraph, XML.tag_cite, XML.tag_emphasis: + INC(italic); + Font.Italic(TRUE, FALSE) + |XML.tag_code: + Font.sysfont(TRUE); + INC(code) + ELSE + END; + + select(cur(XML.TAG).child.first, pos, curpos, strong, italic, code); + + CASE tag_value OF + |XML.tag_title, XML.tag_strong, XML.tag_th, XML.tag_text_author, XML.tag_date: + DEC(strong); + Font.Bold(strong > 0) + |XML.tag_epigraph, XML.tag_cite, XML.tag_emphasis: + DEC(italic); + Font.Italic(italic > 0, FALSE) + |XML.tag_code: + DEC(code); + Font.sysfont(code > 0) + ELSE + END; + + IF pos # NIL THEN + selbeg := pos.first; + selend := pos.last + END + ELSIF cur IS XML.WORD THEN + word := cur(XML.WORD); + len := word.value.last - word.value.first + 1; + wbeg := curpos; + wend := curpos + len - 1; + INC(curpos, len); + + a := MAX(wbeg, selbeg); + b := MIN(wend, selend); + + IF b >= a THEN + x := word.width; + IF (a = wbeg) & (b = wend) THEN + New(pos.RectList, word.X, word.Y, word.X + word.width, word.Y + Font.FontH()); + ELSIF (a = selbeg) & (b = wend) THEN + z := selbeg - wbeg; + INC(word.value.first, z); + word.width := Font.TextWidth(word.value, S.Utf8Length(word.value)); + INC(word.X, x - word.width); + New(pos.RectList, word.X, word.Y, word.X + word.width, word.Y + Font.FontH()); + DEC(word.value.first, z); + DEC(word.X, x - word.width) + ELSIF (a = wbeg) & (b = selend) THEN + z := wend - selend; + DEC(word.value.last, z); + word.width := Font.TextWidth(word.value, S.Utf8Length(word.value)); + New(pos.RectList, word.X, word.Y, word.X + word.width, word.Y + Font.FontH()); + INC(word.value.last, z) + ELSIF (a = selbeg) & (b = selend) THEN + z := selbeg - wbeg; + w := wend - selend; + INC(word.value.first, z); + INC(word.X, x - Font.TextWidth(word.value, S.Utf8Length(word.value))); + DEC(word.value.last, w); + word.width := Font.TextWidth(word.value, S.Utf8Length(word.value)); + New(pos.RectList, word.X, word.Y, word.X + word.width, word.Y + Font.FontH()); + INC(word.value.last, w); + DEC(word.X, x - Font.TextWidth(word.value, S.Utf8Length(word.value))); + DEC(word.value.first, z) + END; + word.width := x + END + ELSIF cur IS XML.SPACE THEN + IF (selbeg <= curpos) & (curpos <= selend) THEN + space := cur(XML.SPACE); + New(pos.RectList, space.X, space.Y, space.X + space.width, space.Y + Font.FontH()) + END; + len := 1; + INC(curpos) + END; + IF curpos > selend THEN + IF pos # NIL THEN + pos := pos.next(TPos); + END; + IF cur IS XML.TEXT THEN + DEC(curpos, len) + ELSE (* tag *) + cur := cur.next + END + ELSE + cur := cur.next + END + END +END select; + + +PROCEDURE streq (s1, s2, n: INTEGER): BOOLEAN; +VAR + c1, c2: CHAR; + +BEGIN + REPEAT + SYSTEM.GET(s1, c1); INC(s1); + SYSTEM.GET(s2, c2); INC(s2); + DEC(n) + UNTIL (n = 0) OR (c1 # c2) + + RETURN c1 = c2 +END streq; + + +PROCEDURE destroy (VAR item: LISTS.ITEM); +BEGIN + LISTS.destroy(item(TPos).RectList); + DISPOSE(item) +END destroy; + + +PROCEDURE find (body: XML.TAG; str: STRING); +VAR + c: CHAR; + offs, i, pos, strong, italic, code: INTEGER; + posItem: TPos; + text: Text; + pstr, slen: INTEGER; + idx: TextIdx; + +BEGIN + text := body.text(Text); + text.found := 0; + LISTS.destroy(text.PosList); + text.PosList := LISTS.create(NIL); + + text.str0 := str; + UpCase(SYSTEM.ADR(str[0]), SYSTEM.ADR(text.str1[0]), LENGTH(str)); + + IF text.case THEN + idx := text.idx0; + pstr := SYSTEM.ADR(text.str0[0]) + ELSE + idx := text.idx1; + pstr := SYSTEM.ADR(text.str1[0]) + END; + + slen := LENGTH(str); + + SYSTEM.GET(pstr, c); + offs := idx.offs[ORD(c)]; + i := idx.cnt[ORD(c)]; + WHILE i > 0 DO + SYSTEM.GET(idx.table + offs, pos); + INC(offs, 4); + IF (pos + slen <= idx.size) & streq(pstr, idx.data + pos, slen) THEN + NEW(posItem); + posItem.n := text.found; + posItem.first := pos; + posItem.last := pos + slen - 1; + posItem.RectList := LISTS.create(NIL); + posItem.destroy := destroy; + LISTS.push(text.PosList, posItem); + INC(text.found) + END; + DEC(i) + END; + posItem := text.PosList.first(TPos); + pos := 0; strong := 0; italic := 0; code := 0; + select(body.child.first, posItem, pos, strong, italic, code); + text.curPos := NIL +END find; + + +PROCEDURE ffirst (body: XML.TAG); +VAR + text: Text; + +BEGIN + text := body.text(Text); + IF text.str0 # "" THEN + find(body, text.str0); + text.curPos := text.PosList.first(TPos) + END +END ffirst; + + +PROCEDURE found* (body: XML.TAG): BOOLEAN; + RETURN (body # NIL) & (body.text # NIL) & (body.text(Text).found # 0) +END found; + + +PROCEDURE fnext* (body: XML.TAG; VAR y: INTEGER; d: INTEGER); +VAR + text: Text; + rect: TRect; + cur: LISTS.ITEM; + +BEGIN + text := body.text(Text); + IF (text # NIL) & (text.found # 0) THEN + cur := text.curPos; + CASE d OF + |1: + IF cur.next # NIL THEN + cur := cur.next + ELSE + cur := text.PosList.first + END + + |-1: + IF cur.prev # NIL THEN + cur := cur.prev + ELSE + cur := text.PosList.last + END + + |0: + cur := text.PosList.first + + END; + text.curPos := cur(TPos); + rect := text.curPos.RectList.first(TRect); + IF rect # NIL THEN + y := rect.y1 + END + ELSE + y := -1 + END +END fnext; + + +PROCEDURE open* (_find: PFind); +BEGIN + Find := _find; + SearchForm.open +END open; + + +PROCEDURE close*; +VAR + text: Text; + body: XML.TAG; + +BEGIN + body := Body; + text := body.text(Text); + IF text # NIL THEN + LISTS.destroy(text.PosList); + text.PosList := LISTS.create(NIL); + text.found := 0; + text.curPos := NIL + END +END close; + + +PROCEDURE resize*; +VAR + n: INTEGER; + text: Text; + item: LISTS.ITEM; + +BEGIN + text := TextList.first(Text); + WHILE text # NIL DO + IF text.found # 0 THEN + n := text.curPos.n; + find(text.body, text.str0); + item := LISTS.get(text.PosList, n); + text.curPos := item(TPos) + END; + text := text.next(Text) + END +END resize; + + +PROCEDURE callback (case: BOOLEAN; str: STRING): BOOLEAN; +VAR + body: XML.TAG; + +BEGIN + body := Body; + IF body.text = NIL THEN + create(body) + END; + body.text(Text).case := case; + body.text(Text).str0 := str; + ffirst(body); + Find(0) + + RETURN body.text(Text).found # 0 +END callback; + + +BEGIN + TextList := LISTS.create(NIL); + SearchForm.init(callback) +END Search. \ No newline at end of file diff --git a/programs/other/fb2reader/SRC/SearchForm.ob07 b/programs/other/fb2reader/SRC/SearchForm.ob07 new file mode 100644 index 0000000000..ddafaa2212 --- /dev/null +++ b/programs/other/fb2reader/SRC/SearchForm.ob07 @@ -0,0 +1,199 @@ +(* + Copyright 2020-2021 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE SearchForm; + +IMPORT + + SYSTEM, SU := SysUtils, W := Window, box_lib, K := KOSAPI, Encode, S := Strings; + + +CONST + + BTN_CLOSE = 1; + BTN_FIND = 19; + BTN_CANCEL = 20; + + BtnH = 25; + BtnW = 80; + + WINDOW_BEVEL = 4; + + MAXCHARS = 2000; + + +TYPE + + STRING* = ARRAY MAXCHARS OF CHAR; + + PROC = PROCEDURE (case: BOOLEAN; str: STRING): BOOLEAN; + + +VAR + + PID, Slot: INTEGER; + Stack: ARRAY 1000000 OF CHAR; + Window: W.TWindow; + str: STRING; + + callback: PROC; + case: box_lib.checkbox; + text: box_lib.edit_box; + + +PROCEDURE DrawText (x, y: INTEGER; text: ARRAY OF CHAR); +VAR + L: INTEGER; +BEGIN + L := LENGTH(text); + SU.Box(x, y, L*SU.FontW, SU.FontH, SU.winColor, SU.winColor); + SU.OutText(x, y, text, L, SU.textColor) +END DrawText; + + +PROCEDURE buttons; +BEGIN + SU.CreateButton(BTN_FIND, 5, 80, BtnW, BtnH, SU.btnColor, "find"); + SU.CreateButton(BTN_CANCEL, 5 - BtnW + text.width, 80, BtnW, BtnH, SU.btnColor, "cancel"); + box_lib.check_box_draw2(case); DrawText(25, 50, "match case"); + box_lib.edit_box_draw(text) +END buttons; + + +PROCEDURE DrawWindow; +BEGIN + SU.GetSystemColors; + SU.WindowRedrawStatus(1); + SU.DefineAndDrawWindow(Window.Left, Window.Top, Window.Width, Window.Height, + SU.winColor, LSL(ORD({0, 1}), 4) + 4, Window.Caption); + buttons; + SU.WindowRedrawStatus(2) +END DrawWindow; + + +PROCEDURE close* (ok: BOOLEAN); +VAR + pid, i, j, k, n: INTEGER; + found: BOOLEAN; + str0: STRING; + u: S.UTF8; + +BEGIN + found := TRUE; + box_lib.edit_box_get_value(text, str); + + IF ok THEN + IF str # "" THEN + j := 0; + i := 0; + WHILE str[i] # 0X DO + u := Encode.CP866[ORD(str[i])].utf8; + n := Encode.CP866[ORD(str[i])].len; + FOR k := 0 TO n - 1 DO + str0[j] := u[k]; + INC(j) + END; + INC(i) + END; + found := callback(box_lib.check_box_get_value(case), str0) + ELSE + found := FALSE + END + END; + + IF found THEN + pid := PID; + PID := 0; + IF pid # 0 THEN + SU.TerminateThreadId(pid) + END + ELSE + IF str # "" THEN + DrawText(5 + BtnW + 10, 80 + 4, "not found") + END + END +END close; + + +PROCEDURE ButtonClick; +BEGIN + CASE SU.GetButtonCode() OF + |0 : + |BTN_CLOSE, BTN_CANCEL : close(FALSE) + |BTN_FIND : close(TRUE) + END; + buttons +END ButtonClick; + + +PROCEDURE show; +VAR + scrWidth, scrHeight, key: INTEGER; + +BEGIN + SU.SetEventsMask({0, 1, 2, 5, 30, 31}); + W.InitWindow(Window, 0, 0, 320, 140, "Search"); + SU.GetScreenSize(scrWidth, scrHeight); + Window.Left := (scrWidth - Window.Width) DIV 2; + Window.Top := (scrHeight - Window.Height) DIV 2; + + DrawWindow; + WHILE TRUE DO + CASE SU.WaitForEvent() OF + |1: DrawWindow + |2: key := K.sysfunc1(2); + IF key DIV 65536 = 28 THEN + close(TRUE) + ELSIF key DIV 65536 = 1 THEN + close(FALSE) + ELSE + box_lib.edit_box_key_safe(text, key) + END + |3: ButtonClick + |6: + box_lib.check_box_mouse2(case); + box_lib.edit_box_mouse(text) + ELSE + END + END +END show; + + +PROCEDURE open*; +BEGIN + IF PID = 0 THEN + PID := SU.NewThread(show, Stack); + Slot := SU.GetThreadSlot(PID) + ELSE + SU.FocusWindow(Slot) + END +END open; + + +PROCEDURE init* (proc: PROC); +BEGIN + callback := proc; + PID := 0; + case := box_lib.kolibri_new_check_box(5, 50, 16, 16, SYSTEM.SADR(""), 14 * 8 + 5); + text := box_lib.kolibri_new_edit_box(5, 10, 300, MAXCHARS DIV 3); + text.flags := 4002H; +END init; + + +END SearchForm. \ No newline at end of file diff --git a/programs/other/fb2reader/SRC/SelEnc.ob07 b/programs/other/fb2reader/SRC/SelEnc.ob07 new file mode 100644 index 0000000000..6f0d8377f6 --- /dev/null +++ b/programs/other/fb2reader/SRC/SelEnc.ob07 @@ -0,0 +1,163 @@ +(* + Copyright 2016, 2018, 2020-2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE SelEnc; + +IMPORT + + SU := SysUtils, W := Window, OpenDlg, S := Strings, TXT := Txt2FB2, SYSTEM, K := KOSAPI, Settings, File; + + +CONST + + BtnH = 30; + BtnW = 150; + BtnX = 5; + BtnY = 10; + BtnInter = 10; + + tempfile* = "/tmp0/1/~temp.fb2"; + + +VAR + + Window : W.TWindow; + ENCODING* : INTEGER; + FileName : S.STRING; + + +PROCEDURE Buttons; +VAR + Y : INTEGER; + +BEGIN + Y := BtnY; + SU.CreateButton(TXT.AUTO, BtnX, Y, BtnW, BtnH, SU.btnColor, "AUTO" ); INC(Y, BtnH + BtnInter); + SU.CreateButton(TXT.CP866, BtnX, Y, BtnW, BtnH, SU.btnColor, "CP-866" ); INC(Y, BtnH + BtnInter); + SU.CreateButton(TXT.CP1251, BtnX, Y, BtnW, BtnH, SU.btnColor, "CP-1251"); INC(Y, BtnH + BtnInter); + SU.CreateButton(TXT.CP1252, BtnX, Y, BtnW, BtnH, SU.btnColor, "CP-1252"); INC(Y, BtnH + BtnInter); + SU.CreateButton(TXT.CP1250, BtnX, Y, BtnW, BtnH, SU.btnColor, "CP-1250"); INC(Y, BtnH + BtnInter); + SU.CreateButton(TXT.UTF8, BtnX, Y, BtnW, BtnH, SU.btnColor, "UTF-8" ) +END Buttons; + + +PROCEDURE DrawWindow; +BEGIN + SU.GetSystemColors; + SU.WindowRedrawStatus(1); + SU.DefineAndDrawWindow(Window.Left, Window.Top, Window.Width, Window.Height, + SU.winColor, LSL(ORD({0, 1}), 4) + 4, Window.Caption); + Buttons; + SU.WindowRedrawStatus(2) +END DrawWindow; + + +PROCEDURE auto (fname: S.STRING): INTEGER; +VAR + enc, data, size, ptr: INTEGER; + + + PROCEDURE SearchPair (ptr, size: INTEGER; chr1, chr2: BYTE): BOOLEAN; + VAR + c, c0: BYTE; + res: BOOLEAN; + + BEGIN + c := 0; + res := FALSE; + WHILE (size > 0) & ~res DO + c0 := c; + SYSTEM.GET(ptr, c); + IF (c = chr2) & (c0 = chr1) THEN + res := TRUE + END; + INC(ptr); + DEC(size) + END + + RETURN res + END SearchPair; + + +BEGIN + data := File.Load(fname, size); + SU.ErrorIf(data = 0, 1); + ptr := data; + + IF SearchPair(ptr, size, 208, 190) THEN + enc := TXT.UTF8 + ELSE + IF SearchPair(ptr, size, 239, 240) OR SearchPair(ptr, size, 241, 242) THEN + enc := TXT.CP1251 + ELSE + enc := TXT.CP866 + END + END; + + data := K.free(data) + + RETURN enc +END auto; + + +PROCEDURE ButtonClick; +VAR + btn_code: INTEGER; + program, file: S.STRING; + +BEGIN + btn_code := SU.GetButtonCode(); + IF btn_code = TXT.AUTO THEN + ENCODING := auto(FileName) + ELSE + ENCODING := btn_code + END; + TXT.convert(FileName, tempfile, ENCODING); + S.PtrToString(K.GetName(), program); + file := tempfile; + file[0] := "!"; + SU.Run(program, SYSTEM.ADR(file)); + SU.Halt +END ButtonClick; + + +PROCEDURE Show*(FName: S.STRING); +VAR + X1, Y1, X2, Y2: INTEGER; + +BEGIN + FileName := FName; + SU.SetEventsMask({0, 2, 31}); + SU.GetScreenArea(X1, Y1, X2, Y2); + W.InitWindow(Window, 0, 0, BtnX * 2 + BtnW + 10, (BtnH + BtnInter) * 6 + BtnY * 2 + SU.SkinHeight() - 5, "Encoding"); + Window.Left := (X2 - X1 - Window.Width) DIV 2; + Window.Top := (Y2 - Y1 - Window.Height) DIV 2; + DrawWindow; + WHILE TRUE DO + CASE SU.WaitForEvent() OF + |1 : DrawWindow + |3 : ButtonClick + END + END +END Show; + + +BEGIN + ENCODING := 0 +END SelEnc. \ No newline at end of file diff --git a/programs/other/fb2reader/SRC/Settings.ob07 b/programs/other/fb2reader/SRC/Settings.ob07 new file mode 100644 index 0000000000..57a0c567e2 --- /dev/null +++ b/programs/other/fb2reader/SRC/Settings.ob07 @@ -0,0 +1,420 @@ +(* + Copyright 2016, 2018, 2020-2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Settings; + +IMPORT SU := SysUtils, W := Window, C := ColorDlg, DOM, S := Strings, + Font, KF := kfonts, OD := OpenDlg, LibImg, G := Graph, Ini, box_lib, sys := SYSTEM; + + +CONST + + DAY = 19; + NIGHT = 20; + APPLY = 21; + CANCEL = 22; + BACK_PICTURE = 23; + + C100 = 100; + + CHANGE_BACK_COLOR = DOM.BACK_COLOR + C100; + CHANGE_TEXT_COLOR = DOM.TEXT_COLOR + C100; + CHANGE_ITALIC_COLOR = DOM.ITALIC_COLOR + C100; + CHANGE_LINK_COLOR = DOM.LINK_COLOR + C100; + CHANGE_VISITED_COLOR = DOM.VISITED_COLOR + C100; + + MAX_LRpc = 25; + MAX_Top = 120; + MAX_PARAGRAPH = 120; + MAX_EPIGRAPH = 120; + MAX_CInt = 25; + MAX_InterLin = 50; + MAX_FONT_SIZE = 40; + MIN_FONT_SIZE = 10; + + BtnH* = 25; + BoxW = 50; + TextLeft = 20; + BtnW* = 80; + + +VAR + + Window : W.TWindow; + PID : INTEGER; + Slot : INTEGER; + Color : C.Dialog; + Data : DOM.TSettings; + + String : S.STRING; + + sb : ARRAY 7 OF box_lib.scrollbar; + check1 : box_lib.checkbox; + check2 : box_lib.checkbox; + OpenPict : OD.Dialog; + picture : INTEGER; + + picture_path : S.STRING; + + +PROCEDURE Close*; +VAR pid: INTEGER; +BEGIN + IF PID # 0 THEN + pid := PID; + PID := 0; + IF (picture # 0) & (picture # Data.Picture) THEN + LibImg.img_destroy(picture) + END; + C.Destroy(Color); + OD.Destroy(OpenPict); + SU.TerminateThreadId(pid) + END +END Close; + + +PROCEDURE ClearWindow; +BEGIN + SU.Box(0, 0, Window.Width - 10, Window.Height - SU.SkinHeight() - 5, SU.winColor, SU.winColor) +END ClearWindow; + + +PROCEDURE OutText (x, y: INTEGER; text: ARRAY OF CHAR); +BEGIN + SU.OutText(x, y, text, LENGTH(text), SU.textColor) +END OutText; + + +PROCEDURE PlusMinus(x, y, max, min: INTEGER; _sb: box_lib.scrollbar); +VAR range, Y: INTEGER; + sysfont: ARRAY 20 OF CHAR; +BEGIN + sysfont := "System font only"; + S.IntToString(_sb.position + min, String); + IF _sb = sb[0] THEN + Y := y - (BtnH + 10) * 2 + 26; + SU.Box(TextLeft + 230, Y, SU.FontW * LENGTH(sysfont), SU.FontH, SU.winColor, SU.winColor); + IF ~KF.Enabled(Font.KFont, _sb.position + min) THEN + OutText(TextLeft + 230, Y, sysfont) + END + END; + SU.Box(x + 25, y + 6, SU.FontW * 4, SU.FontH, SU.winColor, SU.winColor); + OutText(x + 25 + (35 - SU.FontW * LENGTH(String)) DIV 2, y + 6, String); + x := x + 60 - 25; + range := max - min; + _sb := box_lib.kolibri_scrollbar(_sb, (x + 30) * 65536 + 196, y * 65536 + 22 + 2, 22, range + range DIV 10, range DIV 10, + _sb.position, SU.lightColor, SU.btnColor, 0, 2) +END PlusMinus; + + +PROCEDURE Buttons; + +VAR + + X, Y, TextY : INTEGER; + WinW, WinH, SkinH : INTEGER; + i : INTEGER; + Rect : W.TRect; + +BEGIN + Rect.Left := 10; + Rect.Top := 85; + Rect.Width := 210; + Rect.Height := 255; + SU.Box(Rect.Left, Rect.Top, Rect.Width, Rect.Height, SU.winColor, SU.borderColor); + SU.Box(Rect.Left + 230, Rect.Top, Rect.Width + 170, Rect.Height, SU.winColor, SU.borderColor); + + WinW := Window.Width; + WinH := Window.Height; + SkinH := SU.SkinHeight(); + X := 125; + Y := 10; + IF picture = 0 THEN + OutText(TextLeft + 20, Y + 6, "back picture (none)") + ELSE + OutText(TextLeft + 20, Y + 6, "back picture") + END; + SU.CreateButton(BACK_PICTURE, X + 75, Y, 30, BtnH, SU.btnColor, "..."); + + Y := 10 + (BtnH + 10); + + OutText(TextLeft + 20, Y + 6, "two columns"); + + Y := Y + (BtnH + 10) * 2 - 20; + + TextY := Y; + FOR i := 0 TO 4 DO + SU.Box(X, Y, BoxW, BtnH, Data.Colors[i], 0); + SU.CreateButton(i + C100, X + BoxW + 5, Y, 30, BtnH, SU.btnColor, "..."); + Y := Y + BtnH + 10; + END; + + X := 20; Y := TextY + 6; + + OutText(TextLeft, Y, "back"); OutText(TextLeft + 230, Y, "font size"); PlusMinus(TextLeft + 330, Y - 6, MAX_FONT_SIZE, MIN_FONT_SIZE, sb[0]); Y := Y + BtnH + 10; + OutText(TextLeft, Y, "text"); OutText(TextLeft + 230, Y, "left & right %"); PlusMinus(TextLeft + 330, Y - 6, MAX_LRpc, 0, sb[1]); Y := Y + BtnH + 10; + OutText(TextLeft, Y, "italic"); OutText(TextLeft + 230, Y, "col. spacing %"); PlusMinus(TextLeft + 330, Y - 6, MAX_CInt, 0, sb[2]); Y := Y + BtnH + 10; + OutText(TextLeft, Y, "link"); OutText(TextLeft + 230, Y, "top & bottom"); PlusMinus(TextLeft + 330, Y - 6, MAX_Top, 0, sb[3]); Y := Y + BtnH + 10; + OutText(TextLeft, Y, "visited"); OutText(TextLeft + 230, Y, "paragraph"); PlusMinus(TextLeft + 330, Y - 6, MAX_PARAGRAPH, 0, sb[4]); Y := Y + BtnH + 10; + + OutText(TextLeft + 230, Y, "epigraph"); PlusMinus(TextLeft + 330, Y - 6, MAX_EPIGRAPH, 0, sb[5]); Y := Y + BtnH + 10; + OutText(TextLeft + 230, Y, "line spacing"); PlusMinus(TextLeft + 330, Y - 6, MAX_InterLin, 0, sb[6]); + + Y := Y - 6; + + SU.CreateButton(DAY, (Rect.Width - (BtnW + 5 + BtnW)) DIV 2 + Rect.Left, Y, 80, BtnH, SU.btnColor, "Day" ); + SU.CreateButton(NIGHT, (Rect.Width - (BtnW + 5 + BtnW)) DIV 2 + Rect.Left + 5 + BtnW, Y, 80, BtnH, SU.btnColor, "Night" ); + + SU.CreateButton(APPLY, (WinW - (BtnW + 5 + BtnW) - 10) DIV 2, WinH - BtnH - SkinH - 10, 80, BtnH, SU.btnColor, "Apply" ); + SU.CreateButton(CANCEL, (WinW - (BtnW + 5 + BtnW) - 10) DIV 2 + 5 + BtnW, WinH - BtnH - SkinH - 10, 80, BtnH, SU.btnColor, "Cancel"); + + FOR i := 0 TO LEN(sb) - 1 DO + box_lib.scrollbar_h_draw(sb[i]) + END; + box_lib.check_box_draw2(check1); + box_lib.check_box_draw2(check2); + +END Buttons; + + +PROCEDURE DrawWindow; +BEGIN + SU.GetSystemColors; + SU.WindowRedrawStatus(1); + SU.DefineAndDrawWindow(Window.Left, Window.Top, Window.Width, Window.Height, + SU.winColor, LSL(ORD({0, 1}), 4) + 4, Window.Caption); + Buttons; + SU.WindowRedrawStatus(2) +END DrawWindow; + + +PROCEDURE SelColor(Color: C.Dialog; Default: INTEGER): INTEGER; +VAR Result: INTEGER; +BEGIN + Result := Default; + IF Color # NIL THEN + C.Show(Color); + WHILE Color.status = 2 DO + SU.Pause(20) + END; + IF Color.status = 1 THEN + Result := Color.color + END + END + RETURN Result +END SelColor; + + +PROCEDURE ChangeColor(idx: INTEGER); +BEGIN + Data.Colors[idx] := SelColor(Color, Data.Colors[idx]) +END ChangeColor; + + +PROCEDURE Day; +BEGIN + Data.Colors[DOM.BACK_COLOR] := 0F0F0C7H; + Data.Colors[DOM.TEXT_COLOR] := 0000000H; + Data.Colors[DOM.ITALIC_COLOR] := 0505050H; + Data.Colors[DOM.LINK_COLOR] := 00000FFH; + Data.Colors[DOM.VISITED_COLOR] := 0800080H; + Data.Colors[DOM.CLICKED_COLOR] := 0FF0000H; +END Day; + + +PROCEDURE Night; +BEGIN + Data.Colors[DOM.BACK_COLOR] := 0000000H; + Data.Colors[DOM.TEXT_COLOR] := 0AFAFAFH; + Data.Colors[DOM.ITALIC_COLOR] := 07F7F7FH; + Data.Colors[DOM.LINK_COLOR] := 000A0D0H; + Data.Colors[DOM.VISITED_COLOR] := 0C000C0H; + Data.Colors[DOM.CLICKED_COLOR] := 0FF0000H; +END Night; + + +PROCEDURE Apply; +BEGIN + Data.FontSize := sb[0].position + MIN_FONT_SIZE; + Data.PADDING.LRpc := sb[1].position; + Data.PADDING.CInt := sb[2].position; + Data.PADDING.Top := sb[3].position; + Data.PARAGRAPH := sb[4].position; + Data.EPIGRAPH := sb[5].position; + Data.InterLin := sb[6].position; + IF Data.Picture # picture THEN + IF Data.Picture # 0 THEN + LibImg.img_destroy(Data.Picture) + END; + Data.Picture := picture; + Ini.SetPicturePath(picture_path) + END; + picture := 0; + DOM.SetSettings(Data); + Close +END Apply; + + +PROCEDURE LoadPicture(file_path: S.STRING); +VAR ysize, img: INTEGER; +BEGIN + img := LibImg.LoadFromFile(file_path, 10240000, ysize); + IF img # 0 THEN + IF (picture # 0) & (picture # Data.Picture) THEN + LibImg.img_destroy(picture) + END; + picture := img; + picture_path := file_path + END +END LoadPicture; + + +PROCEDURE OpenPicture; +BEGIN + IF OpenPict # NIL THEN + OD.Show(OpenPict, 500, 400); + WHILE OpenPict.status = 2 DO + SU.Pause(30) + END; + IF OpenPict.status = 1 THEN + COPY(OpenPict.FilePath, picture_path); + LoadPicture(picture_path) + END + END +END OpenPicture; + + +PROCEDURE ButtonClick; +BEGIN + CASE SU.GetButtonCode() OF + |0 : + |1 : Close + |BACK_PICTURE : OpenPicture + |DAY : Day + |NIGHT : Night + |APPLY : Apply + |CANCEL : Close + + |CHANGE_BACK_COLOR : ChangeColor(DOM.BACK_COLOR) + |CHANGE_TEXT_COLOR : ChangeColor(DOM.TEXT_COLOR) + |CHANGE_ITALIC_COLOR : ChangeColor(DOM.ITALIC_COLOR) + |CHANGE_LINK_COLOR : ChangeColor(DOM.LINK_COLOR) + |CHANGE_VISITED_COLOR : ChangeColor(DOM.VISITED_COLOR) + + END; + ClearWindow; + Buttons +END ButtonClick; + + +PROCEDURE Default*; +BEGIN + Day; + Data.FontSize := 16; + Data.TwoCol := FALSE; + Data.PADDING.Top := 15; + Data.PADDING.LRpc := 3; + Data.PADDING.CInt := 6; + Data.PARAGRAPH := 30; + Data.EPIGRAPH := 100; + Data.InterLin := 0; + Data.Picture := picture; + DOM.SetSettings(Data) +END Default; + + +PROCEDURE Show; +VAR i, scrWidth, scrHeight: INTEGER; +BEGIN + SU.SetEventsMask({0, 2, 5, 30, 31}); + W.InitWindow(Window, 0, 0, 640, 420, "Settings"); + SU.GetScreenSize(scrWidth, scrHeight); + Window.Left := (scrWidth - Window.Width) DIV 2; + Window.Top := (scrHeight - Window.Height) DIV 2; + Color := C.Create(DrawWindow); + OpenPict := OD.Create(DrawWindow, 0, "/sys", "JPG|PNG|BMP|GIF"); + Data := DOM.Settings; + picture := Data.Picture; + DrawWindow; + WHILE TRUE DO + CASE SU.WaitForEvent() OF + |1 : DrawWindow + |3 : ButtonClick + |6 : FOR i := 0 TO LEN(sb) - 1 DO + box_lib.scrollbar_h_mouse(sb[i]) + END; + box_lib.check_box_mouse2(check1); + box_lib.check_box_mouse2(check2); + PlusMinus(TextLeft + 330, sb[0].y_h DIV 65536, MAX_FONT_SIZE, MIN_FONT_SIZE, sb[0]); + PlusMinus(TextLeft + 330, sb[1].y_h DIV 65536, MAX_LRpc, 0, sb[1]); + PlusMinus(TextLeft + 330, sb[2].y_h DIV 65536, MAX_CInt, 0, sb[2]); + PlusMinus(TextLeft + 330, sb[3].y_h DIV 65536, MAX_Top, 0, sb[3]); + PlusMinus(TextLeft + 330, sb[4].y_h DIV 65536, MAX_PARAGRAPH, 0, sb[4]); + PlusMinus(TextLeft + 330, sb[5].y_h DIV 65536, MAX_EPIGRAPH, 0, sb[5]); + PlusMinus(TextLeft + 330, sb[6].y_h DIV 65536, MAX_InterLin, 0, sb[6]); + Data.TwoCol := box_lib.check_box_get_value(check1); + Data.b_pict := box_lib.check_box_get_value(check2); + END + END +END Show; + + +PROCEDURE Open*; +BEGIN + IF PID = 0 THEN + Data := DOM.Settings; + box_lib.check_box_set_value(check1, Data.TwoCol); + box_lib.check_box_set_value(check2, Data.b_pict); + PID := SU.NewThread(Show, DOM.Stack); + Slot := SU.GetThreadSlot(PID); + sb[0].position := Data.FontSize - MIN_FONT_SIZE; + sb[1].position := Data.PADDING.LRpc; + sb[2].position := Data.PADDING.CInt; + sb[3].position := Data.PADDING.Top; + sb[4].position := Data.PARAGRAPH; + sb[5].position := Data.EPIGRAPH; + sb[6].position := Data.InterLin; + ELSE + SU.FocusWindow(Slot) + END +END Open; + + +PROCEDURE main; +VAR i: INTEGER; + bpicture, twocol: ARRAY 20 OF CHAR; +BEGIN + PID := 0; + FOR i := 0 TO LEN(sb) - 1 DO + sb[i] := box_lib.kolibri_new_scrollbar(10 * 65536 + 200, 10 * 65536 + 22 + 2, 22, 15, 10, 0, 0, 0, 0, 2) + END; + bpicture := "back picture"; + twocol := "two columns"; + check2 := box_lib.kolibri_new_check_box(TextLeft, 10 + 5, 16, 16, sys.SADR(""), LENGTH(bpicture) * 8 + 5); + check1 := box_lib.kolibri_new_check_box(TextLeft, 10 + (BtnH + 10) + 5, 16, 16, sys.SADR(""), LENGTH(twocol) * 8 + 5); + picture := 0; + IF Ini.Picture # "" THEN + LoadPicture(Ini.Picture) + END +END main; + + +BEGIN + main +END Settings. diff --git a/programs/other/fb2reader/SRC/Strings.ob07 b/programs/other/fb2reader/SRC/Strings.ob07 new file mode 100644 index 0000000000..e42437a7f6 --- /dev/null +++ b/programs/other/fb2reader/SRC/Strings.ob07 @@ -0,0 +1,414 @@ +(* + Copyright 2016, 2019, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Strings; + +IMPORT sys := SYSTEM, KOSAPI; + + +TYPE + + STRING* = ARRAY 1024 OF CHAR; + + UTF8* = ARRAY 8 OF CHAR; + + CHARS* = RECORD first*, last* : INTEGER END; + + +VAR + + CS: BOOLEAN; + + +PROCEDURE [ccall, "base64.obj", ""] base64_decode (inp, outp: INTEGER; Len: INTEGER): INTEGER; END; +PROCEDURE [stdcall, "rasterworks.obj", ""] countUTF8Z (string, byteQuantity: INTEGER): INTEGER; END; + +PROCEDURE DelLeft(VAR s: STRING; count: INTEGER); +VAR i, max: INTEGER; +BEGIN + max := LENGTH(s) - count - 1; + IF max >= 0 THEN + FOR i := 0 TO max DO + s[i] := s[i + count] + END + END +END DelLeft; + + +PROCEDURE Trim*(VAR s: STRING; ch: CHAR); +VAR i, n: INTEGER; +BEGIN + i := 0; + WHILE s[i] = ch DO + INC(i) + END; + DelLeft(s, i); + n := LENGTH(s) - 1; + IF n >= 0 THEN + i := n; + WHILE s[i] = ch DO + DEC(i) + END; + IF n # i THEN + s[i + 1] := 0X + END + END +END Trim; + + +PROCEDURE GetChar*(chars: CHARS; i: INTEGER): CHAR; +VAR c: CHAR; +BEGIN + ASSERT(chars.first + i <= chars.last); + sys.GET(chars.first + i, c) + RETURN c +END GetChar; + + +PROCEDURE Reverse*(VAR s: ARRAY OF CHAR); +VAR i, j: INTEGER; c: CHAR; +BEGIN + i := 0; + j := LENGTH(s) - 1; + WHILE i < j DO + c := s[i]; + s[i] := s[j]; + s[j] := c; + INC(i); + DEC(j) + END +END Reverse; + + +PROCEDURE IntToString*(x: INTEGER; VAR s: STRING); +VAR n, i: INTEGER; +BEGIN + i := 0; + REPEAT + n := x MOD 10; + x := x DIV 10; + s[i] := CHR(ORD("0") + n); + INC(i) + UNTIL x = 0; + s[i] := 0X; + Reverse(s) +END IntToString; + + +PROCEDURE isdigit(c: CHAR): BOOLEAN; + RETURN ("0" <= c) & (c <= "9") +END isdigit; + + +PROCEDURE CharsToInt*(s: CHARS; VAR err: BOOLEAN): INTEGER; +VAR n, i, res, len: INTEGER; c: CHAR; +BEGIN + res := 0; + len := s.last - s.first + 1; + err := len <= 0; + FOR i := 0 TO s.last - s.first DO + c := GetChar(s, i); + IF isdigit(c) THEN + n := ORD(c) - ORD("0"); + res := res * 10 + n + ELSE + err := TRUE + END + END + RETURN res +END CharsToInt; + + +PROCEDURE Append*(VAR str1: STRING; str2: STRING); +VAR + len1, len2 : INTEGER; + i, j : INTEGER; +BEGIN + len1 := LENGTH(str1); + len2 := LENGTH(str2); + ASSERT(len1 + len2 < LEN(str1)); + j := len1; + FOR i := 0 TO len2 - 1 DO + str1[j] := str2[i]; + INC(j) + END; + str1[j] := 0X +END Append; + + +PROCEDURE GetPath*(VAR S: STRING); +VAR i, j: INTEGER; +BEGIN + j := 0; + i := LENGTH(S) - 1; + WHILE i >= 0 DO + IF S[i] = "/" THEN + j := i; + i := 0 + END; + DEC(i) + END; + S[j] := 0X +END GetPath; + + +PROCEDURE PutChar*(chars: CHARS; i: INTEGER; c: CHAR); +BEGIN + ASSERT(chars.first + i <= chars.last); + sys.PUT(chars.first + i, c) +END PutChar; + + +PROCEDURE StrToChars*(str: ARRAY OF CHAR; VAR chars: CHARS); +BEGIN + ASSERT(str # ""); + chars.first := sys.ADR(str[0]); + chars.last := sys.ADR(str[LENGTH(str) - 1]) +END StrToChars; + + +PROCEDURE PtrToString*(ptr: INTEGER; VAR S: STRING); +VAR i: INTEGER; c: CHAR; +BEGIN + i := 0; + REPEAT + sys.GET(ptr, c); + S[i] := c; + INC(i); + INC(ptr) + UNTIL (c = 0X) OR (i = LEN(S)); + S[i - 1] := 0X +END PtrToString; + + +PROCEDURE CharsEq*(chars1, chars2: CHARS): BOOLEAN; +VAR + pos, len2 : INTEGER; + c1, c2 : CHAR; + Result : BOOLEAN; + + PROCEDURE CAP(VAR c: CHAR); + BEGIN + IF ~CS & ("a" <= c) & (c <= "z") THEN + c := CHR(ORD(c) - 32) + END + END CAP; + +BEGIN + pos := chars1.last - chars1.first; + len2 := chars2.last - chars2.first; + IF pos = len2 THEN + REPEAT + c1 := GetChar(chars1, pos); + c2 := GetChar(chars2, pos); + CAP(c1); + CAP(c2); + DEC(pos) + UNTIL (c1 # c2) OR (pos = -1); + Result := c1 = c2 + ELSE + Result := FALSE + END + RETURN Result +END CharsEq; + + +PROCEDURE CharsEqStr*(chars: CHARS; str: STRING): BOOLEAN; +VAR + chars2: CHARS; +BEGIN + StrToChars(str, chars2) + RETURN CharsEq(chars, chars2) +END CharsEqStr; + + +PROCEDURE SetCS*(value: BOOLEAN); +BEGIN + CS := value +END SetCS; + + +PROCEDURE Utf8Length*(chars: CHARS): INTEGER; + RETURN countUTF8Z(chars.first, chars.last - chars.first + 1) +END Utf8Length; + + +PROCEDURE Replace*(VAR chars: CHARS; str1, str2: ARRAY OF CHAR); +VAR + temp: CHARS; + s : CHARS; + len1: INTEGER; + len2: INTEGER; + diff: INTEGER; + + PROCEDURE Put(first, last, len1, len2, diff: INTEGER; str2: ARRAY OF CHAR); + VAR i: INTEGER; c: CHAR; + BEGIN + sys.MOVE(sys.ADR(str2[0]), first, len2); + FOR i := first + len1 TO last DO + sys.GET(i, c); + sys.PUT(i - diff, c); + END + END Put; + +BEGIN + len1 := LENGTH(str1); + len2 := LENGTH(str2); + diff := len1 - len2; + ASSERT(diff >= 0); + ASSERT(len1 > 0); + StrToChars(str1, s); + temp := chars; + temp.last := temp.first + len1 - 1; + WHILE temp.last <= chars.last DO + IF CharsEq(temp, s) THEN + Put(temp.first, chars.last, len1, len2, diff, str2); + chars.last := chars.last - diff; + temp.first := temp.first + len2; + temp.last := temp.first + len1 - 1 + ELSE + INC(temp.first); + INC(temp.last) + END + END +END Replace; + + +PROCEDURE utf8*(code: INTEGER; VAR uchar: UTF8); +BEGIN + uchar[0] := 0X; + IF code < 80H THEN + uchar[0] := CHR(code); + uchar[1] := 0X + ELSIF code < 800H THEN + uchar[1] := CHR(ORD(BITS(code) * {0..5}) + 80H); + uchar[0] := CHR(ASR(code, 6) + 0C0H); + uchar[2] := 0X + ELSIF code < 10000H THEN + uchar[2] := CHR(ORD(BITS(code) * {0..5}) + 80H); + code := ASR(code, 6); + uchar[1] := CHR(ORD(BITS(code) * {0..5}) + 80H); + uchar[0] := CHR(ASR(code, 6) + 0E0H); + uchar[3] := 0X +(* + ELSIF code < 200000H THEN + ELSIF code < 4000000H THEN + ELSE *) + END +END utf8; + + +PROCEDURE EntOct*(VAR chars: CHARS): BOOLEAN; +VAR + i : INTEGER; + c : CHAR; + amp : BOOLEAN; + oct : BOOLEAN; + val : INTEGER; + exit : BOOLEAN; + str : STRING; + str2 : STRING; + uchar : UTF8; + res : BOOLEAN; + +BEGIN + i := 0; + amp := FALSE; + oct := FALSE; + res := FALSE; + WHILE i <= chars.last - chars.first DO + c := GetChar(chars, i); + CASE c OF + |"&": + amp := TRUE; + oct := FALSE + |"#": + oct := amp; + amp := FALSE + |"0".."9": + IF oct THEN + val := 0; + str := "&#"; + str2[1] := 0X; + exit := FALSE; + REPEAT + val := val * 10 + ORD(c) - ORD("0"); + str2[0] := c; + Append(str, str2); + INC(i); + IF i <= chars.last - chars.first THEN + c := GetChar(chars, i) + ELSE + exit := TRUE + END + UNTIL ~isdigit(c) OR exit; + IF c = ";" THEN + str2[0] := c; + Append(str, str2); + utf8(val, uchar); + Replace(chars, str, uchar); + res := TRUE; + i := chars.last - chars.first + ELSE + IF ~exit THEN + DEC(i); + amp := FALSE; + oct := FALSE + END + END + ELSE + amp := FALSE + END + ELSE + amp := FALSE; + oct := FALSE + END; + INC(i) + END + RETURN res +END EntOct; + + +PROCEDURE UCase*(VAR s: STRING); +VAR i, n: INTEGER; c: CHAR; +BEGIN + n := LENGTH(s) - 1; + FOR i := 0 TO n DO + c := s[i]; + IF ("a" <= c) & (c <= "z") OR (0A0X <= c) & (c <= 0AFX) THEN + c := CHR(ORD(c) - 32) + ELSIF (0E0X <= c) & (c <= 0EFX) THEN + c := CHR(ORD(c) - 50H) + ELSIF (c = 0F1X) OR (c = 0F3X) OR (c = 0F5X) OR (c = 0F7X) THEN + c := CHR(ORD(c) - 1) + END; + s[i] := c + END +END UCase; + + +PROCEDURE Base64* (VAR chars: CHARS); +BEGIN + chars.last := chars.first + base64_decode(chars.first, chars.first, chars.last - chars.first + 1) - 1 +END Base64; + + +BEGIN + CS := TRUE +END Strings. diff --git a/programs/other/fb2reader/SRC/SysUtils.ob07 b/programs/other/fb2reader/SRC/SysUtils.ob07 new file mode 100644 index 0000000000..ba4ed391e0 --- /dev/null +++ b/programs/other/fb2reader/SRC/SysUtils.ob07 @@ -0,0 +1,365 @@ +(* + Copyright 2016, 2019, 2021, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE SysUtils; + +IMPORT K := KOSAPI, sys := SYSTEM, S := Strings; + + +CONST + + L_BUTTON* = 0; + + FontH* = 16; + FontW* = 8; + + +TYPE + + ENTRY* = PROCEDURE; + + +VAR + (*darkColor*,*) lightColor*, + winColor*, textColor*, btnColor*, btnTextColor*, + borderColor*: INTEGER; + + +PROCEDURE GetParam*(VAR Param: S.STRING); +VAR + adr : INTEGER; + c : CHAR; + i, max : INTEGER; +BEGIN + adr := K.GetCommandLine(); + i := 0; + max := LEN(Param) - 1; + REPEAT + sys.GET(adr, c); + INC(adr); + Param[i] := c; + INC(i) + UNTIL (c = 0X) OR (i = max); + Param[i] := 0X; + S.Trim(Param, 20X); + S.Trim(Param, 22X) +END GetParam; + + +PROCEDURE Halt*; +BEGIN + K.sysfunc1(-1) +END Halt; + + +PROCEDURE Run*(program: S.STRING; param: INTEGER); +TYPE + + info_struct = RECORD + subfunc : INTEGER; + flags : INTEGER; + param : INTEGER; + rsrvd1 : INTEGER; + rsrvd2 : INTEGER; + fname : ARRAY 1024 OF CHAR + END; + +VAR + info: info_struct; + +BEGIN + info.subfunc := 7; + info.flags := 0; + info.param := param; + info.rsrvd1 := 0; + info.rsrvd2 := 0; + COPY(program, info.fname); + K.sysfunc2(70, sys.ADR(info)) +END Run; + + +PROCEDURE ErrorIf*(condition: BOOLEAN; code: INTEGER); +VAR str, str2: S.STRING; +BEGIN + IF condition THEN + str := "'FB2 ERROR: "; + S.IntToString(code, str2); + S.Append(str, str2); + S.Append(str, "' -E"); + Run("/sys/@notify", sys.ADR(str[0])); + Halt + END +END ErrorIf; + + +PROCEDURE MemError*(err: BOOLEAN); +BEGIN + ErrorIf(err, 13) +END MemError; + + +PROCEDURE MinMax*(VAR value: INTEGER; min, max: INTEGER); +BEGIN + value := MIN(MAX(value, min), max) +END MinMax; + + +PROCEDURE MousePos*(VAR X, Y: INTEGER); +VAR res: INTEGER; +BEGIN + res := K.sysfunc2(37, 0); + X := LSR(res, 16); + Y := ORD(BITS(res) * {0..15}); +END MousePos; + + +PROCEDURE MouseVScroll*(): INTEGER; + RETURN ASR(LSL(K.sysfunc2(37, 7), 16), 16) +END MouseVScroll; + + +PROCEDURE MouseStatus*(): SET; + RETURN BITS(K.sysfunc2(37, 2)) +END MouseStatus; + + +PROCEDURE WindowRedrawStatus*(status: INTEGER); +BEGIN + K.sysfunc2(12, status) +END WindowRedrawStatus; + + +PROCEDURE DefineAndDrawWindow*(Left, Top, Width, Height, Color, Style: INTEGER; Caption: ARRAY OF CHAR); +BEGIN + K.sysfunc6(0, LSL(Left, 16) + Width, LSL(Top, 16) + Height, Color + LSL(Style, 24), 0, sys.ADR(Caption[0])) +END DefineAndDrawWindow; + + +PROCEDURE WaitForEvent*(): INTEGER; + RETURN K.sysfunc1(10) +END WaitForEvent; + + +PROCEDURE CheckEvent*(): INTEGER; + RETURN K.sysfunc1(11) +END CheckEvent; + + +PROCEDURE SetEventsMask*(mask: SET); +BEGIN + K.sysfunc2(40, ORD(mask)) +END SetEventsMask; + + +PROCEDURE GetKeyCode*(): INTEGER; + RETURN LSR(LSL(K.sysfunc1(2), 16), 24) +END GetKeyCode; + + +PROCEDURE GetButtonCode*(): INTEGER; +VAR res, button_code: INTEGER; +BEGIN + res := K.sysfunc1(17); + IF ORD(BITS(res) * {0..7}) = 0 THEN + button_code := LSR(res, 8) + ELSE + button_code := 0 + END + RETURN button_code +END GetButtonCode; + + +PROCEDURE OutText*(X, Y: INTEGER; Text: ARRAY OF CHAR; length: INTEGER; color: INTEGER); +BEGIN + K.sysfunc6(4, LSL(X, 16) + Y, LSL(3 * 16, 24) + color, sys.ADR(Text[0]), length, 0) +END OutText; + + +PROCEDURE GetWindowPos*(VAR Left, Top: INTEGER); +VAR info: ARRAY 1024 OF CHAR; +BEGIN + K.sysfunc3(9, sys.ADR(info[0]), -1); + sys.GET(sys.ADR(info[34]), Left); + sys.GET(sys.ADR(info[38]), Top) +END GetWindowPos; + + +PROCEDURE GetWindowSize*(VAR Width, Height: INTEGER); +VAR info: ARRAY 1024 OF CHAR; +BEGIN + K.sysfunc3(9, sys.ADR(info[0]), -1); + sys.GET(sys.ADR(info[42]), Width); + sys.GET(sys.ADR(info[46]), Height) +END GetWindowSize; + + +PROCEDURE SetWindowSize*(Width, Height: INTEGER); +BEGIN + K.sysfunc5(67, -1, -1, Width, Height) +END SetWindowSize; + + +PROCEDURE GetScreenSize*(VAR Width, Height: INTEGER); +VAR res: INTEGER; +BEGIN + res := K.sysfunc1(14); + Width := LSR(res, 16) + 1; + Height := ORD(BITS(res) * {0..15}) + 1 +END GetScreenSize; + + +PROCEDURE GetScreenArea*(VAR X1, Y1, X2, Y2: INTEGER); +VAR eax, ebx: INTEGER; +BEGIN + eax := K.sysfunc22(48, 5, ebx); + X1 := LSR(eax, 16); + Y1 := LSR(ebx, 16); + X2 := ORD(BITS(eax) * {0..15}); + Y2 := ORD(BITS(ebx) * {0..15}) +END GetScreenArea; + + +PROCEDURE SkinHeight*(): INTEGER; + RETURN K.sysfunc2(48, 4) +END SkinHeight; + + +PROCEDURE DrawRect*(Left, Top, Width, Height, Color: INTEGER); +BEGIN + K.sysfunc4(13, LSL(Left, 16) + Width, LSL(Top, 16) + Height, Color) +END DrawRect; + + +PROCEDURE NewThread*(eip: ENTRY; stack: ARRAY OF CHAR): INTEGER; +VAR entry: INTEGER; +BEGIN + sys.GET(sys.ADR(eip), entry) + RETURN K.sysfunc4(51, 1, entry, sys.ADR(stack[0]) + LEN(stack)) +END NewThread; + + +PROCEDURE Pause*(time: INTEGER); +BEGIN + K.sysfunc2(5, time) +END Pause; + + +PROCEDURE GetThreadSlot*(PID: INTEGER): INTEGER; + RETURN K.sysfunc3(18, 21, PID) +END GetThreadSlot; + + +PROCEDURE TerminateThreadId*(PID: INTEGER); +BEGIN + K.sysfunc3(18, 18, PID) +END TerminateThreadId; + + +PROCEDURE IsTerminated*(PID: INTEGER): BOOLEAN; + RETURN GetThreadSlot(PID) = 0 +END IsTerminated; + + +PROCEDURE FocusWindow*(Slot: INTEGER); +BEGIN + K.sysfunc3(18, 3, Slot) +END FocusWindow; + + +PROCEDURE CreateButton*(id, Left, Top, Width, Height, Color: INTEGER; Caption: ARRAY OF CHAR); +VAR + X, Y, len: INTEGER; + +BEGIN + len := LENGTH(Caption); + K.sysfunc5(8, LSL(Left, 16) + Width, LSL(Top, 16) + Height, id, btnColor); + X := Left + (Width - FontW * len) DIV 2; + Y := Top + (Height - FontH) DIV 2 + 1; + OutText(X, Y, Caption, len, btnTextColor) +END CreateButton; + + +PROCEDURE DrawLine* (x1, y1, x2, y2: INTEGER; color: INTEGER); +BEGIN + K.sysfunc4(38, x1*65536 + x2, y1*65536 + y2, color) +END DrawLine; + + +PROCEDURE Box*(Left, Top, Width, Height, BrushColor, PenColor: INTEGER); +BEGIN + K.sysfunc4(13, LSL(Left, 16) + Width, LSL(Top, 16) + Height, BrushColor); + DrawLine(Left, Top, Left + Width, Top, PenColor); + DrawLine(Left + Width, Top, Left + Width, Top + Height, PenColor); + DrawLine(Left + Width, Top + Height, Left, Top + Height, PenColor); + DrawLine(Left, Top + Height, Left, Top, PenColor); +END Box; + + +PROCEDURE LoadCursor*(cursor: INTEGER): INTEGER; + RETURN K.sysfunc4(37, 4, cursor, 1) +END LoadCursor; + + +PROCEDURE SetCursor*(handle: INTEGER); +BEGIN + K.sysfunc3(37, 5, handle) +END SetCursor; + + +PROCEDURE DelCursor*(handle: INTEGER); +BEGIN + K.sysfunc3(37, 6, handle) +END DelCursor; + + +PROCEDURE DrawImage* (data, sizeX, sizeY, x, y: INTEGER); +BEGIN + K.sysfunc4(7, data, sizeX*65536 + sizeY, x*65536 + y) +END DrawImage; + + +PROCEDURE DrawText69* (x, y, color: INTEGER; text: ARRAY OF CHAR); +BEGIN + K.sysfunc6(4, x*65536 + y, color + LSL(080H, 24), sys.ADR(text[0]), 0, 0) +END DrawText69; + + +PROCEDURE PutPixel* (x, y, color: INTEGER); +BEGIN + K.sysfunc5(1, x, y, color, 0) +END PutPixel; + + +PROCEDURE GetSystemColors*; +VAR + buf: ARRAY 10 OF INTEGER; +BEGIN + ASSERT(LEN(buf) >= 10); + K.sysfunc4(48, 3, sys.ADR(buf[0]), 40); + (*darkColor := buf[2];*) + lightColor := buf[3]; + winColor := buf[5]; + textColor := buf[8]; + btnColor := buf[6]; + btnTextColor := buf[7]; + borderColor := buf[9]; +END GetSystemColors; + + +END SysUtils. diff --git a/programs/other/fb2reader/SRC/Toolbar.ob07 b/programs/other/fb2reader/SRC/Toolbar.ob07 new file mode 100644 index 0000000000..162f79324d --- /dev/null +++ b/programs/other/fb2reader/SRC/Toolbar.ob07 @@ -0,0 +1,167 @@ +(* + Copyright 2021, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Toolbar; + +IMPORT + Icons, K := SysUtils; + +CONST + max = 14; + + BtnSize* = 26; + BtnInter = 5; + DelimSize = 7; + IconPad = (BtnSize - Icons.SIZE) DIV 2; + +TYPE + tButtonText = ARRAY 4 OF CHAR; + + tButton = RECORD + btn, icon, x: INTEGER; + text: tButtonText; + enabled: BOOLEAN + END; + + tToolbar* = RECORD + buttons: ARRAY max OF tButton; + x, y, cnt, width: INTEGER; + icons, grayIcons: INTEGER; + colors: RECORD back, text, disText, light, shadow, window: INTEGER END + END; + + +PROCEDURE drawIcons* (toolbar: tToolbar); +VAR + i, icons, color: INTEGER; + button: tButton; +BEGIN + i := 0; + WHILE i < toolbar.cnt DO + button := toolbar.buttons[i]; + IF button.btn # 0 THEN + IF button.enabled THEN + icons := toolbar.icons; + color := toolbar.colors.text + ELSE + icons := toolbar.grayIcons; + color := toolbar.colors.disText + END; + IF button.icon # -1 THEN + Icons.draw(icons, button.icon, button.x + IconPad, toolbar.y + IconPad) + ELSE + K.DrawRect(button.x + 1, toolbar.y + 1, BtnSize - 1, BtnSize - 1, toolbar.colors.back); + K.DrawText69(button.x + (BtnSize - LENGTH(button.text)*6) DIV 2, toolbar.y + (BtnSize - 9) DIV 2 + 2, color, button.text) + END + END; + INC(i) + END +END drawIcons; + + +PROCEDURE setColors (VAR toolbar: tToolbar); +BEGIN + toolbar.colors.back := 0F2EFECH; + toolbar.colors.text := 00000FFH; + toolbar.colors.disText := 0808080H; + toolbar.colors.light := 0FEFEFEH; + toolbar.colors.shadow := 09F9C9AH; + toolbar.colors.window := K.winColor +END setColors; + + +PROCEDURE draw* (VAR toolbar: tToolbar); +VAR + i, x, y, btn: INTEGER; + button: tButton; +BEGIN + setColors(toolbar); + Icons.get(toolbar.icons, toolbar.grayIcons, toolbar.colors.back); + i := 0; + WHILE i < toolbar.cnt DO + button := toolbar.buttons[i]; + btn := button.btn; + IF btn # 0 THEN + x := button.x; + y := toolbar.y; + K.DrawRect(x + 1, y + 1, BtnSize, BtnSize - 1, toolbar.colors.back); + K.DrawLine(x + 1, y + BtnSize, x + BtnSize - 1, y + BtnSize, toolbar.colors.shadow); + K.DrawLine(x + 1, y, x + BtnSize - 1, y, toolbar.colors.light); + K.DrawLine(x, y + 1, x, y + BtnSize - 1, toolbar.colors.light); + K.PutPixel(x + BtnSize, y + 1, toolbar.colors.light); + K.PutPixel(x, y + BtnSize - 1, toolbar.colors.shadow); + K.PutPixel(x + BtnSize, y + BtnSize - 1, toolbar.colors.shadow); + K.CreateButton(btn + ORD({30}), x, y, BtnSize, BtnSize, 0, "") + END; + INC(i) + END; + drawIcons(toolbar) +END draw; + + +PROCEDURE enable* (VAR toolbar: tToolbar; btn: INTEGER; value: BOOLEAN); +VAR + i: INTEGER; +BEGIN + i := 0; + WHILE (i < toolbar.cnt) & (toolbar.buttons[i].btn # btn) DO + INC(i) + END; + IF i < toolbar.cnt THEN + toolbar.buttons[i].enabled := value + END +END enable; + + +PROCEDURE add* (VAR toolbar: tToolbar; btn, icon: INTEGER; text: tButtonText); +VAR + button: tButton; +BEGIN + ASSERT(toolbar.cnt < max); + button.btn := btn; + button.icon := icon; + button.x := toolbar.width + toolbar.x; + button.text := text; + button.enabled := TRUE; + toolbar.buttons[toolbar.cnt] := button; + INC(toolbar.cnt); + IF btn # 0 THEN + INC(toolbar.width, BtnSize + BtnInter) + ELSE + INC(toolbar.width, DelimSize) + END +END add; + + +PROCEDURE delimiter* (VAR toolbar: tToolbar); +BEGIN + add(toolbar, 0, 0, "") +END delimiter; + + +PROCEDURE create* (VAR toolbar: tToolbar; x, y: INTEGER); +BEGIN + toolbar.x := x; + toolbar.y := y; + toolbar.cnt := 0; + toolbar.width := 0 +END create; + + +END Toolbar. \ No newline at end of file diff --git a/programs/other/fb2reader/SRC/Txt2fb2.ob07 b/programs/other/fb2reader/SRC/Txt2fb2.ob07 new file mode 100644 index 0000000000..649d9f96e6 --- /dev/null +++ b/programs/other/fb2reader/SRC/Txt2fb2.ob07 @@ -0,0 +1,129 @@ +(* + Copyright 2016, 2020 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Txt2FB2; + +IMPORT File, sys := SYSTEM, K := KOSAPI, S := Strings, SU := SysUtils; + + +CONST + + AUTO* = 15; + CP866* = 16; + CP1251* = 17; + CP1252* = 18; + CP1250* = 19; + UTF8* = 20; + + +VAR F: File.FS; ch: CHAR; pos, mem, mem2, pos2: INTEGER; + + +PROCEDURE getch; +BEGIN + sys.GET(mem + pos, ch); + INC(pos) +END getch; + + +PROCEDURE WriteStr(s: ARRAY OF CHAR); +BEGIN + sys.MOVE(sys.ADR(s[0]), mem2 + pos2, LENGTH(s)); + pos2 := pos2 + LENGTH(s) +END WriteStr; + + +PROCEDURE WriteChar(ch: CHAR); +BEGIN + sys.PUT(mem2 + pos2, ch); + INC(pos2) +END WriteChar; + + +PROCEDURE convert*(in, out: S.STRING; encoding: INTEGER); +CONST buf_size = 1024*16; +VAR n, size: INTEGER; CR: BOOLEAN; +BEGIN + F := File.Open(in); + size := File.Seek(F, 0, 2); + n := File.Seek(F, 0, 0); + mem := K.malloc(size + 1024); + SU.MemError(mem = 0); + n := File.Read(F, mem, size); + File.Close(F); + pos := 0; + F := File.Create(out); + mem2 := K.malloc(buf_size); + SU.MemError(mem2 = 0); + pos2 := 0; + WriteStr(""); + WriteChar(0DX); + WriteChar(0AX); + WriteStr(""); + WHILE pos < size DO + IF pos2 > buf_size - 32 THEN + n := File.Write(F, mem2, pos2); + pos2 := 0 + END; + getch; + IF ch = "<" THEN + WriteStr("<") + ELSIF ch = ">" THEN + WriteStr(">") + ELSIF ch = "&" THEN + WriteStr("&") + ELSIF ch = "'" THEN + WriteStr("'") + ELSIF ch = 22X THEN + WriteStr(""") + ELSIF ch = 0DX THEN + WriteStr("") + ELSIF ch = 0AX THEN + IF ~CR THEN + WriteStr("") + END + ELSIF ch = 0X THEN + WriteChar(20X) + ELSE + WriteChar(ch) + END; + CR := ch = 0DX + END; + + WriteStr(""); + n := File.Write(F, mem2, pos2); + File.Close(F); + mem := K.free(mem); + mem2 := K.free(mem2) +END convert; + + +END Txt2FB2. diff --git a/programs/other/fb2reader/SRC/Vector.ob07 b/programs/other/fb2reader/SRC/Vector.ob07 new file mode 100644 index 0000000000..a2fa7f632e --- /dev/null +++ b/programs/other/fb2reader/SRC/Vector.ob07 @@ -0,0 +1,105 @@ +(* + Copyright 2016 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Vector; + + +IMPORT sys := SYSTEM, K := KOSAPI; + + +TYPE + + DESC_VECTOR = RECORD + + data : INTEGER; + count* : INTEGER; + size : INTEGER + + END; + + VECTOR* = POINTER TO DESC_VECTOR; + + ANYREC* = RECORD END; + + ANYPTR* = POINTER TO ANYREC; + + DESTRUCTOR* = PROCEDURE (VAR ptr: ANYPTR); + + +PROCEDURE push* (vector: VECTOR; value: ANYPTR); +BEGIN + IF vector.count = vector.size THEN + vector.data := K.realloc(vector.data, (vector.size + 1024) * 4); + vector.size := vector.size + 1024 + END; + sys.PUT(vector.data + vector.count * 4, value); + INC(vector.count) +END push; + + +PROCEDURE get* (vector: VECTOR; idx: INTEGER): ANYPTR; +VAR res: ANYPTR; +BEGIN + ASSERT( (0 <= idx) & (idx < vector.count) ); + sys.GET(vector.data + idx * 4, res) + RETURN res +END get; + + +PROCEDURE put* (vector: VECTOR; idx: INTEGER; value: ANYPTR); +BEGIN + ASSERT( (0 <= idx) & (idx < vector.count) ); + sys.PUT(vector.data + idx * 4, value) +END put; + + +PROCEDURE create* (size: INTEGER): VECTOR; +VAR vector: VECTOR; +BEGIN + NEW(vector); + vector.data := K.malloc(4 * size); + vector.size := size; + vector.count := 0 + RETURN vector +END create; + + +PROCEDURE def_destructor (VAR any: ANYPTR); +BEGIN + DISPOSE(any) +END def_destructor; + + +PROCEDURE destroy* (VAR vector: VECTOR; destructor: DESTRUCTOR); +VAR i: INTEGER; + any: ANYPTR; +BEGIN + IF destructor = NIL THEN + destructor := def_destructor + END; + FOR i := 0 TO vector.count - 1 DO + any := get(vector, i); + destructor(any) + END; + vector.data := K.free(vector.data); + DISPOSE(vector) +END destroy; + + +END Vector. diff --git a/programs/other/fb2reader/SRC/Window.ob07 b/programs/other/fb2reader/SRC/Window.ob07 new file mode 100644 index 0000000000..c2c71e9093 --- /dev/null +++ b/programs/other/fb2reader/SRC/Window.ob07 @@ -0,0 +1,58 @@ +(* + Copyright 2016, 2021 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Window; + +IMPORT S := Strings; + +TYPE + + TRect* = RECORD + Left*, Top*, Width*, Height* : INTEGER + END; + + TWindow* = RECORD (TRect) + Caption* : S.STRING; + Created* : BOOLEAN; + dWidth*, dHeight* : INTEGER + END; + +PROCEDURE InitWindow*(VAR Window: TWindow; Left, Top, Width, Height: INTEGER; Caption: ARRAY OF CHAR); +BEGIN + Window.Left := Left; + Window.Top := Top; + Window.Width := Width; + Window.Height := Height; + Window.Created := FALSE; + Window.dWidth := 0; + Window.dHeight := 0; + COPY(Caption, Window.Caption) +END InitWindow; + + +PROCEDURE InitRect*(VAR Rect: TRect; Left, Top, Width, Height: INTEGER); +BEGIN + Rect.Left := Left; + Rect.Top := Top; + Rect.Width := Width; + Rect.Height := Height +END InitRect; + + +END Window. diff --git a/programs/other/fb2reader/SRC/Write.ob07 b/programs/other/fb2reader/SRC/Write.ob07 new file mode 100644 index 0000000000..e12cb07fa4 --- /dev/null +++ b/programs/other/fb2reader/SRC/Write.ob07 @@ -0,0 +1,42 @@ +(* + Copyright 2016 Anton Krotov + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*) + +MODULE Write; + +IMPORT File, sys := SYSTEM; + +PROCEDURE Char*(F: File.FS; x: CHAR): BOOLEAN; + RETURN File.Write(F, sys.ADR(x), sys.SIZE(CHAR)) = sys.SIZE(CHAR) +END Char; + +PROCEDURE Int*(F: File.FS; x: INTEGER): BOOLEAN; + RETURN File.Write(F, sys.ADR(x), sys.SIZE(INTEGER)) = sys.SIZE(INTEGER) +END Int; + +PROCEDURE Real*(F: File.FS; x: REAL): BOOLEAN; + RETURN File.Write(F, sys.ADR(x), sys.SIZE(REAL)) = sys.SIZE(REAL) +END Real; + +PROCEDURE Boolean*(F: File.FS; x: BOOLEAN): BOOLEAN; + RETURN File.Write(F, sys.ADR(x), sys.SIZE(BOOLEAN)) = sys.SIZE(BOOLEAN) +END Boolean; + +PROCEDURE Set*(F: File.FS; x: SET): BOOLEAN; + RETURN File.Write(F, sys.ADR(x), sys.SIZE(SET)) = sys.SIZE(SET) +END Set; + +END Write. diff --git a/programs/other/fb2reader/SRC/XML.ob07 b/programs/other/fb2reader/SRC/XML.ob07 new file mode 100644 index 0000000000..c063c727dd --- /dev/null +++ b/programs/other/fb2reader/SRC/XML.ob07 @@ -0,0 +1,755 @@ +(* + Copyright 2016, 2020, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE XML; + +IMPORT SU := SysUtils, RF := ReadFile, S := Strings, Encode, V := Vector, tables, LISTS; + + +CONST + + tag_p* = 1; + tag_v* = 2; + tag_section* = 3; + tag_stanza* = 4; + tag_empty_line* = 5; + tag_subtitle* = 6; + tag_date* = 7; + tag_text_author* = 8; + tag_a* = 9; + tag_sub* = 10; + tag_sup* = 11; + tag_code* = 12; + tag_poem* = 13; + tag_title* = 14; + tag_FictionBook* = 15; + tag_body* = 16; + tag_strikethrough* = 17; + tag_strong* = 18; + tag_cite* = 19; + tag_epigraph* = 20; + tag_emphasis* = 21; + tag_image* = 22; + tag_binary* = 23; + tag_coverpage* = 24; + tag_description* = 25; + tag_xml* = 26; + tag_annotation* = 27; + tag_contents_item* = 28; + tag_table* = 29; + tag_tr* = 30; + tag_td* = 31; + tag_th* = 32; + tag_unknown* = -1; + + +TYPE + + ELEMENT* = POINTER TO DESC_ELEMENT; + + TEXT* = POINTER TO DESC_TEXT; + + SPACE* = POINTER TO DESC_SPACE; + + WORD* = POINTER TO DESC_WORD; + + TAG* = POINTER TO DESC_TAG; + + ATTR* = POINTER TO DESC_ATTR; + + TAG_ID = POINTER TO DESC_TAG_ID; + + + LIST* = RECORD first*, last* : ELEMENT END; + + DESC_ELEMENT* = RECORD (V.ANYREC) + parent*, next* : ELEMENT + END; + + DESC_TEXT = RECORD (DESC_ELEMENT) + X*, Y* : INTEGER; + width* : INTEGER + END; + + DESC_SPACE = RECORD (DESC_TEXT) + + END; + + DESC_WORD = RECORD (DESC_TEXT) + length* : INTEGER; + value* : S.CHARS + END; + + DESC_TAG = RECORD (DESC_ELEMENT) + name* : S.CHARS; + value* : INTEGER; + child* : LIST; + attr* : LIST; + Ymin* : INTEGER; + Ymax* : INTEGER; + X* : INTEGER; + Width* : INTEGER; + Clicked* : BOOLEAN; + Visited* : BOOLEAN; + img* : INTEGER; + num* : INTEGER; + cell* : INTEGER; + table* : tables.Table; + text* : LISTS.ITEM + END; + + DESC_ATTR = RECORD (DESC_ELEMENT) + name : S.CHARS; + value : S.CHARS + END; + + DESC_TAG_ID = RECORD (DESC_ELEMENT) + tag : TAG; + id : S.CHARS + END; + + +VAR + ch: CHAR; binary: BOOLEAN; + + Root, Current, Header, FB*: ELEMENT; + + Tag_id: LIST; + + tire1, tire2, nbsp, ellipsis, apo, + quot1, quot2, quot3, quot4, quot5, quot6, quot7, + number, bullet, euro, + dash1, dash2: S.UTF8; + + num: INTEGER; + Tags: V.VECTOR; + + +PROCEDURE GetTagByNum*(n: INTEGER): TAG; +VAR ptr: V.ANYPTR; +BEGIN + ptr := V.get(Tags, n) + RETURN ptr(TAG) +END GetTagByNum; + + +PROCEDURE ListCount*(list: LIST): INTEGER; +VAR cur: ELEMENT; res: INTEGER; +BEGIN + res := 0; + cur := list.first; + WHILE cur # NIL DO + INC(res); + cur := cur.next + END + RETURN res +END ListCount; + + +PROCEDURE GetTagByID(id: S.CHARS): TAG; +VAR + cur : TAG_ID; + Result : TAG; +BEGIN + Result := NIL; + cur := Tag_id.first(TAG_ID); + WHILE cur # NIL DO + IF S.CharsEq(id, cur.id) THEN + Result := cur.tag; + cur := NIL + ELSE + cur := cur.next(TAG_ID) + END + END + RETURN Result +END GetTagByID; + + +PROCEDURE GetAttr*(tag: TAG; attr_name: S.STRING; VAR attr_value: S.CHARS): BOOLEAN; +VAR attr: ELEMENT; + found: BOOLEAN; +BEGIN + found := FALSE; + attr := tag.attr.first; + WHILE ~found & (attr # NIL) DO + IF S.CharsEqStr(attr(ATTR).name, attr_name) THEN + attr_value := attr(ATTR).value; + INC(attr_value.first); + DEC(attr_value.last); + found := TRUE + ELSE + attr := attr.next + END + END + RETURN found +END GetAttr; + + +PROCEDURE IsHref(attr_name: S.CHARS): BOOLEAN; +VAR chars: S.CHARS; +BEGIN + chars := attr_name; + chars.first := chars.last - 4 + RETURN S.CharsEqStr(chars, ":href") +END IsHref; + + +PROCEDURE GetRef*(tag: TAG; VAR note: BOOLEAN; VAR URL: INTEGER): TAG; +VAR + attr : ATTR; + chars : S.CHARS; + Result : TAG; +BEGIN + Result := NIL; + note := FALSE; + URL := 0; + attr := tag.attr.first(ATTR); + WHILE attr # NIL DO + IF IsHref(attr.name) THEN + chars := attr.value; + INC(chars.first); + IF S.GetChar(chars, 0) = "#" THEN + DEC(chars.last); + INC(chars.first); + Result := GetTagByID(chars) + ELSE + S.PutChar(chars, chars.last - chars.first, 0X); + URL := chars.first + END + ELSIF S.CharsEqStr(attr.name, "type") THEN + chars := attr.value; + INC(chars.first); + DEC(chars.last); + note := S.CharsEqStr(chars, "note") + END; + attr := attr.next(ATTR) + END + RETURN Result +END GetRef; + + +PROCEDURE IsNote*(tag: TAG): BOOLEAN; +VAR + res : TAG; + note : BOOLEAN; + URL : INTEGER; +BEGIN + res := GetRef(tag, note, URL) + RETURN note +END IsNote; + + +PROCEDURE CreateTag*(): TAG; +VAR tag: TAG; +BEGIN + NEW(tag); + tag.Visited := FALSE; + SU.MemError(tag = NIL); + INC(num); + tag.num := num; + V.push(Tags, tag) + RETURN tag +END CreateTag; + + +PROCEDURE CreateWord*(): WORD; +VAR word: WORD; +BEGIN + NEW(word); + SU.MemError(word = NIL) + RETURN word +END CreateWord; + + +PROCEDURE CreateSpace(): SPACE; +VAR space: SPACE; +BEGIN + NEW(space); + SU.MemError(space = NIL) + RETURN space +END CreateSpace; + + +PROCEDURE CreateAttr(): ATTR; +VAR attr: ATTR; +BEGIN + NEW(attr); + SU.MemError(attr = NIL) + RETURN attr +END CreateAttr; + + +PROCEDURE AddItem*(VAR list: LIST; item: ELEMENT); +BEGIN + IF list.first = NIL THEN + list.first := item + ELSE + list.last.next := item + END; + list.last := item +END AddItem; + + +PROCEDURE DelLastItem*(VAR list: LIST); +VAR cur: ELEMENT; +BEGIN + IF list.first = list.last THEN + IF list.last # NIL THEN + DISPOSE(list.last) + END; + list.first := NIL + ELSE + cur := list.first; + WHILE cur.next # list.last DO + cur := cur.next + END; + DISPOSE(list.last); + cur.next := NIL; + list.last := cur + END +END DelLastItem; + + +PROCEDURE AddChild*(tag: TAG; child: ELEMENT); +BEGIN + AddItem(tag.child, child); + child.parent := tag +END AddChild; + + +PROCEDURE AddAttr(tag: TAG; attr: ATTR); +BEGIN + AddItem(tag.attr, attr); + attr.parent := tag +END AddAttr; + + +PROCEDURE Copy*(node: ELEMENT): ELEMENT; +VAR + space : SPACE; + word : WORD; + tag : TAG; + cur : ELEMENT; + num : INTEGER; + + Result : ELEMENT; +BEGIN + IF node IS TAG THEN + tag := CreateTag(); + num := tag.num; + tag^ := node(TAG)^; + tag.num := num; + tag.child.first := NIL; + tag.child.last := NIL; + cur := node(TAG).child.first; + WHILE cur # NIL DO + AddChild(tag, Copy(cur)); + cur := cur.next + END; + Result := tag + ELSIF node IS WORD THEN + word := CreateWord(); + word^ := node(WORD)^; + Result := word + ELSIF node IS SPACE THEN + space := CreateSpace(); + space^ := node(SPACE)^; + Result := space + END; + Result.next := NIL + RETURN Result +END Copy; + + +PROCEDURE IsIdentChar(): BOOLEAN; + RETURN ("A" <= ch) & (ch <= "Z") OR + ("a" <= ch) & (ch <= "z") OR + ("0" <= ch) & (ch <= "9") OR + (ch = "?") OR (ch = "!") OR + (ch = ":") OR (ch = "_") OR + (ch = "-") +END IsIdentChar; + + +PROCEDURE Space(): BOOLEAN; + RETURN (ch # 0X) & (ch <= 20X) +END Space; + + +PROCEDURE Ident(VAR id: S.CHARS); +BEGIN + id.first := RF.Adr(); + WHILE IsIdentChar() DO + RF.Next(ch) + END; + id.last := RF.Adr() - 1 +END Ident; + + +PROCEDURE Skip; +BEGIN + WHILE Space() DO + RF.Next(ch) + END +END Skip; + + +PROCEDURE String(VAR str: S.CHARS); +VAR quot: CHAR; +BEGIN + SU.ErrorIf((ch # "'") & (ch # 22X), 1); + str.first := RF.Adr(); + quot := ch; + REPEAT + RF.Next(ch) + UNTIL (ch = quot) OR (ch = 0X); + SU.ErrorIf(ch = 0X, 2); + str.last := RF.Adr(); + RF.Next(ch) +END String; + + +PROCEDURE SetTagValue(tag: TAG); +VAR + value : INTEGER; + name : S.CHARS; +BEGIN + name := tag.name; + IF S.CharsEqStr(name, "p") THEN + value := tag_p + ELSIF S.CharsEqStr(name, "v") THEN + value := tag_v + ELSIF S.CharsEqStr(name, "section") THEN + value := tag_section + ELSIF S.CharsEqStr(name, "stanza") THEN + value := tag_stanza + ELSIF S.CharsEqStr(name, "empty-line") THEN + value := tag_empty_line + ELSIF S.CharsEqStr(name, "subtitle") THEN + value := tag_subtitle + ELSIF S.CharsEqStr(name, "date") THEN + value := tag_date + ELSIF S.CharsEqStr(name, "text-author") THEN + value := tag_text_author + ELSIF S.CharsEqStr(name, "a") THEN + value := tag_a + ELSIF S.CharsEqStr(name, "sub") THEN + value := tag_sub + ELSIF S.CharsEqStr(name, "sup") THEN + value := tag_sup + ELSIF S.CharsEqStr(name, "code") THEN + value := tag_code + ELSIF S.CharsEqStr(name, "poem") THEN + value := tag_poem + ELSIF S.CharsEqStr(name, "title") THEN + value := tag_title + ELSIF S.CharsEqStr(name, "FictionBook") THEN + value := tag_FictionBook; + FB := tag + ELSIF S.CharsEqStr(name, "body") THEN + value := tag_body + ELSIF S.CharsEqStr(name, "strikethrough") THEN + value := tag_strikethrough + ELSIF S.CharsEqStr(name, "strong") THEN + value := tag_strong + ELSIF S.CharsEqStr(name, "cite") THEN + value := tag_cite + ELSIF S.CharsEqStr(name, "epigraph") THEN + value := tag_epigraph + ELSIF S.CharsEqStr(name, "emphasis") THEN + value := tag_emphasis + ELSIF S.CharsEqStr(name, "image") THEN + value := tag_image + ELSIF S.CharsEqStr(name, "binary") THEN + binary := TRUE; + value := tag_binary + ELSIF S.CharsEqStr(name, "coverpage") THEN + value := tag_coverpage + ELSIF S.CharsEqStr(name, "description") THEN + value := tag_description + ELSIF S.CharsEqStr(name, "annotation") THEN + value := tag_annotation + ELSIF S.CharsEqStr(name, "table") THEN + value := tag_table + ELSIF S.CharsEqStr(name, "tr") THEN + value := tag_tr + ELSIF S.CharsEqStr(name, "td") THEN + value := tag_td + ELSIF S.CharsEqStr(name, "th") THEN + value := tag_th + ELSIF S.CharsEqStr(name, "?xml") THEN + value := tag_xml; + Header := tag + ELSE + value := tag_unknown + END; + tag.value := value +END SetTagValue; + + +PROCEDURE ReadTag; +VAR tag: TAG; name: S.CHARS; attr: ATTR; tag_id: TAG_ID; +BEGIN + RF.Next(ch); + Skip; + IF ch = "/" THEN + RF.Next(ch); + Skip; + SU.ErrorIf(~IsIdentChar(), 3); + Ident(name); + Skip; + SU.ErrorIf(ch # ">", 4); + RF.Next(ch); + tag := Current(TAG); + SU.ErrorIf(~S.CharsEq(tag.name, name), 5); + IF tag.value = tag_binary THEN + binary := FALSE; + IF tag.child.first IS WORD THEN + S.Base64(tag.child.first(WORD).value) + END + END; + Current := Current.parent + ELSE + tag := CreateTag(); + AddChild(Current(TAG), tag); + Current := tag; + SU.ErrorIf(~IsIdentChar(), 6); + Ident(tag.name); + SetTagValue(tag); + WHILE Space() DO + Skip; + IF IsIdentChar() THEN + attr := CreateAttr(); + Ident(attr.name); + Skip; + SU.ErrorIf(ch # "=", 7); + RF.Next(ch); + Skip; + String(attr.value); + AddAttr(Current(TAG), attr); + IF S.CharsEqStr(attr.name, "id") THEN + NEW(tag_id); + SU.MemError(tag_id = NIL); + tag_id.tag := Current(TAG); + tag_id.id := attr.value; + INC(tag_id.id.first); + DEC(tag_id.id.last); + AddItem(Tag_id, tag_id) + END + END + END; + IF ch = "/" THEN + RF.Next(ch); + IF Current(TAG).value = tag_binary THEN + binary := FALSE + END; + Current := Current.parent + ELSIF ch = "?" THEN + RF.Next(ch); + SU.ErrorIf(Current(TAG).value # tag_xml, 8); + Current := Current.parent + END; + SU.ErrorIf(ch # ">", 9); + RF.Next(ch) + END +END ReadTag; + + +PROCEDURE ReadSpace; +VAR space: SPACE; +BEGIN + space := CreateSpace(); + AddChild(Current(TAG), space); + RF.Next(ch) +END ReadSpace; + + +PROCEDURE ReadWord; +VAR word: WORD; chars: S.CHARS; repl: BOOLEAN; +BEGIN + word := CreateWord(); + word.value.first := RF.Adr(); + repl := FALSE; + WHILE ((ch > 20X) OR binary) & (ch # 0X) & (ch # "<") DO + repl := repl OR (ch = "&") OR (ch = 0C2X) OR (ch >= 0E0X) & (ch < 0F0X); + RF.Next(ch) + END; + word.value.last := RF.Adr() - 1; + IF repl THEN + chars := word.value; + S.Replace(chars, "&", "&"); + S.Replace(chars, "<", "<"); + S.Replace(chars, ">", ">"); + S.Replace(chars, """, 22X); + S.Replace(chars, "'", "'"); + WHILE S.EntOct(chars) DO END; + S.Replace(chars, tire1, "--"); + S.Replace(chars, tire2, "--"); + S.Replace(chars, nbsp, " "); + S.Replace(chars, ellipsis, "..."); + S.Replace(chars, quot1, 22X); + S.Replace(chars, quot2, 22X); + S.Replace(chars, quot3, 22X); + S.Replace(chars, quot4, "'"); + S.Replace(chars, quot5, ","); + S.Replace(chars, quot6, "<"); + S.Replace(chars, quot7, ">"); + S.Replace(chars, number, "No."); + S.Replace(chars, apo, "'"); + S.Replace(chars, dash1, "-"); + S.Replace(chars, dash2, "-"); + S.Replace(chars, bullet, "*"); + S.Replace(chars, euro, "EUR"); + word.value := chars + END; + AddChild(Current(TAG), word) +END ReadWord; + + +PROCEDURE Comment(): BOOLEAN; +CONST com = 2D2D213CH; +VAR res: BOOLEAN; +BEGIN + res := FALSE; + IF RF.Int() = com THEN + RF.Next(ch); + RF.Next(ch); + RF.Next(ch); + RF.Next(ch); + + REPEAT + RF.Next(ch); + IF ch = "-" THEN + RF.Next(ch); + WHILE (ch = "-") & ~res DO + RF.Next(ch); + IF ch = ">" THEN + RF.Next(ch); + res := TRUE + END + END + END + UNTIL (ch = 0X) OR res + + END + RETURN res +END Comment; + + +PROCEDURE Prolog; +VAR attr: ATTR; chars: S.CHARS; +BEGIN + RF.Next(ch); + IF ch = 0EFX THEN + RF.Next(ch); + SU.ErrorIf(ch # 0BBX, 16); + RF.Next(ch); + SU.ErrorIf(ch # 0BFX, 16); + RF.Next(ch) + END; + Skip; + IF ch = "<" THEN + ReadTag + END; + + SU.ErrorIf(Header = NIL, 15); + + attr := Header(TAG).attr.first(ATTR); + WHILE attr # NIL DO + IF S.CharsEqStr(attr.name, "encoding") THEN + chars := attr.value; + INC(chars.first); + DEC(chars.last); + S.SetCS(FALSE); + IF S.CharsEqStr(chars, "windows-1250") THEN + RF.Conv(Encode.W1250) + ELSIF S.CharsEqStr(chars, "windows-1251") THEN + RF.Conv(Encode.W1251) + ELSIF S.CharsEqStr(chars, "windows-1252") THEN + RF.Conv(Encode.W1252) + ELSIF S.CharsEqStr(chars, "cp866" ) THEN + RF.Conv(Encode.CP866) + ELSIF S.CharsEqStr(chars, "utf-8" ) THEN + RF.SeekBeg + ELSE + SU.ErrorIf(TRUE, 14) + END; + S.SetCS(TRUE) + END; + attr := attr.next(ATTR) + END +END Prolog; + + +PROCEDURE Parse; +BEGIN + Prolog; + binary := FALSE; + RF.Next(ch); + WHILE ch = "<" DO + IF ~Comment() THEN + ReadTag + END + ELSIF Space() & ~binary DO + ReadSpace + ELSIF (ch # 0X) DO + ReadWord + END +END Parse; + + +PROCEDURE Open*(FileName: S.STRING); +BEGIN + Root := CreateTag(); + Current := Root; + Header := NIL; + FB := NIL; + num := 0; + RF.Load(FileName); + Parse; + SU.ErrorIf(Current # Root, 10) +END Open; + + +PROCEDURE Init; +BEGIN + S.utf8(8212, tire1); + S.utf8(8211, tire2); + S.utf8( 160, nbsp); + S.utf8(8230, ellipsis); + S.utf8(8217, apo); + S.utf8(8220, quot1); + S.utf8(8221, quot2); + S.utf8(8222, quot3); + S.utf8(8216, quot4); + S.utf8(8218, quot5); + S.utf8(8249, quot6); + S.utf8(8250, quot7); + S.utf8(8470, number); + S.utf8(8208, dash1); + S.utf8(8209, dash2); + S.utf8(8226, bullet); + S.utf8(8364, euro); + Tags := V.create(1024) +END Init; + + +BEGIN + Init +END XML. diff --git a/programs/other/fb2reader/SRC/box_lib.ob07 b/programs/other/fb2reader/SRC/box_lib.ob07 new file mode 100644 index 0000000000..f9683d250f --- /dev/null +++ b/programs/other/fb2reader/SRC/box_lib.ob07 @@ -0,0 +1,236 @@ +(* + Copyright 2016, 2017, 2020, 2022 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE box_lib; + +IMPORT sys := SYSTEM, KOSAPI; + + +CONST + + CHECKBOX_IS_SET* = 1; + + +TYPE + + checkbox* = POINTER TO RECORD + + left_s: INTEGER; + top_s: INTEGER; + ch_text_margin*: INTEGER; + color: INTEGER; + border_color: INTEGER; + text_color: INTEGER; + text: INTEGER; + flags*: SET; + + (* Users can use members above this *) + size_of_str: INTEGER + + END; + + + scrollbar* = POINTER TO RECORD + + x_w: INTEGER; + y_h*: INTEGER; + btn_height: INTEGER; + typ: INTEGER; + max_area*: INTEGER; + cur_area*: INTEGER; + position*: INTEGER; + back_color: INTEGER; + front_color: INTEGER; + line_color: INTEGER; + redraw: INTEGER; + + delta: WCHAR; + delta2: WCHAR; + r_size_x: WCHAR; + r_start_x: WCHAR; + r_size_y: WCHAR; + r_start_y: WCHAR; + + m_pos: INTEGER; + m_pos2: INTEGER; + m_keys: INTEGER; + run_size: INTEGER; + position2: INTEGER; + work_size: INTEGER; + all_redraw: INTEGER; + ar_offset: INTEGER + + END; + + edit_box* = POINTER TO RECORD + width*, + left, + top, + color, + shift_color, + focus_border_color, + blur_border_color, + text_color*, + max: INTEGER; + text*: INTEGER; + mouse_variable: INTEGER; + flags*, + + size, + pos: INTEGER; + (* The following struct members are not used by the users of API *) + offset, cl_curs_x, cl_curs_y, shift, shift_old, height, char_width: INTEGER + END; + + +PROCEDURE [stdcall, "box_lib.obj", ""] check_box_draw2* (cb: checkbox); END; +PROCEDURE [stdcall, "box_lib.obj", ""] check_box_mouse2* (cb: checkbox); END; +PROCEDURE [stdcall, "box_lib.obj", ""] init_checkbox2 (cb: checkbox); END; + +PROCEDURE [stdcall, "box_lib.obj", ""] scrollbar_h_draw* (sb: scrollbar); END; +PROCEDURE [stdcall, "box_lib.obj", ""] scrollbar_h_mouse* (sb: scrollbar); END; +PROCEDURE [stdcall, "box_lib.obj", ""] scrollbar_v_draw* (sb: scrollbar); END; +PROCEDURE [stdcall, "box_lib.obj", ""] scrollbar_v_mouse* (sb: scrollbar); END; + +PROCEDURE [stdcall, "box_lib.obj", ""] edit_box_draw* (eb: edit_box); END; +PROCEDURE [stdcall, "box_lib.obj", ""] edit_box_key_safe* (eb: edit_box; key: INTEGER); END; +PROCEDURE [stdcall, "box_lib.obj", ""] edit_box_mouse* (eb: edit_box); END; +PROCEDURE [stdcall, "box_lib.obj", ""] edit_box_set_text* (eb: edit_box; text: INTEGER); END; + + +PROCEDURE edit_box_get_value* (text: edit_box; VAR str: ARRAY OF CHAR); +VAR + ptr, max, i: INTEGER; + +BEGIN + ptr := text.text; + max := text.max; + ASSERT(max < LEN(str)); + i := 0; + REPEAT + sys.GET(ptr, str[i]); + INC(i); + INC(ptr) + UNTIL (str[i - 1] = 0X) OR (i = max); + str[i] := 0X +END edit_box_get_value; + + +PROCEDURE memset(adr: INTEGER; c: CHAR; n: INTEGER); +BEGIN + WHILE n > 0 DO + sys.PUT(adr, c); + INC(adr); + DEC(n) + END +END memset; + + +PROCEDURE check_box_set_value* (cb: checkbox; value: BOOLEAN); +BEGIN + IF cb # NIL THEN + IF value THEN + INCL(cb.flags, CHECKBOX_IS_SET) + ELSE + EXCL(cb.flags, CHECKBOX_IS_SET) + END + END +END check_box_set_value; + + +PROCEDURE check_box_get_value* (cb: checkbox): BOOLEAN; +VAR res: BOOLEAN; +BEGIN + res := FALSE; + IF cb # NIL THEN + res := CHECKBOX_IS_SET IN cb.flags + END + RETURN res +END check_box_get_value; + + +PROCEDURE kolibri_new_check_box* (tlx, tly, sizex, sizey, label_text, text_margin: INTEGER): checkbox; +VAR new_checkbox: checkbox; +BEGIN + NEW(new_checkbox); + new_checkbox.left_s := tlx * 65536 + sizex; + new_checkbox.top_s := tly * 65536 + sizey; + new_checkbox.ch_text_margin := text_margin; + new_checkbox.color := 80808080H; + new_checkbox.border_color := 0000FF00H; + new_checkbox.text_color := 00000000H; + new_checkbox.text := label_text; + new_checkbox.flags := {3}; + init_checkbox2(new_checkbox) + RETURN new_checkbox +END kolibri_new_check_box; + + +PROCEDURE kolibri_scrollbar*(sb: scrollbar; x_w, y_h, btn_height, max_area, cur_area, position, back_color, front_color, line_color, typ: INTEGER): scrollbar; +BEGIN + memset(sys.ADR(sb^), 0X, sys.SIZE(scrollbar)); + sb.x_w := x_w; + sb.y_h := y_h; + sb.btn_height := btn_height; + sb.typ := typ; + sb.max_area := max_area; + sb.cur_area := cur_area; + sb.position := position; + sb.line_color := line_color; + sb.back_color := back_color; + sb.front_color := front_color; + sb.ar_offset := 1; + sb.all_redraw := 1 + RETURN sb +END kolibri_scrollbar; + + +PROCEDURE kolibri_new_scrollbar*(x_w, y_h, btn_height, max_area, cur_area, position, back_color, front_color, line_color, typ: INTEGER): scrollbar; +VAR sb: scrollbar; +BEGIN + NEW(sb); + RETURN kolibri_scrollbar(sb, x_w, y_h, btn_height, max_area, cur_area, position, back_color, front_color, line_color, typ) +END kolibri_new_scrollbar; + + +PROCEDURE kolibri_new_edit_box* (tlx, tly, width, max_chars: INTEGER): edit_box; +VAR + new_textbox: edit_box; + +BEGIN + NEW(new_textbox); + + new_textbox.width := width; + new_textbox.left := tlx; + new_textbox.top := tly; + new_textbox.color := 0FFFFFFH; + new_textbox.shift_color := 06A9480H; + new_textbox.focus_border_color := 0; + new_textbox.blur_border_color := 06A9480H; + new_textbox.text_color := 30000000H; + new_textbox.max := max_chars; + new_textbox.text := KOSAPI.malloc(max_chars + 2); + new_textbox.mouse_variable := 0; + new_textbox.flags := 0 + + RETURN new_textbox +END kolibri_new_edit_box; + + +END box_lib. diff --git a/programs/other/fb2reader/SRC/encode.ob07 b/programs/other/fb2reader/SRC/encode.ob07 new file mode 100644 index 0000000000..fa2621d28b --- /dev/null +++ b/programs/other/fb2reader/SRC/encode.ob07 @@ -0,0 +1,149 @@ +(* + Copyright 2016 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE Encode; + +IMPORT S := Strings; + +TYPE + + CP* = ARRAY 256 OF RECORD code*, len*: INTEGER; utf8*: S.UTF8 END; + + +VAR + + W1250*, W1251*, W1252*, CP866*: CP; + + +PROCEDURE InitCP(VAR cp: CP); +VAR i: INTEGER; +BEGIN + FOR i := 0H TO 7FH DO + cp[i].code := i + END; + FOR i := 0H TO 0FFH DO + S.utf8(cp[i].code, cp[i].utf8); + cp[i].len := LENGTH(cp[i].utf8) + END +END InitCP; + + +PROCEDURE Init8(VAR cp: CP; VAR n: INTEGER; a, b, c, d, e, f, g, h: INTEGER); +BEGIN + cp[n].code := a; INC(n); + cp[n].code := b; INC(n); + cp[n].code := c; INC(n); + cp[n].code := d; INC(n); + cp[n].code := e; INC(n); + cp[n].code := f; INC(n); + cp[n].code := g; INC(n); + cp[n].code := h; INC(n); +END Init8; + + +PROCEDURE InitW1250(VAR cp: CP); +VAR n: INTEGER; +BEGIN + n := 80H; + Init8(cp, n, 20ACH, 20H, 201AH, 20H, 201EH, 2026H, 2020H, 2021H); + Init8(cp, n, 20H, 2030H, 0160H, 2039H, 015AH, 0164H, 017DH, 0179H); + Init8(cp, n, 20H, 2018H, 2019H, 201CH, 201DH, 2022H, 2013H, 2014H); + Init8(cp, n, 20H, 2122H, 0161H, 203AH, 015BH, 0165H, 017EH, 017AH); + Init8(cp, n, 00A0H, 02C7H, 02D8H, 0141H, 00A4H, 0104H, 00A6H, 00A7H); + Init8(cp, n, 00A8H, 00A9H, 015EH, 00ABH, 00ACH, 00ADH, 00AEH, 017BH); + Init8(cp, n, 00B0H, 00B1H, 02DBH, 0142H, 00B4H, 00B5H, 00B6H, 00B7H); + Init8(cp, n, 00B8H, 0105H, 015FH, 00BBH, 013DH, 02DDH, 013EH, 017CH); + Init8(cp, n, 0154H, 00C1H, 00C2H, 0102H, 00C4H, 0139H, 0106H, 00C7H); + Init8(cp, n, 010CH, 00C9H, 0118H, 00CBH, 011AH, 00CDH, 00CEH, 010EH); + Init8(cp, n, 0110H, 0143H, 0147H, 00D3H, 00D4H, 0150H, 00D6H, 00D7H); + Init8(cp, n, 0158H, 016EH, 00DAH, 0170H, 00DCH, 00DDH, 0162H, 00DFH); + Init8(cp, n, 0155H, 00E1H, 00E2H, 0103H, 00E4H, 013AH, 0107H, 00E7H); + Init8(cp, n, 010DH, 00E9H, 0119H, 00EBH, 011BH, 00EDH, 00EEH, 010FH); + Init8(cp, n, 0111H, 0144H, 0148H, 00F3H, 00F4H, 0151H, 00F6H, 00F7H); + Init8(cp, n, 0159H, 016FH, 00FAH, 0171H, 00FCH, 00FDH, 0163H, 02D9H); + InitCP(cp) +END InitW1250; + + +PROCEDURE InitW1251(VAR cp: CP); +VAR n, i: INTEGER; +BEGIN + n := 80H; + Init8(cp, n, 0402H, 0403H, 201AH, 0453H, 201EH, 2026H, 2020H, 2021H); + Init8(cp, n, 20ACH, 2030H, 0409H, 2039H, 040AH, 040CH, 040BH, 040FH); + Init8(cp, n, 0452H, 2018H, 2019H, 201CH, 201DH, 2022H, 2013H, 2014H); + Init8(cp, n, 20H, 2122H, 0459H, 203AH, 045AH, 045CH, 045BH, 045FH); + Init8(cp, n, 00A0H, 040EH, 045EH, 0408H, 00A4H, 0490H, 00A6H, 00A7H); + Init8(cp, n, 0401H, 00A9H, 0404H, 00ABH, 00ACH, 00ADH, 00AEH, 0407H); + Init8(cp, n, 00B0H, 00B1H, 0406H, 0456H, 0491H, 00B5H, 00B6H, 00B7H); + Init8(cp, n, 0451H, 2116H, 0454H, 00BBH, 0458H, 0405H, 0455H, 0457H); + FOR i := 0410H TO 044FH DO + cp[i - 350H].code := i + END; + InitCP(cp) +END InitW1251; + + +PROCEDURE InitW1252(VAR cp: CP); +VAR n, i: INTEGER; +BEGIN + n := 80H; + Init8(cp, n, 20ACH, 20H, 201AH, 0192H, 201EH, 2026H, 2020H, 2021H); + Init8(cp, n, 02C6H, 2030H, 0160H, 2039H, 0152H, 20H, 017DH, 20H); + Init8(cp, n, 20H, 2018H, 2019H, 201CH, 201DH, 2022H, 2013H, 2014H); + Init8(cp, n, 02DCH, 2122H, 0161H, 203AH, 0153H, 20H, 017EH, 0178H); + FOR i := 0A0H TO 0FFH DO + cp[i].code := i + END; + InitCP(cp) +END InitW1252; + + +PROCEDURE InitCP866(VAR cp: CP); +VAR n, i: INTEGER; +BEGIN + FOR i := 0410H TO 043FH DO + cp[i - 0410H + 80H].code := i + END; + FOR i := 0440H TO 044FH DO + cp[i - 0440H + 0E0H].code := i + END; + + n := 0B0H; + Init8(cp, n, 2591H, 2592H, 2593H, 2502H, 2524H, 2561H, 2562H, 2556H); + Init8(cp, n, 2555H, 2563H, 2551H, 2557H, 255DH, 255CH, 255BH, 2510H); + Init8(cp, n, 2514H, 2534H, 252CH, 251CH, 2500H, 253CH, 255EH, 255FH); + Init8(cp, n, 255AH, 2554H, 2569H, 2566H, 2560H, 2550H, 256CH, 2567H); + Init8(cp, n, 2568H, 2564H, 2565H, 2559H, 2558H, 2552H, 2553H, 256BH); + Init8(cp, n, 256AH, 2518H, 250CH, 2588H, 2584H, 258CH, 2590H, 2580H); + + n := 0F0H; + Init8(cp, n, 0401H, 0451H, 0404H, 0454H, 0407H, 0457H, 040EH, 045EH); + Init8(cp, n, 00B0H, 2219H, 00B7H, 221AH, 2116H, 00A4H, 25A0H, 00A0H); + + InitCP(cp) +END InitCP866; + + +BEGIN + InitW1250(W1250); + InitW1251(W1251); + InitW1252(W1252); + InitCP866(CP866); +END Encode. diff --git a/programs/other/fb2reader/SRC/kfonts.ob07 b/programs/other/fb2reader/SRC/kfonts.ob07 new file mode 100644 index 0000000000..01a2f0c40b --- /dev/null +++ b/programs/other/fb2reader/SRC/kfonts.ob07 @@ -0,0 +1,466 @@ +(* + Copyright 2018-2020 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE kfonts; + +IMPORT File, sys := SYSTEM, LISTS, KOSAPI, S := Strings; + + +CONST + + MIN_FONT_SIZE = 8; + MAX_FONT_SIZE = 46; + + bold* = 1; + //italic* = 2; + underline* = 4; + strike_through* = 8; + //smoothing* = 16; + //bpp32* = 32; + + +TYPE + + FNAME = ARRAY 2048 OF CHAR; + + FILE = RECORD + + name: FNAME; + data, size, pos: INTEGER + + END; + + PIX = POINTER TO RECORD (LISTS.ITEM) + + x, y: INTEGER + + END; + + FONT = POINTER TO RECORD + + chars, + smooth: ARRAY 256 OF LISTS.LIST; + width: ARRAY 256 OF INTEGER; + height: INTEGER; + file: FILE + + END; + + TFont* = FONT; + + +PROCEDURE getch (VAR F: FILE): CHAR; +VAR + ch: CHAR; +BEGIN + IF (F.pos >= 0) & (F.pos < F.size) THEN + sys.GET(F.data + F.pos, ch); + INC(F.pos) + ELSE + ch := 0X + END + RETURN ch +END getch; + + +PROCEDURE getint (VAR F: FILE): INTEGER; +VAR + i: INTEGER; +BEGIN + IF (F.pos >= 0) & (F.pos < F.size) THEN + sys.GET(F.data + F.pos, i); + INC(F.pos, 4) + ELSE + i := 0 + END + RETURN i +END getint; + + +PROCEDURE getpix (list: LISTS.LIST; x, y: INTEGER): BOOLEAN; +VAR + pix: PIX; + res: BOOLEAN; + +BEGIN + res := FALSE; + pix := list.first(PIX); + WHILE pix # NIL DO + IF (pix.x = x) & (pix.y = y) THEN + res := TRUE; + pix := NIL + ELSE + pix := pix.next(PIX) + END + END + + RETURN res +END getpix; + + +PROCEDURE process (font: FONT; n: INTEGER); +VAR + xsize, ysize, size, ch_size, xmax: INTEGER; + ptr: INTEGER; i, c: INTEGER; + s: SET; x, y: INTEGER; + eoc: BOOLEAN; + + pix: PIX; chr, smooth: LISTS.LIST; +BEGIN + font.file.pos := n * 4; + ptr := getint(font.file) + 156; + font.file.pos := ptr; + size := getint(font.file); + INC(font.file.pos, size - 6); + xsize := ORD(getch(font.file)); + ysize := ORD(getch(font.file)); + ch_size := (size - 6) DIV 256; + + INC(ptr, 4); + + font.height := ysize; + + FOR c := 0 TO 255 DO + chr := font.chars[c]; + smooth := font.smooth[c]; + font.file.pos := ptr + c * ch_size; + + x := 0; y := 0; eoc := FALSE; + xmax := 0; + + eoc := (xsize = 0) OR (ysize = 0); + + WHILE ~eoc DO + + s := BITS(getint(font.file)); + i := 0; + + WHILE i <= 31 DO + IF i IN s THEN + NEW(pix); + IF x > xmax THEN + xmax := x + END; + pix.x := x; + pix.y := y; + LISTS.push(chr, pix) + END; + INC(x); + IF x = xsize THEN + x := 0; + INC(y); + IF y = ysize THEN + eoc := TRUE; + i := 31 + END + END; + INC(i) + END + + END; + + FOR x := 0 TO xsize - 2 DO + FOR y := 0 TO ysize - 2 DO + IF getpix(chr, x, y) & getpix(chr, x + 1, y + 1) & + ~getpix(chr, x + 1, y) & ~getpix(chr, x, y + 1) THEN + + IF ~getpix(smooth, x + 1, y) THEN + NEW(pix); + pix.x := x + 1; + pix.y := y; + LISTS.push(smooth, pix); + END; + + IF ~getpix(smooth, x, y + 1) THEN + NEW(pix); + pix.x := x; + pix.y := y + 1; + LISTS.push(smooth, pix) + END + END + END + END; + + FOR x := 1 TO xsize - 1 DO + FOR y := 0 TO ysize - 2 DO + IF getpix(chr, x, y) & getpix(chr, x - 1, y + 1) & + ~getpix(chr, x - 1, y) & ~getpix(chr, x, y + 1) THEN + + IF ~getpix(smooth, x - 1, y) THEN + NEW(pix); + pix.x := x - 1; + pix.y := y; + LISTS.push(smooth, pix); + END; + + IF ~getpix(smooth, x, y + 1) THEN + NEW(pix); + pix.x := x; + pix.y := y + 1; + LISTS.push(smooth, pix) + END + END + END + END; + + IF xmax = 0 THEN + xmax := xsize DIV 3 + END; + + font.width[c] := xmax + + END + +END process; + + +PROCEDURE getrgb(color: INTEGER; VAR r, g, b: INTEGER); +BEGIN + b := ORD(BITS(color) * {0..7}); + g := ORD(BITS(LSR(color, 8)) * {0..7}); + r := ORD(BITS(LSR(color, 16)) * {0..7}) +END getrgb; + + +PROCEDURE rgb(r, g, b: INTEGER): INTEGER; + RETURN b + LSL(g, 8) + LSL(r, 16) +END rgb; + + +PROCEDURE OutChar (font: FONT; canvas: INTEGER; x, y: INTEGER; c: CHAR; color: INTEGER); +VAR + xsize, ysize: INTEGER; + pix: PIX; + bkcolor: INTEGER; + r0, b0, g0, r, g, b: INTEGER; + ptr: INTEGER; +BEGIN + sys.GET(canvas, xsize); + sys.GET(canvas, ysize); + INC(canvas, 8); + getrgb(color, r0, g0, b0); + + pix := font.chars[ORD(c)].first(PIX); + WHILE pix # NIL DO + sys.PUT(canvas + ((pix.y + y) * xsize + (pix.x + x)) * 4, color); + pix := pix.next(PIX) + END; + + pix := font.smooth[ORD(c)].first(PIX); + WHILE pix # NIL DO + ptr := canvas + ((pix.y + y) * xsize + (pix.x + x)) * 4; + sys.GET(ptr, bkcolor); + getrgb(bkcolor, r, g, b); + + r := (r * 7 + r0 * 2) DIV 9; + g := (g * 7 + g0 * 2) DIV 9; + b := (b * 7 + b0 * 2) DIV 9; + + sys.PUT(ptr, rgb(r, g, b)); + pix := pix.next(PIX) + END + +END OutChar; + + +PROCEDURE TextHeight* (font: FONT): INTEGER; +VAR + res: INTEGER; + +BEGIN + IF font # NIL THEN + res := font.height + ELSE + res := 0 + END + + RETURN res +END TextHeight; + + + +PROCEDURE TextOut* (font: FONT; canvas: INTEGER; x, y: INTEGER; text: INTEGER; length: INTEGER; color: INTEGER; flags: INTEGER); +VAR + c: CHAR; + x1: INTEGER; + +BEGIN + IF font # NIL THEN + x1 := x; + WHILE length > 0 DO + sys.GET(text, c); + INC(text); + DEC(length); + OutChar(font, canvas, x, y, c, color); + IF BITS(bold) * BITS(flags) = BITS(bold) THEN + INC(x); + OutChar(font, canvas, x, y, c, color) + END; + INC(x, font.width[ORD(c)]) + END; + IF length = -1 THEN + sys.GET(text, c); + INC(text); + WHILE c # 0X DO + OutChar(font, canvas, x, y, c, color); + IF BITS(bold) * BITS(flags) = BITS(bold) THEN + INC(x); + OutChar(font, canvas, x, y, c, color) + END; + INC(x, font.width[ORD(c)]); + sys.GET(text, c); + INC(text) + END + END + END +END TextOut; + + +PROCEDURE TextWidth* (font: FONT; text: INTEGER; length: INTEGER; flags: INTEGER): INTEGER; +VAR + c: CHAR; + res: INTEGER; + +BEGIN + res := 0; + + IF font # NIL THEN + WHILE length > 0 DO + sys.GET(text, c); + INC(text); + DEC(length); + IF BITS(bold) * BITS(flags) = BITS(bold) THEN + INC(res) + END; + INC(res, font.width[ORD(c)]) + END; + IF length = -1 THEN + sys.GET(text, c); + INC(text); + WHILE c # 0X DO + IF BITS(bold) * BITS(flags) = BITS(bold) THEN + INC(res) + END; + INC(res, font.width[ORD(c)]); + sys.GET(text, c); + INC(text) + END + END + END + + RETURN res +END TextWidth; + + +PROCEDURE Enabled*(font: FONT; size: INTEGER): BOOLEAN; +VAR + offset, temp: INTEGER; + +BEGIN + offset := -1; + IF (MIN_FONT_SIZE <= size) & (size <= MAX_FONT_SIZE) & (font # NIL) THEN + temp := font.file.data + (size - 8) * 4; + IF (font.file.data <= temp) & (temp <= font.file.size + font.file.data - 4) THEN + sys.GET(temp, offset) + END + END + RETURN offset # -1 +END Enabled; + + +PROCEDURE LoadFont* (fname: ARRAY OF CHAR): FONT; +VAR + font: FONT; + c: INTEGER; + ptr: INTEGER; + +BEGIN + NEW(font); + IF font # NIL THEN + font.file.data := File.Load(fname, font.file.size); + IF font.file.data # 0 THEN + ptr := KOSAPI.malloc(font.file.size + 4096); + IF ptr # 0 THEN + + sys.MOVE(font.file.data, ptr, font.file.size); + font.file.data := KOSAPI.sysfunc3(68, 13, font.file.data); + font.file.data := ptr; + + font.file.pos := 0; + COPY(fname, font.file.name); + + FOR c := 0 TO 255 DO + font.chars[c] := LISTS.create(NIL); + font.smooth[c] := LISTS.create(NIL); + font.width[c] := 0; + font.height := 0 + END + + ELSE + font.file.data := KOSAPI.sysfunc3(68, 13, font.file.data); + DISPOSE(font) + END + + ELSE + DISPOSE(font) + END + END + + RETURN font +END LoadFont; + + +PROCEDURE Destroy* (VAR font: FONT); +VAR + c: INTEGER; + +BEGIN + IF font # NIL THEN + FOR c := 0 TO 255 DO + LISTS.destroy(font.chars[c]); + LISTS.destroy(font.smooth[c]); + END; + IF font.file.data # 0 THEN + font.file.data := KOSAPI.sysfunc3(68, 13, font.file.data) + END; + DISPOSE(font) + END +END Destroy; + + +PROCEDURE SetSize* (VAR font: FONT; size: INTEGER): BOOLEAN; +VAR + res: BOOLEAN; + fname: FNAME; + +BEGIN + IF Enabled(font, size) THEN + fname := font.file.name; + Destroy(font); + font := LoadFont(fname); + process(font, size - 8); + res := TRUE + ELSE + res := FALSE + END + RETURN res +END SetSize; + + +END kfonts. diff --git a/programs/other/fb2reader/SRC/tables.ob07 b/programs/other/fb2reader/SRC/tables.ob07 new file mode 100644 index 0000000000..4b6641acd7 --- /dev/null +++ b/programs/other/fb2reader/SRC/tables.ob07 @@ -0,0 +1,256 @@ +(* + Copyright 2016 Anton Krotov + + This file is part of fb2read. + + fb2read 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 3 of the License, or + (at your option) any later version. + + fb2read 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 fb2read. If not, see . +*) + +MODULE tables; + +IMPORT V := Vector; + + +TYPE + + + Int = POINTER TO RECORD (V.ANYREC) value: INTEGER END; + + Cell = POINTER TO RECORD (V.ANYREC) top, bottom, left, right, colspan, rowspan: INTEGER END; + + Tab = POINTER TO RECORD (V.ANYREC) col, row: INTEGER END; + + Table* = POINTER TO RECORD + + tab : V.VECTOR; + h_lines : V.VECTOR; + v_lines : V.VECTOR; + cells* : V.VECTOR; + + tab_x, tab_y, max_length: INTEGER + + END; + + +PROCEDURE GetCell (t: Table; cell: INTEGER): Cell; +VAR any: V.ANYPTR; +BEGIN + any := V.get(t.cells, cell) + RETURN any(Cell) +END GetCell; + + +PROCEDURE GetInt (v: V.VECTOR; idx: INTEGER): INTEGER; +VAR any: V.ANYPTR; +BEGIN + any := V.get(v, idx) + RETURN any(Int).value +END GetInt; + + +PROCEDURE PutInt (v: V.VECTOR; idx, value: INTEGER); +VAR any: V.ANYPTR; +BEGIN + any := V.get(v, idx); + any(Int).value := value +END PutInt; + + +PROCEDURE PushInt (v: V.VECTOR; value: INTEGER); +VAR int: Int; +BEGIN + NEW(int); + int.value := value; + V.push(v, int) +END PushInt; + + +PROCEDURE get_tab_xy (t: Table; x, y: INTEGER): BOOLEAN; +VAR i: INTEGER; + tab: Tab; any: V.ANYPTR; + res: BOOLEAN; +BEGIN + res := FALSE; + i := 0; + WHILE (i < t.tab.count) & ~res DO + any := V.get(t.tab, i); + tab := any(Tab); + res := (tab.col = x) & (tab.row = y); + INC(i) + END + RETURN res +END get_tab_xy; + + +PROCEDURE set_tab_xy (t: Table; x, y: INTEGER); +VAR tab: Tab; +BEGIN + NEW(tab); + tab.col := x; + tab.row := y; + V.push(t.tab, tab) +END set_tab_xy; + + +PROCEDURE tr* (t: Table); +BEGIN + INC(t.tab_y); + WHILE t.h_lines.count < t.tab_y + 10 DO + PushInt(t.h_lines, 0) + END; + t.tab_x := 0; + WHILE get_tab_xy(t, t.tab_x, t.tab_y) DO + INC(t.tab_x); + WHILE t.v_lines.count < t.tab_x + 10 DO + PushInt(t.v_lines, 0) + END + END +END tr; + + +PROCEDURE td* (t: Table; colspan, rowspan: INTEGER); +VAR i, j: INTEGER; _cell: Cell; +BEGIN + FOR i := t.tab_x TO t.tab_x + colspan - 1 DO + FOR j := t.tab_y TO t.tab_y + rowspan - 1 DO + set_tab_xy(t, i, j); + IF i > t.max_length THEN + t.max_length := i + END + END + END; + NEW(_cell); + _cell.left := t.tab_x; + _cell.top := t.tab_y; + _cell.right := t.tab_x + colspan; + WHILE t.v_lines.count < _cell.right + 10 DO + PushInt(t.v_lines, 0) + END; + _cell.bottom := t.tab_y + rowspan; + WHILE t.h_lines.count < _cell.bottom + 10 DO + PushInt(t.h_lines, 0) + END; + _cell.colspan := colspan; + _cell.rowspan := rowspan; + V.push(t.cells, _cell); + WHILE get_tab_xy(t, t.tab_x, t.tab_y) DO + INC(t.tab_x); + WHILE t.v_lines.count < t.tab_x + 10 DO + PushInt(t.v_lines, 0) + END + END +END td; + + +PROCEDURE set_width* (t: Table; cell, width: INTEGER); +VAR left, right, old_width, d_width, i: INTEGER; _cell: Cell; +BEGIN + _cell := GetCell(t, cell); + right := GetInt(t.v_lines, _cell.right); + left := GetInt(t.v_lines, _cell.left); + old_width := right - left; + d_width := width - old_width; + PutInt(t.v_lines, _cell.right, left + width); + FOR i := _cell.right + 1 TO t.v_lines.count - 1 DO + PutInt(t.v_lines, i, GetInt(t.v_lines, i) + d_width) + END +END set_width; + + +PROCEDURE set_height* (t: Table; cell, height: INTEGER); +VAR top, bottom, old_height, d_height, i: INTEGER; _cell: Cell; +BEGIN + _cell := GetCell(t, cell); + top := GetInt(t.h_lines, _cell.top); + bottom := GetInt(t.h_lines, _cell.bottom); + old_height := bottom - top; + d_height := height - old_height; + PutInt(t.h_lines, _cell.bottom, top + height); + FOR i := _cell.bottom + 1 TO t.h_lines.count - 1 DO + PutInt(t.h_lines, i, GetInt(t.h_lines, i) + d_height) + END +END set_height; + + +PROCEDURE get_height* (t: Table; cell: INTEGER): INTEGER; +VAR _cell: Cell; +BEGIN + _cell := GetCell(t, cell) + RETURN GetInt(t.h_lines, _cell.bottom) - GetInt(t.h_lines, _cell.top) +END get_height; + + +PROCEDURE get_width* (t: Table; cell: INTEGER): INTEGER; +VAR _cell: Cell; +BEGIN + _cell := GetCell(t, cell) + RETURN GetInt(t.v_lines, _cell.right) - GetInt(t.v_lines, _cell.left) +END get_width; + + +PROCEDURE get_x* (t: Table; cell: INTEGER): INTEGER; +VAR _cell: Cell; +BEGIN + _cell := GetCell(t, cell) + RETURN GetInt(t.v_lines, _cell.left) +END get_x; + + +PROCEDURE get_y* (t: Table; cell: INTEGER): INTEGER; +VAR _cell: Cell; +BEGIN + _cell := GetCell(t, cell) + RETURN GetInt(t.h_lines, _cell.top) +END get_y; + + +PROCEDURE get_table_height* (t: Table): INTEGER; + RETURN GetInt(t.h_lines, t.tab_y + 1) +END get_table_height; + + +PROCEDURE table* (t: Table; tab_width: INTEGER; open: BOOLEAN); +VAR i, width: INTEGER; _cell: Cell; +BEGIN + IF open THEN + t.cells := V.create(1024); + t.v_lines := V.create(1024); + t.h_lines := V.create(1024); + t.tab := V.create(1024); + t.tab_x := 0; + t.tab_y := -1; + t.max_length := 0; + ELSE + width := tab_width DIV (t.max_length + 1); + FOR i := 0 TO t.cells.count - 1 DO + _cell := GetCell(t, i); + set_width(t, i, width * _cell.colspan) + END + END +END table; + + +PROCEDURE destroy* (t: Table); +BEGIN + IF t # NIL THEN + V.destroy(t.tab, NIL); + V.destroy(t.h_lines, NIL); + V.destroy(t.v_lines, NIL); + V.destroy(t.cells, NIL); + DISPOSE(t) + END +END destroy; + + +END tables.