1
0
Fork 0
mirror of https://github.com/seiichiro0185/sailotp.git synced 2024-05-18 00:20:55 +00:00

Compare commits

...

189 commits

Author SHA1 Message Date
seiichiro 90314355e0 Fix Empty Token List after Restart for New Installs 2023-02-26 19:11:38 +01:00
seiichiro 78b9e561bd Merge branch 'fix-crypto' into develop 2023-02-26 16:39:23 +01:00
seiichiro 4d6f5a2ba1 Prepare Release 1.11.0 2023-02-20 17:03:13 +01:00
seiichiro 11a6fb9142 Add Error Crude Handling for Encryption/Decryption 2023-02-20 16:48:52 +01:00
seiichiro 62a1b88ab0 Use FilePicker for Import 2023-02-20 16:38:40 +01:00
seiichiro 2017f4510a Switch File Encryption to OpenSSL 2023-02-20 16:10:57 +01:00
seiichiro 029d2d937c Merge branch 'release-1.10.2' into develop 2023-01-25 15:47:06 +01:00
seiichiro 672f988c00 Release 1.10.2-1 2023-01-25 15:46:14 +01:00
seiichiro f06cb462f9
Merge pull request #69 from Keeper-of-the-Keys/patch-1
Add Sailjail Camera permissions
2023-01-25 15:16:05 +01:00
Keeper-of-the-Keys 2bb7f90e06
Add Sailjail Camera permissions
Camera permissions are missing this makes scanning QR codes difficult.
2023-01-24 23:58:00 +02:00
seiichiro 5c37d0816e Merge branch 'release-1.10.1' into develop 2022-12-27 17:34:05 +01:00
seiichiro 223887b09a Release 1.10.1 2022-12-27 17:33:52 +01:00
seiichiro d3b47073f6
Merge pull request #68 from eson57/patch-1
Update harbour-sailotp-sv.ts
2022-12-27 15:45:44 +01:00
Åke Engelbrektson 6e349843c2
Create harbour-sailotp-sv.ts
Sorry. I copy /paste the old file, here's the right one.
2022-12-19 09:01:26 +01:00
Åke Engelbrektson f14324b715
Delete harbour-sailotp-sv.ts 2022-12-19 08:59:33 +01:00
Åke Engelbrektson d54013d5c6
Update harbour-sailotp-sv.ts
Update Swedish translation
2022-12-19 08:54:11 +01:00
seiichiro 9d346f649c Merge branch 'release-1.10' into develop 2022-12-18 13:13:48 +01:00
seiichiro d0dfbfb009 Prepare Release 1.10.0-1 2022-12-18 13:12:59 +01:00
seiichiro 020d917fe8
Merge pull request #65 from AndreySV/custom-period
Implement custom period for TOTP tokens
2022-12-18 11:15:55 +01:00
seiichiro 7def525735
Merge pull request #67 from DrYak/patch-1
Add missing Sailjail permissions to .desktop file
2022-12-18 11:06:03 +01:00
DrYak f62f3298ab
Add missing Sailjail permissions to .desktop file
- Recent versions of SailfishOS have made permissions mandatory
- Without _UserDirs_ (for `/home/nemo`) or _RemovableMedia_ (for SD cards and USB-C sticks) SailOTP cannot Import/Export.
2022-12-15 16:39:08 +01:00
Andrey Skvortsov 6bec89dfa2 Ignore built files 2022-11-14 21:46:26 +03:00
Andrey Skvortsov 5339deb2df Add custom period for TOTP tokens 2022-11-14 21:23:12 +03:00
Andrey Skvortsov e3fd514d55 Set default DB version to 4.0 2022-11-14 19:33:02 +03:00
seiichiro c7303e3dc4 Merge pull Request #56 from JSEHV/develop 2021-06-27 21:38:44 +02:00
Åke Engelbrektson 925c41918a Update harbour-sailotp-sv.ts
Update Swedish translation
2021-06-27 21:37:08 +02:00
1Zgp f64e1ee305 Update harbour-sailotp-hu.ts 2021-06-27 21:37:08 +02:00
seiichiro ff0c0a08a2 Merge Dutch Translation Update 2021-06-27 21:36:36 +02:00
caio2k d941809274 Update pt_br translation and updated html entities 2021-06-27 21:35:33 +02:00
seiichiro a623ede263
Merge pull request #57 from eson57/patch-1
Update harbour-sailotp-sv.ts
2021-06-27 21:31:47 +02:00
seiichiro 3d77a611f9
Merge pull request #58 from 1Zgp/develop
Update harbour-sailotp-hu.ts
2021-06-27 21:31:39 +02:00
1Zgp 13004850a3
Update harbour-sailotp-hu.ts 2021-06-27 10:28:08 +03:00
Åke Engelbrektson c82e223b9e
Update harbour-sailotp-sv.ts
Update Swedish translation
2021-06-27 07:45:28 +02:00
JSEHV 06d69a5197 Update on Dutch language
Update on Dutch language, including features of 1.9.4
2021-06-26 19:46:21 +02:00
JSEHV f472d5ff93 Update harbour-sailotp-nl.ts
Update Dutch translation to the last features
2021-06-26 19:41:49 +02:00
seiichiro 075f9949c3 Merge branch 'release-1.9.4' into develop 2021-06-26 16:04:27 +02:00
seiichiro a6044de2b1 Prepare Release 1.9.4 2021-06-26 16:03:23 +02:00
seiichiro dbdf3ee3be
Merge pull request #55 from JSEHV/develop
App icon refresh
2021-06-26 15:39:53 +02:00
seiichiro a5c75d9dfd
Merge pull request #53 from caio2k/develop
Update pt_br translation and its html entities
2021-06-26 15:35:52 +02:00
JSEHV 4df0cddfeb App icon refresh
App icon refresh
2021-06-24 20:47:42 +02:00
caio2k 4e21436982 Update pt_br translation and updated html entities 2021-06-02 00:05:54 +02:00
seiichiro b0d5c23afe Merge branch 'release-1.9.3' into develop 2021-02-21 12:28:54 +01:00
seiichiro 16e3d2226e Integrate Hungarian Translation File, Prepare 1.9.3 2021-02-21 12:28:34 +01:00
seiichiro 3d7bdced0d
Merge pull request #47 from 1Zgp/develop
Hungarian translation file for your app
2021-02-21 12:02:55 +01:00
1Zgp 8cdfb544c4
Add files via upload 2021-02-16 09:30:30 +02:00
seiichiro 35a0a5ac7d Merge branch 'release-1.9.2' into develop 2021-01-18 18:08:32 +01:00
seiichiro ca331ec1bd Release preparations for 1.9.2 2021-01-18 18:08:17 +01:00
seiichiro 3ffea61fbe
Merge pull request #45 from ZeiP/search_bug_fix
Fix a minor search bug
2021-01-18 08:20:32 +01:00
Jyri-Petteri Paloposki c950a1c0af Apply the search term when returning to the main view for example after editing an entry 2021-01-14 21:52:43 +02:00
seiichiro 9e747a24f0 Merge branch 'release-1.9.1' into develop 2021-01-11 17:20:28 +01:00
seiichiro 8990e320ed Update Translation Files, Visual Fix for the Progressbar 2021-01-11 17:19:51 +01:00
seiichiro 62adfdcaa3 Fix German Translation 2021-01-11 16:41:18 +01:00
seiichiro 0cdeb4be99 Release Preparations 1.9.1, About-Page Adaptions 2021-01-11 16:35:07 +01:00
seiichiro 569a4432f3
Merge pull request #44 from ZeiP/about_fixes
Prettier styles for the about page
2021-01-11 15:46:08 +01:00
Jyri-Petteri Paloposki 5d06fcf5cd Add some paddings and update to locales 2021-01-05 16:31:53 +02:00
seiichiro d9e662b34c
Merge pull request #43 from eson57/patch-1
Update harbour-sailotp-sv.ts
2021-01-05 09:09:28 +01:00
Jyri-Petteri Paloposki 11de9daf82 Prettier styles for the about page. Changed the search field to a SearchField. 2021-01-04 23:42:36 +02:00
Åke Engelbrektson cd64cb617f
Update harbour-sailotp-sv.ts
Update Swedish translation
2021-01-04 21:33:59 +01:00
seiichiro 4e622d8987 Merge branch 'release-1.9.0' into develop 2021-01-04 20:26:18 +01:00
seiichiro 6273578f57 Version 1.9.0
Added Search Functionality (contributed by Jyri-Petteri Paloposki)
Updated Finnish Translation (contributed by Jyri-Petteri Paloposki)
2021-01-04 20:17:57 +01:00
seiichiro 178ab186ba Update Translation Files for Search, Add German Translation 2021-01-04 19:57:54 +01:00
seiichiro 535f098ae6
Merge pull request #41 from ZeiP/search
#38: Add a search box to the main view.
2021-01-04 19:43:47 +01:00
Jyri-Petteri Paloposki 4648012416 Make the search functionality case insensitive. 2021-01-03 13:50:27 +02:00
Jyri-Petteri Paloposki da4f2bbd73 #38: Add a search box to the main view. 2021-01-03 11:26:38 +02:00
seiichiro f7d206c026
Merge pull request #40 from ZeiP/develop
Update the Finnish translation
2021-01-03 09:19:51 +01:00
Jyri-Petteri Paloposki bd29a93f4a Update the Finnish translation 2021-01-03 07:52:11 +02:00
seiichiro f1d195fa1d Relaxed Base32 Check for Amazon Secrets 2019-04-07 21:12:50 +02:00
seiichiro da4ce5dd3f
Merge pull request #34 from JSEHV/origin/dutch-translation
Added dutch translation
2019-04-07 21:05:25 +02:00
JSEHV 5d6084193b Added dutch translation
Added dutch translation
2019-03-29 11:51:52 +01:00
seiichiro cc07047c74 Merge branch 'hotfix-1.8.1' into develop 2019-03-03 17:11:01 +01:00
seiichiro 7d238123a7 Version 1.8.1 preparation 2019-03-03 17:10:44 +01:00
seiichiro 47d5eb3df1
Merge pull request #32 from eson57/patch-1
Update harbour-sailotp-sv.ts
2019-02-27 20:19:16 +01:00
Åke Engelbrektson 2ba7dcadc6
Update harbour-sailotp-sv.ts
Google translations fixed and small adjustments.
Please don't use Google translate, for Swedish they mostly make no sense. Better not to translate at all.
2019-02-24 21:10:17 +01:00
seiichiro d59a0d969f Merge branch 'release-1.8' into develop 2019-02-24 16:34:52 +01:00
seiichiro 6e56507ca8 Fixup Validator Warnings, Small Bugfix 2019-02-24 16:22:15 +01:00
seiichiro b3a1a02b15 Release Notes and Version Up for 1.8.0 2019-02-24 15:35:39 +01:00
seiichiro 0c181fd6c6 Fixup Translations for 1.8 2019-02-24 15:18:55 +01:00
seiichiro bb6c7706f2 Added Options to Hide Tokens and Show Token as QR-Code 2019-02-24 14:03:07 +01:00
seiichiro 192072e12a Merge branch 'feat-design' into develop 2019-02-23 16:41:20 +01:00
seiichiro 2db3986513 Github #28 Check Input for Valid Base32 2019-02-23 16:39:15 +01:00
seiichiro 714f1f1917 Github #29 Fix Progressbar Position for Light Ambiances, First Attempt 2019-02-23 16:00:41 +01:00
seiichiro 2f91faf876 GitHub #30 Fix About Page Text for Light Ambiances 2019-02-23 13:35:36 +01:00
seiichiro b20fbf3c53
Merge pull request #27 from caio2k/develop
add pt_BR translation
2018-07-10 15:39:28 +02:00
caio2k a43a08e881 add pt_BR translation 2018-06-27 01:06:27 +02:00
seiichiro 1646332bbe Small Visual Fix for SFOS 2.2.0.29 2018-06-17 09:12:54 +02:00
seiichiro b6a9036d3c Merge branch 'hotfix-1.7.1' into develop 2018-04-09 19:16:36 +02:00
seiichiro f916c7eaef Adapt YAML for Correct File Permission to Pass Harbour Validation 2018-04-09 19:16:13 +02:00
seiichiro cf1dacc762 Version 1.7.1 Preparations 2018-04-09 18:53:30 +02:00
seiichiro 2ab78c257b Added Italian Translation 2018-04-09 18:42:30 +02:00
seiichiro b827e40735 Simplified Packaging and adapted to latest SailfishOS Standards 2018-04-09 18:38:56 +02:00
seiichiro 10dee5e24e
Merge pull request #25 from Tichy/patch-1
Italian translation
2018-04-09 18:37:53 +02:00
Tichy 70017a4b55
Italian translation 2018-04-07 13:17:26 +02:00
seiichiro d893792593 Merge branch 'release-1.7' into develop 2018-04-02 09:27:16 +02:00
seiichiro 2e0881aaf5 Changelog for 1.7 2018-04-02 09:26:53 +02:00
seiichiro e6ca5450ad Release Preparations for 1.7 2018-04-02 09:12:49 +02:00
seiichiro 2ccf4e1a78
Merge pull request #24 from p4moedo/develop
Added Spanish (es) translation.
2018-02-05 09:38:39 +01:00
p4moedo 3c36912e76
Added Spanish (es) translation 2018-01-31 23:29:12 +01:00
p4moedo fbac974b81
Update es.ts 2018-01-31 23:27:00 +01:00
p4moedo ca9bb6ea31
Create es.ts
Spanish translation
2018-01-31 23:26:05 +01:00
seiichiro f65e4eb836
Merge pull request #23 from 0312birdzhang/develop
Add Chinese simple translation
2018-01-06 09:07:22 +01:00
BirdZhang d9f0ff2416 add ts file 2017-12-27 16:53:44 +08:00
BirdZhang 9f57c6f065 Add zh_CN translation 2017-12-27 16:51:12 +08:00
seiichiro 0bc2d44b4c Merge branch 'feat-settings' into develop 2017-12-25 13:31:02 +01:00
seiichiro 6f2159745d Added Global Settings Storage and First Example Setting 2017-12-25 13:30:43 +01:00
seiichiro a833d36280 Merge branch 'feat-cleanup' into develop 2017-12-25 12:39:42 +01:00
seiichiro 0e990b9e2d Added OpenSSL Decryption Commandline to Export Page 2017-12-25 12:39:12 +01:00
seiichiro ff3f1d3084 About Page Layout Fixes 2017-12-25 12:10:19 +01:00
seiichiro 00b1c594c9 Fix About Page, Add Manual and Github Links 2017-12-25 12:07:42 +01:00
seiichiro f7e4f2c053 Fixup URLs and openssl command in README 2017-11-08 08:30:13 +01:00
seiichiro e6ea72d4f7 Merge branch 'feat-translations' into develop 2017-11-08 08:15:48 +01:00
seiichiro 253771cd96 Merged Finnish and Russian Translations, Added New Translators to List of Contributers 2017-11-08 08:10:50 +01:00
seiichiro c70f235233
Merge pull request #20 from hevanaa/finnish-translation
Added Finnish translation
2017-11-08 07:42:47 +01:00
seiichiro ee1e1efe73
Merge pull request #21 from moorchegue/develop
Russian translations.
2017-11-08 07:41:50 +01:00
Johan Heikkilä cfbc9b70a8
Update fi.ts 2017-11-07 16:40:54 +02:00
murchik 7c42c0390c Russian translations. 2017-11-07 17:45:56 +08:00
Johan Heikkilä ad5a7c8020 Added Finnish translation 2017-11-06 23:54:58 +02:00
seiichiro c6d197a741 Bugfix for Github Issues #14 / #16, Version 1.6 2017-10-30 12:22:18 +01:00
seiichiro 0327463a62 Change to New Sourcecode Address 2016-11-27 17:48:05 +01:00
seiichiro 4d62ea0687 Release Preparations for Version 1.5 2016-10-09 09:55:28 +02:00
seiichiro ed55e58397 Bugfix: Refresh HOTP-Token from Cover. Closes Github Issue #11 2016-10-09 09:43:41 +02:00
seiichiro dc6d6f9988 Merge pull request #10 from smortex/i18n-fr
Add french translation
2016-08-23 08:29:05 +02:00
Romain Tartière a1430c9fcf Add french translation 2016-08-20 23:48:21 +02:00
seiichiro 38671a65f7 Merge branch 'feat-diff_and_length' into develop 2016-07-17 19:33:38 +02:00
seiichiro 8338ca6d73 Include Length in Generated QR-Code 2016-07-17 19:33:12 +02:00
seiichiro 7caade42be Translation, UI-Fixes, Get Digits from OTP-URL 2016-07-17 19:06:09 +02:00
seiichiro 4e83005525 Added Token Length and Time Derivation Options 2016-07-14 13:41:00 +02:00
seiichiro 8291ef6fc9 Merge branch 'release-1.3' into develop 2015-12-06 19:35:26 +01:00
seiichiro 65e8346ec4 Updated Readme 2015-12-06 19:35:06 +01:00
seiichiro 8917c45e83 Updated Version, Translations and About-Page 2015-12-06 19:09:19 +01:00
seiichiro 4817aea2f7 Added SteamGuard as new OTP Type 2015-12-06 18:47:13 +01:00
seiichiro 3561d57d63 Merge branch 'icewind1991-steam-auth' into develop 2015-12-06 18:44:34 +01:00
Robin Appelman b6f105d355 Also handle steam authenticator tokens on the cover 2015-12-04 16:27:28 +01:00
Robin Appelman 53e0f1f32b Add suport for generating steam authenticator tokens 2015-12-04 15:52:19 +01:00
seiichiro 168463cacb Allow all pages to rotate 2015-09-26 10:51:17 +02:00
seiichiro b9b665afa2 Preparation for Release of Version 1.2 2015-06-17 21:15:57 +02:00
seiichiro 323893d7ee Added translation contributors to README 2015-05-23 15:13:26 +02:00
seiichiro 43e31ba8b3 Merge pull request #5 from eson57/patch-1
Added Swedish translation contributed by Åke Engelbrektson
2015-05-23 15:05:23 +02:00
Åke Engelbrektson 1d9df556a9 Create sv.ts
Swedish translation if wanted.
2015-05-23 09:28:29 +02:00
seiichiro a448deda07 Added URL-Decoding for OTP Titles 2015-05-22 18:58:46 +02:00
seiichiro b039fa737a Fixed a small bug found by harbour-QA 2014-07-13 12:03:02 +02:00
seiichiro 91dfc732a3 Version 1.0
* QR-Code Reader is now harbour-compatible
2014-07-01 16:30:33 +02:00
seiichiro d722da8688 Added a harbour-compatible QR-Code Reader 2014-07-01 16:09:14 +02:00
seiichiro e5ff3b4a35 Fix for wrong DB-Version on initializing DB 2014-06-20 01:23:22 +02:00
seiichiro 83fc6ec7d1 Small fix for Main Page 2014-05-25 11:03:19 +02:00
seiichiro 263c02a947 Version Bump to 0.8 2014-05-24 19:31:45 +02:00
seiichiro 8de63f5f68 Cleanup and minor Fixes 2014-05-24 19:14:51 +02:00
seiichiro 14f725f364 Added QR-Code export
Added Translation for QR-Code Export and Token reordering
2014-05-24 18:35:41 +02:00
seiichiro 7b48f929c5 Added possibility to Reorder the List of Tokens. 2014-05-24 15:42:52 +02:00
seiichiro 95f00e8dd0 Some minor changes
Switched to FileIO as subproject
Minor cosmetic changes for the CoverPage
2014-02-23 16:46:38 +01:00
seiichiro ffb712f685 Version 0.7 (openrepos only)
Added QR-Code Reader
2014-02-22 11:32:19 +01:00
seiichiro f31998f6e2 Added translations for QR-Reader 2014-02-19 06:45:25 +01:00
seiichiro 965c7a382e Finished up QR-Code Reader Integration 2014-02-16 21:41:36 +01:00
seiichiro e74749642f Added first version of experimental QR-Code support 2014-02-16 16:27:28 +01:00
seiichiro 1a2390c6e7 Added QXZing Library 2014-02-16 14:18:45 +01:00
seiichiro dc02a1aa3f Preparations for version 0.6 release
Added possibility to cycle through the tokens from the cover
2014-02-09 10:50:58 +01:00
seiichiro 82ea4f182c Added Enter-Key Customization to Add and Export/Import Pages 2014-02-08 18:05:23 +01:00
seiichiro 99308f8ecf Adapted Translations
Minor tweaks to the About-Page
2014-02-08 17:22:44 +01:00
seiichiro 5029f99db3 Added Localization support
Added German Translation
2014-02-08 17:08:10 +01:00
seiichiro 2553a699d3 Preparations for version 0.5 release 2014-02-02 15:36:59 +01:00
seiichiro e68cf226a4 Error handling for export / import
Added error-handling for export / import
Added sanity-checks to export / import
2014-02-02 14:14:59 +01:00
seiichiro 9fe40ff767 Added NotifyBanner component for showing notifications
Show notification after copying token to clipboard
2014-02-02 11:26:22 +01:00
seiichiro 0ea71dfb89 Added AES-encryption for export/import 2014-02-01 17:06:34 +01:00
seiichiro 743b06f065 Added basic import and export
The DB can be exported to json file
Added handling of duplicate entries
2014-02-01 15:38:09 +01:00
seiichiro 09edf6c8b8 Fix for GitLab Issue #3
Initial DB-Creation and DB-Update now both set the default values.
2014-02-01 13:07:29 +01:00
seiichiro 99c3f83db7 Added Import / Export Dialog Page 2014-02-01 12:59:39 +01:00
seiichiro 42f686846d Added FileIO Class as preparation for DB Export/Import 2014-02-01 12:24:05 +01:00
seiichiro aa945ff787 Application version is now read from YAML-Definition at buildtime
Upstream URL changed to gitlab
2014-02-01 12:23:59 +01:00
seiichiro 656dee7143 Merge branch 'hotfix-0.4-2' into develop 2014-01-13 00:03:40 +01:00
seiichiro 539acb21df Fixed padding for base32tohex return value 2014-01-13 00:02:01 +01:00
seiichiro ebbc3ddcf5 Merge branch 'release-0.4' into develop 2014-01-12 18:19:09 +01:00
seiichiro 9f1dc6d232 Changed Version to 0.4 and adapted the readme 2014-01-12 18:18:25 +01:00
seiichiro 33e13af394 Merge branch 'feat-hotp' into develop 2014-01-12 18:04:56 +01:00
seiichiro f86a8c74a3 Added HOTP support 2014-01-12 18:03:23 +01:00
seiichiro 5ddc4dcf90 Added type and counter value to the Add/Edit-Page 2014-01-12 16:25:02 +01:00
seiichiro 7dfd336c77 Merge branch 'release-0.3' into develop 2014-01-10 19:47:24 +01:00
seiichiro 5cbc98f1a3 Changed version to 0.3 and adapted Readme 2014-01-10 19:43:49 +01:00
seiichiro 2c4ab39b54 Merge branch 'feat-cover' into develop 2014-01-10 19:30:53 +01:00
seiichiro a586ea01a7 Added copy token on tap 2014-01-10 19:26:46 +01:00
seiichiro 7f781b8d90 Finalized favourites feature
* Favourite is now shown on the ActiveCover
* Added possibility to "unstar" a favourite
2014-01-10 19:20:52 +01:00
seiichiro eb08a4eee1 Changed favourite switch to icon 2014-01-10 06:45:03 +01:00
seiichiro 40f53fc47a Changed MainView to support favourites
* Added switch to show status
* Save selected favourite to LocalStorage DB
2014-01-09 22:12:55 +01:00
seiichiro 11072b2f16 Changed DB Schema
* DB Schema now supports setting favourites
* Added Colums for future addition of HOTP Tokens
* Created DB-Update Logic
2014-01-09 19:56:26 +01:00
seiichiro 26bafc2f18 Merge branch 'release-0.2' into develop 2014-01-08 19:24:29 +01:00
seiichiro 2522e4d4a2 Changed version to 0.2 2014-01-08 19:23:29 +01:00
seiichiro 67820a1e55 Merge branch 'feat-edit' into develop 2014-01-08 19:19:14 +01:00
seiichiro ef1b5ad51d Catch error from invalid secrets 2014-01-08 19:16:56 +01:00
seiichiro 50770f0799 Added possibility to edit existing entries. 2014-01-08 19:13:53 +01:00
seiichiro 12cf6106a5 Merge branch 'feat-cleanup' into develop 2014-01-06 20:10:16 +01:00
seiichiro f98444d5a4 Cleanup and Comments for publishing
* Added Readme and License
* Cleaned up the code
* Added comments to the code
2014-01-06 20:08:16 +01:00
256 changed files with 34183 additions and 900 deletions

10
.gitignore vendored
View file

@ -1,3 +1,13 @@
# User Specific Project Files
*.pro.user
*.pro.user.*
*.autosave
*.o
moc_*
documentation.list
harbour-sailotp
RPMS
Makefile
rpm/harbour-sailotp.spec
rpm/harbour-sailotp.spec.*
translations/*.qm

View file

@ -1,49 +1,80 @@
# SailOTP
SailOTP is a Sailfish Implementation of the Google-Authenticator algorithms,
also known as TOPT (timer based) and HOTP (counter based) as described in RFC 6238 and 4226. A growing
number of sites uses this algorithm for two-factor-authentication, including
Github, Linode and several Google services.
SailOTP is a Sailfish Implementation of the Google-Authenticator algorithms, also known as TOPT (timer based) and HOTP (counter based) as described in RFC 6238 and 4226. A growing number of sites uses this algorithm for two-factor-authentication, including Github, Linode and several Google services.
One can add new OTP-entries using the pulley-menu. The type of token can be selected. Title and the shared
secret have to be provided. For counter based HOTP-tokens the counter value for the next update of the
Token can be set. The default of 1 is the standard value for new HOTP-tokens and should not be changed.
One can add new OTP-entries using the pulley-menu. Codes can be added using the integrated QR-Code-Reader or by manually typing in the token information.
The main view of the app will show a list off all entries and their current One-Time-Tokens.
The entries will be regenerated every 30 seconds, the remaining time for the current tokens is shown
through a progress bar at the top of the app. HOTP-type tokens are not updated automatically, instead
a refresh button is shown on the right of the token to calculate the next value and increment the counter
An entry can be edited or deleted by long-pressing on it.
The main view of the app will show a list off all entries and their current One-Time-Tokens. The entries will be regenerated every 30 seconds, the remaining time for the current tokens is shown through a progress bar at the top of the app. HOTP-type tokens are not updated automatically, instead a refresh button is shown on the right of the token to calculate the next value and increment the counter. An entry can be edited, deleted or moved up and down in the list by long-pressing on it.
One entry can be stared by tapping the star icon on the left. the stared item will be shown
on the ActiveCover. If the Token is timer based, it will be refreshed every 30 seconds. 5 seconds before the token changes it's
color will change to red. For counter based tokens a cover action to calculate the next token is shown instead.
The item can be unstared by tapping the star icon again on the main view.
In edit-mode one can show a QR-Code of the entry (e.g. for importing it on another device) through the pulley menu.
One entry can be stared by tapping the star icon on the left. the stared item will be shown on the ActiveCover. If the Token is timer based, it will be refreshed every 30 seconds. 5 seconds before the token changes it's color will change to red. For counter based tokens a cover action to calculate the next token is shown instead. The item can be unstared by tapping the star icon again on the main view.
From the main view a token can be copied to the clipboard by tapping on it.
## Known Limitations
From the pulley menu the token database can be exported to a file for backup purposes. The backup is a AES-256-CBC encrypted and
Base64 encoded file containing a JSON-representation of the database. It can be decrypted with openssl using the following command:
At the moment the only way to insert new entries into the app is to insert the
title and secret key by hand. It's not possible to use the QR-Codes some sites
provide directly.
openssl enc -d -a -aes-256-cbc -in <file>
if you need the information outside of SailOTP.
Importing the file is also possible from the pulley menu. If a file contains tokens that are already in the database (title and secret of the token match an existing one), these tokens will not be added again.
It is also possible to generate tokens for SteamGuard (Steams TOTP-Variant for 2-Factor-Auth). To use this feature, one will have to activate it using the original Steam Android app. After activating it one can get the secret code from '/opt/alien/data/data/com.valvesoftware.android.steam.community/files/Steamguard-$STEAMID'. This file contains json data, including the OTP-URL in the form 'otpauth://totp/Steam:$STEAM_USERNAME?secret=$SECRET&issuer=Steam'. The code from this URL can be added manually using the 'Steam Guard'-OTP-Type in SailOTP.
## Contact and Issues
If you find any bugs or want to suggest a feature, feel free to use Githubs
Issues feature.
If you find any bugs or want to suggest a feature, feel free to use Githubs Issues feature at
<a href="https://github.com/seiichiro0185/sailotp/issues" target="_blank">https://github.com/seiichiro0185/sailotp/issues</a>
or write an email to sailfish _AT_ seiichiro0185.org
## License
SailOTP is licensed under a 3-Clause BSD-License. See COPYING for details.
## Accnowledgements
## Contributors
The Following people have contributed code or other improvements to SailOTP:
* SteamGuard support: Robin Appelman
* Search function: Jyri-Petteri Paloposki
* Improved App Icon: JSEHV
* Custom Time Period support: Andrey Skvortsov
* SailJail Permissions: DrYak
## Translations
The following people have contributed to translating SailOTP:
* Brazilian Portuguese: caio2k
* Chinese: BirdZhang
* Finnish: Johan Heikkilä (hevanaa), Jyri-Petteri Paloposki (ZeiP)
* French: Romain Tartière (smortex)
* Italian: Tichy
* Hungarian: 1Zgp
* Russian: moorchegue
* Spanish: p4moedo
* Swedish: Åke Engelbrektson (eson57)
* English: Stefan Brand (seiichiro0185)
* German: Stefan Brand (seiichiro0185)
## Acknowledgements
SailOTP uses the SHA-1 and HMAC-Implementation from
<a href="https://github.com/Caligatio/jsSHA" target="_blank">https://github.com/Caligatio/jsSHA</a>
SailOTP also uses the AES-Implementation from
<a href="https://code.google.com/archive/p/crypto-js/" target="_blank">https://code.google.com/archive/p/crypto-js/</a>
The implementation of the TOTP-algorithm was inspired by:
<a href="http://blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript/" target="_blank">http://blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript/</a>
An adapted version of the QZXing-library is used for QRCode-decoding
<a href="http://sourceforge.net/projects/qzxing/">http://sourceforge.net/projects/qzxing/</a>
The qrencode library is used for QRCode-encoding existing tokens for export to other devices.
<a href="http://fukuchi.org/works/qrencode/">http://fukuchi.org/works/qrencode/</a>

View file

@ -5,3 +5,7 @@ Name=SailOTP
Icon=harbour-sailotp
Exec=harbour-sailotp
[X-Sailjail]
Permissions=UserDirs;RemovableMedia;Camera
OrganizationName=org.seiichiro0185
ApplicationName=harbour-sailotp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

View file

@ -1,27 +1,52 @@
# The name of your app.
# NOTICE: name defined in TARGET has a corresponding QML filename.
# If name defined in TARGET is changed, following needs to be
# done to match new name:
# - corresponding QML filename must be changed
# - desktop icon filename must be changed
# - desktop filename must be changed
# - icon definition filename in desktop file must be changed
TARGET = harbour-sailotp
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
DEFINES += APP_BUILDNUM=\\\"$$RELEASE\\\"
CONFIG += sailfishapp
PKGCONFIG += libcrypto
SOURCES += src/harbour-sailotp.cpp
OTHER_FILES += qml/harbour-sailotp.qml \
DISTFILES += qml/harbour-sailotp.qml \
icons/86x86/sailotp.png \
qml/cover/CoverPage.qml \
rpm/harbour-sailotp.spec \
rpm/harbour-sailotp.yaml \
harbour-sailotp.desktop \
qml/pages/MainView.qml \
qml/pages/AddOTP.qml \
qml/pages/About.qml \
qml/pages/ExportPage.qml \
qml/pages/ScanOTP.qml \
qml/pages/QRPage.qml \
qml/pages/Settings.qml \
qml/components/NotifyBanner.qml \
qml/lib/urldecoder.js \
qml/lib/storage.js \
qml/lib/crypto.js \
qml/lib/sha.js \
qml/sailotp.png
qml/sailotp.png \
rpm/harbour-sailotp.spec \
rpm/harbour-sailotp.yaml \
rpm/harbour-sailotp.changes \
translations/*.ts \
harbour-sailotp.desktop
SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172
CONFIG += sailfishapp_i18n
TRANSLATIONS = translations/harbour-sailotp-de.ts \
translations/harbour-sailotp-es.ts \
translations/harbour-sailotp-fi.ts \
translations/harbour-sailotp-fr.ts \
translations/harbour-sailotp-it.ts \
translations/harbour-sailotp-pt_BR.ts \
translations/harbour-sailotp-ru.ts \
translations/harbour-sailotp-sv.ts \
translations/harbour-sailotp-nl.ts \
translations/harbour-sailotp-hu.ts \
translations/harbour-sailotp-zh_CN.ts
include(src/qzxing/QZXing.pri)
include(src/FileIO/FileIO.pri)
include(src/QCipher/QCipher.pri)
include(src/qqrencode/qqrencode.pri)

View file

@ -1,529 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 2.8.1, 2014-01-05T21:44:53. -->
<qtcreator>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QString" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QString" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">MerSDK-SailfishOS-armv7hl</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">MerSDK-SailfishOS-armv7hl</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{45efb901-3e2e-4d50-95ba-c432b8781a69}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/home/seiichiro/Projekte/Sailfish/build-harbour-sailotp-MerSDK_SailfishOS_armv7hl-Debug</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/home/seiichiro/Projekte/Sailfish/build-harbour-sailotp-MerSDK_SailfishOS_armv7hl-Release</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">2</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Rpm</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRpmBuildStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy By Building An RPM Package</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerArmDeployConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Rsync</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRsyncDeployStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy By Copying Binaries</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRSyncDeployConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.2">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Rpm</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRpmDeployStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy As RPM Package</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRpmDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Project.UseGlobal">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">1</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">harbour-sailotp (auf Mobilgerät)</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRunConfiguration:/home/seiichiro/Projekte/Sailfish/harbour-sailotp/harbour-sailotp.pro</value>
<value type="QString" key="Qt4ProjectManager.MaemoRunConfiguration.Arguments"></value>
<value type="QString" key="Qt4ProjectManager.MaemoRunConfiguration.ProFile">harbour-sailotp.pro</value>
<value type="QString" key="RemoteLinux.RunConfig.AlternateRemoteExecutable"></value>
<value type="bool" key="RemoteLinux.RunConfig.UseAlternateRemoteExecutable">false</value>
<value type="QString" key="RemoteLinux.RunConfig.WorkingDirectory"></value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.1</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">MerSDK-SailfishOS-i486-x86</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">MerSDK-SailfishOS-i486-x86</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{08e6ddb6-6d52-4f4e-938d-998fac04baad}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/home/seiichiro/Projekte/Sailfish/build-harbour-sailotp-MerSDK_SailfishOS_i486_x86-Debug</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/home/seiichiro/Projekte/Sailfish/build-harbour-sailotp-MerSDK_SailfishOS_i486_x86-Release</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">2</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Start Emulator</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerEmulatorStartStep</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Rsync</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRsyncDeployStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy By Copying Binaries</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRSyncDeployConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Start Emulator</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerEmulatorStartStep</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Rpm</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRpmDeployStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy As RPM Package</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRpmDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">2</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Project.UseGlobal">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">1</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">harbour-sailotp (auf Mobilgerät)</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MerRunConfiguration:/home/seiichiro/Projekte/Sailfish/harbour-sailotp/harbour-sailotp.pro</value>
<value type="QString" key="Qt4ProjectManager.MaemoRunConfiguration.Arguments"></value>
<value type="QString" key="Qt4ProjectManager.MaemoRunConfiguration.ProFile">harbour-sailotp.pro</value>
<value type="QString" key="RemoteLinux.RunConfig.AlternateRemoteExecutable"></value>
<value type="bool" key="RemoteLinux.RunConfig.UseAlternateRemoteExecutable">false</value>
<value type="QString" key="RemoteLinux.RunConfig.WorkingDirectory"></value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">2</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
<value type="QByteArray">{ea1259ba-c840-46cd-876a-b91d58edff1f}</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">14</value>
</data>
</qtcreator>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

16
icons/harbour-sailotp.svg Normal file
View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="Layer_1">
<path d="M84.277,85.674C85.063,85.674 85.7,85.037 85.7,84.251L85.7,42.987C85.7,19.411 66.583,0.3 43,0.3C19.418,0.3 0.3,19.411 0.3,42.987C0.3,66.563 19.418,85.675 43,85.675C43.636,85.675 84.277,85.674 84.277,85.674Z" style="fill:url(#_Linear1);fill-rule:nonzero;"/>
<g transform="matrix(0.211288,0,0,0.211288,13.6147,13.7701)">
<path d="M287.305,243.005C287.169,241.233 286.377,239.529 285.078,238.258L172.835,126.015C177.251,115.612 179.582,104.346 179.582,92.703C179.582,69.949 170.707,48.54 154.644,32.437C138.558,16.366 117.164,7.5 94.397,7.5C71.619,7.5 50.262,16.369 34.15,32.45C0.907,65.675 0.9,119.716 34.145,152.938C50.256,169.053 71.62,177.928 94.386,177.928C106.032,177.928 117.27,175.578 127.698,171.156L164.572,208.058C166.106,209.573 168.129,210.377 170.312,210.306L190.407,209.601L189.751,229.746C189.689,231.871 190.456,233.939 191.996,235.452C193.48,236.964 195.565,237.786 197.681,237.7L217.85,237.011L217.126,257.134C217.063,259.261 217.88,261.333 219.364,262.846C220.898,264.358 222.685,265.171 225.104,265.097L245.223,264.413L244.549,284.539C244.431,286.771 245.371,288.918 246.967,290.442C248.439,291.781 250.276,292.502 252.212,292.502C252.49,292.502 252.775,292.49 253.059,292.465L283.91,289.039C288.079,288.584 291.115,284.864 290.757,280.686L287.305,243.005ZM84.106,82.415C74.63,91.881 59.31,91.881 49.854,82.415C40.384,72.946 40.384,57.629 49.854,48.169C59.31,38.709 74.625,38.7 84.106,48.166C93.563,57.625 93.557,72.952 84.106,82.415ZM260.97,245.575C259.844,246.701 258.335,247.263 256.869,247.263C255.403,247.263 253.893,246.7 252.768,245.575L157.267,150.046C159.926,147.179 162.344,144.161 164.54,140.988L260.969,237.398C263.221,239.65 263.221,243.324 260.97,245.575Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1.72062,0,0,1.72062,-21.2913,-21.4266)">
<circle cx="31.868" cy="31.826" r="7.722" style="fill:rgb(228,86,70);fill-opacity:0.22;"/>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,42.6872,-42.7001,0,43,42.9873)"><stop offset="0" style="stop-color:rgb(228,86,70);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(139,49,55);stop-opacity:1"/></linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
MouseArea {
id: notifyBanner
width: Screen.width
height: notifyText.height + 2*Theme.paddingMedium
visible: showBanner
property bool showBanner: false
function show(text, time) {
notifyText.text = text;
timeout.interval = time;
showBanner = true;
timeout.start();
}
Timer {
id: timeout
interval: 3000
onTriggered: {
interval = 3000
showBanner = false
}
}
Rectangle {
id: banner
anchors.fill: parent
color: Theme.secondaryHighlightColor
Text {
id: notifyText
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Theme.paddingLarge
font.pixelSize: Theme.fontSizeSmall
color: Theme.primaryColor
wrapMode: Text.Wrap
elide: Text.ElideRight
maximumLineCount: 3
}
}
onClicked: {
showBanner = false
timeout.stop()
timeout.interval = 3000
}
}

View file

@ -38,28 +38,32 @@ CoverBackground {
property double lastUpdated: 0
function updateOTP() {
// get seconds from current Date
var curDate = new Date();
var seconds = (curDate.getSeconds() + appWin.coverDiff) % 30
if (lOTP.text == "------" || seconds == 0 || (curDate.getTime() - lastUpdated > 2000)) {
appWin.coverOTP = OTP.calcOTP(appWin.coverSecret, appWin.coverType, appWin.coverLen, appWin.coverDiff, 0, appWin.coverPeriod);
}
// Change color of the OTP to red if less than 5 seconds left
if (29 - seconds < 5) {
lOTP.color = "red"
} else {
lOTP.color = Theme.highlightColor
}
lastUpdated = curDate.getTime();
}
Timer {
interval: 1000
// Timer runs only when cover is visible and favourite is set
running: !Qt.application.active && appWin.coverSecret != "" && appWin.coverType == "TOTP"
running: !Qt.application.active && appWin.coverSecret != "" && (appWin.coverType == "TOTP" || appWin.coverType == "TOTP_STEAM")
repeat: true
onTriggered: {
// get seconds from current Date
var curDate = new Date();
if (lOTP.text == "------" || curDate.getSeconds() == 30 || curDate.getSeconds() == 0 || (curDate.getTime() - lastUpdated > 2000)) {
appWin.coverOTP = OTP.calcOTP(appWin.coverSecret, "TOTP", 0);
}
// Change color of the OTP to red if less than 5 seconds left
if (29 - (curDate.getSeconds() % 30) < 5) {
lOTP.color = "red"
} else {
lOTP.color = Theme.highlightColor
}
lastUpdated = curDate.getTime();
}
onTriggered: updateOTP();
}
// Show the SailOTP Logo
@ -73,13 +77,17 @@ CoverBackground {
Column {
anchors.top: logo.bottom
width: parent.width
anchors.topMargin: 48
anchors.horizontalCenter: parent.horizontalCenter
Label {
text: appWin.coverTitle
anchors.horizontalCenter: parent.horizontalCenter
color: Theme.secondaryColor
width: parent.width - Theme.paddingMedium*2
maximumLineCount: 1
truncationMode: TruncationMode.Fade
horizontalAlignment: contentWidth <= width ? Text.AlignHCenter : Text.AlignLeft
}
Label {
id: lOTP
@ -91,11 +99,30 @@ CoverBackground {
}
// CoverAction to update a HOTP-Token, only visible for HOTP-Type Tokens
CoverActionList {
enabled: appWin.coverType == "HOTP" ? true : false
CoverAction {
iconSource: "image://theme/icon-m-refresh"
iconSource: appWin.coverType == "HOTP" ? "image://theme/icon-cover-refresh" : "image://theme/icon-cover-previous"
onTriggered: {
appWin.coverOTP = OTP.calcOTP(appWin.coverSecret, "HOTP", DB.getCounter(appWin.coverTitle, appWin.coverSecret, true));
if (appWin.coverType == "HOTP") {
appWin.listModel.setProperty(appWin.coverIndex, "counter", DB.getCounter(appWin.coverTitle, appWin.coverSecret, true));
appWin.listModel.setProperty(appWin.coverIndex, "otp", OTP.calcOTP(appWin.coverSecret, "HOTP", appWin.coverLen, 0, appWin.listModel.get(appWin.coverIndex).counter));
appWin.coverOTP = appWin.listModel.get(appWin.coverIndex).otp;
} else {
var index = appWin.coverIndex - 1
if (index < 0) index = appWin.listModel.count - 1
appWin.setCover(index);
DB.setFav(appWin.coverTitle, appWin.coverSecret)
if (appWin.coverType == "TOTP" || appWin.coverType == "TOTP_STEAM") updateOTP();
}
}
}
CoverAction {
iconSource: "image://theme/icon-cover-next"
onTriggered: {
var index = appWin.coverIndex + 1
if (index >= appWin.listModel.count) index = 0
appWin.setCover(index);
DB.setFav(appWin.coverTitle, appWin.coverSecret)
if (appWin.coverType == "TOTP" || appWin.coverType == "TOTP_STEAM") updateOTP();
}
}
}

View file

@ -29,20 +29,75 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import Nemo.Configuration 1.0
import "pages"
import "components"
ApplicationWindow
{
id: appWin
// Properties to pass values between MainPage and Cover
property alias listModel: otpListModel
property string coverTitle: "SailOTP"
property string coverSecret: ""
property string coverType: ""
property string coverOTP: "------"
property int coverLen: 6
property int coverDiff: 0
property int coverPeriod: 30
property int coverIndex: 0
// Global Listmodel for Tokens
ListModel { id: otpListModel }
// Global Component for showing notification banners
NotifyBanner { id: notify }
// Global Settings Storage
ConfigurationGroup
{
id: settings
path: "/apps/harbour-sailotp"
property bool showQrDefaultAction: false
property bool hideTokens: false
}
// Add an entry to the list
function appendOTP(title, secret, type, counter, fav, len, diff, period) {
listModel.append({"secret": secret, "title": title, "fav": fav, "type": type, "counter": counter, "len": len, "diff": diff, "period": period, "otp": "------", "itemVisible": true});
}
// Set the OTP shown on the Cover
function setCover(index) {
if (index >= 0 && index < listModel.count) {
coverTitle = listModel.get(index).title;
coverSecret = listModel.get(index).secret;
coverType = listModel.get(index).type;
coverLen = listModel.get(index).len;
coverDiff = listModel.get(index).diff;
coverPeriod = listModel.get(index).period;
coverIndex = index;
if (coverType == "TOTP") { coverOTP = "------"; } else { coverOTP = listModel.get(index).otp; }
for (var i=0; i<listModel.count; i++) {
if (i != index) {
listModel.setProperty(i, "fav", 0);
} else {
listModel.setProperty(i, "fav", 1);
}
}
} else {
coverTitle = "SailOTP";
coverSecret = "";
coverType = "";
coverIndex = -1;
}
}
initialPage: Component { MainView { } }
cover: Qt.resolvedUrl("cover/CoverPage.qml")
}

View file

@ -52,7 +52,7 @@ function base32tohex(base32) {
var chunk = bits.substr(i, 4);
hex = hex + parseInt(chunk, 2).toString(16) ;
}
return hex;
return hex.length % 2 ? hex + "0" : hex;
}
// Pad Strings to given length
@ -63,6 +63,11 @@ function leftpad(str, len, pad) {
return str;
}
// characters steam uses to generate the final code
var steamChars = ['2', '3', '4', '5', '6', '7', '8', '9', 'B', 'C',
'D', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q',
'R', 'T', 'V', 'W', 'X', 'Y']
// *** Main Function *** //
// Calculate an OTP-Value from the given secret
@ -70,16 +75,18 @@ function leftpad(str, len, pad) {
// secret: The secret key in Base32-Notation
// tpye: either TOTP for timer based or HOTP for counter based calculation
// counter: counter value for HOTP
function calcOTP(secret, type, counter) {
// length: length of the returned token
// diff: derivation of time between phone and server
function calcOTP(secret, type, len, diff, counter, period) {
// Convert the key to HEX
var key = base32tohex(secret);
var factor = "";
if (type == "TOTP") {
// Get current Time in UNIX Timestamp format (Seconds since 01.01.1970 00:00 UTC)
var epoch = Math.round(new Date().getTime() / 1000.0);
// Get last full 30 / 60 Seconds and convert to HEX
factor = leftpad(dec2hex(Math.floor(epoch / 30)), 16, '0');
if (type.substr(0, 4) == "TOTP") {
// Get current Time in UNIX Timestamp format (Seconds since 01.01.1970 00:00 UTC), and add derivation value
var epoch = Math.round(new Date().getTime() / 1000.0) + diff;
// Get last full period Seconds and convert to HEX
factor = leftpad(dec2hex(Math.floor(epoch / period)), 16, '0');
} else {
factor = leftpad(dec2hex(counter), 16, '0');
}
@ -92,8 +99,23 @@ function calcOTP(secret, type, counter) {
// Finally convert the HMAC-Value to the corresponding 6-digit token
var offset = hex2dec(hmac.substring(hmac.length - 1));
var otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec('7fffffff')) + '';
otp = (otp).substr(otp.length - 6, 6);
var code = hex2dec(hmac.substr(offset * 2, 8)) & hex2dec('7fffffff');
var otp = '';
// Steam has it's own way of creating the code from the result
if (type == "TOTP_STEAM") {
for (var i = 0; i < 5; i++) {
otp += steamChars[code % steamChars.length];
code = Math.floor(code/steamChars.length);
}
} else {
otp = code + '';
otp = (otp).substr(otp.length - len, len);
// pad return code with 0 from the left
for (i=0; i++; otp.length < len) {
otp = "0" + otp;
}
}
} catch (e) {
otp = "Invalid Secret!"
}

View file

@ -5,25 +5,25 @@
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote products
*
* 3. The names of the contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@ -36,20 +36,45 @@ function getDB() {
if (db.version == "") {
// Initialize an empty DB, Create the Table
db.changeVersion("", "2",
db.changeVersion("", "5",
function(tx) {
tx.executeSql("CREATE TABLE IF NOT EXISTS OTPStorage(title TEXT, secret TEXT, type TEXT, counter INTEGER, fav INTEGER);");
}
);
tx.executeSql("CREATE TABLE IF NOT EXISTS OTPStorage(title TEXT, secret TEXT, type TEXT DEFAULT 'TOPT', counter INTEGER DEFAULT 0, fav INTEGER DEFAULT 0, sort INTEGER DEFAULT 0, len INTEGER default 6, diff INTEGER default 0, period INTEGER default 30);");
});
} else if (db.version == "1.0") {
// Upgrade DB Schema to Version 2
db.changeVersion("1.0", "2",
// Upgrade DB Schema to Version 4
db.changeVersion("1.0", "5",
function(tx) {
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN type TEXT DEFAULT 'TOTP';");
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN counter INTEGER DEFAULT 0;");
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN fav INTEGER DEFAULT 0;");
}
);
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN sort INTEGER DEFAULT 0;");
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN len INTEGER DEFAULT 6;");
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN diff INTEGER DEFAULT 0;");
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN period INTEGER DEFAULT 30;");
});
} else if (db.version == "2") {
// Upgrade DB Schema to Version 3
db.changeVersion("2", "5",
function(tx) {
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN sort INTEGER DEFAULT 0;");
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN len INTEGER DEFAULT 6;");
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN diff INTEGER DEFAULT 0;");
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN period INTEGER DEFAULT 30;");
});
} else if (db.version == "3") {
// Upgrade DB Schema to Version 4
db.changeVersion("3", "5",
function(tx) {
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN len INTEGER DEFAULT 6;");
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN diff INTEGER DEFAULT 0;");
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN period INTEGER DEFAULT 30;");
});
} else if (db.version == "4") {
// Upgrade DB Schema to Version 4
db.changeVersion("4", "5",
function(tx) {
tx.executeSql("ALTER TABLE OTPStorage ADD COLUMN period INTEGER DEFAULT 30;");
});
}
} catch (e) {
// DB Failed to open
@ -63,26 +88,106 @@ function getDB() {
function getOTP() {
var db = getDB();
db.transaction(
function(tx) {
var res = tx.executeSql("select * from OTPStorage order by sort;");
for (var i=0; i < res.rows.length; i++) {
appWin.appendOTP(res.rows.item(i).title, res.rows.item(i).secret, res.rows.item(i).type, res.rows.item(i).counter, res.rows.item(i).fav, res.rows.item(i).len, res.rows.item(i).diff, res.rows.item(i).period);
if (res.rows.item(i).fav) appWin.setCover(i);
}
});
}
// Get all OTP Values and put them into a JSON-Object
function db2json() {
var db = getDB();
var otpList = [];
db.transaction(
function(tx) {
var res = tx.executeSql("select * from OTPStorage;");
for (var i=0; i < res.rows.length; i++) {
mainPage.appendOTP(res.rows.item(i).title, res.rows.item(i).secret, res.rows.item(i).type, res.rows.item(i).counter, res.rows.item(i).fav);
if (res.rows.item(i).fav) mainPage.setCoverOTP(res.rows.item(i).title, res.rows.item(i).secret, res.rows.item(i).type);
}
otpList.push({
"title": res.rows.item(i).title,
"secret": res.rows.item(i).secret,
"type": res.rows.item(i).type,
"counter": res.rows.item(i).counter,
"sort": res.rows.item(i).sort,
"len": res.rows.item(i).len,
"diff": res.rows.item(i).diff,
"period": res.rows.item(i).period,
});
}
)
});
if (otpList.length > 0) {
return(JSON.stringify({"app": "sailotp", "version": 4, "otplist": otpList}));
} else {
return("")
}
}
// Read Values from JSON and put them into the DB
function json2db(jsonString, error) {
var json = JSON.parse(jsonString);
error = "";
if ((json.version != "1" || json.version != "2" || json.version != "3" || json.version != "4") && json.app != "sailotp" ) {
error = "Unrecognized format, file is not a SailOTP export";
return(false);
} else {
var otpList = [];
otpList = json.otplist;
if (otpList.length > 0) {
while(otpList.length > 0) {
var otpItem = otpList.shift();
if (otpItem.title != "" & otpItem.secret.length >= 16) {
if (json.version == "1") {
addOTP(otpItem.title, otpItem.secret, otpItem.type, otpItem.counter, 0, 6, 0, 30);
} else if (json.version == "2") {
addOTP(otpItem.title, otpItem.secret, otpItem.type, otpItem.counter, otpItem.sort, 6, 0, 30);
} else if (json.version == "3") {
addOTP(otpItem.title, otpItem.secret, otpItem.type, otpItem.counter, otpItem.sort, otpItem.len, otpItem.diff, 30);
} else {
addOTP(otpItem.title, otpItem.secret, otpItem.type, otpItem.counter, otpItem.sort, otpItem.len, otpItem.diff, otpItem.period);
}
}
}
parentPage.refreshOTPList();
return(true);
} else {
error = "File contains no Tokens";
return(false);
}
}
}
// Add a new OTP
function addOTP(title, secret, type, counter) {
function addOTP(title, secret, type, counter, sort, len, diff, period) {
var db = getDB();
db.transaction(
function(tx) {
tx.executeSql("INSERT INTO OTPStorage VALUES(?, ?, ?, ?, ?);", [title, secret, type, counter, 0]);
}
)
if (checkOTP(title, secret)) {
console.log("Token " + title + " is already in DB");
} else {
tx.executeSql("INSERT INTO OTPStorage VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?);", [title, secret, type, counter, 0, sort, len, diff, period]);
console.log("Token " + title + " added.");
}
});
}
// Check if an OTP Token already exists in the DB
function checkOTP(title, secret) {
var db = getDB();
var res
db.transaction(
function(tx) {
res = tx.executeSql("select title FROM OTPStorage WHERE title=? and secret=?;", [title, secret]);
});
return res.rows.length > 0 ? true : false
}
// Remove an existing OTP
@ -92,10 +197,10 @@ function removeOTP(title, secret) {
db.transaction(
function(tx) {
tx.executeSql("DELETE FROM OTPStorage WHERE title=? and secret=?;", [title, secret]);
}
)
});
}
// Set OTP to favourite
function setFav(title, secret) {
var db = getDB();
@ -103,31 +208,44 @@ function setFav(title, secret) {
function(tx) {
tx.executeSql("UPDATE OTPStorage set fav = 0");
tx.executeSql("UPDATE OTPStorage set fav = 1 WHERE title=? and secret=?;", [title, secret]);
}
)
});
}
// Reset favourite Flag for OTP
function resetFav(title, secret) {
var db = getDB();
db.transaction(
function(tx) {
tx.executeSql("UPDATE OTPStorage set fav = 0");
}
)
});
}
// Change an existing OTP
function changeOTP(title, secret, type, counter, oldtitle, oldsecret) {
function changeOTP(title, secret, type, counter, len, diff, period, oldtitle, oldsecret) {
var db = getDB();
db.transaction(
function(tx) {
tx.executeSql("UPDATE OTPStorage SET title=?, secret=?, type=?, counter=? WHERE title=? and secret=?;", [title, secret, type, counter, oldtitle, oldsecret]);
}
)
tx.executeSql("UPDATE OTPStorage SET title=?, secret=?, type=?, counter=?, len=?, diff=?, period=? WHERE title=? and secret=?;", [title, secret, type, counter, len, diff, period, oldtitle, oldsecret]);
console.log("Token " + title + " modified.");
}
);
}
function changeOTPSort(title, secret, sort) {
var db = getDB();
db.transaction(
function(tx) {
if (!checkOTP(title, secret)) {
console.log("Token " + title + " is not in DB");
} else {
tx.executeSql("UPDATE OTPStorage SET sort=? WHERE title=? and secret=?;", [sort, title, secret]);
console.log("Token " + title + " modified.");
}
});
}
// Get the counter for a HOTP value, incerment the counter on request
function getCounter(title, secret, increment) {
@ -139,8 +257,7 @@ function getCounter(title, secret, increment) {
function(tx) {
res = tx.executeSql("SELECT counter FROM OTPStorage where title=? and secret=?;", [title, secret]);
if (increment) tx.executeSql("UPDATE OTPStorage set counter=counter+1 WHERE title=? and secret=?;", [title, secret]);
}
)
});
return res.rows.item(0).counter;
}

24
qml/lib/urldecoder.js Normal file
View file

@ -0,0 +1,24 @@
function decode(url) {
// otpauth://totp/user@host.com?secret=JBSWY3DPEHPK3PXP
// otpauth://totp/user@host.com?secret=JBSWY3DPEHPK3PXP
if (url.search(/^otpauth:\/\/[th]otp\/.*?.*/) != -1) {
var ret = {"type": "", "title": "", "secret": "", "counter": ""};
ret.type = url.slice(10,14).toUpperCase();
ret.title = decodeURIComponent(url.slice(15, url.indexOf("?")));
var pstr = url.slice(url.indexOf("?")+1, url.length);
var params = pstr.split("&");
for (var i = 0; i < params.length; ++i) {
pstr = params[i];
var tmp = pstr.split("=");
if (tmp[0] == "secret") ret.secret = tmp[1];
if (tmp[0] == "counter") ret.counter = tmp[1];
if (tmp[0] == "digits") ret.digits = tmp[1];
}
return ret;
}
}

View file

@ -1,29 +1,29 @@
/*
* Copyright (c) 2013, Stefan Brand <seiichiro@seiichiro0185.org>
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote products
*
* 3. The names of the contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@ -33,51 +33,253 @@ import Sailfish.Silica 1.0
// Define the Layout of the About Page
Page {
id: aboutPage
Image {
id: logo
source: "../sailotp.png"
anchors.horizontalCenter: parent.horizontalCenter
y: 200
}
Label {
id: name
anchors.horizontalCenter: parent.horizontalCenter
y: 320
font.bold: true
text: "SailOTP 0.4"
}
Text {
id: desc
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: name.bottom
anchors.topMargin: 20
text: "A Simple Sailfish OTP Generator<br />(RFC 6238/4226 compatible)"
color: "white"
}
Text {
id: copyright
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: desc.bottom
anchors.topMargin: 20
text: "Copyright: Stefan Brand<br />License: BSD (3-clause)"
color: "white"
}
Button {
id: homepage
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: copyright.bottom
anchors.topMargin: 20
text: "<a href=\"https://github.com/seiichiro0185/sailotp\">SailOTP on Github</a>"
onClicked: {
Qt.openUrlExternally("https://github.com/seiichiro0185/sailotp")
allowedOrientations: Orientation.All
SilicaFlickable {
id: flickable
anchors.fill: parent
width: parent.width
contentHeight: column.height
Column {
id: column
width: parent.width
spacing: Theme.paddingSmall
// Spacer
Item {
width: parent.width
height: Theme.paddingLarge
}
Image {
id: logo
source: "../sailotp.png"
anchors.horizontalCenter: parent.horizontalCenter
}
Label {
id: name
anchors.horizontalCenter: parent.horizontalCenter
font.bold: true
text: "SailOTP " + Qt.application.version
}
Label {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
horizontalAlignment: TextEdit.Center
text: qsTr("A simple Sailfish OTP generator")
color: Theme.primaryColor
}
Label {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
horizontalAlignment: TextEdit.Center
font.pixelSize: Theme.fontSizeSmall
text: qsTr("(RFC 6238/4226 compatible)")
color: Theme.primaryColor
}
// Spacer
Item {
width: parent.width
height: Theme.paddingMedium
}
Button {
text: qsTr("Online Manual")
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
Qt.openUrlExternally("https://www.seiichiro0185.org/sailfish:apps:sailotp:manual")
}
}
Button {
text: qsTr("Source Code & Issue Tracker")
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
Qt.openUrlExternally("https://github.com/seiichiro0185/sailotp/")
}
}
// Spacer
Item {
width: parent.width
height: Theme.paddingMedium
}
Label {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
font.pixelSize: Theme.fontSizeSmall
horizontalAlignment: Text.Center
wrapMode: Text.WordWrap
text: qsTr("Copyright") + " Stefan Brand"
color: Theme.secondaryHighlightColor
}
Label {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
font.pixelSize: Theme.fontSizeSmall
horizontalAlignment: Text.Center
wrapMode: Text.WordWrap
text: qsTr("License") + " " + qsTr("BSD (3-clause)")
color: Theme.secondaryHighlightColor
}
Item {
width: parent.width
height: Theme.paddingMedium
}
Label {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
font.pixelSize: Theme.fontSizeMedium
horizontalAlignment: TextEdit.Center
wrapMode: Text.WordWrap
text: qsTr("Contributors:")
color: Theme.secondaryHighlightColor
}
DetailItem {
width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
label: qsTr("SteamGuard support")
value: "Robin Appelman"
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: qsTr("Search")
value: "Jyri-Petteri Paloposki"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: qsTr("Icon")
value: "JSEHV"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: qsTr("Customizable Time Period")
value: "Andrey Skvortsov"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: qsTr("SailJail Permissions")
value: "DrYak"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
Item {
width: parent.width
height: Theme.paddingMedium
}
Label {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
font.pixelSize: Theme.fontSizeMedium
horizontalAlignment: Text.Center
wrapMode: Text.WordWrap
text: qsTr("Translators:")
color: Theme.secondaryHighlightColor
}
DetailItem {
label: "Brazilian Portuguese"
value: "caio2k"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "Chinese"
value: "BirdZhang"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "Dutch"
value: "JSEHV"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "Finnish"
value: "Johan Heikkilä, Jyri-Petteri Paloposki"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "French"
value: "Romain Tartière"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "Italian"
value: "Tichy"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "Hungarian"
value: "1Zgp"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "Russian"
value: "moorchegue"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "Spanish"
value: "p4moedo"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "Swedish"
value: "Åke Engelbrektson"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "English"
value: "Stefan Brand"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
DetailItem {
label: "German"
value: "Stefan Brand"
width: parent.width
alignment: Qt.AlignLeft
leftMargin: Theme.paddingLarge*2
}
LinkedLabel {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - Theme.paddingLarge*4
font.pixelSize: Theme.fontSizeSmall
horizontalAlignment: TextEdit.left
plainText: "\n"+qsTr("SailOTP uses the following third party libs:")+'
http://caligatio.github.io/jsSHA/
https://github.com/jlinoff/openssl-aes-cipher/
http://sourceforge.net/projects/qzxing/
http://fukuchi.org/works/qrencode/'
color: Theme.secondaryHighlightColor
}
}
}
Text {
id: accnowledgement
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: homepage.bottom
anchors.topMargin: 20
text: "SailOTP uses the SHA-1 Implementation<br />from http://caligatio.github.io/jsSHA/"
color: "white"
VerticalScrollDecorator { }
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Stefan Brand <seiichiro@seiichiro0185.org>
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@ -36,6 +36,8 @@ import "../lib/storage.js" as DB // Import the storage library for Config-Access
Dialog {
id: addOTP
allowedOrientations: Orientation.All
// We get the Object of the parent page on call to refresh it after adding a new Entry
property QtObject parentPage: null
@ -43,76 +45,173 @@ Dialog {
property string paramType: "TOTP"
property string paramLabel: ""
property string paramKey: ""
property int paramLen: 6
property int paramDiff: 0
property int paramCounter: 1 // New Counters start at 1
property int paramPeriod: 30
property bool paramNew: false
function checkQR() {
if (paramLabel != "" && paramKey != "" && !paramNew) {
return(true);
} else {
return(false);
}
}
SilicaFlickable {
id: addOtpList
anchors.fill: parent
contentHeight: dialog.height
PullDownMenu {
visible: checkQR()
MenuItem {
text: qsTr("Show QR-Code")
onClicked: {
if (((paramType == "TOTP" || paramType == "TOTP_STEAM") && (otpLabel.text == "" || otpSecret.text == "")) || (paramType == "HOTP" && (otpLabel.text == "" || otpSecret.text == "" || otpCounter.text <= 0))) {
notify.show(qsTr("Can't create QR-Code from incomplete settings!"), 4000);
} else {
var otpurl = "";
if (paramType == "TOTP") {
if (otpLabel.text != "" && otpSecret.text != "")
otpurl = "otpauth://totp/"+otpLabel.text+"?secret="+otpSecret.text+"&digits="+otpLen.text;
} else if (paramType == "HOTP") {
if (paramLabel != "" && paramKey != "" && paramCounter > 0)
otpurl = "otpauth://hotp/"+otpLabel.text+"?secret="+otpSecret.text+"&counter="+otpCounter.text+"&digits="+otpLen.text;
}
if (otpurl != "") {
pageStack.push(Qt.resolvedUrl("QRPage.qml"), {paramQrsource: otpurl, paramLabel: otpLabel.text, paramQRId: -1});
} else {
notify.show(qsTr("Can't create QR-Code from incomplete settings!"), 4000);
}
}
}
}
}
VerticalScrollDecorator {}
Column {
anchors.fill: parent
id: dialog
width: parent.width
DialogHeader {
acceptText: paramLabel != "" ? "Save" : "Add"
acceptText: paramNew ? qsTr("Add") : qsTr("Save")
}
ComboBox {
id: typeSel
label: "Type"
label: qsTr("Type")
menu: ContextMenu {
MenuItem { text: "Time-based (TOTP)"; onClicked: { paramType = "TOTP" } }
MenuItem { text: "Counter-based (HOTP)"; onClicked: { paramType = "HOTP" } }
MenuItem { text: qsTr("Time-based (TOTP)"); onClicked: { paramType = "TOTP" } }
MenuItem { text: qsTr("Counter-based (HOTP)"); onClicked: { paramType = "HOTP" } }
MenuItem { text: qsTr("Steam Guard"); onClicked: { paramType = "TOTP_STEAM" } }
}
}
TextField {
id: otpLabel
width: parent.width
label: "Title"
placeholderText: "Title for the OTP"
label: qsTr("Title")
placeholderText: qsTr("Title for the OTP")
text: paramLabel != "" ? paramLabel : ""
focus: true
horizontalAlignment: TextInput.AlignLeft
EnterKey.enabled: text.length > 0
EnterKey.iconSource: "image://theme/icon-m-enter-next"
EnterKey.onClicked: otpSecret.focus = true
}
TextField {
id: otpSecret
width: parent.width
label: "Secret (at least 16 characters)"
label: qsTr("Secret (at least 16 characters)")
text: paramKey != "" ? paramKey : ""
placeholderText: "Secret OTP Key"
placeholderText: qsTr("Secret OTP Key")
focus: true
validator: RegExpValidator { regExp: /^(?:[A-Za-z2-7]{8})*(?:[A-Za-z2-7]{2}|[A-Za-z2-7]{4}|[A-Za-z2-7]{5}|[A-Za-z2-7]{7})?$/ }
inputMethodHints: Qt.ImhNoPredictiveText
horizontalAlignment: TextInput.AlignLeft
EnterKey.enabled: text.length > 15
EnterKey.iconSource: "image://theme/icon-m-enter-next"
EnterKey.onClicked: otpLen.focus = true
}
TextField {
id: otpLen
width: parent.width
visible: paramType != "TOTP_STEAM" ? true : false
label: qsTr("Length")
text: paramLen
placeholderText: qsTr("Length of the Token")
focus: true
horizontalAlignment: TextInput.AlignLeft
validator: IntValidator { bottom: 1 }
EnterKey.iconSource: "image://theme/icon-m-enter-next"
EnterKey.onClicked: paramType == "HOTP" ? otpCounter.focus = true : otpDiff.focus = true
}
TextField {
id: otpDiff
width: parent.width
visible: paramType == "TOTP" ? true : false
label: qsTr("Time Derivation (Seconds)")
text: paramDiff
placeholderText: qsTr("Time Derivation (Seconds)")
focus: true
horizontalAlignment: TextInput.AlignLeft
validator: IntValidator {}
EnterKey.iconSource: "image://theme/icon-m-enter-accept"
EnterKey.onClicked: addOTP.accept()
}
TextField {
id: otpPeriod
width: parent.width
visible: paramType == "TOTP" ? true : false
label: qsTr("Period (Seconds)")
text: paramPeriod
placeholderText: qsTr("Period (Seconds)")
focus: true
horizontalAlignment: TextInput.AlignLeft
validator: IntValidator {}
EnterKey.iconSource: "image://theme/icon-m-enter-accept"
EnterKey.onClicked: addOTP.accept()
}
TextField {
id: otpCounter
width: parent.width
visible: paramType == "HOTP" ? true : false
label: "Next Counter Value"
label: qsTr("Next Counter Value")
text: paramCounter
placeholderText: "Next Value of the Counter"
placeholderText: qsTr("Next Value of the Counter")
focus: true
horizontalAlignment: TextInput.AlignLeft
validator: IntValidator { bottom: 0 }
EnterKey.iconSource: "image://theme/icon-m-enter-accept"
EnterKey.onClicked: addOTP.accept()
}
Component.onCompleted: { typeSel.currentIndex = paramType == "HOTP" ? 1 : 0 }
}
}
// Check if we can Save
canAccept: otpLabel.text.length > 0 && otpSecret.text.length >= 16 && (paramType == "TOTP" || otpCounter.text.length > 0) ? true : false
canAccept: otpLabel.text.length > 0 && otpSecret.text.length >= 16 && otpSecret.acceptableInput && otpLen.text >= 1 && ((paramType == "TOTP" && otpDiff.text != "" && otpPeriod.text > 0) || paramType == "TOTP_STEAM" || otpCounter.text.length > 0) ? true : false
// Save if page is Left with Add
onDone: {
if (result == DialogResult.Accepted) {
// Save the entry to the Config DB
if (paramLabel != "" && paramKey != "") {
// Save the entry to the Config DB
if (paramLabel != "" && paramKey != "" && !paramNew) {
// Parameters where filled -> Change existing entry
DB.changeOTP(otpLabel.text, otpSecret.text, paramType, otpCounter.text, paramLabel, paramKey)
DB.changeOTP(otpLabel.text, otpSecret.text, paramType, otpCounter.text, otpLen.text, otpDiff.text, otpPeriod.text, paramLabel, paramKey)
} else {
// There were no parameters -> Add new entry
DB.addOTP(otpLabel.text, otpSecret.text, paramType, otpCounter.text);
DB.addOTP(otpLabel.text, otpSecret.text, paramType, otpCounter.text, appWin.listModel.count, otpLen.text, otpDiff.text, otpPeriod.text);
}
// Refresh the main Page
// Refresh the main Page
parentPage.refreshOTPList();
}
}

275
qml/pages/ExportPage.qml Normal file
View file

@ -0,0 +1,275 @@
/*
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import QtQuick 2.2
import Sailfish.Silica 1.0
import Sailfish.Pickers 1.0
import harbour.sailotp.FileIO 1.0 // Import FileIO Class
import harbour.sailotp.QCipher 1.0 // Import FileIO Class
import "../lib/storage.js" as DB // Import the storage library for Config-Access
// Define Layout of the Export / Import Page
Dialog {
id: exportPage
allowedOrientations: Orientation.All
// We get the Object of the parent page on call to refresh it after adding a new Entry
property QtObject parentPage: null
property string mode: "import"
function fillNum(num) {
if (num < 10) {
return("0"+num);
} else {
return(num)
}
}
function creFileName() {
var date = new Date();
return(XDG_HOME_DIR + "/sailotp_"+date.getFullYear()+fillNum(date.getMonth()+1)+fillNum(date.getDate())+".aes");
}
function checkFileName(file) {
if (mode == "export") {
if (exportFile.exists(file) && !fileOverwrite.checked) {
notify.show(qsTr("File already exists, choose \"Overwrite existing\" to overwrite it."), 4000);
return(false)
} else {
return(true)
}
} else {
if (exportFile.exists(file)) {
return(true)
} else {
notify.show(qsTr("Given file does not exist!"), 4000);
return(false)
}
}
}
// FileIO Object for reading / writing files
FileIO {
id: exportFile
source: fileName.text
onError: { console.log(msg); }
}
// QCipher Object for Encryption
QCipher {
id: cipher
}
SilicaFlickable {
id: exportFlickable
anchors.fill: parent
PullDownMenu {
MenuItem {
text: mode == "export" ? qsTr("Import") : qsTr("Export")
onClicked: {
if (mode == "export") {
mode = "import"
fileName.text = ""
} else {
mode = "export"
fileName.text = creFileName()
}
}
}
}
// FilePicker for the Input File
Component {
id: filePickerPage
FilePickerPage {
nameFilters: [ '*' ]
onSelectedContentPropertiesChanged: {
fileName.text = selectedContentProperties.filePath
}
}
}
VerticalScrollDecorator {}
Column {
anchors.fill: parent
DialogHeader {
acceptText: mode == "export" ? qsTr("Export") : qsTr("Import")
}
TextField {
id: fileName
width: parent.width
text: mode == "export" ? creFileName() : "";
label: qsTr("Filename")
placeholderText: qsTr("File to export")
visible: mode == "export"
focus: true
horizontalAlignment: TextInput.AlignLeft
EnterKey.enabled: text.length > 0
EnterKey.iconSource: "image://theme/icon-m-enter-next"
EnterKey.onClicked: filePassword.focus = true
}
ValueButton {
width: parent.width
label: qsTr("File to import")
value: fileName.text ? fileName.text : "None"
visible: mode == "import"
onClicked: pageStack.push(filePickerPage)
}
TextSwitch {
id: fileOverwrite
checked: false
visible: mode == "export"
text: qsTr("Overwrite existing")
}
TextField {
id: filePassword
width: parent.width
label: qsTr("Password")
placeholderText: qsTr("Password for the file")
echoMode: TextInput.Password
focus: true
horizontalAlignment: TextInput.AlignLeft
EnterKey.enabled: text.length > 0
EnterKey.iconSource: mode == "export" ? "image://theme/icon-m-enter-next" : "image://theme/icon-m-enter-accept"
EnterKey.onClicked: mode == "export" ? filePasswordCheck.focus = true : exportPage.accept()
}
TextField {
id: filePasswordCheck
width: parent.width
label: (filePassword.text != filePasswordCheck.text && filePassword.text.length > 0) ? qsTr("Passwords don't match!") : qsTr("Passwords match!")
placeholderText: qsTr("Repeated Password for the file")
visible: mode == "export"
echoMode: TextInput.Password
focus: true
horizontalAlignment: TextInput.AlignLeft
EnterKey.enabled: filePassword.text == filePasswordCheck.text && filePassword.text.length > 0
EnterKey.iconSource: "image://theme/icon-m-enter-accept"
EnterKey.onClicked: exportPage.accept()
}
Text {
id: importText
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: 20
width: parent.width - 2*Theme.paddingLarge
wrapMode: Text.Wrap
maximumLineCount: 15
font.pixelSize: Theme.fontSizeTiny
color: Theme.secondaryColor
visible: mode == "import"
text: qsTr("Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import.")
}
Text {
id: exportText
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: 20
width: parent.width - 2*Theme.paddingLarge
wrapMode: Text.Wrap
maximumLineCount: 15
font.pixelSize: Theme.fontSizeTiny
color: Theme.secondaryColor
visible: mode == "export"
text: qsTr("Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export.")+"\n\n"+qsTr("To view the content of the export file outside of SailOTP use the following openssl command:") + "\n\nopenssl enc -d -a -aes-256-cbc -in <file>"
}
}
}
// Check if we can continue
canAccept: fileName.text.length > 0 && filePassword.text.length > 0 && (mode == "import" || filePassword.text == filePasswordCheck.text) && checkFileName(fileName.text) ? true : false
// Do the DB-Export / Import
onDone: {
if (result == DialogResult.Accepted) {
var plainText = ""
var chipherText = ""
if (mode == "export") {
// Export Database to File
plainText = DB.db2json();
if (plainText != "") {
try {
chipherText = cipher.encrypt(plainText, filePassword.text);
if (chipherText != "") {
if (!exportFile.write(chipherText)) {
notify.show(qsTr("Error writing to file ")+ fileName.text, 4000);
} else {
notify.show(qsTr("Token Database exported to ")+ fileName.text, 4000);
}
} else {
notify.show(qsTr("Could not encrypt tokens. Error: "), 4000);
}
} catch(e) {
notify.show(qsTr("Could not encrypt tokens. Error: ") + e, 4000);
}
} else {
notify.show(qsTr("Could not read tokens from Database"), 4000);
}
} else if(mode == "import") {
// Import Tokens from File
chipherText = exportFile.read();
if (chipherText != "") {
try {
var errormsg = ""
plainText = cipher.decrypt(chipherText, filePassword.text)
if (DB.json2db(plainText, errormsg)) {
notify.show(qsTr("Tokens imported from ")+ fileName.text, 4000);
} else {
notify.show(errormsg, 4000);
}
} catch (e) {
notify.show(qsTr("Unable to decrypt file, did you use the right password?"), 4000);
}
} else {
notify.show(qsTr("Could not read from file ") + fileName.text, 4000);
}
}
}
}
}

View file

@ -1,29 +1,29 @@
/*
* Copyright (c) 2013, Stefan Brand <seiichiro@seiichiro0185.org>
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote products
*
* 3. The names of the contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@ -36,69 +36,67 @@ import "../lib/crypto.js" as OTP
Page {
id: mainPage
ListModel {
id: otpListModel
}
allowedOrientations: Orientation.All
// This holds the time of the last update of the page as Unix Timestamp (in Milliseconds)
// This holds the time of the last update of the page as Unix Timestamp (in Milliseconds)
property double lastUpdated: 0
// Add an entry to the list
function appendOTP(title, secret, type, counter, fav) {
otpListModel.append({"secret": secret, "title": title, "fav": fav, "type": type, "counter": counter, "otp": "------"});
}
// Hand favorite over to the cover
function setCoverOTP(title, secret, type) {
appWin.coverTitle = title
appWin.coverSecret = secret
appWin.coverType = type
if (secret = "") {
appWin.coverOTP = "";
} else if (type == "HOTP") {
appWin.coverOTP = "------";
}
}
property double seconds_global: 0
property string searchTerm: ""
// Reload the List of OTPs from storage
function refreshOTPList() {
otpList.visible = false;
otpListModel.clear();
otpList.model = null; // Hack to prevent unaccessible pulley after List refresh
appWin.listModel.clear();
DB.getOTP();
refreshOTPValues();
otpList.model = appWin.listModel; // Hack to prevent unaccessible pulley after List refresh
otpList.visible = true;
}
// Calculate new OTPs for every entry
function refreshOTPValues() {
// get seconds from current Date
var curDate = new Date();
var seconds = curDate.getSeconds();
// get seconds from current Date
var curDate = new Date();
seconds_global = curDate.getSeconds() % 30
// Iterate over all List entries
for (var i=0; i<otpListModel.count; i++) {
if (otpListModel.get(i).type == "TOTP") {
// Only update on full 30 / 60 Seconds or if last run of the Functions is more than 2s in the past (e.g. app was in background)
if (otpListModel.get(i).otp == "------" || seconds == 30 || seconds == 0 || (curDate.getTime() - lastUpdated > 2000)) {
var curOTP = OTP.calcOTP(otpListModel.get(i).secret, "TOTP")
otpListModel.setProperty(i, "otp", curOTP);
// Iterate over all List entries
for (var i=0; i<appWin.listModel.count; i++) {
if (appWin.listModel.get(i).type === "TOTP" || appWin.listModel.get(i).type === "TOTP_STEAM" ) {
// Take derivation into account if set
var seconds = (curDate.getSeconds() + appWin.listModel.get(i).diff) % appWin.listModel.get(i).period;
// Only update on full period Seconds or if last run of the Functions is more than 2s in the past (e.g. app was in background)
if (appWin.listModel.get(i).otp === "------" || seconds == 0 || (curDate.getTime() - lastUpdated > 2000)) {
var curOTP = OTP.calcOTP(appWin.listModel.get(i).secret, appWin.listModel.get(i).type, appWin.listModel.get(i).len, appWin.listModel.get(i).diff, 0, appWin.listModel.get(i).period);
appWin.listModel.setProperty(i, "otp", curOTP);
} else if (appWin.coverType === "HOTP" && (curDate.getTime() - lastUpdated > 2000) && appWin.listModel.get(i).fav === 1) {
// If we are coming back from the CoverPage update OTP value if current favourite is HOTP
appWin.listModel.setProperty(i, "otp", appWin.coverOTP);
}
} else if (appWin.coverType == "HOTP" && (curDate.getTime() - lastUpdated > 2000) && otpListModel.get(i).fav == 1) {
// If we are coming back from the CoverPage update OTP value if current favourite is HOTP
otpListModel.setProperty(i, "otp", appWin.coverOTP);
}
}
// Update the Progressbar
updateProgress.value = 29 - (seconds % 30)
// Set lastUpdate property
// Set lastUpdate property
lastUpdated = curDate.getTime();
}
// Reload OTP List on Return to the Page (to e.g. accomodate changed settings)
onStatusChanged: {
if (status === PageStatus.Activating) {
refreshOTPList();
if (searchTerm != "") {
for (var i = 0; i < appWin.listModel.count; i++) {
appWin.listModel.get(i).itemVisible = appWin.listModel.get(i).title.toString().toLowerCase().indexOf(searchTerm.toLowerCase()) > -1
}
}
}
}
Timer {
interval: 500
// Timer only runs when app is acitive and we have entries
running: Qt.application.active && otpListModel.count
running: Qt.application.active && appWin.listModel.count
repeat: true
onTriggered: refreshOTPValues();
}
@ -108,53 +106,118 @@ Page {
PullDownMenu {
MenuItem {
text: "About"
text: qsTr("About")
onClicked: pageStack.push(Qt.resolvedUrl("About.qml"))
}
MenuItem {
text: "Add OTP"
onClicked: pageStack.push(Qt.resolvedUrl("AddOTP.qml"), {parentPage: mainPage})
text: qsTr("Settings")
visible: true
onClicked: pageStack.push(Qt.resolvedUrl("Settings.qml"))
}
MenuItem {
text: qsTr("Export / Import")
onClicked: pageStack.push(Qt.resolvedUrl("ExportPage.qml"), {parentPage: mainPage, mode: "export"})
}
MenuItem {
text: qsTr("Add Token")
onClicked: pageStack.push(Qt.resolvedUrl("ScanOTP.qml"), {parentPage: mainPage})
}
}
ProgressBar {
id: updateProgress
width: parent.width
maximumValue: 29
anchors.top: parent.top
anchors.topMargin: 48
// Only show when there are enries
visible: otpListModel.count
}
SilicaListView {
id: otpList
header: PageHeader {
title: "SailOTP"
}
anchors.fill: parent
model: otpListModel
model: appWin.listModel
width: parent.width
ViewPlaceholder {
enabled: otpList.count == 0
text: "Nothing here"
hintText: "Pull down to add a OTP"
text: qsTr("Nothing here")
hintText: qsTr("Pull down to add a OTP")
}
header: Column {
width: parent.width
height: headerRow.height + searchRow.height
Row {
id: headerRow
height: Theme.itemSizeSmall
width: parent.width
ProgressBar {
id: updateProgress
anchors.topMargin: Theme.paddingLarge * 1.15
anchors.top: parent.top
anchors.bottom: parent.bottom
height: parent.height
width: parent.width * 0.65
maximumValue: 29
value: 29 - seconds_global
// Only show when there are enries
visible: appWin.listModel.count
}
PageHeader {
id: header
anchors.top: parent.top
height: Theme.itemSizeSmall
width: parent.width * 0.35
title: "SailOTP"
}
}
Row {
id: searchRow
width: parent.width
SearchField {
id: searchField
font.pixelSize: Theme.fontSizeMedium
width: parent.width
// This would be useful, but seems to break the button altogether. Perhaps it'll work later?
// canHide: true
EnterKey.enabled: false
inputMethodHints: Qt.ImhNoPredictiveText // Qt.ImhPreferUppercase | Qt.ImhNoAutoUppercase
placeholderText: qsTr("Search")
onTextChanged: {
searchTerm = searchField.text
for (var i = 0; i < appWin.listModel.count; i++) {
appWin.listModel.get(i).itemVisible = appWin.listModel.get(i).title.toString().toLowerCase().indexOf(searchField.text.toLowerCase()) > -1
}
}
}
}
}
delegate: ListItem {
id: otpListItem
menu: otpContextMenu
contentHeight: Theme.itemSizeMedium
contentHeight: visible ? Theme.itemSizeMedium : 0
width: parent.width
visible: itemVisible
function remove() {
// Show 5s countdown, then delete from DB and List
remorseAction("Deleting", function() { DB.removeOTP(title, secret); otpListModel.remove(index) })
remorseAction(qsTr("Deleting"), function() { DB.removeOTP(title, secret); appWin.listModel.remove(index) })
}
function moveEntry(direction, index) {
if (direction) {
appWin.listModel.move(index, index-1, 1);
} else {
appWin.listModel.move(index, index+1, 1);
}
for (var i=0; i<appWin.listModel.count; i++) {
DB.changeOTPSort(appWin.listModel.get(i).title, appWin.listModel.get(i).secret, i);
}
}
onClicked: {
Clipboard.text = otp
if (settings.hideTokens) {
otpValue.visible = !otpValue.visible
} else if (settings.showQrDefaultAction) {
pageStack.push(Qt.resolvedUrl("QRPage.qml"), {paramQrsource: otp, paramLabel: title, paramQRId: index});
} else {
Clipboard.text = otp
notify.show(qsTr("Token for ") + title + qsTr(" copied to clipboard"), 3000);
}
}
ListView.onRemove: animateRemoval()
@ -169,19 +232,19 @@ Page {
onClicked: {
if (fav == 0) {
DB.setFav(title, secret)
setCoverOTP(title, secret, type)
appWin.setCover(index)
if (type == "HOTP") appWin.coverOTP = otp
for (var i=0; i<otpListModel.count; i++) {
for (var i=0; i<appWin.listModel.count; i++) {
if (i != index) {
otpListModel.setProperty(i, "fav", 0);
appWin.listModel.setProperty(i, "fav", 0);
} else {
otpListModel.setProperty(i, "fav", 1);
appWin.listModel.setProperty(i, "fav", 1);
}
}
} else {
DB.resetFav(title, secret)
setCoverOTP("SailOTP", "", "")
otpListModel.setProperty(index, "fav", 0);
DB.resetFav(title, secret);
appWin.setCover(-1);
appWin.listModel.setProperty(index, "fav", 0);
}
}
}
@ -201,19 +264,20 @@ Page {
text: model.otp
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeLarge
visible: !settings.hideTokens
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
// Show an update button on HTOP-Type Tokens
// Show an update button on HOTP type tokens
IconButton {
icon.source: "image://theme/icon-m-refresh"
anchors.right: parent.right
visible: type == "HOTP" ? true : false
onClicked: {
otpListModel.setProperty(index, "counter", DB.getCounter(title, secret, true));
otpListModel.setProperty(index, "otp", OTP.calcOTP(secret, "HOTP", counter));
appWin.listModel.setProperty(index, "counter", DB.getCounter(title, secret, true));
appWin.listModel.setProperty(index, "otp", OTP.calcOTP(secret, "HOTP", len, 0, counter));
if (fav == 1) appWin.coverOTP = otp;
}
}
@ -222,13 +286,36 @@ Page {
id: otpContextMenu
ContextMenu {
MenuItem {
text: "Edit"
text: qsTr("Copy to Clipboard")
visible: settings.hideTokens || settings.showQrDefaultAction
onClicked: {
pageStack.push(Qt.resolvedUrl("AddOTP.qml"), {parentPage: mainPage, paramLabel: title, paramKey: secret, paramType: type, paramCounter: DB.getCounter(title, secret, false)})
Clipboard.text = otp
notify.show(qsTr("Token for ") + title + qsTr(" copied to clipboard"), 3000);
}
}
MenuItem {
text: "Delete"
text: qsTr("Show Token as QR-Code")
visible: !settings.showQrDefaultAction
onClicked: pageStack.push(Qt.resolvedUrl("QRPage.qml"), {paramQrsource: otp, paramLabel: title, paramQRId: index});
}
MenuItem {
text: qsTr("Move up")
visible: index > 0 ? true : false;
onClicked: moveEntry(1, index);
}
MenuItem {
text: qsTr("Move down")
visible: index < appWin.listModel.count - 1 ? true : false;
onClicked: moveEntry(0, index);
}
MenuItem {
text: qsTr("Edit")
onClicked: {
pageStack.push(Qt.resolvedUrl("AddOTP.qml"), {parentPage: mainPage, paramLabel: title, paramKey: secret, paramType: type, paramLen: len, paramDiff: diff, paramCounter: DB.getCounter(title, secret, false), paramPeriod: period})
}
}
MenuItem {
text: qsTr("Delete")
onClicked: remove()
}
}
@ -237,11 +324,9 @@ Page {
VerticalScrollDecorator{}
Component.onCompleted: {
// Load list of OTP-Entries
// Load list of OTP-Entries
refreshOTPList();
}
}
}
}

77
qml/pages/QRPage.qml Normal file
View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
id: qrpage
allowedOrientations: Orientation.All
property int paramQRId: -1;
property string paramLabel: ""
property string paramQrsource: ""
Timer {
interval: 1000
// Timer only runs when app is acitive and we have entries
running: Qt.application.active && appWin.listModel.count && paramQRId >= 0
repeat: true
onTriggered: {
qrImage.source = "image://qqrencoder/"+appWin.listModel.get(paramQRId).otp;
}
}
Label {
id: qrLabel
text: paramLabel
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeLarge
anchors.horizontalCenter: parent.horizontalCenter
y: 96
}
Image {
id: qrImage
anchors.horizontalCenter: parent.horizontalCenter
y: 200
width: Theme.buttonWidthLarge
height: Theme.buttonWidthLarge
cache: false
}
Component.onCompleted: {
if (paramQrsource !== "") {
qrImage.source = "image://qqrencoder/"+paramQrsource;
} else {
notify.show(qsTr("Can't create QR-Code from an empty String"), 4000);
}
}
}

140
qml/pages/ScanOTP.qml Normal file
View file

@ -0,0 +1,140 @@
/*
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import QtQuick 2.0
import QtMultimedia 5.0
import Sailfish.Silica 1.0
import harbour.sailotp.QZXing 2.2
import harbour.sailotp.FileIO 1.0
import "../lib/urldecoder.js" as URL
Page {
id: scanPage
allowedOrientations: Orientation.All
property QtObject parentPage: null
property bool scanning: false
Timer {
id: scanTimer
interval: 100
running: false
repeat: false
onTriggered: {
if (fileIO.mkpath(XDG_CACHE_DIR)) {
cam.imageCapture.captureToLocation(XDG_CACHE_DIR + "/qrscan.jpg");
} else {
notify.show(qsTr("Can't access temporary directory"), 3000);
}
}
}
SilicaFlickable {
anchors.fill: parent
PullDownMenu {
MenuItem {
text: qsTr("Add manually")
onClicked: pageStack.replace(Qt.resolvedUrl("AddOTP.qml"), {parentPage: parentPage, paramNew: true})
}
}
PageHeader {
id: header
title: scanning ? qsTr("Scanning...") : qsTr("Scan Code")
}
Camera {
id: cam
flash.mode: Camera.FlashOff
captureMode: Camera.CaptureStillImage
focus.focusMode: Camera.FocusContinuous
imageCapture.onImageSaved: { decoder.decodeImageFromFile(path); }
}
QZXing {
id: decoder
onTagFound: {
var ret = URL.decode(tag);
var len = 6
scanning = false
if (ret && ret.type !== "" && ret.title !== "" && ret.secret !== "" && (ret.counter !== "" || ret.type === "TOTP")) {
if (ret.digits !== "") {
len = ret.digits
}
pageStack.replace(Qt.resolvedUrl("AddOTP.qml"), {parentPage: parentPage, paramLabel: ret.title, paramKey: ret.secret.toUpperCase(), paramType: ret.type, paramCounter: ret.counter, paramLen: len, paramNew: true})
} else {
notify.show(qsTr("No valid Token data found."), 3000);
}
}
onDecodingFinished: { if (succeeded==false && scanning) scanTimer.start(); }
}
FileIO {
id: fileIO
}
VideoOutput {
id: prev
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: header.bottom
source: cam
MouseArea {
anchors.fill: parent
onClicked: {
if (scanning) {
scanning = false;
} else {
scanning = true;
scanTimer.start();
}
}
}
}
Text {
id: text
anchors.top: prev.bottom
anchors.topMargin: 32
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 2*Theme.paddingLarge
wrapMode: Text.Wrap
maximumLineCount: 4
font.pixelSize: Theme.fontSizeSmall
color: Theme.primaryColor
text: qsTr("Tap the picture to start / stop scanning. Pull down to add Token manually.")
}
}
}

80
qml/pages/Settings.qml Normal file
View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
id: settingsPage
allowedOrientations: Orientation.All
SilicaFlickable {
id: flickable
anchors.fill: parent
width: parent.width
contentHeight: column.height
Column {
id: column
width: parent.width
spacing: Theme.paddingSmall
PageHeader { title: qsTr("Settings") }
SectionHeader { text: qsTr("Behaviour") }
TextSwitch {
id: showQrDefaultAction
checked: settings.showQrDefaultAction
text: qsTr("Show Token as QR on Tap")
onClicked: {
settings.showQrDefaultAction = !settings.showQrDefaultAction;
if (settings.showQrDefaultAction) {
settings.hideTokens = false;
hideTokens.checked = settings.hideTokens
}
}
}
TextSwitch {
id: hideTokens
checked: settings.hideTokens
text: qsTr("Hide Tokens and Reveal on Tap")
onClicked: {
settings.hideTokens = !settings.hideTokens;
if (settings.hideTokens) {
settings.showQrDefaultAction = false;
showQrDefaultAction.checked = settings.showQrDefaultAction
}
}
}
}
VerticalScrollDecorator { }
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View file

@ -0,0 +1,83 @@
* Sun Feb 26 2023 Stefan Brand <sailfish@seiichiro0185.org> 1.11.1-1
- Fix Empty Token List after Restart for New Installs.
* Mon Feb 20 2023 Stefan Brand <sailfish@seiichiro0185.org> 1.11.0-1
- Rework Export/Import File Encryption to use C++
- Switch to SHA256 for Export/Import Encryption instead of MD5
- Add FilePicker to select Import-File
* Wed Jan 25 2023 Stefan Brand <sailfish@seiichiro0185.org> 1.10.2-1
- Add Sailjail Permission for Camera Use (contributed by Keeper-of-the-Keys)
* Sun Dec 27 2022 Stefan Brand <sailfish@seiichiro0185.org> 1.10.1-1
- Update Swedish Translation (contributed by Åke Engelbrektson)
* Sun Dec 18 2022 Stefan Brand <sailfish@seiichiro0185.org> 1.10.0-1
- Added Customizable Time Period (contributed by Andrey Skvortsov)
- Added SailJail Permissions (contributed by DrYak)
* Sat Jun 26 2021 Stefan Brand <sailfish@seiichiro0185.org> 1.9.4-1
- Update pt_br Translation (contributed by caio2k)
- Refreshed App Icon (contributed by JSEHV)
* Sun Feb 21 2021 Stefan Brand <sailfish@seiichiro0185.org> 1.9.3-1
- Added Hungarian Translation (conbtributed by 1Zgp)
* Mon Jan 18 2021 Stefan Brand <sailfish@seiichiro0185.org> 1.9.2-1
- Fix a Small Bug in Search (conbtributed by Jyri-Petteri Paloposki)
* Mon Jan 11 2021 Stefan Brand <sailfish@seiichiro0185.org> 1.9.1-1
- Fix About Page (contributed in parts by Jyri-Petteri Paloposki)
- Update Swedish Translation (contributed by Åke Engelbrektson)
- Small Visual Fix for the Progressbar
* Mon Jan 04 2021 Stefan Brand <sailfish@seiichiro0185.org> 1.9.0-1
- Add Search Functionality (conbtributed by Jyri-Petteri Paloposki)
- Updated Finnish Translation (contributed by Jyri-Petteri Paloposki)
* Sun Mar 03 2019 Stefan Brand <sailfish@seiichiro0185.org> 1.8.1-1
- Translation Updates
* Sun Feb 24 2019 Stefan Brand <sailfish@seiichiro0185.org> 1.8.0-1
- Added possibility to show a Token as QR-Code
- Added possibility to hide Tokens by default and reveal on tap
- Added Base32 input validation for secret
- Fix progressbar placement for different screen sizes / ambiances
- Fix About-Page styling for light ambiances
* Sun Jun 17 2018 Stefan Brand <sailfish@seiichiro0185.org> 1.7.2-1
- Visual fixes for SFOS 2.2.0.29
* Mon Apr 09 2018 Stefan Brand <sailfish@seiichiro0185.org> 1.7.1-1
- Added Italian Translation
- Adapt Packaging for new Harbour Rules
* Mon Apr 02 2018 Stefan Brand <sailfish@seiichiro0185.org> 1.7-1
- Added Chinese Translation
- Added Finish Translation
- Added Russian Translation
- Added Spanish Translation
- Some internal Preparation for future features
* Mon Oct 30 2017 Stefan Brand <sailfish@seiichiro0185.org> 1.6-1
- Changed AES Engine to cryptojs for Export/Import
* Sun Oct 09 2016 Stefan Brand <sailfish@seiichiro0185.org> 1.5-1
- Added French Translation (Thanks to Romain Tartière)
- Bugfix: Refresh HOTP-Token from Cover. Closes Github Issue #11
* Thu Jul 14 2016 Stefan Brand <sailfish@seiichiro0185.org> 1.4-1
- Added Setting for Time Derivation
- Added Setting for Token Length
* Sun Dec 06 2015 Stefan Brand <sailfish@seiichiro0185.org> 1.3-1
- Added SteamGuard OTP Type (Thanks to Robin Appelman)
* Sat May 30 2015 Stefan Brand <sailfish@seiichiro0185.org> 1.2-1
- Added Swedish translation (Thanks to Åke Engelbrektson)
* Fri May 22 2015 Stefan Brand <sailfish@seiichiro0185.org> 1.1-1
- Added URL-decoding for OTP-titles when scanning QR-codes
* Tue Jul 01 2014 Stefan Brand <sailfish@seiichiro0185.org> 1.0-1
- Added harbour-compatible QR-Reader

View file

@ -1,75 +0,0 @@
#
# Do NOT Edit the Auto-generated Part!
# Generated by: spectacle version 0.27
#
Name: harbour-sailotp
# >> macros
# << macros
%{!?qtc_qmake:%define qtc_qmake %qmake}
%{!?qtc_qmake5:%define qtc_qmake5 %qmake5}
%{!?qtc_make:%define qtc_make make}
%{?qtc_builddir:%define _builddir %qtc_builddir}
Summary: SailOTP
Version: 0.2
Release: 1
Group: Security
License: BSD
URL: https://github.com/seiichiro0185/sailotp/
Source0: %{name}-%{version}.tar.bz2
Source100: harbour-sailotp.yaml
Requires: sailfishsilica-qt5 >= 0.10.9
BuildRequires: pkgconfig(sailfishapp) >= 0.0.10
BuildRequires: pkgconfig(Qt5Core)
BuildRequires: pkgconfig(Qt5Qml)
BuildRequires: pkgconfig(Qt5Quick)
BuildRequires: desktop-file-utils
%description
A Sailfish implementation of the Timebased One Time Pad algorithm as used by Google Authenticator and a growing number of Websites.
%prep
%setup -q -n %{name}-%{version}
# >> setup
# << setup
%build
# >> build pre
# << build pre
%qtc_qmake5
%qtc_make %{?_smp_mflags}
# >> build post
# << build post
%install
rm -rf %{buildroot}
# >> install pre
# << install pre
%qmake5_install
# >> install post
# << install post
desktop-file-install --delete-original \
--dir %{buildroot}%{_datadir}/applications \
%{buildroot}%{_datadir}/applications/*.desktop
%files
%defattr(-,root,root,-)
/usr/share/icons/hicolor/86x86/apps
/usr/share/applications
/usr/share/harbour-sailotp
/usr/bin
%{_datadir}/icons/hicolor/86x86/apps/%{name}.png
%{_datadir}/applications/%{name}.desktop
%{_datadir}/%{name}/qml
%{_bindir}
# >> files
# << files

View file

@ -1,30 +1,42 @@
Name: harbour-sailotp
Summary: SailOTP
Version: 0.4
Version: 1.11.1
Release: 1
Group: Security
URL: https://github.com/seiichiro0185/sailotp/
License: "BSD\t"
Sources:
- '%{name}-%{version}.tar.bz2'
- '%{name}-%{version}.tar.bz2'
Description: |
A Sailfish implementation of the One Time Pad algorithm as used by Google Authenticator and a growing number of Websites.
Configure: none
Builder: qtc5
Builder: qmake5
QMakeOptions:
- VERSION=%{version}
- RELEASE=%{release}
PkgConfigBR:
- sailfishapp >= 0.0.10
- Qt5Core
- Qt5Qml
- Qt5Quick
- Qt5Quick
- Qt5Qml
- Qt5Core
- Qt5Multimedia
- sailfishapp >= 1.0.2
- libcrypto
Requires:
- sailfishsilica-qt5 >= 0.10.9
- sailfishsilica-qt5 >= 0.10.9
Files:
- /usr/share/icons/hicolor/86x86/apps
- /usr/share/applications
- /usr/share/harbour-sailotp
- /usr/bin
- '%{_datadir}/icons/hicolor/86x86/apps/%{name}.png'
- '%{_datadir}/applications/%{name}.desktop'
- '%{_datadir}/%{name}/qml'
- '%{_bindir}'
- '%defattr(644, root, root, 755)'
- '%attr(755, root, root) %{_bindir}'
- '%{_datadir}/%{name}'
- '%{_datadir}/applications/%{name}.desktop'
- '%{_datadir}/icons/hicolor/*/apps/%{name}.png'
PkgBR: []

7
src/FileIO/FileIO.pri Normal file
View file

@ -0,0 +1,7 @@
QT += core quick
INCLUDEPATH += $$PWD/src
HEADERS += $$PWD/src/fileio.h
SOURCES += $$PWD/src/fileio.cpp

113
src/FileIO/src/fileio.cpp Normal file
View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fileio.h"
#include <QFile>
#include <QDir>
#include <QTextStream>
FileIO::FileIO(QObject *parent) :
QObject(parent)
{
}
QString FileIO::read()
{
if (mSource.isEmpty()){
emit error("source is empty");
return QString();
}
QFile file(mSource);
QString fileContent;
if ( file.open(QIODevice::ReadOnly) ) {
QString line;
QTextStream t( &file );
do {
line = t.readLine();
fileContent += line + "\n";
} while (!line.isNull());
file.close();
} else {
emit error("Unable to open the file");
return QString();
}
return fileContent;
}
bool FileIO::write(const QString& data)
{
if (mSource.isEmpty())
return false;
QFile file(mSource);
if (!file.open(QFile::WriteOnly | QFile::Truncate))
return false;
QTextStream out(&file);
out << data;
file.close();
return true;
}
bool FileIO::exists()
{
if (mSource.isEmpty()) {
emit error("Source is empty!");
return false;
}
QFile file(mSource);
return file.exists();
}
bool FileIO::exists(const QString& filename)
{
if (filename.isEmpty()) {
emit error("Source is empty!");
return false;
}
QFile file(filename);
return file.exists();
}
bool FileIO::mkpath(const QString& dirpath) {
if (dirpath.isEmpty()) {
emit error("Source is empty!");
return false;
}
QDir dir(dirpath);
return dir.mkpath(dirpath);
}

64
src/FileIO/src/fileio.h Normal file
View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FILEIO_H
#define FILEIO_H
#include <QObject>
#include <QString>
class FileIO : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
explicit FileIO(QObject *parent = 0);
Q_INVOKABLE QString read();
Q_INVOKABLE bool write(const QString& data);
Q_INVOKABLE bool exists();
Q_INVOKABLE bool exists(const QString& filename);
Q_INVOKABLE bool mkpath(const QString& dirpath);
QString source() { return mSource; };
public slots:
void setSource(const QString& source) { mSource = source; };
signals:
void sourceChanged(const QString& source);
void error(const QString& msg);
private:
QString mSource;
};
#endif // FILEIO_H

9
src/QCipher/QCipher.pri Normal file
View file

@ -0,0 +1,9 @@
QT += core quick
INCLUDEPATH += $$PWD/src
HEADERS += $$PWD/src/cipher.h \
$$PWD/src/qcipher.h
SOURCES += $$PWD/src/cipher.cpp \
$$PWD/src/qcipher.cpp

3
src/QCipher/README.md Normal file
View file

@ -0,0 +1,3 @@
# QChipher - a minimal OpenSSL Encryption / Decryption Wrapper
Based on https://github.com/jlinoff/openssl-aes-cipher by Joe Linoff

476
src/QCipher/src/cipher.cpp Normal file
View file

@ -0,0 +1,476 @@
// ================================================================
// Description: Cipher class.
// Copyright: Copyright (c) 2012 by Joe Linoff
// Version: 1.3.0
// Author: Joe Linoff
//
// LICENSE
// The cipher package is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// The cipher package 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 the change
// tool; if not, write to the Free Software Foundation, Inc., 59
// Temple Place, Suite 330, Boston, MA 02111-1307 USA.
// ================================================================
#include "cipher.h"
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <stdexcept>
#include <sstream>
#include <cstring> // strlen
#include <cstdlib> // getenv
#include <unistd.h> // getdomainname
#include <openssl/aes.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>
#include <openssl/err.h>
using namespace std;
// ================================================================
// MACROS
// ================================================================
#define DBG_PRE __FILE__ << ":" << __LINE__ << ": "
#define DBG_FCT(fct) if(m_debug) cout << DBG_PRE << "FCT " << fct << endl
#define DBG_TDUMP(v) if(m_debug) tdump(__FILE__, __LINE__, #v, v)
#define DBG_PKV(v) if(m_debug) vdump(__FILE__, __LINE__, #v, v)
#define DBG_PKVR(k, v) if(m_debug) vdump(__FILE__, __LINE__, k, v)
#define DBG_BDUMP(a, x) if(m_debug) bdump(__FILE__, __LINE__, #a, a, x)
#define DBG_MDUMP(a) if(m_debug) bdump(__FILE__, __LINE__, #a, (unsigned char*)a.c_str(), a.size())
#define DBG_MADEIT cout << DBG_PRE << "MADE IT" << endl
#define PKV(v) vdump(__FILE__, __LINE__, #v, v)
#define SALTED_PREFIX "Salted__"
namespace
{
// ================================================================
// DEBUG mode only.
// Formated dump of a general type.
// ================================================================
template<typename T> void vdump(const string& fn,
uint ln,
const string& prefix,
const T& d)
{
cout << fn << ":" << ln << ": " << prefix << "\t" << d << endl;
}
// ================================================================
// DEBUG mode only.
// Explicit template instantiation of the above for string
// types so that I can report the length.
// ================================================================
template<> void vdump<string>(const string& fn,
uint ln,
const string& prefix,
const string& d)
{
cout << fn << ":" << ln << ": "
<< prefix << "\t"
<< left << setw(64) << d
<< " (" << d.size() << ")"
<< endl;
}
// ================================================================
// DEBUG mode only.
// Dump for fixed sized types like m_salt and m_key.
// ================================================================
template<typename T> void tdump(const string& fn,
uint ln,
const string& prefix,
const T& d)
{
cout << fn << ":" << ln << ": " << prefix << "\t";
for(uint i=0;i<sizeof(T);++i) {
#if 0
// Prettified output.
// I turned it off so that the format would match openssl.
if ((i%16)==0) {
if (i) {
cout << endl;
cout << "\t\t\t";
}
else {
if (prefix.size()<4) {
cout << "\t";
}
cout << "\t";
}
}
else if (i) {
cout << ", ";
}
#endif
cout << setw(2) << setfill('0') << hex << right << uint(d[i]) << dec << setfill(' ');
}
cout << " (" << sizeof(T) << ")" << endl;
}
// ================================================================
// DEBUG mode only.
// Binary data dump.
// ================================================================
void bdump(const string& fn,
uint ln,
const string& prefix,
unsigned char* a,
unsigned int len)
{
cout << fn << ":" << ln << ": " << prefix;
for(uint i=0;i<len;++i) {
if ((i%16)==0) {
if (i) {
cout << endl;
cout << "\t\t\t";
}
else {
cout << "\t\t";
}
}
else if (i) {
cout << ", ";
}
cout << setw(2) << hex << right << uint(a[i]) << dec;
}
cout << " (" << len << ")" << endl;
}
}
// ================================================================
// Constructor.
// ================================================================
Cipher::Cipher()
: m_cipher(CIPHER_DEFAULT_CIPHER),
m_digest(CIPHER_DEFAULT_DIGEST),
m_count(CIPHER_DEFAULT_COUNT),
m_embed(true), // compatible with openssl
m_debug(false)
{
}
// ================================================================
// Constructor.
// ================================================================
Cipher::Cipher(const std::string& cipher,
const std::string& digest,
uint count,
bool embed)
: m_cipher(cipher),
m_digest(digest),
m_count(count),
m_embed(embed),
m_debug(false)
{
}
// ================================================================
// Destructor.
// ================================================================
Cipher::~Cipher()
{
}
// ================================================================
// encrypt
// ================================================================
string Cipher::encrypt(const string& plaintext,
const string& pass,
const string& salt)
{
DBG_FCT("encrypt");
set_salt(salt);
init(pass);
kv1_t x = encode_cipher(plaintext);
uchar* ct = x.first;
uint ctlen = x.second;
DBG_BDUMP(ct, ctlen);
string ret = encode_base64(ct, ctlen);
delete [] ct;
DBG_MDUMP(ret);
return ret;
}
// ================================================================
// decrypt
// ================================================================
string Cipher::decrypt(const string& mimetext,
const string& pass,
const string& salt)
{
DBG_FCT("decrypt");
DBG_PKV(mimetext);
kv1_t x = decode_base64(mimetext);
uchar* ct = x.first;
uint ctlen = x.second;
DBG_PKV(ctlen);
DBG_BDUMP(ct, ctlen);
if (strncmp((const char*)ct, SALTED_PREFIX, 8) == 0) {
memcpy(m_salt, &ct[8], 8);
ct += 16;
ctlen -= 16;
}
else {
set_salt(salt);
}
init(pass);
string ret = decode_cipher(ct, ctlen);
DBG_MDUMP(ret);
return ret;
}
// ================================================================
// encode_base64
// ================================================================
string Cipher::encode_base64(uchar* ciphertext,
uint ciphertext_len) const
{
DBG_FCT("encode_base64");
BIO* b64 = BIO_new(BIO_f_base64());
BIO* bm = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bm);
if (BIO_write(b64, ciphertext, ciphertext_len)<2) {
throw runtime_error("BIO_write() failed");
}
if (BIO_flush(b64)<1) {
throw runtime_error("BIO_flush() failed");
}
BUF_MEM *bptr=0;
BIO_get_mem_ptr(b64, &bptr);
uint len=bptr->length;
char* mimetext = new char[len+1];
memcpy(mimetext, bptr->data, bptr->length-1);
mimetext[bptr->length-1]=0;
BIO_free_all(b64);
string ret = mimetext;
delete [] mimetext;
return ret;
}
// ================================================================
// decode_base64
// ================================================================
Cipher::kv1_t Cipher::decode_base64(const string& mimetext) const
{
DBG_FCT("decode_base64");
kv1_t x;
int SZ=mimetext.size(); // this will always be smaller
x.first = new uchar[SZ];
char* tmpbuf = new char[SZ+1];
strcpy(tmpbuf, mimetext.c_str());
BIO* b64 = BIO_new(BIO_f_base64());
BIO* bm = BIO_new_mem_buf(tmpbuf, mimetext.size());
bm = BIO_push(b64, bm);
if (SZ <= 64) {
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
}
x.second = BIO_read(bm, x.first, SZ);
BIO_free_all(bm);
delete [] tmpbuf;
return x;
}
// ================================================================
// encode_cipher
// ================================================================
Cipher::kv1_t Cipher::encode_cipher(const string& plaintext) const
{
DBG_FCT("encode_cipher");
uint SZ = plaintext.size() + AES_BLOCK_SIZE + 20; // leave some padding
uchar* ciphertext = new uchar[SZ];
bzero(ciphertext, SZ);
uchar* pbeg = ciphertext;
// This requires some explanation.
// In order to be compatible with openssl, I need to append
// 16 characters worth of information that describe the salt.
// I found this in the openssl source code but I couldn't
// find any associated documentation.
uint off = 0;
if (m_embed) {
memcpy(&ciphertext[0], SALTED_PREFIX, 8);
memcpy(&ciphertext[8], m_salt, 8);
off = 16;
ciphertext += off;
}
int ciphertext_len=0;
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
const EVP_CIPHER* cipher = EVP_aes_256_cbc();
EVP_CIPHER_CTX_init(ctx);
if (1 != EVP_EncryptInit_ex(ctx, cipher, NULL, m_key, m_iv)) {
EVP_CIPHER_CTX_free(ctx);
throw runtime_error("EVP_EncryptInit_ex DBG_PKV() init key/iv failed");
}
EVP_CIPHER_CTX_set_key_length(ctx, EVP_MAX_KEY_LENGTH);
// Encrypt the plaintext data all at once.
// It would be straightforward to chunk it but that
// add unecesary complexity at this point.
uchar* pt_buf = (uchar*)plaintext.c_str();
uint pt_len = plaintext.size();
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &ciphertext_len, pt_buf, pt_len)) {
EVP_CIPHER_CTX_free(ctx);
throw runtime_error("EVP_EncryptUpdate() failed");
}
uchar* pad_buf = ciphertext + ciphertext_len; // pad at the end
int pad_len=0;
if (1 != EVP_EncryptFinal_ex(ctx, pad_buf, &pad_len)) {
EVP_CIPHER_CTX_free(ctx);
throw runtime_error("EVP_EncryptFinal_ex() failed");
}
ciphertext_len += pad_len + off; // <off> for the Salted prefix
EVP_CIPHER_CTX_free(ctx);
return kv1_t(pbeg, ciphertext_len);
}
// ================================================================
// decode_cipher
// ================================================================
string Cipher::decode_cipher(uchar* ciphertext,
uint ciphertext_len) const
{
DBG_FCT("decode_cipher");
const uint SZ = ciphertext_len+20;
uchar* plaintext = new uchar[SZ];
int plaintext_len = 0;
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
bzero(plaintext, SZ);
EVP_CIPHER_CTX_init(ctx);
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, m_key, m_iv)) {
EVP_CIPHER_CTX_free(ctx);
throw runtime_error("EVP_DecryptInit_ex() failed");
}
//EVP_CIPHER_CTX_set_key_length(ctx, EVP_MAX_KEY_LENGTH);
if (1 != EVP_DecryptUpdate(ctx, plaintext, &plaintext_len, ciphertext, ciphertext_len)) {
EVP_CIPHER_CTX_free(ctx);
throw runtime_error("EVP_DecryptUpdate() failed");
}
int plaintext_padlen=0;
if (1 != EVP_DecryptFinal_ex(ctx, plaintext+plaintext_len, &plaintext_padlen)) {
ERR_print_errors_fp(stderr);
EVP_CIPHER_CTX_free(ctx);
throw runtime_error("EVP_DecryptFinal_ex() failed");
}
plaintext_len += plaintext_padlen;
plaintext[plaintext_len] = 0;
string ret = (char*)plaintext;
delete [] plaintext;
EVP_CIPHER_CTX_free(ctx);
return ret;
}
// ================================================================
// set_salt
// ================================================================
void Cipher::set_salt(const string& salt)
{
DBG_FCT("set_salt");
if (salt.length() == 0) {
// Choose a random salt.
for(uint i=0;i<sizeof(m_salt);++i) {
m_salt[i] = rand() % 256;
}
}
else if (salt.length() == 8) {
memcpy(m_salt, salt.c_str(), 8);
}
else if (salt.length()<8) {
throw underflow_error("init(): salt is too short, must be 8 characters");
}
else if (salt.length()>8) {
throw overflow_error("init(): salt is too long, must be 8 characters");
}
}
// ================================================================
// init()
// ================================================================
void Cipher::init(const string& pass)
{
DBG_FCT("init");
// Use a default passphrase if the user didn't specify one.
m_pass = pass;
if (m_pass.empty() ) {
// Default: ' deFau1t pASsw0rD'
// Obfuscate so that a simple strings will not find it.
char a[] = {' ', 'd', 'e', 'F', 'a', 'u', '1', 't', ' ',
'p', 'A', 'S', 's', 'w', '0', 'r', 'D', 0};
m_pass = a;
}
// Create the key and IV values from the passkey.
bzero(m_key, sizeof(m_key));
bzero(m_iv, sizeof(m_iv));
OpenSSL_add_all_algorithms();
const EVP_CIPHER* cipher = EVP_get_cipherbyname(m_cipher.c_str());
const EVP_MD* digest = EVP_get_digestbyname(m_digest.c_str());
if (!cipher) {
string msg = "init(): cipher does not exist "+m_cipher;
throw runtime_error(msg);
}
if (!digest) {
string msg = "init(): digest does not exist "+m_digest;
throw runtime_error(msg);
}
int ks = EVP_BytesToKey(cipher, // cipher type
digest, // message digest
m_salt, // 8 bytes
(uchar*)m_pass.c_str(), // pass value
m_pass.length(),
m_count, // number of rounds
m_key,
m_iv);
if (ks!=32) {
throw runtime_error("init() failed: "
"EVP_BytesToKey did not return a 32 byte key");
}
DBG_PKV(m_pass);
DBG_PKV(m_cipher);
DBG_PKV(m_digest);
DBG_TDUMP(m_salt);
DBG_TDUMP(m_key);
DBG_TDUMP(m_iv);
DBG_PKV(m_count);
}
// ================================================================
// get_version
// ================================================================
std::string Cipher::get_version() {
return "1.3.0";
}
// ================================================================
// get_ssl_version
// ================================================================
#define TO_STRING_(x) #x
#define TO_STRING(x) TO_STRING_(x)
std::string Cipher::get_ssl_version() {
return TO_STRING(OPENSSL_VERSION_NUMBER);
}

208
src/QCipher/src/cipher.h Normal file
View file

@ -0,0 +1,208 @@
// ================================================================
// Description: Cipher class.
// Copyright: Copyright (c) 2012 by Joe Linoff
// Version: 1.3.0
// Author: Joe Linoff
//
// LICENSE
// The cipher package is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// The cipher package 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 the change
// tool; if not, write to the Free Software Foundation, Inc., 59
// Temple Place, Suite 330, Boston, MA 02111-1307 USA.
// ================================================================
#ifndef cipher_h
#define cipher_h
#include <string>
#include <vector>
#include <utility> // pair
#define CIPHER_DEFAULT_CIPHER "aes-256-cbc"
#define CIPHER_DEFAULT_DIGEST "sha256"
#define CIPHER_DEFAULT_COUNT 1
/**
* The cipher object encrypts plaintext data or decrypts ciphertext
* data. All data is in ASCII because it is MIME encoded.
*
* The default cipher used is AES-256-CBC from the openssl library
* but there are many others available. The default digest used is
* SHA256 which is stronger than MD5.
*
* The algorithms mimic openssl so files created with this object
* and with the openssl tool are interchangeable.
*
* Here is how you would use it to encrypt and decrypt plaintext
* data in memory.
* @code
* #include "cipher.h"
* #include <string>
* using namepsace std;
*
* // Example the encrypts and decrypts some plaintext.
* // Use encrypt_file or decrypt_file to deal with files.
* void cipher_test()
* {
* string pass = "testTEST!23_";
* string salt = "12345678"; // must be 8 chars
* string plaintext = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
*
* // Encrypt and decrypt.
* Cipher c;
* string ciphertext = c.encrypt(plaintext ,pass,salt);
* string decoded = c.decrypt(ciphertext,pass,salt);
*
* // Test the results
* if (plaintext == decoded) {
* cout << "passed" << endl;
* }
* else {
* cout << "failed" << endl;
* }
* }
* @endcode
* @author Joe Linoff
*/
class Cipher
{
public:
typedef unsigned int uint;
typedef unsigned char uchar;
typedef uchar aes_key_t[32];
typedef uchar aes_iv_t[32];
typedef uchar aes_salt_t[8];
typedef std::pair<uchar*,uint> kv1_t;
public:
/**
* Constructor.
*/
Cipher();
/**
* Constructor.
* @param cipher The cipher algorithm to use (ex. aes-256-cbc).
* @param digest The digest to use (ex. sha256).
* @param count The number of iterations (def. 1).
* @param embed Embed the salt. If this is false, the output will
* not be compatible with openssl.
*/
Cipher(const std::string& cipher,
const std::string& digest,
uint count=1,
bool embed=true);
/**
* Destructor.
*/
~Cipher();
public:
/**
* Encrypt buffer using AES 256 CBC (SHA256).
* @param plaintext The plaintext buffer.
* @param pass The passphrase.
* @param salt The optional salt.
* @returns The ciphertext: encrypted, MIME encoded data.
*/
std::string encrypt(const std::string& plaintext,
const std::string& pass="",
const std::string& salt="");
public:
/**
* Decrypt a buffer using AES 256 CBC (SHA256).
* @param ciphertext The encrypted data.
* @param pass The passphrase.
* @param salt The optional salt.
* @returns The plaintext: decrypted, MIME decoded data.
*/
std::string decrypt(const std::string& ciphertext,
const std::string& pass="",
const std::string& salt="");
public:
/**
* Base64 encode.
* @param ciphertext Binary cipher text.
* @param ciphertext_len Length of cipher buffer.
* @returns The encoded ASCII MIME string.
*/
std::string encode_base64(uchar* ciphertext,
uint ciphertext_len) const;
/**
* Cipher encode.
* @param plaintext ASCII data to encode.
* @returns Binary data.
*/
kv1_t encode_cipher(const std::string& plaintext) const;
/**
* Base64 decode.
* @param mimetext ASCII MIME text.
* @returns Binary data.
*/
kv1_t decode_base64(const std::string& mimetext) const;
/**
* Cipher decode.
* @param ciphertext Binary cipher text.
* @param ciphertext_len Length of cipher buffer.
* @returns The decoded ASCII string.
*/
std::string decode_cipher(uchar* ciphertext,
uint ciphertext_len) const;
public:
/**
* Get the version of this class.
* @returns The version of the class.
*/
static std::string get_version();
/**
* Get the version of ssl.
*/
static std::string get_ssl_version();
public:
/**
* Set the internal debug flag.
* This is only useful for library developers.
* @param b True for debug or false otherwise.
*/
void debug(bool b=true) {m_debug=b;}
/**
* Is debug mode set?
* @returns The current debug mode.
*/
bool debug() const {return m_debug;}
private:
/**
* Convert string salt to internal format.
* @param salt The salt.
*/
void set_salt(const std::string& salt);
/**
* Initialize the cipher: set the key and IV values.
* @param pass The passphrase.
*/
void init(const std::string& pass);
private:
std::string m_pass;
std::string m_cipher;
std::string m_digest;
aes_salt_t m_salt;
aes_key_t m_key;
aes_iv_t m_iv;
uint m_count;
bool m_embed;
bool m_debug;
};
#endif

View file

@ -0,0 +1,29 @@
#include "qcipher.h"
QCipher::QCipher(QObject *parent) : QObject(parent)
{
c = Cipher("aes-256-cbc", "sha256");
}
QString QCipher::encrypt(QString plaintext, QString pass)
{
try {
std::string enc;
enc = c.encrypt(plaintext.toStdString(), pass.toStdString());
return QString::fromUtf8(enc.c_str());
} catch (...) {
return "";
}
}
QString QCipher::decrypt(QString ciphertext, QString pass)
{
try {
std::string dec;
dec = c.decrypt(ciphertext.toStdString(), pass.toStdString());
return QString::fromUtf8(dec.c_str());
} catch (...) {
return "";
}
};

24
src/QCipher/src/qcipher.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef QCIPHER_H
#define QCIPHER_H
#include <QObject>
#include <QString>
#include "cipher.h"
class QCipher : public QObject
{
Q_OBJECT
public:
explicit QCipher(QObject *parent = nullptr);
Q_INVOKABLE QString encrypt(QString plaintext, QString pass);
Q_INVOKABLE QString decrypt(QString ciphertext, QString pass);
private:
Cipher c;
signals:
};
#endif // QCIPHER_H

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Stefan Brand <seiichiro@seiichiro0185.org>
* Copyright (c) 2014, Stefan Brand <seiichiro@seiichiro0185.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@ -27,14 +27,77 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef QT_QML_DEBUG
#include <QtQuick>
#endif
#include <sailfishapp.h>
#include <QGuiApplication>
#include "fileio.h"
#include "qcipher.h"
#include "qzxing.h"
#include "qqrencode.h"
void migrateLocalStorage()
{
// The new location of the LocalStorage database
QDir newDbDir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/QML/OfflineStorage/Databases/");
if(newDbDir.exists())
return;
newDbDir.mkpath(newDbDir.path());
QString dbname = QString(QCryptographicHash::hash(("harbour-sailotp"), QCryptographicHash::Md5).toHex());
// The old LocalStorage database
QFile oldDb(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.local/share/harbour-sailotp/harbour-sailotp/QML/OfflineStorage/Databases/" + dbname + ".sqlite");
QFile oldIni(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.local/share/harbour-sailotp/harbour-sailotp/QML/OfflineStorage/Databases/" + dbname + ".ini");
qDebug() << "Migrating " + oldDb.fileName() + " to " + newDbDir.absolutePath() + "/" + dbname + ".sqlite";
// Copy to new Database Location
oldDb.copy(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/QML/OfflineStorage/Databases/" + dbname + ".sqlite");
oldIni.copy(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/QML/OfflineStorage/Databases/" + dbname + ".ini");
}
int main(int argc, char *argv[])
{
return SailfishApp::main(argc, argv);
// Get App and QML-View objects
QScopedPointer<QGuiApplication> app(SailfishApp::application(argc, argv));
QScopedPointer<QQuickView> view(SailfishApp::createView());
// QZXing QR Decoder
QZXing qrdecoder;
qrdecoder.registerQMLTypes();
// Internationalization, Load the Language
QString locale = QLocale::system().name();
QTranslator translator;
translator.load(locale,SailfishApp::pathTo(QString("i18n")).toLocalFile());
app->installTranslator(&translator);
// Migrate to new Storage Directory
migrateLocalStorage();
// Set some global values
app->setOrganizationName("org.seiichiro0185");
app->setOrganizationDomain("org.seiichiro0185");
app->setApplicationName("harbour-sailotp");
app->setApplicationVersion(APP_VERSION);
// Register FileIO Class
qmlRegisterType<FileIO, 1>("harbour.sailotp.FileIO", 1, 0, "FileIO");
// Register QCipher Class
qmlRegisterType<QCipher, 1>("harbour.sailotp.QCipher", 1, 0, "QCipher");
// Prepare the QML and set Homedir
view->setSource(SailfishApp::pathTo("qml/harbour-sailotp.qml"));
view->rootContext()->setContextProperty("XDG_HOME_DIR", QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
view->rootContext()->setContextProperty("XDG_CACHE_DIR", QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
view->engine()->addImageProvider("qqrencoder", new QQRencoder());
view->show();
// Run the app
return app->exec();
}

View file

@ -0,0 +1,43 @@
#include <QPainter>
#include "qqrencode.h"
#include "qrencode.h"
QQRencoder::QQRencoder() : QQuickImageProvider(QQuickImageProvider::Image) {}
QImage QQRencoder::requestImage(const QString &id, QSize *size, const QSize &requestedSize) {
// Inspired by https://code.google.com/p/livepro/source/browse/trunk/gfxengine/QRCodeQtUtil.cpp
int imgSize = 400;
if (requestedSize.width() > 0) imgSize = requestedSize.width();
// Encode QR-Data
QRcode *qrdata = QRcode_encodeString(qPrintable(id), 0, QR_ECLEVEL_M, QR_MODE_8, 1);
// Calculate qr-pixel size
int datawidth = qrdata->width;
int pixsize = static_cast<int>((imgSize - 64) / datawidth);
// allocate memory for the image
QImage image(imgSize, imgSize, QImage::Format_Mono);
memset(image.scanLine(0),0,image.byteCount());
// Draw Image from QR-Data
QPainter painter(&image);
painter.fillRect(image.rect(),Qt::white);
for(int x=0;x<datawidth;x++) {
for(int y=0;y<datawidth;y++) {
if(1 & qrdata->data[y*datawidth+x]) painter.fillRect(QRect(x*pixsize+32, y*pixsize+32, pixsize, pixsize), Qt::black);
}
}
size->setHeight(image.height());
size->setWidth(image.width());
// free up memory
painter.end();
QRcode_free(qrdata);
// return image data
return image;
}

16
src/qqrencode/qqrencode.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef QQRENCODE_H
#define QQRENCODE_H
#include <QObject>
#include <QImage>
#include <QQuickImageProvider>
QT_BEGIN_NAMESPACE
class QQRencoder : public QQuickImageProvider {
public:
explicit QQRencoder();
virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize);
};
#endif // QQRENCODE_H

View file

@ -0,0 +1,11 @@
INCLUDEPATH += \
$$PWD \
$$PWD/qrencode
HEADERS += \
$$PWD/qrencode/*.h \
$$PWD/qqrencode.h
SOURCES += \
$$PWD/qrencode/*.c \
$$PWD/qqrencode.cpp

1164
src/qqrencode/qrenc.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,238 @@
/*
* qrencode - QR Code encoder
*
* Binary sequence class.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bitstream.h"
BitStream *BitStream_new(void)
{
BitStream *bstream;
bstream = (BitStream *)malloc(sizeof(BitStream));
if(bstream == NULL) return NULL;
bstream->length = 0;
bstream->data = NULL;
return bstream;
}
static int BitStream_allocate(BitStream *bstream, int length)
{
unsigned char *data;
if(bstream == NULL) {
return -1;
}
data = (unsigned char *)malloc(length);
if(data == NULL) {
return -1;
}
if(bstream->data) {
free(bstream->data);
}
bstream->length = length;
bstream->data = data;
return 0;
}
static BitStream *BitStream_newFromNum(int bits, unsigned int num)
{
unsigned int mask;
int i;
unsigned char *p;
BitStream *bstream;
bstream = BitStream_new();
if(bstream == NULL) return NULL;
if(BitStream_allocate(bstream, bits)) {
BitStream_free(bstream);
return NULL;
}
p = bstream->data;
mask = 1 << (bits - 1);
for(i=0; i<bits; i++) {
if(num & mask) {
*p = 1;
} else {
*p = 0;
}
p++;
mask = mask >> 1;
}
return bstream;
}
static BitStream *BitStream_newFromBytes(int size, unsigned char *data)
{
unsigned char mask;
int i, j;
unsigned char *p;
BitStream *bstream;
bstream = BitStream_new();
if(bstream == NULL) return NULL;
if(BitStream_allocate(bstream, size * 8)) {
BitStream_free(bstream);
return NULL;
}
p = bstream->data;
for(i=0; i<size; i++) {
mask = 0x80;
for(j=0; j<8; j++) {
if(data[i] & mask) {
*p = 1;
} else {
*p = 0;
}
p++;
mask = mask >> 1;
}
}
return bstream;
}
int BitStream_append(BitStream *bstream, BitStream *arg)
{
unsigned char *data;
if(arg == NULL) {
return -1;
}
if(arg->length == 0) {
return 0;
}
if(bstream->length == 0) {
if(BitStream_allocate(bstream, arg->length)) {
return -1;
}
memcpy(bstream->data, arg->data, arg->length);
return 0;
}
data = (unsigned char *)malloc(bstream->length + arg->length);
if(data == NULL) {
return -1;
}
memcpy(data, bstream->data, bstream->length);
memcpy(data + bstream->length, arg->data, arg->length);
free(bstream->data);
bstream->length += arg->length;
bstream->data = data;
return 0;
}
int BitStream_appendNum(BitStream *bstream, int bits, unsigned int num)
{
BitStream *b;
int ret;
if(bits == 0) return 0;
b = BitStream_newFromNum(bits, num);
if(b == NULL) return -1;
ret = BitStream_append(bstream, b);
BitStream_free(b);
return ret;
}
int BitStream_appendBytes(BitStream *bstream, int size, unsigned char *data)
{
BitStream *b;
int ret;
if(size == 0) return 0;
b = BitStream_newFromBytes(size, data);
if(b == NULL) return -1;
ret = BitStream_append(bstream, b);
BitStream_free(b);
return ret;
}
unsigned char *BitStream_toByte(BitStream *bstream)
{
int i, j, size, bytes;
unsigned char *data, v;
unsigned char *p;
size = BitStream_size(bstream);
if(size == 0) {
return NULL;
}
data = (unsigned char *)malloc((size + 7) / 8);
if(data == NULL) {
return NULL;
}
bytes = size / 8;
p = bstream->data;
for(i=0; i<bytes; i++) {
v = 0;
for(j=0; j<8; j++) {
v = v << 1;
v |= *p;
p++;
}
data[i] = v;
}
if(size & 7) {
v = 0;
for(j=0; j<(size & 7); j++) {
v = v << 1;
v |= *p;
p++;
}
data[bytes] = v;
}
return data;
}
void BitStream_free(BitStream *bstream)
{
if(bstream != NULL) {
free(bstream->data);
free(bstream);
}
}

View file

@ -0,0 +1,38 @@
/*
* qrencode - QR Code encoder
*
* Binary sequence class.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __BITSTREAM_H__
#define __BITSTREAM_H__
typedef struct {
int length;
unsigned char *data;
} BitStream;
extern BitStream *BitStream_new(void);
extern int BitStream_append(BitStream *bstream, BitStream *arg);
extern int BitStream_appendNum(BitStream *bstream, int bits, unsigned int num);
extern int BitStream_appendBytes(BitStream *bstream, int size, unsigned char *data);
#define BitStream_size(__bstream__) (__bstream__->length)
extern unsigned char *BitStream_toByte(BitStream *bstream);
extern void BitStream_free(BitStream *bstream);
#endif /* __BITSTREAM_H__ */

View file

@ -0,0 +1,330 @@
/*
* qrencode - QR Code encoder
*
* Masking.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include "qrencode.h"
#include "qrspec.h"
#include "mask.h"
static int Mask_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level)
{
unsigned int format;
unsigned char v;
int i;
int blacks = 0;
format = QRspec_getFormatInfo(mask, level);
for(i=0; i<8; i++) {
if(format & 1) {
blacks += 2;
v = 0x85;
} else {
v = 0x84;
}
frame[width * 8 + width - 1 - i] = v;
if(i < 6) {
frame[width * i + 8] = v;
} else {
frame[width * (i + 1) + 8] = v;
}
format= format >> 1;
}
for(i=0; i<7; i++) {
if(format & 1) {
blacks += 2;
v = 0x85;
} else {
v = 0x84;
}
frame[width * (width - 7 + i) + 8] = v;
if(i == 0) {
frame[width * 8 + 7] = v;
} else {
frame[width * 8 + 6 - i] = v;
}
format= format >> 1;
}
return blacks;
}
/**
* Demerit coefficients.
* See Section 8.8.2, pp.45, JIS X0510:2004.
*/
#define N1 (3)
#define N2 (3)
#define N3 (40)
#define N4 (10)
#define MASKMAKER(__exp__) \
int x, y;\
int b = 0;\
\
for(y=0; y<width; y++) {\
for(x=0; x<width; x++) {\
if(*s & 0x80) {\
*d = *s;\
} else {\
*d = *s ^ ((__exp__) == 0);\
}\
b += (int)(*d & 1);\
s++; d++;\
}\
}\
return b;
static int Mask_mask0(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER((x+y)&1)
}
static int Mask_mask1(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER(y&1)
}
static int Mask_mask2(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER(x%3)
}
static int Mask_mask3(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER((x+y)%3)
}
static int Mask_mask4(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER(((y/2)+(x/3))&1)
}
static int Mask_mask5(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER(((x*y)&1)+(x*y)%3)
}
static int Mask_mask6(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER((((x*y)&1)+(x*y)%3)&1)
}
static int Mask_mask7(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER((((x*y)%3)+((x+y)&1))&1)
}
#define maskNum (8)
typedef int MaskMaker(int, const unsigned char *, unsigned char *);
static MaskMaker *maskMakers[maskNum] = {
Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3,
Mask_mask4, Mask_mask5, Mask_mask6, Mask_mask7
};
#ifdef WITH_TESTS
unsigned char *Mask_makeMaskedFrame(int width, unsigned char *frame, int mask)
{
unsigned char *masked;
masked = (unsigned char *)malloc(width * width);
if(masked == NULL) return NULL;
maskMakers[mask](width, frame, masked);
return masked;
}
#endif
unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask, QRecLevel level)
{
unsigned char *masked;
if(mask < 0 || mask >= maskNum) {
errno = EINVAL;
return NULL;
}
masked = (unsigned char *)malloc(width * width);
if(masked == NULL) return NULL;
maskMakers[mask](width, frame, masked);
Mask_writeFormatInformation(width, masked, mask, level);
return masked;
}
//static int n1;
//static int n2;
//static int n3;
//static int n4;
static int Mask_calcN1N3(int length, int *runLength)
{
int i;
int demerit = 0;
int fact;
for(i=0; i<length; i++) {
if(runLength[i] >= 5) {
demerit += N1 + (runLength[i] - 5);
//n1 += N1 + (runLength[i] - 5);
}
if((i & 1)) {
if(i >= 3 && i < length-2 && (runLength[i] % 3) == 0) {
fact = runLength[i] / 3;
if(runLength[i-2] == fact &&
runLength[i-1] == fact &&
runLength[i+1] == fact &&
runLength[i+2] == fact) {
if(i == 3 || runLength[i-3] >= 4 * fact) {
demerit += N3;
//n3 += N3;
} else if(i+4 >= length || runLength[i+3] >= 4 * fact) {
demerit += N3;
//n3 += N3;
}
}
}
}
}
return demerit;
}
static int Mask_calcN2(int width, unsigned char *frame)
{
int x, y;
unsigned char *p;
unsigned char b22, w22;
int demerit = 0;
p = frame + width + 1;
for(y=1; y<width; y++) {
for(x=1; x<width; x++) {
b22 = p[0] & p[-1] & p[-width] & p [-width-1];
w22 = p[0] | p[-1] | p[-width] | p [-width-1];
if((b22 | (w22 ^ 1))&1) {
demerit += N2;
}
p++;
}
p++;
}
return demerit;
}
static int Mask_calcRunLength(int width, unsigned char *frame, int dir, int *runLength)
{
int head;
int i;
unsigned char *p;
int pitch;
pitch = (dir==0)?1:width;
if(frame[0] & 1) {
runLength[0] = -1;
head = 1;
} else {
head = 0;
}
runLength[head] = 1;
p = frame + pitch;
for(i=1; i<width; i++) {
if((p[0] ^ p[-pitch]) & 1) {
head++;
runLength[head] = 1;
} else {
runLength[head]++;
}
p += pitch;
}
return head + 1;
}
static int Mask_evaluateSymbol(int width, unsigned char *frame)
{
int x, y;
int demerit = 0;
int runLength[QRSPEC_WIDTH_MAX + 1];
int length;
demerit += Mask_calcN2(width, frame);
for(y=0; y<width; y++) {
length = Mask_calcRunLength(width, frame + y * width, 0, runLength);
demerit += Mask_calcN1N3(length, runLength);
}
for(x=0; x<width; x++) {
length = Mask_calcRunLength(width, frame + x, 1, runLength);
demerit += Mask_calcN1N3(length, runLength);
}
return demerit;
}
unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level)
{
int i;
unsigned char *mask, *bestMask;
int minDemerit = INT_MAX;
int blacks;
int bratio;
int demerit;
int w2 = width * width;
mask = (unsigned char *)malloc(w2);
if(mask == NULL) return NULL;
bestMask = NULL;
for(i=0; i<maskNum; i++) {
// n1 = n2 = n3 = n4 = 0;
demerit = 0;
blacks = maskMakers[i](width, frame, mask);
blacks += Mask_writeFormatInformation(width, mask, i, level);
bratio = (200 * blacks + w2) / w2 / 2; /* (int)(100*blacks/w2+0.5) */
demerit = (abs(bratio - 50) / 5) * N4;
// n4 = demerit;
demerit += Mask_evaluateSymbol(width, mask);
// printf("(%d,%d,%d,%d)=%d\n", n1, n2, n3 ,n4, demerit);
if(demerit < minDemerit) {
minDemerit = demerit;
free(bestMask);
bestMask = mask;
mask = (unsigned char *)malloc(w2);
if(mask == NULL) break;
}
}
free(mask);
return bestMask;
}

View file

@ -0,0 +1,37 @@
/*
* qrencode - QR Code encoder
*
* Masking.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __MASK_H__
#define __MASK_H__
extern unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask, QRecLevel level);
extern unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level);
#ifdef WITH_TESTS
extern int Mask_calcN2(int width, unsigned char *frame);
extern int Mask_calcN1N3(int length, int *runLength);
extern int Mask_calcRunLength(int width, unsigned char *frame, int dir, int *runLength);
extern int Mask_evaluateSymbol(int width, unsigned char *frame);
extern int Mask_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level);
extern unsigned char *Mask_makeMaskedFrame(int width, unsigned char *frame, int mask);
#endif
#endif /* __MASK_H__ */

View file

@ -0,0 +1,177 @@
/*
* qrencode - QR Code encoder
*
* Masking for Micro QR Code.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include "qrencode.h"
#include "mqrspec.h"
#include "mmask.h"
static void MMask_writeFormatInformation(int version, int width, unsigned char *frame, int mask, QRecLevel level)
{
unsigned int format;
unsigned char v;
int i;
format = MQRspec_getFormatInfo(mask, version, level);
for(i=0; i<8; i++) {
v = 0x84 | (format & 1);
frame[width * (i + 1) + 8] = v;
format = format >> 1;
}
for(i=0; i<7; i++) {
v = 0x84 | (format & 1);
frame[width * 8 + 7 - i] = v;
format = format >> 1;
}
}
#define MASKMAKER(__exp__) \
int x, y;\
\
for(y=0; y<width; y++) {\
for(x=0; x<width; x++) {\
if(*s & 0x80) {\
*d = *s;\
} else {\
*d = *s ^ ((__exp__) == 0);\
}\
s++; d++;\
}\
}
static void Mask_mask0(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER(y&1)
}
static void Mask_mask1(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER(((y/2)+(x/3))&1)
}
static void Mask_mask2(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER((((x*y)&1)+(x*y)%3)&1)
}
static void Mask_mask3(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER((((x+y)&1)+((x*y)%3))&1)
}
#define maskNum (4)
typedef void MaskMaker(int, const unsigned char *, unsigned char *);
static MaskMaker *maskMakers[maskNum] = {
Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3
};
#ifdef WITH_TESTS
unsigned char *MMask_makeMaskedFrame(int width, unsigned char *frame, int mask)
{
unsigned char *masked;
masked = (unsigned char *)malloc(width * width);
if(masked == NULL) return NULL;
maskMakers[mask](width, frame, masked);
return masked;
}
#endif
unsigned char *MMask_makeMask(int version, unsigned char *frame, int mask, QRecLevel level)
{
unsigned char *masked;
int width;
if(mask < 0 || mask >= maskNum) {
errno = EINVAL;
return NULL;
}
width = MQRspec_getWidth(version);
masked = (unsigned char *)malloc(width * width);
if(masked == NULL) return NULL;
maskMakers[mask](width, frame, masked);
MMask_writeFormatInformation(version, width, masked, mask, level);
return masked;
}
static int MMask_evaluateSymbol(int width, unsigned char *frame)
{
int x, y;
unsigned char *p;
int sum1 = 0, sum2 = 0;
p = frame + width * (width - 1);
for(x=1; x<width; x++) {
sum1 += (p[x] & 1);
}
p = frame + width * 2 - 1;
for(y=1; y<width; y++) {
sum2 += (*p & 1);
p += width;
}
return (sum1 <= sum2)?(sum1 * 16 + sum2):(sum2 * 16 + sum1);
}
unsigned char *MMask_mask(int version, unsigned char *frame, QRecLevel level)
{
int i;
unsigned char *mask, *bestMask;
int maxScore = 0;
int score;
int width;
width = MQRspec_getWidth(version);
mask = (unsigned char *)malloc(width * width);
if(mask == NULL) return NULL;
bestMask = NULL;
for(i=0; i<maskNum; i++) {
score = 0;
maskMakers[i](width, frame, mask);
MMask_writeFormatInformation(version, width, mask, i, level);
score = MMask_evaluateSymbol(width, mask);
if(score > maxScore) {
maxScore = score;
free(bestMask);
bestMask = mask;
mask = (unsigned char *)malloc(width * width);
if(mask == NULL) break;
}
}
free(mask);
return bestMask;
}

View file

@ -0,0 +1,34 @@
/*
* qrencode - QR Code encoder
*
* Masking for Micro QR Code.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __MMASK_H__
#define __MMASK_H__
extern unsigned char *MMask_makeMask(int version, unsigned char *frame, int mask, QRecLevel level);
extern unsigned char *MMask_mask(int version, unsigned char *frame, QRecLevel level);
#ifdef WITH_TESTS
extern int MMask_evaluateSymbol(int width, unsigned char *frame);
extern void MMask_writeFormatInformation(int version, int width, unsigned char *frame, int mask, QRecLevel level);
extern unsigned char *MMask_makeMaskedFrame(int width, unsigned char *frame, int mask);
#endif
#endif /* __MMASK_H__ */

View file

@ -0,0 +1,280 @@
/*
* qrencode - QR Code encoder
*
* Micor QR Code specification in convenient format.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* The following data / specifications are taken from
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
* or
* "Automatic identification and data capture techniques --
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_LIBPTHREAD
#include <pthread.h>
#endif
#include "mqrspec.h"
/******************************************************************************
* Version and capacity
*****************************************************************************/
typedef struct {
int width; //< Edge length of the symbol
int ec[4]; //< Number of ECC code (bytes)
} MQRspec_Capacity;
/**
* Table of the capacity of symbols
* See Table 1 (pp.106) and Table 8 (pp.113) of Appendix 1, JIS X0510:2004.
*/
static const MQRspec_Capacity mqrspecCapacity[MQRSPEC_VERSION_MAX + 1] = {
{ 0, {0, 0, 0, 0}},
{ 11, {2, 0, 0, 0}},
{ 13, {5, 6, 0, 0}},
{ 15, {6, 8, 0, 0}},
{ 17, {8, 10, 14, 0}}
};
int MQRspec_getDataLengthBit(int version, QRecLevel level)
{
int w;
int ecc;
w = mqrspecCapacity[version].width - 1;
ecc = mqrspecCapacity[version].ec[level];
if(ecc == 0) return 0;
return w * w - 64 - ecc * 8;
}
int MQRspec_getDataLength(int version, QRecLevel level)
{
return (MQRspec_getDataLengthBit(version, level) + 4) / 8;
}
int MQRspec_getECCLength(int version, QRecLevel level)
{
return mqrspecCapacity[version].ec[level];
}
int MQRspec_getWidth(int version)
{
return mqrspecCapacity[version].width;
}
/******************************************************************************
* Length indicator
*****************************************************************************/
/**
* See Table 3 (pp.107) of Appendix 1, JIS X0510:2004.
*/
static const int lengthTableBits[4][4] = {
{ 3, 4, 5, 6},
{ 0, 3, 4, 5},
{ 0, 0, 4, 5},
{ 0, 0, 3, 4}
};
int MQRspec_lengthIndicator(QRencodeMode mode, int version)
{
return lengthTableBits[mode][version - 1];
}
int MQRspec_maximumWords(QRencodeMode mode, int version)
{
int bits;
int words;
bits = lengthTableBits[mode][version - 1];
words = (1 << bits) - 1;
if(mode == QR_MODE_KANJI) {
words *= 2; // the number of bytes is required
}
return words;
}
/******************************************************************************
* Format information
*****************************************************************************/
/* See calcFormatInfo in tests/test_mqrspec.c */
static const unsigned int formatInfo[4][8] = {
{0x4445, 0x55ae, 0x6793, 0x7678, 0x06de, 0x1735, 0x2508, 0x34e3},
{0x4172, 0x5099, 0x62a4, 0x734f, 0x03e9, 0x1202, 0x203f, 0x31d4},
{0x4e2b, 0x5fc0, 0x6dfd, 0x7c16, 0x0cb0, 0x1d5b, 0x2f66, 0x3e8d},
{0x4b1c, 0x5af7, 0x68ca, 0x7921, 0x0987, 0x186c, 0x2a51, 0x3bba}
};
/* See Table 10 of Appendix 1. (pp.115) */
static const int typeTable[MQRSPEC_VERSION_MAX + 1][3] = {
{-1, -1, -1},
{ 0, -1, -1},
{ 1, 2, -1},
{ 3, 4, -1},
{ 5, 6, 7}
};
unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level)
{
int type;
if(mask < 0 || mask > 3) return 0;
if(version <= 0 || version > MQRSPEC_VERSION_MAX) return 0;
if(level == QR_ECLEVEL_H) return 0;
type = typeTable[version][level];
if(type < 0) return 0;
return formatInfo[mask][type];
}
/******************************************************************************
* Frame
*****************************************************************************/
/**
* Cache of initial frames.
*/
/* C99 says that static storage shall be initialized to a null pointer
* by compiler. */
static unsigned char *frames[MQRSPEC_VERSION_MAX + 1];
#ifdef HAVE_LIBPTHREAD
static pthread_mutex_t frames_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
/**
* Put a finder pattern.
* @param frame
* @param width
* @param ox,oy upper-left coordinate of the pattern
*/
static void putFinderPattern(unsigned char *frame, int width, int ox, int oy)
{
static const unsigned char finder[] = {
0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
};
int x, y;
const unsigned char *s;
frame += oy * width + ox;
s = finder;
for(y=0; y<7; y++) {
for(x=0; x<7; x++) {
frame[x] = s[x];
}
frame += width;
s += 7;
}
}
static unsigned char *MQRspec_createFrame(int version)
{
unsigned char *frame, *p, *q;
int width;
int x, y;
width = mqrspecCapacity[version].width;
frame = (unsigned char *)malloc(width * width);
if(frame == NULL) return NULL;
memset(frame, 0, width * width);
/* Finder pattern */
putFinderPattern(frame, width, 0, 0);
/* Separator */
p = frame;
for(y=0; y<7; y++) {
p[7] = 0xc0;
p += width;
}
memset(frame + width * 7, 0xc0, 8);
/* Mask format information area */
memset(frame + width * 8 + 1, 0x84, 8);
p = frame + width + 8;
for(y=0; y<7; y++) {
*p = 0x84;
p += width;
}
/* Timing pattern */
p = frame + 8;
q = frame + width * 8;
for(x=1; x<width-7; x++) {
*p = 0x90 | (x & 1);
*q = 0x90 | (x & 1);
p++;
q += width;
}
return frame;
}
unsigned char *MQRspec_newFrame(int version)
{
unsigned char *frame;
int width;
if(version < 1 || version > MQRSPEC_VERSION_MAX) return NULL;
#ifdef HAVE_LIBPTHREAD
pthread_mutex_lock(&frames_mutex);
#endif
if(frames[version] == NULL) {
frames[version] = MQRspec_createFrame(version);
}
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&frames_mutex);
#endif
if(frames[version] == NULL) return NULL;
width = mqrspecCapacity[version].width;
frame = (unsigned char *)malloc(width * width);
if(frame == NULL) return NULL;
memcpy(frame, frames[version], width * width);
return frame;
}
void MQRspec_clearCache(void)
{
int i;
#ifdef HAVE_LIBPTHREAD
pthread_mutex_lock(&frames_mutex);
#endif
for(i=1; i<=MQRSPEC_VERSION_MAX; i++) {
free(frames[i]);
frames[i] = NULL;
}
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&frames_mutex);
#endif
}

View file

@ -0,0 +1,157 @@
/*
* qrencode - QR Code encoder
*
* Micro QR Code specification in convenient format.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __MQRSPEC_H__
#define __MQRSPEC_H__
#include "qrencode.h"
/******************************************************************************
* Version and capacity
*****************************************************************************/
/**
* Maximum width of a symbol
*/
#define MQRSPEC_WIDTH_MAX 17
/**
* Return maximum data code length (bits) for the version.
* @param version
* @param level
* @return maximum size (bits)
*/
extern int MQRspec_getDataLengthBit(int version, QRecLevel level);
/**
* Return maximum data code length (bytes) for the version.
* @param version
* @param level
* @return maximum size (bytes)
*/
extern int MQRspec_getDataLength(int version, QRecLevel level);
/**
* Return maximum error correction code length (bytes) for the version.
* @param version
* @param level
* @return ECC size (bytes)
*/
extern int MQRspec_getECCLength(int version, QRecLevel level);
/**
* Return a version number that satisfies the input code length.
* @param size input code length (byte)
* @param level
* @return version number
*/
extern int MQRspec_getMinimumVersion(int size, QRecLevel level);
/**
* Return the width of the symbol for the version.
* @param version
* @return width
*/
extern int MQRspec_getWidth(int version);
/**
* Return the numer of remainder bits.
* @param version
* @return number of remainder bits
*/
extern int MQRspec_getRemainder(int version);
/******************************************************************************
* Length indicator
*****************************************************************************/
/**
* Return the size of lenght indicator for the mode and version.
* @param mode
* @param version
* @return the size of the appropriate length indicator (bits).
*/
extern int MQRspec_lengthIndicator(QRencodeMode mode, int version);
/**
* Return the maximum length for the mode and version.
* @param mode
* @param version
* @return the maximum length (bytes)
*/
extern int MQRspec_maximumWords(QRencodeMode mode, int version);
/******************************************************************************
* Version information pattern
*****************************************************************************/
/**
* Return BCH encoded version information pattern that is used for the symbol
* of version 7 or greater. Use lower 18 bits.
* @param version
* @return BCH encoded version information pattern
*/
extern unsigned int MQRspec_getVersionPattern(int version);
/******************************************************************************
* Format information
*****************************************************************************/
/**
* Return BCH encoded format information pattern.
* @param mask
* @param version
* @param level
* @return BCH encoded format information pattern
*/
extern unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level);
/******************************************************************************
* Frame
*****************************************************************************/
/**
* Return a copy of initialized frame.
* When the same version is requested twice or more, a copy of cached frame
* is returned.
* @param version
* @return Array of unsigned char. You can free it by free().
*/
extern unsigned char *MQRspec_newFrame(int version);
/**
* Clear the frame cache. Typically for debug.
*/
extern void MQRspec_clearCache(void);
/******************************************************************************
* Mode indicator
*****************************************************************************/
/**
* Mode indicator. See Table 2 in Appendix 1 of JIS X0510:2004, pp.107.
*/
#define MQRSPEC_MODEID_NUM 0
#define MQRSPEC_MODEID_AN 1
#define MQRSPEC_MODEID_8 2
#define MQRSPEC_MODEID_KANJI 3
#endif /* __MQRSPEC_H__ */

View file

@ -0,0 +1,929 @@
/*
* qrencode - QR Code encoder
*
* Copyright (C) 2006-2012 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "qrencode.h"
#include "qrspec.h"
#include "mqrspec.h"
#include "bitstream.h"
#include "qrinput.h"
#include "rscode.h"
#include "split.h"
#include "mask.h"
#include "mmask.h"
/******************************************************************************
* Raw code
*****************************************************************************/
typedef struct {
int dataLength;
unsigned char *data;
int eccLength;
unsigned char *ecc;
} RSblock;
typedef struct {
int version;
int dataLength;
int eccLength;
unsigned char *datacode;
unsigned char *ecccode;
int b1;
int blocks;
RSblock *rsblock;
int count;
} QRRawCode;
static void RSblock_initBlock(RSblock *block, int dl, unsigned char *data, int el, unsigned char *ecc, RS *rs)
{
block->dataLength = dl;
block->data = data;
block->eccLength = el;
block->ecc = ecc;
encode_rs_char(rs, data, ecc);
}
static int RSblock_init(RSblock *blocks, int spec[5], unsigned char *data, unsigned char *ecc)
{
int i;
RSblock *block;
unsigned char *dp, *ep;
RS *rs;
int el, dl;
dl = QRspec_rsDataCodes1(spec);
el = QRspec_rsEccCodes1(spec);
rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el);
if(rs == NULL) return -1;
block = blocks;
dp = data;
ep = ecc;
for(i=0; i<QRspec_rsBlockNum1(spec); i++) {
RSblock_initBlock(block, dl, dp, el, ep, rs);
dp += dl;
ep += el;
block++;
}
if(QRspec_rsBlockNum2(spec) == 0) return 0;
dl = QRspec_rsDataCodes2(spec);
el = QRspec_rsEccCodes2(spec);
rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el);
if(rs == NULL) return -1;
for(i=0; i<QRspec_rsBlockNum2(spec); i++) {
RSblock_initBlock(block, dl, dp, el, ep, rs);
dp += dl;
ep += el;
block++;
}
return 0;
}
static void QRraw_free(QRRawCode *raw);
static QRRawCode *QRraw_new(QRinput *input)
{
QRRawCode *raw;
int spec[5], ret;
raw = (QRRawCode *)malloc(sizeof(QRRawCode));
if(raw == NULL) return NULL;
raw->datacode = QRinput_getByteStream(input);
if(raw->datacode == NULL) {
free(raw);
return NULL;
}
QRspec_getEccSpec(input->version, input->level, spec);
raw->version = input->version;
raw->b1 = QRspec_rsBlockNum1(spec);
raw->dataLength = QRspec_rsDataLength(spec);
raw->eccLength = QRspec_rsEccLength(spec);
raw->ecccode = (unsigned char *)malloc(raw->eccLength);
if(raw->ecccode == NULL) {
free(raw->datacode);
free(raw);
return NULL;
}
raw->blocks = QRspec_rsBlockNum(spec);
raw->rsblock = (RSblock *)calloc(raw->blocks, sizeof(RSblock));
if(raw->rsblock == NULL) {
QRraw_free(raw);
return NULL;
}
ret = RSblock_init(raw->rsblock, spec, raw->datacode, raw->ecccode);
if(ret < 0) {
QRraw_free(raw);
return NULL;
}
raw->count = 0;
return raw;
}
/**
* Return a code (byte).
* This function can be called iteratively.
* @param raw raw code.
* @return code
*/
static unsigned char QRraw_getCode(QRRawCode *raw)
{
int col, row;
unsigned char ret;
if(raw->count < raw->dataLength) {
row = raw->count % raw->blocks;
col = raw->count / raw->blocks;
if(col >= raw->rsblock[0].dataLength) {
row += raw->b1;
}
ret = raw->rsblock[row].data[col];
} else if(raw->count < raw->dataLength + raw->eccLength) {
row = (raw->count - raw->dataLength) % raw->blocks;
col = (raw->count - raw->dataLength) / raw->blocks;
ret = raw->rsblock[row].ecc[col];
} else {
return 0;
}
raw->count++;
return ret;
}
static void QRraw_free(QRRawCode *raw)
{
if(raw != NULL) {
free(raw->datacode);
free(raw->ecccode);
free(raw->rsblock);
free(raw);
}
}
/******************************************************************************
* Raw code for Micro QR Code
*****************************************************************************/
typedef struct {
int version;
int dataLength;
int eccLength;
unsigned char *datacode;
unsigned char *ecccode;
RSblock *rsblock;
int oddbits;
int count;
} MQRRawCode;
static void MQRraw_free(MQRRawCode *raw);
static MQRRawCode *MQRraw_new(QRinput *input)
{
MQRRawCode *raw;
RS *rs;
raw = (MQRRawCode *)malloc(sizeof(MQRRawCode));
if(raw == NULL) return NULL;
raw->version = input->version;
raw->dataLength = MQRspec_getDataLength(input->version, input->level);
raw->eccLength = MQRspec_getECCLength(input->version, input->level);
raw->oddbits = raw->dataLength * 8 - MQRspec_getDataLengthBit(input->version, input->level);
raw->datacode = QRinput_getByteStream(input);
if(raw->datacode == NULL) {
free(raw);
return NULL;
}
raw->ecccode = (unsigned char *)malloc(raw->eccLength);
if(raw->ecccode == NULL) {
free(raw->datacode);
free(raw);
return NULL;
}
raw->rsblock = (RSblock *)calloc(1, sizeof(RSblock));
if(raw->rsblock == NULL) {
MQRraw_free(raw);
return NULL;
}
rs = init_rs(8, 0x11d, 0, 1, raw->eccLength, 255 - raw->dataLength - raw->eccLength);
if(rs == NULL) {
MQRraw_free(raw);
return NULL;
}
RSblock_initBlock(raw->rsblock, raw->dataLength, raw->datacode, raw->eccLength, raw->ecccode, rs);
raw->count = 0;
return raw;
}
/**
* Return a code (byte).
* This function can be called iteratively.
* @param raw raw code.
* @return code
*/
static unsigned char MQRraw_getCode(MQRRawCode *raw)
{
unsigned char ret;
if(raw->count < raw->dataLength) {
ret = raw->datacode[raw->count];
} else if(raw->count < raw->dataLength + raw->eccLength) {
ret = raw->ecccode[raw->count - raw->dataLength];
} else {
return 0;
}
raw->count++;
return ret;
}
static void MQRraw_free(MQRRawCode *raw)
{
if(raw != NULL) {
free(raw->datacode);
free(raw->ecccode);
free(raw->rsblock);
free(raw);
}
}
/******************************************************************************
* Frame filling
*****************************************************************************/
typedef struct {
int width;
unsigned char *frame;
int x, y;
int dir;
int bit;
int mqr;
} FrameFiller;
static FrameFiller *FrameFiller_new(int width, unsigned char *frame, int mqr)
{
FrameFiller *filler;
filler = (FrameFiller *)malloc(sizeof(FrameFiller));
if(filler == NULL) return NULL;
filler->width = width;
filler->frame = frame;
filler->x = width - 1;
filler->y = width - 1;
filler->dir = -1;
filler->bit = -1;
filler->mqr = mqr;
return filler;
}
static unsigned char *FrameFiller_next(FrameFiller *filler)
{
unsigned char *p;
int x, y, w;
if(filler->bit == -1) {
filler->bit = 0;
return filler->frame + filler->y * filler->width + filler->x;
}
x = filler->x;
y = filler->y;
p = filler->frame;
w = filler->width;
if(filler->bit == 0) {
x--;
filler->bit++;
} else {
x++;
y += filler->dir;
filler->bit--;
}
if(filler->dir < 0) {
if(y < 0) {
y = 0;
x -= 2;
filler->dir = 1;
if(!filler->mqr && x == 6) {
x--;
y = 9;
}
}
} else {
if(y == w) {
y = w - 1;
x -= 2;
filler->dir = -1;
if(!filler->mqr && x == 6) {
x--;
y -= 8;
}
}
}
if(x < 0 || y < 0) return NULL;
filler->x = x;
filler->y = y;
if(p[y * w + x] & 0x80) {
// This tail recursion could be optimized.
return FrameFiller_next(filler);
}
return &p[y * w + x];
}
#ifdef WITH_TESTS
extern unsigned char *FrameFiller_test(int version)
{
int width;
unsigned char *frame, *p;
FrameFiller *filler;
int i, length;
width = QRspec_getWidth(version);
frame = QRspec_newFrame(version);
if(frame == NULL) return NULL;
filler = FrameFiller_new(width, frame, 0);
if(filler == NULL) {
free(frame);
return NULL;
}
length = QRspec_getDataLength(version, QR_ECLEVEL_L) * 8
+ QRspec_getECCLength(version, QR_ECLEVEL_L) * 8
+ QRspec_getRemainder(version);
for(i=0; i<length; i++) {
p = FrameFiller_next(filler);
if(p == NULL) {
free(filler);
free(frame);
return NULL;
}
*p = (unsigned char)(i & 0x7f) | 0x80;
}
free(filler);
return frame;
}
extern unsigned char *FrameFiller_testMQR(int version)
{
int width;
unsigned char *frame, *p;
FrameFiller *filler;
int i, length;
width = MQRspec_getWidth(version);
frame = MQRspec_newFrame(version);
if(frame == NULL) return NULL;
filler = FrameFiller_new(width, frame, 1);
if(filler == NULL) {
free(frame);
return NULL;
}
length = MQRspec_getDataLengthBit(version, QR_ECLEVEL_L)
+ MQRspec_getECCLength(version, QR_ECLEVEL_L) * 8;
for(i=0; i<length; i++) {
p = FrameFiller_next(filler);
if(p == NULL) {
fprintf(stderr, "Frame filler run over the frame!\n");
free(filler);
return frame;
}
*p = (unsigned char)(i & 0x7f) | 0x80;
}
free(filler);
return frame;
}
#endif
/******************************************************************************
* QR-code encoding
*****************************************************************************/
static QRcode *QRcode_new(int version, int width, unsigned char *data)
{
QRcode *qrcode;
qrcode = (QRcode *)malloc(sizeof(QRcode));
if(qrcode == NULL) return NULL;
qrcode->version = version;
qrcode->width = width;
qrcode->data = data;
return qrcode;
}
void QRcode_free(QRcode *qrcode)
{
if(qrcode != NULL) {
free(qrcode->data);
free(qrcode);
}
}
static QRcode *QRcode_encodeMask(QRinput *input, int mask)
{
int width, version;
QRRawCode *raw;
unsigned char *frame, *masked, *p, code, bit;
FrameFiller *filler;
int i, j;
QRcode *qrcode = NULL;
if(input->mqr) {
errno = EINVAL;
return NULL;
}
if(input->version < 0 || input->version > QRSPEC_VERSION_MAX) {
errno = EINVAL;
return NULL;
}
if(input->level > QR_ECLEVEL_H) {
errno = EINVAL;
return NULL;
}
raw = QRraw_new(input);
if(raw == NULL) return NULL;
version = raw->version;
width = QRspec_getWidth(version);
frame = QRspec_newFrame(version);
if(frame == NULL) {
QRraw_free(raw);
return NULL;
}
filler = FrameFiller_new(width, frame, 0);
if(filler == NULL) {
QRraw_free(raw);
free(frame);
return NULL;
}
/* inteleaved data and ecc codes */
for(i=0; i<raw->dataLength + raw->eccLength; i++) {
code = QRraw_getCode(raw);
bit = 0x80;
for(j=0; j<8; j++) {
p = FrameFiller_next(filler);
if(p == NULL) goto EXIT;
*p = 0x02 | ((bit & code) != 0);
bit = bit >> 1;
}
}
QRraw_free(raw);
raw = NULL;
/* remainder bits */
j = QRspec_getRemainder(version);
for(i=0; i<j; i++) {
p = FrameFiller_next(filler);
if(p == NULL) goto EXIT;
*p = 0x02;
}
/* masking */
if(mask == -2) { // just for debug purpose
masked = (unsigned char *)malloc(width * width);
memcpy(masked, frame, width * width);
} else if(mask < 0) {
masked = Mask_mask(width, frame, input->level);
} else {
masked = Mask_makeMask(width, frame, mask, input->level);
}
if(masked == NULL) {
goto EXIT;
}
qrcode = QRcode_new(version, width, masked);
EXIT:
QRraw_free(raw);
free(filler);
free(frame);
return qrcode;
}
static QRcode *QRcode_encodeMaskMQR(QRinput *input, int mask)
{
int width, version;
MQRRawCode *raw;
unsigned char *frame, *masked, *p, code, bit;
FrameFiller *filler;
int i, j;
QRcode *qrcode = NULL;
if(!input->mqr) {
errno = EINVAL;
return NULL;
}
if(input->version <= 0 || input->version > MQRSPEC_VERSION_MAX) {
errno = EINVAL;
return NULL;
}
if(input->level > QR_ECLEVEL_Q) {
errno = EINVAL;
return NULL;
}
raw = MQRraw_new(input);
if(raw == NULL) return NULL;
version = raw->version;
width = MQRspec_getWidth(version);
frame = MQRspec_newFrame(version);
if(frame == NULL) {
MQRraw_free(raw);
return NULL;
}
filler = FrameFiller_new(width, frame, 1);
if(filler == NULL) {
MQRraw_free(raw);
free(frame);
return NULL;
}
/* inteleaved data and ecc codes */
for(i=0; i<raw->dataLength + raw->eccLength; i++) {
code = MQRraw_getCode(raw);
if(raw->oddbits && i == raw->dataLength - 1) {
bit = 1 << (raw->oddbits - 1);
for(j=0; j<raw->oddbits; j++) {
p = FrameFiller_next(filler);
if(p == NULL) goto EXIT;
*p = 0x02 | ((bit & code) != 0);
bit = bit >> 1;
}
} else {
bit = 0x80;
for(j=0; j<8; j++) {
p = FrameFiller_next(filler);
if(p == NULL) goto EXIT;
*p = 0x02 | ((bit & code) != 0);
bit = bit >> 1;
}
}
}
MQRraw_free(raw);
raw = NULL;
/* masking */
if(mask < 0) {
masked = MMask_mask(version, frame, input->level);
} else {
masked = MMask_makeMask(version, frame, mask, input->level);
}
if(masked == NULL) {
goto EXIT;
}
qrcode = QRcode_new(version, width, masked);
EXIT:
MQRraw_free(raw);
free(filler);
free(frame);
return qrcode;
}
QRcode *QRcode_encodeInput(QRinput *input)
{
if(input->mqr) {
return QRcode_encodeMaskMQR(input, -1);
} else {
return QRcode_encodeMask(input, -1);
}
}
static QRcode *QRcode_encodeStringReal(const char *string, int version, QRecLevel level, int mqr, QRencodeMode hint, int casesensitive)
{
QRinput *input;
QRcode *code;
int ret;
if(string == NULL) {
errno = EINVAL;
return NULL;
}
if(hint != QR_MODE_8 && hint != QR_MODE_KANJI) {
errno = EINVAL;
return NULL;
}
if(mqr) {
input = QRinput_newMQR(version, level);
} else {
input = QRinput_new2(version, level);
}
if(input == NULL) return NULL;
ret = Split_splitStringToQRinput(string, input, hint, casesensitive);
if(ret < 0) {
QRinput_free(input);
return NULL;
}
code = QRcode_encodeInput(input);
QRinput_free(input);
return code;
}
QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive)
{
return QRcode_encodeStringReal(string, version, level, 0, hint, casesensitive);
}
QRcode *QRcode_encodeStringMQR(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive)
{
return QRcode_encodeStringReal(string, version, level, 1, hint, casesensitive);
}
static QRcode *QRcode_encodeDataReal(const unsigned char *data, int length, int version, QRecLevel level, int mqr)
{
QRinput *input;
QRcode *code;
int ret;
if(data == NULL || length == 0) {
errno = EINVAL;
return NULL;
}
if(mqr) {
input = QRinput_newMQR(version, level);
} else {
input = QRinput_new2(version, level);
}
if(input == NULL) return NULL;
ret = QRinput_append(input, QR_MODE_8, length, data);
if(ret < 0) {
QRinput_free(input);
return NULL;
}
code = QRcode_encodeInput(input);
QRinput_free(input);
return code;
}
QRcode *QRcode_encodeData(int size, const unsigned char *data, int version, QRecLevel level)
{
return QRcode_encodeDataReal(data, size, version, level, 0);
}
QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level)
{
if(string == NULL) {
errno = EINVAL;
return NULL;
}
return QRcode_encodeDataReal((unsigned char *)string, strlen(string), version, level, 0);
}
QRcode *QRcode_encodeDataMQR(int size, const unsigned char *data, int version, QRecLevel level)
{
return QRcode_encodeDataReal(data, size, version, level, 1);
}
QRcode *QRcode_encodeString8bitMQR(const char *string, int version, QRecLevel level)
{
if(string == NULL) {
errno = EINVAL;
return NULL;
}
return QRcode_encodeDataReal((unsigned char *)string, strlen(string), version, level, 1);
}
/******************************************************************************
* Structured QR-code encoding
*****************************************************************************/
static QRcode_List *QRcode_List_newEntry(void)
{
QRcode_List *entry;
entry = (QRcode_List *)malloc(sizeof(QRcode_List));
if(entry == NULL) return NULL;
entry->next = NULL;
entry->code = NULL;
return entry;
}
static void QRcode_List_freeEntry(QRcode_List *entry)
{
if(entry != NULL) {
QRcode_free(entry->code);
free(entry);
}
}
void QRcode_List_free(QRcode_List *qrlist)
{
QRcode_List *list = qrlist, *next;
while(list != NULL) {
next = list->next;
QRcode_List_freeEntry(list);
list = next;
}
}
int QRcode_List_size(QRcode_List *qrlist)
{
QRcode_List *list = qrlist;
int size = 0;
while(list != NULL) {
size++;
list = list->next;
}
return size;
}
#if 0
static unsigned char QRcode_parity(const char *str, int size)
{
unsigned char parity = 0;
int i;
for(i=0; i<size; i++) {
parity ^= str[i];
}
return parity;
}
#endif
QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s)
{
QRcode_List *head = NULL;
QRcode_List *tail = NULL;
QRcode_List *entry;
QRinput_InputList *list = s->head;
while(list != NULL) {
if(head == NULL) {
entry = QRcode_List_newEntry();
if(entry == NULL) goto ABORT;
head = entry;
tail = head;
} else {
entry = QRcode_List_newEntry();
if(entry == NULL) goto ABORT;
tail->next = entry;
tail = tail->next;
}
tail->code = QRcode_encodeInput(list->input);
if(tail->code == NULL) {
goto ABORT;
}
list = list->next;
}
return head;
ABORT:
QRcode_List_free(head);
return NULL;
}
static QRcode_List *QRcode_encodeInputToStructured(QRinput *input)
{
QRinput_Struct *s;
QRcode_List *codes;
s = QRinput_splitQRinputToStruct(input);
if(s == NULL) return NULL;
codes = QRcode_encodeInputStructured(s);
QRinput_Struct_free(s);
return codes;
}
static QRcode_List *QRcode_encodeDataStructuredReal(
int size, const unsigned char *data,
int version, QRecLevel level,
int eightbit, QRencodeMode hint, int casesensitive)
{
QRinput *input;
QRcode_List *codes;
int ret;
if(version <= 0) {
errno = EINVAL;
return NULL;
}
if(!eightbit && (hint != QR_MODE_8 && hint != QR_MODE_KANJI)) {
errno = EINVAL;
return NULL;
}
input = QRinput_new2(version, level);
if(input == NULL) return NULL;
if(eightbit) {
ret = QRinput_append(input, QR_MODE_8, size, data);
} else {
ret = Split_splitStringToQRinput((char *)data, input, hint, casesensitive);
}
if(ret < 0) {
QRinput_free(input);
return NULL;
}
codes = QRcode_encodeInputToStructured(input);
QRinput_free(input);
return codes;
}
QRcode_List *QRcode_encodeDataStructured(int size, const unsigned char *data, int version, QRecLevel level) {
return QRcode_encodeDataStructuredReal(size, data, version, level, 1, QR_MODE_NUL, 0);
}
QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level) {
if(string == NULL) {
errno = EINVAL;
return NULL;
}
return QRcode_encodeDataStructured(strlen(string), (unsigned char *)string, version, level);
}
QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive)
{
if(string == NULL) {
errno = EINVAL;
return NULL;
}
return QRcode_encodeDataStructuredReal(strlen(string), (unsigned char *)string, version, level, 0, hint, casesensitive);
}
/******************************************************************************
* System utilities
*****************************************************************************/
void QRcode_APIVersion(int *major_version, int *minor_version, int *micro_version)
{
if(major_version != NULL) {
*major_version = 3;
}
if(minor_version != NULL) {
*minor_version = 4;
}
if(micro_version != NULL) {
*micro_version = 3;
}
}
char *QRcode_APIVersionString(void)
{
return "3.4.3";
}
void QRcode_clearCache(void)
{
QRspec_clearCache();
MQRspec_clearCache();
free_rs_cache();
}

View file

@ -0,0 +1,566 @@
/**
* qrencode - QR Code encoder
*
* Copyright (C) 2006-2012 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** \mainpage
* Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D
* symbology.
*
* \section encoding Encoding
*
* There are two methods to encode data: <b>encoding a string/data</b> or
* <b>encoding a structured data</b>.
*
* \subsection encoding-string Encoding a string/data
* You can encode a string by calling QRcode_encodeString().
* The given string is parsed automatically and encoded. If you want to encode
* data that can be represented as a C string style (NUL terminated), you can
* simply use this way.
*
* If the input data contains Kanji (Shift-JIS) characters and you want to
* encode them as Kanji in QR Code, you should give QR_MODE_KANJI as a hint.
* Otherwise, all of non-alphanumeric characters are encoded as 8 bit data.
* If you want to encode a whole string in 8 bit mode, you can use
* QRcode_encodeString8bit() instead.
*
* Please note that a C string can not contain NUL characters. If your data
* contains NUL, you must use QRcode_encodeData().
*
* \subsection encoding-input Encoding a structured data
* You can construct a structured input data manually. If the structure of the
* input data is known, you can use this way.
* At first, create a ::QRinput object by QRinput_new(). Then add input data
* to the QRinput object by QRinput_append(). Finally call QRcode_encodeInput()
* to encode the QRinput data.
* You can reuse the QRinput data again to encode it in other symbols with
* different parameters.
*
* \section result Result
* The encoded symbol is resulted as a ::QRcode object. It will contain
* its version number, width of the symbol and an array represents the symbol.
* See ::QRcode for the details. You can free the object by QRcode_free().
*
* Please note that the version of the result may be larger than specified.
* In such cases, the input data would be too large to be encoded in a
* symbol of the specified version.
*
* \section structured Structured append
* Libqrencode can generate "Structured-appended" symbols that enables to split
* a large data set into mulitple QR codes. A QR code reader concatenates
* multiple QR code symbols into a string.
* Just like QRcode_encodeString(), you can use QRcode_encodeStringStructured()
* to generate structured-appended symbols. This functions returns an instance
* of ::QRcode_List. The returned list is a singly-linked list of QRcode: you
* can retrieve each QR code in this way:
*
* \code
* QRcode_List *qrcodes;
* QRcode_List *entry;
* QRcode *qrcode;
*
* qrcodes = QRcode_encodeStringStructured(...);
* entry = qrcodes;
* while(entry != NULL) {
* qrcode = entry->code;
* // do something
* entry = entry->next;
* }
* QRcode_List_free(entry);
* \endcode
*
* Instead of using auto-parsing functions, you can construct your own
* structured input. At first, instantiate an object of ::QRinput_Struct
* by calling QRinput_Struct_new(). This object can hold multiple ::QRinput,
* and one QR code is generated for a ::QRinput.
* QRinput_Struct_appendInput() appends a ::QRinput to a ::QRinput_Struct
* object. In order to generate structured-appended symbols, it is required to
* embed headers to each symbol. You can use
* QRinput_Struct_insertStructuredAppendHeaders() to insert appropriate
* headers to each symbol. You should call this function just once before
* encoding symbols.
*/
#ifndef __QRENCODE_H__
#define __QRENCODE_H__
#if defined(__cplusplus)
extern "C" {
#endif
/**
* Encoding mode.
*/
typedef enum {
QR_MODE_NUL = -1, ///< Terminator (NUL character). Internal use only
QR_MODE_NUM = 0, ///< Numeric mode
QR_MODE_AN, ///< Alphabet-numeric mode
QR_MODE_8, ///< 8-bit data mode
QR_MODE_KANJI, ///< Kanji (shift-jis) mode
QR_MODE_STRUCTURE, ///< Internal use only
QR_MODE_ECI, ///< ECI mode
QR_MODE_FNC1FIRST, ///< FNC1, first position
QR_MODE_FNC1SECOND, ///< FNC1, second position
} QRencodeMode;
/**
* Level of error correction.
*/
typedef enum {
QR_ECLEVEL_L = 0, ///< lowest
QR_ECLEVEL_M,
QR_ECLEVEL_Q,
QR_ECLEVEL_H ///< highest
} QRecLevel;
/**
* Maximum version (size) of QR-code symbol.
*/
#define QRSPEC_VERSION_MAX 40
/**
* Maximum version (size) of QR-code symbol.
*/
#define MQRSPEC_VERSION_MAX 4
/******************************************************************************
* Input data (qrinput.c)
*****************************************************************************/
/**
* Singly linked list to contain input strings. An instance of this class
* contains its version and error correction level too. It is required to
* set them by QRinput_setVersion() and QRinput_setErrorCorrectionLevel(),
* or use QRinput_new2() to instantiate an object.
*/
typedef struct _QRinput QRinput;
/**
* Instantiate an input data object. The version is set to 0 (auto-select)
* and the error correction level is set to QR_ECLEVEL_L.
* @return an input object (initialized). On error, NULL is returned and errno
* is set to indicate the error.
* @throw ENOMEM unable to allocate memory.
*/
extern QRinput *QRinput_new(void);
/**
* Instantiate an input data object.
* @param version version number.
* @param level Error correction level.
* @return an input object (initialized). On error, NULL is returned and errno
* is set to indicate the error.
* @throw ENOMEM unable to allocate memory for input objects.
* @throw EINVAL invalid arguments.
*/
extern QRinput *QRinput_new2(int version, QRecLevel level);
/**
* Instantiate an input data object. Object's Micro QR Code flag is set.
* Unlike with full-sized QR Code, version number must be specified (>0).
* @param version version number (1--4).
* @param level Error correction level.
* @return an input object (initialized). On error, NULL is returned and errno
* is set to indicate the error.
* @throw ENOMEM unable to allocate memory for input objects.
* @throw EINVAL invalid arguments.
*/
extern QRinput *QRinput_newMQR(int version, QRecLevel level);
/**
* Append data to an input object.
* The data is copied and appended to the input object.
* @param input input object.
* @param mode encoding mode.
* @param size size of data (byte).
* @param data a pointer to the memory area of the input data.
* @retval 0 success.
* @retval -1 an error occurred and errno is set to indeicate the error.
* See Execptions for the details.
* @throw ENOMEM unable to allocate memory.
* @throw EINVAL input data is invalid.
*
*/
extern int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data);
/**
* Append ECI header.
* @param input input object.
* @param ecinum ECI indicator number (0 - 999999)
* @retval 0 success.
* @retval -1 an error occurred and errno is set to indeicate the error.
* See Execptions for the details.
* @throw ENOMEM unable to allocate memory.
* @throw EINVAL input data is invalid.
*
*/
extern int QRinput_appendECIheader(QRinput *input, unsigned int ecinum);
/**
* Get current version.
* @param input input object.
* @return current version.
*/
extern int QRinput_getVersion(QRinput *input);
/**
* Set version of the QR code that is to be encoded.
* This function cannot be applied to Micro QR Code.
* @param input input object.
* @param version version number (0 = auto)
* @retval 0 success.
* @retval -1 invalid argument.
*/
extern int QRinput_setVersion(QRinput *input, int version);
/**
* Get current error correction level.
* @param input input object.
* @return Current error correcntion level.
*/
extern QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input);
/**
* Set error correction level of the QR code that is to be encoded.
* This function cannot be applied to Micro QR Code.
* @param input input object.
* @param level Error correction level.
* @retval 0 success.
* @retval -1 invalid argument.
*/
extern int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level);
/**
* Set version and error correction level of the QR code at once.
* This function is recommened for Micro QR Code.
* @param input input object.
* @param version version number (0 = auto)
* @param level Error correction level.
* @retval 0 success.
* @retval -1 invalid argument.
*/
extern int QRinput_setVersionAndErrorCorrectionLevel(QRinput *input, int version, QRecLevel level);
/**
* Free the input object.
* All of data chunks in the input object are freed too.
* @param input input object.
*/
extern void QRinput_free(QRinput *input);
/**
* Validate the input data.
* @param mode encoding mode.
* @param size size of data (byte).
* @param data a pointer to the memory area of the input data.
* @retval 0 success.
* @retval -1 invalid arguments.
*/
extern int QRinput_check(QRencodeMode mode, int size, const unsigned char *data);
/**
* Set of QRinput for structured symbols.
*/
typedef struct _QRinput_Struct QRinput_Struct;
/**
* Instantiate a set of input data object.
* @return an instance of QRinput_Struct. On error, NULL is returned and errno
* is set to indicate the error.
* @throw ENOMEM unable to allocate memory.
*/
extern QRinput_Struct *QRinput_Struct_new(void);
/**
* Set parity of structured symbols.
* @param s structured input object.
* @param parity parity of s.
*/
extern void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity);
/**
* Append a QRinput object to the set. QRinput created by QRinput_newMQR()
* will be rejected.
* @warning never append the same QRinput object twice or more.
* @param s structured input object.
* @param input an input object.
* @retval >0 number of input objects in the structure.
* @retval -1 an error occurred. See Exceptions for the details.
* @throw ENOMEM unable to allocate memory.
* @throw EINVAL invalid arguments.
*/
extern int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input);
/**
* Free all of QRinput in the set.
* @param s a structured input object.
*/
extern void QRinput_Struct_free(QRinput_Struct *s);
/**
* Split a QRinput to QRinput_Struct. It calculates a parity, set it, then
* insert structured-append headers. QRinput created by QRinput_newMQR() will
* be rejected.
* @param input input object. Version number and error correction level must be
* set.
* @return a set of input data. On error, NULL is returned, and errno is set
* to indicate the error. See Exceptions for the details.
* @throw ERANGE input data is too large.
* @throw EINVAL invalid input data.
* @throw ENOMEM unable to allocate memory.
*/
extern QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input);
/**
* Insert structured-append headers to the input structure. It calculates
* a parity and set it if the parity is not set yet.
* @param s input structure
* @retval 0 success.
* @retval -1 an error occurred and errno is set to indeicate the error.
* See Execptions for the details.
* @throw EINVAL invalid input object.
* @throw ENOMEM unable to allocate memory.
*/
extern int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s);
/**
* Set FNC1-1st position flag.
*/
extern int QRinput_setFNC1First(QRinput *input);
/**
* Set FNC1-2nd position flag and application identifier.
*/
extern int QRinput_setFNC1Second(QRinput *input, unsigned char appid);
/******************************************************************************
* QRcode output (qrencode.c)
*****************************************************************************/
/**
* QRcode class.
* Symbol data is represented as an array contains width*width uchars.
* Each uchar represents a module (dot). If the less significant bit of
* the uchar is 1, the corresponding module is black. The other bits are
* meaningless for usual applications, but here its specification is described.
*
* <pre>
* MSB 76543210 LSB
* |||||||`- 1=black/0=white
* ||||||`-- data and ecc code area
* |||||`--- format information
* ||||`---- version information
* |||`----- timing pattern
* ||`------ alignment pattern
* |`------- finder pattern and separator
* `-------- non-data modules (format, timing, etc.)
* </pre>
*/
typedef struct {
int version; ///< version of the symbol
int width; ///< width of the symbol
unsigned char *data; ///< symbol data
} QRcode;
/**
* Singly-linked list of QRcode. Used to represent a structured symbols.
* A list is terminated with NULL.
*/
typedef struct _QRcode_List {
QRcode *code;
struct _QRcode_List *next;
} QRcode_List;
/**
* Create a symbol from the input data.
* @warning This function is THREAD UNSAFE when pthread is disabled.
* @param input input data.
* @return an instance of QRcode class. The version of the result QRcode may
* be larger than the designated version. On error, NULL is returned,
* and errno is set to indicate the error. See Exceptions for the
* details.
* @throw EINVAL invalid input object.
* @throw ENOMEM unable to allocate memory for input objects.
*/
extern QRcode *QRcode_encodeInput(QRinput *input);
/**
* Create a symbol from the string. The library automatically parses the input
* string and encodes in a QR Code symbol.
* @warning This function is THREAD UNSAFE when pthread is disabled.
* @param string input string. It must be NUL terminated.
* @param version version of the symbol. If 0, the library chooses the minimum
* version for the given input data.
* @param level error correction level.
* @param hint tell the library how Japanese Kanji characters should be
* encoded. If QR_MODE_KANJI is given, the library assumes that the
* given string contains Shift-JIS characters and encodes them in
* Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical
* characters will be encoded as is. If you want to embed UTF-8
* string, choose this. Other mode will cause EINVAL error.
* @param casesensitive case-sensitive(1) or not(0).
* @return an instance of QRcode class. The version of the result QRcode may
* be larger than the designated version. On error, NULL is returned,
* and errno is set to indicate the error. See Exceptions for the
* details.
* @throw EINVAL invalid input object.
* @throw ENOMEM unable to allocate memory for input objects.
* @throw ERANGE input data is too large.
*/
extern QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
/**
* Same to QRcode_encodeString(), but encode whole data in 8-bit mode.
* @warning This function is THREAD UNSAFE when pthread is disabled.
*/
extern QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level);
/**
* Micro QR Code version of QRcode_encodeString().
* @warning This function is THREAD UNSAFE when pthread is disabled.
*/
extern QRcode *QRcode_encodeStringMQR(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
/**
* Micro QR Code version of QRcode_encodeString8bit().
* @warning This function is THREAD UNSAFE when pthread is disabled.
*/
extern QRcode *QRcode_encodeString8bitMQR(const char *string, int version, QRecLevel level);
/**
* Encode byte stream (may include '\0') in 8-bit mode.
* @warning This function is THREAD UNSAFE when pthread is disabled.
* @param size size of the input data.
* @param data input data.
* @param version version of the symbol. If 0, the library chooses the minimum
* version for the given input data.
* @param level error correction level.
* @throw EINVAL invalid input object.
* @throw ENOMEM unable to allocate memory for input objects.
* @throw ERANGE input data is too large.
*/
extern QRcode *QRcode_encodeData(int size, const unsigned char *data, int version, QRecLevel level);
/**
* Micro QR Code version of QRcode_encodeData().
* @warning This function is THREAD UNSAFE when pthread is disabled.
*/
extern QRcode *QRcode_encodeDataMQR(int size, const unsigned char *data, int version, QRecLevel level);
/**
* Free the instance of QRcode class.
* @param qrcode an instance of QRcode class.
*/
extern void QRcode_free(QRcode *qrcode);
/**
* Create structured symbols from the input data.
* @warning This function is THREAD UNSAFE when pthread is disabled.
* @param s
* @return a singly-linked list of QRcode.
*/
extern QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s);
/**
* Create structured symbols from the string. The library automatically parses
* the input string and encodes in a QR Code symbol.
* @warning This function is THREAD UNSAFE when pthread is disabled.
* @param string input string. It must be NUL terminated.
* @param version version of the symbol.
* @param level error correction level.
* @param hint tell the library how Japanese Kanji characters should be
* encoded. If QR_MODE_KANJI is given, the library assumes that the
* given string contains Shift-JIS characters and encodes them in
* Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical
* characters will be encoded as is. If you want to embed UTF-8
* string, choose this. Other mode will cause EINVAL error.
* @param casesensitive case-sensitive(1) or not(0).
* @return a singly-linked list of QRcode. On error, NULL is returned, and
* errno is set to indicate the error. See Exceptions for the details.
* @throw EINVAL invalid input object.
* @throw ENOMEM unable to allocate memory for input objects.
*/
extern QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
/**
* Same to QRcode_encodeStringStructured(), but encode whole data in 8-bit mode.
* @warning This function is THREAD UNSAFE when pthread is disabled.
*/
extern QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level);
/**
* Create structured symbols from byte stream (may include '\0'). Wholde data
* are encoded in 8-bit mode.
* @warning This function is THREAD UNSAFE when pthread is disabled.
* @param size size of the input data.
* @param data input dat.
* @param version version of the symbol.
* @param level error correction level.
* @return a singly-linked list of QRcode. On error, NULL is returned, and
* errno is set to indicate the error. See Exceptions for the details.
* @throw EINVAL invalid input object.
* @throw ENOMEM unable to allocate memory for input objects.
*/
extern QRcode_List *QRcode_encodeDataStructured(int size, const unsigned char *data, int version, QRecLevel level);
/**
* Return the number of symbols included in a QRcode_List.
* @param qrlist a head entry of a QRcode_List.
* @return number of symbols in the list.
*/
extern int QRcode_List_size(QRcode_List *qrlist);
/**
* Free the QRcode_List.
* @param qrlist a head entry of a QRcode_List.
*/
extern void QRcode_List_free(QRcode_List *qrlist);
/******************************************************************************
* System utilities
*****************************************************************************/
/**
* Return a string that identifies the library version.
* @param major_version
* @param minor_version
* @param micro_version
*/
extern void QRcode_APIVersion(int *major_version, int *minor_version, int *micro_version);
/**
* Return a string that identifies the library version.
* @return a string identifies the library version. The string is held by the
* library. Do NOT free it.
*/
extern char *QRcode_APIVersionString(void);
/**
* Clear all caches. This is only for debug purpose. If you are attacking a
* complicated memory leak bug, try this to reduce the reachable blocks record.
* @warning This function is THREAD UNSAFE when pthread is disabled.
*/
extern void QRcode_clearCache(void);
#if defined(__cplusplus)
}
#endif
#endif /* __QRENCODE_H__ */

View file

@ -0,0 +1,88 @@
/**
* qrencode - QR Code encoder
*
* Header for test use
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __QRENCODE_INNER_H__
#define __QRENCODE_INNER_H__
/**
* This header file includes definitions for test use.
*/
/******************************************************************************
* Raw code
*****************************************************************************/
typedef struct {
int dataLength;
unsigned char *data;
int eccLength;
unsigned char *ecc;
} RSblock;
typedef struct {
int version;
int dataLength;
int eccLength;
unsigned char *datacode;
unsigned char *ecccode;
int b1;
int blocks;
RSblock *rsblock;
int count;
} QRRawCode;
extern QRRawCode *QRraw_new(QRinput *input);
extern unsigned char QRraw_getCode(QRRawCode *raw);
extern void QRraw_free(QRRawCode *raw);
/******************************************************************************
* Raw code for Micro QR Code
*****************************************************************************/
typedef struct {
int version;
int dataLength;
int eccLength;
unsigned char *datacode;
unsigned char *ecccode;
RSblock *rsblock;
int oddbits;
int count;
} MQRRawCode;
extern MQRRawCode *MQRraw_new(QRinput *input);
extern unsigned char MQRraw_getCode(MQRRawCode *raw);
extern void MQRraw_free(MQRRawCode *raw);
/******************************************************************************
* Frame filling
*****************************************************************************/
extern unsigned char *FrameFiller_test(int version);
extern unsigned char *FrameFiller_testMQR(int version);
/******************************************************************************
* QR-code encoding
*****************************************************************************/
extern QRcode *QRcode_encodeMask(QRinput *input, int mask);
extern QRcode *QRcode_encodeMaskMQR(QRinput *input, int mask);
extern QRcode *QRcode_new(int version, int width, unsigned char *data);
#endif /* __QRENCODE_INNER_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,123 @@
/*
* qrencode - QR Code encoder
*
* Input data chunk class
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __QRINPUT_H__
#define __QRINPUT_H__
#include "qrencode.h"
#include "bitstream.h"
int QRinput_isSplittableMode(QRencodeMode mode);
/******************************************************************************
* Entry of input data
*****************************************************************************/
typedef struct _QRinput_List QRinput_List;
struct _QRinput_List {
QRencodeMode mode;
int size; ///< Size of data chunk (byte).
unsigned char *data; ///< Data chunk.
BitStream *bstream;
QRinput_List *next;
};
/******************************************************************************
* Input Data
*****************************************************************************/
struct _QRinput {
int version;
QRecLevel level;
QRinput_List *head;
QRinput_List *tail;
int mqr;
int fnc1;
unsigned char appid;
};
/******************************************************************************
* Structured append input data
*****************************************************************************/
typedef struct _QRinput_InputList QRinput_InputList;
struct _QRinput_InputList {
QRinput *input;
QRinput_InputList *next;
};
struct _QRinput_Struct {
int size; ///< number of structured symbols
int parity;
QRinput_InputList *head;
QRinput_InputList *tail;
};
/**
* Pack all bit streams padding bits into a byte array.
* @param input input data.
* @return padded merged byte stream
*/
extern unsigned char *QRinput_getByteStream(QRinput *input);
extern int QRinput_estimateBitsModeNum(int size);
extern int QRinput_estimateBitsModeAn(int size);
extern int QRinput_estimateBitsMode8(int size);
extern int QRinput_estimateBitsModeKanji(int size);
extern QRinput *QRinput_dup(QRinput *input);
extern const signed char QRinput_anTable[128];
/**
* Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
* @param __c__ character
* @return value
*/
#define QRinput_lookAnTable(__c__) \
((__c__ & 0x80)?-1:QRinput_anTable[(int)__c__])
/**
* Length of a standard mode indicator in bits.
*/
#define MODE_INDICATOR_SIZE 4
/**
* Length of a segment of structured-append header.
*/
#define STRUCTURE_HEADER_SIZE 20
/**
* Maximum number of symbols in a set of structured-appended symbols.
*/
#define MAX_STRUCTURED_SYMBOLS 16
#ifdef WITH_TESTS
extern BitStream *QRinput_mergeBitStream(QRinput *input);
extern BitStream *QRinput_getBitStream(QRinput *input);
extern int QRinput_estimateBitStreamSize(QRinput *input, int version);
extern int QRinput_splitEntry(QRinput_List *entry, int bytes);
extern int QRinput_lengthOfCode(QRencodeMode mode, int version, int bits);
extern int QRinput_insertStructuredAppendHeader(QRinput *input, int size, int index, unsigned char parity);
#endif
#endif /* __QRINPUT_H__ */

View file

@ -0,0 +1,562 @@
/*
* qrencode - QR Code encoder
*
* QR Code specification in convenient format.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* The following data / specifications are taken from
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
* or
* "Automatic identification and data capture techniques --
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_LIBPTHREAD
#include <pthread.h>
#endif
#include "qrspec.h"
#include "qrinput.h"
/******************************************************************************
* Version and capacity
*****************************************************************************/
typedef struct {
int width; //< Edge length of the symbol
int words; //< Data capacity (bytes)
int remainder; //< Remainder bit (bits)
int ec[4]; //< Number of ECC code (bytes)
} QRspec_Capacity;
/**
* Table of the capacity of symbols
* See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
*/
static const QRspec_Capacity qrspecCapacity[QRSPEC_VERSION_MAX + 1] = {
{ 0, 0, 0, { 0, 0, 0, 0}},
{ 21, 26, 0, { 7, 10, 13, 17}}, // 1
{ 25, 44, 7, { 10, 16, 22, 28}},
{ 29, 70, 7, { 15, 26, 36, 44}},
{ 33, 100, 7, { 20, 36, 52, 64}},
{ 37, 134, 7, { 26, 48, 72, 88}}, // 5
{ 41, 172, 7, { 36, 64, 96, 112}},
{ 45, 196, 0, { 40, 72, 108, 130}},
{ 49, 242, 0, { 48, 88, 132, 156}},
{ 53, 292, 0, { 60, 110, 160, 192}},
{ 57, 346, 0, { 72, 130, 192, 224}}, //10
{ 61, 404, 0, { 80, 150, 224, 264}},
{ 65, 466, 0, { 96, 176, 260, 308}},
{ 69, 532, 0, { 104, 198, 288, 352}},
{ 73, 581, 3, { 120, 216, 320, 384}},
{ 77, 655, 3, { 132, 240, 360, 432}}, //15
{ 81, 733, 3, { 144, 280, 408, 480}},
{ 85, 815, 3, { 168, 308, 448, 532}},
{ 89, 901, 3, { 180, 338, 504, 588}},
{ 93, 991, 3, { 196, 364, 546, 650}},
{ 97, 1085, 3, { 224, 416, 600, 700}}, //20
{101, 1156, 4, { 224, 442, 644, 750}},
{105, 1258, 4, { 252, 476, 690, 816}},
{109, 1364, 4, { 270, 504, 750, 900}},
{113, 1474, 4, { 300, 560, 810, 960}},
{117, 1588, 4, { 312, 588, 870, 1050}}, //25
{121, 1706, 4, { 336, 644, 952, 1110}},
{125, 1828, 4, { 360, 700, 1020, 1200}},
{129, 1921, 3, { 390, 728, 1050, 1260}},
{133, 2051, 3, { 420, 784, 1140, 1350}},
{137, 2185, 3, { 450, 812, 1200, 1440}}, //30
{141, 2323, 3, { 480, 868, 1290, 1530}},
{145, 2465, 3, { 510, 924, 1350, 1620}},
{149, 2611, 3, { 540, 980, 1440, 1710}},
{153, 2761, 3, { 570, 1036, 1530, 1800}},
{157, 2876, 0, { 570, 1064, 1590, 1890}}, //35
{161, 3034, 0, { 600, 1120, 1680, 1980}},
{165, 3196, 0, { 630, 1204, 1770, 2100}},
{169, 3362, 0, { 660, 1260, 1860, 2220}},
{173, 3532, 0, { 720, 1316, 1950, 2310}},
{177, 3706, 0, { 750, 1372, 2040, 2430}} //40
};
int QRspec_getDataLength(int version, QRecLevel level)
{
return qrspecCapacity[version].words - qrspecCapacity[version].ec[level];
}
int QRspec_getECCLength(int version, QRecLevel level)
{
return qrspecCapacity[version].ec[level];
}
int QRspec_getMinimumVersion(int size, QRecLevel level)
{
int i;
int words;
for(i=1; i<= QRSPEC_VERSION_MAX; i++) {
words = qrspecCapacity[i].words - qrspecCapacity[i].ec[level];
if(words >= size) return i;
}
return -1;
}
int QRspec_getWidth(int version)
{
return qrspecCapacity[version].width;
}
int QRspec_getRemainder(int version)
{
return qrspecCapacity[version].remainder;
}
/******************************************************************************
* Length indicator
*****************************************************************************/
static const int lengthTableBits[4][3] = {
{10, 12, 14},
{ 9, 11, 13},
{ 8, 16, 16},
{ 8, 10, 12}
};
int QRspec_lengthIndicator(QRencodeMode mode, int version)
{
int l;
if(!QRinput_isSplittableMode(mode)) return 0;
if(version <= 9) {
l = 0;
} else if(version <= 26) {
l = 1;
} else {
l = 2;
}
return lengthTableBits[mode][l];
}
int QRspec_maximumWords(QRencodeMode mode, int version)
{
int l;
int bits;
int words;
if(!QRinput_isSplittableMode(mode)) return 0;
if(version <= 9) {
l = 0;
} else if(version <= 26) {
l = 1;
} else {
l = 2;
}
bits = lengthTableBits[mode][l];
words = (1 << bits) - 1;
if(mode == QR_MODE_KANJI) {
words *= 2; // the number of bytes is required
}
return words;
}
/******************************************************************************
* Error correction code
*****************************************************************************/
/**
* Table of the error correction code (Reed-Solomon block)
* See Table 12-16 (pp.30-36), JIS X0510:2004.
*/
static const int eccTable[QRSPEC_VERSION_MAX+1][4][2] = {
{{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}},
{{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}}, // 1
{{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}},
{{ 1, 0}, { 1, 0}, { 2, 0}, { 2, 0}},
{{ 1, 0}, { 2, 0}, { 2, 0}, { 4, 0}},
{{ 1, 0}, { 2, 0}, { 2, 2}, { 2, 2}}, // 5
{{ 2, 0}, { 4, 0}, { 4, 0}, { 4, 0}},
{{ 2, 0}, { 4, 0}, { 2, 4}, { 4, 1}},
{{ 2, 0}, { 2, 2}, { 4, 2}, { 4, 2}},
{{ 2, 0}, { 3, 2}, { 4, 4}, { 4, 4}},
{{ 2, 2}, { 4, 1}, { 6, 2}, { 6, 2}}, //10
{{ 4, 0}, { 1, 4}, { 4, 4}, { 3, 8}},
{{ 2, 2}, { 6, 2}, { 4, 6}, { 7, 4}},
{{ 4, 0}, { 8, 1}, { 8, 4}, {12, 4}},
{{ 3, 1}, { 4, 5}, {11, 5}, {11, 5}},
{{ 5, 1}, { 5, 5}, { 5, 7}, {11, 7}}, //15
{{ 5, 1}, { 7, 3}, {15, 2}, { 3, 13}},
{{ 1, 5}, {10, 1}, { 1, 15}, { 2, 17}},
{{ 5, 1}, { 9, 4}, {17, 1}, { 2, 19}},
{{ 3, 4}, { 3, 11}, {17, 4}, { 9, 16}},
{{ 3, 5}, { 3, 13}, {15, 5}, {15, 10}}, //20
{{ 4, 4}, {17, 0}, {17, 6}, {19, 6}},
{{ 2, 7}, {17, 0}, { 7, 16}, {34, 0}},
{{ 4, 5}, { 4, 14}, {11, 14}, {16, 14}},
{{ 6, 4}, { 6, 14}, {11, 16}, {30, 2}},
{{ 8, 4}, { 8, 13}, { 7, 22}, {22, 13}}, //25
{{10, 2}, {19, 4}, {28, 6}, {33, 4}},
{{ 8, 4}, {22, 3}, { 8, 26}, {12, 28}},
{{ 3, 10}, { 3, 23}, { 4, 31}, {11, 31}},
{{ 7, 7}, {21, 7}, { 1, 37}, {19, 26}},
{{ 5, 10}, {19, 10}, {15, 25}, {23, 25}}, //30
{{13, 3}, { 2, 29}, {42, 1}, {23, 28}},
{{17, 0}, {10, 23}, {10, 35}, {19, 35}},
{{17, 1}, {14, 21}, {29, 19}, {11, 46}},
{{13, 6}, {14, 23}, {44, 7}, {59, 1}},
{{12, 7}, {12, 26}, {39, 14}, {22, 41}}, //35
{{ 6, 14}, { 6, 34}, {46, 10}, { 2, 64}},
{{17, 4}, {29, 14}, {49, 10}, {24, 46}},
{{ 4, 18}, {13, 32}, {48, 14}, {42, 32}},
{{20, 4}, {40, 7}, {43, 22}, {10, 67}},
{{19, 6}, {18, 31}, {34, 34}, {20, 61}},//40
};
void QRspec_getEccSpec(int version, QRecLevel level, int spec[5])
{
int b1, b2;
int data, ecc;
b1 = eccTable[version][level][0];
b2 = eccTable[version][level][1];
data = QRspec_getDataLength(version, level);
ecc = QRspec_getECCLength(version, level);
if(b2 == 0) {
spec[0] = b1;
spec[1] = data / b1;
spec[2] = ecc / b1;
spec[3] = spec[4] = 0;
} else {
spec[0] = b1;
spec[1] = data / (b1 + b2);
spec[2] = ecc / (b1 + b2);
spec[3] = b2;
spec[4] = spec[1] + 1;
}
}
/******************************************************************************
* Alignment pattern
*****************************************************************************/
/**
* Positions of alignment patterns.
* This array includes only the second and the third position of the alignment
* patterns. Rest of them can be calculated from the distance between them.
*
* See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
*/
static const int alignmentPattern[QRSPEC_VERSION_MAX+1][2] = {
{ 0, 0},
{ 0, 0}, {18, 0}, {22, 0}, {26, 0}, {30, 0}, // 1- 5
{34, 0}, {22, 38}, {24, 42}, {26, 46}, {28, 50}, // 6-10
{30, 54}, {32, 58}, {34, 62}, {26, 46}, {26, 48}, //11-15
{26, 50}, {30, 54}, {30, 56}, {30, 58}, {34, 62}, //16-20
{28, 50}, {26, 50}, {30, 54}, {28, 54}, {32, 58}, //21-25
{30, 58}, {34, 62}, {26, 50}, {30, 54}, {26, 52}, //26-30
{30, 56}, {34, 60}, {30, 58}, {34, 62}, {30, 54}, //31-35
{24, 50}, {28, 54}, {32, 58}, {26, 54}, {30, 58}, //35-40
};
/**
* Put an alignment marker.
* @param frame
* @param width
* @param ox,oy center coordinate of the pattern
*/
static void QRspec_putAlignmentMarker(unsigned char *frame, int width, int ox, int oy)
{
static const unsigned char finder[] = {
0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa0, 0xa0, 0xa0, 0xa1,
0xa1, 0xa0, 0xa1, 0xa0, 0xa1,
0xa1, 0xa0, 0xa0, 0xa0, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
};
int x, y;
const unsigned char *s;
frame += (oy - 2) * width + ox - 2;
s = finder;
for(y=0; y<5; y++) {
for(x=0; x<5; x++) {
frame[x] = s[x];
}
frame += width;
s += 5;
}
}
static void QRspec_putAlignmentPattern(int version, unsigned char *frame, int width)
{
int d, w, x, y, cx, cy;
if(version < 2) return;
d = alignmentPattern[version][1] - alignmentPattern[version][0];
if(d < 0) {
w = 2;
} else {
w = (width - alignmentPattern[version][0]) / d + 2;
}
if(w * w - 3 == 1) {
x = alignmentPattern[version][0];
y = alignmentPattern[version][0];
QRspec_putAlignmentMarker(frame, width, x, y);
return;
}
cx = alignmentPattern[version][0];
for(x=1; x<w - 1; x++) {
QRspec_putAlignmentMarker(frame, width, 6, cx);
QRspec_putAlignmentMarker(frame, width, cx, 6);
cx += d;
}
cy = alignmentPattern[version][0];
for(y=0; y<w-1; y++) {
cx = alignmentPattern[version][0];
for(x=0; x<w-1; x++) {
QRspec_putAlignmentMarker(frame, width, cx, cy);
cx += d;
}
cy += d;
}
}
/******************************************************************************
* Version information pattern
*****************************************************************************/
/**
* Version information pattern (BCH coded).
* See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
*/
static const unsigned int versionPattern[QRSPEC_VERSION_MAX - 6] = {
0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,
0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,
0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,
0x27541, 0x28c69
};
unsigned int QRspec_getVersionPattern(int version)
{
if(version < 7 || version > QRSPEC_VERSION_MAX) return 0;
return versionPattern[version - 7];
}
/******************************************************************************
* Format information
*****************************************************************************/
/* See calcFormatInfo in tests/test_qrspec.c */
static const unsigned int formatInfo[4][8] = {
{0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976},
{0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0},
{0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed},
{0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b}
};
unsigned int QRspec_getFormatInfo(int mask, QRecLevel level)
{
if(mask < 0 || mask > 7) return 0;
return formatInfo[level][mask];
}
/******************************************************************************
* Frame
*****************************************************************************/
/**
* Cache of initial frames.
*/
/* C99 says that static storage shall be initialized to a null pointer
* by compiler. */
static unsigned char *frames[QRSPEC_VERSION_MAX + 1];
#ifdef HAVE_LIBPTHREAD
static pthread_mutex_t frames_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
/**
* Put a finder pattern.
* @param frame
* @param width
* @param ox,oy upper-left coordinate of the pattern
*/
static void putFinderPattern(unsigned char *frame, int width, int ox, int oy)
{
static const unsigned char finder[] = {
0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
};
int x, y;
const unsigned char *s;
frame += oy * width + ox;
s = finder;
for(y=0; y<7; y++) {
for(x=0; x<7; x++) {
frame[x] = s[x];
}
frame += width;
s += 7;
}
}
static unsigned char *QRspec_createFrame(int version)
{
unsigned char *frame, *p, *q;
int width;
int x, y;
unsigned int verinfo, v;
width = qrspecCapacity[version].width;
frame = (unsigned char *)malloc(width * width);
if(frame == NULL) return NULL;
memset(frame, 0, width * width);
/* Finder pattern */
putFinderPattern(frame, width, 0, 0);
putFinderPattern(frame, width, width - 7, 0);
putFinderPattern(frame, width, 0, width - 7);
/* Separator */
p = frame;
q = frame + width * (width - 7);
for(y=0; y<7; y++) {
p[7] = 0xc0;
p[width - 8] = 0xc0;
q[7] = 0xc0;
p += width;
q += width;
}
memset(frame + width * 7, 0xc0, 8);
memset(frame + width * 8 - 8, 0xc0, 8);
memset(frame + width * (width - 8), 0xc0, 8);
/* Mask format information area */
memset(frame + width * 8, 0x84, 9);
memset(frame + width * 9 - 8, 0x84, 8);
p = frame + 8;
for(y=0; y<8; y++) {
*p = 0x84;
p += width;
}
p = frame + width * (width - 7) + 8;
for(y=0; y<7; y++) {
*p = 0x84;
p += width;
}
/* Timing pattern */
p = frame + width * 6 + 8;
q = frame + width * 8 + 6;
for(x=1; x<width-15; x++) {
*p = 0x90 | (x & 1);
*q = 0x90 | (x & 1);
p++;
q += width;
}
/* Alignment pattern */
QRspec_putAlignmentPattern(version, frame, width);
/* Version information */
if(version >= 7) {
verinfo = QRspec_getVersionPattern(version);
p = frame + width * (width - 11);
v = verinfo;
for(x=0; x<6; x++) {
for(y=0; y<3; y++) {
p[width * y + x] = 0x88 | (v & 1);
v = v >> 1;
}
}
p = frame + width - 11;
v = verinfo;
for(y=0; y<6; y++) {
for(x=0; x<3; x++) {
p[x] = 0x88 | (v & 1);
v = v >> 1;
}
p += width;
}
}
/* and a little bit... */
frame[width * (width - 8) + 8] = 0x81;
return frame;
}
unsigned char *QRspec_newFrame(int version)
{
unsigned char *frame;
int width;
if(version < 1 || version > QRSPEC_VERSION_MAX) return NULL;
#ifdef HAVE_LIBPTHREAD
pthread_mutex_lock(&frames_mutex);
#endif
if(frames[version] == NULL) {
frames[version] = QRspec_createFrame(version);
}
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&frames_mutex);
#endif
if(frames[version] == NULL) return NULL;
width = qrspecCapacity[version].width;
frame = (unsigned char *)malloc(width * width);
if(frame == NULL) return NULL;
memcpy(frame, frames[version], width * width);
return frame;
}
void QRspec_clearCache(void)
{
int i;
#ifdef HAVE_LIBPTHREAD
pthread_mutex_lock(&frames_mutex);
#endif
for(i=1; i<=QRSPEC_VERSION_MAX; i++) {
free(frames[i]);
frames[i] = NULL;
}
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&frames_mutex);
#endif
}

View file

@ -0,0 +1,181 @@
/*
* qrencode - QR Code encoder
*
* QR Code specification in convenient format.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __QRSPEC_H__
#define __QRSPEC_H__
#include "qrencode.h"
/******************************************************************************
* Version and capacity
*****************************************************************************/
/**
* Maximum width of a symbol
*/
#define QRSPEC_WIDTH_MAX 177
/**
* Return maximum data code length (bytes) for the version.
* @param version
* @param level
* @return maximum size (bytes)
*/
extern int QRspec_getDataLength(int version, QRecLevel level);
/**
* Return maximum error correction code length (bytes) for the version.
* @param version
* @param level
* @return ECC size (bytes)
*/
extern int QRspec_getECCLength(int version, QRecLevel level);
/**
* Return a version number that satisfies the input code length.
* @param size input code length (byte)
* @param level
* @return version number
*/
extern int QRspec_getMinimumVersion(int size, QRecLevel level);
/**
* Return the width of the symbol for the version.
* @param version
* @return width
*/
extern int QRspec_getWidth(int version);
/**
* Return the numer of remainder bits.
* @param version
* @return number of remainder bits
*/
extern int QRspec_getRemainder(int version);
/******************************************************************************
* Length indicator
*****************************************************************************/
/**
* Return the size of lenght indicator for the mode and version.
* @param mode
* @param version
* @return the size of the appropriate length indicator (bits).
*/
extern int QRspec_lengthIndicator(QRencodeMode mode, int version);
/**
* Return the maximum length for the mode and version.
* @param mode
* @param version
* @return the maximum length (bytes)
*/
extern int QRspec_maximumWords(QRencodeMode mode, int version);
/******************************************************************************
* Error correction code
*****************************************************************************/
/**
* Return an array of ECC specification.
* @param version
* @param level
* @param spec an array of ECC specification contains as following:
* {# of type1 blocks, # of data code, # of ecc code,
* # of type2 blocks, # of data code}
*/
void QRspec_getEccSpec(int version, QRecLevel level, int spec[5]);
#define QRspec_rsBlockNum(__spec__) (__spec__[0] + __spec__[3])
#define QRspec_rsBlockNum1(__spec__) (__spec__[0])
#define QRspec_rsDataCodes1(__spec__) (__spec__[1])
#define QRspec_rsEccCodes1(__spec__) (__spec__[2])
#define QRspec_rsBlockNum2(__spec__) (__spec__[3])
#define QRspec_rsDataCodes2(__spec__) (__spec__[4])
#define QRspec_rsEccCodes2(__spec__) (__spec__[2])
#define QRspec_rsDataLength(__spec__) \
((QRspec_rsBlockNum1(__spec__) * QRspec_rsDataCodes1(__spec__)) + \
(QRspec_rsBlockNum2(__spec__) * QRspec_rsDataCodes2(__spec__)))
#define QRspec_rsEccLength(__spec__) \
(QRspec_rsBlockNum(__spec__) * QRspec_rsEccCodes1(__spec__))
/******************************************************************************
* Version information pattern
*****************************************************************************/
/**
* Return BCH encoded version information pattern that is used for the symbol
* of version 7 or greater. Use lower 18 bits.
* @param version
* @return BCH encoded version information pattern
*/
extern unsigned int QRspec_getVersionPattern(int version);
/******************************************************************************
* Format information
*****************************************************************************/
/**
* Return BCH encoded format information pattern.
* @param mask
* @param level
* @return BCH encoded format information pattern
*/
extern unsigned int QRspec_getFormatInfo(int mask, QRecLevel level);
/******************************************************************************
* Frame
*****************************************************************************/
/**
* Return a copy of initialized frame.
* When the same version is requested twice or more, a copy of cached frame
* is returned.
* @param version
* @return Array of unsigned char. You can free it by free().
*/
extern unsigned char *QRspec_newFrame(int version);
/**
* Clear the frame cache. Typically for debug.
*/
extern void QRspec_clearCache(void);
/******************************************************************************
* Mode indicator
*****************************************************************************/
/**
* Mode indicator. See Table 2 of JIS X0510:2004, pp.16.
*/
#define QRSPEC_MODEID_ECI 7
#define QRSPEC_MODEID_NUM 1
#define QRSPEC_MODEID_AN 2
#define QRSPEC_MODEID_8 4
#define QRSPEC_MODEID_KANJI 8
#define QRSPEC_MODEID_FNC1FIRST 5
#define QRSPEC_MODEID_FNC1SECOND 9
#define QRSPEC_MODEID_STRUCTURE 3
#define QRSPEC_MODEID_TERMINATOR 0
#endif /* __QRSPEC_H__ */

View file

@ -0,0 +1,327 @@
/*
* qrencode - QR Code encoder
*
* Reed solomon encoder. This code is taken from Phil Karn's libfec then
* editted and packed into a pair of .c and .h files.
*
* Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
* (libfec is released under the GNU Lesser General Public License.)
*
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_LIBPTHREAD
# include <pthread.h>
#endif
#include "rscode.h"
/* Stuff specific to the 8-bit symbol version of the general purpose RS codecs
*
*/
typedef unsigned char data_t;
/**
* Reed-Solomon codec control block
*/
struct _RS {
int mm; /* Bits per symbol */
int nn; /* Symbols per block (= (1<<mm)-1) */
data_t *alpha_to; /* log lookup table */
data_t *index_of; /* Antilog lookup table */
data_t *genpoly; /* Generator polynomial */
int nroots; /* Number of generator roots = number of parity symbols */
int fcr; /* First consecutive root, index form */
int prim; /* Primitive element, index form */
int iprim; /* prim-th root of 1, index form */
int pad; /* Padding bytes in shortened block */
int gfpoly;
struct _RS *next;
};
static RS *rslist = NULL;
#ifdef HAVE_LIBPTHREAD
static pthread_mutex_t rslist_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
static inline int modnn(RS *rs, int x){
while (x >= rs->nn) {
x -= rs->nn;
x = (x >> rs->mm) + (x & rs->nn);
}
return x;
}
#define MODNN(x) modnn(rs,x)
#define MM (rs->mm)
#define NN (rs->nn)
#define ALPHA_TO (rs->alpha_to)
#define INDEX_OF (rs->index_of)
#define GENPOLY (rs->genpoly)
#define NROOTS (rs->nroots)
#define FCR (rs->fcr)
#define PRIM (rs->prim)
#define IPRIM (rs->iprim)
#define PAD (rs->pad)
#define A0 (NN)
/* Initialize a Reed-Solomon codec
* symsize = symbol size, bits
* gfpoly = Field generator polynomial coefficients
* fcr = first root of RS code generator polynomial, index form
* prim = primitive element to generate polynomial roots
* nroots = RS code generator polynomial degree (number of roots)
* pad = padding bytes at front of shortened block
*/
static RS *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad)
{
RS *rs;
/* Common code for intializing a Reed-Solomon control block (char or int symbols)
* Copyright 2004 Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
//#undef NULL
//#define NULL ((void *)0)
int i, j, sr,root,iprim;
rs = NULL;
/* Check parameter ranges */
if(symsize < 0 || symsize > (int)(8*sizeof(data_t))){
goto done;
}
if(fcr < 0 || fcr >= (1<<symsize))
goto done;
if(prim <= 0 || prim >= (1<<symsize))
goto done;
if(nroots < 0 || nroots >= (1<<symsize))
goto done; /* Can't have more roots than symbol values! */
if(pad < 0 || pad >= ((1<<symsize) -1 - nroots))
goto done; /* Too much padding */
rs = (RS *)calloc(1,sizeof(RS));
if(rs == NULL)
goto done;
rs->mm = symsize;
rs->nn = (1<<symsize)-1;
rs->pad = pad;
rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
if(rs->alpha_to == NULL){
free(rs);
rs = NULL;
goto done;
}
rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
if(rs->index_of == NULL){
free(rs->alpha_to);
free(rs);
rs = NULL;
goto done;
}
/* Generate Galois field lookup tables */
rs->index_of[0] = A0; /* log(zero) = -inf */
rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */
sr = 1;
for(i=0;i<rs->nn;i++){
rs->index_of[sr] = i;
rs->alpha_to[i] = sr;
sr <<= 1;
if(sr & (1<<symsize))
sr ^= gfpoly;
sr &= rs->nn;
}
if(sr != 1){
/* field generator polynomial is not primitive! */
free(rs->alpha_to);
free(rs->index_of);
free(rs);
rs = NULL;
goto done;
}
/* Form RS code generator polynomial from its roots */
rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1));
if(rs->genpoly == NULL){
free(rs->alpha_to);
free(rs->index_of);
free(rs);
rs = NULL;
goto done;
}
rs->fcr = fcr;
rs->prim = prim;
rs->nroots = nroots;
rs->gfpoly = gfpoly;
/* Find prim-th root of 1, used in decoding */
for(iprim=1;(iprim % prim) != 0;iprim += rs->nn)
;
rs->iprim = iprim / prim;
rs->genpoly[0] = 1;
for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) {
rs->genpoly[i+1] = 1;
/* Multiply rs->genpoly[] by @**(root + x) */
for (j = i; j > 0; j--){
if (rs->genpoly[j] != 0)
rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)];
else
rs->genpoly[j] = rs->genpoly[j-1];
}
/* rs->genpoly[0] can never be zero */
rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)];
}
/* convert rs->genpoly[] to index form for quicker encoding */
for (i = 0; i <= nroots; i++)
rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
done:;
return rs;
}
RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad)
{
RS *rs;
#ifdef HAVE_LIBPTHREAD
pthread_mutex_lock(&rslist_mutex);
#endif
for(rs = rslist; rs != NULL; rs = rs->next) {
if(rs->pad != pad) continue;
if(rs->nroots != nroots) continue;
if(rs->mm != symsize) continue;
if(rs->gfpoly != gfpoly) continue;
if(rs->fcr != fcr) continue;
if(rs->prim != prim) continue;
goto DONE;
}
rs = init_rs_char(symsize, gfpoly, fcr, prim, nroots, pad);
if(rs == NULL) goto DONE;
rs->next = rslist;
rslist = rs;
DONE:
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&rslist_mutex);
#endif
return rs;
}
void free_rs_char(RS *rs)
{
free(rs->alpha_to);
free(rs->index_of);
free(rs->genpoly);
free(rs);
}
void free_rs_cache(void)
{
RS *rs, *next;
#ifdef HAVE_LIBPTHREAD
pthread_mutex_lock(&rslist_mutex);
#endif
rs = rslist;
while(rs != NULL) {
next = rs->next;
free_rs_char(rs);
rs = next;
}
rslist = NULL;
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&rslist_mutex);
#endif
}
/* The guts of the Reed-Solomon encoder, meant to be #included
* into a function body with the following typedefs, macros and variables supplied
* according to the code parameters:
* data_t - a typedef for the data symbol
* data_t data[] - array of NN-NROOTS-PAD and type data_t to be encoded
* data_t parity[] - an array of NROOTS and type data_t to be written with parity symbols
* NROOTS - the number of roots in the RS code generator polynomial,
* which is the same as the number of parity symbols in a block.
Integer variable or literal.
*
* NN - the total number of symbols in a RS block. Integer variable or literal.
* PAD - the number of pad symbols in a block. Integer variable or literal.
* ALPHA_TO - The address of an array of NN elements to convert Galois field
* elements in index (log) form to polynomial form. Read only.
* INDEX_OF - The address of an array of NN elements to convert Galois field
* elements in polynomial form to index (log) form. Read only.
* MODNN - a function to reduce its argument modulo NN. May be inline or a macro.
* GENPOLY - an array of NROOTS+1 elements containing the generator polynomial in index form
* The memset() and memmove() functions are used. The appropriate header
* file declaring these functions (usually <string.h>) must be included by the calling
* program.
* Copyright 2004, Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
#undef A0
#define A0 (NN) /* Special reserved value encoding zero in index form */
void encode_rs_char(RS *rs, const data_t *data, data_t *parity)
{
int i, j;
data_t feedback;
memset(parity,0,NROOTS*sizeof(data_t));
for(i=0;i<NN-NROOTS-PAD;i++){
feedback = INDEX_OF[data[i] ^ parity[0]];
if(feedback != A0){ /* feedback term is non-zero */
#ifdef UNNORMALIZED
/* This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
* always be for the polynomials constructed by init_rs()
*/
feedback = MODNN(NN - GENPOLY[NROOTS] + feedback);
#endif
for(j=1;j<NROOTS;j++)
parity[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS-j])];
}
/* Shift */
memmove(&parity[0],&parity[1],sizeof(data_t)*(NROOTS-1));
if(feedback != A0)
parity[NROOTS-1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])];
else
parity[NROOTS-1] = 0;
}
}

View file

@ -0,0 +1,41 @@
/*
* qrencode - QR Code encoder
*
* Reed solomon encoder. This code is taken from Phil Karn's libfec then
* editted and packed into a pair of .c and .h files.
*
* Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
* (libfec is released under the GNU Lesser General Public License.)
*
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __RSCODE_H__
#define __RSCODE_H__
/*
* General purpose RS codec, 8-bit symbols.
*/
typedef struct _RS RS;
extern RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad);
extern void encode_rs_char(RS *rs, const unsigned char *data, unsigned char *parity);
extern void free_rs_char(RS *rs);
extern void free_rs_cache(void);
#endif /* __RSCODE_H__ */

View file

@ -0,0 +1,326 @@
/*
* qrencode - QR Code encoder
*
* Input data splitter.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* The following data / specifications are taken from
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
* or
* "Automatic identification and data capture techniques --
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "qrencode.h"
#include "qrinput.h"
#include "qrspec.h"
#include "split.h"
#define isdigit(__c__) ((unsigned char)((signed char)(__c__) - '0') < 10)
#define isalnum(__c__) (QRinput_lookAnTable(__c__) >= 0)
#if !HAVE_STRDUP
#undef strdup
char *strdup(const char *s)
{
size_t len = strlen(s) + 1;
void *new = malloc(len);
if(new == NULL) return NULL;
return (char *)memcpy(new, s, len);
}
#endif
static QRencodeMode Split_identifyMode(const char *string, QRencodeMode hint)
{
unsigned char c, d;
unsigned int word;
c = string[0];
if(c == '\0') return QR_MODE_NUL;
if(isdigit(c)) {
return QR_MODE_NUM;
} else if(isalnum(c)) {
return QR_MODE_AN;
} else if(hint == QR_MODE_KANJI) {
d = string[1];
if(d != '\0') {
word = ((unsigned int)c << 8) | d;
if((word >= 0x8140 && word <= 0x9ffc) || (word >= 0xe040 && word <= 0xebbf)) {
return QR_MODE_KANJI;
}
}
}
return QR_MODE_8;
}
static int Split_eatNum(const char *string, QRinput *input, QRencodeMode hint);
static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint);
static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint);
static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint);
static int Split_eatNum(const char *string, QRinput *input,QRencodeMode hint)
{
const char *p;
int ret;
int run;
int dif;
int ln;
QRencodeMode mode;
ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
p = string;
while(isdigit(*p)) {
p++;
}
run = p - string;
mode = Split_identifyMode(p, hint);
if(mode == QR_MODE_8) {
dif = QRinput_estimateBitsModeNum(run) + 4 + ln
+ QRinput_estimateBitsMode8(1) /* + 4 + l8 */
- QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */;
if(dif > 0) {
return Split_eat8(string, input, hint);
}
}
if(mode == QR_MODE_AN) {
dif = QRinput_estimateBitsModeNum(run) + 4 + ln
+ QRinput_estimateBitsModeAn(1) /* + 4 + la */
- QRinput_estimateBitsModeAn(run + 1) /* - 4 - la */;
if(dif > 0) {
return Split_eatAn(string, input, hint);
}
}
ret = QRinput_append(input, QR_MODE_NUM, run, (unsigned char *)string);
if(ret < 0) return -1;
return run;
}
static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint)
{
const char *p, *q;
int ret;
int run;
int dif;
int la, ln;
la = QRspec_lengthIndicator(QR_MODE_AN, input->version);
ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
p = string;
while(isalnum(*p)) {
if(isdigit(*p)) {
q = p;
while(isdigit(*q)) {
q++;
}
dif = QRinput_estimateBitsModeAn(p - string) /* + 4 + la */
+ QRinput_estimateBitsModeNum(q - p) + 4 + ln
+ (isalnum(*q)?(4 + ln):0)
- QRinput_estimateBitsModeAn(q - string) /* - 4 - la */;
if(dif < 0) {
break;
} else {
p = q;
}
} else {
p++;
}
}
run = p - string;
if(*p && !isalnum(*p)) {
dif = QRinput_estimateBitsModeAn(run) + 4 + la
+ QRinput_estimateBitsMode8(1) /* + 4 + l8 */
- QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */;
if(dif > 0) {
return Split_eat8(string, input, hint);
}
}
ret = QRinput_append(input, QR_MODE_AN, run, (unsigned char *)string);
if(ret < 0) return -1;
return run;
}
static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint)
{
const char *p;
int ret;
int run;
p = string;
while(Split_identifyMode(p, hint) == QR_MODE_KANJI) {
p += 2;
}
run = p - string;
ret = QRinput_append(input, QR_MODE_KANJI, run, (unsigned char *)string);
if(ret < 0) return -1;
return run;
}
static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint)
{
const char *p, *q;
QRencodeMode mode;
int ret;
int run;
int dif;
int la, ln, l8;
int swcost;
la = QRspec_lengthIndicator(QR_MODE_AN, input->version);
ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
l8 = QRspec_lengthIndicator(QR_MODE_8, input->version);
p = string + 1;
while(*p != '\0') {
mode = Split_identifyMode(p, hint);
if(mode == QR_MODE_KANJI) {
break;
}
if(mode == QR_MODE_NUM) {
q = p;
while(isdigit(*q)) {
q++;
}
if(Split_identifyMode(q, hint) == QR_MODE_8) {
swcost = 4 + l8;
} else {
swcost = 0;
}
dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */
+ QRinput_estimateBitsModeNum(q - p) + 4 + ln
+ swcost
- QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */;
if(dif < 0) {
break;
} else {
p = q;
}
} else if(mode == QR_MODE_AN) {
q = p;
while(isalnum(*q)) {
q++;
}
if(Split_identifyMode(q, hint) == QR_MODE_8) {
swcost = 4 + l8;
} else {
swcost = 0;
}
dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */
+ QRinput_estimateBitsModeAn(q - p) + 4 + la
+ swcost
- QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */;
if(dif < 0) {
break;
} else {
p = q;
}
} else {
p++;
}
}
run = p - string;
ret = QRinput_append(input, QR_MODE_8, run, (unsigned char *)string);
if(ret < 0) return -1;
return run;
}
static int Split_splitString(const char *string, QRinput *input,
QRencodeMode hint)
{
int length;
QRencodeMode mode;
if(*string == '\0') return 0;
mode = Split_identifyMode(string, hint);
if(mode == QR_MODE_NUM) {
length = Split_eatNum(string, input, hint);
} else if(mode == QR_MODE_AN) {
length = Split_eatAn(string, input, hint);
} else if(mode == QR_MODE_KANJI && hint == QR_MODE_KANJI) {
length = Split_eatKanji(string, input, hint);
} else {
length = Split_eat8(string, input, hint);
}
if(length == 0) return 0;
if(length < 0) return -1;
return Split_splitString(&string[length], input, hint);
}
static char *dupAndToUpper(const char *str, QRencodeMode hint)
{
char *newstr, *p;
QRencodeMode mode;
newstr = strdup(str);
if(newstr == NULL) return NULL;
p = newstr;
while(*p != '\0') {
mode = Split_identifyMode(p, hint);
if(mode == QR_MODE_KANJI) {
p += 2;
} else {
if (*p >= 'a' && *p <= 'z') {
*p = (char)((int)*p - 32);
}
p++;
}
}
return newstr;
}
int Split_splitStringToQRinput(const char *string, QRinput *input,
QRencodeMode hint, int casesensitive)
{
char *newstr;
int ret;
if(string == NULL || *string == '\0') {
errno = EINVAL;
return -1;
}
if(!casesensitive) {
newstr = dupAndToUpper(string, hint);
if(newstr == NULL) return -1;
ret = Split_splitString(newstr, input, hint);
free(newstr);
} else {
ret = Split_splitString(string, input, hint);
}
return ret;
}

View file

@ -0,0 +1,47 @@
/*
* qrencode - QR Code encoder
*
* Input data splitter.
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* The following data / specifications are taken from
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
* or
* "Automatic identification and data capture techniques --
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __SPLIT_H__
#define __SPLIT_H__
#include "qrencode.h"
/**
* Split the input string (null terminated) into QRinput.
* @param string input string
* @param hint give QR_MODE_KANJI if the input string contains Kanji character encoded in Shift-JIS. If not, give QR_MODE_8.
* @param casesensitive 0 for case-insensitive encoding (all alphabet characters are replaced to UPPER-CASE CHARACTERS.
* @retval 0 success.
* @retval -1 an error occurred. errno is set to indicate the error. See
* Exceptions for the details.
* @throw EINVAL invalid input object.
* @throw ENOMEM unable to allocate memory for input objects.
*/
extern int Split_splitStringToQRinput(const char *string, QRinput *input,
QRencodeMode hint, int casesensitive);
#endif /* __SPLIT_H__ */

View file

@ -0,0 +1,144 @@
#include "CameraImageWrapper.h"
#include <QColor>
CameraImageWrapper::CameraImageWrapper() : LuminanceSource(), isSmoothTransformationEnabled(false)
{
}
CameraImageWrapper::CameraImageWrapper(QImage& image) : LuminanceSource() , isSmoothTransformationEnabled(false)
{
setImage(image);
}
CameraImageWrapper::CameraImageWrapper(CameraImageWrapper& otherInstance) : LuminanceSource() , isSmoothTransformationEnabled(false)
{
image = otherInstance.getOriginalImage().copy();
}
CameraImageWrapper::~CameraImageWrapper()
{
}
int CameraImageWrapper::getWidth() const
{
return image.width();
}
int CameraImageWrapper::getHeight() const
{
return image.height();
}
unsigned char CameraImageWrapper::getPixel(int x, int y) const
{
QRgb pixel = image.pixel(x,y);
return qGray(pixel);//((qRed(pixel) + qGreen(pixel) + qBlue(pixel)) / 3);
}
unsigned char* CameraImageWrapper::copyMatrix() const
{
unsigned char* newMatrix = (unsigned char*)malloc(image.width()*image.height()*sizeof(unsigned char));
int cnt = 0;
for(int i=0; i<image.width(); i++)
{
for(int j=0; j<image.height(); j++)
{
newMatrix[cnt++] = getPixel(i,j);
}
}
return newMatrix;
}
bool CameraImageWrapper::setImage(QString fileName)
{
bool isLoaded = image.load(fileName);
if(!isLoaded)
return false;
// if(image.width() > QApplication::desktop()->width())
// image = image.scaled(QApplication::desktop()->width(), image.height(), Qt::IgnoreAspectRatio);
// if(image.height() > QApplication::desktop()->height())
// image = image.scaled(image.width(), QApplication::desktop()->height(), Qt::IgnoreAspectRatio);
return true;
}
bool CameraImageWrapper::setImage(QImage newImage)
{
if(newImage.isNull())
return false;
image = newImage.copy();
if(image.width() > 640)
image = image.scaled(640, image.height(), Qt::KeepAspectRatio, isSmoothTransformationEnabled ? Qt::SmoothTransformation : Qt::FastTransformation);
return true;
}
QImage CameraImageWrapper::grayScaleImage(QImage::Format f)
{
QImage tmp(image.width(), image.height(), f);
for(int i=0; i<image.width(); i++)
{
for(int j=0; j<image.height(); j++)
{
int pix = (int)getPixel(i,j);
tmp.setPixel(i,j, qRgb(pix ,pix,pix));
}
}
return tmp;
//return image.convertToFormat(f);
}
QImage CameraImageWrapper::getOriginalImage()
{
return image;
}
unsigned char* CameraImageWrapper::getRow(int y, unsigned char* row)
{
int width = getWidth();
if (row == NULL)
{
row = new unsigned char[width];
pRow = row;
}
for (int x = 0; x < width; x++)
row[x] = getPixel(x,y);
return row;
}
unsigned char* CameraImageWrapper::getMatrix()
{
int width = getWidth();
int height = getHeight();
unsigned char* matrix = new unsigned char[width*height];
unsigned char* m = matrix;
for(int y=0; y<height; y++)
{
unsigned char* tmpRow;
memcpy(m, tmpRow = getRow(y, NULL), width);
m += width * sizeof(unsigned char);
delete tmpRow;
}
pMatrix = matrix;
return matrix;
}
void CameraImageWrapper::setSmoothTransformation(bool enable)
{
isSmoothTransformationEnabled = enable;
}

View file

@ -0,0 +1,47 @@
#ifndef CAMERAIMAGE_H
#define CAMERAIMAGE_H
#include <QImage>
#include <QString>
#include <zxing/LuminanceSource.h>
using namespace zxing;
class CameraImageWrapper : public LuminanceSource
{
public:
CameraImageWrapper();
CameraImageWrapper(QImage& image);
CameraImageWrapper(CameraImageWrapper& otherInstance);
~CameraImageWrapper();
int getWidth() const;
int getHeight() const;
unsigned char getPixel(int x, int y) const;
unsigned char* copyMatrix() const;
/**
* Set the source of the image. If it fails, returns false.
*/
bool setImage(QString fileName);
bool setImage(QImage newImage);
QImage grayScaleImage(QImage::Format f);
QImage getOriginalImage();
// Callers take ownership of the returned memory and must call delete [] on it themselves.
unsigned char* getRow(int y, unsigned char* row);
unsigned char* getMatrix();
void setSmoothTransformation(bool enable);
private:
QImage image;
unsigned char* pRow;
unsigned char* pMatrix;
bool isSmoothTransformationEnabled;
};
#endif //CAMERAIMAGE_H

191
src/qzxing/QZXing.pri Normal file
View file

@ -0,0 +1,191 @@
QT += core gui quick
INCLUDEPATH += \
$$PWD \
$$PWD/zxing
HEADERS += \
$$PWD/CameraImageWrapper.h \
$$PWD/qzxing.h \
$$PWD/qzxing_global.h \
$$PWD/zxing/ResultPointCallback.h \
$$PWD/zxing/ResultPoint.h \
$$PWD/zxing/Result.h \
$$PWD/zxing/ReaderException.h \
$$PWD/zxing/Reader.h \
$$PWD/zxing/NotFoundException.h \
$$PWD/zxing/MultiFormatReader.h \
$$PWD/zxing/LuminanceSource.h \
$$PWD/zxing/FormatException.h \
$$PWD/zxing/Exception.h \
$$PWD/zxing/DecodeHints.h \
$$PWD/zxing/BinaryBitmap.h \
$$PWD/zxing/Binarizer.h \
$$PWD/zxing/BarcodeFormat.h \
$$PWD/zxing/aztec/AztecReader.h \
$$PWD/zxing/aztec/AztecDetectorResult.h \
$$PWD/zxing/aztec/decoder/Decoder.h \
$$PWD/zxing/aztec/detector/Detector.h \
$$PWD/zxing/common/StringUtils.h \
$$PWD/zxing/common/Str.h \
$$PWD/zxing/common/Point.h \
$$PWD/zxing/common/PerspectiveTransform.h \
$$PWD/zxing/common/IllegalArgumentException.h \
$$PWD/zxing/common/HybridBinarizer.h \
$$PWD/zxing/common/GridSampler.h \
$$PWD/zxing/common/GreyscaleRotatedLuminanceSource.h \
$$PWD/zxing/common/GreyscaleLuminanceSource.h \
$$PWD/zxing/common/GlobalHistogramBinarizer.h \
$$PWD/zxing/common/EdgeDetector.h \
$$PWD/zxing/common/DetectorResult.h \
$$PWD/zxing/common/DecoderResult.h \
$$PWD/zxing/common/Counted.h \
$$PWD/zxing/common/CharacterSetECI.h \
$$PWD/zxing/common/BitSource.h \
$$PWD/zxing/common/BitMatrix.h \
$$PWD/zxing/common/BitArray.h \
$$PWD/zxing/common/Array.h \
$$PWD/zxing/common/detector/WhiteRectangleDetector.h \
$$PWD/zxing/common/detector/MonochromeRectangleDetector.h \
$$PWD/zxing/common/reedsolomon/ReedSolomonException.h \
$$PWD/zxing/common/reedsolomon/ReedSolomonDecoder.h \
$$PWD/zxing/common/reedsolomon/GenericGFPoly.h \
$$PWD/zxing/common/reedsolomon/GenericGF.h \
$$PWD/zxing/datamatrix/Version.h \
$$PWD/zxing/datamatrix/DataMatrixReader.h \
$$PWD/zxing/datamatrix/decoder/Decoder.h \
$$PWD/zxing/datamatrix/decoder/DecodedBitStreamParser.h \
$$PWD/zxing/datamatrix/decoder/DataBlock.h \
$$PWD/zxing/datamatrix/decoder/BitMatrixParser.h \
$$PWD/zxing/datamatrix/detector/MonochromeRectangleDetector.h \
$$PWD/zxing/datamatrix/detector/DetectorException.h \
$$PWD/zxing/datamatrix/detector/Detector.h \
$$PWD/zxing/datamatrix/detector/CornerPoint.h \
$$PWD/zxing/oned/UPCEReader.h \
$$PWD/zxing/oned/UPCEANReader.h \
$$PWD/zxing/oned/UPCAReader.h \
$$PWD/zxing/oned/OneDResultPoint.h \
$$PWD/zxing/oned/OneDReader.h \
$$PWD/zxing/oned/MultiFormatUPCEANReader.h \
$$PWD/zxing/oned/MultiFormatOneDReader.h \
$$PWD/zxing/oned/ITFReader.h \
$$PWD/zxing/oned/EAN13Reader.h \
$$PWD/zxing/oned/EAN8Reader.h \
$$PWD/zxing/oned/Code128Reader.h \
$$PWD/zxing/oned/Code39Reader.h \
$$PWD/zxing/qrcode/Version.h \
$$PWD/zxing/qrcode/QRCodeReader.h \
$$PWD/zxing/qrcode/FormatInformation.h \
$$PWD/zxing/qrcode/ErrorCorrectionLevel.h \
$$PWD/zxing/qrcode/decoder/Mode.h \
$$PWD/zxing/qrcode/decoder/Decoder.h \
$$PWD/zxing/qrcode/decoder/DecodedBitStreamParser.h \
$$PWD/zxing/qrcode/decoder/DataMask.h \
$$PWD/zxing/qrcode/decoder/DataBlock.h \
$$PWD/zxing/qrcode/decoder/BitMatrixParser.h \
$$PWD/zxing/qrcode/detector/QREdgeDetector.h \
$$PWD/zxing/qrcode/detector/FinderPatternInfo.h \
$$PWD/zxing/qrcode/detector/FinderPatternFinder.h \
$$PWD/zxing/qrcode/detector/FinderPattern.h \
$$PWD/zxing/qrcode/detector/Detector.h \
$$PWD/zxing/qrcode/detector/AlignmentPatternFinder.h \
$$PWD/zxing/qrcode/detector/AlignmentPattern.h \
$$PWD/zxing/multi/MultipleBarcodeReader.h \
$$PWD/zxing/multi/GenericMultipleBarcodeReader.h \
$$PWD/zxing/multi/ByQuadrantReader.h \
$$PWD/zxing/multi/qrcode/QRCodeMultiReader.h \
$$PWD/zxing/multi/qrcode/detector/MultiFinderPatternFinder.h \
$$PWD/zxing/multi/qrcode/detector/MultiDetector.h
SOURCES += \
$$PWD/CameraImageWrapper.cpp \
$$PWD/qzxing.cpp \
$$PWD/zxing/ResultPointCallback.cpp \
$$PWD/zxing/ResultPoint.cpp \
$$PWD/zxing/Result.cpp \
$$PWD/zxing/ReaderException.cpp \
$$PWD/zxing/Reader.cpp \
$$PWD/zxing/NotFoundException.cpp \
$$PWD/zxing/MultiFormatReader.cpp \
$$PWD/zxing/LuminanceSource.cpp \
$$PWD/zxing/FormatException.cpp \
$$PWD/zxing/Exception.cpp \
$$PWD/zxing/DecodeHints.cpp \
$$PWD/zxing/BinaryBitmap.cpp \
$$PWD/zxing/Binarizer.cpp \
$$PWD/zxing/BarcodeFormat.cpp \
$$PWD/zxing/aztec/AztecReader.cpp \
$$PWD/zxing/aztec/AztecDetectorResult.cpp \
$$PWD/zxing/common/StringUtils.cpp \
$$PWD/zxing/common/Str.cpp \
$$PWD/zxing/common/PerspectiveTransform.cpp \
$$PWD/zxing/common/IllegalArgumentException.cpp \
$$PWD/zxing/common/HybridBinarizer.cpp \
$$PWD/zxing/common/GridSampler.cpp \
$$PWD/zxing/common/GreyscaleRotatedLuminanceSource.cpp \
$$PWD/zxing/common/GreyscaleLuminanceSource.cpp \
$$PWD/zxing/common/GlobalHistogramBinarizer.cpp \
$$PWD/zxing/common/EdgeDetector.cpp \
$$PWD/zxing/common/DetectorResult.cpp \
$$PWD/zxing/common/DecoderResult.cpp \
$$PWD/zxing/common/Counted.cpp \
$$PWD/zxing/common/CharacterSetECI.cpp \
$$PWD/zxing/common/BitSource.cpp \
$$PWD/zxing/common/BitMatrix.cpp \
$$PWD/zxing/common/BitArray.cpp \
$$PWD/zxing/common/Array.cpp \
$$PWD/zxing/common/detector/WhiteRectangleDetector.cpp \
$$PWD/zxing/common/detector/MonochromeRectangleDetector.cpp \
$$PWD/zxing/common/reedsolomon/ReedSolomonException.cpp \
$$PWD/zxing/common/reedsolomon/ReedSolomonDecoder.cpp \
$$PWD/zxing/common/reedsolomon/GenericGFPoly.cpp \
$$PWD/zxing/common/reedsolomon/GenericGF.cpp \
$$PWD/zxing/datamatrix/DataMatrixReader.cpp \
$$PWD/zxing/oned/UPCEReader.cpp \
$$PWD/zxing/oned/UPCEANReader.cpp \
$$PWD/zxing/oned/UPCAReader.cpp \
$$PWD/zxing/oned/OneDResultPoint.cpp \
$$PWD/zxing/oned/OneDReader.cpp \
$$PWD/zxing/oned/MultiFormatUPCEANReader.cpp \
$$PWD/zxing/oned/MultiFormatOneDReader.cpp \
$$PWD/zxing/oned/ITFReader.cpp \
$$PWD/zxing/oned/EAN13Reader.cpp \
$$PWD/zxing/oned/EAN8Reader.cpp \
$$PWD/zxing/oned/Code128Reader.cpp \
$$PWD/zxing/oned/Code39Reader.cpp \
$$PWD/zxing/qrcode/QRCodeReader.cpp \
$$PWD/zxing/qrcode/detector/QREdgeDetector.cpp \
$$PWD/zxing/multi/MultipleBarcodeReader.cpp \
$$PWD/zxing/multi/GenericMultipleBarcodeReader.cpp \
$$PWD/zxing/multi/ByQuadrantReader.cpp \
$$PWD/zxing/multi/qrcode/QRCodeMultiReader.cpp \
$$PWD/zxing/multi/qrcode/detector/MultiFinderPatternFinder.cpp \
$$PWD/zxing/multi/qrcode/detector/MultiDetector.cpp \
$$PWD/zxing/aztec/decoder/AztecDecoder.cpp \
$$PWD/zxing/aztec/detector/AztecDetector.cpp \
$$PWD/zxing/datamatrix/DataMatrixVersion.cpp \
$$PWD/zxing/datamatrix/decoder/DataMatrixDecoder.cpp \
$$PWD/zxing/datamatrix/decoder/DataMatrixBitMatrixParser.cpp \
$$PWD/zxing/datamatrix/decoder/DataMatrixDataBlock.cpp \
$$PWD/zxing/datamatrix/decoder/DataMatrixDecodedBitStreamParser.cpp \
$$PWD/zxing/datamatrix/detector/DataMatrixCornerPoint.cpp \
$$PWD/zxing/datamatrix/detector/DataMatrixDetector.cpp \
$$PWD/zxing/datamatrix/detector/DataMatrixDetectorException.cpp \
$$PWD/zxing/datamatrix/detector/DataMatrixMonochromeRectangleDetector.cpp \
$$PWD/zxing/qrcode/decoder/QRBitMatrixParser.cpp \
$$PWD/zxing/qrcode/decoder/QRDataBlock.cpp \
$$PWD/zxing/qrcode/decoder/QRDataMask.cpp \
$$PWD/zxing/qrcode/decoder/QRDecodedBitStreamParser.cpp \
$$PWD/zxing/qrcode/decoder/QRDecoder.cpp \
$$PWD/zxing/qrcode/decoder/QRMode.cpp \
$$PWD/zxing/qrcode/detector/QRAlignmentPattern.cpp \
$$PWD/zxing/qrcode/detector/QRAlignmentPatternFinder.cpp \
$$PWD/zxing/qrcode/detector/QRDetector.cpp \
$$PWD/zxing/qrcode/detector/QRFinderPattern.cpp \
$$PWD/zxing/qrcode/detector/QRFinderPatternFinder.cpp \
$$PWD/zxing/qrcode/detector/QRFinderPatternInfo.cpp \
$$PWD/zxing/qrcode/QRVersion.cpp \
$$PWD/zxing/qrcode/QRFormatInformation.cpp \
$$PWD/zxing/qrcode/QRErrorCorrectionLevel.cpp

179
src/qzxing/qzxing.cpp Normal file
View file

@ -0,0 +1,179 @@
#include "qzxing.h"
#include <QtCore>
#include <zxing/common/GlobalHistogramBinarizer.h>
#include <zxing/Binarizer.h>
#include <zxing/BinaryBitmap.h>
#include <zxing/MultiFormatReader.h>
#include <zxing/DecodeHints.h>
#include "CameraImageWrapper.h"
using namespace zxing;
QZXing::QZXing(QObject *parent) : QObject(parent)
{
decoder = new MultiFormatReader();
setDecoder(DecoderFormat_QR_CODE);
/*setDecoder(DecoderFormat_QR_CODE |
DecoderFormat_DATA_MATRIX |
DecoderFormat_UPC_E |
DecoderFormat_UPC_A |
DecoderFormat_EAN_8 |
DecoderFormat_EAN_13 |
DecoderFormat_CODE_128 |
DecoderFormat_CODE_39 |
DecoderFormat_ITF |
DecoderFormat_Aztec);*/
}
QZXing::~QZXing() {
delete (MultiFormatReader*)decoder;
decoder = 0;
}
void QZXing::setDecoder(DecoderFormatType hint)
{
DecodeHints newHints;
if(hint & DecoderFormat_QR_CODE)
newHints.addFormat((BarcodeFormat)BarcodeFormat_QR_CODE);
if(hint & DecoderFormat_DATA_MATRIX)
newHints.addFormat((BarcodeFormat)BarcodeFormat_DATA_MATRIX);
if(hint & DecoderFormat_UPC_E)
newHints.addFormat((BarcodeFormat)BarcodeFormat_UPC_E);
if(hint & DecoderFormat_UPC_A)
newHints.addFormat((BarcodeFormat)BarcodeFormat_UPC_A);
if(hint & DecoderFormat_EAN_8)
newHints.addFormat((BarcodeFormat)BarcodeFormat_EAN_8);
if(hint & DecoderFormat_EAN_13)
newHints.addFormat((BarcodeFormat)BarcodeFormat_EAN_13);
if(hint & DecoderFormat_CODE_128)
newHints.addFormat((BarcodeFormat)BarcodeFormat_CODE_128);
if(hint & DecoderFormat_CODE_39)
newHints.addFormat((BarcodeFormat)BarcodeFormat_CODE_39);
if(hint & DecoderFormat_ITF)
newHints.addFormat((BarcodeFormat)BarcodeFormat_ITF);
if(hint & DecoderFormat_Aztec)
newHints.addFormat((BarcodeFormat)BarcodeFormat_AZTEC);
supportedFormats = newHints.getCurrentHint();
}
QString QZXing::decodeImage(QImage image)
{
Ref<Result> result;
emit decodingStarted();
try {
Ref<LuminanceSource> source(new CameraImageWrapper(image));
Ref<Binarizer> binarizer;
binarizer = new GlobalHistogramBinarizer(source);
Ref<BinaryBitmap> binary(new BinaryBitmap(binarizer));
DecodeHints hints((int)supportedFormats);
result = ((MultiFormatReader*)decoder)->decode(binary, hints);
QString string = QString(result->getText()->getText().c_str());
emit tagFound(string);
emit decodingFinished(true);
return string;
}
catch(zxing::Exception& e)
{
qDebug() << "[decodeImage()] Exception:" << e.what();
emit decodingFinished(false);
return "";
}
}
QVariantHash QZXing::decodeImageEx(QImage image)
{
QVariantHash resultMap;
Ref<Result> result;
emit decodingStarted();
try {
Ref<LuminanceSource> source(new CameraImageWrapper(image));
Ref<Binarizer> binarizer;
binarizer = new GlobalHistogramBinarizer(source);
Ref<BinaryBitmap> binary(new BinaryBitmap(binarizer));
DecodeHints hints((int)supportedFormats);
result = ((MultiFormatReader*)decoder)->decode(binary, hints);
QString string = QString(result->getText()->getText().c_str());
QList<QVariant> points;
emit tagFound(string);
emit decodingFinished(true);
resultMap.insert("content", string);
std::vector<Ref<ResultPoint> > resultPoints = result->getResultPoints();
for (unsigned int i = 0; i < resultPoints.size(); i++) {
points.append(QPoint(resultPoints[i]->getX(), resultPoints[i]->getY()));
}
resultMap.insert("points", points);
}
catch(zxing::Exception& e)
{
qDebug() << "[decodeImage()] Exception:" << e.what();
emit decodingFinished(false);
resultMap.insert("content", QString(""));
resultMap.insert("points", QList<QVariant>());
}
return resultMap;
}
QString QZXing::decodeImageFromFile(QString imageFilePath)
{
//used to have a check if this image exists
//but was removed because if the image file path doesn't point to a valid image
// then the QImage::isNull will return true and the decoding will fail eitherway.
return decodeImage(QImage(imageFilePath));
}
QString QZXing::decodeImageQML(const QUrl &imageUrl)
{
return decodeSubImageQML(imageUrl);
}
QString QZXing::decodeSubImageQML(const QUrl &imageUrl,
const double offsetX, const double offsetY,
const double width, const double height)
{
QString imagePath = imageUrl.path();
imagePath = imagePath.trimmed();
QFile file(imagePath);
if (!file.exists()) {
qDebug() << "[decodeSubImageQML()] The file" << file.fileName() << "does not exist.";
emit decodingFinished(false);
return "";
}
QImage img(imageUrl.path());
if(!(offsetX == 0 && offsetY == 0 && width == 0 && height == 0)) {
img = img.copy(offsetX, offsetY, width, height);
}
return decodeImage(img);
}

94
src/qzxing/qzxing.h Normal file
View file

@ -0,0 +1,94 @@
#ifndef QZXING_H
#define QZXING_H
#include "qzxing_global.h"
#include <QObject>
#include <QImage>
#include <QVariantHash>
#include <QtQuick>
/**
* A class containing a very very small subset of the ZXing library.
* Created for ease of use.
*
* Anyone interested in using more technical stuff
* from the ZXing library is welcomed to add/edit on free will.
*
* Regarding DecoderFormat, by default all of those are enabled (except DataMatrix will is still not supported)
*/
class QZXing : public QObject
{
Q_OBJECT
Q_ENUMS(DecoderFormat)
public:
enum DecoderFormat {
DecoderFormat_None = 0,
DecoderFormat_QR_CODE = 1,
DecoderFormat_DATA_MATRIX = 2,
DecoderFormat_UPC_E = 4,
DecoderFormat_UPC_A = 8,
DecoderFormat_EAN_8 = 16,
DecoderFormat_EAN_13 = 32,
DecoderFormat_CODE_128 = 64,
DecoderFormat_CODE_39 = 128,
DecoderFormat_ITF = 256,
DecoderFormat_Aztec = 512
} ;
typedef unsigned int DecoderFormatType;
public:
QZXing(QObject *parent = NULL);
virtual ~QZXing();
/**
* Set the enabled decoders.
* As argument it is possible to pass conjuction of decoders by using logic OR.
* e.x. setDecoder ( DecoderFormat_QR_CODE | DecoderFormat_EAN_13 | DecoderFormat_CODE_39 )
*/
void setDecoder(DecoderFormatType hint);
#if QT_VERSION >= 0x040700
static void registerQMLTypes()
{
qmlRegisterType<QZXing>("harbour.sailotp.QZXing", 2, 2, "QZXing");
}
#endif
public slots:
/**
* The decoding function. Will try to decode the given image based on the enabled decoders.
*
*/
QString decodeImage(QImage image);
QVariantHash decodeImageEx(QImage image);
/**
* The decoding function accessible from QML
*/
QString decodeImageQML(const QUrl &imageUrl);
QString decodeImageFromFile(QString imageFilePath);
/**
* The decoding function accessible from QML. Able to set the decoding
* of a portion of the image.
*/
QString decodeSubImageQML(const QUrl &imageUrl,
const double offsetX = 0 , const double offsetY = 0,
const double width = 0, const double height = 0);
signals:
void decodingStarted();
void decodingFinished(bool succeeded);
void tagFound(QString tag);
private:
void* decoder;
DecoderFormatType supportedFormats;
};
#endif // QZXING_H

View file

@ -0,0 +1,12 @@
#ifndef QZXING_GLOBAL_H
#define QZXING_GLOBAL_H
#include <QtCore/QtGlobal>
#if defined(QZXING_LIBRARY)
# define QZXINGSHARED_EXPORT Q_DECL_EXPORT
#else
# define QZXINGSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif //QZXING_GLOBAL_H

View file

@ -0,0 +1,37 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* Created by Christian Brunschen on 13/05/2008.
* Copyright 2008 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/BarcodeFormat.h>
namespace zxing {
const char *barcodeFormatNames[] = {
"None",
"QR_CODE",
"DATA_MATRIX",
"UPC_E",
"UPC_A",
"EAN_8",
"EAN_13",
"CODE_128",
"CODE_39",
"ITF",
"AZTEC"
};
}

View file

@ -0,0 +1,44 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __BARCODE_FORMAT_H__
#define __BARCODE_FORMAT_H__
/*
* BarcodeFormat.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace zxing {
typedef enum BarcodeFormat {
BarcodeFormat_None = 0,
BarcodeFormat_QR_CODE,
BarcodeFormat_DATA_MATRIX,
BarcodeFormat_UPC_E,
BarcodeFormat_UPC_A,
BarcodeFormat_EAN_8,
BarcodeFormat_EAN_13,
BarcodeFormat_CODE_128,
BarcodeFormat_CODE_39,
BarcodeFormat_ITF,
BarcodeFormat_AZTEC
} BarcodeFormat;
/* if you update the enum, please update the name in BarcodeFormat.cpp */
extern const char *barcodeFormatNames[];
}
#endif // __BARCODE_FORMAT_H__

View file

@ -0,0 +1,37 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* Binarizer.cpp
* zxing
*
* Created by Ralf Kistner on 16/10/2009.
* Copyright 2008 ZXing authors All rights reserved.
* Modified by Lukasz Warchol on 02/02/2010.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/Binarizer.h>
namespace zxing {
Binarizer::Binarizer(Ref<LuminanceSource> source) : source_(source) {
}
Binarizer::~Binarizer() {
}
Ref<LuminanceSource> Binarizer::getLuminanceSource() const {
return source_;
}
}

View file

@ -0,0 +1,46 @@
#ifndef BINARIZER_H_
#define BINARIZER_H_
/*
* Binarizer.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/LuminanceSource.h>
#include <zxing/common/BitArray.h>
#include <zxing/common/BitMatrix.h>
#include <zxing/common/Counted.h>
namespace zxing {
class Binarizer : public Counted {
private:
Ref<LuminanceSource> source_;
public:
Binarizer(Ref<LuminanceSource> source);
virtual ~Binarizer();
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row) = 0;
virtual Ref<BitMatrix> getBlackMatrix() = 0;
Ref<LuminanceSource> getLuminanceSource() const ;
virtual Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) = 0;
};
}
#endif /* BINARIZER_H_ */

View file

@ -0,0 +1,67 @@
/*
* BinaryBitmap.cpp
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/BinaryBitmap.h>
namespace zxing {
BinaryBitmap::BinaryBitmap(Ref<Binarizer> binarizer) : binarizer_(binarizer) {
}
BinaryBitmap::~BinaryBitmap() {
}
Ref<BitArray> BinaryBitmap::getBlackRow(int y, Ref<BitArray> row) {
return binarizer_->getBlackRow(y, row);
}
Ref<BitMatrix> BinaryBitmap::getBlackMatrix() {
return binarizer_->getBlackMatrix();
}
int BinaryBitmap::getWidth() const {
return getLuminanceSource()->getWidth();
}
int BinaryBitmap::getHeight() const {
return getLuminanceSource()->getHeight();
}
Ref<LuminanceSource> BinaryBitmap::getLuminanceSource() const {
return binarizer_->getLuminanceSource();
}
bool BinaryBitmap::isCropSupported() const {
return getLuminanceSource()->isCropSupported();
}
Ref<BinaryBitmap> BinaryBitmap::crop(int left, int top, int width, int height) {
return Ref<BinaryBitmap> (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->crop(left, top, width, height))));
}
bool BinaryBitmap::isRotateSupported() const {
return getLuminanceSource()->isRotateSupported();
}
Ref<BinaryBitmap> BinaryBitmap::rotateCounterClockwise() {
return Ref<BinaryBitmap> (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->rotateCounterClockwise())));
}
}

View file

@ -0,0 +1,57 @@
#ifndef __BINARYBITMAP_H__
#define __BINARYBITMAP_H__
/*
* BinaryBitmap.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/common/Counted.h>
#include <zxing/common/BitMatrix.h>
#include <zxing/common/BitArray.h>
#include <zxing/Binarizer.h>
namespace zxing {
class BinaryBitmap : public Counted {
private:
Ref<Binarizer> binarizer_;
int cached_y_;
public:
BinaryBitmap(Ref<Binarizer> binarizer);
virtual ~BinaryBitmap();
Ref<BitArray> getBlackRow(int y, Ref<BitArray> row);
Ref<BitMatrix> getBlackMatrix();
Ref<LuminanceSource> getLuminanceSource() const;
int getWidth() const;
int getHeight() const;
bool isRotateSupported() const;
Ref<BinaryBitmap> rotateCounterClockwise();
bool isCropSupported() const;
Ref<BinaryBitmap> crop(int left, int top, int width, int height);
};
}
#endif /* BINARYBITMAP_H_ */

View file

@ -0,0 +1,120 @@
/*
* DecodeHintType.cpp
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/DecodeHints.h>
#include <zxing/common/IllegalArgumentException.h>
namespace zxing {
const DecodeHintType DecodeHints::CHARACTER_SET;
const DecodeHints DecodeHints::PRODUCT_HINT(
BARCODEFORMAT_UPC_E_HINT |
BARCODEFORMAT_UPC_A_HINT |
BARCODEFORMAT_EAN_8_HINT |
BARCODEFORMAT_EAN_13_HINT);
const DecodeHints DecodeHints::ONED_HINT(
BARCODEFORMAT_UPC_E_HINT |
BARCODEFORMAT_UPC_A_HINT |
BARCODEFORMAT_EAN_8_HINT |
BARCODEFORMAT_EAN_13_HINT |
BARCODEFORMAT_CODE_128_HINT |
BARCODEFORMAT_CODE_39_HINT |
BARCODEFORMAT_ITF_HINT);
const DecodeHints DecodeHints::DEFAULT_HINT(
BARCODEFORMAT_UPC_E_HINT |
BARCODEFORMAT_UPC_A_HINT |
BARCODEFORMAT_EAN_8_HINT |
BARCODEFORMAT_EAN_13_HINT |
BARCODEFORMAT_CODE_128_HINT |
BARCODEFORMAT_CODE_39_HINT |
BARCODEFORMAT_ITF_HINT |
BARCODEFORMAT_DATA_MATRIX_HINT |
BARCODEFORMAT_AZTEC_HINT |
BARCODEFORMAT_QR_CODE_HINT);
DecodeHints::DecodeHints() {
hints = 0;
}
DecodeHints::DecodeHints(DecodeHintType init) {
hints = init;
}
void DecodeHints::addFormat(BarcodeFormat toadd) {
switch (toadd) {
case BarcodeFormat_AZTEC: hints |= BARCODEFORMAT_AZTEC_HINT; break;
case BarcodeFormat_QR_CODE: hints |= BARCODEFORMAT_QR_CODE_HINT; break;
case BarcodeFormat_DATA_MATRIX: hints |= BARCODEFORMAT_DATA_MATRIX_HINT; break;
case BarcodeFormat_UPC_E: hints |= BARCODEFORMAT_UPC_E_HINT; break;
case BarcodeFormat_UPC_A: hints |= BARCODEFORMAT_UPC_A_HINT; break;
case BarcodeFormat_EAN_8: hints |= BARCODEFORMAT_EAN_8_HINT; break;
case BarcodeFormat_EAN_13: hints |= BARCODEFORMAT_EAN_13_HINT; break;
case BarcodeFormat_CODE_128: hints |= BARCODEFORMAT_CODE_128_HINT; break;
case BarcodeFormat_CODE_39: hints |= BARCODEFORMAT_CODE_39_HINT; break;
case BarcodeFormat_ITF: hints |= BARCODEFORMAT_ITF_HINT; break;
default: throw IllegalArgumentException("Unrecognizd barcode format");
}
}
bool DecodeHints::containsFormat(BarcodeFormat tocheck) const {
DecodeHintType checkAgainst;
switch (tocheck) {
case BarcodeFormat_AZTEC: checkAgainst = BARCODEFORMAT_AZTEC_HINT; break;
case BarcodeFormat_QR_CODE: checkAgainst = BARCODEFORMAT_QR_CODE_HINT; break;
case BarcodeFormat_DATA_MATRIX: checkAgainst = BARCODEFORMAT_DATA_MATRIX_HINT; break;
case BarcodeFormat_UPC_E: checkAgainst = BARCODEFORMAT_UPC_E_HINT; break;
case BarcodeFormat_UPC_A: checkAgainst = BARCODEFORMAT_UPC_A_HINT; break;
case BarcodeFormat_EAN_8: checkAgainst = BARCODEFORMAT_EAN_8_HINT; break;
case BarcodeFormat_EAN_13: checkAgainst = BARCODEFORMAT_EAN_13_HINT; break;
case BarcodeFormat_CODE_128: checkAgainst = BARCODEFORMAT_CODE_128_HINT; break;
case BarcodeFormat_CODE_39: checkAgainst = BARCODEFORMAT_CODE_39_HINT; break;
case BarcodeFormat_ITF: checkAgainst = BARCODEFORMAT_ITF_HINT; break;
default: throw IllegalArgumentException("Unrecognizd barcode format");
}
return (hints & checkAgainst);
}
void DecodeHints::setTryHarder(bool toset) {
if (toset) {
hints |= TRYHARDER_HINT;
} else {
hints &= ~TRYHARDER_HINT;
}
}
bool DecodeHints::getTryHarder() const {
return (hints & TRYHARDER_HINT);
}
void DecodeHints::setResultPointCallback(Ref<ResultPointCallback> const& _callback) {
callback = _callback;
}
Ref<ResultPointCallback> DecodeHints::getResultPointCallback() const {
return callback;
}
DecodeHintType DecodeHints::getCurrentHint()
{
return hints;
}
} /* namespace */

View file

@ -0,0 +1,72 @@
#ifndef __DECODEHINTS_H_
#define __DECODEHINTS_H_
/*
* DecodeHintType.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/BarcodeFormat.h>
#include <zxing/ResultPointCallback.h>
namespace zxing {
typedef unsigned int DecodeHintType;
class DecodeHints {
private:
DecodeHintType hints;
Ref<ResultPointCallback> callback;
public:
static const DecodeHintType BARCODEFORMAT_QR_CODE_HINT = 1 << BarcodeFormat_QR_CODE;
static const DecodeHintType BARCODEFORMAT_DATA_MATRIX_HINT = 1 << BarcodeFormat_DATA_MATRIX;
static const DecodeHintType BARCODEFORMAT_UPC_E_HINT = 1 << BarcodeFormat_UPC_E;
static const DecodeHintType BARCODEFORMAT_UPC_A_HINT = 1 << BarcodeFormat_UPC_A;
static const DecodeHintType BARCODEFORMAT_EAN_8_HINT = 1 << BarcodeFormat_EAN_8;
static const DecodeHintType BARCODEFORMAT_EAN_13_HINT = 1 << BarcodeFormat_EAN_13;
static const DecodeHintType BARCODEFORMAT_CODE_128_HINT = 1 << BarcodeFormat_CODE_128;
static const DecodeHintType BARCODEFORMAT_CODE_39_HINT = 1 << BarcodeFormat_CODE_39;
static const DecodeHintType BARCODEFORMAT_ITF_HINT = 1 << BarcodeFormat_ITF;
static const DecodeHintType BARCODEFORMAT_AZTEC_HINT = 1 << BarcodeFormat_AZTEC;
static const DecodeHintType CHARACTER_SET = 1 << 30;
static const DecodeHintType TRYHARDER_HINT = 1 << 31;
static const DecodeHints PRODUCT_HINT;
static const DecodeHints ONED_HINT;
static const DecodeHints DEFAULT_HINT;
DecodeHints();
DecodeHints(DecodeHintType init);
void addFormat(BarcodeFormat toadd);
bool containsFormat(BarcodeFormat tocheck) const;
void setTryHarder(bool toset);
bool getTryHarder() const;
void setResultPointCallback(Ref<ResultPointCallback> const&);
Ref<ResultPointCallback> getResultPointCallback() const;
DecodeHintType getCurrentHint();
};
}
#endif

View file

@ -0,0 +1,40 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* Exception.cpp
* ZXing
*
* Created by Christian Brunschen on 03/06/2008.
* Copyright 2008-2011 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/Exception.h>
namespace zxing {
Exception::Exception() {}
Exception::Exception(const char *msg) :
message(msg) {
}
const char* Exception::what() const throw() {
return message.c_str();
}
Exception::~Exception() throw() {
}
}

View file

@ -0,0 +1,40 @@
#ifndef __EXCEPTION_H__
#define __EXCEPTION_H__
/*
* Exception.h
* ZXing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string>
#include <exception>
namespace zxing {
class Exception : public std::exception {
private:
std::string message;
public:
Exception();
Exception(const char *msg);
virtual const char* what() const throw();
virtual ~Exception() throw();
};
}
#endif // __EXCEPTION_H__

View file

@ -0,0 +1,35 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* FormatException.cpp
* zxing
*
* Created by Christian Brunschen on 13/05/2008.
* Copyright 2008 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/FormatException.h>
namespace zxing {
FormatException::FormatException() {}
FormatException::FormatException(const char *msg) :
ReaderException(msg) {
}
FormatException::~FormatException() throw() {
}
}

View file

@ -0,0 +1,35 @@
#ifndef __FORMAT_EXCEPTION_H__
#define __FORMAT_EXCEPTION_H__
/*
* FormatException.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/ReaderException.h>
namespace zxing {
class FormatException : public ReaderException {
public:
FormatException();
FormatException(const char *msg);
~FormatException() throw();
};
}
#endif // __FORMAT_EXCEPTION_H__

View file

@ -0,0 +1,80 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* LuminanceSource.cpp
* zxing
*
* Copyright 2008 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sstream>
#include <zxing/LuminanceSource.h>
#include <zxing/common/IllegalArgumentException.h>
namespace zxing {
LuminanceSource::LuminanceSource() {
}
LuminanceSource::~LuminanceSource() {
}
bool LuminanceSource::isCropSupported() const {
return false;
}
Ref<LuminanceSource> LuminanceSource::crop(int left, int top, int width, int height) {
(void)left;
(void)top;
(void)width;
(void)height;
throw IllegalArgumentException("This luminance source does not support cropping.");
}
bool LuminanceSource::isRotateSupported() const {
return false;
}
Ref<LuminanceSource> LuminanceSource::rotateCounterClockwise() {
throw IllegalArgumentException("This luminance source does not support rotation.");
}
LuminanceSource::operator std::string() {
unsigned char* row = 0;
std::ostringstream oss;
for (int y = 0; y < getHeight(); y++) {
row = getRow(y, row);
for (int x = 0; x < getWidth(); x++) {
int luminance = row[x] & 0xFF;
char c;
if (luminance < 0x40) {
c = '#';
} else if (luminance < 0x80) {
c = '+';
} else if (luminance < 0xC0) {
c = '.';
} else {
c = ' ';
}
oss << c;
}
oss << '\n';
}
delete [] row;
return oss.str();
}
}

View file

@ -0,0 +1,52 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __LUMINANCESOURCE_H__
#define __LUMINANCESOURCE_H__
/*
* LuminanceSource.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/common/Counted.h>
#include <string.h>
namespace zxing {
class LuminanceSource : public Counted {
public:
LuminanceSource();
virtual ~LuminanceSource();
virtual int getWidth() const = 0;
virtual int getHeight() const = 0;
// Callers take ownership of the returned memory and must call delete [] on it themselves.
virtual unsigned char* getRow(int y, unsigned char* row) = 0;
virtual unsigned char* getMatrix() = 0;
virtual bool isCropSupported() const;
virtual Ref<LuminanceSource> crop(int left, int top, int width, int height);
virtual bool isRotateSupported() const;
virtual Ref<LuminanceSource> rotateCounterClockwise();
operator std::string (); // should be const but don't want to make sure a
// large breaking change right now
};
}
#endif /* LUMINANCESOURCE_H_ */

View file

@ -0,0 +1,106 @@
/*
* MultiFormatBarcodeReader.cpp
* ZXing
*
* Created by Lukasz Warchol on 10-01-26.
* Modified by Luiz Silva on 09/02/2010.
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/MultiFormatReader.h>
#include <zxing/qrcode/QRCodeReader.h>
#include <zxing/datamatrix/DataMatrixReader.h>
#include <zxing/aztec/AztecReader.h>
#include <zxing/oned/MultiFormatUPCEANReader.h>
#include <zxing/oned/MultiFormatOneDReader.h>
#include <zxing/ReaderException.h>
namespace zxing {
MultiFormatReader::MultiFormatReader() {
}
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image) {
setHints(DecodeHints::DEFAULT_HINT);
return decodeInternal(image);
}
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
setHints(hints);
return decodeInternal(image);
}
Ref<Result> MultiFormatReader::decodeWithState(Ref<BinaryBitmap> image) {
// Make sure to set up the default state so we don't crash
if (readers_.size() == 0) {
setHints(DecodeHints::DEFAULT_HINT);
}
return decodeInternal(image);
}
void MultiFormatReader::setHints(DecodeHints hints) {
hints_ = hints;
readers_.clear();
bool tryHarder = hints.getTryHarder();
bool addOneDReader = hints.containsFormat(BarcodeFormat_UPC_E) ||
hints.containsFormat(BarcodeFormat_UPC_A) ||
hints.containsFormat(BarcodeFormat_EAN_8) ||
hints.containsFormat(BarcodeFormat_EAN_13) ||
hints.containsFormat(BarcodeFormat_CODE_128) ||
hints.containsFormat(BarcodeFormat_CODE_39) ||
hints.containsFormat(BarcodeFormat_ITF);
if (addOneDReader && !tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
}
if (hints.containsFormat(BarcodeFormat_QR_CODE)) {
readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));
}
if (hints.containsFormat(BarcodeFormat_DATA_MATRIX)) {
readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader()));
}
if (hints.containsFormat(BarcodeFormat_AZTEC)) {
readers_.push_back(Ref<Reader>(new zxing::aztec::AztecReader()));
}
//TODO: add PDF417 here once PDF417 reader is implemented
if (addOneDReader && tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
}
if (readers_.size() == 0) {
if (!tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
}
readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));
if (tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
}
}
}
Ref<Result> MultiFormatReader::decodeInternal(Ref<BinaryBitmap> image) {
for (unsigned int i = 0; i < readers_.size(); i++) {
try {
return readers_[i]->decode(image, hints_);
} catch (ReaderException const& re) {
// continue
}
}
throw ReaderException("No code detected");
}
MultiFormatReader::~MultiFormatReader() {
}
}

View file

@ -0,0 +1,49 @@
#ifndef __MULTI_FORMAT_READER_H__
#define __MULTI_FORMAT_READER_H__
/*
* MultiFormatBarcodeReader.h
* ZXing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/Reader.h>
#include <zxing/common/BitArray.h>
#include <zxing/Result.h>
#include <zxing/DecodeHints.h>
namespace zxing {
class MultiFormatReader : public Reader {
private:
Ref<Result> decodeInternal(Ref<BinaryBitmap> image);
std::vector<Ref<Reader> > readers_;
DecodeHints hints_;
public:
MultiFormatReader();
Ref<Result> decode(Ref<BinaryBitmap> image);
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
Ref<Result> decodeWithState(Ref<BinaryBitmap> image);
void setHints(DecodeHints hints);
~MultiFormatReader();
};
}
#endif

View file

@ -0,0 +1,28 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* Copyright 20011 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/NotFoundException.h>
namespace zxing {
NotFoundException::NotFoundException(const char *msg)
: ReaderException(msg) {}
NotFoundException::~NotFoundException() throw() {
}
}

View file

@ -0,0 +1,33 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __NOT_FOUND_EXCEPTION_H__
#define __NOT_FOUND_EXCEPTION_H__
/*
* Copyright 20011 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/ReaderException.h>
namespace zxing {
class NotFoundException : public ReaderException {
public:
NotFoundException(const char *msg);
~NotFoundException() throw();
};
}
#endif // __NOT_FOUND_EXCEPTION_H__

View file

@ -0,0 +1,31 @@
/*
* Reader.cpp
* zxing
*
* Created by Christian Brunschen on 13/05/2008.
* Copyright 2008 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/Reader.h>
namespace zxing {
Reader::~Reader() { }
Ref<Result> Reader::decode(Ref<BinaryBitmap> image) {
return decode(image, DecodeHints::DEFAULT_HINT);
}
}

40
src/qzxing/zxing/Reader.h Normal file
View file

@ -0,0 +1,40 @@
#ifndef __READER_H__
#define __READER_H__
/*
* Reader.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/BinaryBitmap.h>
#include <zxing/Result.h>
#include <zxing/DecodeHints.h>
namespace zxing {
class Reader : public Counted {
protected:
Reader() {}
public:
virtual Ref<Result> decode(Ref<BinaryBitmap> image);
virtual Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints) = 0;
virtual ~Reader();
};
}
#endif // __READER_H__

View file

@ -0,0 +1,35 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* ReaderException.cpp
* zxing
*
* Created by Christian Brunschen on 13/05/2008.
* Copyright 2008-2011 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/ReaderException.h>
namespace zxing {
ReaderException::ReaderException() {}
ReaderException::ReaderException(const char *msg) :
Exception(msg) {
}
ReaderException::~ReaderException() throw() {
}
}

View file

@ -0,0 +1,35 @@
#ifndef __READER_EXCEPTION_H__
#define __READER_EXCEPTION_H__
/*
* ReaderException.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/Exception.h>
namespace zxing {
class ReaderException : public Exception {
public:
ReaderException();
ReaderException(const char *msg);
~ReaderException() throw();
};
}
#endif // __READER_EXCEPTION_H__

View file

@ -0,0 +1,64 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* Result.cpp
* zxing
*
* Created by Christian Brunschen on 13/05/2008.
* Copyright 2008 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/Result.h>
namespace zxing {
using namespace std;
Result::Result(Ref<String> text, ArrayRef<unsigned char> rawBytes, std::vector<Ref<ResultPoint> > resultPoints,
BarcodeFormat format) :
text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format) {
}
Result::~Result() {
}
Ref<String> Result::getText() {
return text_;
}
ArrayRef<unsigned char> Result::getRawBytes() {
return rawBytes_;
}
const std::vector<Ref<ResultPoint> >& Result::getResultPoints() const {
return resultPoints_;
}
std::vector<Ref<ResultPoint> >& Result::getResultPoints() {
return resultPoints_;
}
BarcodeFormat Result::getBarcodeFormat() const {
return format_;
}
ostream& operator<<(ostream &out, Result& result) {
if (result.text_ != 0) {
out << result.text_->getText();
} else {
out << "[" << result.rawBytes_->size() << " bytes]";
}
return out;
}
}

54
src/qzxing/zxing/Result.h Normal file
View file

@ -0,0 +1,54 @@
#ifndef __RESULT_H__
#define __RESULT_H__
/*
* Result.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string>
#include <vector>
#include <zxing/common/Array.h>
#include <zxing/common/Counted.h>
#include <zxing/common/Str.h>
#include <zxing/ResultPoint.h>
#include <zxing/BarcodeFormat.h>
namespace zxing {
class Result : public Counted {
private:
Ref<String> text_;
ArrayRef<unsigned char> rawBytes_;
std::vector<Ref<ResultPoint> > resultPoints_;
BarcodeFormat format_;
public:
Result(Ref<String> text, ArrayRef<unsigned char> rawBytes, std::vector<Ref<ResultPoint> > resultPoints,
BarcodeFormat format);
~Result();
Ref<String> getText();
ArrayRef<unsigned char> getRawBytes();
const std::vector<Ref<ResultPoint> >& getResultPoints() const;
std::vector<Ref<ResultPoint> >& getResultPoints();
BarcodeFormat getBarcodeFormat() const;
friend std::ostream& operator<<(std::ostream &out, Result& result);
};
}
#endif // __RESULT_H__

View file

@ -0,0 +1,100 @@
/*
* ResultPoint.cpp
* zxing
*
* Created by Christian Brunschen on 13/05/2008.
* Copyright 2008 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/ResultPoint.h>
#include <math.h>
namespace zxing {
ResultPoint::ResultPoint() : posX_(0), posY_(0) {}
ResultPoint::ResultPoint(float x, float y) : posX_(x), posY_(y) {}
ResultPoint::~ResultPoint() {}
float ResultPoint::getX() const {
return posX_;
}
float ResultPoint::getY() const {
return posY_;
}
bool ResultPoint::equals(Ref<ResultPoint> other) {
return posX_ == other->getX() && posY_ == other->getY();
}
/**
* <p>Orders an array of three ResultPoints in an order [A,B,C] such that AB < AC and
* BC < AC and the angle between BC and BA is less than 180 degrees.
*/
void ResultPoint::orderBestPatterns(std::vector<Ref<ResultPoint> > &patterns) {
// Find distances between pattern centers
float zeroOneDistance = distance(patterns[0]->getX(), patterns[1]->getX(),patterns[0]->getY(), patterns[1]->getY());
float oneTwoDistance = distance(patterns[1]->getX(), patterns[2]->getX(),patterns[1]->getY(), patterns[2]->getY());
float zeroTwoDistance = distance(patterns[0]->getX(), patterns[2]->getX(),patterns[0]->getY(), patterns[2]->getY());
Ref<ResultPoint> pointA, pointB, pointC;
// Assume one closest to other two is B; A and C will just be guesses at first
if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
pointB = patterns[0];
pointA = patterns[1];
pointC = patterns[2];
} else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
pointB = patterns[1];
pointA = patterns[0];
pointC = patterns[2];
} else {
pointB = patterns[2];
pointA = patterns[0];
pointC = patterns[1];
}
// Use cross product to figure out whether A and C are correct or flipped.
// This asks whether BC x BA has a positive z component, which is the arrangement
// we want for A, B, C. If it's negative, then we've got it flipped around and
// should swap A and C.
if (crossProductZ(pointA, pointB, pointC) < 0.0f) {
Ref<ResultPoint> temp = pointA;
pointA = pointC;
pointC = temp;
}
patterns[0] = pointA;
patterns[1] = pointB;
patterns[2] = pointC;
}
float ResultPoint::distance(Ref<ResultPoint> point1, Ref<ResultPoint> point2) {
return distance(point1->getX(), point1->getY(), point2->getX(), point2->getY());
}
float ResultPoint::distance(float x1, float x2, float y1, float y2) {
float xDiff = x1 - x2;
float yDiff = y1 - y2;
return (float) sqrt((double) (xDiff * xDiff + yDiff * yDiff));
}
float ResultPoint::crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC) {
float bX = pointB->getX();
float bY = pointB->getY();
return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX));
}
}

View file

@ -0,0 +1,54 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __RESULT_POINT_H__
#define __RESULT_POINT_H__
/*
* ResultPoint.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/common/Counted.h>
#include <vector>
namespace zxing {
class ResultPoint : public Counted {
protected:
float posX_;
float posY_;
public:
ResultPoint();
ResultPoint(float x, float y);
virtual ~ResultPoint();
virtual float getX() const;
virtual float getY() const;
bool equals(Ref<ResultPoint> other);
static void orderBestPatterns(std::vector<Ref<ResultPoint> > &patterns);
static float distance(Ref<ResultPoint> point1, Ref<ResultPoint> point2);
static float distance(float x1, float x2, float y1, float y2);
private:
static float crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC);
};
}
#endif // __RESULT_POINT_H__

View file

@ -0,0 +1,26 @@
/*
* ResultPointCallback.cpp
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/ResultPointCallback.h>
namespace zxing {
ResultPointCallback::~ResultPointCallback() {}
}

View file

@ -0,0 +1,39 @@
#ifndef __RESULT_POINT_CALLBACK_H__
#define __RESULT_POINT_CALLBACK_H__
/*
* ResultPointCallback.h
* zxing
*
* Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/common/Counted.h>
namespace zxing {
class ResultPoint;
class ResultPointCallback : public Counted {
protected:
ResultPointCallback() {}
public:
virtual void foundPossibleResultPoint(ResultPoint const& point) = 0;
virtual ~ResultPointCallback();
};
}
#endif // __RESULT_POINT_CALLBACK_H__

View file

@ -0,0 +1,45 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* AtztecDetecorResult.cpp
* zxing
*
* Created by Lukas Stabe on 08/02/2012.
* Copyright 2012 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/aztec/AztecDetectorResult.h>
namespace zxing {
namespace aztec {
AztecDetectorResult::AztecDetectorResult(Ref<BitMatrix> bits, std::vector<Ref<ResultPoint> > points, bool compact, int nbDatablocks, int nbLayers)
: DetectorResult(bits, points),
compact_(compact),
nbDatablocks_(nbDatablocks),
nbLayers_(nbLayers) {
}
bool AztecDetectorResult::isCompact() {
return compact_;
}
int AztecDetectorResult::getNBDatablocks() {
return nbDatablocks_;
}
int AztecDetectorResult::getNBLayers() {
return nbLayers_;
}
}
}

View file

@ -0,0 +1,42 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* AtztecDetecorResult.h
* zxing
*
* Created by Lukas Stabe on 08/02/2012.
* Copyright 2012 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/common/DetectorResult.h>
#ifndef ZXingWidget_AtztecDetecorResult_h
#define ZXingWidget_AtztecDetecorResult_h
namespace zxing {
namespace aztec {
class AztecDetectorResult : public DetectorResult {
private:
bool compact_;
int nbDatablocks_, nbLayers_;
public:
AztecDetectorResult(Ref<BitMatrix> bits, std::vector<Ref<ResultPoint> > points, bool compact, int nbDatablocks, int nbLayers);
bool isCompact();
int getNBDatablocks();
int getNBLayers();
};
}
}
#endif

View file

@ -0,0 +1,64 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* AztecReader.cpp
* zxing
*
* Created by Lukas Stabe on 08/02/2012.
* Copyright 2012 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/aztec/AztecReader.h>
#include <zxing/aztec/detector/Detector.h>
#include <iostream>
namespace zxing {
namespace aztec {
AztecReader::AztecReader() : decoder_() {
// nothing
}
Ref<Result> AztecReader::decode(Ref<zxing::BinaryBitmap> image) {
Detector detector(image->getBlackMatrix());
Ref<AztecDetectorResult> detectorResult(detector.detect());
std::vector<Ref<ResultPoint> > points(detectorResult->getPoints());
Ref<DecoderResult> decoderResult(decoder_.decode(detectorResult));
Ref<Result> result(new Result(decoderResult->getText(),
decoderResult->getRawBytes(),
points,
BarcodeFormat_AZTEC));
return result;
}
Ref<Result> AztecReader::decode(Ref<BinaryBitmap> image, DecodeHints) {
//cout << "decoding with hints not supported for aztec" << "\n" << flush;
return this->decode(image);
}
AztecReader::~AztecReader() {
// nothing
}
Decoder& AztecReader::getDecoder() {
return decoder_;
}
}
}

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