diff --git a/CMakeLists.txt b/CMakeLists.txt index f75817f..6fdd0ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,31 +1,50 @@ cmake_minimum_required(VERSION 2.8.12) if (POLICY CMP0048) - cmake_policy(SET CMP0048 NEW) + cmake_policy(SET CMP0048 NEW) endif (POLICY CMP0048) -project(base16384 VERSION 2.2.5) +project(base16384 VERSION 2.3.0) + +add_definitions(-DBASE16384_VERSION="${PROJECT_VERSION}") +add_definitions(-DBASE16384_VERSION_DATE="April 5th 2024") + +message(STATUS "Testing endian...") +include(TestBigEndian) +test_big_endian(isBigEndian) +message(STATUS "Is big endian: ${isBigEndian}.") +if (${isBigEndian}) + add_definitions(-DWORDS_BIGENDIAN) +endif () + +if (BUILD STREQUAL "test") + add_definitions(-DBASE16384_BUFSZ_FACTOR=1) +endif () add_executable(base16384_b base16384.c) -include(TestBigEndian) -test_big_endian(isBigEndian) -if (${isBigEndian}) - add_definitions(-DWORDS_BIGENDIAN) -endif() - -IF(CMAKE_SIZEOF_VOID_P EQUAL 8) - add_library(base16384 SHARED file.c base1464.c) - add_library(base16384_s STATIC file.c base1464.c) -ELSE() - add_library(base16384 SHARED file.c base1432.c) - add_library(base16384_s STATIC file.c base1432.c) -ENDIF() +IF ((NOT FORCE_32BIT) AND CMAKE_SIZEOF_VOID_P EQUAL 8) + message(STATUS "Adding 64bit libraries...") + add_definitions(-DIS_64BIT_PROCESSOR) + add_library(base16384 SHARED wrap.c file.c base1464.c) + add_library(base16384_s STATIC wrap.c file.c base1464.c) +ELSE () + message(STATUS "Adding 32bit libraries...") + add_library(base16384 SHARED wrap.c file.c base1432.c) + add_library(base16384_s STATIC wrap.c file.c base1432.c) +ENDIF () set_target_properties(base16384_b PROPERTIES OUTPUT_NAME base16384) set_target_properties(base16384_s PROPERTIES OUTPUT_NAME base16384) set_target_properties(base16384 PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) +message(STATUS "Linking libraries...") target_link_libraries(base16384_b base16384_s) +if (BUILD STREQUAL "test") + message(STATUS "Building test...") + enable_testing() + add_subdirectory(test) +endif () + INSTALL(TARGETS base16384_b RUNTIME DESTINATION bin) INSTALL(TARGETS base16384 LIBRARY DESTINATION lib) INSTALL(TARGETS base16384_s ARCHIVE DESTINATION lib) diff --git a/README.md b/README.md index e6bbd8b..32f9ee9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,9 @@ Encode binary file to printable utf16be, and vice versa. -## Description 说明 +## Description +> 说明 + Use 16384 Chinene characters (from \u4E00 to \u8DFF) as the "alphabet", just like what base64 did. 使用16384个汉字(从`\u4E00`到`\u8DFF`)作为字符表,就像base64用64个字符作为字符表一样。 @@ -14,31 +16,38 @@ If length of the data has a remainder after moduled by 7, we will use \u3Dxx to 使用`\u3Dxx`附加在末尾以表示编码时数据不满7位的个数,其范围在01~06。 -## Benefits 优点 +## Benefits +> 优点 + Save more space and since the code 0x0000 is encoded to "一", finding zero space seems to be easier. 相较base64节省更多空间,更容易发现二进制文件的规律。 -## Usage 使用说明 +## Usage +> 用法 -### Install from Debian Bookworm or higher 从 Debian Bookworm 或更高版本安装 +### Install from Debian Bookworm or higher +> 从 Debian Bookworm 或更高版本安装 ```bash sudo apt install base16384 ``` -### Install from Homebrew 从 Homebrew 安装 +### Install from Homebrew +> 从 Homebrew 安装 ```bash brew install base16384 ``` -### Install from my PPA in Ubuntu 乌班图下从我的 PPA 安装 +### Install from my PPA in Ubuntu +> 乌班图下从我的 PPA 安装 ```bash sudo add-apt-repository ppa:fumiama/ppa sudo apt-get update sudo apt-get install base16384 ``` -### Build from source code 编译 +### Build from source code +> 编译 Clone this repo first. @@ -67,33 +76,39 @@ Now you can encode/decode a file by commands below. ```kotlin Usage: -base16384 [-edt] [inputfile] [outputfile] - -e encode - -d decode - -t show spend time - inputfile pass - to read from stdin - outputfile pass - to write to stdout +base16384 [-edtn] [inputfile] [outputfile] + -e encode (default) + -d decode + -t show spend time + -n don't write utf16be file header (0xFEFF) + -c embed or validate checksum in remainder + inputfile pass - to read from stdin + outputfile pass - to write to stdout ``` -## Examples 用例 -1. Encode simple text 简单文本编码 +## Examples +> 用例 +1. Encode simple text + > 简单文本编码 -```bash -echo -n "1234567" | base16384 -e - - | iconv -f utf-16be -t utf-8 -婌焳廔萷 -``` + ```bash + echo -n "1234567" | base16384 -e - - | iconv -f utf-16be -t utf-8 + 婌焳廔萷 + ``` -3. Decode simple text 简单文本解码 +3. Decode simple text + > 简单文本解码 -```bash -echo -n "婌焳廔萷" | iconv -f utf-8 -t utf-16be | base16384 -d - - -1234567 -``` + ```bash + echo -n "婌焳廔萷" | iconv -f utf-8 -t utf-16be | base16384 -d - - + 1234567 + ``` -3. Encode file 编码文件 +3. Encode file + > 编码文件 -The text below is the encoding of the base16384 itself on MacOS 12.6 arm64. It is clear to see the strucutre of the binary file. + The text below is the encoding of the base16384 itself on MacOS 12.6 arm64. It is clear to see the strucutre of the binary file. -下面的文本是使用base16384程序在 MacOS Mojave 版本下编码自身的结果。可见文件结构十分清晰。 + 下面的文本是使用base16384程序在 MacOS Mojave 版本下编码自身的结果。可见文件结构十分清晰。 -臾糟蘜一乀縀倀倀一仰一习佀丈戀渀一一乤一丒一丁浟成扴捩卒懀一一一一一一一一一一伀一一一一一一一一一一一一一一一一一一一丙一不渄一旗荄捡戀一一一一一一一丁一一亀一一一一一一一一丠一一一丅一一戀一佀一一一丗菷徕虴一一一一一丅譽扅搕一一一一一丂爋一丐一仈刀一一一眂縀丈一一一一一一一市一一一一一一一佽浳欝搧娀一一一一也旕剕潐一一一一一丛俀一伀一唠一一一丆繰一乀一一一一一一嘄丠一一丆一一一一旗蔷忕灟栙擇侕耀一叵譑単挀一一一一一冀樀一帀七尀一一一仠唀一嘀一一一一一一乀倀一一一一一一丅譽煳欜璖螜一一一丁浟挑掅帀一一一一一禇帀丄一丸帐一一一壡舀一一一一一一一丈一一一一一一一一也旝擧殥籤旚擦枼一丗菵引晔一一一一一三乼一乀一俀一一一丂帟一丠一一一一一一一一一一一一一一一侐一予乀丅譽剁挐帀一一一一一丠一丐一一刈一一一丈一一一一伀一一一丰一七一一帀一一一佽浮椗蔷玵灯椗蔇忈也旑刕弄一一一一一一倀一伀一亀一一一一亀一什一一一一一一吀一估一一一一一一旗葶诐一一一一一一叵謑佔幀一一一一一丠渀一帀一昀一一一丈嘀一娀一一一一一丁渀一戀一一一一一丅譽穡旜薖莉絬旜啇嘁浟弐捄刀一一一一一嘈一丄一並一一一一倂一七一一一一一一东一丅縀一一一一一也旘蓶莵絮一一一一丗菴弅扁一一一一一丌亀一乀一丰丠一一一一一乀一一一一一一乀一一一一一一一一侐一么一丅譽婉憒艔弥戀一一一丰嘀丐一一刀一一一丌一一一丼习一一一丐一丁一一一一一一予一渌一一丰一亀一丈娀七一一一一一一与儀一币一劃刀付一一嘀一吀一你耀三一丁丵一夀刀下一丅一一一一丄一一帀一嬀一仠一世一一一一一一一一一一一一一一一亘嬀丂瘀一一一一一一一一一一仠一丠一一縀一姝攷嚽穩暋葇玱爀一一一丛一丁渀一斪罒跻舷圪讫惙硗垚愠一丠一一刀一七溠一崊一帀一儀一一么倪一丁一一一一一一上一倀昀一峀稀一一一一一一一丰一与一一昀一丠一一一幐一伀姝攷嚽穩暋蓆玉慹櫝呖芹倮朞擆玈一一一亘一丄一一渲一侀一丩一丁一一尌渀亀一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一丁捈灹挴瀏稘怣揞烼吀一劈畻皮刀丄澤姨什丄烣椴箵蘭虭先诚纄瀧幈繺凴焇蠒怣幀圠俈怠詁潭毃捒嚞挅敁掐捅嬢凬删跰忔蝉災劈筸嚀峋敒茢域蠮伀丂埁滸淨巤偵媑嚧稅侀距啓怏蘂歟粇蘈一簿淿跿礊蠜渠丂蛿跿跴瀏刐擐揄卹佟数貅稈一簿緿跿秧滾丰谖夀一嘇稉舏潞縐丁嚍整姰昀一怢毮熰崀丒咐綠儀丒妍竒蓗溷澴嬣蕫倒暝朢埐怰沃謧俾劒帜朤俎裒劈荷庿侀一伢埞蠬仰丁嚸蓍奭氋氛廒嵶稡垉莒咐嶠儀丒嚝匣俩巒樟虉圁膒帜朦奄圂剈矠僫仑感朄嶾翠趆忐皃谙廸敘一丒暷纐幉烝偁漢嬕粄缀伢嬍盄縀冣码一岱茦奼圄劘篐爘怣彙穌帀怣廘幌一蠼繐丁侉翓晟柑晅潿蕕嬦奄圆周嫠筴怒囕蕂贆一丄瀧注亃縀伡眳蠀縀伢蛛嬭筸奸楃怽蒰漢埐怰沃謣俺劒东地矶怀此瀴謔刀七唃瘓净七唁厅跃虉添跿幣承谏蘆毑劈舷昀一劆娒佈乲巾伢嬽譃縀冣欎一妀刀一衚巯跿盐一下燯跿跺掟觿跨繀一僣諿跿貔移跿怣懘湀一蠪廠丁劉谺慯觿赈煏檐言仨獃渀僠倀一岒击跿怣懝娼一蠟绠丂蘃一与爫賿跒囓蕰崀为咐蘀亸伀一冧苽跿芈苷洏一岅娸一簁帀七矞赿跴瀴诧净与滴尀丮习一仩耿淿謢嬽覃縀冠甎一妀樀一衬緟跼崟丌淿跽蟿跿蛿跿趥跿跻緿跿艿跿趟跿跕抈疕嚍嵵绰七盺兀丄瀴謘刀与熸嬀丒囓苘帀为尠舀么煏慱一仨莃帀伢嬽射一冣堍一劈苵倐一岋蘴一怣懕繀一敺椐舀亐爤協瀧獁提捤单佔拒嘞肠一丒暜茦埖怢涶栌购怢敜濔捈灼犈獷幈烁橱一乌烈儜疬荈煭意跿赈灷貆訴一幯縐一亅縃虖済一怢苙伢叉凢厰嘀么灗欄拇版烕檆栌蠭歃劈稖吐一勈竣礘怢檴瀴菭净丄瀧旨蛃一伢埙恢橴萗贏漪帀丁嚅聃虊稀一怠涐刀帀凣柠一么灓樄瀭诐婽焜冣弌一噜举嘹乀丈甌翿愢葜伲埦粀帀丂蜂一丄吧久婲沉舰一怠趏訾刚乀丈獷幉曳劆畆愤恤犌喨湄乸皝唇真繾渠唪嬜荀一一矚幣捁懾出佃虰娄一怣廙訄一怘罉匠俊跸犘甚凋侺涰一乁緀渀七睩乀丄萗牵唒囓扤崀丒嚷蕃瘋儀丄琧剈潰仸悤一丯跠一乌灿粏測一緿縀丁媉趺岰稀亾乀一僫諿净勈痝媉虺寀稀么潰啂謲執灱狈疪蜸恄渎濤唀丒吿僨伀一勈疽媉豺妀稀么潰啛膧洀一劈笗噦滎僗帡媉跺嗠稀久婿芈笗幦滎僐谓倀一勈疟癥僀与瓔一丐槰戀一衪渀丁便侀一冦洀一创訌一为杀一义灱瘼娣礓恢橮稹垉羠誰憬呉灱瘼娪凃启跠一乌灿粂昬一緿縀丁媉趺侐稀乌災苈算乄灹狈疪埙蠯繠丁噣訮渐一乌灻苈痧盾傀丄瀗乴墓嚟欲埦蠾溠丁嚋彲周嫠筴倓嚟趢谊一嚷蕃皰傀丄拇跫侐槰帀一弢涄瀇动一丅笅橁敐揤卽毃枤启跿赪趿跶移跿捿跿譗跿跚緿跽捈灹戕欅摁挔芈旽艶恢浴瀗葴歒暜蜢埓恢淋跸一专嚟覡渊一姿言一愢淮潌堀丯渐一人贿绰伢域愢氞漐堀丒噜俐赈灷蚜朲埲籎劑嘃盡佀丄澏纺乀一伲執愢涞満堀丒噜俖誸伀一冬庸什一冬垸亀一冬倱縖舕缅汁旗樵挢埥幕舕朅捁挔茈旽虨幢浸旙虨恢櫤琧捁灿劈苗嘌一妠嘀一弢淾渜堀丮総証乄灹苈疻盟偀丄瀗乴嵓嚞谧呌灼禓漤怀蠓乐丁噣萑嚟謲埶怢殮焼圀丒冝濷冸伀一冬庸什一冬垸亀一冬倱縒嘼帡楁攐揔卹佟数荔瀧獁提捤单佔拒嘞肠一丒暜缢坕縒暟挢埻枠臲菔恈灗欄瀬厢儀丄耬縱蓺腴瀶茰跿跴瀧淨悂帀伆贁一丈攀嶅搀渀伢奍爒噜爾噋亀丄瀧噈灗欄拇葈灲葤名謀奓嚖蔡茌怢繕爰一愢膎穉嚍孰纰丁媉觺妐渀义灱苈箷乍潿绸慈一丒噝稾勔一丄瀇褁丄一谷唀一劈篷帱讌樎炨嘀両樀谣吁一刘甘翿怢毫瘄一丮帠一乁灰剓唧癹倀丄瀏蛿凡塰刀义灱嚝甇蜟繺忐啦埈繾丸嶇蘩繠訑勇乁渏偏蘾拀恣懄张俀灷炜朲埪蠁习丁噣訮渐一乌灻苈痧瘟倀丄瀗丏漆縐丁媉蟒嚝覠攈一劈笗噦滎僗帡媉跺宰樀乄災貌舜一彌淾狔伀丐槰嘀一衊渐丁宅讝忄瀴菅傀丄瀭诐蠭繰丁垉羒噜举刃乀丄耧藨畁縀价谀一啐眲執蠣湰七礊灱苈痛盖俀下蘄一丮渀乀乌灹苈症癿俀丄瀧内蓃蛨樀一愢浾潨唀丠趏译劃谏敓挲執蠒买丂叀欌芈略囁虈劋瘀一一帀丁嘁艒吽嬇各匏曕稉囁豈刘渐嫫傢橴耧蓨杁縀伲埧灷狈疪蜑七渎熤刀丒吿僨伀一勈疽媉豺乀樀么潰仸掇跿跐槰帀一裏芈笗噦滎僗帡媉跺娰昀久婿芈笗幦滎僗庁媉诺壠昀仫厐槰戀一裃爛記一为繤哼儀一剈痡嚁缪一丁楁攐揔卹佟数荔瀧獁提捤单佔拔劈旽舧恢浴瀗葴塒暜缦埖恢淞潸吀丏淠一乵喓嚞趡崆一岱裠儀一岛縀一簀渀七瞲一丈甝媉覺嘰昀亾乀一僨一刀勈疝媉衺僀昀么灰虝稾岆一丄耧編俁渀倏蛿欑嘿滵茵愢泾燔匀両樇廍嚉葒娞劁嚺一一丄一丒丝匡燓幱湁延孛互娟犁侈伃岰砧啌灻粁嘘一愢汸畹媉誮弐丸仨玀縀伡燰粀帀丁媉诓嚟疢缅一劈攀嶅晿跿賠刀一岰囇么滱亅笅橁敐揤卽毃捒嚞挅敁掐捔卑慈滻侄瀥揀灟欈旼嶈赀一倧膅讃蚏瘀一恢櫬昄人亀一倭诐怢櫮濨匀丒嚜哠唀一劈巤倏然縀丂坝脑愞茆举趐廹攕匁襒搽茦嬴單渀乀么塶皷蕃癀佀丄琧喅蓟纔搗贏熨帀丁匱蜑晟诹廆彵縋瘄一丢藝伢孵菺估戀亊彵臃菔抺乀一倭诐怣敝涣褄一嚤敝匁赡娇幍坣腐橠常譄煚帤吡刎乺繤哰伀一勈痝劉覒嚵蔁嚉蒮弐丸仨桀渀伱燸烟櫄瀧汌灾粌渐一形汔继蘏煓淿跾蘄一与穂蘃一与稦蘂一与稈翀怠詁潭作幗戕蜅浝绤圅挢埥幕舕朅打怘詤羧亓園朤甇瘠幀洄性仁蠇舜嗠偁买刨舓匀一丄劧乂煓乯谏蜅毈犈艷唁一劆娲奈乶淾吏嘆裃昼丣礈滲乎税净傐帟倏哹氞拆崹匱蜒榠一一一巳謦褀一丏諼一息渄蘁尀憀勤拇赊烇側渿奈灷犌喸偌噵犈略囁衁勂啥嘉詒嚝蜣修侠池七贿怂櫬喬嚁蛿臰丁嘉諓丟嬠巋悢忏眧跇恠詀欴蟌涬岰朔翿彌汄搗丏漄帐丁吏箃側耧坈繺帤琏漃恰氐蜤埉幠趀刾勒一丄瘾豌埀抈甹囁螁瘞昀贀专亜蜢凡仒娞剑垉聒废匆凸亃虊帀一悃觤纜偈灳犌喘媁螀一訁娉膒嘾刽囁虇劘甥圉詐昿渍艺悃觤纜先灳犌喘抁螀一丽娉膒嘾刽囁虈犘甥圉詐昿渑艐悃觤纜剈灳犈喛一一劌喘桌偳犈嶄赈繸悤琧坉偼战巠却坒滻蜰甅怢櫤瀇瓀一丄焇琢愂櫤瀏漿怰氓传埱恢檔烥尀憀勠伸乌乲抨爳衈曲婤師谽弢剀秽楁攐揤卽毃枤勏觿赂趿跴姻跿忿緿謟賿跔淯跽噣羑愜倁訇趏敓茐嶾弁跴吵仿滾乗檹嚍兲帐丁噣传技唣跠滱綮穦准谺罈崛詁簀帀七礉滱絤哠吀一協瀧獁提捤单佔拢洌嗠淁蠇帟倧俁豀蘾几矈庣拀処叉氞苆崥匱蜒榠儣資趱跬欦褀一一七諿息渀一仼跀丄瓼一縿绰一久婻抨穳絈凲芘苒案灼拂啥嚉諓借嬢嬌瑒嚟嬣俣伓借笠埋怰池标琀跏縄渧汈凳犨狐灉跱折崐啍屳嗫熬呅婻打喑刁縑晜举勠一丄砬諯煓褬喤岃虀蛘胧图跿舨渰灁滾丐谒谀一劈萾胿穿蚜複簆湹緀一争胰沱怏焃偼舨潰瀁幠趀嘾劓一丈画修儠汯一一繺忀病傈愈渤吏蘃欞劋糋趱跬淿跽嘁賢毬喸抁螼一丁嚉葒娞犊凡凂洔堡娢仐昿渑艉怢殔焇眚湸樀一么繺肨嶌贉胐皅纈剁滾乗庡嚹窿褟資趱跒东謢培怰沒堇激一丄焇細滹臰甽傈洈湕笅橁敐揤卽毃悿緿謃賿跐巯跽叾跿艟觿赕趿跿誖簃一已擀儀丿聛嘌一跉楀娀仿坭渰七败簀縀凼玺什丏誖訃一已擸儀丿聜丌一跉樠娀仿坱丰七败羀縀凼珈什丏誗堃一已攰儀丿聜蘌一跉欀娀仿坴渰一一愣忑爌一幔跲护儀两咀一一衹緿跽瘕一与畳跿跚倠一仩芿跿讠縀一岜燿跿栏帀七瞾跿跶漨一为楏跿赨揀一冦磿跿蒆帀一表巿跽癲一与瑛跿跚嗠一仩焿跿订娀一岘姿跿栦一七睸跿跶炘一为擯跿赨筀一冥狿跿蒌嘀一衖緿跽盏一与獃跿跚局一仩徿跿讣脀一岓臿跿栀渐七眲跿跷寁獮月商玵猺嘉擇掵脊丘琗宔缶嫎充讕聲旙著彽瑩椙揷宥补丘琗宔缶嫎充讕聲旙瓷侕籟槝敇俕艟枚擆戁灡櫙愓曌蘴旙攧坽瑯標擥讥籰歝叶枥穥丘琗宔缶嫎充讕聲旝蔦珑獟枚擆戁灡櫙愓曌蘴旙攧坽絰杛珶玹繵欗葦玱猀暘收拄萳對叶揉聟楘攅讥籰歝叶枥穥丘琗宔缶嫎充讕聲旜瑖厑浦桛呐侉潳杌慣嫠舀廛蔇珉睧栝倂澌眠媌儣嚁呵楚搖莄湍桛琖莽良如爦反猱完膃庀耮媋焢亡剥曈儓忑瘠媌儣嚤簠捜萖殔蠀暘收拄萳對倅窵獤欗怅箥籰歝呦玱獝嘖蓷揑繵欙璖羕欀嘈僖戤坥榘蓶徔丠嘋摀爥牥曛葆戀渠奝亐珍癯毈唷侕籤嘝咖莔丠嘚擧俕艦桛呐珁潳櫈僒俑素檙搖庁瑲槛怇寑物榀倂侽荴樝敆枥穥停吗富渭嘝哲保聩欙怇徼湳欙哷提乷暀唦嘃賿一丐一东一一嘀一圀一一一三一一倀一伐稐俑搁帚帬一崀一仰一丛忀一一一净一七一一縀嘀夀丠一一仒一一娃一璀娀佘侀丏樘丁瘃一儐尀乀一丄伀乀帀一一一一一一一一一一一一一一一一一仰唀一刀一貇一丄一丁俐一伀一仡舀丁一丁湴一乀一予欀一帀一稝一丐一丶啀一刀一帇帀丄一丒濐一伀一十舀丁一丅虴一乀一侠欀一帀丁耝一丐一乼啀一刀一澇帀丄一两俐一伀一垡舀丁一上年一乀一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一丁劈湠勀一久也旗蔷徑睮樀北嘢幀旗菷寑牯歝唀偁乤汛呅词艵暗萦玹牥檀圇嚀彀旘蓆讍祟柙敇徥筥两万嚠彀旘蓆词猀爀唣久也枘蓆词猀爀唣湅也枙著後亐东爁匁浦槜呖蘂帀檒伔佽瑰歝吰偀乲戄戅讙聥晙三丁聘剐叶柝聩欙帉丁聠剐叶莵潰两万垠彀旛敖螵潰两万埀彀旛蔆掸亐东疁匁浰杜甦诈亐东瘀剅也樜璖蟑琀爀唨渄彀旜啗忌亐东眀剅也檙搖市帀檦丑匁浳欘敂弥屏弑慣市帀檨丑匁浳欜瓆掸亐东碀剅也歛瑶揑焀爀唫丄彀旝蔦珑猀爀一卼丅丁珶莡浥氙搷揑獟栙搖徕耀慙著彽腴晜畅讵脀扛搖玸乖暘收拄萳對台佭牥曘畖昃圁杛琶埕琀膀帠一七丩佰丌们叀一垕籣槙呐侹牥曛葆戂搁一珶昁蔀緀帀宥穥両縗丂威最圐刌二喀丰凰焀什垲戀丂旙渊丄仄乀丶玱猀稀攀僔佤丮渐娂舦一縏檬七両烠丌仄娀丰冠舀什娄刀刀舰戀一一丩佴焐卜訁柰呤促佣縫蘊爄一一偐尀万一布爑一侀丐乐咀丁渀刀指一习丄丧帐一封一夀蘀丁一一嘀一净开一一一帀一搀一仰刀乨咀一刀一堀一丼伀丁潰一伀一凐一丏乀七幌一乀一佐一七縐七蔕一丐一乩一一訄一弆一丄一丞縀一崁一垱嘀丁一三一一净帀丰崀一帀丂甀一仰刀仼剀一刀一紀一丼圀丰倀一伀一婀一丏偀不亀帀乀一儰一七縐丂爋一丐一仚一一訄一褂縀丄一丸一一伀一帀一一一与瘀一乀一刀一一一七茀一丐一伀一一一一伀帀丄一乀一一一一亰刀丁一丐一一一一乌伀一帀丄一一一一业乀一刀丁一一一一丈帐一伀一帀一一一丂渄一乀一刀一一一一紁一丐一伀一一一一寀帀丄一乀一一一一凐刀丁一丐一一一一伔伀一帀丄一一一一之乀一刀丁一一一一且縐一伀一帀一一一丅稄一乀一刀一一一丁漁一丐一伀一一一一柀帀丄一乀一一一一啐刀丁一丐一一一一俴伀一帀丄一一一一亅乀一刀丁一一一一丣丐一伀一帀一一一丁一一剀一么一丄縀一戀一佐一世一丁樀一吀一乤一丆渀一椀一俀一丝一丁蘀一嗀一亀一丈帀一瀀一一丁与一一言一囀一乀一丄帀一怀一估一且一丁戀一厀一乜一丆一一最一侠一丛一丁縀一啀一乸一万縀一渀一倐一丢一丂丁浟楚叶握獣歝呕计獡朙攠佽灡櫙愓曌蘴旙呖宽牥丗萦反猱完膃彽牥曛葆捽瑤丗萦反猱完膃彽牥曛葆捽瑩椙帅讉潳杌慣嫠艟朙搶讑獟果丅讉潳杌慣嫠艟杛琶讑猀旘琗宔缶嫎充讕籣槙呕讙爀旘琗宔缶嫎充讕籣槙呕讙睬杀叶垅腥婍焳滑浥榘蓶徕浦樀叶徕煢歙清讕籣暝摠佽略欗蔷待聴旛攰佽筡桛清譽浳欙咖蟀也旗蔷徑絵欜丅讍穯曚菶殕艴桛摐佽煬槜葐佽瑣椛蔶戁浦柙敆威浦槜呖蘁浦樝敆威浦檙搖币浦毜璗徔也楛搗丁浭歛瓖叀也槜呖蘁浰杜甦诈也樜璖蟑琀旜啗忌也檙搖币浳欘敂弥屏弑慣币浳欜瓆掸也歛瑶揑焀旝蔦珑猀朞擆彽腴歘珶垥籤杜清证聩榝号揍潧杀一一一一㴁 + 臾糟蘜一乀縀倀倀一仰一习佀丈戀渀一一乤一丒一丁浟成扴捩卒懀一一一一一一一一一一伀一一一一一一一一一一一一一一一一一一一丙一不渄一旗荄捡戀一一一一一一一丁一一亀一一一一一一一一丠一一一丅一一戀一佀一一一丗菷徕虴一一一一一丅譽扅搕一一一一一丂爋一丐一仈刀一一一眂縀丈一一一一一一一市一一一一一一一佽浳欝搧娀一一一一也旕剕潐一一一一一丛俀一伀一唠一一一丆繰一乀一一一一一一嘄丠一一丆一一一一旗蔷忕灟栙擇侕耀一叵譑単挀一一一一一冀樀一帀七尀一一一仠唀一嘀一一一一一一乀倀一一一一一一丅譽煳欜璖螜一一一丁浟挑掅帀一一一一一禇帀丄一丸帐一一一壡舀一一一一一一一丈一一一一一一一一也旝擧殥籤旚擦枼一丗菵引晔一一一一一三乼一乀一俀一一一丂帟一丠一一一一一一一一一一一一一一一侐一予乀丅譽剁挐帀一一一一一丠一丐一一刈一一一丈一一一一伀一一一丰一七一一帀一一一佽浮椗蔷玵灯椗蔇忈也旑刕弄一一一一一一倀一伀一亀一一一一亀一什一一一一一一吀一估一一一一一一旗葶诐一一一一一一叵謑佔幀一一一一一丠渀一帀一昀一一一丈嘀一娀一一一一一丁渀一戀一一一一一丅譽穡旜薖莉絬旜啇嘁浟弐捄刀一一一一一嘈一丄一並一一一一倂一七一一一一一一东一丅縀一一一一一也旘蓶莵絮一一一一丗菴弅扁一一一一一丌亀一乀一丰丠一一一一一乀一一一一一一乀一一一一一一一一侐一么一丅譽婉憒艔弥戀一一一丰嘀丐一一刀一一一丌一一一丼习一一一丐一丁一一一一一一予一渌一一丰一亀一丈娀七一一一一一一与儀一币一劃刀付一一嘀一吀一你耀三一丁丵一夀刀下一丅一一一一丄一一帀一嬀一仠一世一一一一一一一一一一一一一一一亘嬀丂瘀一一一一一一一一一一仠一丠一一縀一姝攷嚽穩暋葇玱爀一一一丛一丁渀一斪罒跻舷圪讫惙硗垚愠一丠一一刀一七溠一崊一帀一儀一一么倪一丁一一一一一一上一倀昀一峀稀一一一一一一一丰一与一一昀一丠一一一幐一伀姝攷嚽穩暋蓆玉慹櫝呖芹倮朞擆玈一一一亘一丄一一渲一侀一丩一丁一一尌渀亀一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一丁捈灹挴瀏稘怣揞烼吀一劈畻皮刀丄澤姨什丄烣椴箵蘭虭先诚纄瀧幈繺凴焇蠒怣幀圠俈怠詁潭毃捒嚞挅敁掐捅嬢凬删跰忔蝉災劈筸嚀峋敒茢域蠮伀丂埁滸淨巤偵媑嚧稅侀距啓怏蘂歟粇蘈一簿淿跿礊蠜渠丂蛿跿跴瀏刐擐揄卹佟数貅稈一簿緿跿秧滾丰谖夀一嘇稉舏潞縐丁嚍整姰昀一怢毮熰崀丒咐綠儀丒妍竒蓗溷澴嬣蕫倒暝朢埐怰沃謧俾劒帜朤俎裒劈荷庿侀一伢埞蠬仰丁嚸蓍奭氋氛廒嵶稡垉莒咐嶠儀丒嚝匣俩巒樟虉圁膒帜朦奄圂剈矠僫仑感朄嶾翠趆忐皃谙廸敘一丒暷纐幉烝偁漢嬕粄缀伢嬍盄縀冣码一岱茦奼圄劘篐爘怣彙穌帀怣廘幌一蠼繐丁侉翓晟柑晅潿蕕嬦奄圆周嫠筴怒囕蕂贆一丄瀧注亃縀伡眳蠀縀伢蛛嬭筸奸楃怽蒰漢埐怰沃謣俺劒东地矶怀此瀴謔刀七唃瘓净七唁厅跃虉添跿幣承谏蘆毑劈舷昀一劆娒佈乲巾伢嬽譃縀冣欎一妀刀一衚巯跿盐一下燯跿跺掟觿跨繀一僣諿跿貔移跿怣懘湀一蠪廠丁劉谺慯觿赈煏檐言仨獃渀僠倀一岒击跿怣懝娼一蠟绠丂蘃一与爫賿跒囓蕰崀为咐蘀亸伀一冧苽跿芈苷洏一岅娸一簁帀七矞赿跴瀴诧净与滴尀丮习一仩耿淿謢嬽覃縀冠甎一妀樀一衬緟跼崟丌淿跽蟿跿蛿跿趥跿跻緿跿艿跿趟跿跕抈疕嚍嵵绰七盺兀丄瀴謘刀与熸嬀丒囓苘帀为尠舀么煏慱一仨莃帀伢嬽射一冣堍一劈苵倐一岋蘴一怣懕繀一敺椐舀亐爤協瀧獁提捤单佔拒嘞肠一丒暜茦埖怢涶栌购怢敜濔捈灼犈獷幈烁橱一乌烈儜疬荈煭意跿赈灷貆訴一幯縐一亅縃虖済一怢苙伢叉凢厰嘀么灗欄拇版烕檆栌蠭歃劈稖吐一勈竣礘怢檴瀴菭净丄瀧旨蛃一伢埙恢橴萗贏漪帀丁嚅聃虊稀一怠涐刀帀凣柠一么灓樄瀭诐婽焜冣弌一噜举嘹乀丈甌翿愢葜伲埦粀帀丂蜂一丄吧久婲沉舰一怠趏訾刚乀丈獷幉曳劆畆愤恤犌喨湄乸皝唇真繾渠唪嬜荀一一矚幣捁懾出佃虰娄一怣廙訄一怘罉匠俊跸犘甚凋侺涰一乁緀渀七睩乀丄萗牵唒囓扤崀丒嚷蕃瘋儀丄琧剈潰仸悤一丯跠一乌灿粏測一緿縀丁媉趺岰稀亾乀一僫諿净勈痝媉虺寀稀么潰啂謲執灱狈疪蜸恄渎濤唀丒吿僨伀一勈疽媉豺妀稀么潰啛膧洀一劈笗噦滎僗帡媉跺嗠稀久婿芈笗幦滎僐谓倀一勈疟癥僀与瓔一丐槰戀一衪渀丁便侀一冦洀一创訌一为杀一义灱瘼娣礓恢橮稹垉羠誰憬呉灱瘼娪凃启跠一乌灿粂昬一緿縀丁媉趺侐稀乌災苈算乄灹狈疪埙蠯繠丁噣訮渐一乌灻苈痧盾傀丄瀗乴墓嚟欲埦蠾溠丁嚋彲周嫠筴倓嚟趢谊一嚷蕃皰傀丄拇跫侐槰帀一弢涄瀇动一丅笅橁敐揤卽毃枤启跿赪趿跶移跿捿跿譗跿跚緿跽捈灹戕欅摁挔芈旽艶恢浴瀗葴歒暜蜢埓恢淋跸一专嚟覡渊一姿言一愢淮潌堀丯渐一人贿绰伢域愢氞漐堀丒噜俐赈灷蚜朲埲籎劑嘃盡佀丄澏纺乀一伲執愢涞満堀丒噜俖誸伀一冬庸什一冬垸亀一冬倱縖舕缅汁旗樵挢埥幕舕朅捁挔茈旽虨幢浸旙虨恢櫤琧捁灿劈苗嘌一妠嘀一弢淾渜堀丮総証乄灹苈疻盟偀丄瀗乴嵓嚞谧呌灼禓漤怀蠓乐丁噣萑嚟謲埶怢殮焼圀丒冝濷冸伀一冬庸什一冬垸亀一冬倱縒嘼帡楁攐揔卹佟数荔瀧獁提捤单佔拒嘞肠一丒暜缢坕縒暟挢埻枠臲菔恈灗欄瀬厢儀丄耬縱蓺腴瀶茰跿跴瀧淨悂帀伆贁一丈攀嶅搀渀伢奍爒噜爾噋亀丄瀧噈灗欄拇葈灲葤名謀奓嚖蔡茌怢繕爰一愢膎穉嚍孰纰丁媉觺妐渀义灱苈箷乍潿绸慈一丒噝稾勔一丄瀇褁丄一谷唀一劈篷帱讌樎炨嘀両樀谣吁一刘甘翿怢毫瘄一丮帠一乁灰剓唧癹倀丄瀏蛿凡塰刀义灱嚝甇蜟繺忐啦埈繾丸嶇蘩繠訑勇乁渏偏蘾拀恣懄张俀灷炜朲埪蠁习丁噣訮渐一乌灻苈痧瘟倀丄瀗丏漆縐丁媉蟒嚝覠攈一劈笗噦滎僗帡媉跺宰樀乄災貌舜一彌淾狔伀丐槰嘀一衊渐丁宅讝忄瀴菅傀丄瀭诐蠭繰丁垉羒噜举刃乀丄耧藨畁縀价谀一啐眲執蠣湰七礊灱苈痛盖俀下蘄一丮渀乀乌灹苈症癿俀丄瀧内蓃蛨樀一愢浾潨唀丠趏译劃谏敓挲執蠒买丂叀欌芈略囁虈劋瘀一一帀丁嘁艒吽嬇各匏曕稉囁豈刘渐嫫傢橴耧蓨杁縀伲埧灷狈疪蜑七渎熤刀丒吿僨伀一勈疽媉豺乀樀么潰仸掇跿跐槰帀一裏芈笗噦滎僗帡媉跺娰昀久婿芈笗幦滎僗庁媉诺壠昀仫厐槰戀一裃爛記一为繤哼儀一剈痡嚁缪一丁楁攐揔卹佟数荔瀧獁提捤单佔拔劈旽舧恢浴瀗葴塒暜缦埖恢淞潸吀丏淠一乵喓嚞趡崆一岱裠儀一岛縀一簀渀七瞲一丈甝媉覺嘰昀亾乀一僨一刀勈疝媉衺僀昀么灰虝稾岆一丄耧編俁渀倏蛿欑嘿滵茵愢泾燔匀両樇廍嚉葒娞劁嚺一一丄一丒丝匡燓幱湁延孛互娟犁侈伃岰砧啌灻粁嘘一愢汸畹媉誮弐丸仨玀縀伡燰粀帀丁媉诓嚟疢缅一劈攀嶅晿跿賠刀一岰囇么滱亅笅橁敐揤卽毃捒嚞挅敁掐捔卑慈滻侄瀥揀灟欈旼嶈赀一倧膅讃蚏瘀一恢櫬昄人亀一倭诐怢櫮濨匀丒嚜哠唀一劈巤倏然縀丂坝脑愞茆举趐廹攕匁襒搽茦嬴單渀乀么塶皷蕃癀佀丄琧喅蓟纔搗贏熨帀丁匱蜑晟诹廆彵縋瘄一丢藝伢孵菺估戀亊彵臃菔抺乀一倭诐怣敝涣褄一嚤敝匁赡娇幍坣腐橠常譄煚帤吡刎乺繤哰伀一勈痝劉覒嚵蔁嚉蒮弐丸仨桀渀伱燸烟櫄瀧汌灾粌渐一形汔继蘏煓淿跾蘄一与穂蘃一与稦蘂一与稈翀怠詁潭作幗戕蜅浝绤圅挢埥幕舕朅打怘詤羧亓園朤甇瘠幀洄性仁蠇舜嗠偁买刨舓匀一丄劧乂煓乯谏蜅毈犈艷唁一劆娲奈乶淾吏嘆裃昼丣礈滲乎税净傐帟倏哹氞拆崹匱蜒榠一一一巳謦褀一丏諼一息渄蘁尀憀勤拇赊烇側渿奈灷犌喸偌噵犈略囁衁勂啥嘉詒嚝蜣修侠池七贿怂櫬喬嚁蛿臰丁嘉諓丟嬠巋悢忏眧跇恠詀欴蟌涬岰朔翿彌汄搗丏漄帐丁吏箃側耧坈繺帤琏漃恰氐蜤埉幠趀刾勒一丄瘾豌埀抈甹囁螁瘞昀贀专亜蜢凡仒娞剑垉聒废匆凸亃虊帀一悃觤纜偈灳犌喘媁螀一訁娉膒嘾刽囁虇劘甥圉詐昿渍艺悃觤纜先灳犌喘抁螀一丽娉膒嘾刽囁虈犘甥圉詐昿渑艐悃觤纜剈灳犈喛一一劌喘桌偳犈嶄赈繸悤琧坉偼战巠却坒滻蜰甅怢櫤瀇瓀一丄焇琢愂櫤瀏漿怰氓传埱恢檔烥尀憀勠伸乌乲抨爳衈曲婤師谽弢剀秽楁攐揤卽毃枤勏觿赂趿跴姻跿忿緿謟賿跔淯跽噣羑愜倁訇趏敓茐嶾弁跴吵仿滾乗檹嚍兲帐丁噣传技唣跠滱綮穦准谺罈崛詁簀帀七礉滱絤哠吀一協瀧獁提捤单佔拢洌嗠淁蠇帟倧俁豀蘾几矈庣拀処叉氞苆崥匱蜒榠儣資趱跬欦褀一一七諿息渀一仼跀丄瓼一縿绰一久婻抨穳絈凲芘苒案灼拂啥嚉諓借嬢嬌瑒嚟嬣俣伓借笠埋怰池标琀跏縄渧汈凳犨狐灉跱折崐啍屳嗫熬呅婻打喑刁縑晜举勠一丄砬諯煓褬喤岃虀蛘胧图跿舨渰灁滾丐谒谀一劈萾胿穿蚜複簆湹緀一争胰沱怏焃偼舨潰瀁幠趀嘾劓一丈画修儠汯一一繺忀病傈愈渤吏蘃欞劋糋趱跬淿跽嘁賢毬喸抁螼一丁嚉葒娞犊凡凂洔堡娢仐昿渑艉怢殔焇眚湸樀一么繺肨嶌贉胐皅纈剁滾乗庡嚹窿褟資趱跒东謢培怰沒堇激一丄焇細滹臰甽傈洈湕笅橁敐揤卽毃悿緿謃賿跐巯跽叾跿艟觿赕趿跿誖簃一已擀儀丿聛嘌一跉楀娀仿坭渰七败簀縀凼玺什丏誖訃一已擸儀丿聜丌一跉樠娀仿坱丰七败羀縀凼珈什丏誗堃一已攰儀丿聜蘌一跉欀娀仿坴渰一一愣忑爌一幔跲护儀两咀一一衹緿跽瘕一与畳跿跚倠一仩芿跿讠縀一岜燿跿栏帀七瞾跿跶漨一为楏跿赨揀一冦磿跿蒆帀一表巿跽癲一与瑛跿跚嗠一仩焿跿订娀一岘姿跿栦一七睸跿跶炘一为擯跿赨筀一冥狿跿蒌嘀一衖緿跽盏一与獃跿跚局一仩徿跿讣脀一岓臿跿栀渐七眲跿跷寁獮月商玵猺嘉擇掵脊丘琗宔缶嫎充讕聲旙著彽瑩椙揷宥补丘琗宔缶嫎充讕聲旙瓷侕籟槝敇俕艟枚擆戁灡櫙愓曌蘴旙攧坽瑯標擥讥籰歝叶枥穥丘琗宔缶嫎充讕聲旝蔦珑獟枚擆戁灡櫙愓曌蘴旙攧坽絰杛珶玹繵欗葦玱猀暘收拄萳對叶揉聟楘攅讥籰歝叶枥穥丘琗宔缶嫎充讕聲旜瑖厑浦桛呐侉潳杌慣嫠舀廛蔇珉睧栝倂澌眠媌儣嚁呵楚搖莄湍桛琖莽良如爦反猱完膃庀耮媋焢亡剥曈儓忑瘠媌儣嚤簠捜萖殔蠀暘收拄萳對倅窵獤欗怅箥籰歝呦玱獝嘖蓷揑繵欙璖羕欀嘈僖戤坥榘蓶徔丠嘋摀爥牥曛葆戀渠奝亐珍癯毈唷侕籤嘝咖莔丠嘚擧俕艦桛呐珁潳櫈僒俑素檙搖庁瑲槛怇寑物榀倂侽荴樝敆枥穥停吗富渭嘝哲保聩欙怇徼湳欙哷提乷暀唦嘃賿一丐一东一一嘀一圀一一一三一一倀一伐稐俑搁帚帬一崀一仰一丛忀一一一净一七一一縀嘀夀丠一一仒一一娃一璀娀佘侀丏樘丁瘃一儐尀乀一丄伀乀帀一一一一一一一一一一一一一一一一一仰唀一刀一貇一丄一丁俐一伀一仡舀丁一丁湴一乀一予欀一帀一稝一丐一丶啀一刀一帇帀丄一丒濐一伀一十舀丁一丅虴一乀一侠欀一帀丁耝一丐一乼啀一刀一澇帀丄一两俐一伀一垡舀丁一上年一乀一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一丁劈湠勀一久也旗蔷徑睮樀北嘢幀旗菷寑牯歝唀偁乤汛呅词艵暗萦玹牥檀圇嚀彀旘蓆讍祟柙敇徥筥两万嚠彀旘蓆词猀爀唣久也枘蓆词猀爀唣湅也枙著後亐东爁匁浦槜呖蘂帀檒伔佽瑰歝吰偀乲戄戅讙聥晙三丁聘剐叶柝聩欙帉丁聠剐叶莵潰两万垠彀旛敖螵潰两万埀彀旛蔆掸亐东疁匁浰杜甦诈亐东瘀剅也樜璖蟑琀爀唨渄彀旜啗忌亐东眀剅也檙搖市帀檦丑匁浳欘敂弥屏弑慣市帀檨丑匁浳欜瓆掸亐东碀剅也歛瑶揑焀爀唫丄彀旝蔦珑猀爀一卼丅丁珶莡浥氙搷揑獟栙搖徕耀慙著彽腴晜畅讵脀扛搖玸乖暘收拄萳對台佭牥曘畖昃圁杛琶埕琀膀帠一七丩佰丌们叀一垕籣槙呐侹牥曛葆戂搁一珶昁蔀緀帀宥穥両縗丂威最圐刌二喀丰凰焀什垲戀丂旙渊丄仄乀丶玱猀稀攀僔佤丮渐娂舦一縏檬七両烠丌仄娀丰冠舀什娄刀刀舰戀一一丩佴焐卜訁柰呤促佣縫蘊爄一一偐尀万一布爑一侀丐乐咀丁渀刀指一习丄丧帐一封一夀蘀丁一一嘀一净开一一一帀一搀一仰刀乨咀一刀一堀一丼伀丁潰一伀一凐一丏乀七幌一乀一佐一七縐七蔕一丐一乩一一訄一弆一丄一丞縀一崁一垱嘀丁一三一一净帀丰崀一帀丂甀一仰刀仼剀一刀一紀一丼圀丰倀一伀一婀一丏偀不亀帀乀一儰一七縐丂爋一丐一仚一一訄一褂縀丄一丸一一伀一帀一一一与瘀一乀一刀一一一七茀一丐一伀一一一一伀帀丄一乀一一一一亰刀丁一丐一一一一乌伀一帀丄一一一一业乀一刀丁一一一一丈帐一伀一帀一一一丂渄一乀一刀一一一一紁一丐一伀一一一一寀帀丄一乀一一一一凐刀丁一丐一一一一伔伀一帀丄一一一一之乀一刀丁一一一一且縐一伀一帀一一一丅稄一乀一刀一一一丁漁一丐一伀一一一一柀帀丄一乀一一一一啐刀丁一丐一一一一俴伀一帀丄一一一一亅乀一刀丁一一一一丣丐一伀一帀一一一丁一一剀一么一丄縀一戀一佐一世一丁樀一吀一乤一丆渀一椀一俀一丝一丁蘀一嗀一亀一丈帀一瀀一一丁与一一言一囀一乀一丄帀一怀一估一且一丁戀一厀一乜一丆一一最一侠一丛一丁縀一啀一乸一万縀一渀一倐一丢一丂丁浟楚叶握獣歝呕计獡朙攠佽灡櫙愓曌蘴旙呖宽牥丗萦反猱完膃彽牥曛葆捽瑤丗萦反猱完膃彽牥曛葆捽瑩椙帅讉潳杌慣嫠艟朙搶讑獟果丅讉潳杌慣嫠艟杛琶讑猀旘琗宔缶嫎充讕籣槙呕讙爀旘琗宔缶嫎充讕籣槙呕讙睬杀叶垅腥婍焳滑浥榘蓶徕浦樀叶徕煢歙清讕籣暝摠佽略欗蔷待聴旛攰佽筡桛清譽浳欙咖蟀也旗蔷徑絵欜丅讍穯曚菶殕艴桛摐佽煬槜葐佽瑣椛蔶戁浦柙敆威浦槜呖蘁浦樝敆威浦檙搖币浦毜璗徔也楛搗丁浭歛瓖叀也槜呖蘁浰杜甦诈也樜璖蟑琀旜啗忌也檙搖币浳欘敂弥屏弑慣币浳欜瓆掸也歛瑶揑焀旝蔦珑猀朞擆彽腴歘珶垥籤杜清证聩榝号揍潧杀一一一一㴁 diff --git a/base1432.c b/base1432.c index ac09987..9089ab0 100644 --- a/base1432.c +++ b/base1432.c @@ -1,6 +1,6 @@ /* base1432.c * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). - * Copyright (c) 2022-2023 Fumiama Minamoto. + * Copyright (c) 2022-2024 Fumiama Minamoto. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,51 +16,113 @@ * along with this program. If not, see . */ -#ifdef __cosmopolitan // always le -# define be16toh(x) bswap_16(x) -# define be32toh(x) bswap_32(x) -# define htobe16(x) bswap_16(x) -# define htobe32(x) bswap_32(x) -#else -#include -#include -#include -#ifdef __linux__ -# include -#endif -#ifdef __FreeBSD__ -# include -#endif -#ifdef __NetBSD__ -# include -#endif -#ifdef __OpenBSD__ -# include -# define be16toh(x) betoh16(x) -# define be32toh(x) betoh32(x) -#endif -#ifdef __APPLE__ -# define be16toh(x) ntohs(x) -# define be32toh(x) ntohl(x) -# define htobe16(x) ntohs(x) -# define htobe32(x) htonl(x) -#endif -#ifdef _WIN32 - #ifdef WORDS_BIGENDIAN - # define be16toh(x) (x) - # define be32toh(x) (x) - # define htobe16(x) (x) - # define htobe32(x) (x) - #else - # define be16toh(x) _byteswap_ushort(x) - # define be32toh(x) _byteswap_ulong(x) - # define htobe16(x) _byteswap_ushort(x) - # define htobe32(x) _byteswap_ulong(x) - #endif -#endif +#ifndef __cosmopolitan +#include #endif -// #define DEBUG +#include "binary.h" + +typedef union { + uint8_t buf[4]; + uint32_t val; +} base16384_union_remainder; + +int base16384_encode_safe(const char* data, int dlen, char* buf) { + int outlen = dlen / 7 * 8; + int offset = dlen % 7; + switch(offset) { // 算上偏移标志字符占用的2字节 + case 0: break; + case 1: outlen += 4; break; + case 2: + case 3: outlen += 6; break; + case 4: + case 5: outlen += 8; break; + case 6: outlen += 10; break; + default: break; + } + uint32_t* vals = (uint32_t*)buf; + uint32_t n = 0; + int32_t i = 0; + for(; i < dlen - 7; i += 7) { + register uint32_t sum = 0; + register uint32_t shift = htobe32(*(uint32_t*)(data+i)); + sum |= (shift>>2) & 0x3fff0000; + sum |= (shift>>4) & 0x00003fff; + sum += 0x4e004e00; + vals[n++] = be32toh(sum); + shift <<= 26; + shift &= 0x3c000000; + sum = 0; + shift |= (htobe32(*(uint32_t*)(data+i+4))>>6)&0x03fffffc; + sum |= shift & 0x3fff0000; + shift >>= 2; + sum |= shift & 0x00003fff; + sum += 0x4e004e00; + vals[n++] = be32toh(sum); + } + base16384_union_remainder valbuf; + if(dlen - i == 7) { + register uint32_t sum = 0; + register uint32_t shift = htobe32(*(uint32_t*)(data+i)); + sum |= (shift>>2) & 0x3fff0000; + sum |= (shift>>4) & 0x00003fff; + sum += 0x4e004e00; + vals[n++] = be32toh(sum); + shift <<= 26; + shift &= 0x3c000000; + sum = 0; + memcpy(valbuf.buf, data+i+4, 3); + shift |= (htobe32(valbuf.val)>>6)&0x03fffffc; + sum |= shift & 0x3fff0000; + shift >>= 2; + sum |= shift & 0x00003fff; + sum += 0x4e004e00; + vals[n++] = be32toh(sum); + return outlen; + } + uint8_t o = offset; + if(o--) { + register uint32_t sum = 0x0000003f & (data[i] >> 2); + sum |= ((uint32_t)data[i] << 14) & 0x0000c000; + if(o--) { + sum |= ((uint32_t)data[i + 1] << 6) & 0x00003f00; + sum |= ((uint32_t)data[i + 1] << 20) & 0x00300000; + if(o--) { + sum |= ((uint32_t)data[i + 2] << 12) & 0x000f0000; + sum |= ((uint32_t)data[i + 2] << 28) & 0xf0000000; + if(o--) { + sum |= ((uint32_t)data[i + 3] << 20) & 0x0f000000; + sum += 0x004e004e; + // safe, because it will never go over 0x3dxx + #ifdef WORDS_BIGENDIAN + vals[n++] = __builtin_bswap32(sum); + #else + vals[n++] = sum; + #endif + sum = (((uint32_t)data[i + 3] << 2)) & 0x0000003c; + if(o--) { + sum |= (((uint32_t)data[i + 4] >> 6)) & 0x00000003; + sum |= ((uint32_t)data[i + 4] << 10) & 0x0000fc00; + if(o--) { + sum |= ((uint32_t)data[i + 5] << 2) & 0x00000300; + sum |= ((uint32_t)data[i + 5] << 16) & 0x003f0000; + } + } + } + } + } + sum += 0x004e004e; + // safe, because it will never go over 0x3dxx + #ifdef WORDS_BIGENDIAN + vals[n] = __builtin_bswap32(sum); + #else + vals[n] = sum; + #endif + buf[outlen - 2] = '='; + buf[outlen - 1] = offset; + } + return outlen; +} int base16384_encode(const char* data, int dlen, char* buf) { int outlen = dlen / 7 * 8; @@ -75,9 +137,6 @@ int base16384_encode(const char* data, int dlen, char* buf) { case 6: outlen += 10; break; default: break; } - #ifdef DEBUG - printf("outlen: %llu, offset: %u, malloc: %llu\n", outlen, offset, outlen + 8); - #endif uint32_t* vals = (uint32_t*)buf; uint32_t n = 0; int32_t i = 0; @@ -140,6 +199,143 @@ int base16384_encode(const char* data, int dlen, char* buf) { return outlen; } +int base16384_encode_unsafe(const char* data, int dlen, char* buf) { + int outlen = dlen / 7 * 8; + int offset = dlen % 7; + switch(offset) { // 算上偏移标志字符占用的2字节 + case 0: break; + case 1: outlen += 4; break; + case 2: + case 3: outlen += 6; break; + case 4: + case 5: outlen += 8; break; + case 6: outlen += 10; break; + default: break; + } + uint32_t* vals = (uint32_t*)buf; + uint32_t n = 0; + int32_t i = 0; + for(; i < dlen; i += 7) { + register uint32_t sum = 0; + register uint32_t shift = htobe32(*(uint32_t*)(data+i)); + sum |= (shift>>2) & 0x3fff0000; + sum |= (shift>>4) & 0x00003fff; + sum += 0x4e004e00; + vals[n++] = be32toh(sum); + shift <<= 26; + shift &= 0x3c000000; + sum = 0; + shift |= (htobe32(*(uint32_t*)(data+i+4))>>6)&0x03fffffc; + sum |= shift & 0x3fff0000; + shift >>= 2; + sum |= shift & 0x00003fff; + sum += 0x4e004e00; + vals[n++] = be32toh(sum); + } + if(offset) { + buf[outlen - 2] = '='; + buf[outlen - 1] = offset; + } + return outlen; +} + +int base16384_decode_safe(const char* data, int dlen, char* buf) { + int outlen = dlen; + int offset = 0; + if(data[dlen-2] == '=') { + offset = data[dlen-1]; + switch(offset) { // 算上偏移标志字符占用的2字节 + case 0: break; + case 1: outlen -= 4; break; + case 2: + case 3: outlen -= 6; break; + case 4: + case 5: outlen -= 8; break; + case 6: outlen -= 10; break; + default: break; + } + } + outlen = outlen / 8 * 7 + offset; + const uint32_t* vals = (const uint32_t*)data; + uint32_t n = 0; + int32_t i = 0; + for(; i < outlen - 7; i+=7) { // n实际每次自增2 + register uint32_t sum = 0; + register uint32_t shift = htobe32(vals[n++]) - 0x4e004e00; + shift <<= 2; + sum |= shift & 0xfffc0000; + shift <<= 2; + sum |= shift & 0x0003fff0; + shift = htobe32(vals[n++]) - 0x4e004e00; + sum |= shift >> 26; + *(uint32_t*)(buf+i) = be32toh(sum); + sum = 0; + shift <<= 6; + sum |= shift & 0xffc00000; + shift <<= 2; + sum |= shift & 0x003fff00; + *(uint32_t*)(buf+i+4) = be32toh(sum); + } + base16384_union_remainder valbuf; + if(outlen - i == 7) { + register uint32_t sum = 0; + register uint32_t shift = htobe32(vals[n++]) - 0x4e004e00; + shift <<= 2; + sum |= shift & 0xfffc0000; + shift <<= 2; + sum |= shift & 0x0003fff0; + shift = htobe32(vals[n]) - 0x4e004e00; + sum |= shift >> 26; + *(uint32_t*)(buf+i) = be32toh(sum); + sum = 0; + shift <<= 6; + sum |= shift & 0xffc00000; + shift <<= 2; + sum |= shift & 0x003fff00; + valbuf.val = be32toh(sum); + memcpy(buf+i+4, valbuf.buf, 3); + } else if((*(uint8_t*)(&vals[n]) != '=') && offset--) { + int cnt = dlen-2-(int)n*(int)sizeof(uint32_t); + if (cnt > 4) cnt = 4; + memcpy(valbuf.buf, &vals[n], cnt); + n++; + #ifdef WORDS_BIGENDIAN + register uint32_t sum = __builtin_bswap32(valbuf.val); + #else + register uint32_t sum = valbuf.val; + #endif + sum -= 0x0000004e; + buf[i++] = ((sum & 0x0000003f) << 2) | ((sum & 0x0000c000) >> 14); + if(offset--) { + sum -= 0x004e0000; + buf[i++] = ((sum & 0x00003f00) >> 6) | ((sum & 0x00300000) >> 20); + if(offset--) { + buf[i++] = ((sum & 0x000f0000) >> 12) | ((sum & 0xf0000000) >> 28); + if(offset--) { + buf[i] = (sum & 0x0f000000) >> 20; + if(*(uint8_t*)(&vals[n]) == '=') return outlen; + memcpy(valbuf.buf, &vals[n], dlen-2-(int)n*(int)sizeof(uint32_t)); + #ifdef WORDS_BIGENDIAN + sum = __builtin_bswap32(valbuf.val); + #else + sum = valbuf.val; + #endif + sum -= 0x0000004e; + buf[i++] |= (sum & 0x0000003c) >> 2; + if(offset--) { + buf[i++] = ((sum & 0x00000003) << 6) | ((sum & 0x0000fc00) >> 10); + if(offset--) { + sum -= 0x004e0000; + buf[i] = ((sum & 0x00000300) >> 2) | ((sum & 0x003f0000) >> 16); + } + } + } + } + } + } + return outlen; +} + int base16384_decode(const char* data, int dlen, char* buf) { int outlen = dlen; int offset = 0; @@ -157,7 +353,7 @@ int base16384_decode(const char* data, int dlen, char* buf) { } } outlen = outlen / 8 * 7 + offset; - uint32_t* vals = (uint32_t*)data; + const uint32_t* vals = (const uint32_t*)data; uint32_t n = 0; int32_t i = 0; for(; i <= outlen - 7; i+=7) { // n实际每次自增2 @@ -177,6 +373,7 @@ int base16384_decode(const char* data, int dlen, char* buf) { sum |= shift & 0x003fff00; *(uint32_t*)(buf+i+4) = be32toh(sum); } + if(*(uint8_t*)(&vals[n]) == '=') return outlen; if(offset--) { // 这里有读取越界 #ifdef WORDS_BIGENDIAN @@ -193,6 +390,7 @@ int base16384_decode(const char* data, int dlen, char* buf) { buf[i++] = ((sum & 0x000f0000) >> 12) | ((sum & 0xf0000000) >> 28); if(offset--) { buf[i] = (sum & 0x0f000000) >> 20; + if(*(uint8_t*)(&vals[n]) == '=') return outlen; // 这里有读取越界 #ifdef WORDS_BIGENDIAN sum = __builtin_bswap32(vals[n]); @@ -214,3 +412,69 @@ int base16384_decode(const char* data, int dlen, char* buf) { } return outlen; } + +int base16384_decode_unsafe(const char* data, int dlen, char* buf) { + int outlen = dlen; + int offset = 0; + if(data[dlen-2] == '=') { + offset = data[dlen-1]; + switch(offset) { // 算上偏移标志字符占用的2字节 + case 0: break; + case 1: outlen -= 4; break; + case 2: + case 3: outlen -= 6; break; + case 4: + case 5: outlen -= 8; break; + case 6: outlen -= 10; break; + default: break; + } + } + outlen = outlen / 8 * 7 + offset; + const uint32_t* vals = (const uint32_t*)data; + uint32_t n = 0; + int32_t i = 0; + for(; i < outlen-7; i+=7) { // n实际每次自增2 + register uint32_t sum = 0; + register uint32_t shift = htobe32(vals[n++]) - 0x4e004e00; + shift <<= 2; + sum |= shift & 0xfffc0000; + shift <<= 2; + sum |= shift & 0x0003fff0; + shift = htobe32(vals[n++]) - 0x4e004e00; + sum |= shift >> 26; + *(uint32_t*)(buf+i) = be32toh(sum); + sum = 0; + shift <<= 6; + sum |= shift & 0xffc00000; + shift <<= 2; + sum |= shift & 0x003fff00; + *(uint32_t*)(buf+i+4) = be32toh(sum); + } + register uint32_t sum = 0; + register uint32_t shift = htobe32(vals[n++]); + if(((shift>>24)&0xff) == 0x3d) return outlen; + if(((shift>>24)&0xff) < 0x4e) shift |= 0xff000000; + if(((shift>> 8)&0xff) < 0x4e) shift |= 0x0000ff00; + shift -= 0x4e004e00; + shift <<= 2; + sum |= shift & 0xfffc0000; + shift <<= 2; + sum |= shift & 0x0003fff0; + shift = htobe32(vals[n]); + if(((shift>>24)&0xff) == 0x3d) { + *(uint32_t*)(buf+i) = be32toh(sum); + return outlen; + } + if(((shift>>24)&0xff) < 0x4e) shift |= 0xff000000; + if(((shift>> 8)&0xff) < 0x4e) shift |= 0x0000ff00; + shift -= 0x4e004e00; + sum |= shift >> 26; + *(uint32_t*)(buf+i) = be32toh(sum); + sum = 0; + shift <<= 6; + sum |= shift & 0xffc00000; + shift <<= 2; + sum |= shift & 0x003fff00; + *(uint32_t*)(buf+i+4) = be32toh(sum); + return outlen; +} diff --git a/base1464.c b/base1464.c index 73b0432..1cfc786 100644 --- a/base1464.c +++ b/base1464.c @@ -1,6 +1,6 @@ /* base1464.c * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). - * Copyright (c) 2022-2023 Fumiama Minamoto. + * Copyright (c) 2022-2024 Fumiama Minamoto. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,51 +16,98 @@ * along with this program. If not, see . */ -#include -#include -#include -#ifdef __linux__ -# include -#endif -#ifdef __FreeBSD__ -# include -#endif -#ifdef __NetBSD__ -# include -#endif -#ifdef __OpenBSD__ -# include -# define be16toh(x) betoh16(x) -# define be32toh(x) betoh32(x) -# define be64toh(x) betoh64(x) -#endif -#ifdef __APPLE__ -# define be16toh(x) ntohs(x) -# define be32toh(x) ntohl(x) -# define be64toh(x) ntohll(x) -# define htobe16(x) ntohs(x) -# define htobe32(x) htonl(x) -# define htobe64(x) htonll(x) -#endif -#ifdef _WIN64 - #ifdef WORDS_BIGENDIAN - # define be16toh(x) (x) - # define be32toh(x) (x) - # define be64toh(x) (x) - # define htobe16(x) (x) - # define htobe32(x) (x) - # define htobe64(x) (x) - #else - # define be16toh(x) _byteswap_ushort(x) - # define be32toh(x) _byteswap_ulong(x) - # define be64toh(x) _byteswap_uint64(x) - # define htobe16(x) _byteswap_ushort(x) - # define htobe32(x) _byteswap_ulong(x) - # define htobe64(x) _byteswap_uint64(x) - #endif +#ifndef __cosmopolitan +#include #endif -// #define DEBUG +#include "binary.h" + +typedef union { + uint8_t buf[8]; + uint64_t val; +} base16384_union_remainder; + +int base16384_encode_safe(const char* data, int dlen, char* buf) { + int outlen = dlen / 7 * 8; + int offset = dlen % 7; + switch(offset) { // 算上偏移标志字符占用的2字节 + case 0: break; + case 1: outlen += 4; break; + case 2: + case 3: outlen += 6; break; + case 4: + case 5: outlen += 8; break; + case 6: outlen += 10; break; + default: break; + } + uint64_t* vals = (uint64_t*)buf; + uint64_t n = 0; + int64_t i = 0; + for(; i < dlen - 7; i += 7) { + register uint64_t sum = 0; + register uint64_t shift = htobe64(*(uint64_t*)(data+i))>>2; + sum |= shift & 0x3fff000000000000; + shift >>= 2; + sum |= shift & 0x00003fff00000000; + shift >>= 2; + sum |= shift & 0x000000003fff0000; + shift >>= 2; + sum |= shift & 0x0000000000003fff; + sum += 0x4e004e004e004e00; + vals[n++] = be64toh(sum); + } + base16384_union_remainder valbuf; + if(dlen - i == 7) { + memcpy(valbuf.buf, data+i, 7); + register uint64_t sum = 0; + register uint64_t shift = htobe64(valbuf.val)>>2; + sum |= shift & 0x3fff000000000000; + shift >>= 2; + sum |= shift & 0x00003fff00000000; + shift >>= 2; + sum |= shift & 0x000000003fff0000; + shift >>= 2; + sum |= shift & 0x0000000000003fff; + sum += 0x4e004e004e004e00; + vals[n++] = be64toh(sum); + return outlen; + } + int o = offset; + if(o--) { + register uint64_t sum = 0x000000000000003f & (data[i] >> 2); + sum |= ((uint64_t)data[i] << 14) & 0x000000000000c000; + if(o--) { + sum |= ((uint64_t)data[i + 1] << 6) & 0x0000000000003f00; + sum |= ((uint64_t)data[i + 1] << 20) & 0x0000000000300000; + if(o--) { + sum |= ((uint64_t)data[i + 2] << 12) & 0x00000000000f0000; + sum |= ((uint64_t)data[i + 2] << 28) & 0x00000000f0000000; + if(o--) { + sum |= ((uint64_t)data[i + 3] << 20) & 0x000000000f000000; + sum |= ((uint64_t)data[i + 3] << 34) & 0x0000003c00000000; + if(o--) { + sum |= ((uint64_t)data[i + 4] << 26) & 0x0000000300000000; + sum |= ((uint64_t)data[i + 4] << 42) & 0x0000fc0000000000; + if(o--) { + sum |= ((uint64_t)data[i + 5] << 34) & 0x0000030000000000; + sum |= ((uint64_t)data[i + 5] << 48) & 0x003f000000000000; + } + } + } + } + } + sum += 0x004e004e004e004e; + #ifdef WORDS_BIGENDIAN + valbuf.val = __builtin_bswap64(sum); + #else + valbuf.val = sum; + #endif + memcpy(&vals[n], valbuf.buf, outlen-2-(int)n*(int)sizeof(uint64_t)); + buf[outlen - 2] = '='; + buf[outlen - 1] = offset; + } + return outlen; +} int base16384_encode(const char* data, int dlen, char* buf) { int outlen = dlen / 7 * 8; @@ -75,9 +122,6 @@ int base16384_encode(const char* data, int dlen, char* buf) { case 6: outlen += 10; break; default: break; } - #ifdef DEBUG - printf("outlen: %llu, offset: %u, malloc: %llu\n", outlen, offset, outlen + 8); - #endif uint64_t* vals = (uint64_t*)buf; uint64_t n = 0; int64_t i = 0; @@ -93,9 +137,6 @@ int base16384_encode(const char* data, int dlen, char* buf) { sum |= shift & 0x0000000000003fff; sum += 0x4e004e004e004e00; vals[n++] = be64toh(sum); - #ifdef DEBUG - printf("i: %llu, add sum: %016llx\n", i, sum); - #endif } int o = offset; if(o--) { @@ -127,15 +168,125 @@ int base16384_encode(const char* data, int dlen, char* buf) { #else vals[n] = sum; #endif - #ifdef DEBUG - printf("i: %llu, add sum: %016llx\n", i, sum); - #endif buf[outlen - 2] = '='; buf[outlen - 1] = offset; } return outlen; } +int base16384_encode_unsafe(const char* data, int dlen, char* buf) { + int outlen = dlen / 7 * 8; + int offset = dlen % 7; + switch(offset) { // 算上偏移标志字符占用的2字节 + case 0: break; + case 1: outlen += 4; break; + case 2: + case 3: outlen += 6; break; + case 4: + case 5: outlen += 8; break; + case 6: outlen += 10; break; + default: break; + } + uint64_t* vals = (uint64_t*)buf; + uint64_t n = 0; + int64_t i = 0; + for(; i < dlen; i += 7) { + register uint64_t sum = 0; + register uint64_t shift = htobe64(*(uint64_t*)(data+i))>>2; // 这里有读取越界 + sum |= shift & 0x3fff000000000000; + shift >>= 2; + sum |= shift & 0x00003fff00000000; + shift >>= 2; + sum |= shift & 0x000000003fff0000; + shift >>= 2; + sum |= shift & 0x0000000000003fff; + sum += 0x4e004e004e004e00; + vals[n++] = be64toh(sum); + } + if(offset) { + buf[outlen - 2] = '='; + buf[outlen - 1] = offset; + } + return outlen; +} + +int base16384_decode_safe(const char* data, int dlen, char* buf) { + int outlen = dlen; + int offset = 0; + if(data[dlen-2] == '=') { + offset = data[dlen-1]; + switch(offset) { // 算上偏移标志字符占用的2字节 + case 0: break; + case 1: outlen -= 4; break; + case 2: + case 3: outlen -= 6; break; + case 4: + case 5: outlen -= 8; break; + case 6: outlen -= 10; break; + default: break; + } + } + outlen = outlen / 8 * 7 + offset; + const uint64_t* vals = (const uint64_t*)data; + uint64_t n = 0; + int64_t i = 0; + for(; i < outlen - 7; n++, i+=7) { + register uint64_t sum = 0; + register uint64_t shift = htobe64(vals[n]) - 0x4e004e004e004e00; + shift <<= 2; + sum |= shift & 0xfffc000000000000; + shift <<= 2; + sum |= shift & 0x0003fff000000000; + shift <<= 2; + sum |= shift & 0x0000000fffc00000; + shift <<= 2; + sum |= shift & 0x00000000003fff00; + *(uint64_t*)(buf+i) = be64toh(sum); + } + base16384_union_remainder valbuf; + if(outlen - i == 7) { + register uint64_t sum = 0; + register uint64_t shift = htobe64(vals[n]) - 0x4e004e004e004e00; + shift <<= 2; + sum |= shift & 0xfffc000000000000; + shift <<= 2; + sum |= shift & 0x0003fff000000000; + shift <<= 2; + sum |= shift & 0x0000000fffc00000; + shift <<= 2; + sum |= shift & 0x00000000003fff00; + valbuf.val = be64toh(sum); + memcpy(buf+i, valbuf.buf, 7); + } else if((*(uint8_t*)(&vals[n]) != '=') && offset--) { + memcpy(valbuf.buf, &vals[n], dlen-2-(int)n*(int)sizeof(uint64_t)); + #ifdef WORDS_BIGENDIAN + register uint64_t sum = __builtin_bswap64(valbuf.val) - 0x000000000000004e; + #else + register uint64_t sum = valbuf.val - 0x000000000000004e; + #endif + buf[i++] = ((sum & 0x000000000000003f) << 2) | ((sum & 0x000000000000c000) >> 14); + if(offset--) { + sum -= 0x00000000004e0000; + buf[i++] = ((sum & 0x0000000000003f00) >> 6) | ((sum & 0x0000000000300000) >> 20); + if(offset--) { + buf[i++] = ((sum & 0x00000000000f0000) >> 12) | ((sum & 0x00000000f0000000) >> 28); + if(offset--) { + sum -= 0x0000004e00000000; + buf[i++] = ((sum & 0x000000000f000000) >> 20) | ((sum & 0x0000003c00000000) >> 34); + if(offset--) { + buf[i++] = ((sum & 0x0000000300000000) >> 26) | ((sum & 0x0000fc0000000000) >> 42); + if(offset--) { + sum -= 0x004e000000000000; + buf[i] = ((sum & 0x0000030000000000) >> 34) | ((sum & 0x003f000000000000) >> 48); + } + } + } + } + } + } + return outlen; +} + int base16384_decode(const char* data, int dlen, char* buf) { int outlen = dlen; int offset = 0; @@ -153,7 +304,7 @@ int base16384_decode(const char* data, int dlen, char* buf) { } } outlen = outlen / 8 * 7 + offset; - uint64_t* vals = (uint64_t*)data; + const uint64_t* vals = (const uint64_t*)data; uint64_t n = 0; int64_t i = 0; for(; i <= outlen - 7; n++, i+=7) { @@ -168,10 +319,8 @@ int base16384_decode(const char* data, int dlen, char* buf) { shift <<= 2; sum |= shift & 0x00000000003fff00; *(uint64_t*)(buf+i) = be64toh(sum); - #ifdef DEBUG - printf("i: %llu, add sum: %016llx\n", i, sum); - #endif } + if(*(uint8_t*)(&vals[n]) == '=') return outlen; if(offset--) { // 这里有读取越界 #ifdef WORDS_BIGENDIAN @@ -201,3 +350,56 @@ int base16384_decode(const char* data, int dlen, char* buf) { } return outlen; } + +int base16384_decode_unsafe(const char* data, int dlen, char* buf) { + int outlen = dlen; + int offset = 0; + if(data[dlen-2] == '=') { + offset = data[dlen-1]; + switch(offset) { // 算上偏移标志字符占用的2字节 + case 0: break; + case 1: outlen -= 4; break; + case 2: + case 3: outlen -= 6; break; + case 4: + case 5: outlen -= 8; break; + case 6: outlen -= 10; break; + default: break; + } + } + outlen = outlen / 8 * 7 + offset; + const uint64_t* vals = (const uint64_t*)data; + uint64_t n = 0; + int64_t i = 0; + for(; i < outlen-7; n++, i+=7) { + register uint64_t sum = 0; + register uint64_t shift = htobe64(vals[n]) - 0x4e004e004e004e00; + shift <<= 2; + sum |= shift & 0xfffc000000000000; + shift <<= 2; + sum |= shift & 0x0003fff000000000; + shift <<= 2; + sum |= shift & 0x0000000fffc00000; + shift <<= 2; + sum |= shift & 0x00000000003fff00; + *(uint64_t*)(buf+i) = be64toh(sum); + } + register uint64_t sum = 0; + register uint64_t shift = htobe64(vals[n]); + if(((shift>>56)&0xff) == 0x3d) return outlen; + if(((shift>>56)&0xff) < 0x4e) shift |= 0xff00000000000000; + if(((shift>>40)&0xff) < 0x4e) shift |= 0x0000ff0000000000; + if(((shift>>24)&0xff) < 0x4e) shift |= 0x00000000ff000000; + if(((shift>> 8)&0xff) < 0x4e) shift |= 0x000000000000ff00; + shift -= 0x4e004e004e004e00; + shift <<= 2; + sum |= shift & 0xfffc000000000000; + shift <<= 2; + sum |= shift & 0x0003fff000000000; + shift <<= 2; + sum |= shift & 0x0000000fffc00000; + shift <<= 2; + sum |= shift & 0x00000000003fff00; + *(uint64_t*)(buf+i) = be64toh(sum); + return outlen; +} diff --git a/base16384.1 b/base16384.1 index 279534d..0b8b258 100644 --- a/base16384.1 +++ b/base16384.1 @@ -1,9 +1,9 @@ -.TH BASE16384 1 "26 August 2023" "GNU" "User Commands" +.TH BASE16384 1 "5 April 2024" "GNU" "User Commands" .SH NAME base16384 \- Encode binary files to printable utf16be .SH SYNOPSIS .B base16384 --[e|d|t] <\fIinputfile\fR> <\fIoutputfile\fR> +-[edtn] <\fIinputfile\fR> <\fIoutputfile\fR> .SH DESCRIPTION .LP There are @@ -27,7 +27,30 @@ to .sp 1 .TP 0.5i \fB\-e\fR -Read data from \fIinputfile\fR and encode them into \fIoutputfile\fR. +Read data from \fIinputfile\fR and encode them into \fIoutputfile\fR. It's the default option when neither +.B -e +nor +.B -d +is specified. +.TP 0.5i +\fB\-d\fR +Read data from \fIinputfile\fR and decode them into \fIoutputfile\fR. +.TP 0.5i +\fB\-t\fR +Show spend time. +.TP 0.5i +\fB\-n\fR +Do not write utf16be file header +.B 0xFEFF +to the output. +.TP 0.5i +\fB\-c\fR +Embed or validate checksum in remainder when using \fIstdin\fR or \fIstdout\fR or inputsize > _BASE16384_ENCBUFSZ. +.TP 0.5i +\fB\-C\fR +Do +.B -c +forcely. .TP 0.5i \fB\-d\fR Read data from \fIinputfile\fR and decode them into \fIoutputfile\fR. @@ -36,10 +59,14 @@ Read data from \fIinputfile\fR and decode them into \fIoutputfile\fR. Show spend time. .TP 0.5i \fBinputfile\fR -An absolute or relative file path. Specially, pass - to read from stdin. +An absolute or relative file path. Specially, pass +.B - +to read from \fIstdin\fR. .TP 0.5i \fBoutputfile\fR -An absolute or relative file path. Specially, pass - to write to stdout. +An absolute or relative file path. Specially, pass +.B - +to write to \fIstdout\fR. .SH "EXIT STATUS" .TP 0.5i \fB0\fR @@ -68,6 +95,12 @@ Write file error in mmap. .TP 0.5i \fB8\fR Invalid input/output filename. +.TP 0.5i +\fB9\fR +Invalid commandline parameter. +.TP 0.5i +\fB10\fR +Invalid decoding checksum. .SH "SEE ALSO" https://github.com/fumiama/base16384 .SH BUGS @@ -77,7 +110,7 @@ on github. .SH AUTHOR This manual page contributed by Fumiama Minamoto. .SH "COPYRIGHT" -Copyright \(co 2022-2023, Fumiama Minamoto +Copyright \(co 2022-2024, Fumiama Minamoto This file is part of .IR "base16384" . .LP diff --git a/base16384.c b/base16384.c index 53d1891..05756b2 100644 --- a/base16384.c +++ b/base16384.c @@ -1,6 +1,6 @@ /* base16384.c * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). - * Copyright (c) 2022-2023 Fumiama Minamoto. + * Copyright (c) 2022-2024 Fumiama Minamoto. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,77 +38,103 @@ unsigned long get_start_ms() { } #endif -static void print_usage() { - puts("Copyright (c) 2022-2023 Fumiama Minamoto.\nBase16384 2.2.5 (August 26th 2023). Usage:"); - puts("base16384 [-edt] [inputfile] [outputfile]"); - puts(" -e\t\tencode"); - puts(" -d\t\tdecode"); - puts(" -t\t\tshow spend time"); - puts(" inputfile\tpass - to read from stdin"); - puts(" outputfile\tpass - to write to stdout"); +static base16384_err_t print_usage() { + #ifndef BASE16384_VERSION + #define BASE16384_VERSION "dev" + #endif + #ifndef BASE16384_VERSION_DATE + #define BASE16384_VERSION_DATE "unknown date" + #endif + fputs( + "Copyright (c) 2022-2024 Fumiama Minamoto.\nBase16384 " + BASE16384_VERSION + " (" + BASE16384_VERSION_DATE + "). Usage:\n", stderr + ); + fputs("base16384 [-edtn] [inputfile] [outputfile]\n", stderr); + fputs(" -e\t\tencode (default)\n", stderr); + fputs(" -d\t\tdecode\n", stderr); + fputs(" -t\t\tshow spend time\n", stderr); + fputs(" -n\t\tdon't write utf16be file header (0xFEFF)\n", stderr); + fputs(" -c\t\tembed or validate checksum in remainder\n", stderr); + fputs(" -C\t\tdo -c forcely\n", stderr); + fputs(" inputfile\tpass - to read from stdin\n", stderr); + fputs(" outputfile\tpass - to write to stdout\n", stderr); + return base16384_err_invalid_commandline_parameter; } int main(int argc, char** argv) { - if(argc != 4 || argv[1][0] != '-') { - print_usage(); - return -1; - } - int flaglen = strlen(argv[1]); - if(flaglen <= 1 || flaglen > 3) { - print_usage(); - return -2; - } + + const char* cmd = argv[1]; + if(argc != 4 || cmd[0] != '-') return print_usage(); + + int flaglen = strlen(cmd); + if(flaglen <= 1 || flaglen > 5) return print_usage(); + #ifdef _WIN32 clock_t t = 0; #else unsigned long t = 0; #endif + + uint16_t is_encode = 1, use_timer = 0, no_header = 0, use_checksum = 0; + #define set_flag(f, v) ((f) = (((((f)>>8)+1) << 8)&0xff00) | (v&0x00ff)) + #define flag_has_been_set(f) ((f)>>8) + #define set_or_test_flag(f, v) (flag_has_been_set(f)?1:(set_flag(f, v), 0)) + while(--flaglen) switch(cmd[flaglen]) { // skip cmd[0] = '-' + case 'e': + if(set_or_test_flag(is_encode, 1)) return print_usage(); + break; + case 'd': + if(set_or_test_flag(is_encode, 0)) return print_usage(); + break; + case 't': + if(set_or_test_flag(use_timer, 1)) return print_usage(); + break; + case 'n': + if(set_or_test_flag(no_header, 1)) return print_usage(); + break; + case 'c': + if(set_or_test_flag(use_checksum, 1)) return print_usage(); + break; + case 'C': + if(set_or_test_flag(use_checksum, 2)) return print_usage(); + break; + default: + return print_usage(); + break; + } + #define clear_high_byte(x) ((x) &= 0x00ff) + clear_high_byte(is_encode); clear_high_byte(use_timer); + clear_high_byte(no_header); clear_high_byte(use_checksum); + + if(use_timer) { + #ifdef _WIN32 + t = clock(); + #else + t = get_start_ms(); + #endif + } + base16384_err_t exitstat = base16384_err_ok; - char cmd = argv[1][1]; - if(cmd == 't') { - if(flaglen == 2) { - print_usage(); return -3; - } + + #define do_coding(method) base16384_##method##_file_detailed( \ + argv[2], argv[3], encbuf, decbuf, \ + (no_header?BASE16384_FLAG_NOHEADER:0) \ + | ((use_checksum&1)?BASE16384_FLAG_SUM_CHECK_ON_REMAIN:0) \ + | ((use_checksum&2)?BASE16384_FLAG_DO_SUM_CHECK_FORCELY:0) \ + ) + exitstat = is_encode?do_coding(encode):do_coding(decode); + #undef do_coding + if(t) { #ifdef _WIN32 - t = clock(); + fprintf(stderr, "spend time: %lums\n", clock() - t); #else - t = get_start_ms(); - #endif - cmd = argv[1][2]; - } else if(flaglen == 3) { - if(argv[1][2] != 't') { - print_usage(); return -4; - } - #ifdef _WIN32 - t = clock(); - #else - t = get_start_ms(); + fprintf(stderr, "spend time: %lums\n", get_start_ms() - t); #endif } - switch(cmd) { - case 'e': exitstat = base16384_encode_file(argv[2], argv[3], encbuf, decbuf); break; - case 'd': exitstat = base16384_decode_file(argv[2], argv[3], encbuf, decbuf); break; - default: print_usage(); return -5; - } - if(t && !exitstat && *(uint16_t*)(argv[3]) != *(uint16_t*)"-") { - #ifdef _WIN32 - printf("spend time: %lums\n", clock() - t); - #else - printf("spend time: %lums\n", get_start_ms() - t); - #endif - } - #define print_base16384_err(n) case base16384_err_##n: perror("base16384_err_"#n); break - if(exitstat) switch(exitstat) { - print_base16384_err(get_file_size); - print_base16384_err(fopen_output_file); - print_base16384_err(fopen_input_file); - print_base16384_err(write_file); - print_base16384_err(open_input_file); - print_base16384_err(map_input_file); - print_base16384_err(read_file); - print_base16384_err(invalid_file_name); - default: perror("base16384"); break; - } - #undef print_base16384_err - return exitstat; + + return base16384_perror(exitstat); + } diff --git a/base16384.h b/base16384.h index fd19063..b5be8a5 100644 --- a/base16384.h +++ b/base16384.h @@ -3,7 +3,7 @@ /* base16384.h * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). - * Copyright (c) 2022-2023 Fumiama Minamoto. + * Copyright (c) 2022-2024 Fumiama Minamoto. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,33 +24,50 @@ #include #endif -#define define_base16384_err_t(n) base16384_err_##n - -// base16384_err_t is the return value of base16384_en/decode_file enum base16384_err_t { - define_base16384_err_t(ok), - define_base16384_err_t(get_file_size), - define_base16384_err_t(fopen_output_file), - define_base16384_err_t(fopen_input_file), - define_base16384_err_t(write_file), - define_base16384_err_t(open_input_file), - define_base16384_err_t(map_input_file), - define_base16384_err_t(read_file), - define_base16384_err_t(invalid_file_name), + base16384_err_ok, + base16384_err_get_file_size, + base16384_err_fopen_output_file, + base16384_err_fopen_input_file, + base16384_err_write_file, + base16384_err_open_input_file, + base16384_err_map_input_file, + base16384_err_read_file, + base16384_err_invalid_file_name, + base16384_err_invalid_commandline_parameter, + base16384_err_invalid_decoding_checksum, }; -// base16384_err_t is the return value of base16384_en/decode_file +/** + * @brief return value of base16384_en/decode_file +*/ typedef enum base16384_err_t base16384_err_t; -#undef define_base16384_err_t +#ifndef BASE16384_BUFSZ_FACTOR + #define BASE16384_BUFSZ_FACTOR (8) +#endif -#define BASE16384_ENCBUFSZ (BUFSIZ*1024/7*7+7) -#define BASE16384_DECBUFSZ (BUFSIZ*1024/8*8+16) +#define _BASE16384_ENCBUFSZ ((BUFSIZ*BASE16384_BUFSZ_FACTOR)/7*7) +#define _BASE16384_DECBUFSZ ((BUFSIZ*BASE16384_BUFSZ_FACTOR)/8*8) -// base16384_encode_len calc min buf size to fill encode result -static inline int base16384_encode_len(int dlen) { +#define BASE16384_ENCBUFSZ (_BASE16384_ENCBUFSZ+16) +#define BASE16384_DECBUFSZ (_BASE16384_DECBUFSZ+16) + +// disable 0xFEFF file header in encode +#define BASE16384_FLAG_NOHEADER (1<<0) +// enable sum check when using stdin or stdout or inputsize > _BASE16384_ENCBUFSZ +#define BASE16384_FLAG_SUM_CHECK_ON_REMAIN (1<<1) +// forcely do sumcheck without checking data length +#define BASE16384_FLAG_DO_SUM_CHECK_FORCELY (1<<2) + +/** + * @brief calculate the exact encoded size + * @param dlen the data length to encode + * @return the size +*/ +static inline int _base16384_encode_len(int dlen) { int outlen = dlen / 7 * 8; int offset = dlen % 7; - switch(offset) { // 算上偏移标志字符占用的2字节 + switch(offset) { // 算上偏移标志字符占用的 2 字节 case 0: break; case 1: outlen += 4; break; case 2: @@ -60,13 +77,27 @@ static inline int base16384_encode_len(int dlen) { case 6: outlen += 10; break; default: break; } - return outlen + 8; // 冗余的8B用于可能的结尾的覆盖 + return outlen; } -// base16384_decode_len calc min buf size to fill decode result -static inline int base16384_decode_len(int dlen, int offset) { +/** + * @brief calculate minimum encoding buffer size (16 bits larger than the real encoded size) + * @param dlen the data length to encode + * @return the minimum encoding buffer size +*/ +static inline int base16384_encode_len(int dlen) { + return _base16384_encode_len(dlen) + 16; // 冗余的 16 字节用于可能的结尾的 unsafe 覆盖 +} + +/** + * @brief calculate the exact decoded size + * @param dlen the data length to decode + * @param offset the last char `xx` of the underfilled coding (0x3Dxx) or 0 for the full coding + * @return the size +*/ +static inline int _base16384_decode_len(int dlen, int offset) { int outlen = dlen; - switch(offset) { // 算上偏移标志字符占用的2字节 + switch(offset) { // 算上偏移标志字符占用的 2 字节 case 0: break; case 1: outlen -= 4; break; case 2: @@ -76,39 +107,180 @@ static inline int base16384_decode_len(int dlen, int offset) { case 6: outlen -= 10; break; default: break; } - return outlen / 8 * 7 + offset + 1; // 多出1字节用于循环覆盖 + return outlen / 8 * 7 + offset; } -// base16384_encode encodes data and write result into buf +/** + * @brief calculate minimum decoding buffer size (16 bits larger than the real decoded size) + * @param dlen the data length to decode + * @param offset the last char `xx` of the underfilled coding (0x3Dxx) or 0 for the full coding + * @return the minimum decoding buffer size +*/ +static inline int base16384_decode_len(int dlen, int offset) { + return _base16384_decode_len(dlen, offset) + 16; // 多出 16 字节用于 unsafe 循环覆盖 +} + +/** + * @brief safely encode data and write result into buf + * @param data data to encode, no data overread + * @param dlen the data length + * @param buf the output buffer, whose size can be exactly `_base16384_encode_len` + * @return the total length written +*/ +int base16384_encode_safe(const char* data, int dlen, char* buf); + +/** + * @brief encode data and write result into buf + * @param data data to encode + * @param dlen the data length + * @param buf the output buffer, whose size must greater than `base16384_encode_len` + * @return the total length written +*/ int base16384_encode(const char* data, int dlen, char* buf); -// base16384_decode decodes data and write result into buf +/** + * @brief encode data and write result into buf without considering border condition + * @param data data to encode + * @param dlen the data length + * @param buf the output buffer, whose size must greater than `base16384_encode_len` + * @return the total length written +*/ +int base16384_encode_unsafe(const char* data, int dlen, char* buf); + +/** + * @brief safely decode data and write result into buf + * @param data data to decode, no data overread + * @param dlen the data length + * @param buf the output buffer, whose size can be exactly `_base16384_decode_len` + * @return the total length written +*/ +int base16384_decode_safe(const char* data, int dlen, char* buf); + +/** + * @brief decode data and write result into buf + * @param data data to decode + * @param dlen the data length + * @param buf the output buffer, whose size must greater than `base16384_decode_len` + * @return the total length written +*/ int base16384_decode(const char* data, int dlen, char* buf); -// base16384_encode_file encodes input file to output file. -// use `-` to specify stdin/stdout -// encbuf & decbuf must be no less than BASE16384_ENCBUFSZ & BASE16384_DECBUFSZ -base16384_err_t base16384_encode_file(const char* input, const char* output, char* encbuf, char* decbuf); +/** + * @brief decode data and write result into buf without considering border condition + * @param data data to decode + * @param dlen the data length + * @param buf the output buffer, whose size must greater than `base16384_decode_len` + * @return the total length written +*/ +int base16384_decode_unsafe(const char* data, int dlen, char* buf); -// base16384_encode_fp encodes input file to output file. -// encbuf & decbuf must be no less than BASE16384_ENCBUFSZ & BASE16384_DECBUFSZ -base16384_err_t base16384_encode_fp(FILE* input, FILE* output, char* encbuf, char* decbuf); +#define base16384_typed_params(type) type input, type output, char* encbuf, char* decbuf +#define base16384_typed_flag_params(type) base16384_typed_params(type), int flag -// base16384_encode_fd encodes input fd to output fd. -// encbuf & decbuf must be no less than BASE16384_ENCBUFSZ & BASE16384_DECBUFSZ -base16384_err_t base16384_encode_fd(int input, int output, char* encbuf, char* decbuf); +/** + * @brief encode input file to output file + * @param input filename or `-` to specify stdin + * @param output filename or `-` to specify stdout + * @param encbuf must be no less than BASE16384_ENCBUFSZ + * @param decbuf must be no less than BASE16384_DECBUFSZ + * @param flag BASE16384_FLAG_xxx value, add multiple flags by `|` + * @return the error code +*/ +base16384_err_t base16384_encode_file_detailed(base16384_typed_flag_params(const char*)); -// base16384_decode_file decodes input file to output file. -// use `-` to specify stdin/stdout -// encbuf & decbuf must be no less than BASE16384_ENCBUFSZ & BASE16384_DECBUFSZ -base16384_err_t base16384_decode_file(const char* input, const char* output, char* encbuf, char* decbuf); +/** + * @brief encode input `FILE*` to output `FILE*` + * @param input `FILE*` pointer + * @param output `FILE*` pointer + * @param encbuf must be no less than BASE16384_ENCBUFSZ + * @param decbuf must be no less than BASE16384_DECBUFSZ + * @param flag BASE16384_FLAG_xxx value, add multiple flags by `|` + * @return the error code +*/ +base16384_err_t base16384_encode_fp_detailed(base16384_typed_flag_params(FILE*)); -// base16384_decode_fp decodes input file to output file. -// encbuf & decbuf must be no less than BASE16384_ENCBUFSZ & BASE16384_DECBUFSZ -base16384_err_t base16384_decode_fp(FILE* input, FILE* output, char* encbuf, char* decbuf); +/** + * @brief encode input stream to output stream + * @param input file descripter + * @param output file descripter + * @param encbuf must be no less than BASE16384_ENCBUFSZ + * @param decbuf must be no less than BASE16384_DECBUFSZ + * @param flag BASE16384_FLAG_xxx value, add multiple flags by `|` + * @return the error code +*/ +base16384_err_t base16384_encode_fd_detailed(base16384_typed_flag_params(int)); -// base16384_decode_fd decodes input fd to output fd. -// encbuf & decbuf must be no less than BASE16384_ENCBUFSZ & BASE16384_DECBUFSZ -base16384_err_t base16384_decode_fd(int input, int output, char* encbuf, char* decbuf); +/** + * @brief decode input file to output file + * @param input filename or `-` to specify stdin + * @param output filename or `-` to specify stdout + * @param encbuf must be no less than BASE16384_ENCBUFSZ + * @param decbuf must be no less than BASE16384_DECBUFSZ + * @param flag BASE16384_FLAG_xxx value, add multiple flags by `|` + * @return the error code +*/ +base16384_err_t base16384_decode_file_detailed(base16384_typed_flag_params(const char*)); + +/** + * @brief decode input `FILE*` to output `FILE*` + * @param input `FILE*` pointer + * @param output `FILE*` pointer + * @param encbuf must be no less than BASE16384_ENCBUFSZ + * @param decbuf must be no less than BASE16384_DECBUFSZ + * @param flag BASE16384_FLAG_xxx value, add multiple flags by `|` + * @return the error code +*/ +base16384_err_t base16384_decode_fp_detailed(base16384_typed_flag_params(FILE*)); + +/** + * @brief decode input stream to output stream + * @param input file descripter + * @param output file descripter + * @param encbuf must be no less than BASE16384_ENCBUFSZ + * @param decbuf must be no less than BASE16384_DECBUFSZ + * @param flag BASE16384_FLAG_xxx value, add multiple flags by `|` + * @return the error code +*/ +base16384_err_t base16384_decode_fd_detailed(base16384_typed_flag_params(int)); + +#define BASE16384_WRAP_DECL(method, name, type) \ + base16384_err_t base16384_##method##_##name(base16384_typed_params(type)); + + BASE16384_WRAP_DECL(encode, file, const char*); + BASE16384_WRAP_DECL(encode, fp, FILE*); + BASE16384_WRAP_DECL(encode, fd, int); + + BASE16384_WRAP_DECL(decode, file, const char*); + BASE16384_WRAP_DECL(decode, fp, FILE*); + BASE16384_WRAP_DECL(decode, fd, int); + +#undef BASE16384_WRAP_DECL + +#undef base16384_typed_flag_params +#undef base16384_typed_params + +/** + * @brief call perror on error + * @param err the error + * @return the input parameter `err` +*/ +static inline base16384_err_t base16384_perror(base16384_err_t err) { + #define base16384_perror_case(n) case base16384_err_##n: perror("base16384_err_"#n) + if(err) switch(err) { + base16384_perror_case(get_file_size); break; + base16384_perror_case(fopen_output_file); break; + base16384_perror_case(fopen_input_file); break; + base16384_perror_case(write_file); break; + base16384_perror_case(open_input_file); break; + base16384_perror_case(map_input_file); break; + base16384_perror_case(read_file); break; + base16384_perror_case(invalid_file_name); break; + base16384_perror_case(invalid_commandline_parameter); break; + base16384_perror_case(invalid_decoding_checksum); break; + default: perror("base16384"); break; + } + #undef base16384_perror_case + return err; +} #endif diff --git a/binary.h b/binary.h new file mode 100644 index 0000000..46c7039 --- /dev/null +++ b/binary.h @@ -0,0 +1,124 @@ +#ifndef _BINARY_H_ +#define _BINARY_H_ + +/* binary.h + * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). + * Copyright (c) 2022-2024 Fumiama Minamoto. + * + * This program 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. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef __cosmopolitan // always le + #define be16toh(x) bswap_16(x) + #define be32toh(x) bswap_32(x) + #define htobe16(x) bswap_16(x) + #define htobe32(x) bswap_32(x) +#else + #include + #include + #include + #ifdef __linux__ + #include + #endif + #ifdef __FreeBSD__ + #include + #endif + #ifdef __NetBSD__ + #include + #endif + #ifdef __OpenBSD__ + #include + #define be16toh(x) betoh16(x) + #define be32toh(x) betoh32(x) + #ifdef IS_64BIT_PROCESSOR + #define be64toh(x) betoh64(x) + #endif + #endif + #ifdef __APPLE__ + #define be16toh(x) ntohs(x) + #define be32toh(x) ntohl(x) + #ifdef IS_64BIT_PROCESSOR + #define be64toh(x) ntohll(x) + #endif + #define htobe16(x) htons(x) + #define htobe32(x) htonl(x) + #ifdef IS_64BIT_PROCESSOR + #define htobe64(x) htonll(x) + #endif + #endif + #ifdef _WIN32 + #ifdef WORDS_BIGENDIAN + #define be16toh(x) (x) + #define be32toh(x) (x) + #ifdef IS_64BIT_PROCESSOR + #define be64toh(x) (x) + #endif + #define htobe16(x) (x) + #define htobe32(x) (x) + #ifdef IS_64BIT_PROCESSOR + #define htobe64(x) (x) + #endif + #else + #define be16toh(x) _byteswap_ushort(x) + #define be32toh(x) _byteswap_ulong(x) + #ifdef IS_64BIT_PROCESSOR + #define be64toh(x) _byteswap_uint64(x) + #endif + #define htobe16(x) _byteswap_ushort(x) + #define htobe32(x) _byteswap_ulong(x) + #ifdef IS_64BIT_PROCESSOR + #define htobe64(x) _byteswap_uint64(x) + #endif + #endif + #endif +#endif + +// leftrotate function definition +#define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (sizeof(x)*8 - (c)))) + +// initial sum value used in BASE16384_FLAG_SUM_CHECK_ON_REMAIN +#define BASE16384_SIMPLE_SUM_INIT_VALUE (0x8e29c213) + +static inline uint32_t calc_sum(uint32_t sum, size_t cnt, const char* encbuf) { + size_t i; + uint32_t buf; + for(i = 0; i < cnt; i++) { + buf = (uint32_t)(encbuf[i])&0xff; + buf = ((buf<<(24-6))&0x03000000) | ((buf<<(16-4))&0x00030000) | ((buf<<(8-2))&0x00000300) | (buf&0x03); + sum += buf; + sum = ~LEFTROTATE(sum, 3); + } + return sum; +} + +static inline int check_sum(uint32_t sum, uint32_t sum_read_raw, int offset) { + offset = offset%7; + if(!offset--) return 0; // no remain bits, pass + // offset 1: 0011 1111 1100 0000 remain: 3*2 bits + // offset 2: 0011 1111 1111 1111 0011 0000 0000 0000 remain: 6*2 bits + // offset 3: 0011 1111 1111 0000 remain: 2*2 bits + // offset 4: 0011 1111 1111 1111 0011 1100 0000 0000 remain: 5*2 bits + // offset 5: 0011 1111 1111 1100 remain: 1*2 bits + // offset 6: 0011 1111 1111 1111 0011 1111 0000 0000 remain: 4*2 bits + // encode: 0415263 (6-1) per 3bits, thus 0x021ab3 + int shift = sizeof(uint32_t)*8 - ((0x021ab3>>(offset*3))&0x07)*2; + uint32_t sum_read = be32toh(sum_read_raw) >> shift; + sum >>= shift; + #ifdef DEBUG + fprintf(stderr, "shift: %d, offset: %d, mysum: %08x, sumrd: %08x\n", shift, offset+1, sum, sum_read); + #endif + return sum != sum_read; +} + +#endif diff --git a/file.c b/file.c index 0d07623..61b2457 100644 --- a/file.c +++ b/file.c @@ -1,6 +1,6 @@ /* file.c * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). - * Copyright (c) 2022-2023 Fumiama Minamoto. + * Copyright (c) 2022-2024 Fumiama Minamoto. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef _WIN32 #include #include @@ -33,6 +34,7 @@ #endif #endif #include "base16384.h" +#include "binary.h" #ifdef __cosmopolitan #define get_file_size(filepath) ((off_t)GetFileSize(filepath)) @@ -45,100 +47,166 @@ static inline off_t get_file_size(const char* filepath) { #define is_standard_io(filename) (*(uint16_t*)(filename) == *(uint16_t*)"-") -base16384_err_t base16384_encode_file(const char* input, const char* output, char* encbuf, char* decbuf) { +#define goto_base16384_file_detailed_cleanup(method, reason, dobeforereturn) { \ + errnobak = errno; \ + retval = reason; \ + dobeforereturn; \ + goto base16384_##method##_file_detailed_cleanup; \ +} + +#define do_sum_check(flag) ((flag)&(BASE16384_FLAG_DO_SUM_CHECK_FORCELY|BASE16384_FLAG_SUM_CHECK_ON_REMAIN)) + +base16384_err_t base16384_encode_file_detailed(const char* input, const char* output, char* encbuf, char* decbuf, int flag) { off_t inputsize; - FILE* fp = NULL; - FILE* fpo; - if(!input || !output || strlen(input) <= 0 || strlen(output) <= 0) return base16384_err_invalid_file_name; - if(is_standard_io(input)) { // read from stdin - inputsize = 0; + FILE *fp = NULL, *fpo; + int errnobak = 0, is_stdin = is_standard_io(input); + base16384_err_t retval = base16384_err_ok; + if(!input || !output || strlen(input) <= 0 || strlen(output) <= 0) { + errno = EINVAL; + return base16384_err_invalid_file_name; + } + if(is_stdin) { // read from stdin + inputsize = _BASE16384_ENCBUFSZ; fp = stdin; } else inputsize = get_file_size(input); - if(inputsize < 0) { + if(inputsize <= 0) { + if(!inputsize) errno = EINVAL; return base16384_err_get_file_size; } fpo = is_standard_io(output)?stdout:fopen(output, "wb"); if(!fpo) { return base16384_err_fopen_output_file; } - if(!inputsize || inputsize > BASE16384_ENCBUFSZ) { // stdin or big file, use encbuf & fread - inputsize = BASE16384_ENCBUFSZ-7; + if(flag&BASE16384_FLAG_DO_SUM_CHECK_FORCELY || inputsize >= _BASE16384_ENCBUFSZ) { // stdin or big file, use encbuf & fread + inputsize = _BASE16384_ENCBUFSZ; #if defined _WIN32 || defined __cosmopolitan } #endif if(!fp) fp = fopen(input, "rb"); if(!fp) { - return base16384_err_fopen_input_file; + goto_base16384_file_detailed_cleanup(encode, base16384_err_fopen_input_file, {}); } - size_t cnt = 0; - fputc(0xFE, fpo); - fputc(0xFF, fpo); + if(!(flag&BASE16384_FLAG_NOHEADER)) { + fputc(0xFE, fpo); + fputc(0xFF, fpo); + } + size_t cnt; + uint32_t sum = BASE16384_SIMPLE_SUM_INIT_VALUE; while((cnt = fread(encbuf, sizeof(char), inputsize, fp)) > 0) { - int n = base16384_encode(encbuf, cnt, decbuf); - if(fwrite(decbuf, n, 1, fpo) <= 0) { - return base16384_err_write_file; + int n; + while(cnt%7) { + n = fread(encbuf+cnt, sizeof(char), 1, fp); + if(n > 0) cnt++; + else break; + } + if(do_sum_check(flag)) { + sum = calc_sum(sum, cnt, encbuf); + if(cnt%7) { // last encode + *(uint32_t*)(&encbuf[cnt]) = htobe32(sum); + #ifdef DEBUG + fprintf(stderr, "writesum: %08x\n", sum); + #endif + } + } + n = base16384_encode_unsafe(encbuf, cnt, decbuf); + if(n && fwrite(decbuf, n, 1, fpo) <= 0) { + goto_base16384_file_detailed_cleanup(encode, base16384_err_write_file, {}); } } - if(!is_standard_io(output)) fclose(fpo); - if(!is_standard_io(input)) fclose(fp); #if !defined _WIN32 && !defined __cosmopolitan } else { // small file, use mmap & fwrite int fd = open(input, O_RDONLY); if(fd < 0) { - return base16384_err_open_input_file; + goto_base16384_file_detailed_cleanup(encode, base16384_err_open_input_file, {}); } char *input_file = mmap(NULL, (size_t)inputsize+16, PROT_READ, MAP_PRIVATE, fd, 0); if(input_file == MAP_FAILED) { - return base16384_err_map_input_file; + goto_base16384_file_detailed_cleanup(encode, base16384_err_map_input_file, close(fd)); } - fputc(0xFE, fpo); - fputc(0xFF, fpo); - int n = base16384_encode(input_file, (int)inputsize, decbuf); - if(fwrite(decbuf, n, 1, fpo) <= 0) { - return base16384_err_write_file; + if(!(flag&BASE16384_FLAG_NOHEADER)) { + fputc(0xFE, fpo); + fputc(0xFF, fpo); + } + int n = base16384_encode_safe(input_file, (int)inputsize, decbuf); + if(n && fwrite(decbuf, n, 1, fpo) <= 0) { + goto_base16384_file_detailed_cleanup(encode, base16384_err_write_file, { + munmap(input_file, (size_t)inputsize); + close(fd); + }); } munmap(input_file, (size_t)inputsize); - if(!is_standard_io(output)) fclose(fpo); close(fd); } #endif - return base16384_err_ok; +base16384_encode_file_detailed_cleanup: + if(fpo && !is_standard_io(output)) fclose(fpo); + if(fp && !is_stdin) fclose(fp); + if(errnobak) errno = errnobak; + return retval; } -base16384_err_t base16384_encode_fp(FILE* input, FILE* output, char* encbuf, char* decbuf) { +base16384_err_t base16384_encode_fp_detailed(FILE* input, FILE* output, char* encbuf, char* decbuf, int flag) { if(!input) { return base16384_err_fopen_input_file; } if(!output) { return base16384_err_fopen_output_file; } - off_t inputsize = BASE16384_ENCBUFSZ-7; - size_t cnt = 0; - fputc(0xFE, output); - fputc(0xFF, output); + if(!(flag&BASE16384_FLAG_NOHEADER)) { + fputc(0xFE, output); + fputc(0xFF, output); + } + off_t inputsize = _BASE16384_ENCBUFSZ; + uint32_t sum = BASE16384_SIMPLE_SUM_INIT_VALUE; + size_t cnt; while((cnt = fread(encbuf, sizeof(char), inputsize, input)) > 0) { - int n = base16384_encode(encbuf, cnt, decbuf); - if(fwrite(decbuf, n, 1, output) <= 0) { + int n; + while(cnt%7) { + n = fread(encbuf+cnt, sizeof(char), 1, input); + if(n > 0) cnt++; + else break; + } + if(do_sum_check(flag)) { + sum = calc_sum(sum, cnt, encbuf); + if(cnt%7) { // last encode + *(uint32_t*)(&encbuf[cnt]) = htobe32(sum); + } + } + n = base16384_encode_unsafe(encbuf, cnt, decbuf); + if(n && fwrite(decbuf, n, 1, output) <= 0) { return base16384_err_write_file; } } return base16384_err_ok; } -base16384_err_t base16384_encode_fd(int input, int output, char* encbuf, char* decbuf) { +base16384_err_t base16384_encode_fd_detailed(int input, int output, char* encbuf, char* decbuf, int flag) { if(input < 0) { return base16384_err_fopen_input_file; } if(output < 0) { return base16384_err_fopen_output_file; } - off_t inputsize = BASE16384_ENCBUFSZ-7; + off_t inputsize = _BASE16384_ENCBUFSZ; size_t cnt = 0; - write(output, "\xfe\xff", 2); + uint32_t sum = BASE16384_SIMPLE_SUM_INIT_VALUE; + if(!(flag&BASE16384_FLAG_NOHEADER)) write(output, "\xfe\xff", 2); while((cnt = read(input, encbuf, inputsize)) > 0) { - int n = base16384_encode(encbuf, cnt, decbuf); - if(write(output, decbuf, n) < n) { + int n; + while(cnt%7) { + n = read(input, encbuf+cnt, sizeof(char)); + if(n > 0) cnt++; + else break; + } + if(do_sum_check(flag)) { + sum = calc_sum(sum, cnt, encbuf); + if(cnt%7) { // last encode + *(uint32_t*)(&encbuf[cnt]) = htobe32(sum); + } + } + n = base16384_encode_unsafe(encbuf, cnt, decbuf); + if(n && write(output, decbuf, n) < n) { return base16384_err_write_file; } } @@ -161,128 +229,232 @@ static inline int is_next_end(FILE* fp) { return 0; } -base16384_err_t base16384_decode_file(const char* input, const char* output, char* encbuf, char* decbuf) { +base16384_err_t base16384_decode_file_detailed(const char* input, const char* output, char* encbuf, char* decbuf, int flag) { off_t inputsize; FILE* fp = NULL; FILE* fpo; - if(!input || !output || strlen(input) <= 0 || strlen(output) <= 0) return base16384_err_invalid_file_name; - if(is_standard_io(input)) { // read from stdin - inputsize = 0; + uint32_t sum = BASE16384_SIMPLE_SUM_INIT_VALUE; + base16384_err_t retval = base16384_err_ok; + int errnobak = 0, is_stdin = is_standard_io(input); + if(!input || !output || strlen(input) <= 0 || strlen(output) <= 0) { + errno = EINVAL; + return base16384_err_invalid_file_name; + } + if(is_stdin) { // read from stdin + inputsize = _BASE16384_DECBUFSZ; fp = stdin; } else inputsize = get_file_size(input); - if(inputsize < 0) { + if(inputsize <= 0) { + if(!inputsize) errno = EINVAL; return base16384_err_get_file_size; } fpo = is_standard_io(output)?stdout:fopen(output, "wb"); if(!fpo) { return base16384_err_fopen_output_file; } - if(!inputsize || inputsize > BASE16384_DECBUFSZ) { // stdin or big file, use decbuf & fread - inputsize = BASE16384_DECBUFSZ/8*8; + int loop_count = 0; + if(inputsize >= _BASE16384_DECBUFSZ) { // stdin or big file, use decbuf & fread + if(!is_stdin) loop_count = inputsize/_BASE16384_DECBUFSZ; + inputsize = _BASE16384_DECBUFSZ; #if defined _WIN32 || defined __cosmopolitan } #endif if(!fp) fp = fopen(input, "rb"); if(!fp) { - return base16384_err_fopen_input_file; + goto_base16384_file_detailed_cleanup(decode, base16384_err_fopen_input_file, {}); } - int cnt = 0; - int end = 0; rm_head(fp); + if(errno) { + goto_base16384_file_detailed_cleanup(decode, base16384_err_read_file, {}); + } + int cnt, last_encbuf_cnt = 0, last_decbuf_cnt = 0, offset = 0; + size_t total_decoded_len = 0; while((cnt = fread(decbuf, sizeof(char), inputsize, fp)) > 0) { + int n; + while(cnt%8) { + n = fread(decbuf+cnt, sizeof(char), 1, fp); + if(n > 0) cnt++; + else break; + } + int end; if((end = is_next_end(fp))) { decbuf[cnt++] = '='; decbuf[cnt++] = end; } - if(fwrite(encbuf, base16384_decode(decbuf, cnt, encbuf), 1, fpo) <= 0) { - return base16384_err_write_file; + if(errno) goto_base16384_file_detailed_cleanup(decode, base16384_err_read_file, {}); + offset = decbuf[cnt-1]; + last_decbuf_cnt = cnt; + cnt = base16384_decode_unsafe(decbuf, cnt, encbuf); + if(cnt && fwrite(encbuf, cnt, 1, fpo) <= 0) { + goto_base16384_file_detailed_cleanup(decode, base16384_err_write_file, {}); } + total_decoded_len += cnt; + if(do_sum_check(flag)) sum = calc_sum(sum, cnt, encbuf); + last_encbuf_cnt = cnt; + } + if(do_sum_check(flag) + && (flag&BASE16384_FLAG_DO_SUM_CHECK_FORCELY || total_decoded_len >= _BASE16384_ENCBUFSZ) + && last_decbuf_cnt > 2 + && decbuf[last_decbuf_cnt-2] == '=' + && check_sum(sum, *(uint32_t*)(&encbuf[last_encbuf_cnt]), offset)) { + errno = EINVAL; + goto_base16384_file_detailed_cleanup(decode, base16384_err_invalid_decoding_checksum, {}); } - if(!is_standard_io(output)) fclose(fpo); - if(!is_standard_io(input)) fclose(fp); #if !defined _WIN32 && !defined __cosmopolitan } else { // small file, use mmap & fwrite int fd = open(input, O_RDONLY); if(fd < 0) { - return base16384_err_open_input_file; + goto_base16384_file_detailed_cleanup(decode, base16384_err_open_input_file, {}); } char *input_file = mmap(NULL, (size_t)inputsize+16, PROT_READ, MAP_PRIVATE, fd, 0); if(input_file == MAP_FAILED) { - return base16384_err_map_input_file; + goto_base16384_file_detailed_cleanup(decode, base16384_err_map_input_file, close(fd)); } - int off = skip_offset(input_file); - if(fwrite(encbuf, base16384_decode(input_file+off, inputsize-off, encbuf), 1, fpo) <= 0) { - return base16384_err_write_file; + int n = skip_offset(input_file); + n = base16384_decode_safe(input_file+n, inputsize-n, encbuf); + if(n && fwrite(encbuf, n, 1, fpo) <= 0) { + goto_base16384_file_detailed_cleanup(decode, base16384_err_write_file, { + munmap(input_file, (size_t)inputsize); + close(fd); + }); } munmap(input_file, (size_t)inputsize); - if(!is_standard_io(output)) fclose(fpo); close(fd); } #endif - return base16384_err_ok; +base16384_decode_file_detailed_cleanup: + if(fpo && !is_standard_io(output)) fclose(fpo); + if(fp && !is_stdin) fclose(fp); + if(errnobak) errno = errnobak; + return retval; } -base16384_err_t base16384_decode_fp(FILE* input, FILE* output, char* encbuf, char* decbuf) { +base16384_err_t base16384_decode_fp_detailed(FILE* input, FILE* output, char* encbuf, char* decbuf, int flag) { if(!input) { + errno = EINVAL; return base16384_err_fopen_input_file; } if(!output) { + errno = EINVAL; return base16384_err_fopen_output_file; } - off_t inputsize = BASE16384_DECBUFSZ/8*8; - int cnt = 0; - int end = 0; + off_t inputsize = _BASE16384_DECBUFSZ; + uint32_t sum = BASE16384_SIMPLE_SUM_INIT_VALUE; rm_head(input); + if(errno) { + return base16384_err_read_file; + } + int cnt, last_encbuf_cnt = 0, last_decbuf_cnt = 0, offset = 0; + size_t total_decoded_len = 0; while((cnt = fread(decbuf, sizeof(char), inputsize, input)) > 0) { + int n; + while(cnt%8) { + n = fread(decbuf+cnt, sizeof(char), 1, input); + if(n > 0) cnt++; + else break; + } + int end; if((end = is_next_end(input))) { decbuf[cnt++] = '='; decbuf[cnt++] = end; } - if(fwrite(encbuf, base16384_decode(decbuf, cnt, encbuf), 1, output) <= 0) { + if(errno) return base16384_err_read_file; + offset = decbuf[cnt-1]; + last_decbuf_cnt = cnt; + cnt = base16384_decode_unsafe(decbuf, cnt, encbuf); + if(cnt && fwrite(encbuf, cnt, 1, output) <= 0) { return base16384_err_write_file; } + total_decoded_len += cnt; + if(do_sum_check(flag)) sum = calc_sum(sum, cnt, encbuf); + last_encbuf_cnt = cnt; + } + if(do_sum_check(flag) + && (flag&BASE16384_FLAG_DO_SUM_CHECK_FORCELY || total_decoded_len >= _BASE16384_ENCBUFSZ) + && last_decbuf_cnt > 2 + && decbuf[last_decbuf_cnt-2] == '=' + && check_sum(sum, *(uint32_t*)(&encbuf[last_encbuf_cnt]), offset)) { + errno = EINVAL; + return base16384_err_invalid_decoding_checksum; } return base16384_err_ok; } -static inline int is_next_end_fd(int fd) { - char ch = 0; - read(fd, &ch, 1); +static inline uint16_t is_next_end_fd(int fd) { + uint8_t ch = 0; + if(read(fd, &ch, 1) != 1) return (uint16_t)EOF; + uint16_t ret = (uint16_t)ch & 0x00ff; if(ch == '=') { - read(fd, &ch, 1); + if(read(fd, &ch, 1) != 1) return (uint16_t)EOF; + ret <<= 8; + ret |= (uint16_t)ch & 0x00ff; } - return (int)ch; + return ret; } -base16384_err_t base16384_decode_fd(int input, int output, char* encbuf, char* decbuf) { +base16384_err_t base16384_decode_fd_detailed(int input, int output, char* encbuf, char* decbuf, int flag) { if(input < 0) { + errno = EINVAL; return base16384_err_fopen_input_file; } if(output < 0) { + errno = EINVAL; return base16384_err_fopen_output_file; } - off_t inputsize = BASE16384_DECBUFSZ/8*8; - int cnt = 0; - int end = 0; + + off_t inputsize = _BASE16384_DECBUFSZ; + uint32_t sum = BASE16384_SIMPLE_SUM_INIT_VALUE; + uint8_t remains[8]; + decbuf[0] = 0; - if(read(input, decbuf, 2) < 2) { + if(read(input, remains, 2) != 2) { return base16384_err_read_file; } - if(decbuf[0] != (char)(0xfe)) cnt = 2; - while((end = read(input, decbuf+cnt, inputsize-cnt)) > 0 || cnt > 0) { - if(end > 0) { - cnt += end; - if((end = is_next_end_fd(input))) { - decbuf[cnt++] = '='; - decbuf[cnt++] = end; - end = 0; - } else end = 1; - } else end = 0; - cnt = base16384_decode(decbuf, cnt, encbuf); - if(write(output, encbuf, cnt) < cnt) { + + int p = 0; + if(remains[0] != (uint8_t)(0xfe)) p = 2; + + int n, last_encbuf_cnt = 0, last_decbuf_cnt = 0, offset = 0; + size_t total_decoded_len = 0; + while((n = read(input, decbuf+p, inputsize-p)) > 0) { + if(p) { + memcpy(decbuf, remains, p); + n += p; + p = 0; + } + int x; + while(n%8) { + x = read(input, decbuf+n, sizeof(char)); + if(x > 0) n++; + else break; + } + uint16_t next = is_next_end_fd(input); + if(errno) { + return base16384_err_read_file; + } + if((uint16_t)(~next)) { + if(next&0xff00) { + decbuf[n++] = '='; + decbuf[n++] = (char)(next&0x00ff); + } else remains[p++] = (char)(next&0x00ff); + } + offset = decbuf[n-1]; + last_decbuf_cnt = n; + n = base16384_decode_unsafe(decbuf, n, encbuf); + if(n && write(output, encbuf, n) != n) { return base16384_err_write_file; } - cnt = end; + total_decoded_len += n; + if(do_sum_check(flag)) sum = calc_sum(sum, n, encbuf); + last_encbuf_cnt = n; + } + if(do_sum_check(flag) + && (flag&BASE16384_FLAG_DO_SUM_CHECK_FORCELY || total_decoded_len >= _BASE16384_ENCBUFSZ) + && last_decbuf_cnt > 2 + && decbuf[last_decbuf_cnt-2] == '=' + && check_sum(sum, *(uint32_t*)(&encbuf[last_encbuf_cnt]), offset)) { + errno = EINVAL; + return base16384_err_invalid_decoding_checksum; } return base16384_err_ok; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..bb82a5e --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 2.8.12) +if (POLICY CMP0048) + cmake_policy(SET CMP0048 NEW) +endif (POLICY CMP0048) +project(base16384_test VERSION 1.0.0) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +file (GLOB_RECURSE C_FILES "*.c") +foreach (C_FILE ${C_FILES}) + get_filename_component(FILE_NAME ${C_FILE} NAME_WE) + message(STATUS "Add test ${FILE_NAME}") + add_executable(${FILE_NAME} ${C_FILE}) + target_link_libraries(${FILE_NAME} base16384_s) + add_test(NAME do_${FILE_NAME} COMMAND ${FILE_NAME}) +endforeach () diff --git a/test/coder_test.c b/test/coder_test.c new file mode 100644 index 0000000..d20674a --- /dev/null +++ b/test/coder_test.c @@ -0,0 +1,91 @@ +/* test/coder_test.c + * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). + * Copyright (c) 2022-2024 Fumiama Minamoto. + * + * This program 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. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "base16384.h" + +#define TEST_SIZE (4096) + +char encbuf[TEST_SIZE+16]; +char decbuf[TEST_SIZE/7*8+16]; +char tstbuf[TEST_SIZE+16]; + +#define loop_diff(target) \ + for(i = start; i < end; i++) { \ + if (encbuf[i] != tstbuf[i]) { \ + if(n) { \ + fprintf(stderr, " @%d", i); \ + n = 0; \ + } \ + fprintf(stderr, " %02x", (uint8_t)(target[i])); \ + } else if(!n) { \ + n = 1; \ + fprintf(stderr, " ..."); \ + } \ + } + +#define return_error(i, n) { \ + int end = i; \ + int start; \ + for(start = 0; start < end; start++) { \ + if(encbuf[start] != tstbuf[start]) break; \ + } \ + fprintf(stderr, "result mismatch @ loop %d, decsz: %d, first diff @ %d\n", i, n, start); \ + fprintf(stderr, "expect"); \ + n = 1; \ + loop_diff(encbuf); \ + fprintf(stderr, "\ngot "); \ + n = 1; \ + loop_diff(tstbuf); \ + fputc('\n', stderr); \ + return 1; \ +} + +#define test_batch(encode, decode) \ + fputs("testing base16384_"#encode"/base16384_"#decode"...\n", stderr); \ + for(i = 0; i <= TEST_SIZE; i++) { \ + n = base16384_##encode(encbuf, i, decbuf); \ + n = base16384_##decode(decbuf, n, tstbuf); \ + if (memcmp(encbuf, tstbuf, n)) return_error(i, n); \ + } + +int main() { + srand(time(NULL)); + int i, n; + for(i = 0; i <= TEST_SIZE; i += sizeof(int)) { + *(int*)(&encbuf[i]) = rand(); + } + + test_batch(encode, decode); + test_batch(encode, decode_unsafe); + test_batch(encode, decode_safe); + + test_batch(encode_unsafe, decode); + test_batch(encode_unsafe, decode_unsafe); + test_batch(encode_unsafe, decode_safe); + + test_batch(encode_safe, decode); + test_batch(encode_safe, decode_unsafe); + test_batch(encode_safe, decode_safe); + return 0; +} diff --git a/test/file_test.c b/test/file_test.c new file mode 100644 index 0000000..0e69266 --- /dev/null +++ b/test/file_test.c @@ -0,0 +1,165 @@ +/* test/file_test.c + * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). + * Copyright (c) 2022-2024 Fumiama Minamoto. + * + * This program 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. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef _WIN32 + #include + #define ftruncate _chsize_s +#else + #define _POSIX1_SOURCE 2 + #include +#endif +#include +#include +#include +#include +#include +#include + +#include "base16384.h" +#include "binary.h" +#include "file_test.h" + +#define TEST_SIZE (4096) +#define TEST_INPUT_FILENAME "file_test_input.bin" +#define TEST_OUTPUT_FILENAME "file_test_output.bin" +#define TEST_VALIDATE_FILENAME "file_test_validate.bin" + +char encbuf[BASE16384_ENCBUFSZ]; +char decbuf[BASE16384_DECBUFSZ]; +char tstbuf[BASE16384_ENCBUFSZ]; + +#define init_input_file() \ + for(i = 0; i < BASE16384_ENCBUFSZ; i += sizeof(int)) { \ + *(int*)(&encbuf[i]) = rand(); \ + } \ + fp = fopen(TEST_INPUT_FILENAME, "wb"); \ + ok(!fp, "fopen"); \ + ok(fwrite(encbuf, BASE16384_ENCBUFSZ, 1, fp) != 1, "fwrite"); \ + ok(fclose(fp), "fclose"); \ + fputs("input file created.\n", stderr); + +#define test_file_detailed(flag) \ + fputs("testing base16384_en/decode_file with flag "#flag"...\n", stderr); \ + init_input_file(); \ + for(i = TEST_SIZE; i > 0; i--) { \ + reset_and_truncate(fd, i); \ + loop_ok(close(fd), i, "close"); \ + \ + err = base16384_encode_file_detailed(TEST_INPUT_FILENAME, TEST_OUTPUT_FILENAME, encbuf, decbuf, flag); \ + base16384_loop_ok(err); \ + \ + err = base16384_decode_file_detailed(TEST_OUTPUT_FILENAME, TEST_VALIDATE_FILENAME, encbuf, decbuf, flag); \ + base16384_loop_ok(err); \ + \ + validate_result(); \ + } + +#define test_fp_detailed(flag) \ + fputs("testing base16384_en/decode_fp with flag "#flag"...\n", stderr); \ + init_input_file(); \ + for(i = TEST_SIZE; i > 0; i--) { \ + reset_and_truncate(fd, i); \ + loop_ok(close(fd), i, "close"); \ + \ + FILE* fpin = fopen(TEST_INPUT_FILENAME, "rb"); \ + loop_ok(!fpin, i, "fopen"); \ + \ + FILE* fpout = fopen(TEST_OUTPUT_FILENAME, "wb+"); \ + loop_ok(!fpout, i, "fopen"); \ + \ + err = base16384_encode_fp_detailed(fpin, fpout, encbuf, decbuf, flag); \ + base16384_loop_ok(err); \ + \ + loop_ok(fclose(fpin), i, "fclose"); \ + \ + FILE* fpval = fopen(TEST_VALIDATE_FILENAME, "wb"); \ + loop_ok(!fpval, i, "fopen"); \ + \ + rewind(fpout); \ + \ + err = base16384_decode_fp_detailed(fpout, fpval, encbuf, decbuf, flag); \ + base16384_loop_ok(err); \ + \ + loop_ok(fclose(fpout), i, "fclose"); \ + loop_ok(fclose(fpval), i, "fclose"); \ + \ + validate_result(); \ + } + +#define test_fd_detailed(flag) \ + fputs("testing base16384_en/decode_fd with flag "#flag"...\n", stderr); \ + init_input_file(); \ + for(i = TEST_SIZE; i > 0; i--) { \ + reset_and_truncate(fd, i); \ + \ + int fdout = open(TEST_OUTPUT_FILENAME, O_RDWR|O_TRUNC|O_CREAT|O_APPEND); \ + loop_ok(!fdout, i, "open"); \ + \ + err = base16384_encode_fd_detailed(fd, fdout, encbuf, decbuf, 0); \ + base16384_loop_ok(err); \ + loop_ok(close(fd), i, "close"); \ + \ + int fdval = open(TEST_VALIDATE_FILENAME, O_WRONLY|O_TRUNC|O_CREAT); \ + loop_ok(!fdval, i, "open"); \ + \ + loop_ok(lseek(fdout, 0, SEEK_SET), i, "lseek"); \ + \ + err = base16384_decode_fd_detailed(fdout, fdval, encbuf, decbuf, 0); \ + base16384_loop_ok(err); \ + \ + loop_ok(close(fdout), i, "close"); \ + loop_ok(close(fdval), i, "close"); \ + \ + validate_result(); \ + } + +#define test_detailed(name) \ + test_##name##_detailed(0); \ +\ + test_##name##_detailed(BASE16384_FLAG_NOHEADER); \ + test_##name##_detailed(BASE16384_FLAG_SUM_CHECK_ON_REMAIN); \ + test_##name##_detailed(BASE16384_FLAG_DO_SUM_CHECK_FORCELY); \ +\ + test_##name##_detailed(BASE16384_FLAG_NOHEADER|BASE16384_FLAG_SUM_CHECK_ON_REMAIN); \ + test_##name##_detailed(BASE16384_FLAG_NOHEADER|BASE16384_FLAG_DO_SUM_CHECK_FORCELY); \ +\ + test_##name##_detailed(BASE16384_FLAG_SUM_CHECK_ON_REMAIN|BASE16384_FLAG_DO_SUM_CHECK_FORCELY); \ +\ + test_##name##_detailed(BASE16384_FLAG_NOHEADER|BASE16384_FLAG_SUM_CHECK_ON_REMAIN|BASE16384_FLAG_DO_SUM_CHECK_FORCELY); + + +#define remove_test_files() \ + remove(TEST_INPUT_FILENAME); \ + remove(TEST_OUTPUT_FILENAME); \ + remove(TEST_VALIDATE_FILENAME); + +int main() { + srand(time(NULL)); + + FILE* fp; + int fd, i; + base16384_err_t err; + + test_detailed(file); + test_detailed(fp); + test_detailed(fd); + + remove_test_files(); + + return 0; +} diff --git a/test/file_test.h b/test/file_test.h new file mode 100644 index 0000000..fd97f4d --- /dev/null +++ b/test/file_test.h @@ -0,0 +1,85 @@ +#ifndef _FILE_TEST_H_ +#define _FILE_TEST_H_ + +/* test/file_test.h + * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). + * Copyright (c) 2022-2024 Fumiama Minamoto. + * + * This program 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. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define ok(has_failed, reason) \ + if (has_failed) { \ + perror(reason); \ + return 1; \ + } + +#define loop_ok(has_failed, i, reason) \ + if (has_failed) { \ + fprintf(stderr, "loop @%d: ", i); \ + perror(reason); \ + return 1; \ + } + +#define reset_and_truncate(fd, i) { \ + fd = open(TEST_INPUT_FILENAME, O_RDWR); \ + ok(!fd, "open"); \ + loop_ok(lseek(fd, 0, SEEK_SET), i, "lseek"); \ + loop_ok(ftruncate(fd, i), i, "ftruncate"); \ +} + +#define base16384_loop_ok(err) \ + if (err) { \ + fprintf(stderr, "loop @%d: ", i); \ + base16384_perror(err); \ + return 1; \ + } + +#define validate_result() \ + uint64_t buf, sum_input = 0, sum_validate = 0; \ + fp = fopen(TEST_INPUT_FILENAME, "rb"); { \ + loop_ok(!fp, i, "fopen"); \ + int cnt; \ + while ((cnt = fread(&buf, 1, sizeof(sum_input), fp)) > 0) { \ + int n; \ + buf = 0; \ + while(cnt < sizeof(sum_input)) { \ + n = fread((uint8_t*)(&buf)+cnt, 1, 1, fp); \ + if (n) cnt++; \ + else break; \ + } \ + sum_input += buf; \ + } \ + } fclose(fp); \ + fp = fopen(TEST_VALIDATE_FILENAME, "rb"); { \ + loop_ok(!fp, i, "fopen"); \ + int cnt; \ + while ((cnt = fread(&buf, 1, sizeof(sum_validate), fp)) > 0) { \ + int n; \ + buf = 0; \ + while(cnt < sizeof(sum_validate)) { \ + n = fread((uint8_t*)(&buf)+cnt, 1, 1, fp); \ + if (n) cnt++; \ + else break; \ + } \ + sum_validate += buf; \ + } \ + } fclose(fp); \ + if (sum_input != sum_validate) { \ + fprintf(stderr, "loop @%d, expect: %016llx, got: %016llx: ", i, (unsigned long long)sum_input, (unsigned long long)sum_validate); \ + fputs(TEST_INPUT_FILENAME " and " TEST_VALIDATE_FILENAME " mismatch.", stderr); \ + return 1; \ + } + +#endif \ No newline at end of file diff --git a/test/wrap_test.c b/test/wrap_test.c new file mode 100644 index 0000000..2e87067 --- /dev/null +++ b/test/wrap_test.c @@ -0,0 +1,140 @@ +/* test/wrap_test.c + * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). + * Copyright (c) 2022-2024 Fumiama Minamoto. + * + * This program 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. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef _WIN32 + #include + #define ftruncate _chsize_s +#else + #define _POSIX1_SOURCE 2 + #include +#endif +#include +#include +#include +#include +#include +#include + +#include "base16384.h" +#include "binary.h" +#include "file_test.h" + +#define TEST_SIZE (4096) +#define TEST_INPUT_FILENAME "wrap_test_input.bin" +#define TEST_OUTPUT_FILENAME "wrap_test_output.bin" +#define TEST_VALIDATE_FILENAME "wrap_test_validate.bin" + +char encbuf[BASE16384_ENCBUFSZ]; +char decbuf[BASE16384_DECBUFSZ]; +char tstbuf[BASE16384_ENCBUFSZ]; + +#define init_input_file() \ + for(i = 0; i < BASE16384_ENCBUFSZ; i += sizeof(int)) { \ + *(int*)(&encbuf[i]) = rand(); \ + } \ + fp = fopen(TEST_INPUT_FILENAME, "wb"); \ + ok(!fp, "fopen"); \ + ok(fwrite(encbuf, BASE16384_ENCBUFSZ, 1, fp) != 1, "fwrite"); \ + ok(fclose(fp), "fclose"); \ + fputs("input file created.\n", stderr); + +int main() { + srand(time(NULL)); + + FILE* fp; + int fd, i; + base16384_err_t err; + + fputs("testing base16384_en/decode_file...\n", stderr); + init_input_file(); + for(i = TEST_SIZE; i > 0; i--) { + reset_and_truncate(fd, i); + loop_ok(close(fd), i, "close"); + + err = base16384_encode_file(TEST_INPUT_FILENAME, TEST_OUTPUT_FILENAME, encbuf, decbuf); + base16384_loop_ok(err); + + err = base16384_decode_file(TEST_OUTPUT_FILENAME, TEST_VALIDATE_FILENAME, encbuf, decbuf); + base16384_loop_ok(err); + + validate_result(); + } + + fputs("testing base16384_en/decode_fp...\n", stderr); + init_input_file(); + for(i = TEST_SIZE; i > 0; i--) { + reset_and_truncate(fd, i); + loop_ok(close(fd), i, "close"); + + FILE* fpin = fopen(TEST_INPUT_FILENAME, "rb"); + loop_ok(!fpin, i, "fopen"); + + FILE* fpout = fopen(TEST_OUTPUT_FILENAME, "wb+"); + loop_ok(!fpout, i, "fopen"); + + err = base16384_encode_fp(fpin, fpout, encbuf, decbuf); + base16384_loop_ok(err); + + loop_ok(fclose(fpin), i, "fclose"); + + FILE* fpval = fopen(TEST_VALIDATE_FILENAME, "wb"); + loop_ok(!fpval, i, "fopen"); + + rewind(fpout); + + err = base16384_decode_fp(fpout, fpval, encbuf, decbuf); + base16384_loop_ok(err); + + loop_ok(fclose(fpout), i, "fclose"); + loop_ok(fclose(fpval), i, "fclose"); + + validate_result(); + } + + fputs("testing base16384_en/decode_fd...\n", stderr); + init_input_file(); + for(i = TEST_SIZE; i > 0; i--) { + reset_and_truncate(fd, i); + + int fdout = open(TEST_OUTPUT_FILENAME, O_RDWR|O_TRUNC|O_CREAT|O_APPEND); + loop_ok(!fdout, i, "open"); + + err = base16384_encode_fd(fd, fdout, encbuf, decbuf); + base16384_loop_ok(err); + loop_ok(close(fd), i, "close"); + + int fdval = open(TEST_VALIDATE_FILENAME, O_WRONLY|O_TRUNC|O_CREAT); + loop_ok(!fdval, i, "open"); + + loop_ok(lseek(fdout, 0, SEEK_SET), i, "lseek"); + + err = base16384_decode_fd(fdout, fdval, encbuf, decbuf); + base16384_loop_ok(err); + + loop_ok(close(fdout), i, "close"); + loop_ok(close(fdval), i, "close"); + + validate_result(); + } + + remove(TEST_INPUT_FILENAME); + remove(TEST_OUTPUT_FILENAME); + remove(TEST_VALIDATE_FILENAME); + + return 0; +} diff --git a/wrap.c b/wrap.c new file mode 100644 index 0000000..5358b5f --- /dev/null +++ b/wrap.c @@ -0,0 +1,38 @@ +/* wrap.c + * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). + * Copyright (c) 2022-2024 Fumiama Minamoto. + * + * This program 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. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "base16384.h" + +#define base16384_typed_params(type) type input, type output, char* encbuf, char* decbuf + +#define BASE16384_WRAP_DECL(method, name, type) \ + base16384_err_t base16384_##method##_##name(base16384_typed_params(type)) { \ + return base16384_##method##_##name##_detailed(input, output, encbuf, decbuf, 0); \ + } + + BASE16384_WRAP_DECL(encode, file, const char*); + BASE16384_WRAP_DECL(encode, fp, FILE*); + BASE16384_WRAP_DECL(encode, fd, int); + + BASE16384_WRAP_DECL(decode, file, const char*); + BASE16384_WRAP_DECL(decode, fp, FILE*); + BASE16384_WRAP_DECL(decode, fd, int); + +#undef BASE16384_WRAP_DECL + +#undef base16384_typed_params