diff --git a/config.xml b/config.xml index b1b64b1..a1f5a67 100644 --- a/config.xml +++ b/config.xml @@ -1,5 +1,5 @@ - + TerranQuest Augmented Reality fantasy game diff --git a/nbproject/plugins.properties b/nbproject/plugins.properties index dc5c041..50218b4 100644 --- a/nbproject/plugins.properties +++ b/nbproject/plugins.properties @@ -9,7 +9,7 @@ # For more information about plugins see http://cordova.apache.org/blog/releases/2013/07/23/cordova-3.html # -com.phonegap.plugins.barcodescanner=https://github.com/phonegap/phonegap-plugin-barcodescanner.git +phonegap-plugin-barcodescanner=https://github.com/phonegap/phonegap-plugin-barcodescanner.git cordova-plugin-whitelist=https://github.com/apache/cordova-plugin-whitelist.git cordova-plugin-splashscreen=https://git-wip-us.apache.org/repos/asf/cordova-plugin-splashscreen.git cordova-plugin-dialogs=https://git-wip-us.apache.org/repos/asf/cordova-plugin-dialogs.git diff --git a/platforms/android/.gradle/2.13/taskArtifacts/cache.properties b/platforms/android/.gradle/2.13/taskArtifacts/cache.properties new file mode 100644 index 0000000..6a2549a --- /dev/null +++ b/platforms/android/.gradle/2.13/taskArtifacts/cache.properties @@ -0,0 +1 @@ +#Sun Aug 07 13:14:29 MDT 2016 diff --git a/platforms/android/.gradle/2.13/taskArtifacts/cache.properties.lock b/platforms/android/.gradle/2.13/taskArtifacts/cache.properties.lock new file mode 100644 index 0000000..5df9cda Binary files /dev/null and b/platforms/android/.gradle/2.13/taskArtifacts/cache.properties.lock differ diff --git a/platforms/android/.gradle/2.13/taskArtifacts/fileHashes.bin b/platforms/android/.gradle/2.13/taskArtifacts/fileHashes.bin new file mode 100644 index 0000000..c748a0f Binary files /dev/null and b/platforms/android/.gradle/2.13/taskArtifacts/fileHashes.bin differ diff --git a/platforms/android/.gradle/2.13/taskArtifacts/fileSnapshots.bin b/platforms/android/.gradle/2.13/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..473ca43 Binary files /dev/null and b/platforms/android/.gradle/2.13/taskArtifacts/fileSnapshots.bin differ diff --git a/platforms/android/.gradle/2.13/taskArtifacts/taskArtifacts.bin b/platforms/android/.gradle/2.13/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..23a3ec0 Binary files /dev/null and b/platforms/android/.gradle/2.13/taskArtifacts/taskArtifacts.bin differ diff --git a/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin new file mode 100644 index 0000000..d2c3ba3 Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin differ diff --git a/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock new file mode 100644 index 0000000..fb6617e Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock differ diff --git a/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin new file mode 100644 index 0000000..eb29afb Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin differ diff --git a/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock new file mode 100644 index 0000000..2fe1614 Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock differ diff --git a/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin new file mode 100644 index 0000000..d2c3ba3 Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin differ diff --git a/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock new file mode 100644 index 0000000..630e60e Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock differ diff --git a/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin new file mode 100644 index 0000000..eb29afb Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin differ diff --git a/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock new file mode 100644 index 0000000..789bcce Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_CordovaLib_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock differ diff --git a/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin b/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin new file mode 100644 index 0000000..fbb88f0 Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin differ diff --git a/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock b/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock new file mode 100644 index 0000000..e953d74 Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock differ diff --git a/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin b/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin new file mode 100644 index 0000000..a0a6ef2 Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin differ diff --git a/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock b/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock new file mode 100644 index 0000000..b5f6997 Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock differ diff --git a/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin b/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin new file mode 100644 index 0000000..f1aecd9 Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin differ diff --git a/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock b/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock new file mode 100644 index 0000000..be5c74f Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock differ diff --git a/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin b/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin new file mode 100644 index 0000000..54b3b77 Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin differ diff --git a/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock b/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock new file mode 100644 index 0000000..85bbb1e Binary files /dev/null and b/platforms/android/.gradle/2.13/tasks/_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock differ diff --git a/platforms/android/.gradle/2.2.1/taskArtifacts/cache.properties.lock b/platforms/android/.gradle/2.2.1/taskArtifacts/cache.properties.lock index 5a38500..84a7807 100644 Binary files a/platforms/android/.gradle/2.2.1/taskArtifacts/cache.properties.lock and b/platforms/android/.gradle/2.2.1/taskArtifacts/cache.properties.lock differ diff --git a/platforms/android/.gradle/2.2.1/taskArtifacts/fileHashes.bin b/platforms/android/.gradle/2.2.1/taskArtifacts/fileHashes.bin index b760d26..6d6f069 100644 Binary files a/platforms/android/.gradle/2.2.1/taskArtifacts/fileHashes.bin and b/platforms/android/.gradle/2.2.1/taskArtifacts/fileHashes.bin differ diff --git a/platforms/android/.gradle/2.2.1/taskArtifacts/fileSnapshots.bin b/platforms/android/.gradle/2.2.1/taskArtifacts/fileSnapshots.bin index 25495c3..1610f20 100644 Binary files a/platforms/android/.gradle/2.2.1/taskArtifacts/fileSnapshots.bin and b/platforms/android/.gradle/2.2.1/taskArtifacts/fileSnapshots.bin differ diff --git a/platforms/android/.gradle/2.2.1/taskArtifacts/outputFileStates.bin b/platforms/android/.gradle/2.2.1/taskArtifacts/outputFileStates.bin index 133a8f3..0312bf9 100644 Binary files a/platforms/android/.gradle/2.2.1/taskArtifacts/outputFileStates.bin and b/platforms/android/.gradle/2.2.1/taskArtifacts/outputFileStates.bin differ diff --git a/platforms/android/.gradle/2.2.1/taskArtifacts/taskArtifacts.bin b/platforms/android/.gradle/2.2.1/taskArtifacts/taskArtifacts.bin index f19b833..18cabec 100644 Binary files a/platforms/android/.gradle/2.2.1/taskArtifacts/taskArtifacts.bin and b/platforms/android/.gradle/2.2.1/taskArtifacts/taskArtifacts.bin differ diff --git a/platforms/android/AndroidManifest.xml b/platforms/android/AndroidManifest.xml index 8dcd319..63cb069 100644 --- a/platforms/android/AndroidManifest.xml +++ b/platforms/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + @@ -9,6 +9,24 @@ + + + + + + + + + + + + + + + + + + @@ -19,4 +37,7 @@ + + + diff --git a/platforms/android/CordovaLib/build.gradle b/platforms/android/CordovaLib/build.gradle index f1c6682..ee0b776 100644 --- a/platforms/android/CordovaLib/build.gradle +++ b/platforms/android/CordovaLib/build.gradle @@ -24,12 +24,12 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.5.0' + classpath 'com.android.tools.build:gradle:2.1.0' } } -apply plugin: 'android-library' +apply plugin: 'com.android.library' ext { apply from: 'cordova.gradle' diff --git a/platforms/android/CordovaLib/build/intermediates/bundles/debug/classes.jar b/platforms/android/CordovaLib/build/intermediates/bundles/debug/classes.jar index 9f717bd..229a6e9 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/bundles/debug/classes.jar and b/platforms/android/CordovaLib/build/intermediates/bundles/debug/classes.jar differ diff --git a/platforms/android/CordovaLib/build/intermediates/bundles/release/classes.jar b/platforms/android/CordovaLib/build/intermediates/bundles/release/classes.jar index fd94b19..cb148e1 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/bundles/release/classes.jar and b/platforms/android/CordovaLib/build/intermediates/bundles/release/classes.jar differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CallbackMap.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CallbackMap.class new file mode 100644 index 0000000..462375d Binary files /dev/null and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CallbackMap.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaActivity.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaActivity.class index efd1ee6..4ff30c1 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaActivity.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaActivity.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaInterfaceImpl$ActivityResultHolder.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaInterfaceImpl$ActivityResultHolder.class index 8562638..2fdcd6b 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaInterfaceImpl$ActivityResultHolder.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaInterfaceImpl$ActivityResultHolder.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaInterfaceImpl.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaInterfaceImpl.class index 718b002..f808f34 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaInterfaceImpl.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaInterfaceImpl.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebView.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebView.class index feaba8c..fcd4dde 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebView.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebView.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$1.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$1.class index 4cf05bb..0f8b669 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$1.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$1.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$2.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$2.class index af9110d..8b5f2f9 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$2.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$2.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$3.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$3.class index e5c567e..fb8413c 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$3.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$3.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient$1$1.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient$1$1.class index 1370f66..429104c 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient$1$1.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient$1$1.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient$1.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient$1.class index a93f937..2ca9913 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient$1.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient$1.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient.class index 4df9559..df31a26 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl$EngineClient.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl.class index 5100928..7d7769e 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/CordovaWebViewImpl.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/engine/SystemCookieManager.class b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/engine/SystemCookieManager.class index 55051d0..4d1199c 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/engine/SystemCookieManager.class and b/platforms/android/CordovaLib/build/intermediates/classes/debug/org/apache/cordova/engine/SystemCookieManager.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CallbackMap.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CallbackMap.class new file mode 100644 index 0000000..462375d Binary files /dev/null and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CallbackMap.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaActivity.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaActivity.class index efd1ee6..4ff30c1 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaActivity.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaActivity.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaInterfaceImpl$ActivityResultHolder.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaInterfaceImpl$ActivityResultHolder.class index 8562638..2fdcd6b 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaInterfaceImpl$ActivityResultHolder.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaInterfaceImpl$ActivityResultHolder.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaInterfaceImpl.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaInterfaceImpl.class index 718b002..f808f34 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaInterfaceImpl.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaInterfaceImpl.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebView.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebView.class index feaba8c..fcd4dde 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebView.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebView.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$1.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$1.class index 4cf05bb..0f8b669 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$1.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$1.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$2.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$2.class index af9110d..8b5f2f9 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$2.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$2.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$3.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$3.class index e5c567e..fb8413c 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$3.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$3.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient$1$1.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient$1$1.class index 1370f66..429104c 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient$1$1.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient$1$1.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient$1.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient$1.class index a93f937..2ca9913 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient$1.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient$1.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient.class index 4df9559..df31a26 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl$EngineClient.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl.class index 5100928..7d7769e 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/CordovaWebViewImpl.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/engine/SystemCookieManager.class b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/engine/SystemCookieManager.class index 55051d0..4d1199c 100644 Binary files a/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/engine/SystemCookieManager.class and b/platforms/android/CordovaLib/build/intermediates/classes/release/org/apache/cordova/engine/SystemCookieManager.class differ diff --git a/platforms/android/CordovaLib/build/intermediates/incremental-safeguard/debug/tag.txt b/platforms/android/CordovaLib/build/intermediates/incremental-safeguard/debug/tag.txt new file mode 100644 index 0000000..c01a13d --- /dev/null +++ b/platforms/android/CordovaLib/build/intermediates/incremental-safeguard/debug/tag.txt @@ -0,0 +1 @@ +incremental task execution \ No newline at end of file diff --git a/platforms/android/CordovaLib/build/intermediates/incremental-safeguard/release/tag.txt b/platforms/android/CordovaLib/build/intermediates/incremental-safeguard/release/tag.txt new file mode 100644 index 0000000..c01a13d --- /dev/null +++ b/platforms/android/CordovaLib/build/intermediates/incremental-safeguard/release/tag.txt @@ -0,0 +1 @@ +incremental task execution \ No newline at end of file diff --git a/platforms/android/CordovaLib/build/intermediates/incremental/mergeDebugAssets/merger.xml b/platforms/android/CordovaLib/build/intermediates/incremental/mergeDebugAssets/merger.xml index 358319f..bcf44ba 100644 --- a/platforms/android/CordovaLib/build/intermediates/incremental/mergeDebugAssets/merger.xml +++ b/platforms/android/CordovaLib/build/intermediates/incremental/mergeDebugAssets/merger.xml @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/platforms/android/CordovaLib/build/intermediates/incremental/mergeDebugShaders/merger.xml b/platforms/android/CordovaLib/build/intermediates/incremental/mergeDebugShaders/merger.xml new file mode 100644 index 0000000..7e9fb17 --- /dev/null +++ b/platforms/android/CordovaLib/build/intermediates/incremental/mergeDebugShaders/merger.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/platforms/android/CordovaLib/build/intermediates/incremental/mergeReleaseAssets/merger.xml b/platforms/android/CordovaLib/build/intermediates/incremental/mergeReleaseAssets/merger.xml index b159f49..79903a2 100644 --- a/platforms/android/CordovaLib/build/intermediates/incremental/mergeReleaseAssets/merger.xml +++ b/platforms/android/CordovaLib/build/intermediates/incremental/mergeReleaseAssets/merger.xml @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/platforms/android/CordovaLib/build/intermediates/incremental/mergeReleaseShaders/merger.xml b/platforms/android/CordovaLib/build/intermediates/incremental/mergeReleaseShaders/merger.xml new file mode 100644 index 0000000..f45782f --- /dev/null +++ b/platforms/android/CordovaLib/build/intermediates/incremental/mergeReleaseShaders/merger.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/platforms/android/CordovaLib/build/outputs/aar/CordovaLib-debug.aar b/platforms/android/CordovaLib/build/outputs/aar/CordovaLib-debug.aar index 48f336c..8ffeb4b 100644 Binary files a/platforms/android/CordovaLib/build/outputs/aar/CordovaLib-debug.aar and b/platforms/android/CordovaLib/build/outputs/aar/CordovaLib-debug.aar differ diff --git a/platforms/android/CordovaLib/build/outputs/aar/CordovaLib-release.aar b/platforms/android/CordovaLib/build/outputs/aar/CordovaLib-release.aar index fc00c5d..98fdee0 100644 Binary files a/platforms/android/CordovaLib/build/outputs/aar/CordovaLib-release.aar and b/platforms/android/CordovaLib/build/outputs/aar/CordovaLib-release.aar differ diff --git a/platforms/android/CordovaLib/cordova.gradle b/platforms/android/CordovaLib/cordova.gradle index 7465266..746b63a 100644 --- a/platforms/android/CordovaLib/cordova.gradle +++ b/platforms/android/CordovaLib/cordova.gradle @@ -61,7 +61,7 @@ String doFindLatestInstalledBuildTools(String minBuildToolsVersion) { highestBuildToolsVersion } else { throw new RuntimeException( - "No installed build tools found. Please install the Android build tools version " + + "No installed build tools found. Install the Android build tools version " + minBuildToolsVersion + " or higher.") } } diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CallbackMap.java b/platforms/android/CordovaLib/src/org/apache/cordova/CallbackMap.java new file mode 100644 index 0000000..050daa0 --- /dev/null +++ b/platforms/android/CordovaLib/src/org/apache/cordova/CallbackMap.java @@ -0,0 +1,65 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ +package org.apache.cordova; + +import android.util.Pair; +import android.util.SparseArray; + +/** + * Provides a collection that maps unique request codes to CordovaPlugins and Integers. + * Used to ensure that when plugins make requests for runtime permissions, those requests do not + * collide with requests from other plugins that use the same request code value. + */ +public class CallbackMap { + private int currentCallbackId = 0; + private SparseArray> callbacks; + + public CallbackMap() { + this.callbacks = new SparseArray>(); + } + + /** + * Stores a CordovaPlugin and request code and returns a new unique request code to use + * in a permission request. + * + * @param receiver The plugin that is making the request + * @param requestCode The original request code used by the plugin + * @return A unique request code that can be used to retrieve this callback + * with getAndRemoveCallback() + */ + public synchronized int registerCallback(CordovaPlugin receiver, int requestCode) { + int mappedId = this.currentCallbackId++; + callbacks.put(mappedId, new Pair(receiver, requestCode)); + return mappedId; + } + + /** + * Retrieves and removes a callback stored in the map using the mapped request code + * obtained from registerCallback() + * + * @param mappedId The request code obtained from registerCallback() + * @return The CordovaPlugin and orignal request code that correspond to the + * given mappedCode + */ + public synchronized Pair getAndRemoveCallback(int mappedId) { + Pair callback = callbacks.get(mappedId); + callbacks.remove(mappedId); + return callback; + } +} diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java index d1420b6..db94e66 100644 --- a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java +++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.util.Log; +import android.util.Pair; import org.json.JSONException; import org.json.JSONObject; @@ -42,8 +43,8 @@ public class CordovaInterfaceImpl implements CordovaInterface { protected PluginManager pluginManager; protected ActivityResultHolder savedResult; + protected CallbackMap permissionResultCallbacks; protected CordovaPlugin activityResultCallback; - protected CordovaPlugin permissionResultCallback; protected String initCallbackService; protected int activityResultRequestCode; protected boolean activityWasDestroyed = false; @@ -56,6 +57,7 @@ public class CordovaInterfaceImpl implements CordovaInterface { public CordovaInterfaceImpl(Activity activity, ExecutorService threadPool) { this.activity = activity; this.threadPool = threadPool; + this.permissionResultCallbacks = new CallbackMap(); } @Override @@ -208,24 +210,21 @@ public class CordovaInterfaceImpl implements CordovaInterface { */ public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException { - if(permissionResultCallback != null) - { - permissionResultCallback.onRequestPermissionResult(requestCode, permissions, grantResults); - permissionResultCallback = null; + Pair callback = permissionResultCallbacks.getAndRemoveCallback(requestCode); + if(callback != null) { + callback.first.onRequestPermissionResult(callback.second, permissions, grantResults); } } public void requestPermission(CordovaPlugin plugin, int requestCode, String permission) { - permissionResultCallback = plugin; String[] permissions = new String [1]; permissions[0] = permission; - getActivity().requestPermissions(permissions, requestCode); + requestPermissions(plugin, requestCode, permissions); } - public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) - { - permissionResultCallback = plugin; - getActivity().requestPermissions(permissions, requestCode); + public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) { + int mappedRequestCode = permissionResultCallbacks.registerCallback(plugin, requestCode); + getActivity().requestPermissions(permissions, mappedRequestCode); } public boolean hasPermission(String permission) diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java index 6b0abca..85a800d 100644 --- a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java +++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java @@ -31,7 +31,7 @@ import android.webkit.WebChromeClient.CustomViewCallback; * are not expected to implement it. */ public interface CordovaWebView { - public static final String CORDOVA_VERSION = "5.1.1"; + public static final String CORDOVA_VERSION = "5.2.1"; void init(CordovaInterface cordova, List pluginEntries, CordovaPreferences preferences); diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java index f83e487..f0b73bf 100644 --- a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java +++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java @@ -135,6 +135,7 @@ public class CordovaWebViewImpl implements CordovaWebView { if (recreatePlugins) { // Don't re-initialize on first load. if (loadedUrl != null) { + appPlugin = null; pluginManager.init(); } loadedUrl = url; diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java index b88909e..acf795f 100644 --- a/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java +++ b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java @@ -37,6 +37,9 @@ class SystemCookieManager implements ICordovaCookieManager { webView = webview; cookieManager = CookieManager.getInstance(); + //REALLY? Nobody has seen this UNTIL NOW? + cookieManager.setAcceptFileSchemeCookies(true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { cookieManager.setAcceptThirdPartyCookies(webView, true); } diff --git a/platforms/android/android.json b/platforms/android/android.json index f96ebe5..b0d930f 100644 --- a/platforms/android/android.json +++ b/platforms/android/android.json @@ -47,6 +47,10 @@ { "xml": "", "count": 1 + }, + { + "xml": "", + "count": 1 } ] } @@ -87,8 +91,34 @@ "count": 1 } ], - "/manifest/application": [], - "/manifest": [] + "/manifest/application": [ + { + "xml": "", + "count": 1 + }, + { + "xml": "", + "count": 1 + }, + { + "xml": "", + "count": 1 + } + ], + "/manifest": [ + { + "xml": "", + "count": 1 + }, + { + "xml": "", + "count": 1 + }, + { + "xml": "", + "count": 1 + } + ] } } } @@ -129,6 +159,9 @@ }, "cordova-plugin-whitelist": { "PACKAGE_NAME": "com.netsyms.terranquest.TerranQuest" + }, + "phonegap-plugin-barcodescanner": { + "PACKAGE_NAME": "com.netsyms.terranquest.TerranQuest" } }, "dependent_plugins": {}, @@ -434,6 +467,14 @@ "file": "plugins/cordova-plugin-whitelist/whitelist.js", "id": "cordova-plugin-whitelist.whitelist", "runs": true + }, + { + "id": "phonegap-plugin-barcodescanner.BarcodeScanner", + "file": "plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js", + "pluginId": "phonegap-plugin-barcodescanner", + "clobbers": [ + "cordova.plugins.barcodeScanner" + ] } ], "plugin_metadata": { @@ -448,6 +489,7 @@ "cordova-plugin-media-capture": "1.2.1-dev", "cordova-plugin-network-information": "1.2.1-dev", "cordova-plugin-splashscreen": "3.2.2-dev", - "cordova-plugin-whitelist": "1.2.1" + "cordova-plugin-whitelist": "1.2.1", + "phonegap-plugin-barcodescanner": "6.0.1" } } \ No newline at end of file diff --git a/platforms/android/assets/www/assets/qrcode.svg b/platforms/android/assets/www/assets/qrcode.svg new file mode 100644 index 0000000..e4f6b54 --- /dev/null +++ b/platforms/android/assets/www/assets/qrcode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/platforms/android/assets/www/cordova.js b/platforms/android/assets/www/cordova.js index e94e0f7..5d20c15 100644 --- a/platforms/android/assets/www/cordova.js +++ b/platforms/android/assets/www/cordova.js @@ -1,5 +1,5 @@ // Platform: android -// c517ca811b4948b630e0b74dbae6c9637939da24 +// 2fd4bcb84048415922d13d80d35b8d1668e8e150 /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -19,7 +19,7 @@ under the License. */ ;(function() { -var PLATFORM_VERSION_BUILD_LABEL = '5.1.1'; +var PLATFORM_VERSION_BUILD_LABEL = '5.2.1'; // file: src/scripts/require.js /*jshint -W079 */ @@ -330,7 +330,7 @@ module.exports = cordova; }); -// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js +// file: D:/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js define("cordova/android/nativeapiprovider", function(require, exports, module) { /** @@ -353,7 +353,7 @@ module.exports = { }); -// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js +// file: D:/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js define("cordova/android/promptbasednativeapi", function(require, exports, module) { /** @@ -862,7 +862,7 @@ module.exports = channel; }); -// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/exec.js +// file: D:/cordova/cordova-android/cordova-js-src/exec.js define("cordova/exec", function(require, exports, module) { /** @@ -1611,7 +1611,7 @@ exports.reset(); }); -// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/platform.js +// file: D:/cordova/cordova-android/cordova-js-src/platform.js define("cordova/platform", function(require, exports, module) { // The last resume event that was received that had the result of a plugin call. @@ -1721,7 +1721,7 @@ function onMessageFromNative(msg) { }); -// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/plugin/android/app.js +// file: D:/cordova/cordova-android/cordova-js-src/plugin/android/app.js define("cordova/plugin/android/app", function(require, exports, module) { var exec = require('cordova/exec'); diff --git a/platforms/android/assets/www/cordova_plugins.js b/platforms/android/assets/www/cordova_plugins.js index 1d13f65..c47fc3e 100644 --- a/platforms/android/assets/www/cordova_plugins.js +++ b/platforms/android/assets/www/cordova_plugins.js @@ -301,6 +301,14 @@ module.exports = [ "file": "plugins/cordova-plugin-whitelist/whitelist.js", "id": "cordova-plugin-whitelist.whitelist", "runs": true + }, + { + "id": "phonegap-plugin-barcodescanner.BarcodeScanner", + "file": "plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js", + "pluginId": "phonegap-plugin-barcodescanner", + "clobbers": [ + "cordova.plugins.barcodeScanner" + ] } ]; module.exports.metadata = @@ -317,7 +325,8 @@ module.exports.metadata = "cordova-plugin-media-capture": "1.2.1-dev", "cordova-plugin-network-information": "1.2.1-dev", "cordova-plugin-splashscreen": "3.2.2-dev", - "cordova-plugin-whitelist": "1.2.1" + "cordova-plugin-whitelist": "1.2.1", + "phonegap-plugin-barcodescanner": "6.0.1" }; // BOTTOM OF METADATA }); \ No newline at end of file diff --git a/platforms/android/assets/www/css/main.css b/platforms/android/assets/www/css/main.css index 12e496f..92eb5dd 100644 --- a/platforms/android/assets/www/css/main.css +++ b/platforms/android/assets/www/css/main.css @@ -226,12 +226,13 @@ body { box-shadow: 0 0 5px grey; width: 60px; height: 60px; + margin-bottom: 20px; } #buttons .circlebutton img { - position: absolute; - top: 15px; - left: 15px; + position: static; + margin-top: 14px; + margin-left: 14px; width: 30px; height: 30px; } diff --git a/platforms/android/assets/www/js/auth.js b/platforms/android/assets/www/js/auth.js index 7179fc7..da40ac6 100644 --- a/platforms/android/assets/www/js/auth.js +++ b/platforms/android/assets/www/js/auth.js @@ -18,28 +18,36 @@ function askLogout() { } function logout() { - localStorage.setItem("username", ''); - localStorage.setItem("password", ''); - username = null; - password = null; - $('#content-zone').load("screens/login.html"); + $.getJSON(mkApiUrl('deletesession', 'gs'), {}, function (data) { + if (data.status === 'OK') { + localStorage.setItem("username", ''); + localStorage.setItem("password", ''); + username = null; + password = null; + $('#content-zone').load("screens/login.html"); + } else { + navigator.notification.alert("Server did not properly acknowledge logout. You might have problems for the next few hours if you switch accounts.", null, "Error", 'Dismiss'); + } + }).fail(function () { + navigator.notification.alert("Cannot connect to authentication server. Check your Internet connection and try again. If that fails, clear the app data or reinstall TerranQuest.", null, "Error", 'Dismiss'); + }); } function checkUserHasTeamOpenChooserIfNot(username) { $.getJSON(mkApiUrl('getstats', 'gs'), { - user: username - }, function (data) { - if (data.status === 'OK' && data.stats.teamid !== null && data.stats.teamid > 0) { - // We're all good. - userteamid = data.stats.teamid; - openscreen("home"); - } else { - // Open the team intro thingy - openscreen('chooseteam'); - } - }).fail(function () { - - }); + user: username + }, function (data) { + if (data.status === 'OK' && data.stats.teamid !== null && data.stats.teamid > 0) { + // We're all good. + userteamid = data.stats.teamid; + openscreen("home"); + } else { + // Open the team intro thingy + openscreen('chooseteam'); + } + }).fail(function () { + + }); } function dosignup() { @@ -71,21 +79,21 @@ function dosignup() { name: $('#nameBox').val(), email: $('#emailBox').val() }, - function (data) { - if (data === 'OK') { - username = $('#usernameBox').val().toLowerCase(); - password = $('#passwordBox').val(); - localStorage.setItem("username", username); - localStorage.setItem("password", password); - checkUserHasTeamOpenChooserIfNot(username); - } else { - $('#signupBtn').html(' Sign Up'); - $('#signupBtn').attr('disabled', false); - $('#errormsg').text("Error: " + data); - $('#errorbase').css('display', 'block'); - } - authOpInProgress = false; - }).fail(function () { + function (data) { + if (data === 'OK') { + username = $('#usernameBox').val().toLowerCase(); + password = $('#passwordBox').val(); + localStorage.setItem("username", username); + localStorage.setItem("password", password); + checkUserHasTeamOpenChooserIfNot(username); + } else { + $('#signupBtn').html(' Sign Up'); + $('#signupBtn').attr('disabled', false); + $('#errormsg').text("Error: " + data); + $('#errorbase').css('display', 'block'); + } + authOpInProgress = false; + }).fail(function () { $('#signupBtn').html(' Sign Up'); $('#signupBtn').attr('disabled', false); $('#errormsg').text("Error: Network failure."); @@ -111,42 +119,42 @@ function dologin() { $('#loginBtn').html(' Logging in...'); $.post("https://sso.netsyms.com/api/simpleauth.php", {user: $('#usernameBox').val(), pass: $('#passwordBox').val()}, - function (data) { - if (data === 'OK') { - // Now that auth is OK, ping the game server - $.getJSON(mkApiUrl('pinglogin') + "?user=" + $('#usernameBox').val(), function (out) { - if (out.status === 'OK') { - username = $('#usernameBox').val().toLowerCase(); - password = $('#passwordBox').val(); - localStorage.setItem("username", username); - localStorage.setItem("password", password); - navigator.splashscreen.hide(); - checkUserHasTeamOpenChooserIfNot(username); + function (data) { + if (data === 'OK') { + // Now that auth is OK, ping the game server + $.getJSON(mkApiUrl('pinglogin') + "?user=" + $('#usernameBox').val(), function (out) { + if (out.status === 'OK') { + username = $('#usernameBox').val().toLowerCase(); + password = $('#passwordBox').val(); + localStorage.setItem("username", username); + localStorage.setItem("password", password); + navigator.splashscreen.hide(); + checkUserHasTeamOpenChooserIfNot(username); + } else { + $('#loginBtn').html(' Login'); + $('#loginBtn').attr('disabled', false); + $('#errormsg').text("Error: " + out.message); + $('#errorbase').css('display', 'block'); + $('#loading').css('display', 'none'); + authOpInProgress = false; + } + }).fail(function (err) { + $('#loginBtn').html(' Login'); + $('#loginBtn').attr('disabled', false); + $('#errormsg').text("Error: Login OK, but cannot connect to game server. Try again later."); + $('#errorbase').css('display', 'block'); + $('#loading').css('display', 'none'); + authOpInProgress = false; + }); } else { $('#loginBtn').html(' Login'); $('#loginBtn').attr('disabled', false); - $('#errormsg').text("Error: " + out.message); + $('#errormsg').text(data); $('#errorbase').css('display', 'block'); $('#loading').css('display', 'none'); - authOpInProgress = false; } - }).fail(function (err) { - $('#loginBtn').html(' Login'); - $('#loginBtn').attr('disabled', false); - $('#errormsg').text("Error: Login OK, but cannot connect to game server. Try again later."); - $('#errorbase').css('display', 'block'); - $('#loading').css('display', 'none'); authOpInProgress = false; - }); - } else { - $('#loginBtn').html(' Login'); - $('#loginBtn').attr('disabled', false); - $('#errormsg').text(data); - $('#errorbase').css('display', 'block'); - $('#loading').css('display', 'none'); - } - authOpInProgress = false; - }).fail(function () { + }).fail(function () { $('#loginBtn').html(' Login'); $('#loginBtn').attr('disabled', false); $('#errormsg').text("Error: Network failure."); diff --git a/platforms/android/assets/www/js/main.js b/platforms/android/assets/www/js/main.js index 44c2266..a9bab5b 100644 --- a/platforms/android/assets/www/js/main.js +++ b/platforms/android/assets/www/js/main.js @@ -83,7 +83,18 @@ function scanCode() { cordova.plugins.barcodeScanner.scan( function (result) { if (!result.cancelled) { - navigator.notification.alert("Scanned code: " + result.text, null, "OK", 'Dismiss'); + $.getJSON(mkApiUrl('code2item', 'gs'), { + code: result.text + }, function (data) { + if (data.status === 'OK') { + navigator.notification.alert("Found one " + data.message, null, "Found an item!", 'OK'); + } else { + navigator.notification.alert(data.message, null, "Huh?", 'OK'); + } + }).fail(function () { + navigator.notification.alert("Nothing happened!", null, "Huh?", 'OK'); + }); + //navigator.notification.alert("Scanned code: " + result.text, null, "OK", 'Dismiss'); } }, function (error) { @@ -91,7 +102,7 @@ function scanCode() { } ); } catch (ex) { - alert(ex.message); + navigator.notification.alert(ex.message, null, "Error", 'Dismiss'); } } diff --git a/platforms/android/assets/www/js/user.js b/platforms/android/assets/www/js/user.js index 9576f31..0085c1d 100644 --- a/platforms/android/assets/www/js/user.js +++ b/platforms/android/assets/www/js/user.js @@ -11,7 +11,7 @@ * Syncs the user's stats with the server and calls refreshStats(). */ function syncStats() { - $.getJSON(mkApiUrl('getstats'), { + $.getJSON(mkApiUrl('getstats', 'gs'), { user: username }, function (data) { if (data.status === 'OK') { diff --git a/platforms/android/assets/www/plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js b/platforms/android/assets/www/plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js new file mode 100644 index 0000000..4711883 --- /dev/null +++ b/platforms/android/assets/www/plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js @@ -0,0 +1,150 @@ +cordova.define("phonegap-plugin-barcodescanner.BarcodeScanner", function(require, exports, module) { +/** + * cordova is available under *either* the terms of the modified BSD license *or* the + * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. + * + * Copyright (c) Matt Kane 2010 + * Copyright (c) 2011, IBM Corporation + */ + + + var exec = require("cordova/exec"); + + var scanInProgress = false; + + /** + * Constructor. + * + * @returns {BarcodeScanner} + */ + function BarcodeScanner() { + + /** + * Encoding constants. + * + * @type Object + */ + this.Encode = { + TEXT_TYPE: "TEXT_TYPE", + EMAIL_TYPE: "EMAIL_TYPE", + PHONE_TYPE: "PHONE_TYPE", + SMS_TYPE: "SMS_TYPE" + // CONTACT_TYPE: "CONTACT_TYPE", // TODO: not implemented, requires passing a Bundle class from Javascript to Java + // LOCATION_TYPE: "LOCATION_TYPE" // TODO: not implemented, requires passing a Bundle class from Javascript to Java + }; + + /** + * Barcode format constants, defined in ZXing library. + * + * @type Object + */ + this.format = { + "all_1D": 61918, + "aztec": 1, + "codabar": 2, + "code_128": 16, + "code_39": 4, + "code_93": 8, + "data_MATRIX": 32, + "ean_13": 128, + "ean_8": 64, + "itf": 256, + "maxicode": 512, + "msi": 131072, + "pdf_417": 1024, + "plessey": 262144, + "qr_CODE": 2048, + "rss_14": 4096, + "rss_EXPANDED": 8192, + "upc_A": 16384, + "upc_E": 32768, + "upc_EAN_EXTENSION": 65536 + }; + } + +/** + * Read code from scanner. + * + * @param {Function} successCallback This function will recieve a result object: { + * text : '12345-mock', // The code that was scanned. + * format : 'FORMAT_NAME', // Code format. + * cancelled : true/false, // Was canceled. + * } + * @param {Function} errorCallback + * @param config + */ +BarcodeScanner.prototype.scan = function (successCallback, errorCallback, config) { + + if (config instanceof Array) { + // do nothing + } else { + if (typeof(config) === 'object') { + config = [ config ]; + } else { + config = []; + } + } + + if (errorCallback == null) { + errorCallback = function () { + }; + } + + if (typeof errorCallback != "function") { + console.log("BarcodeScanner.scan failure: failure parameter not a function"); + return; + } + + if (typeof successCallback != "function") { + console.log("BarcodeScanner.scan failure: success callback parameter must be a function"); + return; + } + + if (scanInProgress) { + errorCallback('Scan is already in progress'); + return; + } + + scanInProgress = true; + + exec( + function(result) { + scanInProgress = false; + successCallback(result); + }, + function(error) { + scanInProgress = false; + errorCallback(error); + }, + 'BarcodeScanner', + 'scan', + config + ); + }; + + //------------------------------------------------------------------- + BarcodeScanner.prototype.encode = function (type, data, successCallback, errorCallback, options) { + if (errorCallback == null) { + errorCallback = function () { + }; + } + + if (typeof errorCallback != "function") { + console.log("BarcodeScanner.encode failure: failure parameter not a function"); + return; + } + + if (typeof successCallback != "function") { + console.log("BarcodeScanner.encode failure: success callback parameter must be a function"); + return; + } + + exec(successCallback, errorCallback, 'BarcodeScanner', 'encode', [ + {"type": type, "data": data, "options": options} + ]); + }; + + var barcodeScanner = new BarcodeScanner(); + module.exports = barcodeScanner; + +}); diff --git a/platforms/android/assets/www/screens/chooseteam.html b/platforms/android/assets/www/screens/chooseteam.html index de31813..61f2c66 100644 --- a/platforms/android/assets/www/screens/chooseteam.html +++ b/platforms/android/assets/www/screens/chooseteam.html @@ -32,7 +32,7 @@ function setTeam() { //alert($('input[name=teamChooser]:checked').val()); var team = $('input[name=teamChooser]:checked').val(); - $.getJSON(mkApiUrl('setteam', 'gs'), { + $.getJSON(mkApiUrl('setteam', 'gs'), { teamid: team }, function (data) { if (data.status === 'OK') { @@ -40,7 +40,7 @@ openscreen("home"); } else { // Error? - alert("Error: " + data.message); + navigator.notification.alert(data.message, null, "Error", 'OK'); } }).fail(function () { alert("Something bad happened, try again later."); diff --git a/platforms/android/assets/www/screens/home.html b/platforms/android/assets/www/screens/home.html index 2d127d6..d4087f7 100644 --- a/platforms/android/assets/www/screens/home.html +++ b/platforms/android/assets/www/screens/home.html @@ -36,6 +36,9 @@
Menu
+
+ Scan Code +
diff --git a/platforms/android/assets/www/screens/inventory.html b/platforms/android/assets/www/screens/inventory.html index abaf430..f28bb3c 100644 --- a/platforms/android/assets/www/screens/inventory.html +++ b/platforms/android/assets/www/screens/inventory.html @@ -7,15 +7,36 @@
\ No newline at end of file diff --git a/platforms/android/assets/www/screens/place.html b/platforms/android/assets/www/screens/place.html index c54a4c6..8bdd5c6 100644 --- a/platforms/android/assets/www/screens/place.html +++ b/platforms/android/assets/www/screens/place.html @@ -10,9 +10,11 @@ - -If you are using node, you can install BigInteger with [npm](https://npmjs.org/). - - npm install big-integer - -Then you can include it in your code: - - var bigInt = require("big-integer"); - - -## Usage -### `bigInt(number, [base])` - -You can create a bigInt by calling the `bigInt` function. You can pass in - - - a string, which it will parse as an bigInt and throw an `"Invalid integer"` error if the parsing fails. - - a Javascript number, which it will parse as an bigInt and throw an `"Invalid integer"` error if the parsing fails. - - another bigInt. - - nothing, and it will return `bigInt.zero`. - - If you provide a second parameter, then it will parse `number` as a number in base `base`. Note that `base` can be any bigInt (even negative or zero). The letters "a-z" and "A-Z" will be interpreted as the numbers 10 to 35. Higher digits can be specified in angle brackets (`<` and `>`). - -Examples: - - var zero = bigInt(); - var ninetyThree = bigInt(93); - var largeNumber = bigInt("75643564363473453456342378564387956906736546456235345"); - var googol = bigInt("1e100"); - var bigNumber = bigInt(largeNumber); - - var maximumByte = bigInt("FF", 16); - var fiftyFiveGoogol = bigInt("<55>0", googol); - -Note that Javascript numbers larger than `9007199254740992` and smaller than `-9007199254740992` are not precisely represented numbers and will not produce exact results. If you are dealing with numbers outside that range, it is better to pass in strings. - -### Method Chaining - -Note that bigInt operations return bigInts, which allows you to chain methods, for example: - - var salary = bigInt(dollarsPerHour).times(hoursWorked).plus(randomBonuses) - -### Constants - -There are three named constants already stored that you do not have to construct with the `bigInt` function yourself: - - - `bigInt.one`, equivalent to `bigInt(1)` - - `bigInt.zero`, equivalent to `bigInt(0)` - - `bigInt.minusOne`, equivalent to `bigInt(-1)` - -The numbers from -999 to 999 are also already prestored and can be accessed using `bigInt[index]`, for example: - - - `bigInt[-999]`, equivalent to `bigInt(-999)` - - `bigInt[256]`, equivalent to `bigInt(256)` - -### Methods - -#### `abs()` - -Returns the absolute value of a bigInt. - - - `bigInt(-45).abs()` => `45` - - `bigInt(45).abs()` => `45` - -#### `add(number)` - -Performs addition. - - - `bigInt(5).add(7)` => `12` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Addition) - -#### `and(number)` - -Performs the bitwise AND operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement). - - - `bigInt(6).and(3)` => `2` - - `bigInt(6).and(-3)` => `4` - -#### `compare(number)` - -Performs a comparison between two numbers. If the numbers are equal, it returns `0`. If the first number is greater, it returns `1`. If the first number is lesser, it returns `-1`. - - - `bigInt(5).compare(5)` => `0` - - `bigInt(5).compare(4)` => `1` - - `bigInt(4).compare(5)` => `-1` - -#### `compareAbs(number)` - -Performs a comparison between the absolute value of two numbers. - - - `bigInt(5).compareAbs(-5)` => `0` - - `bigInt(5).compareAbs(4)` => `1` - - `bigInt(4).compareAbs(-5)` => `-1` - -#### `compareTo(number)` - -Alias for the `compare` method. - -#### `divide(number)` - -Performs integer division, disregarding the remainder. - - - `bigInt(59).divide(5)` => `11` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division) - -#### `divmod(number)` - -Performs division and returns an object with two properties: `quotient` and `remainder`. The sign of the remainder will match the sign of the dividend. - - - `bigInt(59).divmod(5)` => `{quotient: bigInt(11), remainder: bigInt(4) }` - - `bigInt(-5).divmod(2)` => `{quotient: bigInt(-2), remainder: bigInt(-1) }` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division) - -#### `eq(number)` - -Alias for the `equals` method. - -#### `equals(number)` - -Checks if two numbers are equal. - - - `bigInt(5).equals(5)` => `true` - - `bigInt(4).equals(7)` => `false` - -#### `geq(number)` - -Alias for the `greaterOrEquals` method. - - -#### `greater(number)` - -Checks if the first number is greater than the second. - - - `bigInt(5).greater(6)` => `false` - - `bigInt(5).greater(5)` => `false` - - `bigInt(5).greater(4)` => `true` - -#### `greaterOrEquals(number)` - -Checks if the first number is greater than or equal to the second. - - - `bigInt(5).greaterOrEquals(6)` => `false` - - `bigInt(5).greaterOrEquals(5)` => `true` - - `bigInt(5).greaterOrEquals(4)` => `true` - -#### `gt(number)` - -Alias for the `greater` method. - -#### `isDivisibleBy(number)` - -Returns `true` if the first number is divisible by the second number, `false` otherwise. - - - `bigInt(999).isDivisibleBy(333)` => `true` - - `bigInt(99).isDivisibleBy(5)` => `false` - -#### `isEven()` - -Returns `true` if the number is even, `false` otherwise. - - - `bigInt(6).isEven()` => `true` - - `bigInt(3).isEven()` => `false` - -#### `isNegative()` - -Returns `true` if the number is negative, `false` otherwise. -Returns `false` for `0` and `-0`. - - - `bigInt(-23).isNegative()` => `true` - - `bigInt(50).isNegative()` => `false` - -#### `isOdd()` - -Returns `true` if the number is odd, `false` otherwise. - - - `bigInt(13).isOdd()` => `true` - - `bigInt(40).isOdd()` => `false` - -#### `isPositive()` - -Return `true` if the number is positive, `false` otherwise. -Returns `false` for `0` and `-0`. - - - `bigInt(54).isPositive()` => `true` - - `bigInt(-1).isPositive()` => `false` - -#### `isPrime()` - -Returns `true` if the number is prime, `false` otherwise. - - - `bigInt(5).isPrime()` => `true` - - `bigInt(6).isPrime()` => `false` - -#### `isProbablePrime([iterations])` - -Returns `true` if the number is very likely to be positive, `false` otherwise. -Argument is optional and determines the amount of iterations of the test (default: `5`). The more iterations, the lower chance of getting a false positive. -This uses the [Fermat primality test](https://en.wikipedia.org/wiki/Fermat_primality_test). - - - `bigInt(5).isProbablePrime()` => `true` - - `bigInt(49).isProbablePrime()` => `false` - - `bigInt(1729).isProbablePrime(50)` => `false` - -Note that this function is not deterministic, since it relies on random sampling of factors, so the result for some numbers is not always the same. [Carmichael numbers](https://en.wikipedia.org/wiki/Carmichael_number) are particularly prone to give unreliable results. - -For example, `bigInt(1729).isProbablePrime()` returns `false` about 76% of the time and `true` about 24% of the time. The correct result is `false`. - -#### `isUnit()` - -Returns `true` if the number is `1` or `-1`, `false` otherwise. - - - `bigInt.one.isUnit()` => `true` - - `bigInt.minusOne.isUnit()` => `true` - - `bigInt(5).isUnit()` => `false` - -#### `isZero()` - -Return `true` if the number is `0` or `-0`, `false` otherwise. - - - `bigInt.zero.isZero()` => `true` - - `bigInt("-0").isZero()` => `true` - - `bigInt(50).isZero()` => `false` - -#### `leq(number)` - -Alias for the `lesserOrEquals` method. - -#### `lesser(number)` - -Checks if the first number is lesser than the second. - - - `bigInt(5).lesser(6)` => `true` - - `bigInt(5).lesser(5)` => `false` - - `bigInt(5).lesser(4)` => `false` - -#### `lesserOrEquals(number)` - -Checks if the first number is less than or equal to the second. - - - `bigInt(5).lesserOrEquals(6)` => `true` - - `bigInt(5).lesserOrEquals(5)` => `true` - - `bigInt(5).lesserOrEquals(4)` => `false` - -#### `lt(number)` - -Alias for the `lesser` method. - -#### `minus(number)` - -Alias for the `subtract` method. - - - `bigInt(3).minus(5)` => `-2` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Subtraction) - -#### `mod(number)` - -Performs division and returns the remainder, disregarding the quotient. The sign of the remainder will match the sign of the dividend. - - - `bigInt(59).mod(5)` => `4` - - `bigInt(-5).mod(2)` => `-1` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division) - -#### `modPow(exp, mod)` - -Takes the number to the power `exp` modulo `mod`. - - - `bigInt(10).modPow(3, 30)` => `10` - -#### `multiply(number)` - -Performs multiplication. - - - `bigInt(111).multiply(111)` => `12321` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Multiplication) - -#### `neq(number)` - -Alias for the `notEquals` method. - -#### `next()` - -Adds one to the number. - - - `bigInt(6).next()` => `7` - -#### `not()` - -Performs the bitwise NOT operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement). - - - `bigInt(10).not()` => `-11` - - `bigInt(0).not()` => `-1` - -#### `notEquals(number)` - -Checks if two numbers are not equal. - - - `bigInt(5).notEquals(5)` => `false` - - `bigInt(4).notEquals(7)` => `true` - -#### `or(number)` - -Performs the bitwise OR operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement). - - - `bigInt(13).or(10)` => `15` - - `bigInt(13).or(-8)` => `-3` - -#### `over(number)` - -Alias for the `divide` method. - - - `bigInt(59).over(5)` => `11` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division) - -#### `plus(number)` - -Alias for the `add` method. - - - `bigInt(5).plus(7)` => `12` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Addition) - -#### `pow(number)` - -Performs exponentiation. If the exponent is less than `0`, `pow` returns `0`. `bigInt.zero.pow(0)` returns `1`. - - - `bigInt(16).pow(16)` => `18446744073709551616` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Exponentiation) - -#### `prev(number)` - -Subtracts one from the number. - - - `bigInt(6).prev()` => `5` - -#### `remainder(number)` - -Alias for the `mod` method. - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division) - -#### `shiftLeft(n)` - -Shifts the number left by `n` places in its binary representation. If a negative number is provided, it will shift right. Throws an error if `n` is outside of the range `[-9007199254740992, 9007199254740992]`. - - - `bigInt(8).shiftLeft(2)` => `32` - - `bigInt(8).shiftLeft(-2)` => `2` - -#### `shiftRight(n)` - -Shifts the number right by `n` places in its binary representation. If a negative number is provided, it will shift left. Throws an error if `n` is outside of the range `[-9007199254740992, 9007199254740992]`. - - - `bigInt(8).shiftRight(2)` => `2` - - `bigInt(8).shiftRight(-2)` => `32` - -#### `square()` - -Squares the number - - - `bigInt(3).square()` => `9` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Squaring) - -#### `subtract(number)` - -Performs subtraction. - - - `bigInt(3).subtract(5)` => `-2` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Subtraction) - -#### `times(number)` - -Alias for the `multiply` method. - - - `bigInt(111).times(111)` => `12321` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Multiplication) - -#### `toJSNumber()` - -Converts a bigInt into a native Javascript number. Loses precision for numbers outside the range `[-9007199254740992, 9007199254740992]`. - - - `bigInt("18446744073709551616").toJSNumber()` => `18446744073709552000` - -#### `xor(number)` - -Performs the bitwise XOR operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement). - - - `bigInt(12).xor(5)` => `9` - - `bigInt(12).xor(-5)` => `-9` - -### Static Methods - -#### `gcd(a, b)` - -Finds the greatest common denominator of `a` and `b`. - - - `bigInt.gcd(42,56)` => `14` - -#### `isInstance(x)` - -Returns `true` if `x` is a BigInteger, `false` otherwise. - - - `bigInt.isInstance(bigInt(14))` => `true` - - `bigInt.isInstance(14)` => `false` - -#### `lcm(a,b)` - -Finds the least common multiple of `a` and `b`. - - - `bigInt.lcm(21, 6)` => `42` - -#### `max(a,b)` - -Returns the largest of `a` and `b`. - - - `bigInt.max(77, 432)` => `432` - -#### `min(a,b)` - -Returns the smallest of `a` and `b`. - - - `bigInt.min(77, 432)` => `77` - -#### `randBetween(min, max)` - -Returns a random number between `min` and `max`. - - - `bigInt.randBetween("-1e100", "1e100")` => (for example) `8494907165436643479673097939554427056789510374838494147955756275846226209006506706784609314471378745` - - -### Override Methods - -#### `toString(radix = 10)` - -Converts a bigInt to a string. There is an optional radix parameter (which defaults to 10) that converts the number to the given radix. Digits in the range `10-35` will use the letters `a-z`. - - - `bigInt("1e9").toString()` => `"1000000000"` - - `bigInt("1e9").toString(16)` => `"3b9aca00"` - -**Note that arithmetical operators will trigger the `valueOf` function rather than the `toString` function.** When converting a bigInteger to a string, you should use the `toString` method or the `String` function instead of adding the empty string. - - - `bigInt("999999999999999999").toString()` => `"999999999999999999"` - - `String(bigInt("999999999999999999"))` => `"999999999999999999"` - - `bigInt("999999999999999999") + ""` => `1000000000000000000` - -Bases larger than 36 are supported. If a digit is greater than or equal to 36, it will be enclosed in angle brackets. - - - `bigInt(567890).toString(100)` => `"<56><78><90>"` - -Negative bases are also supported. - - - `bigInt(12345).toString(-10)` => `"28465"` - -Base 1 and base -1 are also supported. - - - `bigInt(-15).toString(1)` => `"-111111111111111"` - - `bigInt(-15).toString(-1)` => `"101010101010101010101010101010"` - -Base 0 is only allowed for the number zero. - - - `bigInt(0).toString(0)` => `0` - - `bigInt(1).toString(0)` => `Error: Cannot convert nonzero numbers to base 0.` - -[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#toString) - -#### `valueOf()` - -Converts a bigInt to a native Javascript number. This override allows you to use native arithmetic operators without explicit conversion: - - - `bigInt("100") + bigInt("200") === 300; //true` - -## Contributors - -To contribute, just fork the project, make some changes, and submit a pull request. Please verify that the unit tests pass before submitting. - -The unit tests are contained in the `spec/spec.js` file. You can run them locally by opening the `spec/SpecRunner.html` or file or running `npm test`. You can also [run the tests online from GitHub](http://peterolson.github.io/BigInteger.js/spec/SpecRunner.html). - -There are performance benchmarks that can be viewed from the `benchmarks/index.html` page. You can [run them online from GitHub](http://peterolson.github.io/BigInteger.js/benchmark/). - -## License - +# BigInteger.js [![Build Status][travis-img]][travis-url] [![Coverage Status][coveralls-img]][coveralls-url] [![Monthly Downloads][downloads-img]][downloads-url] + +[travis-url]: https://travis-ci.org/peterolson/BigInteger.js +[travis-img]: https://travis-ci.org/peterolson/BigInteger.js.svg?branch=master +[coveralls-url]: https://coveralls.io/github/peterolson/BigInteger.js?branch=master +[coveralls-img]: https://coveralls.io/repos/peterolson/BigInteger.js/badge.svg?branch=master&service=github +[downloads-url]: https://www.npmjs.com/package/big-integer +[downloads-img]: https://img.shields.io/npm/dm/big-integer.svg + +**BigInteger.js** is an arbitrary-length integer library for Javascript, allowing arithmetic operations on integers of unlimited size, notwithstanding memory and time limitations. + +## Installation + +If you are using a browser, you can download [BigInteger.js from GitHub](http://peterolson.github.com/BigInteger.js/BigInteger.min.js) or just hotlink to it: + + + +If you are using node, you can install BigInteger with [npm](https://npmjs.org/). + + npm install big-integer + +Then you can include it in your code: + + var bigInt = require("big-integer"); + + +## Usage +### `bigInt(number, [base])` + +You can create a bigInt by calling the `bigInt` function. You can pass in + + - a string, which it will parse as an bigInt and throw an `"Invalid integer"` error if the parsing fails. + - a Javascript number, which it will parse as an bigInt and throw an `"Invalid integer"` error if the parsing fails. + - another bigInt. + - nothing, and it will return `bigInt.zero`. + + If you provide a second parameter, then it will parse `number` as a number in base `base`. Note that `base` can be any bigInt (even negative or zero). The letters "a-z" and "A-Z" will be interpreted as the numbers 10 to 35. Higher digits can be specified in angle brackets (`<` and `>`). + +Examples: + + var zero = bigInt(); + var ninetyThree = bigInt(93); + var largeNumber = bigInt("75643564363473453456342378564387956906736546456235345"); + var googol = bigInt("1e100"); + var bigNumber = bigInt(largeNumber); + + var maximumByte = bigInt("FF", 16); + var fiftyFiveGoogol = bigInt("<55>0", googol); + +Note that Javascript numbers larger than `9007199254740992` and smaller than `-9007199254740992` are not precisely represented numbers and will not produce exact results. If you are dealing with numbers outside that range, it is better to pass in strings. + +### Method Chaining + +Note that bigInt operations return bigInts, which allows you to chain methods, for example: + + var salary = bigInt(dollarsPerHour).times(hoursWorked).plus(randomBonuses) + +### Constants + +There are three named constants already stored that you do not have to construct with the `bigInt` function yourself: + + - `bigInt.one`, equivalent to `bigInt(1)` + - `bigInt.zero`, equivalent to `bigInt(0)` + - `bigInt.minusOne`, equivalent to `bigInt(-1)` + +The numbers from -999 to 999 are also already prestored and can be accessed using `bigInt[index]`, for example: + + - `bigInt[-999]`, equivalent to `bigInt(-999)` + - `bigInt[256]`, equivalent to `bigInt(256)` + +### Methods + +#### `abs()` + +Returns the absolute value of a bigInt. + + - `bigInt(-45).abs()` => `45` + - `bigInt(45).abs()` => `45` + +#### `add(number)` + +Performs addition. + + - `bigInt(5).add(7)` => `12` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Addition) + +#### `and(number)` + +Performs the bitwise AND operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement). + + - `bigInt(6).and(3)` => `2` + - `bigInt(6).and(-3)` => `4` + +#### `compare(number)` + +Performs a comparison between two numbers. If the numbers are equal, it returns `0`. If the first number is greater, it returns `1`. If the first number is lesser, it returns `-1`. + + - `bigInt(5).compare(5)` => `0` + - `bigInt(5).compare(4)` => `1` + - `bigInt(4).compare(5)` => `-1` + +#### `compareAbs(number)` + +Performs a comparison between the absolute value of two numbers. + + - `bigInt(5).compareAbs(-5)` => `0` + - `bigInt(5).compareAbs(4)` => `1` + - `bigInt(4).compareAbs(-5)` => `-1` + +#### `compareTo(number)` + +Alias for the `compare` method. + +#### `divide(number)` + +Performs integer division, disregarding the remainder. + + - `bigInt(59).divide(5)` => `11` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division) + +#### `divmod(number)` + +Performs division and returns an object with two properties: `quotient` and `remainder`. The sign of the remainder will match the sign of the dividend. + + - `bigInt(59).divmod(5)` => `{quotient: bigInt(11), remainder: bigInt(4) }` + - `bigInt(-5).divmod(2)` => `{quotient: bigInt(-2), remainder: bigInt(-1) }` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division) + +#### `eq(number)` + +Alias for the `equals` method. + +#### `equals(number)` + +Checks if two numbers are equal. + + - `bigInt(5).equals(5)` => `true` + - `bigInt(4).equals(7)` => `false` + +#### `geq(number)` + +Alias for the `greaterOrEquals` method. + + +#### `greater(number)` + +Checks if the first number is greater than the second. + + - `bigInt(5).greater(6)` => `false` + - `bigInt(5).greater(5)` => `false` + - `bigInt(5).greater(4)` => `true` + +#### `greaterOrEquals(number)` + +Checks if the first number is greater than or equal to the second. + + - `bigInt(5).greaterOrEquals(6)` => `false` + - `bigInt(5).greaterOrEquals(5)` => `true` + - `bigInt(5).greaterOrEquals(4)` => `true` + +#### `gt(number)` + +Alias for the `greater` method. + +#### `isDivisibleBy(number)` + +Returns `true` if the first number is divisible by the second number, `false` otherwise. + + - `bigInt(999).isDivisibleBy(333)` => `true` + - `bigInt(99).isDivisibleBy(5)` => `false` + +#### `isEven()` + +Returns `true` if the number is even, `false` otherwise. + + - `bigInt(6).isEven()` => `true` + - `bigInt(3).isEven()` => `false` + +#### `isNegative()` + +Returns `true` if the number is negative, `false` otherwise. +Returns `false` for `0` and `-0`. + + - `bigInt(-23).isNegative()` => `true` + - `bigInt(50).isNegative()` => `false` + +#### `isOdd()` + +Returns `true` if the number is odd, `false` otherwise. + + - `bigInt(13).isOdd()` => `true` + - `bigInt(40).isOdd()` => `false` + +#### `isPositive()` + +Return `true` if the number is positive, `false` otherwise. +Returns `false` for `0` and `-0`. + + - `bigInt(54).isPositive()` => `true` + - `bigInt(-1).isPositive()` => `false` + +#### `isPrime()` + +Returns `true` if the number is prime, `false` otherwise. + + - `bigInt(5).isPrime()` => `true` + - `bigInt(6).isPrime()` => `false` + +#### `isProbablePrime([iterations])` + +Returns `true` if the number is very likely to be positive, `false` otherwise. +Argument is optional and determines the amount of iterations of the test (default: `5`). The more iterations, the lower chance of getting a false positive. +This uses the [Fermat primality test](https://en.wikipedia.org/wiki/Fermat_primality_test). + + - `bigInt(5).isProbablePrime()` => `true` + - `bigInt(49).isProbablePrime()` => `false` + - `bigInt(1729).isProbablePrime(50)` => `false` + +Note that this function is not deterministic, since it relies on random sampling of factors, so the result for some numbers is not always the same. [Carmichael numbers](https://en.wikipedia.org/wiki/Carmichael_number) are particularly prone to give unreliable results. + +For example, `bigInt(1729).isProbablePrime()` returns `false` about 76% of the time and `true` about 24% of the time. The correct result is `false`. + +#### `isUnit()` + +Returns `true` if the number is `1` or `-1`, `false` otherwise. + + - `bigInt.one.isUnit()` => `true` + - `bigInt.minusOne.isUnit()` => `true` + - `bigInt(5).isUnit()` => `false` + +#### `isZero()` + +Return `true` if the number is `0` or `-0`, `false` otherwise. + + - `bigInt.zero.isZero()` => `true` + - `bigInt("-0").isZero()` => `true` + - `bigInt(50).isZero()` => `false` + +#### `leq(number)` + +Alias for the `lesserOrEquals` method. + +#### `lesser(number)` + +Checks if the first number is lesser than the second. + + - `bigInt(5).lesser(6)` => `true` + - `bigInt(5).lesser(5)` => `false` + - `bigInt(5).lesser(4)` => `false` + +#### `lesserOrEquals(number)` + +Checks if the first number is less than or equal to the second. + + - `bigInt(5).lesserOrEquals(6)` => `true` + - `bigInt(5).lesserOrEquals(5)` => `true` + - `bigInt(5).lesserOrEquals(4)` => `false` + +#### `lt(number)` + +Alias for the `lesser` method. + +#### `minus(number)` + +Alias for the `subtract` method. + + - `bigInt(3).minus(5)` => `-2` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Subtraction) + +#### `mod(number)` + +Performs division and returns the remainder, disregarding the quotient. The sign of the remainder will match the sign of the dividend. + + - `bigInt(59).mod(5)` => `4` + - `bigInt(-5).mod(2)` => `-1` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division) + +#### `modPow(exp, mod)` + +Takes the number to the power `exp` modulo `mod`. + + - `bigInt(10).modPow(3, 30)` => `10` + +#### `multiply(number)` + +Performs multiplication. + + - `bigInt(111).multiply(111)` => `12321` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Multiplication) + +#### `neq(number)` + +Alias for the `notEquals` method. + +#### `next()` + +Adds one to the number. + + - `bigInt(6).next()` => `7` + +#### `not()` + +Performs the bitwise NOT operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement). + + - `bigInt(10).not()` => `-11` + - `bigInt(0).not()` => `-1` + +#### `notEquals(number)` + +Checks if two numbers are not equal. + + - `bigInt(5).notEquals(5)` => `false` + - `bigInt(4).notEquals(7)` => `true` + +#### `or(number)` + +Performs the bitwise OR operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement). + + - `bigInt(13).or(10)` => `15` + - `bigInt(13).or(-8)` => `-3` + +#### `over(number)` + +Alias for the `divide` method. + + - `bigInt(59).over(5)` => `11` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division) + +#### `plus(number)` + +Alias for the `add` method. + + - `bigInt(5).plus(7)` => `12` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Addition) + +#### `pow(number)` + +Performs exponentiation. If the exponent is less than `0`, `pow` returns `0`. `bigInt.zero.pow(0)` returns `1`. + + - `bigInt(16).pow(16)` => `18446744073709551616` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Exponentiation) + +#### `prev(number)` + +Subtracts one from the number. + + - `bigInt(6).prev()` => `5` + +#### `remainder(number)` + +Alias for the `mod` method. + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division) + +#### `shiftLeft(n)` + +Shifts the number left by `n` places in its binary representation. If a negative number is provided, it will shift right. Throws an error if `n` is outside of the range `[-9007199254740992, 9007199254740992]`. + + - `bigInt(8).shiftLeft(2)` => `32` + - `bigInt(8).shiftLeft(-2)` => `2` + +#### `shiftRight(n)` + +Shifts the number right by `n` places in its binary representation. If a negative number is provided, it will shift left. Throws an error if `n` is outside of the range `[-9007199254740992, 9007199254740992]`. + + - `bigInt(8).shiftRight(2)` => `2` + - `bigInt(8).shiftRight(-2)` => `32` + +#### `square()` + +Squares the number + + - `bigInt(3).square()` => `9` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Squaring) + +#### `subtract(number)` + +Performs subtraction. + + - `bigInt(3).subtract(5)` => `-2` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Subtraction) + +#### `times(number)` + +Alias for the `multiply` method. + + - `bigInt(111).times(111)` => `12321` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Multiplication) + +#### `toJSNumber()` + +Converts a bigInt into a native Javascript number. Loses precision for numbers outside the range `[-9007199254740992, 9007199254740992]`. + + - `bigInt("18446744073709551616").toJSNumber()` => `18446744073709552000` + +#### `xor(number)` + +Performs the bitwise XOR operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement). + + - `bigInt(12).xor(5)` => `9` + - `bigInt(12).xor(-5)` => `-9` + +### Static Methods + +#### `gcd(a, b)` + +Finds the greatest common denominator of `a` and `b`. + + - `bigInt.gcd(42,56)` => `14` + +#### `isInstance(x)` + +Returns `true` if `x` is a BigInteger, `false` otherwise. + + - `bigInt.isInstance(bigInt(14))` => `true` + - `bigInt.isInstance(14)` => `false` + +#### `lcm(a,b)` + +Finds the least common multiple of `a` and `b`. + + - `bigInt.lcm(21, 6)` => `42` + +#### `max(a,b)` + +Returns the largest of `a` and `b`. + + - `bigInt.max(77, 432)` => `432` + +#### `min(a,b)` + +Returns the smallest of `a` and `b`. + + - `bigInt.min(77, 432)` => `77` + +#### `randBetween(min, max)` + +Returns a random number between `min` and `max`. + + - `bigInt.randBetween("-1e100", "1e100")` => (for example) `8494907165436643479673097939554427056789510374838494147955756275846226209006506706784609314471378745` + + +### Override Methods + +#### `toString(radix = 10)` + +Converts a bigInt to a string. There is an optional radix parameter (which defaults to 10) that converts the number to the given radix. Digits in the range `10-35` will use the letters `a-z`. + + - `bigInt("1e9").toString()` => `"1000000000"` + - `bigInt("1e9").toString(16)` => `"3b9aca00"` + +**Note that arithmetical operators will trigger the `valueOf` function rather than the `toString` function.** When converting a bigInteger to a string, you should use the `toString` method or the `String` function instead of adding the empty string. + + - `bigInt("999999999999999999").toString()` => `"999999999999999999"` + - `String(bigInt("999999999999999999"))` => `"999999999999999999"` + - `bigInt("999999999999999999") + ""` => `1000000000000000000` + +Bases larger than 36 are supported. If a digit is greater than or equal to 36, it will be enclosed in angle brackets. + + - `bigInt(567890).toString(100)` => `"<56><78><90>"` + +Negative bases are also supported. + + - `bigInt(12345).toString(-10)` => `"28465"` + +Base 1 and base -1 are also supported. + + - `bigInt(-15).toString(1)` => `"-111111111111111"` + - `bigInt(-15).toString(-1)` => `"101010101010101010101010101010"` + +Base 0 is only allowed for the number zero. + + - `bigInt(0).toString(0)` => `0` + - `bigInt(1).toString(0)` => `Error: Cannot convert nonzero numbers to base 0.` + +[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#toString) + +#### `valueOf()` + +Converts a bigInt to a native Javascript number. This override allows you to use native arithmetic operators without explicit conversion: + + - `bigInt("100") + bigInt("200") === 300; //true` + +## Contributors + +To contribute, just fork the project, make some changes, and submit a pull request. Please verify that the unit tests pass before submitting. + +The unit tests are contained in the `spec/spec.js` file. You can run them locally by opening the `spec/SpecRunner.html` or file or running `npm test`. You can also [run the tests online from GitHub](http://peterolson.github.io/BigInteger.js/spec/SpecRunner.html). + +There are performance benchmarks that can be viewed from the `benchmarks/index.html` page. You can [run them online from GitHub](http://peterolson.github.io/BigInteger.js/benchmark/). + +## License + This project is public domain. For more details, read about the [Unlicense](http://unlicense.org/). \ No newline at end of file diff --git a/platforms/android/cordova/node_modules/big-integer/package.json b/platforms/android/cordova/node_modules/big-integer/package.json index f51a9b6..b353a4d 100644 --- a/platforms/android/cordova/node_modules/big-integer/package.json +++ b/platforms/android/cordova/node_modules/big-integer/package.json @@ -1,45 +1,54 @@ { "_args": [ [ - "big-integer@^1.6.7", - "/Users/steveng/repo/cordova/cordova-android/node_modules/bplist-parser" + { + "raw": "big-integer@^1.6.7", + "scope": null, + "escapedName": "big-integer", + "name": "big-integer", + "rawSpec": "^1.6.7", + "spec": ">=1.6.7 <2.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\bplist-parser" ] ], "_from": "big-integer@>=1.6.7 <2.0.0", - "_id": "big-integer@1.6.12", + "_id": "big-integer@1.6.15", "_inCache": true, "_installable": true, "_location": "/big-integer", "_nodeVersion": "0.12.3", "_npmOperationalInternal": { - "host": "packages-6-west.internal.npmjs.com", - "tmp": "tmp/big-integer-1.6.12.tgz_1455702804335_0.11810904298909009" + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/big-integer-1.6.15.tgz_1460079231162_0.7087579960934818" }, "_npmUser": { - "email": "peter.e.c.olson+npm@gmail.com", - "name": "peterolson" + "name": "peterolson", + "email": "peter.e.c.olson+npm@gmail.com" }, "_npmVersion": "2.9.1", "_phantomChildren": {}, "_requested": { - "name": "big-integer", "raw": "big-integer@^1.6.7", - "rawSpec": "^1.6.7", "scope": null, + "escapedName": "big-integer", + "name": "big-integer", + "rawSpec": "^1.6.7", "spec": ">=1.6.7 <2.0.0", "type": "range" }, "_requiredBy": [ "/bplist-parser" ], - "_resolved": "http://registry.npmjs.org/big-integer/-/big-integer-1.6.12.tgz", - "_shasum": "39afcddafcd5c4480864efb757337d508938bb26", + "_resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.15.tgz", + "_shasum": "33d27d3b7388dfcc4b86d3130c10740cec01fb9e", "_shrinkwrap": null, "_spec": "big-integer@^1.6.7", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/bplist-parser", + "_where": "d:\\cordova\\cordova-android\\node_modules\\bplist-parser", "author": { - "email": "peter.e.c.olson+npm@gmail.com", - "name": "Peter Olson" + "name": "Peter Olson", + "email": "peter.e.c.olson+npm@gmail.com" }, "bin": {}, "bugs": { @@ -59,24 +68,24 @@ }, "directories": {}, "dist": { - "shasum": "39afcddafcd5c4480864efb757337d508938bb26", - "tarball": "http://registry.npmjs.org/big-integer/-/big-integer-1.6.12.tgz" + "shasum": "33d27d3b7388dfcc4b86d3130c10740cec01fb9e", + "tarball": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.15.tgz" }, "engines": { "node": ">=0.6" }, - "gitHead": "56f449108e31542f939e701f1fe562a46e6c1fab", + "gitHead": "cda5bcce74c3a4eb34951201d50c1b8776a56eca", "homepage": "https://github.com/peterolson/BigInteger.js#readme", "keywords": [ - "arbitrary", - "arithmetic", + "math", "big", + "bignum", "bigint", "biginteger", - "bignum", "integer", - "math", - "precision" + "arbitrary", + "precision", + "arithmetic" ], "license": "Unlicense", "main": "./BigInteger", @@ -96,5 +105,5 @@ "scripts": { "test": "karma start my.conf.js" }, - "version": "1.6.12" + "version": "1.6.15" } diff --git a/platforms/android/cordova/node_modules/bplist-parser/package.json b/platforms/android/cordova/node_modules/bplist-parser/package.json index 899b577..e4f7e41 100644 --- a/platforms/android/cordova/node_modules/bplist-parser/package.json +++ b/platforms/android/cordova/node_modules/bplist-parser/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "bplist-parser@^0.1.0", - "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common" + { + "raw": "bplist-parser@^0.1.0", + "scope": null, + "escapedName": "bplist-parser", + "name": "bplist-parser", + "rawSpec": "^0.1.0", + "spec": ">=0.1.0 <0.2.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\cordova-common" ] ], "_from": "bplist-parser@>=0.1.0 <0.2.0", @@ -12,30 +20,31 @@ "_location": "/bplist-parser", "_nodeVersion": "5.1.0", "_npmUser": { - "email": "joe@fernsroth.com", - "name": "joeferner" + "name": "joeferner", + "email": "joe@fernsroth.com" }, "_npmVersion": "3.4.0", "_phantomChildren": {}, "_requested": { - "name": "bplist-parser", "raw": "bplist-parser@^0.1.0", - "rawSpec": "^0.1.0", "scope": null, + "escapedName": "bplist-parser", + "name": "bplist-parser", + "rawSpec": "^0.1.0", "spec": ">=0.1.0 <0.2.0", "type": "range" }, "_requiredBy": [ "/cordova-common" ], - "_resolved": "http://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz", + "_resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz", "_shasum": "d60d5dcc20cba6dc7e1f299b35d3e1f95dafbae6", "_shrinkwrap": null, "_spec": "bplist-parser@^0.1.0", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common", + "_where": "d:\\cordova\\cordova-android\\node_modules\\cordova-common", "author": { - "email": "joe.ferner@nearinfinity.com", - "name": "Joe Ferner" + "name": "Joe Ferner", + "email": "joe.ferner@nearinfinity.com" }, "bugs": { "url": "https://github.com/nearinfinity/node-bplist-parser/issues" @@ -50,14 +59,14 @@ "directories": {}, "dist": { "shasum": "d60d5dcc20cba6dc7e1f299b35d3e1f95dafbae6", - "tarball": "http://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz" + "tarball": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz" }, "gitHead": "c4f22650de2cc95edd21a6e609ff0654a2b951bd", "homepage": "https://github.com/nearinfinity/node-bplist-parser#readme", "keywords": [ "bplist", - "parser", - "plist" + "plist", + "parser" ], "license": "MIT", "main": "bplistParser.js", diff --git a/platforms/android/cordova/node_modules/brace-expansion/.npmignore b/platforms/android/cordova/node_modules/brace-expansion/.npmignore deleted file mode 100644 index 353546a..0000000 --- a/platforms/android/cordova/node_modules/brace-expansion/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -test -.gitignore -.travis.yml diff --git a/platforms/android/cordova/node_modules/brace-expansion/example.js b/platforms/android/cordova/node_modules/brace-expansion/example.js deleted file mode 100644 index 60ecfc7..0000000 --- a/platforms/android/cordova/node_modules/brace-expansion/example.js +++ /dev/null @@ -1,8 +0,0 @@ -var expand = require('./'); - -console.log(expand('http://any.org/archive{1996..1999}/vol{1..4}/part{a,b,c}.html')); -console.log(expand('http://www.numericals.com/file{1..100..10}.txt')); -console.log(expand('http://www.letters.com/file{a..z..2}.txt')); -console.log(expand('mkdir /usr/local/src/bash/{old,new,dist,bugs}')); -console.log(expand('chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}')); - diff --git a/platforms/android/cordova/node_modules/brace-expansion/package.json b/platforms/android/cordova/node_modules/brace-expansion/package.json index d6d2f78..08cea7f 100644 --- a/platforms/android/cordova/node_modules/brace-expansion/package.json +++ b/platforms/android/cordova/node_modules/brace-expansion/package.json @@ -1,64 +1,73 @@ { "_args": [ [ - "brace-expansion@^1.0.0", - "/Users/steveng/repo/cordova/cordova-android/node_modules/minimatch" + { + "raw": "brace-expansion@^1.0.0", + "scope": null, + "escapedName": "brace-expansion", + "name": "brace-expansion", + "rawSpec": "^1.0.0", + "spec": ">=1.0.0 <2.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\minimatch" ] ], "_from": "brace-expansion@>=1.0.0 <2.0.0", - "_id": "brace-expansion@1.1.3", + "_id": "brace-expansion@1.1.5", "_inCache": true, "_installable": true, "_location": "/brace-expansion", - "_nodeVersion": "5.5.0", + "_nodeVersion": "4.4.5", "_npmOperationalInternal": { - "host": "packages-6-west.internal.npmjs.com", - "tmp": "tmp/brace-expansion-1.1.3.tgz_1455216688668_0.948847763473168" + "host": "packages-16-east.internal.npmjs.com", + "tmp": "tmp/brace-expansion-1.1.5.tgz_1465989660138_0.34528115345165133" }, "_npmUser": { - "email": "julian@juliangruber.com", - "name": "juliangruber" + "name": "juliangruber", + "email": "julian@juliangruber.com" }, - "_npmVersion": "3.3.12", + "_npmVersion": "2.15.5", "_phantomChildren": {}, "_requested": { - "name": "brace-expansion", "raw": "brace-expansion@^1.0.0", - "rawSpec": "^1.0.0", "scope": null, + "escapedName": "brace-expansion", + "name": "brace-expansion", + "rawSpec": "^1.0.0", "spec": ">=1.0.0 <2.0.0", "type": "range" }, "_requiredBy": [ "/minimatch" ], - "_resolved": "http://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", - "_shasum": "46bff50115d47fc9ab89854abb87d98078a10991", + "_resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "_shasum": "f5b4ad574e2cb7ccc1eb83e6fe79b8ecadf7a526", "_shrinkwrap": null, "_spec": "brace-expansion@^1.0.0", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/minimatch", + "_where": "d:\\cordova\\cordova-android\\node_modules\\minimatch", "author": { - "email": "mail@juliangruber.com", "name": "Julian Gruber", + "email": "mail@juliangruber.com", "url": "http://juliangruber.com" }, "bugs": { "url": "https://github.com/juliangruber/brace-expansion/issues" }, "dependencies": { - "balanced-match": "^0.3.0", + "balanced-match": "^0.4.1", "concat-map": "0.0.1" }, "description": "Brace expansion as known from sh/bash", "devDependencies": { - "tape": "4.4.0" + "tape": "4.5.1" }, "directories": {}, "dist": { - "shasum": "46bff50115d47fc9ab89854abb87d98078a10991", - "tarball": "http://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz" + "shasum": "f5b4ad574e2cb7ccc1eb83e6fe79b8ecadf7a526", + "tarball": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz" }, - "gitHead": "f0da1bb668e655f67b6b2d660c6e1c19e2a6f231", + "gitHead": "ff31acab078f1bb696ac4c55ca56ea24e6495fb6", "homepage": "https://github.com/juliangruber/brace-expansion", "keywords": [], "license": "MIT", @@ -85,20 +94,20 @@ "test": "tape test/*.js" }, "testling": { + "files": "test/*.js", "browsers": [ - "android-browser/4.2..latest", - "chrome/25..latest", - "chrome/canary", + "ie/8..latest", "firefox/20..latest", "firefox/nightly", - "ie/8..latest", - "ipad/6.0..latest", - "iphone/6.0..latest", + "chrome/25..latest", + "chrome/canary", "opera/12..latest", "opera/next", - "safari/5.1..latest" - ], - "files": "test/*.js" + "safari/5.1..latest", + "ipad/6.0..latest", + "iphone/6.0..latest", + "android-browser/4.2..latest" + ] }, - "version": "1.1.3" + "version": "1.1.5" } diff --git a/platforms/android/cordova/node_modules/concat-map/example/map.js b/platforms/android/cordova/node_modules/concat-map/example/map.js deleted file mode 100644 index 3365621..0000000 --- a/platforms/android/cordova/node_modules/concat-map/example/map.js +++ /dev/null @@ -1,6 +0,0 @@ -var concatMap = require('../'); -var xs = [ 1, 2, 3, 4, 5, 6 ]; -var ys = concatMap(xs, function (x) { - return x % 2 ? [ x - 0.1, x, x + 0.1 ] : []; -}); -console.dir(ys); diff --git a/platforms/android/cordova/node_modules/concat-map/package.json b/platforms/android/cordova/node_modules/concat-map/package.json index 3ebe787..c02ce03 100644 --- a/platforms/android/cordova/node_modules/concat-map/package.json +++ b/platforms/android/cordova/node_modules/concat-map/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "concat-map@0.0.1", - "/Users/steveng/repo/cordova/cordova-android/node_modules/brace-expansion" + { + "raw": "concat-map@0.0.1", + "scope": null, + "escapedName": "concat-map", + "name": "concat-map", + "rawSpec": "0.0.1", + "spec": "0.0.1", + "type": "version" + }, + "d:\\cordova\\cordova-android\\node_modules\\brace-expansion" ] ], "_from": "concat-map@0.0.1", @@ -11,30 +19,31 @@ "_installable": true, "_location": "/concat-map", "_npmUser": { - "email": "mail@substack.net", - "name": "substack" + "name": "substack", + "email": "mail@substack.net" }, "_npmVersion": "1.3.21", "_phantomChildren": {}, "_requested": { - "name": "concat-map", "raw": "concat-map@0.0.1", - "rawSpec": "0.0.1", "scope": null, + "escapedName": "concat-map", + "name": "concat-map", + "rawSpec": "0.0.1", "spec": "0.0.1", "type": "version" }, "_requiredBy": [ "/brace-expansion" ], - "_resolved": "http://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "_resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "_shasum": "d8a96bd77fd68df7793a73036a3ba0d5405d477b", "_shrinkwrap": null, "_spec": "concat-map@0.0.1", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/brace-expansion", + "_where": "d:\\cordova\\cordova-android\\node_modules\\brace-expansion", "author": { - "email": "mail@substack.net", "name": "James Halliday", + "email": "mail@substack.net", "url": "http://substack.net" }, "bugs": { @@ -51,15 +60,15 @@ }, "dist": { "shasum": "d8a96bd77fd68df7793a73036a3ba0d5405d477b", - "tarball": "http://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "tarball": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" }, "homepage": "https://github.com/substack/node-concat-map", "keywords": [ "concat", "concatMap", + "map", "functional", - "higher-order", - "map" + "higher-order" ], "license": "MIT", "main": "index.js", @@ -80,30 +89,30 @@ "test": "tape test/*.js" }, "testling": { + "files": "test/*.js", "browsers": { - "chrome": [ - 10, - 22 - ], - "ff": [ - 10, - 15, - 3.5 - ], "ie": [ 6, 7, 8, 9 ], - "opera": [ - 12 + "ff": [ + 3.5, + 10, + 15 + ], + "chrome": [ + 10, + 22 ], "safari": [ 5.1 + ], + "opera": [ + 12 ] - }, - "files": "test/*.js" + } }, "version": "0.0.1" } diff --git a/platforms/android/cordova/node_modules/cordova-common/RELEASENOTES.md b/platforms/android/cordova/node_modules/cordova-common/RELEASENOTES.md index e7db69c..7a99cc9 100644 --- a/platforms/android/cordova/node_modules/cordova-common/RELEASENOTES.md +++ b/platforms/android/cordova/node_modules/cordova-common/RELEASENOTES.md @@ -20,23 +20,45 @@ --> # Cordova-common Release Notes +### 1.3.0 (May 12, 2016) +* [CB-11259](https://issues.apache.org/jira/browse/CB-11259): Improving prepare and build logging +* [CB-11194](https://issues.apache.org/jira/browse/CB-11194) Improve cordova load time +* [CB-1117](https://issues.apache.org/jira/browse/CB-1117) Add `FileUpdater` module to `cordova-common`. +* [CB-11131](https://issues.apache.org/jira/browse/CB-11131) Fix `TypeError: message.toUpperCase` is not a function in `CordovaLogger` + +### 1.2.0 (Apr 18, 2016) +* [CB-11022](https://issues.apache.org/jira/browse/CB-11022) Save modulesMetadata to both www and platform_www when necessary +* [CB-10833](https://issues.apache.org/jira/browse/CB-10833) Deduplicate common logic for plugin installation/uninstallation +* [CB-10822](https://issues.apache.org/jira/browse/CB-10822) Manage plugins/modules metadata using PlatformJson +* [CB-10940](https://issues.apache.org/jira/browse/CB-10940) Can't add Android platform from path +* [CB-10965](https://issues.apache.org/jira/browse/CB-10965) xml helper allows multiple instances to be merge in config.xml + +### 1.1.1 (Mar 18, 2016) +* [CB-10694](https://issues.apache.org/jira/browse/CB-10694) Update test to reflect merging of [CB-9264](https://issues.apache.org/jira/browse/CB-9264) fix +* [CB-10694](https://issues.apache.org/jira/browse/CB-10694) Platform-specific configuration preferences don't override global settings +* [CB-9264](https://issues.apache.org/jira/browse/CB-9264) Duplicate entries in `config.xml` +* [CB-10791](https://issues.apache.org/jira/browse/CB-10791) Add `adjustLoggerLevel` to `cordova-common.CordovaLogger` +* [CB-10662](https://issues.apache.org/jira/browse/CB-10662) Add tests for `ConfigParser.getStaticResources` +* [CB-10622](https://issues.apache.org/jira/browse/CB-10622) fix target attribute being ignored for images in `config.xml`. +* [CB-10583](https://issues.apache.org/jira/browse/CB-10583) Protect plugin preferences from adding extra Array properties. + ### 1.1.0 (Feb 16, 2016) -* CB-10482 Remove references to windows8 from cordova-lib/cli -* CB-10430 Adds forwardEvents method to easily connect two EventEmitters -* CB-10176 Adds CordovaLogger class, based on logger module from cordova-cli -* CB-10052 Expose child process' io streams via promise progress notification -* CB-10497 Prefer .bat over .cmd on windows platform -* CB-9984 Bumps plist version and fixes failing cordova-common test +* [CB-10482](https://issues.apache.org/jira/browse/CB-10482) Remove references to windows8 from cordova-lib/cli +* [CB-10430](https://issues.apache.org/jira/browse/CB-10430) Adds forwardEvents method to easily connect two EventEmitters +* [CB-10176](https://issues.apache.org/jira/browse/CB-10176) Adds CordovaLogger class, based on logger module from cordova-cli +* [CB-10052](https://issues.apache.org/jira/browse/CB-10052) Expose child process' io streams via promise progress notification +* [CB-10497](https://issues.apache.org/jira/browse/CB-10497) Prefer .bat over .cmd on windows platform +* [CB-9984](https://issues.apache.org/jira/browse/CB-9984) Bumps plist version and fixes failing cordova-common test ### 1.0.0 (Oct 29, 2015) -* CB-9890 Documents cordova-common -* CB-9598 Correct cordova-lib -> cordova-common in README +* [CB-9890](https://issues.apache.org/jira/browse/CB-9890) Documents cordova-common +* [CB-9598](https://issues.apache.org/jira/browse/CB-9598) Correct cordova-lib -> cordova-common in README * Pick ConfigParser changes from apache@0c3614e -* CB-9743 Removes system frameworks handling from ConfigChanges -* CB-9598 Cleans out code which has been moved to `cordova-common` +* [CB-9743](https://issues.apache.org/jira/browse/CB-9743) Removes system frameworks handling from ConfigChanges +* [CB-9598](https://issues.apache.org/jira/browse/CB-9598) Cleans out code which has been moved to `cordova-common` * Pick ConfigParser changes from apache@ddb027b * Picking CordovaError changes from apache@a3b1fca -* CB-9598 Adds tests and fixtures based on existing cordova-lib ones -* CB-9598 Initial implementation for cordova-common +* [CB-9598](https://issues.apache.org/jira/browse/CB-9598) Adds tests and fixtures based on existing cordova-lib ones +* [CB-9598](https://issues.apache.org/jira/browse/CB-9598) Initial implementation for cordova-common diff --git a/platforms/android/cordova/node_modules/cordova-common/cordova-common.js b/platforms/android/cordova/node_modules/cordova-common/cordova-common.js index 22e90a7..dcaf7a4 100644 --- a/platforms/android/cordova/node_modules/cordova-common/cordova-common.js +++ b/platforms/android/cordova/node_modules/cordova-common/cordova-common.js @@ -17,27 +17,30 @@ under the License. */ -/* jshint node:true */ - -// For now expose plugman and cordova just as they were in the old repos -exports = module.exports = { - events: require('./src/events'), - superspawn: require('./src/superspawn'), - - ActionStack: require('./src/ActionStack'), - CordovaError: require('./src/CordovaError/CordovaError'), - CordovaLogger: require('./src/CordovaLogger'), - CordovaExternalToolErrorContext: require('./src/CordovaError/CordovaExternalToolErrorContext'), - PlatformJson: require('./src/PlatformJson'), - ConfigParser: require('./src/ConfigParser/ConfigParser.js'), - - PluginInfo: require('./src/PluginInfo/PluginInfo.js'), - PluginInfoProvider: require('./src/PluginInfo/PluginInfoProvider.js'), - - ConfigChanges: require('./src/ConfigChanges/ConfigChanges.js'), - ConfigKeeper: require('./src/ConfigChanges/ConfigKeeper.js'), - ConfigFile: require('./src/ConfigChanges/ConfigFile.js'), - mungeUtil: require('./src/ConfigChanges/munge-util.js'), - - xmlHelpers: require('./src/util/xml-helpers') -}; +var addProperty = require('./src/util/addProperty'); + +module.exports = { }; + +addProperty(module, 'events', './src/events'); +addProperty(module, 'superspawn', './src/superspawn'); + +addProperty(module, 'ActionStack', './src/ActionStack'); +addProperty(module, 'CordovaError', './src/CordovaError/CordovaError'); +addProperty(module, 'CordovaLogger', './src/CordovaLogger'); +addProperty(module, 'CordovaExternalToolErrorContext', './src/CordovaError/CordovaExternalToolErrorContext'); +addProperty(module, 'PlatformJson', './src/PlatformJson'); +addProperty(module, 'ConfigParser', './src/ConfigParser/ConfigParser'); +addProperty(module, 'FileUpdater', './src/FileUpdater'); + +addProperty(module, 'PluginInfo', './src/PluginInfo/PluginInfo'); +addProperty(module, 'PluginInfoProvider', './src/PluginInfo/PluginInfoProvider'); + +addProperty(module, 'PluginManager', './src/PluginManager'); + +addProperty(module, 'ConfigChanges', './src/ConfigChanges/ConfigChanges'); +addProperty(module, 'ConfigKeeper', './src/ConfigChanges/ConfigKeeper'); +addProperty(module, 'ConfigFile', './src/ConfigChanges/ConfigFile'); +addProperty(module, 'mungeUtil', './src/ConfigChanges/munge-util'); + +addProperty(module, 'xmlHelpers', './src/util/xml-helpers'); + diff --git a/platforms/android/cordova/node_modules/cordova-common/package.json b/platforms/android/cordova/node_modules/cordova-common/package.json index 4bd1675..0c2350b 100644 --- a/platforms/android/cordova/node_modules/cordova-common/package.json +++ b/platforms/android/cordova/node_modules/cordova-common/package.json @@ -1,48 +1,57 @@ { "_args": [ [ - "cordova-common@^1.1.0", - "/Users/steveng/repo/cordova/cordova-android" + { + "raw": "cordova-common@^1.3.0", + "scope": null, + "escapedName": "cordova-common", + "name": "cordova-common", + "rawSpec": "^1.3.0", + "spec": ">=1.3.0 <2.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android" ] ], - "_from": "cordova-common@>=1.1.0 <2.0.0", - "_id": "cordova-common@1.1.0", + "_from": "cordova-common@>=1.3.0 <2.0.0", + "_id": "cordova-common@1.3.0", "_inCache": true, "_installable": true, "_location": "/cordova-common", - "_nodeVersion": "4.2.3", + "_nodeVersion": "5.4.1", "_npmOperationalInternal": { - "host": "packages-5-east.internal.npmjs.com", - "tmp": "tmp/cordova-common-1.1.0.tgz_1455781889491_0.6937742941081524" + "host": "packages-16-east.internal.npmjs.com", + "tmp": "tmp/cordova-common-1.3.0.tgz_1464130094288_0.48495062021538615" }, "_npmUser": { - "email": "kotikov.vladimir@gmail.com", - "name": "kotikov.vladimir" + "name": "stevegill", + "email": "stevengill97@gmail.com" }, - "_npmVersion": "2.14.7", + "_npmVersion": "3.9.0", "_phantomChildren": {}, "_requested": { - "name": "cordova-common", - "raw": "cordova-common@^1.1.0", - "rawSpec": "^1.1.0", + "raw": "cordova-common@^1.3.0", "scope": null, - "spec": ">=1.1.0 <2.0.0", + "escapedName": "cordova-common", + "name": "cordova-common", + "rawSpec": "^1.3.0", + "spec": ">=1.3.0 <2.0.0", "type": "range" }, "_requiredBy": [ "/" ], - "_resolved": "http://registry.npmjs.org/cordova-common/-/cordova-common-1.1.0.tgz", - "_shasum": "8682721466ee354747ec6241f34f412b7e0ef636", + "_resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-1.3.0.tgz", + "_shasum": "f75161f6aa7cef5486fd5d69a3b0a1f628334491", "_shrinkwrap": null, - "_spec": "cordova-common@^1.1.0", - "_where": "/Users/steveng/repo/cordova/cordova-android", + "_spec": "cordova-common@^1.3.0", + "_where": "d:\\cordova\\cordova-android", "author": { "name": "Apache Software Foundation" }, "bugs": { - "email": "dev@cordova.apache.org", - "url": "https://issues.apache.org/jira/browse/CB" + "url": "https://issues.apache.org/jira/browse/CB", + "email": "dev@cordova.apache.org" }, "contributors": [], "dependencies": { @@ -51,11 +60,12 @@ "cordova-registry-mapper": "^1.1.8", "elementtree": "^0.1.6", "glob": "^5.0.13", + "minimatch": "^3.0.0", "osenv": "^0.1.3", "plist": "^1.2.0", "q": "^1.4.1", "semver": "^5.0.1", - "shelljs": "^0.5.1", + "shelljs": "^0.5.3", "underscore": "^1.8.3", "unorm": "^1.3.3" }, @@ -63,12 +73,14 @@ "devDependencies": { "istanbul": "^0.3.17", "jasmine-node": "^1.14.5", - "jshint": "^2.8.0" + "jshint": "^2.8.0", + "promise-matchers": "^0.9.6", + "rewire": "^2.5.1" }, "directories": {}, "dist": { - "shasum": "8682721466ee354747ec6241f34f412b7e0ef636", - "tarball": "http://registry.npmjs.org/cordova-common/-/cordova-common-1.1.0.tgz" + "shasum": "f75161f6aa7cef5486fd5d69a3b0a1f628334491", + "tarball": "https://registry.npmjs.org/cordova-common/-/cordova-common-1.3.0.tgz" }, "engineStrict": true, "engines": { @@ -115,5 +127,5 @@ "jshint": "node node_modules/jshint/bin/jshint src && node node_modules/jshint/bin/jshint spec", "test": "npm run jshint && npm run jasmine" }, - "version": "1.1.0" + "version": "1.3.0" } diff --git a/platforms/android/cordova/node_modules/cordova-common/src/ConfigChanges/ConfigFile.js b/platforms/android/cordova/node_modules/cordova-common/src/ConfigChanges/ConfigFile.js index dd9ebbc..9c540b9 100644 --- a/platforms/android/cordova/node_modules/cordova-common/src/ConfigChanges/ConfigFile.js +++ b/platforms/android/cordova/node_modules/cordova-common/src/ConfigChanges/ConfigFile.js @@ -17,13 +17,17 @@ var fs = require('fs'); var path = require('path'); -var bplist = require('bplist-parser'); -var et = require('elementtree'); -var glob = require('glob'); -var plist = require('plist'); - -var plist_helpers = require('../util/plist-helpers'); -var xml_helpers = require('../util/xml-helpers'); +var modules = {}; +var addProperty = require('../util/addProperty'); + +// Use delay loading to ensure plist and other node modules to not get loaded +// on Android, Windows platforms +addProperty(module, 'bplist', 'bplist-parser', modules); +addProperty(module, 'et', 'elementtree', modules); +addProperty(module, 'glob', 'glob', modules); +addProperty(module, 'plist', 'plist', modules); +addProperty(module, 'plist_helpers', '../util/plist-helpers', modules); +addProperty(module, 'xml_helpers', '../util/xml-helpers', modules); /****************************************************************************** * ConfigFile class @@ -67,7 +71,7 @@ function ConfigFile_load() { // the same in a future release if (ext == '.xml' || ext == '.appxmanifest') { self.type = 'xml'; - self.data = xml_helpers.parseElementtreeSync(filepath); + self.data = modules.xml_helpers.parseElementtreeSync(filepath); } else { // plist file self.type = 'plist'; @@ -76,8 +80,8 @@ function ConfigFile_load() { // Do we still need to support binary plist? // If yes, use plist.parseStringSync() and read the file once. self.data = isBinaryPlist(filepath) ? - bplist.parseBuffer(fs.readFileSync(filepath)) : - plist.parse(fs.readFileSync(filepath, 'utf8')); + modules.bplist.parseBuffer(fs.readFileSync(filepath)) : + modules.plist.parse(fs.readFileSync(filepath, 'utf8')); } } @@ -88,7 +92,7 @@ ConfigFile.prototype.save = function ConfigFile_save() { } else { // plist var regExp = new RegExp('[ \t\r\n]+?', 'g'); - fs.writeFileSync(self.filepath, plist.build(self.data).replace(regExp, '')); + fs.writeFileSync(self.filepath, modules.plist.build(self.data).replace(regExp, '')); } self.is_changed = false; }; @@ -98,16 +102,16 @@ ConfigFile.prototype.graft_child = function ConfigFile_graft_child(selector, xml var filepath = self.filepath; var result; if (self.type === 'xml') { - var xml_to_graft = [et.XML(xml_child.xml)]; - result = xml_helpers.graftXML(self.data, xml_to_graft, selector, xml_child.after); + var xml_to_graft = [modules.et.XML(xml_child.xml)]; + result = modules.xml_helpers.graftXML(self.data, xml_to_graft, selector, xml_child.after); if ( !result) { - throw new Error('grafting xml at selector "' + selector + '" from "' + filepath + '" during config install went bad :('); + throw new Error('Unable to graft xml at selector "' + selector + '" from "' + filepath + '" during config install'); } } else { // plist file - result = plist_helpers.graftPLIST(self.data, xml_child.xml, selector); + result = modules.plist_helpers.graftPLIST(self.data, xml_child.xml, selector); if ( !result ) { - throw new Error('grafting to plist "' + filepath + '" during config install went bad :('); + throw new Error('Unable to graft plist "' + filepath + '" during config install'); } } self.is_changed = true; @@ -118,11 +122,11 @@ ConfigFile.prototype.prune_child = function ConfigFile_prune_child(selector, xml var filepath = self.filepath; var result; if (self.type === 'xml') { - var xml_to_graft = [et.XML(xml_child.xml)]; - result = xml_helpers.pruneXML(self.data, xml_to_graft, selector); + var xml_to_graft = [modules.et.XML(xml_child.xml)]; + result = modules.xml_helpers.pruneXML(self.data, xml_to_graft, selector); } else { // plist file - result = plist_helpers.prunePLIST(self.data, xml_child.xml, selector); + result = modules.plist_helpers.prunePLIST(self.data, xml_child.xml, selector); } if (!result) { var err_msg = 'Pruning at selector "' + selector + '" from "' + filepath + '" went bad.'; @@ -140,7 +144,7 @@ function resolveConfigFilePath(project_dir, platform, file) { if (file.indexOf('*') > -1) { // handle wildcards in targets using glob. - matches = glob.sync(path.join(project_dir, '**', file)); + matches = modules.glob.sync(path.join(project_dir, '**', file)); if (matches.length) filepath = matches[0]; // [CB-5989] multiple Info.plist files may exist. default to $PROJECT_NAME-Info.plist @@ -167,7 +171,7 @@ function resolveConfigFilePath(project_dir, platform, file) { } else if (platform == 'android') { filepath = path.join(project_dir, 'res', 'xml', 'config.xml'); } else { - matches = glob.sync(path.join(project_dir, '**', 'config.xml')); + matches = modules.glob.sync(path.join(project_dir, '**', 'config.xml')); if (matches.length) filepath = matches[0]; } return filepath; @@ -180,7 +184,7 @@ function resolveConfigFilePath(project_dir, platform, file) { // Find out the real name of an iOS project // TODO: glob is slow, need a better way or caching, or avoid using more than once. function getIOSProjectname(project_dir) { - var matches = glob.sync(path.join(project_dir, '*.xcodeproj')); + var matches = modules.glob.sync(path.join(project_dir, '*.xcodeproj')); var iospath; if (matches.length === 1) { iospath = path.basename(matches[0],'.xcodeproj'); diff --git a/platforms/android/cordova/node_modules/cordova-common/src/ConfigParser/ConfigParser.js b/platforms/android/cordova/node_modules/cordova-common/src/ConfigParser/ConfigParser.js index 7abddf6..aae59db 100644 --- a/platforms/android/cordova/node_modules/cordova-common/src/ConfigParser/ConfigParser.js +++ b/platforms/android/cordova/node_modules/cordova-common/src/ConfigParser/ConfigParser.js @@ -186,6 +186,7 @@ ConfigParser.prototype = { staticResources.forEach(function (elt) { var res = {}; res.src = elt.attrib.src; + res.target = elt.attrib.target || undefined; res.density = elt.attrib['density'] || elt.attrib[that.cdvNamespacePrefix+':density'] || elt.attrib['gap:density']; res.platform = elt.platform || null; // null means icon represents default icon (shared between platforms) res.width = +elt.attrib.width || undefined; diff --git a/platforms/android/cordova/node_modules/cordova-common/src/CordovaLogger.js b/platforms/android/cordova/node_modules/cordova-common/src/CordovaLogger.js index 06dbcf3..dc49a4b 100644 --- a/platforms/android/cordova/node_modules/cordova-common/src/CordovaLogger.js +++ b/platforms/android/cordova/node_modules/cordova-common/src/CordovaLogger.js @@ -1,203 +1,220 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. - */ - -var ansi = require('ansi'); -var EventEmitter = require('events').EventEmitter; -var CordovaError = require('./CordovaError/CordovaError'); -var EOL = require('os').EOL; - -var INSTANCE; - -/** - * @class CordovaLogger - * - * Implements logging facility that anybody could use. Should not be - * instantiated directly, `CordovaLogger.get()` method should be used instead - * to acquire logger instance - */ -function CordovaLogger () { - this.levels = {}; - this.colors = {}; - this.stdout = process.stdout; - this.stderr = process.stderr; - - this.stdoutCursor = ansi(this.stdout); - this.stderrCursor = ansi(this.stderr); - - this.addLevel('verbose', 1000, 'grey'); - this.addLevel('normal' , 2000); - this.addLevel('warn' , 2000, 'yellow'); - this.addLevel('info' , 3000, 'blue'); - this.addLevel('error' , 5000, 'red'); - this.addLevel('results' , 10000); - - this.setLevel('normal'); -} - -/** - * Static method to create new or acquire existing instance. - * - * @return {CordovaLogger} Logger instance - */ -CordovaLogger.get = function () { - return INSTANCE || (INSTANCE = new CordovaLogger()); -}; - -CordovaLogger.VERBOSE = 'verbose'; -CordovaLogger.NORMAL = 'normal'; -CordovaLogger.WARN = 'warn'; -CordovaLogger.INFO = 'info'; -CordovaLogger.ERROR = 'error'; -CordovaLogger.RESULTS = 'results'; - -/** - * Emits log message to process' stdout/stderr depending on message's severity - * and current log level. If severity is less than current logger's level, - * then the message is ignored. - * - * @param {String} logLevel The message's log level. The logger should have - * corresponding level added (via logger.addLevel), otherwise - * `CordovaLogger.NORMAL` level will be used. - * @param {String} message The message, that should be logged to process' - * stdio - * - * @return {CordovaLogger} Current instance, to allow calls chaining. - */ -CordovaLogger.prototype.log = function (logLevel, message) { - // if there is no such logLevel defined, or provided level has - // less severity than active level, then just ignore this call and return - if (!this.levels[logLevel] || this.levels[logLevel] < this.levels[this.logLevel]) - // return instance to allow to chain calls - return this; - - var isVerbose = this.logLevel === 'verbose'; - var cursor = this.stdoutCursor; - - if(message instanceof Error || logLevel === CordovaLogger.ERROR) { - message = formatError(message, isVerbose); - cursor = this.stderrCursor; - } - - var color = this.colors[logLevel]; - if (color) { - cursor.bold().fg[color](); - } - - cursor.write(message).reset().write(EOL); - - return this; -}; - -/** - * Adds a new level to logger instance. This method also creates a shortcut - * method to log events with the level provided (i.e. after adding new level - * 'debug', the method `debug(message)`, equal to logger.log('debug', message), - * will be added to logger instance) - * - * @param {String} level A log level name. The levels with the following - * names added by default to every instance: 'verbose', 'normal', 'warn', - * 'info', 'error', 'results' - * @param {Number} severity A number that represents level's severity. - * @param {String} color A valid color name, that will be used to log - * messages with this level. Any CSS color code or RGB value is allowed - * (according to ansi documentation: - * https://github.com/TooTallNate/ansi.js#features) - * - * @return {CordovaLogger} Current instance, to allow calls chaining. - */ -CordovaLogger.prototype.addLevel = function (level, severity, color) { - - this.levels[level] = severity; - - if (color) { - this.colors[level] = color; - } - - // Define own method with corresponding name - if (!this[level]) { - this[level] = this.log.bind(this, level); - } - - return this; -}; - -/** - * Sets the current logger level to provided value. If logger doesn't have level - * with this name, `CordovaLogger.NORMAL` will be used. - * - * @param {String} logLevel Level name. The level with this name should be - * added to logger before. - * - * @return {CordovaLogger} Current instance, to allow calls chaining. - */ -CordovaLogger.prototype.setLevel = function (logLevel) { - this.logLevel = this.levels[logLevel] ? logLevel : CordovaLogger.NORMAL; - - return this; -}; - -/** - * Attaches logger to EventEmitter instance provided. - * - * @param {EventEmitter} eventEmitter An EventEmitter instance to attach - * logger to. - * - * @return {CordovaLogger} Current instance, to allow calls chaining. - */ -CordovaLogger.prototype.subscribe = function (eventEmitter) { - - if (!(eventEmitter instanceof EventEmitter)) - throw new Error('Subscribe method only accepts an EventEmitter instance as argument'); - - eventEmitter.on('verbose', this.verbose) - .on('log', this.normal) - .on('info', this.info) - .on('warn', this.warn) - .on('warning', this.warn) - // Set up event handlers for logging and results emitted as events. - .on('results', this.results); - - return this; -}; - -function formatError(error, isVerbose) { - var message = ''; - - if(error instanceof CordovaError) { - message = error.toString(isVerbose); - } else if(error instanceof Error) { - if(isVerbose) { - message = error.stack; - } else { - message = error.message; - } - } else { - // Plain text error message - message = error; - } - - if(message.toUpperCase().indexOf('ERROR:') !== 0) { - // Needed for backward compatibility with external tools - message = 'Error: ' + message; - } - - return message; -} - -module.exports = CordovaLogger; +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + */ + +var ansi = require('ansi'); +var EventEmitter = require('events').EventEmitter; +var CordovaError = require('./CordovaError/CordovaError'); +var EOL = require('os').EOL; + +var INSTANCE; + +/** + * @class CordovaLogger + * + * Implements logging facility that anybody could use. Should not be + * instantiated directly, `CordovaLogger.get()` method should be used instead + * to acquire logger instance + */ +function CordovaLogger () { + this.levels = {}; + this.colors = {}; + this.stdout = process.stdout; + this.stderr = process.stderr; + + this.stdoutCursor = ansi(this.stdout); + this.stderrCursor = ansi(this.stderr); + + this.addLevel('verbose', 1000, 'grey'); + this.addLevel('normal' , 2000); + this.addLevel('warn' , 2000, 'yellow'); + this.addLevel('info' , 3000, 'blue'); + this.addLevel('error' , 5000, 'red'); + this.addLevel('results' , 10000); + + this.setLevel('normal'); +} + +/** + * Static method to create new or acquire existing instance. + * + * @return {CordovaLogger} Logger instance + */ +CordovaLogger.get = function () { + return INSTANCE || (INSTANCE = new CordovaLogger()); +}; + +CordovaLogger.VERBOSE = 'verbose'; +CordovaLogger.NORMAL = 'normal'; +CordovaLogger.WARN = 'warn'; +CordovaLogger.INFO = 'info'; +CordovaLogger.ERROR = 'error'; +CordovaLogger.RESULTS = 'results'; + +/** + * Emits log message to process' stdout/stderr depending on message's severity + * and current log level. If severity is less than current logger's level, + * then the message is ignored. + * + * @param {String} logLevel The message's log level. The logger should have + * corresponding level added (via logger.addLevel), otherwise + * `CordovaLogger.NORMAL` level will be used. + * @param {String} message The message, that should be logged to process' + * stdio + * + * @return {CordovaLogger} Current instance, to allow calls chaining. + */ +CordovaLogger.prototype.log = function (logLevel, message) { + // if there is no such logLevel defined, or provided level has + // less severity than active level, then just ignore this call and return + if (!this.levels[logLevel] || this.levels[logLevel] < this.levels[this.logLevel]) + // return instance to allow to chain calls + return this; + + var isVerbose = this.logLevel === 'verbose'; + var cursor = this.stdoutCursor; + + if (message instanceof Error || logLevel === CordovaLogger.ERROR) { + message = formatError(message, isVerbose); + cursor = this.stderrCursor; + } + + var color = this.colors[logLevel]; + if (color) { + cursor.bold().fg[color](); + } + + cursor.write(message).reset().write(EOL); + + return this; +}; + +/** + * Adds a new level to logger instance. This method also creates a shortcut + * method to log events with the level provided (i.e. after adding new level + * 'debug', the method `debug(message)`, equal to logger.log('debug', message), + * will be added to logger instance) + * + * @param {String} level A log level name. The levels with the following + * names added by default to every instance: 'verbose', 'normal', 'warn', + * 'info', 'error', 'results' + * @param {Number} severity A number that represents level's severity. + * @param {String} color A valid color name, that will be used to log + * messages with this level. Any CSS color code or RGB value is allowed + * (according to ansi documentation: + * https://github.com/TooTallNate/ansi.js#features) + * + * @return {CordovaLogger} Current instance, to allow calls chaining. + */ +CordovaLogger.prototype.addLevel = function (level, severity, color) { + + this.levels[level] = severity; + + if (color) { + this.colors[level] = color; + } + + // Define own method with corresponding name + if (!this[level]) { + this[level] = this.log.bind(this, level); + } + + return this; +}; + +/** + * Sets the current logger level to provided value. If logger doesn't have level + * with this name, `CordovaLogger.NORMAL` will be used. + * + * @param {String} logLevel Level name. The level with this name should be + * added to logger before. + * + * @return {CordovaLogger} Current instance, to allow calls chaining. + */ +CordovaLogger.prototype.setLevel = function (logLevel) { + this.logLevel = this.levels[logLevel] ? logLevel : CordovaLogger.NORMAL; + + return this; +}; + +/** + * Adjusts the current logger level according to the passed options. + * + * @param {Object|Array} opts An object or args array with options + * + * @return {CordovaLogger} Current instance, to allow calls chaining. + */ +CordovaLogger.prototype.adjustLevel = function (opts) { + if (opts.verbose || (Array.isArray(opts) && opts.indexOf('--verbose') !== -1)) { + this.setLevel('verbose'); + } else if (opts.silent || (Array.isArray(opts) && opts.indexOf('--silent') !== -1)) { + this.setLevel('error'); + } + + return this; +}; + +/** + * Attaches logger to EventEmitter instance provided. + * + * @param {EventEmitter} eventEmitter An EventEmitter instance to attach + * logger to. + * + * @return {CordovaLogger} Current instance, to allow calls chaining. + */ +CordovaLogger.prototype.subscribe = function (eventEmitter) { + + if (!(eventEmitter instanceof EventEmitter)) + throw new Error('Subscribe method only accepts an EventEmitter instance as argument'); + + eventEmitter.on('verbose', this.verbose) + .on('log', this.normal) + .on('info', this.info) + .on('warn', this.warn) + .on('warning', this.warn) + // Set up event handlers for logging and results emitted as events. + .on('results', this.results); + + return this; +}; + +function formatError(error, isVerbose) { + var message = ''; + + if (error instanceof CordovaError) { + message = error.toString(isVerbose); + } else if (error instanceof Error) { + if (isVerbose) { + message = error.stack; + } else { + message = error.message; + } + } else { + // Plain text error message + message = error; + } + + if (typeof message === 'string' && message.toUpperCase().indexOf('ERROR:') !== 0) { + // Needed for backward compatibility with external tools + message = 'Error: ' + message; + } + + return message; +} + +module.exports = CordovaLogger; diff --git a/platforms/android/cordova/node_modules/cordova-common/src/FileUpdater.js b/platforms/android/cordova/node_modules/cordova-common/src/FileUpdater.js new file mode 100644 index 0000000..a09f39c --- /dev/null +++ b/platforms/android/cordova/node_modules/cordova-common/src/FileUpdater.js @@ -0,0 +1,422 @@ +/** + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ + +"use strict"; + +var fs = require("fs"); +var path = require("path"); +var shell = require("shelljs"); +var minimatch = require("minimatch"); + +/** + * Logging callback used in the FileUpdater methods. + * @callback loggingCallback + * @param {string} message A message describing a single file update operation. + */ + +/** + * Updates a target file or directory with a source file or directory. (Directory updates are + * not recursive.) Stats for target and source items must be passed in. This is an internal + * helper function used by other methods in this module. + * + * @param {?string} sourcePath Source file or directory to be used to update the + * destination. If the source is null, then the destination is deleted if it exists. + * @param {?fs.Stats} sourceStats An instance of fs.Stats for the source path, or null if + * the source does not exist. + * @param {string} targetPath Required destination file or directory to be updated. If it does + * not exist, it will be created. + * @param {?fs.Stats} targetStats An instance of fs.Stats for the target path, or null if + * the target does not exist. + * @param {Object} [options] Optional additional parameters for the update. + * @param {string} [options.rootDir] Optional root directory (such as a project) to which target + * and source path parameters are relative; may be omitted if the paths are absolute. The + * rootDir is always omitted from any logged paths, to make the logs easier to read. + * @param {boolean} [options.all] If true, all files are copied regardless of last-modified times. + * Otherwise, a file is copied if the source's last-modified time is greather than or + * equal to the target's last-modified time, or if the file sizes are different. + * @param {loggingCallback} [log] Optional logging callback that takes a string message + * describing any file operations that are performed. + * @return {boolean} true if any changes were made, or false if the force flag is not set + * and everything was up to date + */ +function updatePathWithStats(sourcePath, sourceStats, targetPath, targetStats, options, log) { + var updated = false; + + var rootDir = (options && options.rootDir) || ""; + var copyAll = (options && options.all) || false; + + var targetFullPath = path.join(rootDir || "", targetPath); + + if (sourceStats) { + var sourceFullPath = path.join(rootDir || "", sourcePath); + + if (targetStats) { + // The target exists. But if the directory status doesn't match the source, delete it. + if (targetStats.isDirectory() && !sourceStats.isDirectory()) { + log("rmdir " + targetPath + " (source is a file)"); + shell.rm("-rf", targetFullPath); + targetStats = null; + updated = true; + } else if (!targetStats.isDirectory() && sourceStats.isDirectory()) { + log("delete " + targetPath + " (source is a directory)"); + shell.rm("-f", targetFullPath); + targetStats = null; + updated = true; + } + } + + if (!targetStats) { + if (sourceStats.isDirectory()) { + // The target directory does not exist, so it should be created. + log("mkdir " + targetPath); + shell.mkdir("-p", targetFullPath); + updated = true; + } else if (sourceStats.isFile()) { + // The target file does not exist, so it should be copied from the source. + log("copy " + sourcePath + " " + targetPath + (copyAll ? "" : " (new file)")); + shell.cp("-f", sourceFullPath, targetFullPath); + updated = true; + } + } else if (sourceStats.isFile() && targetStats.isFile()) { + // The source and target paths both exist and are files. + if (copyAll) { + // The caller specified all files should be copied. + log("copy " + sourcePath + " " + targetPath); + shell.cp("-f", sourceFullPath, targetFullPath); + updated = true; + } else { + // Copy if the source has been modified since it was copied to the target, or if + // the file sizes are different. (The latter catches most cases in which something + // was done to the file after copying.) Comparison is >= rather than > to allow + // for timestamps lacking sub-second precision in some filesystems. + if (sourceStats.mtime.getTime() >= targetStats.mtime.getTime() || + sourceStats.size !== targetStats.size) { + log("copy " + sourcePath + " " + targetPath + " (updated file)"); + shell.cp("-f", sourceFullPath, targetFullPath); + updated = true; + } + } + } + } else if (targetStats) { + // The target exists but the source is null, so the target should be deleted. + if (targetStats.isDirectory()) { + log("rmdir " + targetPath + (copyAll ? "" : " (no source)")); + shell.rm("-rf", targetFullPath); + } else { + log("delete " + targetPath + (copyAll ? "" : " (no source)")); + shell.rm("-f", targetFullPath); + } + updated = true; + } + + return updated; +} + +/** + * Helper for updatePath and updatePaths functions. Queries stats for source and target + * and ensures target directory exists before copying a file. + */ +function updatePathInternal(sourcePath, targetPath, options, log) { + var rootDir = (options && options.rootDir) || ""; + var targetFullPath = path.join(rootDir, targetPath); + var targetStats = fs.existsSync(targetFullPath) ? fs.statSync(targetFullPath) : null; + var sourceStats = null; + + if (sourcePath) { + // A non-null source path was specified. It should exist. + var sourceFullPath = path.join(rootDir, sourcePath); + if (!fs.existsSync(sourceFullPath)) { + throw new Error("Source path does not exist: " + sourcePath); + } + + sourceStats = fs.statSync(sourceFullPath); + + // Create the target's parent directory if it doesn't exist. + var parentDir = path.dirname(targetFullPath); + if (!fs.existsSync(parentDir)) { + shell.mkdir("-p", parentDir); + } + } + + return updatePathWithStats(sourcePath, sourceStats, targetPath, targetStats, options, log); +} + +/** + * Updates a target file or directory with a source file or directory. (Directory updates are + * not recursive.) + * + * @param {?string} sourcePath Source file or directory to be used to update the + * destination. If the source is null, then the destination is deleted if it exists. + * @param {string} targetPath Required destination file or directory to be updated. If it does + * not exist, it will be created. + * @param {Object} [options] Optional additional parameters for the update. + * @param {string} [options.rootDir] Optional root directory (such as a project) to which target + * and source path parameters are relative; may be omitted if the paths are absolute. The + * rootDir is always omitted from any logged paths, to make the logs easier to read. + * @param {boolean} [options.all] If true, all files are copied regardless of last-modified times. + * Otherwise, a file is copied if the source's last-modified time is greather than or + * equal to the target's last-modified time, or if the file sizes are different. + * @param {loggingCallback} [log] Optional logging callback that takes a string message + * describing any file operations that are performed. + * @return {boolean} true if any changes were made, or false if the force flag is not set + * and everything was up to date + */ +function updatePath(sourcePath, targetPath, options, log) { + if (sourcePath !== null && typeof sourcePath !== "string") { + throw new Error("A source path (or null) is required."); + } + + if (!targetPath || typeof targetPath !== "string") { + throw new Error("A target path is required."); + } + + log = log || function(message) { }; + + return updatePathInternal(sourcePath, targetPath, options, log); +} + +/** + * Updates files and directories based on a mapping from target paths to source paths. Targets + * with null sources in the map are deleted. + * + * @param {Object} pathMap A dictionary mapping from target paths to source paths. + * @param {Object} [options] Optional additional parameters for the update. + * @param {string} [options.rootDir] Optional root directory (such as a project) to which target + * and source path parameters are relative; may be omitted if the paths are absolute. The + * rootDir is always omitted from any logged paths, to make the logs easier to read. + * @param {boolean} [options.all] If true, all files are copied regardless of last-modified times. + * Otherwise, a file is copied if the source's last-modified time is greather than or + * equal to the target's last-modified time, or if the file sizes are different. + * @param {loggingCallback} [log] Optional logging callback that takes a string message + * describing any file operations that are performed. + * @return {boolean} true if any changes were made, or false if the force flag is not set + * and everything was up to date + */ +function updatePaths(pathMap, options, log) { + if (!pathMap || typeof pathMap !== "object" || Array.isArray(pathMap)) { + throw new Error("An object mapping from target paths to source paths is required."); + } + + log = log || function(message) { }; + + var updated = false; + + // Iterate in sorted order to ensure directories are created before files under them. + Object.keys(pathMap).sort().forEach(function (targetPath) { + var sourcePath = pathMap[targetPath]; + updated = updatePathInternal(sourcePath, targetPath, options, log) || updated; + }); + + return updated; +} + +/** + * Updates a target directory with merged files and subdirectories from source directories. + * + * @param {string|string[]} sourceDirs Required source directory or array of source directories + * to be merged into the target. The directories are listed in order of precedence; files in + * directories later in the array supersede files in directories earlier in the array + * (regardless of timestamps). + * @param {string} targetDir Required destination directory to be updated. If it does not exist, + * it will be created. If it exists, newer files from source directories will be copied over, + * and files missing in the source directories will be deleted. + * @param {Object} [options] Optional additional parameters for the update. + * @param {string} [options.rootDir] Optional root directory (such as a project) to which target + * and source path parameters are relative; may be omitted if the paths are absolute. The + * rootDir is always omitted from any logged paths, to make the logs easier to read. + * @param {boolean} [options.all] If true, all files are copied regardless of last-modified times. + * Otherwise, a file is copied if the source's last-modified time is greather than or + * equal to the target's last-modified time, or if the file sizes are different. + * @param {string|string[]} [options.include] Optional glob string or array of glob strings that + * are tested against both target and source relative paths to determine if they are included + * in the merge-and-update. If unspecified, all items are included. + * @param {string|string[]} [options.exclude] Optional glob string or array of glob strings that + * are tested against both target and source relative paths to determine if they are excluded + * from the merge-and-update. Exclusions override inclusions. If unspecified, no items are + * excluded. + * @param {loggingCallback} [log] Optional logging callback that takes a string message + * describing any file operations that are performed. + * @return {boolean} true if any changes were made, or false if the force flag is not set + * and everything was up to date + */ +function mergeAndUpdateDir(sourceDirs, targetDir, options, log) { + if (sourceDirs && typeof sourceDirs === "string") { + sourceDirs = [ sourceDirs ]; + } else if (!Array.isArray(sourceDirs)) { + throw new Error("A source directory path or array of paths is required."); + } + + if (!targetDir || typeof targetDir !== "string") { + throw new Error("A target directory path is required."); + } + + log = log || function(message) { }; + + var rootDir = (options && options.rootDir) || ""; + + var include = (options && options.include) || [ "**" ]; + if (typeof include === "string") { + include = [ include ]; + } else if (!Array.isArray(include)) { + throw new Error("Include parameter must be a glob string or array of glob strings."); + } + + var exclude = (options && options.exclude) || []; + if (typeof exclude === "string") { + exclude = [ exclude ]; + } else if (!Array.isArray(exclude)) { + throw new Error("Exclude parameter must be a glob string or array of glob strings."); + } + + // Scan the files in each of the source directories. + var sourceMaps = []; + for (var i in sourceDirs) { + var sourceFullPath = path.join(rootDir, sourceDirs[i]); + if (!fs.existsSync(sourceFullPath)) { + throw new Error("Source directory does not exist: " + sourceDirs[i]); + } + sourceMaps[i] = mapDirectory(rootDir, sourceDirs[i], include, exclude); + } + + // Scan the files in the target directory, if it exists. + var targetMap = {}; + var targetFullPath = path.join(rootDir, targetDir); + if (fs.existsSync(targetFullPath)) { + targetMap = mapDirectory(rootDir, targetDir, include, exclude); + } + + var pathMap = mergePathMaps(sourceMaps, targetMap, targetDir); + + var updated = false; + + // Iterate in sorted order to ensure directories are created before files under them. + Object.keys(pathMap).sort().forEach(function (subPath) { + var entry = pathMap[subPath]; + updated = updatePathWithStats( + entry.sourcePath, + entry.sourceStats, + entry.targetPath, + entry.targetStats, + options, + log) || updated; + }); + + return updated; +} + +/** + * Creates a dictionary map of all files and directories under a path. + */ +function mapDirectory(rootDir, subDir, include, exclude) { + var dirMap = { "": { subDir: subDir, stats: fs.statSync(path.join(rootDir, subDir)) } }; + mapSubdirectory(rootDir, subDir, "", include, exclude, dirMap); + return dirMap; + + function mapSubdirectory(rootDir, subDir, relativeDir, include, exclude, dirMap) { + var itemMapped = false; + var items = fs.readdirSync(path.join(rootDir, subDir, relativeDir)); + for (var i in items) { + var relativePath = path.join(relativeDir, items[i]); + + // Skip any files or directories (and everything under) that match an exclude glob. + if (matchGlobArray(relativePath, exclude)) { + continue; + } + + // Stats obtained here (required at least to know where to recurse in directories) + // are saved for later, where the modified times may also be used. This minimizes + // the number of file I/O operations performed. + var fullPath = path.join(rootDir, subDir, relativePath); + var stats = fs.statSync(fullPath); + + if (stats.isDirectory()) { + // Directories are included if either something under them is included or they + // match an include glob. + if (mapSubdirectory(rootDir, subDir, relativePath, include, exclude, dirMap) || + matchGlobArray(relativePath, include)) { + dirMap[relativePath] = { subDir: subDir, stats: stats }; + itemMapped = true; + } + } else if (stats.isFile()) { + // Files are included only if they match an include glob. + if (matchGlobArray(relativePath, include)) { + dirMap[relativePath] = { subDir: subDir, stats: stats }; + itemMapped = true; + } + } + } + return itemMapped; + } + + function matchGlobArray(path, globs) { + for (var i in globs) { + if (minimatch(path, globs[i])) { + return true; + } + } + return false; + } +} + +/** + * Merges together multiple source maps and a target map into a single mapping from + * relative paths to objects with target and source paths and stats. + */ +function mergePathMaps(sourceMaps, targetMap, targetDir) { + // Merge multiple source maps together, along with target path info. + // Entries in later source maps override those in earlier source maps. + // Target stats will be filled in below for targets that exist. + var pathMap = {}; + sourceMaps.forEach(function (sourceMap) { + for (var sourceSubPath in sourceMap) { + var sourceEntry = sourceMap[sourceSubPath]; + pathMap[sourceSubPath] = { + targetPath: path.join(targetDir, sourceSubPath), + targetStats: null, + sourcePath: path.join(sourceEntry.subDir, sourceSubPath), + sourceStats: sourceEntry.stats + }; + } + }); + + // Fill in target stats for targets that exist, and create entries + // for targets that don't have any corresponding sources. + for (var subPath in targetMap) { + var entry = pathMap[subPath]; + if (entry) { + entry.targetStats = targetMap[subPath].stats; + } else { + pathMap[subPath] = { + targetPath: path.join(targetDir, subPath), + targetStats: targetMap[subPath].stats, + sourcePath: null, + sourceStats: null + }; + } + } + + return pathMap; +} + +module.exports = { + updatePath: updatePath, + updatePaths: updatePaths, + mergeAndUpdateDir: mergeAndUpdateDir +}; + diff --git a/platforms/android/cordova/node_modules/cordova-common/src/PlatformJson.js b/platforms/android/cordova/node_modules/cordova-common/src/PlatformJson.js index 793e976..4e2b287 100644 --- a/platforms/android/cordova/node_modules/cordova-common/src/PlatformJson.js +++ b/platforms/android/cordova/node_modules/cordova-common/src/PlatformJson.js @@ -91,6 +91,38 @@ PlatformJson.prototype.addPlugin = function(pluginId, variables, isTopLevel) { return this; }; +/** + * @chaining + * Generates and adds metadata for provided plugin into associated .json file + * + * @param {PluginInfo} pluginInfo A pluginInfo instance to add metadata from + * @returns {this} Current PlatformJson instance to allow calls chaining + */ +PlatformJson.prototype.addPluginMetadata = function (pluginInfo) { + + var installedModules = this.root.modules || []; + + var installedPaths = installedModules.map(function (installedModule) { + return installedModule.file; + }); + + var modulesToInstall = pluginInfo.getJsModules(this.platform) + .map(function (module) { + return new ModuleMetadata(pluginInfo.id, module); + }) + .filter(function (metadata) { + // Filter out modules which are already added to metadata + return installedPaths.indexOf(metadata.file) === -1; + }); + + this.root.modules = installedModules.concat(modulesToInstall); + + this.root.plugin_metadata = this.root.plugin_metadata || {}; + this.root.plugin_metadata[pluginInfo.id] = pluginInfo.version; + + return this; +}; + PlatformJson.prototype.removePlugin = function(pluginId, isTopLevel) { var pluginsList = isTopLevel ? this.root.installed_plugins : @@ -101,6 +133,35 @@ PlatformJson.prototype.removePlugin = function(pluginId, isTopLevel) { return this; }; +/** + * @chaining + * Removes metadata for provided plugin from associated file + * + * @param {PluginInfo} pluginInfo A PluginInfo instance to which modules' metadata + * we need to remove + * + * @returns {this} Current PlatformJson instance to allow calls chaining + */ +PlatformJson.prototype.removePluginMetadata = function (pluginInfo) { + var modulesToRemove = pluginInfo.getJsModules(this.platform) + .map(function (jsModule) { + return ['plugins', pluginInfo.id, jsModule.src].join('/'); + }); + + var installedModules = this.root.modules || []; + this.root.modules = installedModules + .filter(function (installedModule) { + // Leave only those metadatas which 'file' is not in removed modules + return (modulesToRemove.indexOf(installedModule.file) === -1); + }); + + if (this.root.plugin_metadata) { + delete this.root.plugin_metadata[pluginInfo.id]; + } + + return this; +}; + PlatformJson.prototype.addInstalledPluginToPrepareQueue = function(pluginDirName, vars, is_top_level) { this.root.prepare_queue.installed.push({'plugin':pluginDirName, 'vars':vars, 'topLevel':is_top_level}); }; @@ -125,6 +186,39 @@ PlatformJson.prototype.makeTopLevel = function(pluginId) { return this; }; +/** + * Generates a metadata for all installed plugins and js modules. The resultant + * string is ready to be written to 'cordova_plugins.js' + * + * @returns {String} cordova_plugins.js contents + */ +PlatformJson.prototype.generateMetadata = function () { + return [ + 'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {', + 'module.exports = ' + JSON.stringify(this.root.modules, null, 4) + ';', + 'module.exports.metadata = ', + '// TOP OF METADATA', + JSON.stringify(this.root.plugin_metadata, null, 4) + ';', + '// BOTTOM OF METADATA', + '});' // Close cordova.define. + ].join('\n'); +}; + +/** + * @chaining + * Generates and then saves metadata to specified file. Doesn't check if file exists. + * + * @param {String} destination File metadata will be written to + * @return {PlatformJson} PlatformJson instance + */ +PlatformJson.prototype.generateAndSaveMetadata = function (destination) { + var meta = this.generateMetadata(); + shelljs.mkdir('-p', path.dirname(destination)); + fs.writeFileSync(destination, meta, 'utf-8'); + + return this; +}; + // convert a munge from the old format ([file][parent][xml] = count) to the current one function fix_munge(root) { root.prepare_queue = root.prepare_queue || {installed:[], uninstalled:[]}; @@ -151,5 +245,35 @@ function fix_munge(root) { return root; } +/** + * @constructor + * @class ModuleMetadata + * + * Creates a ModuleMetadata object that represents module entry in 'cordova_plugins.js' + * file at run time + * + * @param {String} pluginId Plugin id where this module installed from + * @param (JsModule|Object) jsModule A js-module entry from PluginInfo class to generate metadata for + */ +function ModuleMetadata (pluginId, jsModule) { + + if (!pluginId) throw new TypeError('pluginId argument must be a valid plugin id'); + if (!jsModule.src && !jsModule.name) throw new TypeError('jsModule argument must contain src or/and name properties'); + + this.id = pluginId + '.' + ( jsModule.name || jsModule.src.match(/([^\/]+)\.js/)[1] ); + this.file = ['plugins', pluginId, jsModule.src].join('/'); + this.pluginId = pluginId; + + if (jsModule.clobbers && jsModule.clobbers.length > 0) { + this.clobbers = jsModule.clobbers.map(function(o) { return o.target; }); + } + if (jsModule.merges && jsModule.merges.length > 0) { + this.merges = jsModule.merges.map(function(o) { return o.target; }); + } + if (jsModule.runs) { + this.runs = true; + } +} + module.exports = PlatformJson; diff --git a/platforms/android/cordova/node_modules/cordova-common/src/PluginInfo/PluginInfo.js b/platforms/android/cordova/node_modules/cordova-common/src/PluginInfo/PluginInfo.js index 2554a3c..77199ec 100644 --- a/platforms/android/cordova/node_modules/cordova-common/src/PluginInfo/PluginInfo.js +++ b/platforms/android/cordova/node_modules/cordova-common/src/PluginInfo/PluginInfo.js @@ -43,18 +43,14 @@ function PluginInfo(dirname) { // tag // Example: // Used to require a variable to be specified via --variable when installing the plugin. + // returns { key : default | null} self.getPreferences = getPreferences; function getPreferences(platform) { - var arprefs = _getTags(self._et, 'preference', platform, _parsePreference); - - var prefs= {}; - for(var i in arprefs) - { - var pref=arprefs[i]; - prefs[pref.preference]=pref.default; - } - // returns { key : default | null} - return prefs; + return _getTags(self._et, 'preference', platform, _parsePreference) + .reduce(function (preferences, pref) { + preferences[pref.preference] = pref.default; + return preferences; + }, {}); } function _parsePreference(prefTag) { @@ -335,7 +331,7 @@ function PluginInfo(dirname) { ///// PluginInfo Constructor logic ///// self.filepath = path.join(dirname, 'plugin.xml'); if (!fs.existsSync(self.filepath)) { - throw new CordovaError('Cannot find plugin.xml for plugin \'' + path.basename(dirname) + '\'. Please try adding it again.'); + throw new CordovaError('Cannot find plugin.xml for plugin "' + path.basename(dirname) + '". Please try adding it again.'); } self.dir = dirname; diff --git a/platforms/android/cordova/node_modules/cordova-common/src/PluginManager.js b/platforms/android/cordova/node_modules/cordova-common/src/PluginManager.js new file mode 100644 index 0000000..deeb92f --- /dev/null +++ b/platforms/android/cordova/node_modules/cordova-common/src/PluginManager.js @@ -0,0 +1,152 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ + +var Q = require('q'); +var fs = require('fs'); +var path = require('path'); + +var ActionStack = require('./ActionStack'); +var PlatformJson = require('./PlatformJson'); +var CordovaError = require('./CordovaError/CordovaError'); +var PlatformMunger = require('./ConfigChanges/ConfigChanges').PlatformMunger; +var PluginInfoProvider = require('./PluginInfo/PluginInfoProvider'); + +/** + * @constructor + * @class PluginManager + * Represents an entity for adding/removing plugins for platforms + * + * @param {String} platform Platform name + * @param {Object} locations - Platform files and directories + * @param {IDEProject} ideProject The IDE project to add/remove plugin changes to/from + */ +function PluginManager(platform, locations, ideProject) { + this.platform = platform; + this.locations = locations; + this.project = ideProject; + + var platformJson = PlatformJson.load(locations.root, platform); + this.munger = new PlatformMunger(platform, locations.root, platformJson, new PluginInfoProvider()); +} + + +/** + * @constructs PluginManager + * A convenience shortcut to new PluginManager(...) + * + * @param {String} platform Platform name + * @param {Object} locations - Platform files and directories + * @param {IDEProject} ideProject The IDE project to add/remove plugin changes to/from + * @returns new PluginManager instance + */ +PluginManager.get = function(platform, locations, ideProject) { + return new PluginManager(platform, locations, ideProject); +}; + +PluginManager.INSTALL = 'install'; +PluginManager.UNINSTALL = 'uninstall'; + +module.exports = PluginManager; + +/** + * Describes and implements common plugin installation/uninstallation routine. The flow is the following: + * * Validate and set defaults for options. Note that options are empty by default. Everything + * needed for platform IDE project must be passed from outside. Plugin variables (which + * are the part of the options) also must be already populated with 'PACKAGE_NAME' variable. + * * Collect all plugin's native and web files, get installers/uninstallers and process + * all these via ActionStack. + * * Save the IDE project, so the changes made by installers are persisted. + * * Generate config changes munge for plugin and apply it to all required files + * * Generate metadata for plugin and plugin modules and save it to 'cordova_plugins.js' + * + * @param {PluginInfo} plugin A PluginInfo structure representing plugin to install + * @param {Object} [options={}] An installation options. It is expected but is not necessary + * that options would contain 'variables' inner object with 'PACKAGE_NAME' field set by caller. + * + * @returns {Promise} Returns a Q promise, either resolved in case of success, rejected otherwise. + */ +PluginManager.prototype.doOperation = function (operation, plugin, options) { + if (operation !== PluginManager.INSTALL && operation !== PluginManager.UNINSTALL) + return Q.reject(new CordovaError('The parameter is incorrect. The opeation must be either "add" or "remove"')); + + if (!plugin || plugin.constructor.name !== 'PluginInfo') + return Q.reject(new CordovaError('The parameter is incorrect. The first parameter should be a PluginInfo instance')); + + // Set default to empty object to play safe when accesing properties + options = options || {}; + + var self = this; + var actions = new ActionStack(); + + // gather all files need to be handled during operation ... + plugin.getFilesAndFrameworks(this.platform) + .concat(plugin.getAssets(this.platform)) + .concat(plugin.getJsModules(this.platform)) + // ... put them into stack ... + .forEach(function(item) { + var installer = self.project.getInstaller(item.itemType); + var uninstaller = self.project.getUninstaller(item.itemType); + var actionArgs = [item, plugin, self.project, options]; + + var action; + if (operation === PluginManager.INSTALL) { + action = actions.createAction.apply(actions, [installer, actionArgs, uninstaller, actionArgs]); + } else /* op === PluginManager.UNINSTALL */{ + action = actions.createAction.apply(actions, [uninstaller, actionArgs, installer, actionArgs]); + } + actions.push(action); + }); + + // ... and run through the action stack + return actions.process(this.platform) + .then(function () { + if (self.project.write) { + self.project.write(); + } + + if (operation === PluginManager.INSTALL) { + // Ignore passed `is_top_level` option since platform itself doesn't know + // anything about managing dependencies - it's responsibility of caller. + self.munger.add_plugin_changes(plugin, options.variables, /*is_top_level=*/true, /*should_increment=*/true); + self.munger.platformJson.addPluginMetadata(plugin); + } else { + self.munger.remove_plugin_changes(plugin, /*is_top_level=*/true); + self.munger.platformJson.removePluginMetadata(plugin); + } + + // Save everything (munge and plugin/modules metadata) + self.munger.save_all(); + + var metadata = self.munger.platformJson.generateMetadata(); + fs.writeFileSync(path.join(self.locations.www, 'cordova_plugins.js'), metadata, 'utf-8'); + + // CB-11022 save plugin metadata to both www and platform_www if options.usePlatformWww is specified + if (options.usePlatformWww) { + fs.writeFileSync(path.join(self.locations.platformWww, 'cordova_plugins.js'), metadata, 'utf-8'); + } + }); +}; + +PluginManager.prototype.addPlugin = function (plugin, installOptions) { + return this.doOperation(PluginManager.INSTALL, plugin, installOptions); +}; + +PluginManager.prototype.removePlugin = function (plugin, uninstallOptions) { + return this.doOperation(PluginManager.UNINSTALL, plugin, uninstallOptions); +}; diff --git a/platforms/android/cordova/node_modules/cordova-common/src/events.js b/platforms/android/cordova/node_modules/cordova-common/src/events.js index 868d363..e702bd8 100644 --- a/platforms/android/cordova/node_modules/cordova-common/src/events.js +++ b/platforms/android/cordova/node_modules/cordova-common/src/events.js @@ -40,9 +40,16 @@ module.exports.forwardEventsTo = function (eventEmitter) { } if (!(eventEmitter instanceof EventEmitter)) - throw new Error('Cordova events could be redirected to another EventEmitter instance only'); + throw new Error('Cordova events can be redirected to another EventEmitter instance only'); - EVENTS_RECEIVER = eventEmitter; + // CB-10940 Skipping forwarding to self to avoid infinite recursion. + // This is the case when the modules are npm-linked. + if (this !== eventEmitter) { + EVENTS_RECEIVER = eventEmitter; + } else { + // Reset forwarding if we are subscribing to self + EVENTS_RECEIVER = undefined; + } }; var emit = INSTANCE.emit; diff --git a/platforms/android/cordova/node_modules/cordova-common/src/util/addProperty.js b/platforms/android/cordova/node_modules/cordova-common/src/util/addProperty.js new file mode 100644 index 0000000..7dc4dc1 --- /dev/null +++ b/platforms/android/cordova/node_modules/cordova-common/src/util/addProperty.js @@ -0,0 +1,32 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ + +module.exports = function addProperty(module, property, modulePath, obj) { + + obj = obj || module.exports; + // Add properties as getter to delay load the modules on first invocation + Object.defineProperty(obj, property, { + configurable: true, + get: function () { + var delayLoadedModule = module.require(modulePath); + obj[property] = delayLoadedModule; + return delayLoadedModule; + } + }); +}; diff --git a/platforms/android/cordova/node_modules/cordova-common/src/util/xml-helpers.js b/platforms/android/cordova/node_modules/cordova-common/src/util/xml-helpers.js index 8b02989..6366af9 100644 --- a/platforms/android/cordova/node_modules/cordova-common/src/util/xml-helpers.js +++ b/platforms/android/cordova/node_modules/cordova-common/src/util/xml-helpers.js @@ -194,7 +194,7 @@ function findInsertIdx(children, after) { } var BLACKLIST = ['platform', 'feature','plugin','engine']; -var SINGLETONS = ['content', 'author']; +var SINGLETONS = ['content', 'author', 'name']; function mergeXml(src, dest, platform, clobber) { // Do nothing for blacklisted tags. if (BLACKLIST.indexOf(src.tag) != -1) return; @@ -209,6 +209,9 @@ function mergeXml(src, dest, platform, clobber) { if (src.text && (clobber || !dest.text)) { dest.text = src.text; } + //Handle children + src.getchildren().forEach(mergeChild); + //Handle platform if (platform) { src.findall('platform[@name="' + platform + '"]').forEach(function (platformElement) { @@ -216,8 +219,8 @@ function mergeXml(src, dest, platform, clobber) { }); } - //Handle children - src.getchildren().forEach(mergeChild); + //Handle duplicate preference tags (by name attribute) + removeDuplicatePreferences(dest); function mergeChild (srcChild) { var srcTag = srcChild.tag, @@ -254,6 +257,26 @@ function mergeXml(src, dest, platform, clobber) { dest.append(destChild); } } + + function removeDuplicatePreferences(xml) { + // reduce preference tags to a hashtable to remove dupes + var prefHash = xml.findall('preference[@name][@value]').reduce(function(previousValue, currentValue) { + previousValue[ currentValue.attrib.name ] = currentValue.attrib.value; + return previousValue; + }, {}); + + // remove all preferences + xml.findall('preference[@name][@value]').forEach(function(pref) { + xml.remove(pref); + }); + + // write new preferences + Object.keys(prefHash).forEach(function(key, index) { + var element = et.SubElement(xml, 'preference'); + element.set('name', key); + element.set('value', this[key]); + }, prefHash); + } } // Expose for testing. diff --git a/platforms/android/cordova/node_modules/cordova-registry-mapper/package.json b/platforms/android/cordova/node_modules/cordova-registry-mapper/package.json index 989efad..2b8af74 100644 --- a/platforms/android/cordova/node_modules/cordova-registry-mapper/package.json +++ b/platforms/android/cordova/node_modules/cordova-registry-mapper/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "cordova-registry-mapper@^1.1.8", - "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common" + { + "raw": "cordova-registry-mapper@^1.1.8", + "scope": null, + "escapedName": "cordova-registry-mapper", + "name": "cordova-registry-mapper", + "rawSpec": "^1.1.8", + "spec": ">=1.1.8 <2.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\cordova-common" ] ], "_from": "cordova-registry-mapper@>=1.1.8 <2.0.0", @@ -12,27 +20,28 @@ "_location": "/cordova-registry-mapper", "_nodeVersion": "5.4.1", "_npmUser": { - "email": "stevengill97@gmail.com", - "name": "stevegill" + "name": "stevegill", + "email": "stevengill97@gmail.com" }, "_npmVersion": "3.5.3", "_phantomChildren": {}, "_requested": { - "name": "cordova-registry-mapper", "raw": "cordova-registry-mapper@^1.1.8", - "rawSpec": "^1.1.8", "scope": null, + "escapedName": "cordova-registry-mapper", + "name": "cordova-registry-mapper", + "rawSpec": "^1.1.8", "spec": ">=1.1.8 <2.0.0", "type": "range" }, "_requiredBy": [ "/cordova-common" ], - "_resolved": "http://registry.npmjs.org/cordova-registry-mapper/-/cordova-registry-mapper-1.1.15.tgz", + "_resolved": "https://registry.npmjs.org/cordova-registry-mapper/-/cordova-registry-mapper-1.1.15.tgz", "_shasum": "e244b9185b8175473bff6079324905115f83dc7c", "_shrinkwrap": null, "_spec": "cordova-registry-mapper@^1.1.8", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common", + "_where": "d:\\cordova\\cordova-android\\node_modules\\cordova-common", "author": { "name": "Steve Gill" }, @@ -47,7 +56,7 @@ "directories": {}, "dist": { "shasum": "e244b9185b8175473bff6079324905115f83dc7c", - "tarball": "http://registry.npmjs.org/cordova-registry-mapper/-/cordova-registry-mapper-1.1.15.tgz" + "tarball": "https://registry.npmjs.org/cordova-registry-mapper/-/cordova-registry-mapper-1.1.15.tgz" }, "gitHead": "00af0f028ec94154a364eeabe38b8e22320647bd", "homepage": "https://github.com/stevengill/cordova-registry-mapper#readme", diff --git a/platforms/android/cordova/node_modules/elementtree/package.json b/platforms/android/cordova/node_modules/elementtree/package.json index f1a5f14..58a4173 100644 --- a/platforms/android/cordova/node_modules/elementtree/package.json +++ b/platforms/android/cordova/node_modules/elementtree/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "elementtree@^0.1.6", - "/Users/steveng/repo/cordova/cordova-android" + { + "raw": "elementtree@^0.1.6", + "scope": null, + "escapedName": "elementtree", + "name": "elementtree", + "rawSpec": "^0.1.6", + "spec": ">=0.1.6 <0.2.0", + "type": "range" + }, + "d:\\cordova\\cordova-android" ] ], "_from": "elementtree@>=0.1.6 <0.2.0", @@ -11,16 +19,17 @@ "_installable": true, "_location": "/elementtree", "_npmUser": { - "email": "ryan@trolocsis.com", - "name": "rphillips" + "name": "rphillips", + "email": "ryan@trolocsis.com" }, "_npmVersion": "1.3.24", "_phantomChildren": {}, "_requested": { - "name": "elementtree", "raw": "elementtree@^0.1.6", - "rawSpec": "^0.1.6", "scope": null, + "escapedName": "elementtree", + "name": "elementtree", + "rawSpec": "^0.1.6", "spec": ">=0.1.6 <0.2.0", "type": "range" }, @@ -28,11 +37,11 @@ "/", "/cordova-common" ], - "_resolved": "http://registry.npmjs.org/elementtree/-/elementtree-0.1.6.tgz", + "_resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.6.tgz", "_shasum": "2ac4c46ea30516c8c4cbdb5e3ac7418e592de20c", "_shrinkwrap": null, "_spec": "elementtree@^0.1.6", - "_where": "/Users/steveng/repo/cordova/cordova-android", + "_where": "d:\\cordova\\cordova-android", "author": { "name": "Rackspace US, Inc." }, @@ -61,18 +70,18 @@ }, "dist": { "shasum": "2ac4c46ea30516c8c4cbdb5e3ac7418e592de20c", - "tarball": "http://registry.npmjs.org/elementtree/-/elementtree-0.1.6.tgz" + "tarball": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.6.tgz" }, "engines": { "node": ">= 0.4.0" }, "homepage": "https://github.com/racker/node-elementtree", "keywords": [ - "elementtree", - "parser", + "xml", "sax", + "parser", "seralization", - "xml" + "elementtree" ], "licenses": [ { diff --git a/platforms/android/cordova/node_modules/glob/package.json b/platforms/android/cordova/node_modules/glob/package.json index 7c398ae..1f1cec6 100644 --- a/platforms/android/cordova/node_modules/glob/package.json +++ b/platforms/android/cordova/node_modules/glob/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "glob@^5.0.13", - "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common" + { + "raw": "glob@^5.0.13", + "scope": null, + "escapedName": "glob", + "name": "glob", + "rawSpec": "^5.0.13", + "spec": ">=5.0.13 <6.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\cordova-common" ] ], "_from": "glob@>=5.0.13 <6.0.0", @@ -12,30 +20,31 @@ "_location": "/glob", "_nodeVersion": "4.0.0", "_npmUser": { - "email": "isaacs@npmjs.com", - "name": "isaacs" + "name": "isaacs", + "email": "isaacs@npmjs.com" }, "_npmVersion": "3.3.2", "_phantomChildren": {}, "_requested": { - "name": "glob", "raw": "glob@^5.0.13", - "rawSpec": "^5.0.13", "scope": null, + "escapedName": "glob", + "name": "glob", + "rawSpec": "^5.0.13", "spec": ">=5.0.13 <6.0.0", "type": "range" }, "_requiredBy": [ "/cordova-common" ], - "_resolved": "http://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "_resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "_shasum": "1bc936b9e02f4a603fcc222ecf7633d30b8b93b1", "_shrinkwrap": null, "_spec": "glob@^5.0.13", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common", + "_where": "d:\\cordova\\cordova-android\\node_modules\\cordova-common", "author": { - "email": "i@izs.me", "name": "Isaac Z. Schlueter", + "email": "i@izs.me", "url": "http://blog.izs.me/" }, "bugs": { @@ -58,15 +67,15 @@ "directories": {}, "dist": { "shasum": "1bc936b9e02f4a603fcc222ecf7633d30b8b93b1", - "tarball": "http://registry.npmjs.org/glob/-/glob-5.0.15.tgz" + "tarball": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz" }, "engines": { "node": "*" }, "files": [ - "common.js", "glob.js", - "sync.js" + "sync.js", + "common.js" ], "gitHead": "3a7e71d453dd80e75b196fd262dd23ed54beeceb", "homepage": "https://github.com/isaacs/node-glob#readme", diff --git a/platforms/android/cordova/node_modules/inflight/.eslintrc b/platforms/android/cordova/node_modules/inflight/.eslintrc deleted file mode 100644 index b7a1550..0000000 --- a/platforms/android/cordova/node_modules/inflight/.eslintrc +++ /dev/null @@ -1,17 +0,0 @@ -{ - "env" : { - "node" : true - }, - "rules" : { - "semi": [2, "never"], - "strict": 0, - "quotes": [1, "single", "avoid-escape"], - "no-use-before-define": 0, - "curly": 0, - "no-underscore-dangle": 0, - "no-lonely-if": 1, - "no-unused-vars": [2, {"vars" : "all", "args" : "after-used"}], - "no-mixed-requires": 0, - "space-infix-ops": 0 - } -} diff --git a/platforms/android/cordova/node_modules/inflight/package.json b/platforms/android/cordova/node_modules/inflight/package.json index 3bc7cf7..734e580 100644 --- a/platforms/android/cordova/node_modules/inflight/package.json +++ b/platforms/android/cordova/node_modules/inflight/package.json @@ -1,41 +1,54 @@ { "_args": [ [ - "inflight@^1.0.4", - "/Users/steveng/repo/cordova/cordova-android/node_modules/glob" + { + "raw": "inflight@^1.0.4", + "scope": null, + "escapedName": "inflight", + "name": "inflight", + "rawSpec": "^1.0.4", + "spec": ">=1.0.4 <2.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\glob" ] ], "_from": "inflight@>=1.0.4 <2.0.0", - "_id": "inflight@1.0.4", + "_id": "inflight@1.0.5", "_inCache": true, "_installable": true, "_location": "/inflight", - "_nodeVersion": "0.10.32", + "_nodeVersion": "5.10.1", + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/inflight-1.0.5.tgz_1463529611443_0.00041943578980863094" + }, "_npmUser": { - "email": "ogd@aoaioxxysz.net", - "name": "othiym23" + "name": "zkat", + "email": "kat@sykosomatic.org" }, - "_npmVersion": "2.1.3", + "_npmVersion": "3.9.1", "_phantomChildren": {}, "_requested": { - "name": "inflight", "raw": "inflight@^1.0.4", - "rawSpec": "^1.0.4", "scope": null, + "escapedName": "inflight", + "name": "inflight", + "rawSpec": "^1.0.4", "spec": ">=1.0.4 <2.0.0", "type": "range" }, "_requiredBy": [ "/glob" ], - "_resolved": "http://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", - "_shasum": "6cbb4521ebd51ce0ec0a936bfd7657ef7e9b172a", + "_resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "_shasum": "db3204cd5a9de2e6cd890b85c6e2f66bcf4f620a", "_shrinkwrap": null, "_spec": "inflight@^1.0.4", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/glob", + "_where": "d:\\cordova\\cordova-android\\node_modules\\glob", "author": { - "email": "i@izs.me", "name": "Isaac Z. Schlueter", + "email": "i@izs.me", "url": "http://blog.izs.me/" }, "bugs": { @@ -47,18 +60,25 @@ }, "description": "Add callbacks to requests in flight to avoid async duplication", "devDependencies": { - "tap": "^0.4.10" + "tap": "^1.2.0" }, "directories": {}, "dist": { - "shasum": "6cbb4521ebd51ce0ec0a936bfd7657ef7e9b172a", - "tarball": "http://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz" + "shasum": "db3204cd5a9de2e6cd890b85c6e2f66bcf4f620a", + "tarball": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz" }, - "gitHead": "c7b5531d572a867064d4a1da9e013e8910b7d1ba", + "files": [ + "inflight.js" + ], + "gitHead": "559e37b4f6327fca797fe8d7fe8ed6d9cae08821", "homepage": "https://github.com/isaacs/inflight", "license": "ISC", "main": "inflight.js", "maintainers": [ + { + "name": "iarna", + "email": "me@re-becca.org" + }, { "name": "isaacs", "email": "i@izs.me" @@ -68,8 +88,8 @@ "email": "ogd@aoaioxxysz.net" }, { - "name": "iarna", - "email": "me@re-becca.org" + "name": "zkat", + "email": "kat@sykosomatic.org" } ], "name": "inflight", @@ -77,10 +97,10 @@ "readme": "ERROR: No README data found!", "repository": { "type": "git", - "url": "git://github.com/isaacs/inflight.git" + "url": "git+https://github.com/npm/inflight.git" }, "scripts": { "test": "tap test.js" }, - "version": "1.0.4" + "version": "1.0.5" } diff --git a/platforms/android/cordova/node_modules/inflight/test.js b/platforms/android/cordova/node_modules/inflight/test.js deleted file mode 100644 index 2bb75b3..0000000 --- a/platforms/android/cordova/node_modules/inflight/test.js +++ /dev/null @@ -1,97 +0,0 @@ -var test = require('tap').test -var inf = require('./inflight.js') - - -function req (key, cb) { - cb = inf(key, cb) - if (cb) setTimeout(function () { - cb(key) - cb(key) - }) - return cb -} - -test('basic', function (t) { - var calleda = false - var a = req('key', function (k) { - t.notOk(calleda) - calleda = true - t.equal(k, 'key') - if (calledb) t.end() - }) - t.ok(a, 'first returned cb function') - - var calledb = false - var b = req('key', function (k) { - t.notOk(calledb) - calledb = true - t.equal(k, 'key') - if (calleda) t.end() - }) - - t.notOk(b, 'second should get falsey inflight response') -}) - -test('timing', function (t) { - var expect = [ - 'method one', - 'start one', - 'end one', - 'two', - 'tick', - 'three' - ] - var i = 0 - - function log (m) { - t.equal(m, expect[i], m + ' === ' + expect[i]) - ++i - if (i === expect.length) - t.end() - } - - function method (name, cb) { - log('method ' + name) - process.nextTick(cb) - } - - var one = inf('foo', function () { - log('start one') - var three = inf('foo', function () { - log('three') - }) - if (three) method('three', three) - log('end one') - }) - - method('one', one) - - var two = inf('foo', function () { - log('two') - }) - if (two) method('one', two) - - process.nextTick(log.bind(null, 'tick')) -}) - -test('parameters', function (t) { - t.plan(8) - - var a = inf('key', function (first, second, third) { - t.equal(first, 1) - t.equal(second, 2) - t.equal(third, 3) - }) - t.ok(a, 'first returned cb function') - - var b = inf('key', function (first, second, third) { - t.equal(first, 1) - t.equal(second, 2) - t.equal(third, 3) - }) - t.notOk(b, 'second should get falsey inflight response') - - setTimeout(function () { - a(1, 2, 3) - }) -}) diff --git a/platforms/android/cordova/node_modules/inherits/package.json b/platforms/android/cordova/node_modules/inherits/package.json index 6313b8e..7a8df25 100644 --- a/platforms/android/cordova/node_modules/inherits/package.json +++ b/platforms/android/cordova/node_modules/inherits/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "inherits@2", - "/Users/steveng/repo/cordova/cordova-android/node_modules/glob" + { + "raw": "inherits@2", + "scope": null, + "escapedName": "inherits", + "name": "inherits", + "rawSpec": "2", + "spec": ">=2.0.0 <3.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\glob" ] ], "_from": "inherits@>=2.0.0 <3.0.0", @@ -11,27 +19,28 @@ "_installable": true, "_location": "/inherits", "_npmUser": { - "email": "i@izs.me", - "name": "isaacs" + "name": "isaacs", + "email": "i@izs.me" }, "_npmVersion": "1.3.8", "_phantomChildren": {}, "_requested": { - "name": "inherits", "raw": "inherits@2", - "rawSpec": "2", "scope": null, + "escapedName": "inherits", + "name": "inherits", + "rawSpec": "2", "spec": ">=2.0.0 <3.0.0", "type": "range" }, "_requiredBy": [ "/glob" ], - "_resolved": "http://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "_resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "_shasum": "b17d08d326b4423e568eff719f91b0b1cbdf69f1", "_shrinkwrap": null, "_spec": "inherits@2", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/glob", + "_where": "d:\\cordova\\cordova-android\\node_modules\\glob", "browser": "./inherits_browser.js", "bugs": { "url": "https://github.com/isaacs/inherits/issues" @@ -42,18 +51,18 @@ "directories": {}, "dist": { "shasum": "b17d08d326b4423e568eff719f91b0b1cbdf69f1", - "tarball": "http://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" + "tarball": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, "homepage": "https://github.com/isaacs/inherits#readme", "keywords": [ - "browser", - "browserify", - "class", "inheritance", - "inherits", + "class", "klass", + "oop", "object-oriented", - "oop" + "inherits", + "browser", + "browserify" ], "license": "ISC", "main": "./inherits.js", diff --git a/platforms/android/cordova/node_modules/lodash/package.json b/platforms/android/cordova/node_modules/lodash/package.json index 38e2638..d4de5b9 100644 --- a/platforms/android/cordova/node_modules/lodash/package.json +++ b/platforms/android/cordova/node_modules/lodash/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "lodash@^3.5.0", - "/Users/steveng/repo/cordova/cordova-android/node_modules/xmlbuilder" + { + "raw": "lodash@^3.5.0", + "scope": null, + "escapedName": "lodash", + "name": "lodash", + "rawSpec": "^3.5.0", + "spec": ">=3.5.0 <4.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\xmlbuilder" ] ], "_from": "lodash@>=3.5.0 <4.0.0", @@ -12,30 +20,31 @@ "_location": "/lodash", "_nodeVersion": "0.12.5", "_npmUser": { - "email": "john.david.dalton@gmail.com", - "name": "jdalton" + "name": "jdalton", + "email": "john.david.dalton@gmail.com" }, "_npmVersion": "2.13.1", "_phantomChildren": {}, "_requested": { - "name": "lodash", "raw": "lodash@^3.5.0", - "rawSpec": "^3.5.0", "scope": null, + "escapedName": "lodash", + "name": "lodash", + "rawSpec": "^3.5.0", "spec": ">=3.5.0 <4.0.0", "type": "range" }, "_requiredBy": [ "/xmlbuilder" ], - "_resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "_resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "_shasum": "5bf45e8e49ba4189e17d482789dfd15bd140b7b6", "_shrinkwrap": null, "_spec": "lodash@^3.5.0", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/xmlbuilder", + "_where": "d:\\cordova\\cordova-android\\node_modules\\xmlbuilder", "author": { - "email": "john.david.dalton@gmail.com", "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", "url": "http://allyoucanleet.com/" }, "bugs": { @@ -74,7 +83,7 @@ "directories": {}, "dist": { "shasum": "5bf45e8e49ba4189e17d482789dfd15bd140b7b6", - "tarball": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" + "tarball": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" }, "homepage": "https://lodash.com/", "icon": "https://lodash.com/icon.svg", diff --git a/platforms/android/cordova/node_modules/minimatch/README.md b/platforms/android/cordova/node_modules/minimatch/README.md index d458bc2..ad72b81 100644 --- a/platforms/android/cordova/node_modules/minimatch/README.md +++ b/platforms/android/cordova/node_modules/minimatch/README.md @@ -2,7 +2,7 @@ A minimal matching utility. -[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.png)](http://travis-ci.org/isaacs/minimatch) +[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.svg)](http://travis-ci.org/isaacs/minimatch) This is the matching library used internally by npm. @@ -37,7 +37,7 @@ See: ## Minimatch Class -Create a minimatch object by instanting the `minimatch.Minimatch` class. +Create a minimatch object by instantiating the `minimatch.Minimatch` class. ```javascript var Minimatch = require("minimatch").Minimatch @@ -82,13 +82,6 @@ var mm = new Minimatch(pattern, options) All other methods are internal, and will be called as necessary. -## Functions - -The top-level exported function has a `cache` property, which is an LRU -cache set to store 100 items. So, calling these methods repeatedly -with the same pattern and options will use the same Minimatch object, -saving the cost of parsing it multiple times. - ### minimatch(path, pattern, options) Main export. Tests a path against the pattern using the options. diff --git a/platforms/android/cordova/node_modules/minimatch/minimatch.js b/platforms/android/cordova/node_modules/minimatch/minimatch.js index ec4c05c..830a272 100644 --- a/platforms/android/cordova/node_modules/minimatch/minimatch.js +++ b/platforms/android/cordova/node_modules/minimatch/minimatch.js @@ -235,7 +235,7 @@ function braceExpand (pattern, options) { ? this.pattern : pattern if (typeof pattern === 'undefined') { - throw new Error('undefined pattern') + throw new TypeError('undefined pattern') } if (options.nobrace || @@ -261,6 +261,10 @@ function braceExpand (pattern, options) { Minimatch.prototype.parse = parse var SUBPARSE = {} function parse (pattern, isSub) { + if (pattern.length > 1024 * 64) { + throw new TypeError('pattern is too long') + } + var options = this.options // shortcuts @@ -518,7 +522,7 @@ function parse (pattern, isSub) { for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { var tail = re.slice(pl.reStart + 3) // maybe some even number of \, then maybe 1 \, followed by a | - tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, function (_, $1, $2) { + tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) { if (!$2) { // the | isn't already escaped, so escape it. $2 = '\\' @@ -615,7 +619,15 @@ function parse (pattern, isSub) { } var flags = options.nocase ? 'i' : '' - var regExp = new RegExp('^' + re + '$', flags) + try { + var regExp = new RegExp('^' + re + '$', flags) + } catch (er) { + // If it was an invalid regular expression, then it can't match + // anything. This trick looks for a character after the end of + // the string, which is of course impossible, except in multi-line + // mode, but it's not a /m regex. + return new RegExp('$.') + } regExp._glob = pattern regExp._src = re diff --git a/platforms/android/cordova/node_modules/minimatch/package.json b/platforms/android/cordova/node_modules/minimatch/package.json index 5f6a7fc..beed606 100644 --- a/platforms/android/cordova/node_modules/minimatch/package.json +++ b/platforms/android/cordova/node_modules/minimatch/package.json @@ -1,41 +1,55 @@ { "_args": [ [ - "minimatch@2 || 3", - "/Users/steveng/repo/cordova/cordova-android/node_modules/glob" + { + "raw": "minimatch@^3.0.0", + "scope": null, + "escapedName": "minimatch", + "name": "minimatch", + "rawSpec": "^3.0.0", + "spec": ">=3.0.0 <4.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\cordova-common" ] ], - "_from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", - "_id": "minimatch@3.0.0", + "_from": "minimatch@>=3.0.0 <4.0.0", + "_id": "minimatch@3.0.2", "_inCache": true, "_installable": true, "_location": "/minimatch", - "_nodeVersion": "4.0.0", + "_nodeVersion": "4.4.4", + "_npmOperationalInternal": { + "host": "packages-16-east.internal.npmjs.com", + "tmp": "tmp/minimatch-3.0.2.tgz_1466194379770_0.11417287751100957" + }, "_npmUser": { - "email": "isaacs@npmjs.com", - "name": "isaacs" + "name": "isaacs", + "email": "i@izs.me" }, - "_npmVersion": "3.3.2", + "_npmVersion": "3.9.1", "_phantomChildren": {}, "_requested": { - "name": "minimatch", - "raw": "minimatch@2 || 3", - "rawSpec": "2 || 3", + "raw": "minimatch@^3.0.0", "scope": null, - "spec": ">=2.0.0 <3.0.0||>=3.0.0 <4.0.0", + "escapedName": "minimatch", + "name": "minimatch", + "rawSpec": "^3.0.0", + "spec": ">=3.0.0 <4.0.0", "type": "range" }, "_requiredBy": [ + "/cordova-common", "/glob" ], - "_resolved": "http://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", - "_shasum": "5236157a51e4f004c177fb3c527ff7dd78f0ef83", + "_resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", + "_shasum": "0f398a7300ea441e9c348c83d98ab8c9dbf9c40a", "_shrinkwrap": null, - "_spec": "minimatch@2 || 3", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/glob", + "_spec": "minimatch@^3.0.0", + "_where": "d:\\cordova\\cordova-android\\node_modules\\cordova-common", "author": { - "email": "i@izs.me", "name": "Isaac Z. Schlueter", + "email": "i@izs.me", "url": "http://blog.izs.me" }, "bugs": { @@ -47,12 +61,12 @@ "description": "a glob matcher in javascript", "devDependencies": { "standard": "^3.7.2", - "tap": "^1.2.0" + "tap": "^5.6.0" }, "directories": {}, "dist": { - "shasum": "5236157a51e4f004c177fb3c527ff7dd78f0ef83", - "tarball": "http://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz" + "shasum": "0f398a7300ea441e9c348c83d98ab8c9dbf9c40a", + "tarball": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz" }, "engines": { "node": "*" @@ -60,7 +74,7 @@ "files": [ "minimatch.js" ], - "gitHead": "270dbea567f0af6918cb18103e98c612aa717a20", + "gitHead": "81edb7c763abd31ba981c87ec5e835f178786be0", "homepage": "https://github.com/isaacs/minimatch#readme", "license": "ISC", "main": "minimatch.js", @@ -81,5 +95,5 @@ "posttest": "standard minimatch.js test/*.js", "test": "tap test/*.js" }, - "version": "3.0.0" + "version": "3.0.2" } diff --git a/platforms/android/cordova/node_modules/nopt/package.json b/platforms/android/cordova/node_modules/nopt/package.json index 37ed58d..84b9ff6 100644 --- a/platforms/android/cordova/node_modules/nopt/package.json +++ b/platforms/android/cordova/node_modules/nopt/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "nopt@^3.0.1", - "/Users/steveng/repo/cordova/cordova-android" + { + "raw": "nopt@^3.0.1", + "scope": null, + "escapedName": "nopt", + "name": "nopt", + "rawSpec": "^3.0.1", + "spec": ">=3.0.1 <4.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android" ] ], "_from": "nopt@>=3.0.1 <4.0.0", @@ -12,30 +20,31 @@ "_location": "/nopt", "_nodeVersion": "4.2.1", "_npmUser": { - "email": "ogd@aoaioxxysz.net", - "name": "othiym23" + "name": "othiym23", + "email": "ogd@aoaioxxysz.net" }, "_npmVersion": "2.14.10", "_phantomChildren": {}, "_requested": { - "name": "nopt", "raw": "nopt@^3.0.1", - "rawSpec": "^3.0.1", "scope": null, + "escapedName": "nopt", + "name": "nopt", + "rawSpec": "^3.0.1", "spec": ">=3.0.1 <4.0.0", "type": "range" }, "_requiredBy": [ "/" ], - "_resolved": "http://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "_resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "_shasum": "c6465dbf08abcd4db359317f79ac68a646b28ff9", "_shrinkwrap": null, "_spec": "nopt@^3.0.1", - "_where": "/Users/steveng/repo/cordova/cordova-android", + "_where": "d:\\cordova\\cordova-android", "author": { - "email": "i@izs.me", "name": "Isaac Z. Schlueter", + "email": "i@izs.me", "url": "http://blog.izs.me/" }, "bin": { @@ -54,7 +63,7 @@ "directories": {}, "dist": { "shasum": "c6465dbf08abcd4db359317f79ac68a646b28ff9", - "tarball": "http://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz" + "tarball": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz" }, "gitHead": "10a750c9bb99c1950160353459e733ac2aa18cb6", "homepage": "https://github.com/npm/nopt#readme", diff --git a/platforms/android/cordova/node_modules/once/package.json b/platforms/android/cordova/node_modules/once/package.json index 18c7f8c..4a9cde3 100644 --- a/platforms/android/cordova/node_modules/once/package.json +++ b/platforms/android/cordova/node_modules/once/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "once@^1.3.0", - "/Users/steveng/repo/cordova/cordova-android/node_modules/glob" + { + "raw": "once@^1.3.0", + "scope": null, + "escapedName": "once", + "name": "once", + "rawSpec": "^1.3.0", + "spec": ">=1.3.0 <2.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\glob" ] ], "_from": "once@>=1.3.0 <2.0.0", @@ -12,16 +20,17 @@ "_location": "/once", "_nodeVersion": "4.0.0", "_npmUser": { - "email": "i@izs.me", - "name": "isaacs" + "name": "isaacs", + "email": "i@izs.me" }, "_npmVersion": "3.3.2", "_phantomChildren": {}, "_requested": { - "name": "once", "raw": "once@^1.3.0", - "rawSpec": "^1.3.0", "scope": null, + "escapedName": "once", + "name": "once", + "rawSpec": "^1.3.0", "spec": ">=1.3.0 <2.0.0", "type": "range" }, @@ -29,14 +38,14 @@ "/glob", "/inflight" ], - "_resolved": "http://registry.npmjs.org/once/-/once-1.3.3.tgz", + "_resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "_shasum": "b2e261557ce4c314ec8304f3fa82663e4297ca20", "_shrinkwrap": null, "_spec": "once@^1.3.0", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/glob", + "_where": "d:\\cordova\\cordova-android\\node_modules\\glob", "author": { - "email": "i@izs.me", "name": "Isaac Z. Schlueter", + "email": "i@izs.me", "url": "http://blog.izs.me/" }, "bugs": { @@ -54,7 +63,7 @@ }, "dist": { "shasum": "b2e261557ce4c314ec8304f3fa82663e4297ca20", - "tarball": "http://registry.npmjs.org/once/-/once-1.3.3.tgz" + "tarball": "https://registry.npmjs.org/once/-/once-1.3.3.tgz" }, "files": [ "once.js" @@ -62,8 +71,8 @@ "gitHead": "2ad558657e17fafd24803217ba854762842e4178", "homepage": "https://github.com/isaacs/once#readme", "keywords": [ - "function", "once", + "function", "one", "single" ], diff --git a/platforms/android/cordova/node_modules/os-homedir/package.json b/platforms/android/cordova/node_modules/os-homedir/package.json index 7dbd200..98e0586 100644 --- a/platforms/android/cordova/node_modules/os-homedir/package.json +++ b/platforms/android/cordova/node_modules/os-homedir/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "os-homedir@^1.0.0", - "/Users/steveng/repo/cordova/cordova-android/node_modules/osenv" + { + "raw": "os-homedir@^1.0.0", + "scope": null, + "escapedName": "os-homedir", + "name": "os-homedir", + "rawSpec": "^1.0.0", + "spec": ">=1.0.0 <2.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\osenv" ] ], "_from": "os-homedir@>=1.0.0 <2.0.0", @@ -12,30 +20,31 @@ "_location": "/os-homedir", "_nodeVersion": "0.12.5", "_npmUser": { - "email": "sindresorhus@gmail.com", - "name": "sindresorhus" + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" }, "_npmVersion": "2.11.2", "_phantomChildren": {}, "_requested": { - "name": "os-homedir", "raw": "os-homedir@^1.0.0", - "rawSpec": "^1.0.0", "scope": null, + "escapedName": "os-homedir", + "name": "os-homedir", + "rawSpec": "^1.0.0", "spec": ">=1.0.0 <2.0.0", "type": "range" }, "_requiredBy": [ "/osenv" ], - "_resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz", + "_resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz", "_shasum": "0d62bdf44b916fd3bbdcf2cab191948fb094f007", "_shrinkwrap": null, "_spec": "os-homedir@^1.0.0", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/osenv", + "_where": "d:\\cordova\\cordova-android\\node_modules\\osenv", "author": { - "email": "sindresorhus@gmail.com", "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", "url": "sindresorhus.com" }, "bugs": { @@ -50,7 +59,7 @@ "directories": {}, "dist": { "shasum": "0d62bdf44b916fd3bbdcf2cab191948fb094f007", - "tarball": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz" + "tarball": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz" }, "engines": { "node": ">=0.10.0" @@ -63,17 +72,17 @@ "keywords": [ "built-in", "core", + "ponyfill", + "polyfill", + "shim", + "os", + "homedir", + "home", "dir", "directory", "folder", - "home", - "homedir", - "os", - "path", - "polyfill", - "ponyfill", - "shim", - "user" + "user", + "path" ], "license": "MIT", "maintainers": [ diff --git a/platforms/android/cordova/node_modules/os-tmpdir/package.json b/platforms/android/cordova/node_modules/os-tmpdir/package.json index ce48381..a043645 100644 --- a/platforms/android/cordova/node_modules/os-tmpdir/package.json +++ b/platforms/android/cordova/node_modules/os-tmpdir/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "os-tmpdir@^1.0.0", - "/Users/steveng/repo/cordova/cordova-android/node_modules/osenv" + { + "raw": "os-tmpdir@^1.0.0", + "scope": null, + "escapedName": "os-tmpdir", + "name": "os-tmpdir", + "rawSpec": "^1.0.0", + "spec": ">=1.0.0 <2.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\osenv" ] ], "_from": "os-tmpdir@>=1.0.0 <2.0.0", @@ -12,30 +20,31 @@ "_location": "/os-tmpdir", "_nodeVersion": "0.12.3", "_npmUser": { - "email": "sindresorhus@gmail.com", - "name": "sindresorhus" + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" }, "_npmVersion": "2.9.1", "_phantomChildren": {}, "_requested": { - "name": "os-tmpdir", "raw": "os-tmpdir@^1.0.0", - "rawSpec": "^1.0.0", "scope": null, + "escapedName": "os-tmpdir", + "name": "os-tmpdir", + "rawSpec": "^1.0.0", "spec": ">=1.0.0 <2.0.0", "type": "range" }, "_requiredBy": [ "/osenv" ], - "_resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz", + "_resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz", "_shasum": "e9b423a1edaf479882562e92ed71d7743a071b6e", "_shrinkwrap": null, "_spec": "os-tmpdir@^1.0.0", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/osenv", + "_where": "d:\\cordova\\cordova-android\\node_modules\\osenv", "author": { - "email": "sindresorhus@gmail.com", "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", "url": "sindresorhus.com" }, "bugs": { @@ -49,7 +58,7 @@ "directories": {}, "dist": { "shasum": "e9b423a1edaf479882562e92ed71d7743a071b6e", - "tarball": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz" + "tarball": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz" }, "engines": { "node": ">=0.10.0" @@ -62,18 +71,18 @@ "keywords": [ "built-in", "core", - "dir", - "directory", - "env", - "environment", - "os", - "polyfill", "ponyfill", + "polyfill", "shim", - "temp", + "os", + "tmpdir", "tempdir", "tmp", - "tmpdir" + "temp", + "dir", + "directory", + "env", + "environment" ], "license": "MIT", "maintainers": [ diff --git a/platforms/android/cordova/node_modules/osenv/package.json b/platforms/android/cordova/node_modules/osenv/package.json index 43da54d..5b64a32 100644 --- a/platforms/android/cordova/node_modules/osenv/package.json +++ b/platforms/android/cordova/node_modules/osenv/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "osenv@^0.1.3", - "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common" + { + "raw": "osenv@^0.1.3", + "scope": null, + "escapedName": "osenv", + "name": "osenv", + "rawSpec": "^0.1.3", + "spec": ">=0.1.3 <0.2.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\cordova-common" ] ], "_from": "osenv@>=0.1.3 <0.2.0", @@ -12,30 +20,31 @@ "_location": "/osenv", "_nodeVersion": "2.2.1", "_npmUser": { - "email": "isaacs@npmjs.com", - "name": "isaacs" + "name": "isaacs", + "email": "isaacs@npmjs.com" }, "_npmVersion": "3.0.0", "_phantomChildren": {}, "_requested": { - "name": "osenv", "raw": "osenv@^0.1.3", - "rawSpec": "^0.1.3", "scope": null, + "escapedName": "osenv", + "name": "osenv", + "rawSpec": "^0.1.3", "spec": ">=0.1.3 <0.2.0", "type": "range" }, "_requiredBy": [ "/cordova-common" ], - "_resolved": "http://registry.npmjs.org/osenv/-/osenv-0.1.3.tgz", + "_resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.3.tgz", "_shasum": "83cf05c6d6458fc4d5ac6362ea325d92f2754217", "_shrinkwrap": null, "_spec": "osenv@^0.1.3", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common", + "_where": "d:\\cordova\\cordova-android\\node_modules\\cordova-common", "author": { - "email": "i@izs.me", "name": "Isaac Z. Schlueter", + "email": "i@izs.me", "url": "http://blog.izs.me/" }, "bugs": { @@ -54,18 +63,18 @@ }, "dist": { "shasum": "83cf05c6d6458fc4d5ac6362ea325d92f2754217", - "tarball": "http://registry.npmjs.org/osenv/-/osenv-0.1.3.tgz" + "tarball": "https://registry.npmjs.org/osenv/-/osenv-0.1.3.tgz" }, "gitHead": "f746b3405d8f9e28054d11b97e1436f6a15016c4", "homepage": "https://github.com/npm/osenv#readme", "keywords": [ "environment", + "variable", "home", + "tmpdir", "path", "prompt", - "ps1", - "tmpdir", - "variable" + "ps1" ], "license": "ISC", "main": "osenv.js", diff --git a/platforms/android/cordova/node_modules/path-is-absolute/package.json b/platforms/android/cordova/node_modules/path-is-absolute/package.json index 12bed5a..17d2e1c 100644 --- a/platforms/android/cordova/node_modules/path-is-absolute/package.json +++ b/platforms/android/cordova/node_modules/path-is-absolute/package.json @@ -1,8 +1,16 @@ { "_args": [ [ - "path-is-absolute@^1.0.0", - "/Users/steveng/repo/cordova/cordova-android/node_modules/glob" + { + "raw": "path-is-absolute@^1.0.0", + "scope": null, + "escapedName": "path-is-absolute", + "name": "path-is-absolute", + "rawSpec": "^1.0.0", + "spec": ">=1.0.0 <2.0.0", + "type": "range" + }, + "d:\\cordova\\cordova-android\\node_modules\\glob" ] ], "_from": "path-is-absolute@>=1.0.0 <2.0.0", @@ -12,30 +20,31 @@ "_location": "/path-is-absolute", "_nodeVersion": "0.12.0", "_npmUser": { - "email": "sindresorhus@gmail.com", - "name": "sindresorhus" + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" }, "_npmVersion": "2.5.1", "_phantomChildren": {}, "_requested": { - "name": "path-is-absolute", "raw": "path-is-absolute@^1.0.0", - "rawSpec": "^1.0.0", "scope": null, + "escapedName": "path-is-absolute", + "name": "path-is-absolute", + "rawSpec": "^1.0.0", "spec": ">=1.0.0 <2.0.0", "type": "range" }, "_requiredBy": [ "/glob" ], - "_resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", + "_resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", "_shasum": "263dada66ab3f2fb10bf7f9d24dd8f3e570ef912", "_shrinkwrap": null, "_spec": "path-is-absolute@^1.0.0", - "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/glob", + "_where": "d:\\cordova\\cordova-android\\node_modules\\glob", "author": { - "email": "sindresorhus@gmail.com", "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", "url": "sindresorhus.com" }, "bugs": { @@ -47,7 +56,7 @@ "directories": {}, "dist": { "shasum": "263dada66ab3f2fb10bf7f9d24dd8f3e570ef912", - "tarball": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + "tarball": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" }, "engines": { "node": ">=0.10.0" @@ -58,23 +67,23 @@ "gitHead": "7a76a0c9f2263192beedbe0a820e4d0baee5b7a1", "homepage": "https://github.com/sindresorhus/path-is-absolute", "keywords": [ + "path", + "paths", + "file", + "dir", "absolute", + "isabsolute", + "is-absolute", "built-in", - "check", + "util", + "utils", "core", - "detect", - "dir", - "file", - "is", - "is-absolute", - "isabsolute", - "path", - "paths", - "polyfill", "ponyfill", + "polyfill", "shim", - "util", - "utils" + "is", + "detect", + "check" ], "license": "MIT", "maintainers": [ diff --git a/platforms/android/cordova/node_modules/plist/dist/plist-parse.js b/platforms/android/cordova/node_modules/plist/dist/plist-parse.js index 71c1b3d..d84cf6e 100644 --- a/platforms/android/cordova/node_modules/plist/dist/plist-parse.js +++ b/platforms/android/cordova/node_modules/plist/dist/plist-parse.js @@ -2069,261 +2069,261 @@ function config (name) { }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],7:[function(require,module,exports){ -function DOMParser(options){ - this.options = options ||{locator:{}}; - -} -DOMParser.prototype.parseFromString = function(source,mimeType){ - var options = this.options; - var sax = new XMLReader(); - var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler - var errorHandler = options.errorHandler; - var locator = options.locator; - var defaultNSMap = options.xmlns||{}; - var entityMap = {'lt':'<','gt':'>','amp':'&','quot':'"','apos':"'"} - if(locator){ - domBuilder.setDocumentLocator(locator) - } - - sax.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator); - sax.domBuilder = options.domBuilder || domBuilder; - if(/\/x?html?$/.test(mimeType)){ - entityMap.nbsp = '\xa0'; - entityMap.copy = '\xa9'; - defaultNSMap['']= 'http://www.w3.org/1999/xhtml'; - } - if(source){ - sax.parse(source,defaultNSMap,entityMap); - }else{ - sax.errorHandler.error("invalid document source"); - } - return domBuilder.document; -} -function buildErrorHandler(errorImpl,domBuilder,locator){ - if(!errorImpl){ - if(domBuilder instanceof DOMHandler){ - return domBuilder; - } - errorImpl = domBuilder ; - } - var errorHandler = {} - var isCallback = errorImpl instanceof Function; - locator = locator||{} - function build(key){ - var fn = errorImpl[key]; - if(!fn){ - if(isCallback){ - fn = errorImpl.length == 2?function(msg){errorImpl(key,msg)}:errorImpl; - }else{ - var i=arguments.length; - while(--i){ - if(fn = errorImpl[arguments[i]]){ - break; - } - } - } - } - errorHandler[key] = fn && function(msg){ - fn(msg+_locator(locator)); - }||function(){}; - } - build('warning','warn'); - build('error','warn','warning'); - build('fatalError','warn','warning','error'); - return errorHandler; -} -/** - * +ContentHandler+ErrorHandler - * +LexicalHandler+EntityResolver2 - * -DeclHandler-DTDHandler - * - * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler - * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2 - * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html - */ -function DOMHandler() { - this.cdata = false; -} -function position(locator,node){ - node.lineNumber = locator.lineNumber; - node.columnNumber = locator.columnNumber; -} -/** - * @see org.xml.sax.ContentHandler#startDocument - * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html - */ -DOMHandler.prototype = { - startDocument : function() { - this.document = new DOMImplementation().createDocument(null, null, null); - if (this.locator) { - this.document.documentURI = this.locator.systemId; - } - }, - startElement:function(namespaceURI, localName, qName, attrs) { - var doc = this.document; - var el = doc.createElementNS(namespaceURI, qName||localName); - var len = attrs.length; - appendElement(this, el); - this.currentElement = el; - - this.locator && position(this.locator,el) - for (var i = 0 ; i < len; i++) { - var namespaceURI = attrs.getURI(i); - var value = attrs.getValue(i); - var qName = attrs.getQName(i); - var attr = doc.createAttributeNS(namespaceURI, qName); - if( attr.getOffset){ - position(attr.getOffset(1),attr) - } - attr.value = attr.nodeValue = value; - el.setAttributeNode(attr) - } - }, - endElement:function(namespaceURI, localName, qName) { - var current = this.currentElement - var tagName = current.tagName; - this.currentElement = current.parentNode; - }, - startPrefixMapping:function(prefix, uri) { - }, - endPrefixMapping:function(prefix) { - }, - processingInstruction:function(target, data) { - var ins = this.document.createProcessingInstruction(target, data); - this.locator && position(this.locator,ins) - appendElement(this, ins); - }, - ignorableWhitespace:function(ch, start, length) { - }, - characters:function(chars, start, length) { - chars = _toString.apply(this,arguments) - //console.log(chars) - if(this.currentElement && chars){ - if (this.cdata) { - var charNode = this.document.createCDATASection(chars); - this.currentElement.appendChild(charNode); - } else { - var charNode = this.document.createTextNode(chars); - this.currentElement.appendChild(charNode); - } - this.locator && position(this.locator,charNode) - } - }, - skippedEntity:function(name) { - }, - endDocument:function() { - this.document.normalize(); - }, - setDocumentLocator:function (locator) { - if(this.locator = locator){// && !('lineNumber' in locator)){ - locator.lineNumber = 0; - } - }, - //LexicalHandler - comment:function(chars, start, length) { - chars = _toString.apply(this,arguments) - var comm = this.document.createComment(chars); - this.locator && position(this.locator,comm) - appendElement(this, comm); - }, - - startCDATA:function() { - //used in characters() methods - this.cdata = true; - }, - endCDATA:function() { - this.cdata = false; - }, - - startDTD:function(name, publicId, systemId) { - var impl = this.document.implementation; - if (impl && impl.createDocumentType) { - var dt = impl.createDocumentType(name, publicId, systemId); - this.locator && position(this.locator,dt) - appendElement(this, dt); - } - }, - /** - * @see org.xml.sax.ErrorHandler - * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html - */ - warning:function(error) { - console.warn(error,_locator(this.locator)); - }, - error:function(error) { - console.error(error,_locator(this.locator)); - }, - fatalError:function(error) { - console.error(error,_locator(this.locator)); - throw error; - } -} -function _locator(l){ - if(l){ - return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']' - } -} -function _toString(chars,start,length){ - if(typeof chars == 'string'){ - return chars.substr(start,length) - }else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)") - if(chars.length >= start+length || start){ - return new java.lang.String(chars,start,length)+''; - } - return chars; - } -} - -/* - * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html - * used method of org.xml.sax.ext.LexicalHandler: - * #comment(chars, start, length) - * #startCDATA() - * #endCDATA() - * #startDTD(name, publicId, systemId) - * - * - * IGNORED method of org.xml.sax.ext.LexicalHandler: - * #endDTD() - * #startEntity(name) - * #endEntity(name) - * - * - * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html - * IGNORED method of org.xml.sax.ext.DeclHandler - * #attributeDecl(eName, aName, type, mode, value) - * #elementDecl(name, model) - * #externalEntityDecl(name, publicId, systemId) - * #internalEntityDecl(name, value) - * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html - * IGNORED method of org.xml.sax.EntityResolver2 - * #resolveEntity(String name,String publicId,String baseURI,String systemId) - * #resolveEntity(publicId, systemId) - * #getExternalSubset(name, baseURI) - * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html - * IGNORED method of org.xml.sax.DTDHandler - * #notationDecl(name, publicId, systemId) {}; - * #unparsedEntityDecl(name, publicId, systemId, notationName) {}; - */ -"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){ - DOMHandler.prototype[key] = function(){return null} -}) - -/* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */ -function appendElement (hander,node) { - if (!hander.currentElement) { - hander.document.appendChild(node); - } else { - hander.currentElement.appendChild(node); - } -}//appendChild and setAttributeNS are preformance key - -if(typeof require == 'function'){ - var XMLReader = require('./sax').XMLReader; - var DOMImplementation = exports.DOMImplementation = require('./dom').DOMImplementation; - exports.XMLSerializer = require('./dom').XMLSerializer ; - exports.DOMParser = DOMParser; -} +function DOMParser(options){ + this.options = options ||{locator:{}}; + +} +DOMParser.prototype.parseFromString = function(source,mimeType){ + var options = this.options; + var sax = new XMLReader(); + var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler + var errorHandler = options.errorHandler; + var locator = options.locator; + var defaultNSMap = options.xmlns||{}; + var entityMap = {'lt':'<','gt':'>','amp':'&','quot':'"','apos':"'"} + if(locator){ + domBuilder.setDocumentLocator(locator) + } + + sax.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator); + sax.domBuilder = options.domBuilder || domBuilder; + if(/\/x?html?$/.test(mimeType)){ + entityMap.nbsp = '\xa0'; + entityMap.copy = '\xa9'; + defaultNSMap['']= 'http://www.w3.org/1999/xhtml'; + } + if(source){ + sax.parse(source,defaultNSMap,entityMap); + }else{ + sax.errorHandler.error("invalid document source"); + } + return domBuilder.document; +} +function buildErrorHandler(errorImpl,domBuilder,locator){ + if(!errorImpl){ + if(domBuilder instanceof DOMHandler){ + return domBuilder; + } + errorImpl = domBuilder ; + } + var errorHandler = {} + var isCallback = errorImpl instanceof Function; + locator = locator||{} + function build(key){ + var fn = errorImpl[key]; + if(!fn){ + if(isCallback){ + fn = errorImpl.length == 2?function(msg){errorImpl(key,msg)}:errorImpl; + }else{ + var i=arguments.length; + while(--i){ + if(fn = errorImpl[arguments[i]]){ + break; + } + } + } + } + errorHandler[key] = fn && function(msg){ + fn(msg+_locator(locator)); + }||function(){}; + } + build('warning','warn'); + build('error','warn','warning'); + build('fatalError','warn','warning','error'); + return errorHandler; +} +/** + * +ContentHandler+ErrorHandler + * +LexicalHandler+EntityResolver2 + * -DeclHandler-DTDHandler + * + * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler + * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2 + * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html + */ +function DOMHandler() { + this.cdata = false; +} +function position(locator,node){ + node.lineNumber = locator.lineNumber; + node.columnNumber = locator.columnNumber; +} +/** + * @see org.xml.sax.ContentHandler#startDocument + * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html + */ +DOMHandler.prototype = { + startDocument : function() { + this.document = new DOMImplementation().createDocument(null, null, null); + if (this.locator) { + this.document.documentURI = this.locator.systemId; + } + }, + startElement:function(namespaceURI, localName, qName, attrs) { + var doc = this.document; + var el = doc.createElementNS(namespaceURI, qName||localName); + var len = attrs.length; + appendElement(this, el); + this.currentElement = el; + + this.locator && position(this.locator,el) + for (var i = 0 ; i < len; i++) { + var namespaceURI = attrs.getURI(i); + var value = attrs.getValue(i); + var qName = attrs.getQName(i); + var attr = doc.createAttributeNS(namespaceURI, qName); + if( attr.getOffset){ + position(attr.getOffset(1),attr) + } + attr.value = attr.nodeValue = value; + el.setAttributeNode(attr) + } + }, + endElement:function(namespaceURI, localName, qName) { + var current = this.currentElement + var tagName = current.tagName; + this.currentElement = current.parentNode; + }, + startPrefixMapping:function(prefix, uri) { + }, + endPrefixMapping:function(prefix) { + }, + processingInstruction:function(target, data) { + var ins = this.document.createProcessingInstruction(target, data); + this.locator && position(this.locator,ins) + appendElement(this, ins); + }, + ignorableWhitespace:function(ch, start, length) { + }, + characters:function(chars, start, length) { + chars = _toString.apply(this,arguments) + //console.log(chars) + if(this.currentElement && chars){ + if (this.cdata) { + var charNode = this.document.createCDATASection(chars); + this.currentElement.appendChild(charNode); + } else { + var charNode = this.document.createTextNode(chars); + this.currentElement.appendChild(charNode); + } + this.locator && position(this.locator,charNode) + } + }, + skippedEntity:function(name) { + }, + endDocument:function() { + this.document.normalize(); + }, + setDocumentLocator:function (locator) { + if(this.locator = locator){// && !('lineNumber' in locator)){ + locator.lineNumber = 0; + } + }, + //LexicalHandler + comment:function(chars, start, length) { + chars = _toString.apply(this,arguments) + var comm = this.document.createComment(chars); + this.locator && position(this.locator,comm) + appendElement(this, comm); + }, + + startCDATA:function() { + //used in characters() methods + this.cdata = true; + }, + endCDATA:function() { + this.cdata = false; + }, + + startDTD:function(name, publicId, systemId) { + var impl = this.document.implementation; + if (impl && impl.createDocumentType) { + var dt = impl.createDocumentType(name, publicId, systemId); + this.locator && position(this.locator,dt) + appendElement(this, dt); + } + }, + /** + * @see org.xml.sax.ErrorHandler + * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html + */ + warning:function(error) { + console.warn(error,_locator(this.locator)); + }, + error:function(error) { + console.error(error,_locator(this.locator)); + }, + fatalError:function(error) { + console.error(error,_locator(this.locator)); + throw error; + } +} +function _locator(l){ + if(l){ + return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']' + } +} +function _toString(chars,start,length){ + if(typeof chars == 'string'){ + return chars.substr(start,length) + }else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)") + if(chars.length >= start+length || start){ + return new java.lang.String(chars,start,length)+''; + } + return chars; + } +} + +/* + * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html + * used method of org.xml.sax.ext.LexicalHandler: + * #comment(chars, start, length) + * #startCDATA() + * #endCDATA() + * #startDTD(name, publicId, systemId) + * + * + * IGNORED method of org.xml.sax.ext.LexicalHandler: + * #endDTD() + * #startEntity(name) + * #endEntity(name) + * + * + * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html + * IGNORED method of org.xml.sax.ext.DeclHandler + * #attributeDecl(eName, aName, type, mode, value) + * #elementDecl(name, model) + * #externalEntityDecl(name, publicId, systemId) + * #internalEntityDecl(name, value) + * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html + * IGNORED method of org.xml.sax.EntityResolver2 + * #resolveEntity(String name,String publicId,String baseURI,String systemId) + * #resolveEntity(publicId, systemId) + * #getExternalSubset(name, baseURI) + * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html + * IGNORED method of org.xml.sax.DTDHandler + * #notationDecl(name, publicId, systemId) {}; + * #unparsedEntityDecl(name, publicId, systemId, notationName) {}; + */ +"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){ + DOMHandler.prototype[key] = function(){return null} +}) + +/* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */ +function appendElement (hander,node) { + if (!hander.currentElement) { + hander.document.appendChild(node); + } else { + hander.currentElement.appendChild(node); + } +}//appendChild and setAttributeNS are preformance key + +if(typeof require == 'function'){ + var XMLReader = require('./sax').XMLReader; + var DOMImplementation = exports.DOMImplementation = require('./dom').DOMImplementation; + exports.XMLSerializer = require('./dom').XMLSerializer ; + exports.DOMParser = DOMParser; +} },{"./dom":8,"./sax":9}],8:[function(require,module,exports){ /* @@ -3466,590 +3466,590 @@ if(typeof require == 'function'){ } },{}],9:[function(require,module,exports){ -//[4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] -//[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040] -//[5] Name ::= NameStartChar (NameChar)* -var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]///\u10000-\uEFFFF -var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\u00B7\u0300-\u036F\\ux203F-\u2040]"); -var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$'); -//var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/ -//var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',') - -//S_TAG, S_ATTR, S_EQ, S_V -//S_ATTR_S, S_E, S_S, S_C -var S_TAG = 0;//tag name offerring -var S_ATTR = 1;//attr name offerring -var S_ATTR_S=2;//attr name end and space offer -var S_EQ = 3;//=space? -var S_V = 4;//attr value(no quot value only) -var S_E = 5;//attr value end and no space(quot end) -var S_S = 6;//(attr value end || tag end ) && (space offer) -var S_C = 7;//closed el - -function XMLReader(){ - -} - -XMLReader.prototype = { - parse:function(source,defaultNSMap,entityMap){ - var domBuilder = this.domBuilder; - domBuilder.startDocument(); - _copy(defaultNSMap ,defaultNSMap = {}) - parse(source,defaultNSMap,entityMap, - domBuilder,this.errorHandler); - domBuilder.endDocument(); - } -} -function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){ - function fixedFromCharCode(code) { - // String.prototype.fromCharCode does not supports - // > 2 bytes unicode chars directly - if (code > 0xffff) { - code -= 0x10000; - var surrogate1 = 0xd800 + (code >> 10) - , surrogate2 = 0xdc00 + (code & 0x3ff); - - return String.fromCharCode(surrogate1, surrogate2); - } else { - return String.fromCharCode(code); - } - } - function entityReplacer(a){ - var k = a.slice(1,-1); - if(k in entityMap){ - return entityMap[k]; - }else if(k.charAt(0) === '#'){ - return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x'))) - }else{ - errorHandler.error('entity not found:'+a); - return a; - } - } - function appendText(end){//has some bugs - var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer); - locator&&position(start); - domBuilder.characters(xt,0,end-start); - start = end - } - function position(start,m){ - while(start>=endPos && (m = linePattern.exec(source))){ - startPos = m.index; - endPos = startPos + m[0].length; - locator.lineNumber++; - //console.log('line++:',locator,startPos,endPos) - } - locator.columnNumber = start-startPos+1; - } - var startPos = 0; - var endPos = 0; - var linePattern = /.+(?:\r\n?|\n)|.*$/g - var locator = domBuilder.locator; - - var parseStack = [{currentNSMap:defaultNSMapCopy}] - var closeMap = {}; - var start = 0; - while(true){ - var i = source.indexOf('<',start); - if(i<0){ - if(!source.substr(start).match(/^\s*$/)){ - var doc = domBuilder.document; - var text = doc.createTextNode(source.substr(start)); - doc.appendChild(text); - domBuilder.currentElement = text; - } - return; - } - if(i>start){ - appendText(i); - } - switch(source.charAt(i+1)){ - case '/': - var end = source.indexOf('>',i+3); - var tagName = source.substring(i+2,end); - var config = parseStack.pop(); - var localNSMap = config.localNSMap; - - if(config.tagName != tagName){ - errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName ); - } - domBuilder.endElement(config.uri,config.localName,tagName); - if(localNSMap){ - for(var prefix in localNSMap){ - domBuilder.endPrefixMapping(prefix) ; - } - } - end++; - break; - // end elment - case '?':// - locator&&position(i); - end = parseInstruction(source,i,domBuilder); - break; - case '!':// 0){ - value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer); - el.add(attrName,value,start-1); - s = S_E; - }else{ - //fatalError: no end quot match - throw new Error('attribute value no end \''+c+'\' match'); - } - }else if(s == S_V){ - value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer); - //console.log(attrName,value,start,p) - el.add(attrName,value,start); - //console.dir(el) - errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!'); - start = p+1; - s = S_E - }else{ - //fatalError: no equal before - throw new Error('attribute value must after "="'); - } - break; - case '/': - switch(s){ - case S_TAG: - el.setTagName(source.slice(start,p)); - case S_E: - case S_S: - case S_C: - s = S_C; - el.closed = true; - case S_V: - case S_ATTR: - case S_ATTR_S: - break; - //case S_EQ: - default: - throw new Error("attribute invalid close char('/')") - } - break; - case ''://end document - //throw new Error('unexpected end of input') - errorHandler.error('unexpected end of input'); - case '>': - switch(s){ - case S_TAG: - el.setTagName(source.slice(start,p)); - case S_E: - case S_S: - case S_C: - break;//normal - case S_V://Compatible state - case S_ATTR: - value = source.slice(start,p); - if(value.slice(-1) === '/'){ - el.closed = true; - value = value.slice(0,-1) - } - case S_ATTR_S: - if(s === S_ATTR_S){ - value = attrName; - } - if(s == S_V){ - errorHandler.warning('attribute "'+value+'" missed quot(")!!'); - el.add(attrName,value.replace(/&#?\w+;/g,entityReplacer),start) - }else{ - errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!') - el.add(value,value,start) - } - break; - case S_EQ: - throw new Error('attribute value missed!!'); - } -// console.log(tagName,tagNamePattern,tagNamePattern.test(tagName)) - return p; - /*xml space '\x20' | #x9 | #xD | #xA; */ - case '\u0080': - c = ' '; - default: - if(c<= ' '){//space - switch(s){ - case S_TAG: - el.setTagName(source.slice(start,p));//tagName - s = S_S; - break; - case S_ATTR: - attrName = source.slice(start,p) - s = S_ATTR_S; - break; - case S_V: - var value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer); - errorHandler.warning('attribute "'+value+'" missed quot(")!!'); - el.add(attrName,value,start) - case S_E: - s = S_S; - break; - //case S_S: - //case S_EQ: - //case S_ATTR_S: - // void();break; - //case S_C: - //ignore warning - } - }else{//not space -//S_TAG, S_ATTR, S_EQ, S_V -//S_ATTR_S, S_E, S_S, S_C - switch(s){ - //case S_TAG:void();break; - //case S_ATTR:void();break; - //case S_V:void();break; - case S_ATTR_S: - errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead!!') - el.add(attrName,attrName,start); - start = p; - s = S_ATTR; - break; - case S_E: - errorHandler.warning('attribute space is required"'+attrName+'"!!') - case S_S: - s = S_ATTR; - start = p; - break; - case S_EQ: - s = S_V; - start = p; - break; - case S_C: - throw new Error("elements closed character '/' and '>' must be connected to"); - } - } - } - p++; - } -} -/** - * @return end of the elementStartPart(end of elementEndPart for selfClosed el) - */ -function appendElement(el,domBuilder,parseStack){ - var tagName = el.tagName; - var localNSMap = null; - var currentNSMap = parseStack[parseStack.length-1].currentNSMap; - var i = el.length; - while(i--){ - var a = el[i]; - var qName = a.qName; - var value = a.value; - var nsp = qName.indexOf(':'); - if(nsp>0){ - var prefix = a.prefix = qName.slice(0,nsp); - var localName = qName.slice(nsp+1); - var nsPrefix = prefix === 'xmlns' && localName - }else{ - localName = qName; - prefix = null - nsPrefix = qName === 'xmlns' && '' - } - //can not set prefix,because prefix !== '' - a.localName = localName ; - //prefix == null for no ns prefix attribute - if(nsPrefix !== false){//hack!! - if(localNSMap == null){ - localNSMap = {} - //console.log(currentNSMap,0) - _copy(currentNSMap,currentNSMap={}) - //console.log(currentNSMap,1) - } - currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value; - a.uri = 'http://www.w3.org/2000/xmlns/' - domBuilder.startPrefixMapping(nsPrefix, value) - } - } - var i = el.length; - while(i--){ - a = el[i]; - var prefix = a.prefix; - if(prefix){//no prefix attribute has no namespace - if(prefix === 'xml'){ - a.uri = 'http://www.w3.org/XML/1998/namespace'; - }if(prefix !== 'xmlns'){ - a.uri = currentNSMap[prefix] - - //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)} - } - } - } - var nsp = tagName.indexOf(':'); - if(nsp>0){ - prefix = el.prefix = tagName.slice(0,nsp); - localName = el.localName = tagName.slice(nsp+1); - }else{ - prefix = null;//important!! - localName = el.localName = tagName; - } - //no prefix element has default namespace - var ns = el.uri = currentNSMap[prefix || '']; - domBuilder.startElement(ns,localName,tagName,el); - //endPrefixMapping and startPrefixMapping have not any help for dom builder - //localNSMap = null - if(el.closed){ - domBuilder.endElement(ns,localName,tagName); - if(localNSMap){ - for(prefix in localNSMap){ - domBuilder.endPrefixMapping(prefix) - } - } - }else{ - el.currentNSMap = currentNSMap; - el.localNSMap = localNSMap; - parseStack.push(el); - } -} -function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){ - if(/^(?:script|textarea)$/i.test(tagName)){ - var elEndStart = source.indexOf('',elStartEnd); - var text = source.substring(elStartEnd+1,elEndStart); - if(/[&<]/.test(text)){ - if(/^script$/i.test(tagName)){ - //if(!/\]\]>/.test(text)){ - //lexHandler.startCDATA(); - domBuilder.characters(text,0,text.length); - //lexHandler.endCDATA(); - return elEndStart; - //} - }//}else{//text area - text = text.replace(/&#?\w+;/g,entityReplacer); - domBuilder.characters(text,0,text.length); - return elEndStart; - //} - - } - } - return elStartEnd+1; -} -function fixSelfClosed(source,elStartEnd,tagName,closeMap){ - //if(tagName in closeMap){ - var pos = closeMap[tagName]; - if(pos == null){ - //console.log(tagName) - pos = closeMap[tagName] = source.lastIndexOf('') - } - return pos',start+4); - //append comment source.substring(4,end)//',start+4); + //append comment source.substring(4,end)//',start+4); - //append comment source.substring(4,end)//',start+4); + //append comment source.substring(4,end)//',start+4); - //append comment source.substring(4,end)//',start+4); + //append comment source.substring(4,end)// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + use_camera + + + + diff --git a/plugins/phonegap-plugin-barcodescanner/src/android/README.md b/plugins/phonegap-plugin-barcodescanner/src/android/README.md new file mode 100644 index 0000000..537afd2 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/android/README.md @@ -0,0 +1 @@ +The Android .aar sources are [here](https://github.com/EddyVerbruggen/barcodescanner-lib-aar). \ No newline at end of file diff --git a/plugins/phonegap-plugin-barcodescanner/src/android/barcodescanner-release-2.0.1.aar b/plugins/phonegap-plugin-barcodescanner/src/android/barcodescanner-release-2.0.1.aar new file mode 100644 index 0000000..abea644 Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/android/barcodescanner-release-2.0.1.aar differ diff --git a/plugins/phonegap-plugin-barcodescanner/src/android/barcodescanner.gradle b/plugins/phonegap-plugin-barcodescanner/src/android/barcodescanner.gradle new file mode 100644 index 0000000..ff2b44d --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/android/barcodescanner.gradle @@ -0,0 +1,20 @@ +ext.cdvMinSdkVersion = 15 + +repositories{ + jcenter() + flatDir{ + dirs 'libs' + } +} + +dependencies { + compile 'com.android.support:support-v4:+' + compile(name:'barcodescanner', ext:'aar') +} + +android { + packagingOptions { + exclude 'META-INF/NOTICE' + exclude 'META-INF/LICENSE' + } +} \ No newline at end of file diff --git a/plugins/phonegap-plugin-barcodescanner/src/android/com/phonegap/plugins/barcodescanner/BarcodeScanner.java b/plugins/phonegap-plugin-barcodescanner/src/android/com/phonegap/plugins/barcodescanner/BarcodeScanner.java new file mode 100644 index 0000000..f2d4234 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/android/com/phonegap/plugins/barcodescanner/BarcodeScanner.java @@ -0,0 +1,305 @@ +/** + * PhoneGap is available under *either* the terms of the modified BSD license *or* the + * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. + * + * Copyright (c) Matt Kane 2010 + * Copyright (c) 2011, IBM Corporation + * Copyright (c) 2013, Maciej Nux Jaros + */ +package com.phonegap.plugins.barcodescanner; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.Manifest; +import android.app.Activity; +import android.content.Intent; +import android.util.Log; +import android.content.pm.PackageManager; + +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.CallbackContext; +import org.apache.cordova.PluginResult; +import org.apache.cordova.PermissionHelper; + +import com.google.zxing.client.android.Intents; + +/** + * This calls out to the ZXing barcode reader and returns the result. + * + * @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java + */ +public class BarcodeScanner extends CordovaPlugin { + public static final int REQUEST_CODE = 0x0ba7c0de; + + private static final String SCAN = "scan"; + private static final String ENCODE = "encode"; + private static final String CANCELLED = "cancelled"; + private static final String FORMAT = "format"; + private static final String TEXT = "text"; + private static final String DATA = "data"; + private static final String TYPE = "type"; + private static final String PREFER_FRONTCAMERA = "preferFrontCamera"; + private static final String ORIENTATION = "orientation"; + private static final String SHOW_FLIP_CAMERA_BUTTON = "showFlipCameraButton"; + private static final String FORMATS = "formats"; + private static final String PROMPT = "prompt"; + private static final String SCAN_INTENT = "com.google.zxing.client.android.SCAN"; + private static final String ENCODE_DATA = "ENCODE_DATA"; + private static final String ENCODE_TYPE = "ENCODE_TYPE"; + private static final String ENCODE_INTENT = "com.phonegap.plugins.barcodescanner.ENCODE"; + private static final String TEXT_TYPE = "TEXT_TYPE"; + private static final String EMAIL_TYPE = "EMAIL_TYPE"; + private static final String PHONE_TYPE = "PHONE_TYPE"; + private static final String SMS_TYPE = "SMS_TYPE"; + + private static final String LOG_TAG = "BarcodeScanner"; + + private String [] permissions = { Manifest.permission.CAMERA }; + + private JSONArray requestArgs; + private CallbackContext callbackContext; + + /** + * Constructor. + */ + public BarcodeScanner() { + } + + /** + * Executes the request. + * + * This method is called from the WebView thread. To do a non-trivial amount of work, use: + * cordova.getThreadPool().execute(runnable); + * + * To run on the UI thread, use: + * cordova.getActivity().runOnUiThread(runnable); + * + * @param action The action to execute. + * @param args The exec() arguments. + * @param callbackContext The callback context used when calling back into JavaScript. + * @return Whether the action was valid. + * + * @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java + */ + @Override + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) { + this.callbackContext = callbackContext; + this.requestArgs = args; + + if (action.equals(ENCODE)) { + JSONObject obj = args.optJSONObject(0); + if (obj != null) { + String type = obj.optString(TYPE); + String data = obj.optString(DATA); + + // If the type is null then force the type to text + if (type == null) { + type = TEXT_TYPE; + } + + if (data == null) { + callbackContext.error("User did not specify data to encode"); + return true; + } + + encode(type, data); + } else { + callbackContext.error("User did not specify data to encode"); + return true; + } + } else if (action.equals(SCAN)) { + + //android permission auto add + if(!hasPermisssion()) { + requestPermissions(0); + } else { + scan(args); + } + } else { + return false; + } + return true; + } + + /** + * Starts an intent to scan and decode a barcode. + */ + public void scan(final JSONArray args) { + + final CordovaPlugin that = this; + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + + Intent intentScan = new Intent(SCAN_INTENT); + intentScan.addCategory(Intent.CATEGORY_DEFAULT); + + // add config as intent extras + if (args.length() > 0) { + + JSONObject obj; + JSONArray names; + String key; + Object value; + + for (int i = 0; i < args.length(); i++) { + + try { + obj = args.getJSONObject(i); + } catch (JSONException e) { + Log.i("CordovaLog", e.getLocalizedMessage()); + continue; + } + + names = obj.names(); + for (int j = 0; j < names.length(); j++) { + try { + key = names.getString(j); + value = obj.get(key); + + if (value instanceof Integer) { + intentScan.putExtra(key, (Integer) value); + } else if (value instanceof String) { + intentScan.putExtra(key, (String) value); + } + + } catch (JSONException e) { + Log.i("CordovaLog", e.getLocalizedMessage()); + } + } + + intentScan.putExtra(Intents.Scan.CAMERA_ID, obj.optBoolean(PREFER_FRONTCAMERA, false) ? 1 : 0); + intentScan.putExtra(Intents.Scan.SHOW_FLIP_CAMERA_BUTTON, obj.optBoolean(SHOW_FLIP_CAMERA_BUTTON, false)); + if (obj.has(FORMATS)) { + intentScan.putExtra(Intents.Scan.FORMATS, obj.optString(FORMATS)); + } + if (obj.has(PROMPT)) { + intentScan.putExtra(Intents.Scan.PROMPT_MESSAGE, obj.optString(PROMPT)); + } + if (obj.has(ORIENTATION)) { + intentScan.putExtra(Intents.Scan.ORIENTATION_LOCK, obj.optString(ORIENTATION)); + } + } + + } + + // avoid calling other phonegap apps + intentScan.setPackage(that.cordova.getActivity().getApplicationContext().getPackageName()); + + that.cordova.startActivityForResult(that, intentScan, REQUEST_CODE); + } + }); + } + + /** + * Called when the barcode scanner intent completes. + * + * @param requestCode The request code originally supplied to startActivityForResult(), + * allowing you to identify who this result came from. + * @param resultCode The integer result code returned by the child activity through its setResult(). + * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). + */ + @Override + public void onActivityResult(int requestCode, int resultCode, Intent intent) { + if (requestCode == REQUEST_CODE && this.callbackContext != null) { + if (resultCode == Activity.RESULT_OK) { + JSONObject obj = new JSONObject(); + try { + obj.put(TEXT, intent.getStringExtra("SCAN_RESULT")); + obj.put(FORMAT, intent.getStringExtra("SCAN_RESULT_FORMAT")); + obj.put(CANCELLED, false); + } catch (JSONException e) { + Log.d(LOG_TAG, "This should never happen"); + } + //this.success(new PluginResult(PluginResult.Status.OK, obj), this.callback); + this.callbackContext.success(obj); + } else if (resultCode == Activity.RESULT_CANCELED) { + JSONObject obj = new JSONObject(); + try { + obj.put(TEXT, ""); + obj.put(FORMAT, ""); + obj.put(CANCELLED, true); + } catch (JSONException e) { + Log.d(LOG_TAG, "This should never happen"); + } + //this.success(new PluginResult(PluginResult.Status.OK, obj), this.callback); + this.callbackContext.success(obj); + } else { + //this.error(new PluginResult(PluginResult.Status.ERROR), this.callback); + this.callbackContext.error("Unexpected error"); + } + } + } + + /** + * Initiates a barcode encode. + * + * @param type Endoiding type. + * @param data The data to encode in the bar code. + */ + public void encode(String type, String data) { + Intent intentEncode = new Intent(ENCODE_INTENT); + intentEncode.putExtra(ENCODE_TYPE, type); + intentEncode.putExtra(ENCODE_DATA, data); + // avoid calling other phonegap apps + intentEncode.setPackage(this.cordova.getActivity().getApplicationContext().getPackageName()); + + this.cordova.getActivity().startActivity(intentEncode); + } + + /** + * check application's permissions + */ + public boolean hasPermisssion() { + for(String p : permissions) + { + if(!PermissionHelper.hasPermission(this, p)) + { + return false; + } + } + return true; + } + + /** + * We override this so that we can access the permissions variable, which no longer exists in + * the parent class, since we can't initialize it reliably in the constructor! + * + * @param requestCode The code to get request action + */ + public void requestPermissions(int requestCode) + { + PermissionHelper.requestPermissions(this, requestCode, permissions); + } + + /** + * processes the result of permission request + * + * @param requestCode The code to get request action + * @param permissions The collection of permissions + * @param grantResults The result of grant + */ + public void onRequestPermissionResult(int requestCode, String[] permissions, + int[] grantResults) throws JSONException + { + PluginResult result; + for (int r : grantResults) { + if (r == PackageManager.PERMISSION_DENIED) { + Log.d(LOG_TAG, "Permission Denied!"); + result = new PluginResult(PluginResult.Status.ILLEGAL_ACCESS_EXCEPTION); + this.callbackContext.sendPluginResult(result); + return; + } + } + + switch(requestCode) + { + case 0: + scan(this.requestArgs); + break; + } + } + +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/LICENSE b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/LICENSE new file mode 100644 index 0000000..680566f --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/LICENSE @@ -0,0 +1,703 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + +------------------------------------------------------- +*JNEXT (v1.0.8.3) + + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (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.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + +------------------------------------------------------- + +* Tokenizer +/************************************************************************ +The zlib/libpng License + +Copyright (c) 2006 Joerg Wiedenmann + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from +the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment + in the product documentation would be appreciated but is + not required. + +2. Altered source versions must be plainly marked as such, + and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. + +***********************************************************************/ \ No newline at end of file diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/index.js b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/index.js new file mode 100644 index 0000000..e263f07 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/index.js @@ -0,0 +1,213 @@ +/* +* Copyright 2013-2015 BlackBerry Limited. +* +* 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. +*/ +var barcodescanner, + resultObjs = {}, + readCallback, + _utils = require("../../lib/utils"), + _qr = require('plugin/BarcodeScanner/qrcode.js'); + +const SMS_URI_ONE = "smsto:", + SMS_URI_TWO = "sms:", + EMAIL_URI = "mailto:", + PHONE_URI = "tel:+1", + SMS_TYPE = "SMS_TYPE", + PHONE_TYPE = "PHONE_TYPE", + EMAIL_TYPE = "EMAIL_TYPE", + TEXT_TYPE = "TEXT_TYPE"; + +module.exports = { + + // methods to start and stop scanning + scan: function (success, fail, args, env) { + var result = new PluginResult(args, env); + resultObjs[result.callbackId] = result; + readCallback = result.callbackId; + var views = qnx.webplatform.getWebViews(); + var handle = null; + var group = null; + var z = -1; + for (var i = 0; i < views.length; i++) { + if (views[i].visible && views[i].zOrder > z){ + z = views[i].zOrder; + group = views[i].windowGroup; + handle = views[i].jsScreenWindowHandle; + } + } + if (handle !== null) { + var values = { group: group, handle: handle }; + barcodescanner.getInstance().startRead(result.callbackId, values); + result.noResult(true); + } else { + result.error("Failed to find window handle", false); + } + }, + + /* + Method for barcode encoding. Returns base 64 image URI + Currently only creates QRcodes + */ + encode: function (success, fail, args, env) { + + var result = new PluginResult(args, env); + values = decodeURIComponent(args[0]); + values = JSON.parse(values); + data = values["data"]; + type = values["type"]; + + if(data == "" || data == undefined){ + result.error("Data to be encoded was not specified", false); + return; + } + if(type == "" || type == undefined){ + type = TEXT_TYPE; + } + + if(type == SMS_TYPE){ + var check_one = data.substring(0,6).toLowerCase(); + var check_two = data.substring(0,4).toLowerCase(); + if(!(check_one == SMS_URI_ONE || check_two == SMS_URI_TWO)){ + data = SMS_URI_ONE+data; + } + }else if(type == EMAIL_TYPE){ + var check = data.substring(0,7).toLowerCase(); + if(check != EMAIL_URI){ + data = EMAIL_URI+data; + } + }else if(type == PHONE_TYPE){ + var check = data.substring(0,4).toLowerCase(); + if(check != PHONE_URI){ + data = PHONE_URI+data; + } + } + + console.log("Type: "+type + " Data: " + data); + + //Make QRcode using qrcode.js + var bdiv = document.createElement('div'); + var options = { + text: data, + width: 256, + height: 256, + colorDark : "#000000", + colorLight : "#ffffff", + }; + + var imageURI = _qr.makeQRcode(bdiv, options); + + try{ + result.ok(imageURI,false); + }catch(e){ + result.error("Failed to encode barcode", false); + } + } +}; + + +JNEXT.BarcodeScanner = function () { + var self = this, + hasInstance = false; + + self.getId = function () { + return self.m_id; + }; + + self.init = function () { + if (!JNEXT.require("libBarcodeScanner")) { + return false; + } + + self.m_id = JNEXT.createObject("libBarcodeScanner.BarcodeScannerJS"); + + if (self.m_id === "") { + return false; + } + + JNEXT.registerEvents(self); + }; + + // ************************ + // Enter your methods here + // ************************ + + // Fired by the Event framework (used by asynchronous callbacks) + + self.onEvent = function (strData) { + var arData = strData.split(" "), + callbackId = arData[0], + receivedEvent = arData[1], + data = arData[2], + result = resultObjs[callbackId], + events = ["community.barcodescanner.codefound.native", + "community.barcodescanner.errorfound.native", + "community.barcodescanner.started.native", + "community.barcodescanner.ended.native"]; + + // Restructures results when codefound has spaces + if(arData.length > 3){ + var i; + for(i=3; i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/.settings/com.qnx.tools.ide.core.prefs b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/.settings/com.qnx.tools.ide.core.prefs new file mode 100644 index 0000000..5227f00 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/.settings/com.qnx.tools.ide.core.prefs @@ -0,0 +1,2 @@ +QNX_CURRENT_INSTALL=BlackBerry Native SDK 10.2 +eclipse.preferences.version=1 diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/device/.gitignore b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/device/.gitignore new file mode 100644 index 0000000..1209638 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/device/.gitignore @@ -0,0 +1,2 @@ +/src +/public diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/device/libBarcodeScanner.so b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/device/libBarcodeScanner.so new file mode 100644 index 0000000..bd8a3af Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/device/libBarcodeScanner.so differ diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/autolink.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/autolink.h new file mode 100644 index 0000000..37c9258 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/autolink.h @@ -0,0 +1,19 @@ +#ifndef JSON_AUTOLINK_H_INCLUDED +# define JSON_AUTOLINK_H_INCLUDED + +# include "config.h" + +# ifdef JSON_IN_CPPTL +# include +# endif + +# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) +# define CPPTL_AUTOLINK_NAME "json" +# undef CPPTL_AUTOLINK_DLL +# ifdef JSON_DLL +# define CPPTL_AUTOLINK_DLL +# endif +# include "autolink.h" +# endif + +#endif // JSON_AUTOLINK_H_INCLUDED diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/config.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/config.h new file mode 100644 index 0000000..5d334cb --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/config.h @@ -0,0 +1,43 @@ +#ifndef JSON_CONFIG_H_INCLUDED +# define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 +/// If defined, indicates that Json specific container should be used +/// (hash table & simple deque container with customizable allocator). +/// THIS FEATURE IS STILL EXPERIMENTAL! +//# define JSON_VALUE_USE_INTERNAL_MAP 1 +/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. +/// The memory pools allocator used optimization (initializing Value and ValueInternalLink +/// as if it was a POD) that may cause some validation tool to report errors. +/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. +//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 + +/// If defined, indicates that Json use exception to report invalid type manipulation +/// instead of C assert macro. +# define JSON_USE_EXCEPTION 1 + +# ifdef JSON_IN_CPPTL +# include +# ifndef JSON_USE_CPPTL +# define JSON_USE_CPPTL 1 +# endif +# endif + +# ifdef JSON_IN_CPPTL +# define JSON_API CPPTL_API +# elif defined(JSON_DLL_BUILD) +# define JSON_API __declspec(dllexport) +# elif defined(JSON_DLL) +# define JSON_API __declspec(dllimport) +# else +# define JSON_API +# endif + +#endif // JSON_CONFIG_H_INCLUDED diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/features.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/features.h new file mode 100644 index 0000000..5a9adec --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/features.h @@ -0,0 +1,42 @@ +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +# define CPPTL_JSON_FEATURES_H_INCLUDED + +# include "forwards.h" + +namespace Json { + + /** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ + class JSON_API Features + { + public: + /** \brief A configuration that allows all features and assumes all strings are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c false. + bool strictRoot_; + }; + +} // namespace Json + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/forwards.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/forwards.h new file mode 100644 index 0000000..d0ce830 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/forwards.h @@ -0,0 +1,39 @@ +#ifndef JSON_FORWARDS_H_INCLUDED +# define JSON_FORWARDS_H_INCLUDED + +# include "config.h" + +namespace Json { + + // writer.h + class FastWriter; + class StyledWriter; + + // reader.h + class Reader; + + // features.h + class Features; + + // value.h + typedef int Int; + typedef unsigned int UInt; + class StaticString; + class Path; + class PathArgument; + class Value; + class ValueIteratorBase; + class ValueIterator; + class ValueConstIterator; +#ifdef JSON_VALUE_USE_INTERNAL_MAP + class ValueAllocator; + class ValueMapAllocator; + class ValueInternalLink; + class ValueInternalArray; + class ValueInternalMap; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + +} // namespace Json + + +#endif // JSON_FORWARDS_H_INCLUDED diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/json.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/json.h new file mode 100644 index 0000000..c71ed65 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/json.h @@ -0,0 +1,10 @@ +#ifndef JSON_JSON_H_INCLUDED +# define JSON_JSON_H_INCLUDED + +# include "autolink.h" +# include "value.h" +# include "reader.h" +# include "writer.h" +# include "features.h" + +#endif // JSON_JSON_H_INCLUDED diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/reader.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/reader.h new file mode 100644 index 0000000..ee1d6a2 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/reader.h @@ -0,0 +1,196 @@ +#ifndef CPPTL_JSON_READER_H_INCLUDED +# define CPPTL_JSON_READER_H_INCLUDED + +# include "features.h" +# include "value.h" +# include +# include +# include +# include + +namespace Json { + + /** \brief Unserialize a JSON document into a Value. + * + */ + class JSON_API Reader + { + public: + typedef char Char; + typedef const Char *Location; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader( const Features &features ); + + /** \brief Read a Value from a JSON document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const std::string &document, + Value &root, + bool collectComments = true ); + + /** \brief Read a Value from a JSON document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments = true ); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse( std::istream &is, + Value &root, + bool collectComments = true ); + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + */ + std::string getFormatedErrorMessages() const; + + private: + enum TokenType + { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token + { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo + { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool expectToken( TokenType type, Token &token, const char *message ); + bool readToken( Token &token ); + void skipSpaces(); + bool match( Location pattern, + int patternLength ); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject( Token &token ); + bool readArray( Token &token ); + bool decodeNumber( Token &token ); + bool decodeString( Token &token ); + bool decodeString( Token &token, std::string &decoded ); + bool decodeDouble( Token &token ); + bool decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool addError( const std::string &message, + Token &token, + Location extra = 0 ); + bool recoverFromError( TokenType skipUntilToken ); + bool addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ); + void skipUntilSpace(); + Value ¤tValue(); + Char getNextChar(); + void getLocationLineAndColumn( Location location, + int &line, + int &column ) const; + std::string getLocationLineAndColumn( Location location ) const; + void addComment( Location begin, + Location end, + CommentPlacement placement ); + void skipCommentTokens( Token &token ); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value *lastValue_; + std::string commentsBefore_; + Features features_; + bool collectComments_; + }; + + /** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() + */ + std::istream& operator>>( std::istream&, Value& ); + +} // namespace Json + +#endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/value.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/value.h new file mode 100644 index 0000000..58bfd88 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/value.h @@ -0,0 +1,1069 @@ +#ifndef CPPTL_JSON_H_INCLUDED +# define CPPTL_JSON_H_INCLUDED + +# include "forwards.h" +# include +# include + +# ifndef JSON_USE_CPPTL_SMALLMAP +# include +# else +# include +# endif +# ifdef JSON_USE_CPPTL +# include +# endif + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + + /** \brief Type of the value held by a Value object. + */ + enum ValueType + { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). + }; + + enum CommentPlacement + { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for root value) + numberOfCommentPlacement + }; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + + /** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + class JSON_API StaticString + { + public: + explicit StaticString( const char *czstring ) + : str_( czstring ) + { + } + + operator const char *() const + { + return str_; + } + + const char *c_str() const + { + return str_; + } + + private: + const char *str_; + }; + + /** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. + * Non const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resize and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtanis default value in the case the required element + * does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + */ + class JSON_API Value + { + friend class ValueIteratorBase; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + friend class ValueInternalLink; + friend class ValueInternalMap; +# endif + public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; + typedef UInt ArrayIndex; + + static const Value null; + static const Int minInt; + static const Int maxInt; + static const UInt maxUInt; + + private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION +# ifndef JSON_VALUE_USE_INTERNAL_MAP + class CZString + { + public: + enum DuplicationPolicy + { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString( int index ); + CZString( const char *cstr, DuplicationPolicy allocate ); + CZString( const CZString &other ); + ~CZString(); + CZString &operator =( const CZString &other ); + bool operator<( const CZString &other ) const; + bool operator==( const CZString &other ) const; + int index() const; + const char *c_str() const; + bool isStaticString() const; + private: + void swap( CZString &other ); + const char *cstr_; + int index_; + }; + + public: +# ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +# else + typedef CppTL::SmallMap ObjectValues; +# endif // ifndef JSON_USE_CPPTL_SMALLMAP +# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. + This is useful since clear() and resize() will not alter types. + + Examples: + \code + Json::Value null_value; // null + Json::Value arr_value(Json::arrayValue); // [] + Json::Value obj_value(Json::objectValue); // {} + \endcode + */ + Value( ValueType type = nullValue ); + Value( Int value ); + Value( UInt value ); + Value( double value ); + Value( const char *value ); + Value( const char *beginValue, const char *endValue ); + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * \endcode + */ + Value( const StaticString &value ); + Value( const std::string &value ); +# ifdef JSON_USE_CPPTL + Value( const CppTL::ConstString &value ); +# endif + Value( bool value ); + Value( const Value &other ); + ~Value(); + + Value &operator=( const Value &other ); + /// Swap values. + /// \note Currently, comments are intentionally not swapped, for + /// both logic and efficiency. + void swap( Value &other ); + + ValueType type() const; + + bool operator <( const Value &other ) const; + bool operator <=( const Value &other ) const; + bool operator >=( const Value &other ) const; + bool operator >( const Value &other ) const; + + bool operator ==( const Value &other ) const; + bool operator !=( const Value &other ) const; + + int compare( const Value &other ); + + const char *asCString() const; + std::string asString() const; +# ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +# endif + Int asInt() const; + UInt asUInt() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isUInt() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo( ValueType other ) const; + + /// Number of values in array or object + UInt size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize( UInt size ); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value &operator[]( UInt index ); + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value &operator[]( UInt index ) const; + /// If the array contains at least index+1 elements, returns the element value, + /// otherwise returns defaultValue. + Value get( UInt index, + const Value &defaultValue ) const; + /// Return true if index < size(). + bool isValidIndex( UInt index ) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value &append( const Value &value ); + + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const char *key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const char *key ) const; + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const std::string &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const std::string &key ) const; + /** \brief Access an object value by name, create a null member if it does not exist. + + * If the object as no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value &operator[]( const StaticString &key ); +# ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const CppTL::ConstString &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const CppTL::ConstString &key ) const; +# endif + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const char *key, + const Value &defaultValue ) const; + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const std::string &key, + const Value &defaultValue ) const; +# ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const CppTL::ConstString &key, + const Value &defaultValue ) const; +# endif + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + Value removeMember( const char* key ); + /// Same as removeMember(const char*) + Value removeMember( const std::string &key ); + + /// Return true if the object has a member named key. + bool isMember( const char *key ) const; + /// Return true if the object has a member named key. + bool isMember( const std::string &key ) const; +# ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember( const CppTL::ConstString &key ) const; +# endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + +//# ifdef JSON_USE_CPPTL +// EnumMemberNames enumMemberNames() const; +// EnumValues enumValues() const; +//# endif + + /// Comments must be //... or /* ... */ + void setComment( const char *comment, + CommentPlacement placement ); + /// Comments must be //... or /* ... */ + void setComment( const std::string &comment, + CommentPlacement placement ); + bool hasComment( CommentPlacement placement ) const; + /// Include delimiters and embedded newlines. + std::string getComment( CommentPlacement placement ) const; + + std::string toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + private: + Value &resolveReference( const char *key, + bool isStatic ); + +# ifdef JSON_VALUE_USE_INTERNAL_MAP + inline bool isItemAvailable() const + { + return itemIsUsed_ == 0; + } + + inline void setItemUsed( bool isUsed = true ) + { + itemIsUsed_ = isUsed ? 1 : 0; + } + + inline bool isMemberNameStatic() const + { + return memberNameIsStatic_ == 0; + } + + inline void setMemberNameIsStatic( bool isStatic ) + { + memberNameIsStatic_ = isStatic ? 1 : 0; + } +# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP + + private: + struct CommentInfo + { + CommentInfo(); + ~CommentInfo(); + + void setComment( const char *text ); + + char *comment_; + }; + + //struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder + { + Int int_; + UInt uint_; + double real_; + bool bool_; + char *string_; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + ValueInternalArray *array_; + ValueInternalMap *map_; +#else + ObjectValues *map_; +# endif + } value_; + ValueType type_ : 8; + int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. +# ifdef JSON_VALUE_USE_INTERNAL_MAP + unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. + int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. +# endif + CommentInfo *comments_; + }; + + + /** \brief Experimental and untested: represents an element of the "path" to access a node. + */ + class PathArgument + { + public: + friend class Path; + + PathArgument(); + PathArgument( UInt index ); + PathArgument( const char *key ); + PathArgument( const std::string &key ); + + private: + enum Kind + { + kindNone = 0, + kindIndex, + kindKey + }; + std::string key_; + UInt index_; + Kind kind_; + }; + + /** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ + class Path + { + public: + Path( const std::string &path, + const PathArgument &a1 = PathArgument(), + const PathArgument &a2 = PathArgument(), + const PathArgument &a3 = PathArgument(), + const PathArgument &a4 = PathArgument(), + const PathArgument &a5 = PathArgument() ); + + const Value &resolve( const Value &root ) const; + Value resolve( const Value &root, + const Value &defaultValue ) const; + /// Creates the "path" to access the specified node and returns a reference on the node. + Value &make( Value &root ) const; + + private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath( const std::string &path, + const InArgs &in ); + void addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ); + void invalidPath( const std::string &path, + int location ); + + Args args_; + }; + + /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. + * + * - makeMemberName() and releaseMemberName() are called to respectively duplicate and + * free an Json::objectValue member name. + * - duplicateStringValue() and releaseStringValue() are called similarly to + * duplicate and free a Json::stringValue value. + */ + class ValueAllocator + { + public: + enum { unknown = (unsigned)-1 }; + + virtual ~ValueAllocator(); + + virtual char *makeMemberName( const char *memberName ) = 0; + virtual void releaseMemberName( char *memberName ) = 0; + virtual char *duplicateStringValue( const char *value, + unsigned int length = unknown ) = 0; + virtual void releaseStringValue( char *value ) = 0; + }; + +#ifdef JSON_VALUE_USE_INTERNAL_MAP + /** \brief Allocator to customize Value internal map. + * Below is an example of a simple implementation (default implementation actually + * use memory pool for speed). + * \code + class DefaultValueMapAllocator : public ValueMapAllocator + { + public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + return new ValueInternalMap(); + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + return new ValueInternalMap( other ); + } + + virtual void destructMap( ValueInternalMap *map ) + { + delete map; + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + return new ValueInternalLink(); + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + delete link; + } + }; + * \endcode + */ + class JSON_API ValueMapAllocator + { + public: + virtual ~ValueMapAllocator(); + virtual ValueInternalMap *newMap() = 0; + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; + virtual void destructMap( ValueInternalMap *map ) = 0; + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; + virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; + virtual ValueInternalLink *allocateMapLink() = 0; + virtual void releaseMapLink( ValueInternalLink *link ) = 0; + }; + + /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). + * \internal previous_ & next_ allows for bidirectional traversal. + */ + class JSON_API ValueInternalLink + { + public: + enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. + enum InternalFlags { + flagAvailable = 0, + flagUsed = 1 + }; + + ValueInternalLink(); + + ~ValueInternalLink(); + + Value items_[itemPerLink]; + char *keys_[itemPerLink]; + ValueInternalLink *previous_; + ValueInternalLink *next_; + }; + + + /** \brief A linked page based hash-table implementation used internally by Value. + * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked + * list in each bucket to handle collision. There is an addional twist in that + * each node of the collision linked list is a page containing a fixed amount of + * value. This provides a better compromise between memory usage and speed. + * + * Each bucket is made up of a chained list of ValueInternalLink. The last + * link of a given bucket can be found in the 'previous_' field of the following bucket. + * The last link of the last bucket is stored in tailLink_ as it has no following bucket. + * Only the last link of a bucket may contains 'available' item. The last link always + * contains at least one element unless is it the bucket one very first link. + */ + class JSON_API ValueInternalMap + { + friend class ValueIteratorBase; + friend class Value; + public: + typedef unsigned int HashKey; + typedef unsigned int BucketIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState + { + IteratorState() + : map_(0) + , link_(0) + , itemIndex_(0) + , bucketIndex_(0) + { + } + ValueInternalMap *map_; + ValueInternalLink *link_; + BucketIndex itemIndex_; + BucketIndex bucketIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalMap(); + ValueInternalMap( const ValueInternalMap &other ); + ValueInternalMap &operator =( const ValueInternalMap &other ); + ~ValueInternalMap(); + + void swap( ValueInternalMap &other ); + + BucketIndex size() const; + + void clear(); + + bool reserveDelta( BucketIndex growth ); + + bool reserve( BucketIndex newItemCount ); + + const Value *find( const char *key ) const; + + Value *find( const char *key ); + + Value &resolveReference( const char *key, + bool isStatic ); + + void remove( const char *key ); + + void doActualRemove( ValueInternalLink *link, + BucketIndex index, + BucketIndex bucketIndex ); + + ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); + + Value &setNewItem( const char *key, + bool isStatic, + ValueInternalLink *link, + BucketIndex index ); + + Value &unsafeAdd( const char *key, + bool isStatic, + HashKey hashedKey ); + + HashKey hash( const char *key ) const; + + int compare( const ValueInternalMap &other ) const; + + private: + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void incrementBucket( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static const char *key( const IteratorState &iterator ); + static const char *key( const IteratorState &iterator, bool &isStatic ); + static Value &value( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + + private: + ValueInternalLink *buckets_; + ValueInternalLink *tailLink_; + BucketIndex bucketsSize_; + BucketIndex itemCount_; + }; + + /** \brief A simplified deque implementation used internally by Value. + * \internal + * It is based on a list of fixed "page", each page contains a fixed number of items. + * Instead of using a linked-list, a array of pointer is used for fast item look-up. + * Look-up for an element is as follow: + * - compute page index: pageIndex = itemIndex / itemsPerPage + * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] + * + * Insertion is amortized constant time (only the array containing the index of pointers + * need to be reallocated when items are appended). + */ + class JSON_API ValueInternalArray + { + friend class Value; + friend class ValueIteratorBase; + public: + enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. + typedef Value::ArrayIndex ArrayIndex; + typedef unsigned int PageIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState // Must be a POD + { + IteratorState() + : array_(0) + , currentPageIndex_(0) + , currentItemIndex_(0) + { + } + ValueInternalArray *array_; + Value **currentPageIndex_; + unsigned int currentItemIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalArray(); + ValueInternalArray( const ValueInternalArray &other ); + ValueInternalArray &operator =( const ValueInternalArray &other ); + ~ValueInternalArray(); + void swap( ValueInternalArray &other ); + + void clear(); + void resize( ArrayIndex newSize ); + + Value &resolveReference( ArrayIndex index ); + + Value *find( ArrayIndex index ) const; + + ArrayIndex size() const; + + int compare( const ValueInternalArray &other ) const; + + private: + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static Value &dereference( const IteratorState &iterator ); + static Value &unsafeDereference( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + static ArrayIndex indexOf( const IteratorState &iterator ); + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + void makeIterator( IteratorState &it, ArrayIndex index ) const; + + void makeIndexValid( ArrayIndex index ); + + Value **pages_; + ArrayIndex size_; + PageIndex pageCount_; + }; + + /** \brief Experimental: do not use. Allocator to customize Value internal array. + * Below is an example of a simple implementation (actual implementation use + * memory pool). + \code +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator + virtual ~DefaultValueArrayAllocator() + { + } + + virtual ValueInternalArray *newArray() + { + return new ValueInternalArray(); + } + + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) + { + return new ValueInternalArray( other ); + } + + virtual void destruct( ValueInternalArray *array ) + { + delete array; + } + + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) + { + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast( newIndexes ); + } + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) + { + if ( indexes ) + free( indexes ); + } + + virtual Value *allocateArrayPage() + { + return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); + } + + virtual void releaseArrayPage( Value *value ) + { + if ( value ) + free( value ); + } +}; + \endcode + */ + class JSON_API ValueArrayAllocator + { + public: + virtual ~ValueArrayAllocator(); + virtual ValueInternalArray *newArray() = 0; + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; + virtual void destructArray( ValueInternalArray *array ) = 0; + /** \brief Reallocate array page index. + * Reallocates an array of pointer on each page. + * \param indexes [input] pointer on the current index. May be \c NULL. + * [output] pointer on the new index of at least + * \a minNewIndexCount pages. + * \param indexCount [input] current number of pages in the index. + * [output] number of page the reallocated index can handle. + * \b MUST be >= \a minNewIndexCount. + * \param minNewIndexCount Minimum number of page the new index must be able to + * handle. + */ + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) = 0; + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) = 0; + virtual Value *allocateArrayPage() = 0; + virtual void releaseArrayPage( Value *value ) = 0; + }; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + + + /** \brief base class for Value iterators. + * + */ + class ValueIteratorBase + { + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + ValueIteratorBase(); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); +#else + ValueIteratorBase( const ValueInternalArray::IteratorState &state ); + ValueIteratorBase( const ValueInternalMap::IteratorState &state ); +#endif + + bool operator ==( const SelfType &other ) const + { + return isEqual( other ); + } + + bool operator !=( const SelfType &other ) const + { + return !isEqual( other ); + } + + difference_type operator -( const SelfType &other ) const + { + return computeDistance( other ); + } + + /// Return either the index or the member name of the referenced value as a Value. + Value key() const; + + /// Return the index of the referenced Value. -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value. "" if it is not an objectValue. + const char *memberName() const; + + protected: + Value &deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance( const SelfType &other ) const; + + bool isEqual( const SelfType &other ) const; + + void copy( const SelfType &other ); + + private: +#ifndef JSON_VALUE_USE_INTERNAL_MAP + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; +#else + union + { + ValueInternalArray::IteratorState array_; + ValueInternalMap::IteratorState map_; + } iterator_; + bool isArray_; +#endif + }; + + /** \brief const iterator for object and array value. + * + */ + class ValueConstIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef const Value &reference; + typedef const Value *pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueConstIterator( const ValueInternalArray::IteratorState &state ); + ValueConstIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + SelfType &operator =( const ValueIteratorBase &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + + /** \brief Iterator for object and array value. + */ + class ValueIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef Value &reference; + typedef Value *pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + ValueIterator( const ValueConstIterator &other ); + ValueIterator( const ValueIterator &other ); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueIterator( const ValueInternalArray::IteratorState &state ); + ValueIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + + SelfType &operator =( const SelfType &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + +} // namespace Json + + +#endif // CPPTL_JSON_H_INCLUDED diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/writer.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/writer.h new file mode 100644 index 0000000..5f4b83b --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/writer.h @@ -0,0 +1,174 @@ +#ifndef JSON_WRITER_H_INCLUDED +# define JSON_WRITER_H_INCLUDED + +# include "value.h" +# include +# include +# include + +namespace Json { + + class Value; + + /** \brief Abstract class for writers. + */ + class JSON_API Writer + { + public: + virtual ~Writer(); + + virtual std::string write( const Value &root ) = 0; + }; + + /** \brief Outputs a Value in JSON format without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + */ + class JSON_API FastWriter : public Writer + { + public: + FastWriter(); + virtual ~FastWriter(){} + + void enableYAMLCompatibility(); + + public: // overridden from Writer + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + + std::string document_; + bool yamlCompatiblityEnabled_; + }; + + /** \brief Writes a Value in JSON format in a human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledWriter: public Writer + { + public: + StyledWriter(); + virtual ~StyledWriter(){} + + public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; + }; + + /** \brief Writes a Value in JSON format in a human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledStreamWriter + { + public: + StyledStreamWriter( std::string indentation="\t" ); + ~StyledStreamWriter(){} + + public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not return a value. + */ + void write( std::ostream &out, const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_; + }; + + std::string JSON_API valueToString( Int value ); + std::string JSON_API valueToString( UInt value ); + std::string JSON_API valueToString( double value ); + std::string JSON_API valueToString( bool value ); + std::string JSON_API valueToQuotedString( const char *value ); + + /// \brief Output using the StyledStreamWriter. + /// \see Json::operator>>() + std::ostream& operator<<( std::ostream&, const Value &root ); + +} // namespace Json + + + +#endif // JSON_WRITER_H_INCLUDED diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_batchallocator.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_batchallocator.h new file mode 100644 index 0000000..87ea5ed --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_batchallocator.h @@ -0,0 +1,125 @@ +#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED +# define JSONCPP_BATCHALLOCATOR_H_INCLUDED + +# include +# include + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +namespace Json { + +/* Fast memory allocator. + * + * This memory allocator allocates memory for a batch of object (specified by + * the page size, the number of object in each page). + * + * It does not allow the destruction of a single object. All the allocated objects + * can be destroyed at once. The memory can be either released or reused for future + * allocation. + * + * The in-place new operator must be used to construct the object using the pointer + * returned by allocate. + */ +template +class BatchAllocator +{ +public: + typedef AllocatedType Type; + + BatchAllocator( unsigned int objectsPerPage = 255 ) + : freeHead_( 0 ) + , objectsPerPage_( objectsPerPage ) + { +// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); + assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. + assert( objectsPerPage >= 16 ); + batches_ = allocateBatch( 0 ); // allocated a dummy page + currentBatch_ = batches_; + } + + ~BatchAllocator() + { + for ( BatchInfo *batch = batches_; batch; ) + { + BatchInfo *nextBatch = batch->next_; + free( batch ); + batch = nextBatch; + } + } + + /// allocate space for an array of objectPerAllocation object. + /// @warning it is the responsability of the caller to call objects constructors. + AllocatedType *allocate() + { + if ( freeHead_ ) // returns node from free list. + { + AllocatedType *object = freeHead_; + freeHead_ = *(AllocatedType **)object; + return object; + } + if ( currentBatch_->used_ == currentBatch_->end_ ) + { + currentBatch_ = currentBatch_->next_; + while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) + currentBatch_ = currentBatch_->next_; + + if ( !currentBatch_ ) // no free batch found, allocate a new one + { + currentBatch_ = allocateBatch( objectsPerPage_ ); + currentBatch_->next_ = batches_; // insert at the head of the list + batches_ = currentBatch_; + } + } + AllocatedType *allocated = currentBatch_->used_; + currentBatch_->used_ += objectPerAllocation; + return allocated; + } + + /// Release the object. + /// @warning it is the responsability of the caller to actually destruct the object. + void release( AllocatedType *object ) + { + assert( object != 0 ); + *(AllocatedType **)object = freeHead_; + freeHead_ = object; + } + +private: + struct BatchInfo + { + BatchInfo *next_; + AllocatedType *used_; + AllocatedType *end_; + AllocatedType buffer_[objectPerAllocation]; + }; + + // disabled copy constructor and assignement operator. + BatchAllocator( const BatchAllocator & ); + void operator =( const BatchAllocator &); + + static BatchInfo *allocateBatch( unsigned int objectsPerPage ) + { + const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation + + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; + BatchInfo *batch = static_cast( malloc( mallocSize ) ); + batch->next_ = 0; + batch->used_ = batch->buffer_; + batch->end_ = batch->buffer_ + objectsPerPage; + return batch; + } + + BatchInfo *batches_; + BatchInfo *currentBatch_; + /// Head of a single linked list within the allocated space of freeed object + AllocatedType *freeHead_; + unsigned int objectsPerPage_; +}; + + +} // namespace Json + +# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION + +#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED + diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_internalarray.inl b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_internalarray.inl new file mode 100644 index 0000000..9b985d2 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_internalarray.inl @@ -0,0 +1,448 @@ +// included by json_value.cpp +// everything is within Json namespace + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueInternalArray +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueArrayAllocator::~ValueArrayAllocator() +{ +} + +// ////////////////////////////////////////////////////////////////// +// class DefaultValueArrayAllocator +// ////////////////////////////////////////////////////////////////// +#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator + virtual ~DefaultValueArrayAllocator() + { + } + + virtual ValueInternalArray *newArray() + { + return new ValueInternalArray(); + } + + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) + { + return new ValueInternalArray( other ); + } + + virtual void destructArray( ValueInternalArray *array ) + { + delete array; + } + + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) + { + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast( newIndexes ); + } + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) + { + if ( indexes ) + free( indexes ); + } + + virtual Value *allocateArrayPage() + { + return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); + } + + virtual void releaseArrayPage( Value *value ) + { + if ( value ) + free( value ); + } +}; + +#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +/// @todo make this thread-safe (lock when accessign batch allocator) +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator + virtual ~DefaultValueArrayAllocator() + { + } + + virtual ValueInternalArray *newArray() + { + ValueInternalArray *array = arraysAllocator_.allocate(); + new (array) ValueInternalArray(); // placement new + return array; + } + + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) + { + ValueInternalArray *array = arraysAllocator_.allocate(); + new (array) ValueInternalArray( other ); // placement new + return array; + } + + virtual void destructArray( ValueInternalArray *array ) + { + if ( array ) + { + array->~ValueInternalArray(); + arraysAllocator_.release( array ); + } + } + + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) + { + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast( newIndexes ); + } + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) + { + if ( indexes ) + free( indexes ); + } + + virtual Value *allocateArrayPage() + { + return static_cast( pagesAllocator_.allocate() ); + } + + virtual void releaseArrayPage( Value *value ) + { + if ( value ) + pagesAllocator_.release( value ); + } +private: + BatchAllocator arraysAllocator_; + BatchAllocator pagesAllocator_; +}; +#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR + +static ValueArrayAllocator *&arrayAllocator() +{ + static DefaultValueArrayAllocator defaultAllocator; + static ValueArrayAllocator *arrayAllocator = &defaultAllocator; + return arrayAllocator; +} + +static struct DummyArrayAllocatorInitializer { + DummyArrayAllocatorInitializer() + { + arrayAllocator(); // ensure arrayAllocator() statics are initialized before main(). + } +} dummyArrayAllocatorInitializer; + +// ////////////////////////////////////////////////////////////////// +// class ValueInternalArray +// ////////////////////////////////////////////////////////////////// +bool +ValueInternalArray::equals( const IteratorState &x, + const IteratorState &other ) +{ + return x.array_ == other.array_ + && x.currentItemIndex_ == other.currentItemIndex_ + && x.currentPageIndex_ == other.currentPageIndex_; +} + + +void +ValueInternalArray::increment( IteratorState &it ) +{ + JSON_ASSERT_MESSAGE( it.array_ && + (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ + != it.array_->size_, + "ValueInternalArray::increment(): moving iterator beyond end" ); + ++(it.currentItemIndex_); + if ( it.currentItemIndex_ == itemsPerPage ) + { + it.currentItemIndex_ = 0; + ++(it.currentPageIndex_); + } +} + + +void +ValueInternalArray::decrement( IteratorState &it ) +{ + JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_ + && it.currentItemIndex_ == 0, + "ValueInternalArray::decrement(): moving iterator beyond end" ); + if ( it.currentItemIndex_ == 0 ) + { + it.currentItemIndex_ = itemsPerPage-1; + --(it.currentPageIndex_); + } + else + { + --(it.currentItemIndex_); + } +} + + +Value & +ValueInternalArray::unsafeDereference( const IteratorState &it ) +{ + return (*(it.currentPageIndex_))[it.currentItemIndex_]; +} + + +Value & +ValueInternalArray::dereference( const IteratorState &it ) +{ + JSON_ASSERT_MESSAGE( it.array_ && + (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ + < it.array_->size_, + "ValueInternalArray::dereference(): dereferencing invalid iterator" ); + return unsafeDereference( it ); +} + +void +ValueInternalArray::makeBeginIterator( IteratorState &it ) const +{ + it.array_ = const_cast( this ); + it.currentItemIndex_ = 0; + it.currentPageIndex_ = pages_; +} + + +void +ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const +{ + it.array_ = const_cast( this ); + it.currentItemIndex_ = index % itemsPerPage; + it.currentPageIndex_ = pages_ + index / itemsPerPage; +} + + +void +ValueInternalArray::makeEndIterator( IteratorState &it ) const +{ + makeIterator( it, size_ ); +} + + +ValueInternalArray::ValueInternalArray() + : pages_( 0 ) + , size_( 0 ) + , pageCount_( 0 ) +{ +} + + +ValueInternalArray::ValueInternalArray( const ValueInternalArray &other ) + : pages_( 0 ) + , pageCount_( 0 ) + , size_( other.size_ ) +{ + PageIndex minNewPages = other.size_ / itemsPerPage; + arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); + JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, + "ValueInternalArray::reserve(): bad reallocation" ); + IteratorState itOther; + other.makeBeginIterator( itOther ); + Value *value; + for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) ) + { + if ( index % itemsPerPage == 0 ) + { + PageIndex pageIndex = index / itemsPerPage; + value = arrayAllocator()->allocateArrayPage(); + pages_[pageIndex] = value; + } + new (value) Value( dereference( itOther ) ); + } +} + + +ValueInternalArray & +ValueInternalArray::operator =( const ValueInternalArray &other ) +{ + ValueInternalArray temp( other ); + swap( temp ); + return *this; +} + + +ValueInternalArray::~ValueInternalArray() +{ + // destroy all constructed items + IteratorState it; + IteratorState itEnd; + makeBeginIterator( it); + makeEndIterator( itEnd ); + for ( ; !equals(it,itEnd); increment(it) ) + { + Value *value = &dereference(it); + value->~Value(); + } + // release all pages + PageIndex lastPageIndex = size_ / itemsPerPage; + for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex ) + arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); + // release pages index + arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ ); +} + + +void +ValueInternalArray::swap( ValueInternalArray &other ) +{ + Value **tempPages = pages_; + pages_ = other.pages_; + other.pages_ = tempPages; + ArrayIndex tempSize = size_; + size_ = other.size_; + other.size_ = tempSize; + PageIndex tempPageCount = pageCount_; + pageCount_ = other.pageCount_; + other.pageCount_ = tempPageCount; +} + +void +ValueInternalArray::clear() +{ + ValueInternalArray dummy; + swap( dummy ); +} + + +void +ValueInternalArray::resize( ArrayIndex newSize ) +{ + if ( newSize == 0 ) + clear(); + else if ( newSize < size_ ) + { + IteratorState it; + IteratorState itEnd; + makeIterator( it, newSize ); + makeIterator( itEnd, size_ ); + for ( ; !equals(it,itEnd); increment(it) ) + { + Value *value = &dereference(it); + value->~Value(); + } + PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage; + PageIndex lastPageIndex = size_ / itemsPerPage; + for ( ; pageIndex < lastPageIndex; ++pageIndex ) + arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); + size_ = newSize; + } + else if ( newSize > size_ ) + resolveReference( newSize ); +} + + +void +ValueInternalArray::makeIndexValid( ArrayIndex index ) +{ + // Need to enlarge page index ? + if ( index >= pageCount_ * itemsPerPage ) + { + PageIndex minNewPages = (index + 1) / itemsPerPage; + arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); + JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); + } + + // Need to allocate new pages ? + ArrayIndex nextPageIndex = + (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage + : size_; + if ( nextPageIndex <= index ) + { + PageIndex pageIndex = nextPageIndex / itemsPerPage; + PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1; + for ( ; pageToAllocate-- > 0; ++pageIndex ) + pages_[pageIndex] = arrayAllocator()->allocateArrayPage(); + } + + // Initialize all new entries + IteratorState it; + IteratorState itEnd; + makeIterator( it, size_ ); + size_ = index + 1; + makeIterator( itEnd, size_ ); + for ( ; !equals(it,itEnd); increment(it) ) + { + Value *value = &dereference(it); + new (value) Value(); // Construct a default value using placement new + } +} + +Value & +ValueInternalArray::resolveReference( ArrayIndex index ) +{ + if ( index >= size_ ) + makeIndexValid( index ); + return pages_[index/itemsPerPage][index%itemsPerPage]; +} + +Value * +ValueInternalArray::find( ArrayIndex index ) const +{ + if ( index >= size_ ) + return 0; + return &(pages_[index/itemsPerPage][index%itemsPerPage]); +} + +ValueInternalArray::ArrayIndex +ValueInternalArray::size() const +{ + return size_; +} + +int +ValueInternalArray::distance( const IteratorState &x, const IteratorState &y ) +{ + return indexOf(y) - indexOf(x); +} + + +ValueInternalArray::ArrayIndex +ValueInternalArray::indexOf( const IteratorState &iterator ) +{ + if ( !iterator.array_ ) + return ArrayIndex(-1); + return ArrayIndex( + (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage + + iterator.currentItemIndex_ ); +} + + +int +ValueInternalArray::compare( const ValueInternalArray &other ) const +{ + int sizeDiff( size_ - other.size_ ); + if ( sizeDiff != 0 ) + return sizeDiff; + + for ( ArrayIndex index =0; index < size_; ++index ) + { + int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( + other.pages_[index/itemsPerPage][index%itemsPerPage] ); + if ( diff != 0 ) + return diff; + } + return 0; +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_internalmap.inl b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_internalmap.inl new file mode 100644 index 0000000..1977148 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_internalmap.inl @@ -0,0 +1,607 @@ +// included by json_value.cpp +// everything is within Json namespace + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueInternalMap +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) ); + * This optimization is used by the fast allocator. + */ +ValueInternalLink::ValueInternalLink() + : previous_( 0 ) + , next_( 0 ) +{ +} + +ValueInternalLink::~ValueInternalLink() +{ + for ( int index =0; index < itemPerLink; ++index ) + { + if ( !items_[index].isItemAvailable() ) + { + if ( !items_[index].isMemberNameStatic() ) + free( keys_[index] ); + } + else + break; + } +} + + + +ValueMapAllocator::~ValueMapAllocator() +{ +} + +#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +class DefaultValueMapAllocator : public ValueMapAllocator +{ +public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + return new ValueInternalMap(); + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + return new ValueInternalMap( other ); + } + + virtual void destructMap( ValueInternalMap *map ) + { + delete map; + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + return new ValueInternalLink(); + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + delete link; + } +}; +#else +/// @todo make this thread-safe (lock when accessign batch allocator) +class DefaultValueMapAllocator : public ValueMapAllocator +{ +public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + ValueInternalMap *map = mapsAllocator_.allocate(); + new (map) ValueInternalMap(); // placement new + return map; + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + ValueInternalMap *map = mapsAllocator_.allocate(); + new (map) ValueInternalMap( other ); // placement new + return map; + } + + virtual void destructMap( ValueInternalMap *map ) + { + if ( map ) + { + map->~ValueInternalMap(); + mapsAllocator_.release( map ); + } + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + ValueInternalLink *link = linksAllocator_.allocate(); + memset( link, 0, sizeof(ValueInternalLink) ); + return link; + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + link->~ValueInternalLink(); + linksAllocator_.release( link ); + } +private: + BatchAllocator mapsAllocator_; + BatchAllocator linksAllocator_; +}; +#endif + +static ValueMapAllocator *&mapAllocator() +{ + static DefaultValueMapAllocator defaultAllocator; + static ValueMapAllocator *mapAllocator = &defaultAllocator; + return mapAllocator; +} + +static struct DummyMapAllocatorInitializer { + DummyMapAllocatorInitializer() + { + mapAllocator(); // ensure mapAllocator() statics are initialized before main(). + } +} dummyMapAllocatorInitializer; + + + +// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. + +/* +use linked list hash map. +buckets array is a container. +linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124) +value have extra state: valid, available, deleted +*/ + + +ValueInternalMap::ValueInternalMap() + : buckets_( 0 ) + , tailLink_( 0 ) + , bucketsSize_( 0 ) + , itemCount_( 0 ) +{ +} + + +ValueInternalMap::ValueInternalMap( const ValueInternalMap &other ) + : buckets_( 0 ) + , tailLink_( 0 ) + , bucketsSize_( 0 ) + , itemCount_( 0 ) +{ + reserve( other.itemCount_ ); + IteratorState it; + IteratorState itEnd; + other.makeBeginIterator( it ); + other.makeEndIterator( itEnd ); + for ( ; !equals(it,itEnd); increment(it) ) + { + bool isStatic; + const char *memberName = key( it, isStatic ); + const Value &aValue = value( it ); + resolveReference(memberName, isStatic) = aValue; + } +} + + +ValueInternalMap & +ValueInternalMap::operator =( const ValueInternalMap &other ) +{ + ValueInternalMap dummy( other ); + swap( dummy ); + return *this; +} + + +ValueInternalMap::~ValueInternalMap() +{ + if ( buckets_ ) + { + for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex ) + { + ValueInternalLink *link = buckets_[bucketIndex].next_; + while ( link ) + { + ValueInternalLink *linkToRelease = link; + link = link->next_; + mapAllocator()->releaseMapLink( linkToRelease ); + } + } + mapAllocator()->releaseMapBuckets( buckets_ ); + } +} + + +void +ValueInternalMap::swap( ValueInternalMap &other ) +{ + ValueInternalLink *tempBuckets = buckets_; + buckets_ = other.buckets_; + other.buckets_ = tempBuckets; + ValueInternalLink *tempTailLink = tailLink_; + tailLink_ = other.tailLink_; + other.tailLink_ = tempTailLink; + BucketIndex tempBucketsSize = bucketsSize_; + bucketsSize_ = other.bucketsSize_; + other.bucketsSize_ = tempBucketsSize; + BucketIndex tempItemCount = itemCount_; + itemCount_ = other.itemCount_; + other.itemCount_ = tempItemCount; +} + + +void +ValueInternalMap::clear() +{ + ValueInternalMap dummy; + swap( dummy ); +} + + +ValueInternalMap::BucketIndex +ValueInternalMap::size() const +{ + return itemCount_; +} + +bool +ValueInternalMap::reserveDelta( BucketIndex growth ) +{ + return reserve( itemCount_ + growth ); +} + +bool +ValueInternalMap::reserve( BucketIndex newItemCount ) +{ + if ( !buckets_ && newItemCount > 0 ) + { + buckets_ = mapAllocator()->allocateMapBuckets( 1 ); + bucketsSize_ = 1; + tailLink_ = &buckets_[0]; + } +// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; + return true; +} + + +const Value * +ValueInternalMap::find( const char *key ) const +{ + if ( !bucketsSize_ ) + return 0; + HashKey hashedKey = hash( key ); + BucketIndex bucketIndex = hashedKey % bucketsSize_; + for ( const ValueInternalLink *current = &buckets_[bucketIndex]; + current != 0; + current = current->next_ ) + { + for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index ) + { + if ( current->items_[index].isItemAvailable() ) + return 0; + if ( strcmp( key, current->keys_[index] ) == 0 ) + return ¤t->items_[index]; + } + } + return 0; +} + + +Value * +ValueInternalMap::find( const char *key ) +{ + const ValueInternalMap *constThis = this; + return const_cast( constThis->find( key ) ); +} + + +Value & +ValueInternalMap::resolveReference( const char *key, + bool isStatic ) +{ + HashKey hashedKey = hash( key ); + if ( bucketsSize_ ) + { + BucketIndex bucketIndex = hashedKey % bucketsSize_; + ValueInternalLink **previous = 0; + BucketIndex index; + for ( ValueInternalLink *current = &buckets_[bucketIndex]; + current != 0; + previous = ¤t->next_, current = current->next_ ) + { + for ( index=0; index < ValueInternalLink::itemPerLink; ++index ) + { + if ( current->items_[index].isItemAvailable() ) + return setNewItem( key, isStatic, current, index ); + if ( strcmp( key, current->keys_[index] ) == 0 ) + return current->items_[index]; + } + } + } + + reserveDelta( 1 ); + return unsafeAdd( key, isStatic, hashedKey ); +} + + +void +ValueInternalMap::remove( const char *key ) +{ + HashKey hashedKey = hash( key ); + if ( !bucketsSize_ ) + return; + BucketIndex bucketIndex = hashedKey % bucketsSize_; + for ( ValueInternalLink *link = &buckets_[bucketIndex]; + link != 0; + link = link->next_ ) + { + BucketIndex index; + for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) + { + if ( link->items_[index].isItemAvailable() ) + return; + if ( strcmp( key, link->keys_[index] ) == 0 ) + { + doActualRemove( link, index, bucketIndex ); + return; + } + } + } +} + +void +ValueInternalMap::doActualRemove( ValueInternalLink *link, + BucketIndex index, + BucketIndex bucketIndex ) +{ + // find last item of the bucket and swap it with the 'removed' one. + // set removed items flags to 'available'. + // if last page only contains 'available' items, then desallocate it (it's empty) + ValueInternalLink *&lastLink = getLastLinkInBucket( index ); + BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 + for ( ; + lastItemIndex < ValueInternalLink::itemPerLink; + ++lastItemIndex ) // may be optimized with dicotomic search + { + if ( lastLink->items_[lastItemIndex].isItemAvailable() ) + break; + } + + BucketIndex lastUsedIndex = lastItemIndex - 1; + Value *valueToDelete = &link->items_[index]; + Value *valueToPreserve = &lastLink->items_[lastUsedIndex]; + if ( valueToDelete != valueToPreserve ) + valueToDelete->swap( *valueToPreserve ); + if ( lastUsedIndex == 0 ) // page is now empty + { // remove it from bucket linked list and delete it. + ValueInternalLink *linkPreviousToLast = lastLink->previous_; + if ( linkPreviousToLast != 0 ) // can not deleted bucket link. + { + mapAllocator()->releaseMapLink( lastLink ); + linkPreviousToLast->next_ = 0; + lastLink = linkPreviousToLast; + } + } + else + { + Value dummy; + valueToPreserve->swap( dummy ); // restore deleted to default Value. + valueToPreserve->setItemUsed( false ); + } + --itemCount_; +} + + +ValueInternalLink *& +ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex ) +{ + if ( bucketIndex == bucketsSize_ - 1 ) + return tailLink_; + ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_; + if ( !previous ) + previous = &buckets_[bucketIndex]; + return previous; +} + + +Value & +ValueInternalMap::setNewItem( const char *key, + bool isStatic, + ValueInternalLink *link, + BucketIndex index ) +{ + char *duplicatedKey = valueAllocator()->makeMemberName( key ); + ++itemCount_; + link->keys_[index] = duplicatedKey; + link->items_[index].setItemUsed(); + link->items_[index].setMemberNameIsStatic( isStatic ); + return link->items_[index]; // items already default constructed. +} + + +Value & +ValueInternalMap::unsafeAdd( const char *key, + bool isStatic, + HashKey hashedKey ) +{ + JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." ); + BucketIndex bucketIndex = hashedKey % bucketsSize_; + ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex ); + ValueInternalLink *link = previousLink; + BucketIndex index; + for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) + { + if ( link->items_[index].isItemAvailable() ) + break; + } + if ( index == ValueInternalLink::itemPerLink ) // need to add a new page + { + ValueInternalLink *newLink = mapAllocator()->allocateMapLink(); + index = 0; + link->next_ = newLink; + previousLink = newLink; + link = newLink; + } + return setNewItem( key, isStatic, link, index ); +} + + +ValueInternalMap::HashKey +ValueInternalMap::hash( const char *key ) const +{ + HashKey hash = 0; + while ( *key ) + hash += *key++ * 37; + return hash; +} + + +int +ValueInternalMap::compare( const ValueInternalMap &other ) const +{ + int sizeDiff( itemCount_ - other.itemCount_ ); + if ( sizeDiff != 0 ) + return sizeDiff; + // Strict order guaranty is required. Compare all keys FIRST, then compare values. + IteratorState it; + IteratorState itEnd; + makeBeginIterator( it ); + makeEndIterator( itEnd ); + for ( ; !equals(it,itEnd); increment(it) ) + { + if ( !other.find( key( it ) ) ) + return 1; + } + + // All keys are equals, let's compare values + makeBeginIterator( it ); + for ( ; !equals(it,itEnd); increment(it) ) + { + const Value *otherValue = other.find( key( it ) ); + int valueDiff = value(it).compare( *otherValue ); + if ( valueDiff != 0 ) + return valueDiff; + } + return 0; +} + + +void +ValueInternalMap::makeBeginIterator( IteratorState &it ) const +{ + it.map_ = const_cast( this ); + it.bucketIndex_ = 0; + it.itemIndex_ = 0; + it.link_ = buckets_; +} + + +void +ValueInternalMap::makeEndIterator( IteratorState &it ) const +{ + it.map_ = const_cast( this ); + it.bucketIndex_ = bucketsSize_; + it.itemIndex_ = 0; + it.link_ = 0; +} + + +bool +ValueInternalMap::equals( const IteratorState &x, const IteratorState &other ) +{ + return x.map_ == other.map_ + && x.bucketIndex_ == other.bucketIndex_ + && x.link_ == other.link_ + && x.itemIndex_ == other.itemIndex_; +} + + +void +ValueInternalMap::incrementBucket( IteratorState &iterator ) +{ + ++iterator.bucketIndex_; + JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_, + "ValueInternalMap::increment(): attempting to iterate beyond end." ); + if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ ) + iterator.link_ = 0; + else + iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]); + iterator.itemIndex_ = 0; +} + + +void +ValueInternalMap::increment( IteratorState &iterator ) +{ + JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." ); + ++iterator.itemIndex_; + if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink ) + { + JSON_ASSERT_MESSAGE( iterator.link_ != 0, + "ValueInternalMap::increment(): attempting to iterate beyond end." ); + iterator.link_ = iterator.link_->next_; + if ( iterator.link_ == 0 ) + incrementBucket( iterator ); + } + else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() ) + { + incrementBucket( iterator ); + } +} + + +void +ValueInternalMap::decrement( IteratorState &iterator ) +{ + if ( iterator.itemIndex_ == 0 ) + { + JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." ); + if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] ) + { + JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." ); + --(iterator.bucketIndex_); + } + iterator.link_ = iterator.link_->previous_; + iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1; + } +} + + +const char * +ValueInternalMap::key( const IteratorState &iterator ) +{ + JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); + return iterator.link_->keys_[iterator.itemIndex_]; +} + +const char * +ValueInternalMap::key( const IteratorState &iterator, bool &isStatic ) +{ + JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); + isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); + return iterator.link_->keys_[iterator.itemIndex_]; +} + + +Value & +ValueInternalMap::value( const IteratorState &iterator ) +{ + JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); + return iterator.link_->items_[iterator.itemIndex_]; +} + + +int +ValueInternalMap::distance( const IteratorState &x, const IteratorState &y ) +{ + int offset = 0; + IteratorState it = x; + while ( !equals( it, y ) ) + increment( it ); + return offset; +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_reader.cpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_reader.cpp new file mode 100644 index 0000000..5af16c8 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_reader.cpp @@ -0,0 +1,892 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#endif + +namespace Json { + +// QNX is strict about declaring C symbols in the std namespace. +#ifdef __QNXNTO__ +using std::memcpy; +using std::sprintf; +using std::sscanf; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_( true ) + , strictRoot_( false ) +{ +} + + +Features +Features::all() +{ + return Features(); +} + + +Features +Features::strictMode() +{ + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + + +static inline bool +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) +{ + return c == c1 || c == c2 || c == c3 || c == c4; +} + +static inline bool +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) +{ + return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; +} + + +static bool +containsNewLine( Reader::Location begin, + Reader::Location end ) +{ + for ( ;begin < end; ++begin ) + if ( *begin == '\n' || *begin == '\r' ) + return true; + return false; +} + +static std::string codePointToUTF8(unsigned int cp) +{ + std::string result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) + { + result.resize(1); + result[0] = static_cast(cp); + } + else if (cp <= 0x7FF) + { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } + else if (cp <= 0xFFFF) + { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); + result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); + } + else if (cp <= 0x10FFFF) + { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : features_( Features::all() ) +{ +} + + +Reader::Reader( const Features &features ) + : features_( features ) +{ +} + + +bool +Reader::parse( const std::string &document, + Value &root, + bool collectComments ) +{ + document_ = document; + const char *begin = document_.c_str(); + const char *end = begin + document_.length(); + return parse( begin, end, root, collectComments ); +} + + +bool +Reader::parse( std::istream& sin, + Value &root, + bool collectComments ) +{ + //std::istream_iterator begin(sin); + //std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since std::string is reference-counted, this at least does not + // create an extra copy. + std::string doc; + std::getline(sin, doc, (char)EOF); + return parse( doc, root, collectComments ); +} + +bool +Reader::parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments ) +{ + if ( !features_.allowComments_ ) + { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while ( !nodes_.empty() ) + nodes_.pop(); + nodes_.push( &root ); + + bool successful = readValue(); + Token token; + skipCommentTokens( token ); + if ( collectComments_ && !commentsBefore_.empty() ) + root.setComment( commentsBefore_, commentAfter ); + if ( features_.strictRoot_ ) + { + if ( !root.isArray() && !root.isObject() ) + { + // Set error location to start of doc, ideally should be first token found in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( "A valid JSON document must be either an array or an object value.", + token ); + return false; + } + } + return successful; +} + + +bool +Reader::readValue() +{ + Token token; + skipCommentTokens( token ); + bool successful = true; + + if ( collectComments_ && !commentsBefore_.empty() ) + { + currentValue().setComment( commentsBefore_, commentBefore ); + commentsBefore_ = ""; + } + + + switch ( token.type_ ) + { + case tokenObjectBegin: + successful = readObject( token ); + break; + case tokenArrayBegin: + successful = readArray( token ); + break; + case tokenNumber: + successful = decodeNumber( token ); + break; + case tokenString: + successful = decodeString( token ); + break; + case tokenTrue: + currentValue() = true; + break; + case tokenFalse: + currentValue() = false; + break; + case tokenNull: + currentValue() = Value(); + break; + default: + return addError( "Syntax error: value, object or array expected.", token ); + } + + if ( collectComments_ ) + { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + + +void +Reader::skipCommentTokens( Token &token ) +{ + if ( features_.allowComments_ ) + { + do + { + readToken( token ); + } + while ( token.type_ == tokenComment ); + } + else + { + readToken( token ); + } +} + + +bool +Reader::expectToken( TokenType type, Token &token, const char *message ) +{ + readToken( token ); + if ( token.type_ != type ) + return addError( message, token ); + return true; +} + + +bool +Reader::readToken( Token &token ) +{ + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch ( c ) + { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match( "rue", 3 ); + break; + case 'f': + token.type_ = tokenFalse; + ok = match( "alse", 4 ); + break; + case 'n': + token.type_ = tokenNull; + ok = match( "ull", 3 ); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if ( !ok ) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + + +void +Reader::skipSpaces() +{ + while ( current_ != end_ ) + { + Char c = *current_; + if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) + ++current_; + else + break; + } +} + + +bool +Reader::match( Location pattern, + int patternLength ) +{ + if ( end_ - current_ < patternLength ) + return false; + int index = patternLength; + while ( index-- ) + if ( current_[index] != pattern[index] ) + return false; + current_ += patternLength; + return true; +} + + +bool +Reader::readComment() +{ + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if ( c == '*' ) + successful = readCStyleComment(); + else if ( c == '/' ) + successful = readCppStyleComment(); + if ( !successful ) + return false; + + if ( collectComments_ ) + { + CommentPlacement placement = commentBefore; + if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) + { + if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) + placement = commentAfterOnSameLine; + } + + addComment( commentBegin, current_, placement ); + } + return true; +} + + +void +Reader::addComment( Location begin, + Location end, + CommentPlacement placement ) +{ + assert( collectComments_ ); + if ( placement == commentAfterOnSameLine ) + { + assert( lastValue_ != 0 ); + lastValue_->setComment( std::string( begin, end ), placement ); + } + else + { + if ( !commentsBefore_.empty() ) + commentsBefore_ += "\n"; + commentsBefore_ += std::string( begin, end ); + } +} + + +bool +Reader::readCStyleComment() +{ + while ( current_ != end_ ) + { + Char c = getNextChar(); + if ( c == '*' && *current_ == '/' ) + break; + } + return getNextChar() == '/'; +} + + +bool +Reader::readCppStyleComment() +{ + while ( current_ != end_ ) + { + Char c = getNextChar(); + if ( c == '\r' || c == '\n' ) + break; + } + return true; +} + + +void +Reader::readNumber() +{ + while ( current_ != end_ ) + { + if ( !(*current_ >= '0' && *current_ <= '9') && + !in( *current_, '.', 'e', 'E', '+', '-' ) ) + break; + ++current_; + } +} + +bool +Reader::readString() +{ + Char c = 0; + while ( current_ != end_ ) + { + c = getNextChar(); + if ( c == '\\' ) + getNextChar(); + else if ( c == '"' ) + break; + } + return c == '"'; +} + + +bool +Reader::readObject( Token &tokenStart ) +{ + Token tokenName; + std::string name; + currentValue() = Value( objectValue ); + while ( readToken( tokenName ) ) + { + bool initialTokenOk = true; + while ( tokenName.type_ == tokenComment && initialTokenOk ) + initialTokenOk = readToken( tokenName ); + if ( !initialTokenOk ) + break; + if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object + return true; + if ( tokenName.type_ != tokenString ) + break; + + name = ""; + if ( !decodeString( tokenName, name ) ) + return recoverFromError( tokenObjectEnd ); + + Token colon; + if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) + { + return addErrorAndRecover( "Missing ':' after object member name", + colon, + tokenObjectEnd ); + } + Value &value = currentValue()[ name ]; + nodes_.push( &value ); + bool ok = readValue(); + nodes_.pop(); + if ( !ok ) // error already set + return recoverFromError( tokenObjectEnd ); + + Token comma; + if ( !readToken( comma ) + || ( comma.type_ != tokenObjectEnd && + comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment ) ) + { + return addErrorAndRecover( "Missing ',' or '}' in object declaration", + comma, + tokenObjectEnd ); + } + bool finalizeTokenOk = true; + while ( comma.type_ == tokenComment && + finalizeTokenOk ) + finalizeTokenOk = readToken( comma ); + if ( comma.type_ == tokenObjectEnd ) + return true; + } + return addErrorAndRecover( "Missing '}' or object member name", + tokenName, + tokenObjectEnd ); +} + + +bool +Reader::readArray( Token &tokenStart ) +{ + currentValue() = Value( arrayValue ); + skipSpaces(); + if ( *current_ == ']' ) // empty array + { + Token endArray; + readToken( endArray ); + return true; + } + int index = 0; + while ( true ) + { + Value &value = currentValue()[ index++ ]; + nodes_.push( &value ); + bool ok = readValue(); + nodes_.pop(); + if ( !ok ) // error already set + return recoverFromError( tokenArrayEnd ); + + Token token; + // Accept Comment after last item in the array. + ok = readToken( token ); + while ( token.type_ == tokenComment && ok ) + { + ok = readToken( token ); + } + bool badTokenType = ( token.type_ == tokenArraySeparator && + token.type_ == tokenArrayEnd ); + if ( !ok || badTokenType ) + { + return addErrorAndRecover( "Missing ',' or ']' in array declaration", + token, + tokenArrayEnd ); + } + if ( token.type_ == tokenArrayEnd ) + break; + } + return true; +} + + +bool +Reader::decodeNumber( Token &token ) +{ + bool isDouble = false; + for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) + { + isDouble = isDouble + || in( *inspect, '.', 'e', 'E', '+' ) + || ( *inspect == '-' && inspect != token.start_ ); + } + if ( isDouble ) + return decodeDouble( token ); + Location current = token.start_; + bool isNegative = *current == '-'; + if ( isNegative ) + ++current; + Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) + : Value::maxUInt) / 10; + Value::UInt value = 0; + while ( current < token.end_ ) + { + Char c = *current++; + if ( c < '0' || c > '9' ) + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); + if ( value >= threshold ) + return decodeDouble( token ); + value = value * 10 + Value::UInt(c - '0'); + } + if ( isNegative ) + currentValue() = -Value::Int( value ); + else if ( value <= Value::UInt(Value::maxInt) ) + currentValue() = Value::Int( value ); + else + currentValue() = value; + return true; +} + + +bool +Reader::decodeDouble( Token &token ) +{ + double value = 0; + const int bufferSize = 32; + int count; + int length = int(token.end_ - token.start_); + if ( length <= bufferSize ) + { + Char buffer[bufferSize]; + memcpy( buffer, token.start_, length ); + buffer[length] = 0; + count = sscanf( buffer, "%lf", &value ); + } + else + { + std::string buffer( token.start_, token.end_ ); + count = sscanf( buffer.c_str(), "%lf", &value ); + } + + if ( count != 1 ) + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); + currentValue() = value; + return true; +} + + +bool +Reader::decodeString( Token &token ) +{ + std::string decoded; + if ( !decodeString( token, decoded ) ) + return false; + currentValue() = decoded; + return true; +} + + +bool +Reader::decodeString( Token &token, std::string &decoded ) +{ + decoded.reserve( token.end_ - token.start_ - 2 ); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while ( current != end ) + { + Char c = *current++; + if ( c == '"' ) + break; + else if ( c == '\\' ) + { + if ( current == end ) + return addError( "Empty escape sequence in string", token, current ); + Char escape = *current++; + switch ( escape ) + { + case '"': decoded += '"'; break; + case '/': decoded += '/'; break; + case '\\': decoded += '\\'; break; + case 'b': decoded += '\b'; break; + case 'f': decoded += '\f'; break; + case 'n': decoded += '\n'; break; + case 'r': decoded += '\r'; break; + case 't': decoded += '\t'; break; + case 'u': + { + unsigned int unicode; + if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) + return false; + decoded += codePointToUTF8(unicode); + } + break; + default: + return addError( "Bad escape sequence in string", token, current ); + } + } + else + { + decoded += c; + } + } + return true; +} + +bool +Reader::decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ) +{ + + if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) + { + // surrogate pairs + if (end - current < 6) + return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++)== 'u') + { + if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) + { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } + else + return false; + } + else + return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); + } + return true; +} + +bool +Reader::decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ) +{ + if ( end - current < 4 ) + return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); + unicode = 0; + for ( int index =0; index < 4; ++index ) + { + Char c = *current++; + unicode *= 16; + if ( c >= '0' && c <= '9' ) + unicode += c - '0'; + else if ( c >= 'a' && c <= 'f' ) + unicode += c - 'a' + 10; + else if ( c >= 'A' && c <= 'F' ) + unicode += c - 'A' + 10; + else + return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); + } + return true; +} + + +bool +Reader::addError( const std::string &message, + Token &token, + Location extra ) +{ + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back( info ); + return false; +} + + +bool +Reader::recoverFromError( TokenType skipUntilToken ) +{ + int errorCount = int(errors_.size()); + Token skip; + while ( true ) + { + if ( !readToken(skip) ) + errors_.resize( errorCount ); // discard errors caused by recovery + if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) + break; + } + errors_.resize( errorCount ); + return false; +} + + +bool +Reader::addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ) +{ + addError( message, token ); + return recoverFromError( skipUntilToken ); +} + + +Value & +Reader::currentValue() +{ + return *(nodes_.top()); +} + + +Reader::Char +Reader::getNextChar() +{ + if ( current_ == end_ ) + return 0; + return *current_++; +} + + +void +Reader::getLocationLineAndColumn( Location location, + int &line, + int &column ) const +{ + Location current = begin_; + Location lastLineStart = current; + line = 0; + while ( current < location && current != end_ ) + { + Char c = *current++; + if ( c == '\r' ) + { + if ( *current == '\n' ) + ++current; + lastLineStart = current; + ++line; + } + else if ( c == '\n' ) + { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + + +std::string +Reader::getLocationLineAndColumn( Location location ) const +{ + int line, column; + getLocationLineAndColumn( location, line, column ); + char buffer[18+16+16+1]; + sprintf( buffer, "Line %d, Column %d", line, column ); + return buffer; +} + + +std::string +Reader::getFormatedErrorMessages() const +{ + std::string formattedMessage; + for ( Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError ) + { + const ErrorInfo &error = *itError; + formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if ( error.extra_ ) + formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; + } + return formattedMessage; +} + + +std::istream& operator>>( std::istream &sin, Value &root ) +{ + Json::Reader reader; + bool ok = reader.parse(sin, root, true); + //JSON_ASSERT( ok ); + if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); + return sin; +} + + +} // namespace Json diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_value.cpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_value.cpp new file mode 100644 index 0000000..6e5dcd3 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_value.cpp @@ -0,0 +1,1726 @@ +#include +#include +#include +#include +#include +#include +#include +#ifdef JSON_USE_CPPTL +# include +#endif +#include // size_t +#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +# include "json_batchallocator.h" +#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR + +#define JSON_ASSERT_UNREACHABLE assert( false ) +#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw +#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message ); + +namespace Json { + +// QNX is strict about declaring C symbols in the std namespace. +#ifdef __QNXNTO__ +using std::memcpy; +using std::strchr; +using std::strcmp; +using std::strlen; +#endif + +const Value Value::null; +const Int Value::minInt = Int( ~(UInt(-1)/2) ); +const Int Value::maxInt = Int( UInt(-1)/2 ); +const UInt Value::maxUInt = UInt(-1); + +// A "safe" implementation of strdup. Allow null pointer to be passed. +// Also avoid warning on msvc80. +// +//inline char *safeStringDup( const char *czstring ) +//{ +// if ( czstring ) +// { +// const size_t length = (unsigned int)( strlen(czstring) + 1 ); +// char *newString = static_cast( malloc( length ) ); +// memcpy( newString, czstring, length ); +// return newString; +// } +// return 0; +//} +// +//inline char *safeStringDup( const std::string &str ) +//{ +// if ( !str.empty() ) +// { +// const size_t length = str.length(); +// char *newString = static_cast( malloc( length + 1 ) ); +// memcpy( newString, str.c_str(), length ); +// newString[length] = 0; +// return newString; +// } +// return 0; +//} + +ValueAllocator::~ValueAllocator() +{ +} + +class DefaultValueAllocator : public ValueAllocator +{ +public: + virtual ~DefaultValueAllocator() + { + } + + virtual char *makeMemberName( const char *memberName ) + { + return duplicateStringValue( memberName ); + } + + virtual void releaseMemberName( char *memberName ) + { + releaseStringValue( memberName ); + } + + virtual char *duplicateStringValue( const char *value, + unsigned int length = unknown ) + { + //@todo invesgate this old optimization + //if ( !value || value[0] == 0 ) + // return 0; + + if ( length == unknown ) + length = (unsigned int)strlen(value); + char *newString = static_cast( malloc( length + 1 ) ); + memcpy( newString, value, length ); + newString[length] = 0; + return newString; + } + + virtual void releaseStringValue( char *value ) + { + if ( value ) + free( value ); + } +}; + +static ValueAllocator *&valueAllocator() +{ + static DefaultValueAllocator defaultAllocator; + static ValueAllocator *valueAllocator = &defaultAllocator; + return valueAllocator; +} + +static struct DummyValueAllocatorInitializer { + DummyValueAllocatorInitializer() + { + valueAllocator(); // ensure valueAllocator() statics are initialized before main(). + } +} dummyValueAllocatorInitializer; + + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#ifdef JSON_VALUE_USE_INTERNAL_MAP +# include "json_internalarray.inl" +# include "json_internalmap.inl" +#endif // JSON_VALUE_USE_INTERNAL_MAP + +# include "json_valueiterator.inl" + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + + +Value::CommentInfo::CommentInfo() + : comment_( 0 ) +{ +} + +Value::CommentInfo::~CommentInfo() +{ + if ( comment_ ) + valueAllocator()->releaseStringValue( comment_ ); +} + + +void +Value::CommentInfo::setComment( const char *text ) +{ + if ( comment_ ) + valueAllocator()->releaseStringValue( comment_ ); + JSON_ASSERT( text ); + JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = valueAllocator()->duplicateStringValue( text ); +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +# ifndef JSON_VALUE_USE_INTERNAL_MAP + +// Notes: index_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString( int index ) + : cstr_( 0 ) + , index_( index ) +{ +} + +Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) + : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) + : cstr ) + , index_( allocate ) +{ +} + +Value::CZString::CZString( const CZString &other ) +: cstr_( other.index_ != noDuplication && other.cstr_ != 0 + ? valueAllocator()->makeMemberName( other.cstr_ ) + : other.cstr_ ) + , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) + : other.index_ ) +{ +} + +Value::CZString::~CZString() +{ + if ( cstr_ && index_ == duplicate ) + valueAllocator()->releaseMemberName( const_cast( cstr_ ) ); +} + +void +Value::CZString::swap( CZString &other ) +{ + std::swap( cstr_, other.cstr_ ); + std::swap( index_, other.index_ ); +} + +Value::CZString & +Value::CZString::operator =( const CZString &other ) +{ + CZString temp( other ); + swap( temp ); + return *this; +} + +bool +Value::CZString::operator<( const CZString &other ) const +{ + if ( cstr_ ) + return strcmp( cstr_, other.cstr_ ) < 0; + return index_ < other.index_; +} + +bool +Value::CZString::operator==( const CZString &other ) const +{ + if ( cstr_ ) + return strcmp( cstr_, other.cstr_ ) == 0; + return index_ == other.index_; +} + + +int +Value::CZString::index() const +{ + return index_; +} + + +const char * +Value::CZString::c_str() const +{ + return cstr_; +} + +bool +Value::CZString::isStaticString() const +{ + return index_ == noDuplication; +} + +#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value( ValueType type ) + : type_( type ) + , allocated_( 0 ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + switch ( type ) + { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + value_.string_ = 0; + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; +#else + case arrayValue: + value_.array_ = arrayAllocator()->newArray(); + break; + case objectValue: + value_.map_ = mapAllocator()->newMap(); + break; +#endif + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + + +Value::Value( Int value ) + : type_( intValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.int_ = value; +} + + +Value::Value( UInt value ) + : type_( uintValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.uint_ = value; +} + +Value::Value( double value ) + : type_( realValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.real_ = value; +} + +Value::Value( const char *value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( value ); +} + + +Value::Value( const char *beginValue, + const char *endValue ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( beginValue, + UInt(endValue - beginValue) ); +} + + +Value::Value( const std::string &value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), + (unsigned int)value.length() ); + +} + +Value::Value( const StaticString &value ) + : type_( stringValue ) + , allocated_( false ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = const_cast( value.c_str() ); +} + + +# ifdef JSON_USE_CPPTL +Value::Value( const CppTL::ConstString &value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() ); +} +# endif + +Value::Value( bool value ) + : type_( booleanValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.bool_ = value; +} + + +Value::Value( const Value &other ) + : type_( other.type_ ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if ( other.value_.string_ ) + { + value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ ); + allocated_ = true; + } + else + value_.string_ = 0; + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues( *other.value_.map_ ); + break; +#else + case arrayValue: + value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); + break; + case objectValue: + value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); + break; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + if ( other.comments_ ) + { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) + { + const CommentInfo &otherComment = other.comments_[comment]; + if ( otherComment.comment_ ) + comments_[comment].setComment( otherComment.comment_ ); + } + } +} + + +Value::~Value() +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if ( allocated_ ) + valueAllocator()->releaseStringValue( value_.string_ ); + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + delete value_.map_; + break; +#else + case arrayValue: + arrayAllocator()->destructArray( value_.array_ ); + break; + case objectValue: + mapAllocator()->destructMap( value_.map_ ); + break; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + + if ( comments_ ) + delete[] comments_; +} + +Value & +Value::operator=( const Value &other ) +{ + Value temp( other ); + swap( temp ); + return *this; +} + +void +Value::swap( Value &other ) +{ + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap( value_, other.value_ ); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2; +} + +ValueType +Value::type() const +{ + return type_; +} + + +int +Value::compare( const Value &other ) +{ + /* + int typeDelta = other.type_ - type_; + switch ( type_ ) + { + case nullValue: + + return other.type_ == type_; + case intValue: + if ( other.type_.isNumeric() + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue, + break; + case arrayValue: + delete value_.array_; + break; + case objectValue: + delete value_.map_; + default: + JSON_ASSERT_UNREACHABLE; + } + */ + return 0; // unreachable +} + +bool +Value::operator <( const Value &other ) const +{ + int typeDelta = type_ - other.type_; + if ( typeDelta ) + return typeDelta < 0 ? true : false; + switch ( type_ ) + { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: + return ( value_.string_ == 0 && other.value_.string_ ) + || ( other.value_.string_ + && value_.string_ + && strcmp( value_.string_, other.value_.string_ ) < 0 ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + { + int delta = int( value_.map_->size() - other.value_.map_->size() ); + if ( delta ) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } +#else + case arrayValue: + return value_.array_->compare( *(other.value_.array_) ) < 0; + case objectValue: + return value_.map_->compare( *(other.value_.map_) ) < 0; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable +} + +bool +Value::operator <=( const Value &other ) const +{ + return !(other > *this); +} + +bool +Value::operator >=( const Value &other ) const +{ + return !(*this < other); +} + +bool +Value::operator >( const Value &other ) const +{ + return other < *this; +} + +bool +Value::operator ==( const Value &other ) const +{ + //if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if ( type_ != temp ) + return false; + switch ( type_ ) + { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: + return ( value_.string_ == other.value_.string_ ) + || ( other.value_.string_ + && value_.string_ + && strcmp( value_.string_, other.value_.string_ ) == 0 ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() + && (*value_.map_) == (*other.value_.map_); +#else + case arrayValue: + return value_.array_->compare( *(other.value_.array_) ) == 0; + case objectValue: + return value_.map_->compare( *(other.value_.map_) ) == 0; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable +} + +bool +Value::operator !=( const Value &other ) const +{ + return !( *this == other ); +} + +const char * +Value::asCString() const +{ + JSON_ASSERT( type_ == stringValue ); + return value_.string_; +} + + +std::string +Value::asString() const +{ + switch ( type_ ) + { + case nullValue: + return ""; + case stringValue: + return value_.string_ ? value_.string_ : ""; + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + case uintValue: + case realValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return ""; // unreachable +} + +# ifdef JSON_USE_CPPTL +CppTL::ConstString +Value::asConstString() const +{ + return CppTL::ConstString( asString().c_str() ); +} +# endif + +Value::Int +Value::asInt() const +{ + switch ( type_ ) + { + case nullValue: + return 0; + case intValue: + return value_.int_; + case uintValue: + JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); + return Int( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +Value::UInt +Value::asUInt() const +{ + switch ( type_ ) + { + case nullValue: + return 0; + case intValue: + JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); + return value_.int_; + case uintValue: + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); + return UInt( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +double +Value::asDouble() const +{ + switch ( type_ ) + { + case nullValue: + return 0.0; + case intValue: + return value_.int_; + case uintValue: + return value_.uint_; + case realValue: + return value_.real_; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +bool +Value::asBool() const +{ + switch ( type_ ) + { + case nullValue: + return false; + case intValue: + case uintValue: + return value_.int_ != 0; + case realValue: + return value_.real_ != 0.0; + case booleanValue: + return value_.bool_; + case stringValue: + return value_.string_ && value_.string_[0] != 0; + case arrayValue: + case objectValue: + return value_.map_->size() != 0; + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + + +bool +Value::isConvertibleTo( ValueType other ) const +{ + switch ( type_ ) + { + case nullValue: + return true; + case intValue: + return ( other == nullValue && value_.int_ == 0 ) + || other == intValue + || ( other == uintValue && value_.int_ >= 0 ) + || other == realValue + || other == stringValue + || other == booleanValue; + case uintValue: + return ( other == nullValue && value_.uint_ == 0 ) + || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) + || other == uintValue + || other == realValue + || other == stringValue + || other == booleanValue; + case realValue: + return ( other == nullValue && value_.real_ == 0.0 ) + || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) + || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) + || other == realValue + || other == stringValue + || other == booleanValue; + case booleanValue: + return ( other == nullValue && value_.bool_ == false ) + || other == intValue + || other == uintValue + || other == realValue + || other == stringValue + || other == booleanValue; + case stringValue: + return other == stringValue + || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); + case arrayValue: + return other == arrayValue + || ( other == nullValue && value_.map_->size() == 0 ); + case objectValue: + return other == objectValue + || ( other == nullValue && value_.map_->size() == 0 ); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + + +/// Number of values in array or object +Value::UInt +Value::size() const +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: // size of the array is highest index + 1 + if ( !value_.map_->empty() ) + { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index()+1; + } + return 0; + case objectValue: + return Int( value_.map_->size() ); +#else + case arrayValue: + return Int( value_.array_->size() ); + case objectValue: + return Int( value_.map_->size() ); +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +bool +Value::empty() const +{ + if ( isNull() || isArray() || isObject() ) + return size() == 0u; + else + return false; +} + + +bool +Value::operator!() const +{ + return isNull(); +} + + +void +Value::clear() +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); + + switch ( type_ ) + { +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_->clear(); + break; +#else + case arrayValue: + value_.array_->clear(); + break; + case objectValue: + value_.map_->clear(); + break; +#endif + default: + break; + } +} + +void +Value::resize( UInt newSize ) +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + *this = Value( arrayValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + UInt oldSize = size(); + if ( newSize == 0 ) + clear(); + else if ( newSize > oldSize ) + (*this)[ newSize - 1 ]; + else + { + for ( UInt index = newSize; index < oldSize; ++index ) + value_.map_->erase( index ); + assert( size() == newSize ); + } +#else + value_.array_->resize( newSize ); +#endif +} + + +Value & +Value::operator[]( UInt index ) +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + *this = Value( arrayValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString key( index ); + ObjectValues::iterator it = value_.map_->lower_bound( key ); + if ( it != value_.map_->end() && (*it).first == key ) + return (*it).second; + + ObjectValues::value_type defaultValue( key, null ); + it = value_.map_->insert( it, defaultValue ); + return (*it).second; +#else + return value_.array_->resolveReference( index ); +#endif +} + + +const Value & +Value::operator[]( UInt index ) const +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString key( index ); + ObjectValues::const_iterator it = value_.map_->find( key ); + if ( it == value_.map_->end() ) + return null; + return (*it).second; +#else + Value *value = value_.array_->find( index ); + return value ? *value : null; +#endif +} + + +Value & +Value::operator[]( const char *key ) +{ + return resolveReference( key, false ); +} + + +Value & +Value::resolveReference( const char *key, + bool isStatic ) +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + *this = Value( objectValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, isStatic ? CZString::noDuplication + : CZString::duplicateOnCopy ); + ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); + if ( it != value_.map_->end() && (*it).first == actualKey ) + return (*it).second; + + ObjectValues::value_type defaultValue( actualKey, null ); + it = value_.map_->insert( it, defaultValue ); + Value &value = (*it).second; + return value; +#else + return value_.map_->resolveReference( key, isStatic ); +#endif +} + + +Value +Value::get( UInt index, + const Value &defaultValue ) const +{ + const Value *value = &((*this)[index]); + return value == &null ? defaultValue : *value; +} + + +bool +Value::isValidIndex( UInt index ) const +{ + return index < size(); +} + + + +const Value & +Value::operator[]( const char *key ) const +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, CZString::noDuplication ); + ObjectValues::const_iterator it = value_.map_->find( actualKey ); + if ( it == value_.map_->end() ) + return null; + return (*it).second; +#else + const Value *value = value_.map_->find( key ); + return value ? *value : null; +#endif +} + + +Value & +Value::operator[]( const std::string &key ) +{ + return (*this)[ key.c_str() ]; +} + + +const Value & +Value::operator[]( const std::string &key ) const +{ + return (*this)[ key.c_str() ]; +} + +Value & +Value::operator[]( const StaticString &key ) +{ + return resolveReference( key, true ); +} + + +# ifdef JSON_USE_CPPTL +Value & +Value::operator[]( const CppTL::ConstString &key ) +{ + return (*this)[ key.c_str() ]; +} + + +const Value & +Value::operator[]( const CppTL::ConstString &key ) const +{ + return (*this)[ key.c_str() ]; +} +# endif + + +Value & +Value::append( const Value &value ) +{ + return (*this)[size()] = value; +} + + +Value +Value::get( const char *key, + const Value &defaultValue ) const +{ + const Value *value = &((*this)[key]); + return value == &null ? defaultValue : *value; +} + + +Value +Value::get( const std::string &key, + const Value &defaultValue ) const +{ + return get( key.c_str(), defaultValue ); +} + +Value +Value::removeMember( const char* key ) +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, CZString::noDuplication ); + ObjectValues::iterator it = value_.map_->find( actualKey ); + if ( it == value_.map_->end() ) + return null; + Value old(it->second); + value_.map_->erase(it); + return old; +#else + Value *value = value_.map_->find( key ); + if (value){ + Value old(*value); + value_.map_.remove( key ); + return old; + } else { + return null; + } +#endif +} + +Value +Value::removeMember( const std::string &key ) +{ + return removeMember( key.c_str() ); +} + +# ifdef JSON_USE_CPPTL +Value +Value::get( const CppTL::ConstString &key, + const Value &defaultValue ) const +{ + return get( key.c_str(), defaultValue ); +} +# endif + +bool +Value::isMember( const char *key ) const +{ + const Value *value = &((*this)[key]); + return value != &null; +} + + +bool +Value::isMember( const std::string &key ) const +{ + return isMember( key.c_str() ); +} + + +# ifdef JSON_USE_CPPTL +bool +Value::isMember( const CppTL::ConstString &key ) const +{ + return isMember( key.c_str() ); +} +#endif + +Value::Members +Value::getMemberNames() const +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return Value::Members(); + Members members; + members.reserve( value_.map_->size() ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for ( ; it != itEnd; ++it ) + members.push_back( std::string( (*it).first.c_str() ) ); +#else + ValueInternalMap::IteratorState it; + ValueInternalMap::IteratorState itEnd; + value_.map_->makeBeginIterator( it ); + value_.map_->makeEndIterator( itEnd ); + for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) + members.push_back( std::string( ValueInternalMap::key( it ) ) ); +#endif + return members; +} +// +//# ifdef JSON_USE_CPPTL +//EnumMemberNames +//Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +//EnumValues +//Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type() ); +// return EnumValues(); +//} +// +//# endif + + +bool +Value::isNull() const +{ + return type_ == nullValue; +} + + +bool +Value::isBool() const +{ + return type_ == booleanValue; +} + + +bool +Value::isInt() const +{ + return type_ == intValue; +} + + +bool +Value::isUInt() const +{ + return type_ == uintValue; +} + + +bool +Value::isIntegral() const +{ + return type_ == intValue + || type_ == uintValue + || type_ == booleanValue; +} + + +bool +Value::isDouble() const +{ + return type_ == realValue; +} + + +bool +Value::isNumeric() const +{ + return isIntegral() || isDouble(); +} + + +bool +Value::isString() const +{ + return type_ == stringValue; +} + + +bool +Value::isArray() const +{ + return type_ == nullValue || type_ == arrayValue; +} + + +bool +Value::isObject() const +{ + return type_ == nullValue || type_ == objectValue; +} + + +void +Value::setComment( const char *comment, + CommentPlacement placement ) +{ + if ( !comments_ ) + comments_ = new CommentInfo[numberOfCommentPlacement]; + comments_[placement].setComment( comment ); +} + + +void +Value::setComment( const std::string &comment, + CommentPlacement placement ) +{ + setComment( comment.c_str(), placement ); +} + + +bool +Value::hasComment( CommentPlacement placement ) const +{ + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +std::string +Value::getComment( CommentPlacement placement ) const +{ + if ( hasComment(placement) ) + return comments_[placement].comment_; + return ""; +} + + +std::string +Value::toStyledString() const +{ + StyledWriter writer; + return writer.write( *this ); +} + + +Value::const_iterator +Value::begin() const +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator( it ); + return const_iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator( it ); + return const_iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return const_iterator( value_.map_->begin() ); + break; +#endif + default: + break; + } + return const_iterator(); +} + +Value::const_iterator +Value::end() const +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator( it ); + return const_iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator( it ); + return const_iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return const_iterator( value_.map_->end() ); + break; +#endif + default: + break; + } + return const_iterator(); +} + + +Value::iterator +Value::begin() +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator( it ); + return iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator( it ); + return iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return iterator( value_.map_->begin() ); + break; +#endif + default: + break; + } + return iterator(); +} + +Value::iterator +Value::end() +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator( it ); + return iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator( it ); + return iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return iterator( value_.map_->end() ); + break; +#endif + default: + break; + } + return iterator(); +} + + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() + : kind_( kindNone ) +{ +} + + +PathArgument::PathArgument( Value::UInt index ) + : index_( index ) + , kind_( kindIndex ) +{ +} + + +PathArgument::PathArgument( const char *key ) + : key_( key ) + , kind_( kindKey ) +{ +} + + +PathArgument::PathArgument( const std::string &key ) + : key_( key.c_str() ) + , kind_( kindKey ) +{ +} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path( const std::string &path, + const PathArgument &a1, + const PathArgument &a2, + const PathArgument &a3, + const PathArgument &a4, + const PathArgument &a5 ) +{ + InArgs in; + in.push_back( &a1 ); + in.push_back( &a2 ); + in.push_back( &a3 ); + in.push_back( &a4 ); + in.push_back( &a5 ); + makePath( path, in ); +} + + +void +Path::makePath( const std::string &path, + const InArgs &in ) +{ + const char *current = path.c_str(); + const char *end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while ( current != end ) + { + if ( *current == '[' ) + { + ++current; + if ( *current == '%' ) + addPathInArg( path, in, itInArg, PathArgument::kindIndex ); + else + { + Value::UInt index = 0; + for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) + index = index * 10 + Value::UInt(*current - '0'); + args_.push_back( index ); + } + if ( current == end || *current++ != ']' ) + invalidPath( path, int(current - path.c_str()) ); + } + else if ( *current == '%' ) + { + addPathInArg( path, in, itInArg, PathArgument::kindKey ); + ++current; + } + else if ( *current == '.' ) + { + ++current; + } + else + { + const char *beginName = current; + while ( current != end && !strchr( "[.", *current ) ) + ++current; + args_.push_back( std::string( beginName, current ) ); + } + } +} + + +void +Path::addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ) +{ + if ( itInArg == in.end() ) + { + // Error: missing argument %d + } + else if ( (*itInArg)->kind_ != kind ) + { + // Error: bad argument type + } + else + { + args_.push_back( **itInArg ); + } +} + + +void +Path::invalidPath( const std::string &path, + int location ) +{ + // Error: invalid path. +} + + +const Value & +Path::resolve( const Value &root ) const +{ + const Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) + { + // Error: unable to resolve path (array value expected at position... + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + { + // Error: unable to resolve path (object value expected at position...) + } + node = &((*node)[arg.key_]); + if ( node == &Value::null ) + { + // Error: unable to resolve path (object has no member named '' at position...) + } + } + } + return *node; +} + + +Value +Path::resolve( const Value &root, + const Value &defaultValue ) const +{ + const Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) + return defaultValue; + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + return defaultValue; + node = &((*node)[arg.key_]); + if ( node == &Value::null ) + return defaultValue; + } + } + return *node; +} + + +Value & +Path::make( Value &root ) const +{ + Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() ) + { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + + +} // namespace Json diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_valueiterator.inl b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_valueiterator.inl new file mode 100644 index 0000000..736e260 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_valueiterator.inl @@ -0,0 +1,292 @@ +// included by json_value.cpp +// everything is within Json namespace + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() +#ifndef JSON_VALUE_USE_INTERNAL_MAP + : current_() + , isNull_( true ) +{ +} +#else + : isArray_( true ) + , isNull_( true ) +{ + iterator_.array_ = ValueInternalArray::IteratorState(); +} +#endif + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) + : current_( current ) + , isNull_( false ) +{ +} +#else +ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) + : isArray_( true ) +{ + iterator_.array_ = state; +} + + +ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) + : isArray_( false ) +{ + iterator_.map_ = state; +} +#endif + +Value & +ValueIteratorBase::deref() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + return current_->second; +#else + if ( isArray_ ) + return ValueInternalArray::dereference( iterator_.array_ ); + return ValueInternalMap::value( iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::increment() +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ++current_; +#else + if ( isArray_ ) + ValueInternalArray::increment( iterator_.array_ ); + ValueInternalMap::increment( iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::decrement() +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + --current_; +#else + if ( isArray_ ) + ValueInternalArray::decrement( iterator_.array_ ); + ValueInternalMap::decrement( iterator_.map_ ); +#endif +} + + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance( const SelfType &other ) const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP +# ifdef JSON_USE_CPPTL_SMALLMAP + return current_ - other.current_; +# else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if ( isNull_ && other.isNull_ ) + { + return 0; + } + + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) + { + ++myDistance; + } + return myDistance; +# endif +#else + if ( isArray_ ) + return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); + return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); +#endif +} + + +bool +ValueIteratorBase::isEqual( const SelfType &other ) const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + if ( isNull_ ) + { + return other.isNull_; + } + return current_ == other.current_; +#else + if ( isArray_ ) + return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); + return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::copy( const SelfType &other ) +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + current_ = other.current_; +#else + if ( isArray_ ) + iterator_.array_ = other.iterator_.array_; + iterator_.map_ = other.iterator_.map_; +#endif +} + + +Value +ValueIteratorBase::key() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const Value::CZString czstring = (*current_).first; + if ( czstring.c_str() ) + { + if ( czstring.isStaticString() ) + return Value( StaticString( czstring.c_str() ) ); + return Value( czstring.c_str() ); + } + return Value( czstring.index() ); +#else + if ( isArray_ ) + return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); + bool isStatic; + const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); + if ( isStatic ) + return Value( StaticString( memberName ) ); + return Value( memberName ); +#endif +} + + +UInt +ValueIteratorBase::index() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const Value::CZString czstring = (*current_).first; + if ( !czstring.c_str() ) + return czstring.index(); + return Value::UInt( -1 ); +#else + if ( isArray_ ) + return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); + return Value::UInt( -1 ); +#endif +} + + +const char * +ValueIteratorBase::memberName() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const char *name = (*current_).first.c_str(); + return name ? name : ""; +#else + if ( !isArray_ ) + return ValueInternalMap::key( iterator_.map_ ); + return ""; +#endif +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() +{ +} + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) + : ValueIteratorBase( current ) +{ +} +#else +ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} + +ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} +#endif + +ValueConstIterator & +ValueConstIterator::operator =( const ValueIteratorBase &other ) +{ + copy( other ); + return *this; +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() +{ +} + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) + : ValueIteratorBase( current ) +{ +} +#else +ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} + +ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} +#endif + +ValueIterator::ValueIterator( const ValueConstIterator &other ) + : ValueIteratorBase( other ) +{ +} + +ValueIterator::ValueIterator( const ValueIterator &other ) + : ValueIteratorBase( other ) +{ +} + +ValueIterator & +ValueIterator::operator =( const SelfType &other ) +{ + copy( other ); + return *this; +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_writer.cpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_writer.cpp new file mode 100644 index 0000000..cdf4188 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_writer.cpp @@ -0,0 +1,829 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#endif + +namespace Json { + +static bool isControlCharacter(char ch) +{ + return ch > 0 && ch <= 0x1F; +} + +static bool containsControlCharacter( const char* str ) +{ + while ( *str ) + { + if ( isControlCharacter( *(str++) ) ) + return true; + } + return false; +} +static void uintToString( unsigned int value, + char *¤t ) +{ + *--current = 0; + do + { + *--current = (value % 10) + '0'; + value /= 10; + } + while ( value != 0 ); +} + +std::string valueToString( Int value ) +{ + char buffer[32]; + char *current = buffer + sizeof(buffer); + bool isNegative = value < 0; + if ( isNegative ) + value = -value; + uintToString( UInt(value), current ); + if ( isNegative ) + *--current = '-'; + assert( current >= buffer ); + return current; +} + + +std::string valueToString( UInt value ) +{ + char buffer[32]; + char *current = buffer + sizeof(buffer); + uintToString( value, current ); + assert( current >= buffer ); + return current; +} + +std::string valueToString( double value ) +{ + char buffer[32]; +#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. + sprintf_s(buffer, sizeof(buffer), "%#.16g", value); +#else + sprintf(buffer, "%#.16g", value); +#endif + char* ch = buffer + strlen(buffer) - 1; + if (*ch != '0') return buffer; // nothing to truncate, so save time + while(ch > buffer && *ch == '0'){ + --ch; + } + char* last_nonzero = ch; + while(ch >= buffer){ + switch(*ch){ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + --ch; + continue; + case '.': + // Truncate zeroes to save bytes in output, but keep one. + *(last_nonzero+2) = '\0'; + return buffer; + default: + return buffer; + } + } + return buffer; +} + + +std::string valueToString( bool value ) +{ + return value ? "true" : "false"; +} + +std::string valueToQuotedString( const char *value ) +{ + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) + return std::string("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to std::string is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c=value; *c != 0; ++c) + { + switch(*c) + { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + //case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something. + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } + else + { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() +{ +} + + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_( false ) +{ +} + + +void +FastWriter::enableYAMLCompatibility() +{ + yamlCompatiblityEnabled_ = true; +} + + +std::string +FastWriter::write( const Value &root ) +{ + document_ = ""; + writeValue( root ); + document_ += "\n"; + return document_; +} + + +void +FastWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + document_ += "null"; + break; + case intValue: + document_ += valueToString( value.asInt() ); + break; + case uintValue: + document_ += valueToString( value.asUInt() ); + break; + case realValue: + document_ += valueToString( value.asDouble() ); + break; + case stringValue: + document_ += valueToQuotedString( value.asCString() ); + break; + case booleanValue: + document_ += valueToString( value.asBool() ); + break; + case arrayValue: + { + document_ += "["; + int size = value.size(); + for ( int index =0; index < size; ++index ) + { + if ( index > 0 ) + document_ += ","; + writeValue( value[index] ); + } + document_ += "]"; + } + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + document_ += "{"; + for ( Value::Members::iterator it = members.begin(); + it != members.end(); + ++it ) + { + const std::string &name = *it; + if ( it != members.begin() ) + document_ += ","; + document_ += valueToQuotedString( name.c_str() ); + document_ += yamlCompatiblityEnabled_ ? ": " + : ":"; + writeValue( value[name] ); + } + document_ += "}"; + } + break; + } +} + + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_( 74 ) + , indentSize_( 3 ) +{ +} + + +std::string +StyledWriter::write( const Value &root ) +{ + document_ = ""; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue( root ); + writeValue( root ); + writeCommentAfterValueOnSameLine( root ); + document_ += "\n"; + return document_; +} + + +void +StyledWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + pushValue( "null" ); + break; + case intValue: + pushValue( valueToString( value.asInt() ) ); + break; + case uintValue: + pushValue( valueToString( value.asUInt() ) ); + break; + case realValue: + pushValue( valueToString( value.asDouble() ) ); + break; + case stringValue: + pushValue( valueToQuotedString( value.asCString() ) ); + break; + case booleanValue: + pushValue( valueToString( value.asBool() ) ); + break; + case arrayValue: + writeArrayValue( value); + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + if ( members.empty() ) + pushValue( "{}" ); + else + { + writeWithIndent( "{" ); + indent(); + Value::Members::iterator it = members.begin(); + while ( true ) + { + const std::string &name = *it; + const Value &childValue = value[name]; + writeCommentBeforeValue( childValue ); + writeWithIndent( valueToQuotedString( name.c_str() ) ); + document_ += " : "; + writeValue( childValue ); + if ( ++it == members.end() ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "}" ); + } + } + break; + } +} + + +void +StyledWriter::writeArrayValue( const Value &value ) +{ + unsigned size = value.size(); + if ( size == 0 ) + pushValue( "[]" ); + else + { + bool isArrayMultiLine = isMultineArray( value ); + if ( isArrayMultiLine ) + { + writeWithIndent( "[" ); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index =0; + while ( true ) + { + const Value &childValue = value[index]; + writeCommentBeforeValue( childValue ); + if ( hasChildValue ) + writeWithIndent( childValues_[index] ); + else + { + writeIndent(); + writeValue( childValue ); + } + if ( ++index == size ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "]" ); + } + else // output on a single line + { + assert( childValues_.size() == size ); + document_ += "[ "; + for ( unsigned index =0; index < size; ++index ) + { + if ( index > 0 ) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + + +bool +StyledWriter::isMultineArray( const Value &value ) +{ + int size = value.size(); + bool isMultiLine = size*3 >= rightMargin_ ; + childValues_.clear(); + for ( int index =0; index < size && !isMultiLine; ++index ) + { + const Value &childValue = value[index]; + isMultiLine = isMultiLine || + ( (childValue.isArray() || childValue.isObject()) && + childValue.size() > 0 ); + } + if ( !isMultiLine ) // check if line length > max line length + { + childValues_.reserve( size ); + addChildValues_ = true; + int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' + for ( int index =0; index < size && !isMultiLine; ++index ) + { + writeValue( value[index] ); + lineLength += int( childValues_[index].length() ); + isMultiLine = isMultiLine && hasCommentForValue( value[index] ); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + + +void +StyledWriter::pushValue( const std::string &value ) +{ + if ( addChildValues_ ) + childValues_.push_back( value ); + else + document_ += value; +} + + +void +StyledWriter::writeIndent() +{ + if ( !document_.empty() ) + { + char last = document_[document_.length()-1]; + if ( last == ' ' ) // already indented + return; + if ( last != '\n' ) // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + + +void +StyledWriter::writeWithIndent( const std::string &value ) +{ + writeIndent(); + document_ += value; +} + + +void +StyledWriter::indent() +{ + indentString_ += std::string( indentSize_, ' ' ); +} + + +void +StyledWriter::unindent() +{ + assert( int(indentString_.size()) >= indentSize_ ); + indentString_.resize( indentString_.size() - indentSize_ ); +} + + +void +StyledWriter::writeCommentBeforeValue( const Value &root ) +{ + if ( !root.hasComment( commentBefore ) ) + return; + document_ += normalizeEOL( root.getComment( commentBefore ) ); + document_ += "\n"; +} + + +void +StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) +{ + if ( root.hasComment( commentAfterOnSameLine ) ) + document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + + if ( root.hasComment( commentAfter ) ) + { + document_ += "\n"; + document_ += normalizeEOL( root.getComment( commentAfter ) ); + document_ += "\n"; + } +} + + +bool +StyledWriter::hasCommentForValue( const Value &value ) +{ + return value.hasComment( commentBefore ) + || value.hasComment( commentAfterOnSameLine ) + || value.hasComment( commentAfter ); +} + + +std::string +StyledWriter::normalizeEOL( const std::string &text ) +{ + std::string normalized; + normalized.reserve( text.length() ); + const char *begin = text.c_str(); + const char *end = begin + text.length(); + const char *current = begin; + while ( current != end ) + { + char c = *current++; + if ( c == '\r' ) // mac or dos EOL + { + if ( *current == '\n' ) // convert dos EOL + ++current; + normalized += '\n'; + } + else // handle unix EOL & other char + normalized += c; + } + return normalized; +} + + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter( std::string indentation ) + : document_(NULL) + , rightMargin_( 74 ) + , indentation_( indentation ) +{ +} + + +void +StyledStreamWriter::write( std::ostream &out, const Value &root ) +{ + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue( root ); + writeValue( root ); + writeCommentAfterValueOnSameLine( root ); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + + +void +StyledStreamWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + pushValue( "null" ); + break; + case intValue: + pushValue( valueToString( value.asInt() ) ); + break; + case uintValue: + pushValue( valueToString( value.asUInt() ) ); + break; + case realValue: + pushValue( valueToString( value.asDouble() ) ); + break; + case stringValue: + pushValue( valueToQuotedString( value.asCString() ) ); + break; + case booleanValue: + pushValue( valueToString( value.asBool() ) ); + break; + case arrayValue: + writeArrayValue( value); + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + if ( members.empty() ) + pushValue( "{}" ); + else + { + writeWithIndent( "{" ); + indent(); + Value::Members::iterator it = members.begin(); + while ( true ) + { + const std::string &name = *it; + const Value &childValue = value[name]; + writeCommentBeforeValue( childValue ); + writeWithIndent( valueToQuotedString( name.c_str() ) ); + *document_ << " : "; + writeValue( childValue ); + if ( ++it == members.end() ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "}" ); + } + } + break; + } +} + + +void +StyledStreamWriter::writeArrayValue( const Value &value ) +{ + unsigned size = value.size(); + if ( size == 0 ) + pushValue( "[]" ); + else + { + bool isArrayMultiLine = isMultineArray( value ); + if ( isArrayMultiLine ) + { + writeWithIndent( "[" ); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index =0; + while ( true ) + { + const Value &childValue = value[index]; + writeCommentBeforeValue( childValue ); + if ( hasChildValue ) + writeWithIndent( childValues_[index] ); + else + { + writeIndent(); + writeValue( childValue ); + } + if ( ++index == size ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "]" ); + } + else // output on a single line + { + assert( childValues_.size() == size ); + *document_ << "[ "; + for ( unsigned index =0; index < size; ++index ) + { + if ( index > 0 ) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + + +bool +StyledStreamWriter::isMultineArray( const Value &value ) +{ + int size = value.size(); + bool isMultiLine = size*3 >= rightMargin_ ; + childValues_.clear(); + for ( int index =0; index < size && !isMultiLine; ++index ) + { + const Value &childValue = value[index]; + isMultiLine = isMultiLine || + ( (childValue.isArray() || childValue.isObject()) && + childValue.size() > 0 ); + } + if ( !isMultiLine ) // check if line length > max line length + { + childValues_.reserve( size ); + addChildValues_ = true; + int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' + for ( int index =0; index < size && !isMultiLine; ++index ) + { + writeValue( value[index] ); + lineLength += int( childValues_[index].length() ); + isMultiLine = isMultiLine && hasCommentForValue( value[index] ); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + + +void +StyledStreamWriter::pushValue( const std::string &value ) +{ + if ( addChildValues_ ) + childValues_.push_back( value ); + else + *document_ << value; +} + + +void +StyledStreamWriter::writeIndent() +{ + /* + Some comments in this method would have been nice. ;-) + + if ( !document_.empty() ) + { + char last = document_[document_.length()-1]; + if ( last == ' ' ) // already indented + return; + if ( last != '\n' ) // Comments may add new-line + *document_ << '\n'; + } + */ + *document_ << '\n' << indentString_; +} + + +void +StyledStreamWriter::writeWithIndent( const std::string &value ) +{ + writeIndent(); + *document_ << value; +} + + +void +StyledStreamWriter::indent() +{ + indentString_ += indentation_; +} + + +void +StyledStreamWriter::unindent() +{ + assert( indentString_.size() >= indentation_.size() ); + indentString_.resize( indentString_.size() - indentation_.size() ); +} + + +void +StyledStreamWriter::writeCommentBeforeValue( const Value &root ) +{ + if ( !root.hasComment( commentBefore ) ) + return; + *document_ << normalizeEOL( root.getComment( commentBefore ) ); + *document_ << "\n"; +} + + +void +StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) +{ + if ( root.hasComment( commentAfterOnSameLine ) ) + *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + + if ( root.hasComment( commentAfter ) ) + { + *document_ << "\n"; + *document_ << normalizeEOL( root.getComment( commentAfter ) ); + *document_ << "\n"; + } +} + + +bool +StyledStreamWriter::hasCommentForValue( const Value &value ) +{ + return value.hasComment( commentBefore ) + || value.hasComment( commentAfterOnSameLine ) + || value.hasComment( commentAfter ); +} + + +std::string +StyledStreamWriter::normalizeEOL( const std::string &text ) +{ + std::string normalized; + normalized.reserve( text.length() ); + const char *begin = text.c_str(); + const char *end = begin + text.length(); + const char *current = begin; + while ( current != end ) + { + char c = *current++; + if ( c == '\r' ) // mac or dos EOL + { + if ( *current == '\n' ) // convert dos EOL + ++current; + normalized += '\n'; + } + else // handle unix EOL & other char + normalized += c; + } + return normalized; +} + + +std::ostream& operator<<( std::ostream &sout, const Value &root ) +{ + Json::StyledStreamWriter writer; + writer.write(sout, root); + return sout; +} + + +} // namespace Json diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/plugin.cpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/plugin.cpp new file mode 100644 index 0000000..6906275 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/plugin.cpp @@ -0,0 +1,320 @@ +#include "plugin.h" +#include "tokenizer.h" + +#ifdef _WINDOWS +#include +BOOL APIENTRY DllMain( HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved ) +{ + return TRUE; +} +#else +#include +#include + +extern int errno; +#endif + +SendPluginEv SendPluginEvent; + +string g_GetSysErrMsg( void ) +{ + string strError = "Unknown"; + // Problem loading +#ifdef _WINDOWS + int nErrorCode = GetLastError(); + LPTSTR s; + if ( ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, nErrorCode, 0, ( LPTSTR ) &s, 0, NULL ) ) + { + strError = s; + } + else + { + char szBuf[ 20 ]; + _snprintf_s( szBuf, _countof(szBuf), 19, "%d", nErrorCode ); + strError = szBuf; + } +#else + char szError[80]; + if ( strerror_r( errno, szError, sizeof(szError) ) ) + { + strError = "no description found"; + } + else + { + strError = szError; + } +#endif + return strError; +} + +void g_sleep( unsigned int mseconds ) +{ +#ifdef _WINDOWS + Sleep( mseconds ); +#else + usleep( mseconds * 1000 ); +#endif +} + +string& g_trim( string& str ) +{ + // Whitespace characters + char whspc[] = " \t\r\n\v\f"; + + // Whack off first part + size_t pos = str.find_first_not_of( whspc ); + + if ( pos != string::npos ) + str.replace( 0, pos, "" ); + + // Whack off trailing stuff + pos = str.find_last_not_of( whspc ); + + if ( pos != string::npos ) + str.replace( pos + 1, str.length() - pos, "" ); + + return str; +} + +void g_tokenize( const string& str, const string& delimiters, vector& tokens ) +{ + tokenize( str, tokens, delimiters ); +} + +char* SetEventFunc( SendPluginEv funcPtr ) +{ + static char * szObjList = onGetObjList(); + SendPluginEvent = funcPtr; + return szObjList; +} + + +const int nMAXSIZE = 512; +char* g_pszRetVal = NULL; + +//----------------------------------------------------------- +// Map from an object Id to an object instance +//----------------------------------------------------------- +typedef std::map StringToJExt_T; + +//----------------------------------------------------------- +// Map from a browser context to an id mapping +//----------------------------------------------------------- +typedef std::map VoidToMap_T; + +VoidToMap_T g_context2Map; + +class GlobalSharedModule +{ + +public: + GlobalSharedModule( void ) + { + g_pszRetVal = new char[ nMAXSIZE ]; + } + + ~GlobalSharedModule() + { + delete [] g_pszRetVal; + + VoidToMap_T::iterator posMaps; + + for ( posMaps = g_context2Map.begin(); posMaps != g_context2Map.end(); ++posMaps ) + { + StringToJExt_T& id2Obj = *posMaps->second; + StringToJExt_T::iterator posMap; + + for ( posMap = id2Obj.begin(); posMap != id2Obj.end(); ++posMap ) + { + JSExt* pJSExt = posMap->second; + + if ( pJSExt->CanDelete() ) + { + delete pJSExt; + } + } + + id2Obj.erase( id2Obj.begin(), id2Obj.end() ); + } + + g_context2Map.erase( g_context2Map.begin(), g_context2Map.end() ); + } +}; + +GlobalSharedModule g_sharedModule; + +char* g_str2global( const string& strRetVal ) +{ + int nLen = strRetVal.size(); + + if ( nLen >= nMAXSIZE ) + { + delete [] g_pszRetVal; + g_pszRetVal = new char[ nLen + 1 ]; + } + + else + { + // To minimaize the number of memory reallocations, the assumption + // is that in most times this will be the case + delete [] g_pszRetVal; + g_pszRetVal = new char[ nMAXSIZE ]; + } + + strcpy( g_pszRetVal, strRetVal.c_str() ); + return g_pszRetVal; +} + +bool g_unregisterObject( const string& strObjId, void* pContext ) +{ + // Called by the plugin extension implementation + // if the extension handles the deletion of its object + + StringToJExt_T * pID2Obj = NULL; + + VoidToMap_T::iterator iter = g_context2Map.find( pContext ); + + if ( iter != g_context2Map.end() ) + { + pID2Obj = iter->second; + } + else + { + return false; + } + + StringToJExt_T& mapID2Obj = *pID2Obj; + + StringToJExt_T::iterator r = mapID2Obj.find( strObjId ); + + if ( r == mapID2Obj.end() ) + { + return false; + } + + mapID2Obj.erase( strObjId ); + return true; +} + +char* InvokeFunction( const char* szCommand, void* pContext ) +{ + StringToJExt_T * pID2Obj = NULL; + + VoidToMap_T::iterator iter = g_context2Map.find( pContext ); + + if ( iter != g_context2Map.end() ) + { + pID2Obj = iter->second; + } + else + { + pID2Obj = new StringToJExt_T; + g_context2Map[ pContext ] = pID2Obj; + } + + StringToJExt_T& mapID2Obj = *pID2Obj; + + string strFullCommand = szCommand; + vector arParams; + g_tokenize( strFullCommand, " ", arParams ); + string strCommand = arParams[ 0 ]; + string strRetVal = szERROR; + + if ( strCommand == szCREATE ) + { + string strClassName = arParams[ 1 ]; + string strObjId = arParams[ 2 ]; + + StringToJExt_T::iterator r = mapID2Obj.find( strObjId ); + + if ( r != mapID2Obj.end() ) + { + strRetVal += strObjId; + strRetVal += " :Object already exists."; + return g_str2global( strRetVal ); + } + + JSExt* pJSExt = onCreateObject( strClassName, strObjId ); + + if ( pJSExt == NULL ) + { + strRetVal += strObjId; + strRetVal += " :Unknown object type "; + strRetVal += strClassName; + return g_str2global( strRetVal ); + } + + pJSExt->m_pContext = pContext; + mapID2Obj[ strObjId ] = pJSExt; + + strRetVal = szOK; + strRetVal += strObjId; + return g_str2global( strRetVal ); + } + else + if ( strCommand == szINVOKE ) + { + string strObjId = arParams[ 1 ]; + string strMethod = arParams[ 2 ]; + + StringToJExt_T::iterator r = mapID2Obj.find( strObjId ); + + if ( r == mapID2Obj.end() ) + { + strRetVal += strObjId; + strRetVal += " :No object found for id."; + return g_str2global( strRetVal ); + } + + JSExt* pJSExt = r->second; + + size_t nLoc = strFullCommand.find( strObjId ); + + if ( nLoc == string::npos ) + { + strRetVal += strObjId; + strRetVal += " :Internal InvokeMethod error."; + return g_str2global( strRetVal ); + } + + if ( strMethod == szDISPOSE ) + { + StringToJExt_T::iterator r = mapID2Obj.find( strObjId ); + + if ( r == mapID2Obj.end() ) + { + strRetVal = szERROR; + strRetVal += strObjId; + return g_str2global( strRetVal ); + } + + JSExt * pJSExt = mapID2Obj[ strObjId ]; + + if ( pJSExt->CanDelete() ) + { + delete pJSExt; + } + + mapID2Obj.erase( strObjId ); + strRetVal = szOK; + strRetVal += strObjId; + return g_str2global( strRetVal ); + } + + size_t nSuffixLoc = nLoc + strObjId.size(); + string strInvoke = strFullCommand.substr( nSuffixLoc ); + strInvoke = g_trim( strInvoke ); + strRetVal = pJSExt->InvokeMethod( strInvoke ); + return g_str2global( strRetVal ); + } + + strRetVal += " :Unknown command "; + strRetVal += strCommand; + return g_str2global( strRetVal ); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/plugin.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/plugin.h new file mode 100644 index 0000000..4ef7116 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/plugin.h @@ -0,0 +1,70 @@ +#ifndef _PLUGIN_H +#define _PLUGIN_H + +#include +#include +#include +#include +//#include "tokenizer.h" + +using namespace std; + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +//%% Functions exported by this DLL +//%% Should always be only SetEventFunc and InvokeFunction +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// g++ requires extern "C" otherwise the names of SetEventFunc and InvokeFunction +// are mangled C++ style. MS Visual Studio doesn't seem to care though. +extern "C" +{ + typedef void (*SendPluginEv)( const char* szEvent, void* pContext ); + char* SetEventFunc(SendPluginEv funcPtr); + char* InvokeFunction( const char* szCommand, void* pContext ); +} + +// JNEXT Framework function of the form: +// typedef void (*SendPluginEv)( const char* szEvent ); +// used to notify JavaScript of an asynchronous event +extern SendPluginEv SendPluginEvent; + +///////////////////////////////////////////////////////////////////////// +// Constants and methods common to all JNEXT extensions types +///////////////////////////////////////////////////////////////////////// +#define szERROR "Error " +#define szOK "Ok " + +#define szDISPOSE "Dispose" +#define szINVOKE "InvokeMethod" +#define szCREATE "CreateObj" + +///////////////////////////////////////////////////////////////////////// +// Utility functions +///////////////////////////////////////////////////////////////////////// +string& g_trim( string& str ); +void g_tokenize(const string& str,const string& delimiters, vector& tokens); +char* g_str2static( const string& strRetVal ); +void g_sleep( unsigned int mseconds ); +bool g_unregisterObject( const string& strObjId, void* pContext ); + + +///////////////////////////////////////////////////////////////////////// +// Abstract extension object +///////////////////////////////////////////////////////////////////////// +class JSExt +{ +public: + virtual ~JSExt() {}; + virtual string InvokeMethod( const string& strCommand ) = 0; + virtual bool CanDelete( void ) = 0; + virtual void TryDelete( void ) {} +public: + void* m_pContext; +}; + +///////////////////////////////////////////////////////////////////////// +// Callback functions to be implemented by the plugin implementation +///////////////////////////////////////////////////////////////////////// +extern char* onGetObjList( void ); +extern JSExt* onCreateObject( const string& strClassName, const string& strObjId ); + +#endif diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/tokenizer.cpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/tokenizer.cpp new file mode 100644 index 0000000..4a39573 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/tokenizer.cpp @@ -0,0 +1,222 @@ +/************************************************************************ +The zlib/libpng License + +Copyright (c) 2006 Joerg Wiedenmann + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from +the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; +you must not claim that you wrote the original software. +If you use this software in a product, an acknowledgment +in the product documentation would be appreciated but is +not required. + +2. Altered source versions must be plainly marked as such, +and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. + +***********************************************************************/ + +/******************************************************************** + created: 2006-01-28 + filename: tokenizer.cpp + author: Jrg Wiedenmann + + purpose: A tokenizer function which provides a very + customizable way of breaking up strings. + + history: 2006-01-28, Original version + 2006-03-04, Fixed a small parsing bug, thanks Elias. +*********************************************************************/ + +#include "tokenizer.h" + +using namespace std; + +void tokenize ( const string& str, vector& result, + const string& delimiters, const string& delimiters_preserve, + const string& quote, const string& esc ) +{ + // clear the vector + if ( false == result.empty() ) + { + result.clear(); + } + + string::size_type pos = 0; // the current position (char) in the string + char ch = 0; // buffer for the current character + char delimiter = 0; // the buffer for the delimiter char which + // will be added to the tokens if the delimiter + // is preserved + char current_quote = 0; // the char of the current open quote + bool quoted = false; // indicator if there is an open quote + string token; // string buffer for the token + bool token_complete = false; // indicates if the current token is + // read to be added to the result vector + string::size_type len = str.length(); // length of the input-string + + // for every char in the input-string + while ( len > pos ) + { + // get the character of the string and reset the delimiter buffer + ch = str.at(pos); + delimiter = 0; + + // assume ch isn't a delimiter + bool add_char = true; + + // check ... + + // ... if the delimiter is an escaped character + bool escaped = false; // indicates if the next char is protected + if ( false == esc.empty() ) // check if esc-chars are provided + { + if ( string::npos != esc.find_first_of(ch) ) + { + // get the escaped char + ++pos; + if ( pos < len ) // if there are more chars left + { + // get the next one + ch = str.at(pos); + + // add the escaped character to the token + add_char = true; + } + else // cannot get any more characters + { + // don't add the esc-char + add_char = false; + } + + // ignore the remaining delimiter checks + escaped = true; + } + } + + // ... if the delimiter is a quote + if ( false == quote.empty() && false == escaped ) + { + // if quote chars are provided and the char isn't protected + if ( string::npos != quote.find_first_of(ch) ) + { + // if not quoted, set state to open quote and set + // the quote character + if ( false == quoted ) + { + quoted = true; + current_quote = ch; + + // don't add the quote-char to the token + add_char = false; + } + else // if quote is open already + { + // check if it is the matching character to close it + if ( current_quote == ch ) + { + // close quote and reset the quote character + quoted = false; + current_quote = 0; + + // don't add the quote-char to the token + add_char = false; + } + } // else + } + } + + // ... if the delimiter isn't preserved + if ( false == delimiters.empty() && false == escaped && + false == quoted ) + { + // if a delimiter is provided and the char isn't protected by + // quote or escape char + if ( string::npos != delimiters.find_first_of(ch) ) + { + // if ch is a delimiter and the token string isn't empty + // the token is complete + if ( false == token.empty() ) // BUGFIX: 2006-03-04 + { + token_complete = true; + } + + // don't add the delimiter to the token + add_char = false; + } + } + + // ... if the delimiter is preserved - add it as a token + bool add_delimiter = false; + if ( false == delimiters_preserve.empty() && false == escaped && + false == quoted ) + { + // if a delimiter which will be preserved is provided and the + // char isn't protected by quote or escape char + if ( string::npos != delimiters_preserve.find_first_of(ch) ) + { + // if ch is a delimiter and the token string isn't empty + // the token is complete + if ( false == token.empty() ) // BUGFIX: 2006-03-04 + { + token_complete = true; + } + + // don't add the delimiter to the token + add_char = false; + + // add the delimiter + delimiter = ch; + add_delimiter = true; + } + } + + + // add the character to the token + if ( true == add_char ) + { + // add the current char + token.push_back( ch ); + } + + // add the token if it is complete + if ( true == token_complete && false == token.empty() ) + { + // add the token string + result.push_back( token ); + + // clear the contents + token.clear(); + + // build the next token + token_complete = false; + } + + // add the delimiter + if ( true == add_delimiter ) + { + // the next token is the delimiter + string delim_token; + delim_token.push_back( delimiter ); + result.push_back( delim_token ); + + // REMOVED: 2006-03-04, Bugfix + } + + // repeat for the next character + ++pos; + } // while + + // add the final token + if ( false == token.empty() ) + { + result.push_back( token ); + } +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/tokenizer.h b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/tokenizer.h new file mode 100644 index 0000000..75f567c --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/tokenizer.h @@ -0,0 +1,55 @@ +/************************************************************************ +The zlib/libpng License + +Copyright (c) 2006 Joerg Wiedenmann + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from +the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment + in the product documentation would be appreciated but is + not required. + +2. Altered source versions must be plainly marked as such, + and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. + +***********************************************************************/ + +/******************************************************************** + created: 2006-01-28 + filename: tokenizer.cpp + author: Jrg Wiedenmann + + purpose: A tokenizer function which provides a very + customizable way of breaking up strings. +*********************************************************************/ + +#include +#include +using namespace std; + +// Function to break up a string into tokens +// +// Parameters: +//----------- +// str = the input string that will be tokenized +// result = the tokens for str +// delimiters = the delimiter characters +// delimiters preserve = same as above, but the delimiter characters +// will be put into the result as a token +// quote = characters to protect the enclosed characters +// esc = characters to protect a single character +// + +void tokenize ( const string& str, vector& result, + const string& delimiters, const string& delimiters_preserve = "", + const string& quote = "\"", const string& esc = "\\" ); diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/simulator/.gitignore b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/simulator/.gitignore new file mode 100644 index 0000000..f0ed2b6 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/simulator/.gitignore @@ -0,0 +1,2 @@ +/public +/src diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/simulator/libBarcodeScanner.so b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/simulator/libBarcodeScanner.so new file mode 100644 index 0000000..3d26d8e Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/simulator/libBarcodeScanner.so differ diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/Logger.cpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/Logger.cpp new file mode 100644 index 0000000..357e051 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/Logger.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2013 BlackBerry Limited + * + * 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 "Logger.hpp" +#include "barcodescanner_js.hpp" +#include + +namespace webworks { + +Logger::Logger(const char* name, BarcodeScannerJS *parent): m_pParent(parent) { + buffer_config.buffer_set_name = name; + buffer_config.num_buffers = 2; + buffer_config.verbosity_level = SLOG2_DEBUG1; + + /* Configure the first buffer, using 7 x 4KB pages. This larger buffer will be used for + very chatty logging. Our goal is to have 30-60 seconds of history at any given time, + so we will want to log at a rate of around one log line with a string of 16 bytes + long every 150 milliseconds. + */ + + buffer_config.buffer_config[0].buffer_name = "low_priority"; + buffer_config.buffer_config[0].num_pages = 7; + + /* Configure the second buffer, which we will use for high level info logging that is very + infrequent, but we want a longer history (hours or maybe even over a day or two). This + buffer uses 1 x 4KB. + */ + + buffer_config.buffer_config[1].buffer_name = "high_priority"; + buffer_config.buffer_config[1].num_pages = 1; + + /* Register the buffer set. */ + + if( -1 == slog2_register( &buffer_config, buffer_handle, 0 ) ) { + fprintf( stderr, "Error registering slogger2 buffer!\n" ); + } else { + info("Created slogger2 buffers"); + } + +} + +Logger::~Logger() { + critical("slogger2 buffers reset"); + slog2_reset(); +} + +int Logger::log(slog2_buffer_t buffer, _Uint8t severity, const char* message) { + return slog2c(buffer, 0, severity, message); +} + +int Logger::debug(const char* message) { + return log(lowPriorityBuffer(), SLOG2_DEBUG1, message); +} + +int Logger::info(const char* message) { + return log(lowPriorityBuffer(), SLOG2_INFO, message); +} + +int Logger::notice(const char* message) { + return log(lowPriorityBuffer(), SLOG2_NOTICE, message); +} + +int Logger::warn(const char* message) { + return log(lowPriorityBuffer(), SLOG2_WARNING, message); +} + +int Logger::error(const char* message) { + return log(hiPriorityBuffer(), SLOG2_ERROR, message); +} + +int Logger::critical(const char* message) { + return log(hiPriorityBuffer(), SLOG2_CRITICAL, message); +} + +int Logger::setVerbosity(_Uint8t verbosity) { + return slog2_set_verbosity(buffer_handle[0], verbosity); +} + +_Uint8t Logger::getVerbosity() { + return slog2_get_verbosity(buffer_handle[0]); +} + +slog2_buffer_t Logger::hiPriorityBuffer() { + return buffer_handle[1]; +} + +slog2_buffer_t Logger::lowPriorityBuffer() { + return buffer_handle[0]; +} + +} /* namespace webworks */ diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/Logger.hpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/Logger.hpp new file mode 100644 index 0000000..2344fd9 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/Logger.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013 BlackBerry Limited + * + * 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. + */ + +#ifndef LOGGER_HPP_ +#define LOGGER_HPP_ + +#include +#include + +class BarcodeScannerJS; + +namespace webworks { + +class Logger { +public: + explicit Logger(const char* name, BarcodeScannerJS *parent = NULL); + virtual ~Logger(); + int debug(const char* message); + int info(const char* message); + int notice(const char* message); + int warn(const char* message); + int error(const char* message); + int critical(const char* message); + int setVerbosity(_Uint8t verbosity); + _Uint8t getVerbosity(); + slog2_buffer_t hiPriorityBuffer(); + slog2_buffer_t lowPriorityBuffer(); +private: + BarcodeScannerJS *m_pParent; + slog2_buffer_set_config_t buffer_config; + slog2_buffer_t buffer_handle[2]; + int log(slog2_buffer_t buffer, _Uint8t severity, const char* message); +}; + +} /* namespace webworks */ +#endif /* LOGGER_HPP_ */ diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_js.cpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_js.cpp new file mode 100644 index 0000000..fd1db92 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_js.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2013-2014 BlackBerry Limited. + * + * 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 "../public/tokenizer.h" +#include "barcodescanner_js.hpp" +#include "barcodescanner_ndk.hpp" + +using namespace std; + +/** + * Default constructor. + */ +BarcodeScannerJS::BarcodeScannerJS(const std::string& id) : + m_id(id) { + m_pLogger = new webworks::Logger("BarcodeScannerJS", this); + m_pBarcodeScannerController = new webworks::BarcodeScannerNDK(this); +} + +/** + * BarcodeScannerJS destructor. + */ +BarcodeScannerJS::~BarcodeScannerJS() { + if (m_pBarcodeScannerController) + delete m_pBarcodeScannerController; + if (m_pLogger) + delete m_pLogger; +} + +webworks::Logger* BarcodeScannerJS::getLog() { + return m_pLogger; +} + +/** + * This method returns the list of objects implemented by this native + * extension. + */ +char* onGetObjList() { + static char name[] = "BarcodeScannerJS"; + return name; +} + +/** + * This method is used by JNext to instantiate the BarcodeScannerJS object when + * an object is created on the JavaScript server side. + */ +JSExt* onCreateObject(const string& className, const string& id) { + if (className == "BarcodeScannerJS") { + return new BarcodeScannerJS(id); + } + + return NULL; +} + +/** + * Method used by JNext to determine if the object can be deleted. + */ +bool BarcodeScannerJS::CanDelete() { + return true; +} + +/** + * It will be called from JNext JavaScript side with passed string. + * This method implements the interface for the JavaScript to native binding + * for invoking native code. This method is triggered when JNext.invoke is + * called on the JavaScript side with this native objects id. + */ +string BarcodeScannerJS::InvokeMethod(const std::string& command) { + // command appears with parameters following after a space + size_t commandIndex = command.find_first_of(" "); + std::string strCommand = command.substr(0, commandIndex); + size_t callbackIndex = command.find_first_of(" ", commandIndex + 1); + std::string callbackId = command.substr(commandIndex + 1, callbackIndex - commandIndex - 1); + std::string arg = command.substr(callbackIndex + 1, command.length()); + + if (strCommand == "startRead") { + m_pBarcodeScannerController->startRead(callbackId, arg); + } + else if (strCommand == "stopRead") { + m_pBarcodeScannerController->stopRead(callbackId); + } + + strCommand.append(";"); + strCommand.append(command); + return strCommand; +} + +// Notifies JavaScript of an event +void BarcodeScannerJS::NotifyEvent(const std::string& event) { + std::string eventString = m_id + " "; + eventString.append(event); + SendPluginEvent(eventString.c_str(), m_pContext); +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_js.hpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_js.hpp new file mode 100644 index 0000000..4b04a78 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_js.hpp @@ -0,0 +1,41 @@ +/* +* Copyright 2013-2014 BlackBerry Limited. +* +* 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. +*/ + +#ifndef BARCODESCANNERJS_HPP_ +#define BARCODESCANNERJS_HPP_ + +#include "../public/plugin.h" +#include "barcodescanner_ndk.hpp" +#include "Logger.hpp" +#include + +class BarcodeScannerJS: public JSExt { + +public: + explicit BarcodeScannerJS(const std::string& id); + virtual ~BarcodeScannerJS(); + virtual bool CanDelete(); + virtual std::string InvokeMethod(const std::string& command); + void NotifyEvent(const std::string& event); + webworks::Logger* getLog(); + webworks::BarcodeScannerNDK *m_pBarcodeScannerController; +private: + std::string m_id; + // Definition of a pointer to the actual native extension code + webworks::Logger *m_pLogger; +}; + +#endif /* BarcodeScannerJS_HPP_ */ diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_ndk.cpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_ndk.cpp new file mode 100644 index 0000000..830f17b --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_ndk.cpp @@ -0,0 +1,709 @@ +/* + * Copyright 2013-2015 BlackBerry Limited. + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "barcodescanner_ndk.hpp" +#include "barcodescanner_js.hpp" + +#include +#include + +using namespace zxing; + +namespace webworks { + +BarcodeScannerJS* eventDispatcher = NULL; +// Variables for native viewfinder screen +static screen_window_t vf_win = NULL; +static uint32_t vfRotation = 0; +static bool touch = false; + + +#define MUTEX_LOCK() pthread_mutex_trylock(&m_lock) +#define MUTEX_UNLOCK() pthread_mutex_unlock(&m_lock) + +static pthread_mutex_t m_lock; +static pthread_t m_thread = 0; + + /* + * getCameraErrorDesc + * + * Returns a descriptive error message for a given camera error code + */ + const char* getCameraErrorDesc(camera_error_t err) { + switch (err) { + case CAMERA_EOK: + return "The function call to the camera completed successfully."; + case CAMERA_EAGAIN: + return "The specified camera was not available. Try again."; + case CAMERA_EINVAL: + return "The camera call failed because of an invalid parameter."; + case CAMERA_ENODEV: + return "No such camera was found."; + case CAMERA_EMFILE: + return "The camera called failed because of a file table overflow."; + case CAMERA_EBADF: + return "Indicates that an invalid handle to a @c camera_handle_t value was used."; + case CAMERA_EACCESS: + return "Indicates that the necessary permissions to access the camera are not available."; + case CAMERA_EBADR: + return "Indicates that an invalid file descriptor was used."; + case CAMERA_ENOENT: + return "Indicates that the access a file or directory that does not exist."; + case CAMERA_ENOMEM: + return "Indicates that memory allocation failed."; + case CAMERA_EOPNOTSUPP: + return "Indicates that the requested operation is not supported."; + case CAMERA_ETIMEDOUT: + return "The function call failed due to communication problem or time-out with the camera."; + case CAMERA_EALREADY: + return "Indicates an operation on the camera is already in progress. In addition, this error can indicate that an error could not be completed because it was already completed. For example, if you called the @c camera_stop_video() function but the camera had already stopped recording video, this error code would be returned."; + case CAMERA_EUNINIT: + return "Indicates that the Camera Library is not initialized."; + case CAMERA_EREGFAULT: + return "Indicates that registration of a callback failed."; + case CAMERA_EMICINUSE: + return "Indicates that it failed to open because microphone is already in use."; + } + return NULL; + } + + + /* + * viewfinder_callback + * + * This callback is invoked when an image frame from the camera viewfinder becomes available. + * The frame is analyzed to determine if a barcode can be matched. + * Frames come in NV12 format which makes code analysis very fast. + */ + void viewfinder_callback(camera_handle_t handle,camera_buffer_t* buf,void* arg) { + camera_frame_nv12_t* data = (camera_frame_nv12_t*)(&(buf->framedesc)); + uint8_t* buff = buf->framebuf; + int stride = data->stride; + int width = data->width; + int height = data->height; + if ( eventDispatcher != NULL ){ +// eventDispatcher->getLog()->debug("Frame received"); + } + + try { + Ref source(new GreyscaleLuminanceSource((unsigned char *)buff, stride, height, 0,0,width,height)); + + Ref binarizer(new HybridBinarizer(source)); + Ref bitmap(new BinaryBitmap(binarizer)); + Ref result; + + // setup the code reader + MultiFormatReader *reader = new MultiFormatReader(); + DecodeHints *hints = new DecodeHints(); + + hints->addFormat(BarcodeFormat_QR_CODE); + hints->addFormat(BarcodeFormat_EAN_8); + hints->addFormat(BarcodeFormat_EAN_13); + hints->addFormat(BarcodeFormat_UPC_A); + hints->addFormat(BarcodeFormat_UPC_E); + hints->addFormat(BarcodeFormat_DATA_MATRIX); + hints->addFormat(BarcodeFormat_CODE_128); + hints->addFormat(BarcodeFormat_CODE_39); + hints->addFormat(BarcodeFormat_ITF); + hints->addFormat(BarcodeFormat_AZTEC); + + // attempt to decode and retrieve a valid QR code from the image bitmap + result = reader->decode(bitmap, *hints); + + std::string newBarcodeData = result->getText()->getText().data(); + + Json::FastWriter writer; + Json::Value root; + root["text"] = newBarcodeData; + root["format"] = barcodeFormatNames[result->getBarcodeFormat()]; + root["cancelled"] = false; + + // notify caller that a valid QR code has been decoded + if ( eventDispatcher != NULL){ + std::string event = "community.barcodescanner.codefound.native"; + event.insert(0, " "); + event.insert(0, (char *) arg); + eventDispatcher->NotifyEvent(event + " " + writer.write(root)); + eventDispatcher->getLog()->debug("This is the detected Barcode"); + eventDispatcher->getLog()->debug(newBarcodeData.c_str()); + } + + } + catch (const std::exception& ex) + { + // Uncomment this if you need to verify scanning + if ( eventDispatcher != NULL ){ +// eventDispatcher->getLog()->warn("Scan error"); +// eventDispatcher->getLog()->warn(ex.what()); + } + } + } + + std::string convertIntToString(int i) { + stringstream ss; + ss << i; + return ss.str(); + } + + + /* + * Constructor for Barcode Scanner NDK class + */ + BarcodeScannerNDK::BarcodeScannerNDK(BarcodeScannerJS *parent): threadHalt(false) { + cbId = new char[1000]; + m_pParent = parent; + eventDispatcher = parent; + mCameraHandle = CAMERA_HANDLE_INVALID; + } + + BarcodeScannerNDK::~BarcodeScannerNDK() { + delete[] cbId; + } + + webworks::Logger* BarcodeScannerNDK::getLog() { + return m_pParent->getLog(); + } + + void interrogateWindowCV(screen_window_t window, Logger* log, string description, int property) { + char* value = new char[256]; + int ok = screen_get_window_property_cv(window, property, 256, value); + if (ok == 0) { + log->info(description.c_str()); + log->info(value); + } else { + log->warn("Unable to interpret value for"); + log->warn(description.c_str()); + } + } + + void interrogateWindowIV(screen_window_t window, Logger* log, string description, int property) { + int value = -1; + int ok = screen_get_window_property_iv(window, property, &value); + if (ok == 0) { + log->info(description.c_str()); + log->info(convertIntToString(value).c_str()); + } else { + log->warn("Unable to interpret value for"); + log->warn(description.c_str()); + } + } + + void interrogateWindow(screen_window_t window, Logger* log) { + log->info("Window Details--->"); + interrogateWindowCV(window, log, "Window ID", SCREEN_PROPERTY_ID_STRING); + interrogateWindowIV(window, log, "Window Type", SCREEN_PROPERTY_TYPE); + interrogateWindowIV(window, log, "Window Owner PID", SCREEN_PROPERTY_OWNER_PID); + interrogateWindowCV(window, log, "Window Group", SCREEN_PROPERTY_GROUP); + interrogateWindowIV(window, log, "Window Z Order", SCREEN_PROPERTY_ZORDER); + interrogateWindowIV(window, log, "Window Visible", SCREEN_PROPERTY_VISIBLE); + log->info("Window Interrogation complete"); + } + + void *HandleEvents(void *args) { + BarcodeScannerNDK *parent = static_cast(args); + parent->getLog()->debug("BarcodeScannerNDK EventHandler"); + + /** + * Creating a native viewfinder screen + */ + const int usage = SCREEN_USAGE_NATIVE; + screen_window_t screen_win; + screen_buffer_t screen_buf = NULL; + int rect[4] = { 0, 0, 0, 0 }; + + if(screen_create_window_type(&screen_win, parent->windowContext, SCREEN_CHILD_WINDOW) == -1) { + parent->getLog()->error("screen_create_window() failed");; + } + screen_join_window_group(screen_win, parent->windowGroup); + char * groupCheck = new char[256]; + screen_get_window_property_cv(screen_win, SCREEN_PROPERTY_GROUP, 256, groupCheck); + parent->getLog()->info("Window Group Check"); + parent->getLog()->info(groupCheck); + screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_USAGE, &usage); + int r = 0; + screen_display_t display = NULL; + screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_DISPLAY, (void**)&display); + if (display != NULL) { + screen_get_display_property_iv(display, SCREEN_PROPERTY_ROTATION, &r); + parent->getLog()->debug("Current Display Rotation"); + parent->getLog()->debug(convertIntToString(r).c_str()); + } + screen_create_window_buffers(screen_win, 1); + screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&screen_buf); + screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, rect+2); + // The screen (and backing buffer) don't take into account the rotation, so we need to swap the size. + if (r == 90 || r == 270) { + int swap = rect[2]; + rect[2] = rect[3]; + rect[3] = swap; + } + // Set the window size and the buffer follows along + screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_SIZE, rect+2); + screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, rect+2); + + parent->getLog()->debug("Screen Buffer Size:"); + parent->getLog()->debug(convertIntToString(rect[0]).c_str()); + parent->getLog()->debug(convertIntToString(rect[1]).c_str()); + parent->getLog()->debug(convertIntToString(rect[2]).c_str()); + parent->getLog()->debug(convertIntToString(rect[3]).c_str()); + + int type = -1; + screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_TYPE, &type); + parent->getLog()->debug("Window Type"); + parent->getLog()->debug(convertIntToString(type).c_str()); + + // fill the window with a flat colour + int attribs[] = { SCREEN_BLIT_COLOR, 0x00333333, SCREEN_BLIT_END }; + screen_fill(parent->windowContext, screen_buf, attribs); + screen_post_window(screen_win, screen_buf, 1, rect, 0); + // position the window at an arbitrary z-order + int i = 1; + screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &i); + screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &i); + parent->getLog()->debug("Current Zorder"); + parent->getLog()->debug(convertIntToString(i).c_str()); + int visible = 1; + screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_VISIBLE, &visible); + screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_VISIBLE, &visible); + parent->getLog()->debug("Visible?"); + parent->getLog()->debug(convertIntToString(visible).c_str()); + screen_flush_context(parent->windowContext, 0); + + parent->getLog()->debug("Created Background window"); + + if (parent->windowContext) { + if (BPS_SUCCESS == screen_request_events(parent->windowContext)) { + parent->getLog()->debug("Requested Events"); + } else { + parent->getLog()->error("Unable to request events"); + return NULL; + } + } + + screen_group_t group; + screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_GROUP, (void **)&group); + char* groupName = new char[256]; + screen_get_group_property_cv(group, SCREEN_PROPERTY_NAME, 256, groupName); + parent->getLog()->debug("Group Found"); + parent->getLog()->debug(groupName); + + // reset Touch value before starting up listening for touch events + touch = false; + + while(!parent->isThreadHalt()) { + MUTEX_LOCK(); + + int domain; + // Get the first event in the queue. + bps_event_t *event = NULL; + if (BPS_SUCCESS != bps_get_event(&event, 0)) { + parent->getLog()->warn("bps_get_event() failed"); + } + + // Handle all events in the queue. + while (event) { + if (touch) { + // HandleScreenEvent got a tap on the screen + // Shutdown the scanning + parent->cancelScan(); + break; + } + if (event) { + domain = bps_event_get_domain(event); + parent->getLog()->debug("BPS Event"); + if (domain == screen_get_domain()) { + parent->getLog()->debug("BPS Screen Event"); + parent->handleScreenEvent(event, parent->getLog(), parent->windowGroup); + } + } + if (BPS_SUCCESS != bps_get_event(&event, 0)) { + parent->getLog()->error("bps_get_event() failed"); +// return; + } + } + + MUTEX_UNLOCK(); + + // Poll at 10hz + usleep(100000); + } + // stop screen events on this thread + if(screen_stop_events(parent->windowContext) == -1) { + parent->getLog()->error("screen_stop_events failed"); + } + screen_destroy_window(screen_win); + return NULL; + } + + void BarcodeScannerNDK::handleScreenEvent(bps_event_t *event, Logger* log, const char* windowGroup) { + int eventType, objectType, eventProperty; + + screen_event_t screen_event = screen_event_get_event(event); + screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &eventType); + + switch (eventType) { + case SCREEN_EVENT_MTOUCH_RELEASE: + case SCREEN_EVENT_MTOUCH_TOUCH: + case SCREEN_EVENT_MTOUCH_MOVE: + log->info("Touch Event"); + touch = true; + break; + case SCREEN_EVENT_CREATE: + log->info("Screen Create Event"); + if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void **)&vf_win) == -1) { + log->error("screen_get_event_property_pv(SCREEN_PROPERTY_WINDOW)"); + } else { + log->info("viewfinder window found!"); + } + break; + case SCREEN_EVENT_IDLE: + log->debug("Screen Idle"); + break; + case SCREEN_EVENT_POST: + log->debug("Screen posted first frame"); + if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void **)&vf_win) == -1) { + log->error("screen_get_event_property_pv(SCREEN_PROPERTY_WINDOW)"); + } else { + interrogateWindow(vf_win, log); + int i = 100; + screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_ZORDER, &i); + screen_get_window_property_iv(vf_win, SCREEN_PROPERTY_ZORDER, &i); + log->debug("Current Zorder"); + log->debug(convertIntToString(i).c_str()); + // make viewfinder window visible + i = 1; + screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_VISIBLE, &i); + screen_get_window_property_iv(vf_win, SCREEN_PROPERTY_VISIBLE, &i); + log->debug("Visible?"); + log->debug(convertIntToString(i).c_str()); + // Rotate the window as needed + screen_get_window_property_iv(vf_win, SCREEN_PROPERTY_ROTATION, &i); + log->debug("Current Rotation"); + log->debug(convertIntToString(i).c_str()); + i = 360 - vfRotation; + screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_ROTATION, &i); + screen_get_window_property_iv(vf_win, SCREEN_PROPERTY_ROTATION, &i); + log->debug("Rotation"); + log->debug(convertIntToString(i).c_str()); + // Make full screen + screen_display_t display = NULL; + screen_get_window_property_pv(vf_win, SCREEN_PROPERTY_DISPLAY, (void **)&display); + if (display != NULL) { + log->debug("Found a Display"); + int size[2] = { 0, 0 }; + screen_get_display_property_iv(display, SCREEN_PROPERTY_SIZE, size); + log->debug("Display Size"); + log->debug(convertIntToString(size[0]).c_str()); + log->debug(convertIntToString(size[1]).c_str()); + int r = 0; + screen_get_display_property_iv(display, SCREEN_PROPERTY_ROTATION, &r); + log->debug("Current Display Rotation"); + log->debug(convertIntToString(r).c_str()); + if (r == 90 || r == 270) { + int swap = size[0]; + size[0] = size[1]; + size[1] = swap; + } + screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_SIZE, size); + screen_get_window_property_iv(vf_win, SCREEN_PROPERTY_SIZE, size); + log->debug("Window Size"); + log->debug(convertIntToString(size[0]).c_str()); + log->debug(convertIntToString(size[1]).c_str()); + } + + } + break; + case SCREEN_EVENT_CLOSE: + log->debug("Screen closed"); + break; + case SCREEN_EVENT_INPUT: + log->debug("Screen input event"); + break; + case SCREEN_EVENT_PROPERTY: + log->debug("Screen property event"); + screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType); + log->debug("Object Type"); + log->debug(convertIntToString(objectType).c_str()); + screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_NAME, &eventProperty); + log->debug("Property Name"); + log->debug(convertIntToString(eventProperty).c_str()); + break; + default: + log->warn("Unhandled Screen Event Type"); + log->warn(convertIntToString(eventType).c_str()); + break; + } + } + + bool BarcodeScannerNDK::StartEvents() { + if (!m_thread) { + threadHalt = false; + pthread_attr_t thread_attr; + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE); + int error = pthread_create(&m_thread, &thread_attr, HandleEvents, static_cast(this)); + pthread_attr_destroy(&thread_attr); + if (error) { + m_pParent->getLog()->error("Thread Failed to start"); + m_thread = 0; + return false; + } else { + m_pParent->getLog()->info("Thread Started"); + MUTEX_LOCK(); + return true; + } + } + + return false; + } + + void BarcodeScannerNDK::StopEvents() { + if (m_thread) { + MUTEX_LOCK(); + threadHalt = true; + MUTEX_UNLOCK(); + m_pParent->getLog()->debug("BarcodeScannerNDK joining event thread"); + pthread_join(m_thread, NULL); + m_thread = 0; + m_pParent->getLog()->debug("BarcodeScannerNDK event thread stopped"); + } + } + + + // getter for the stop value + bool BarcodeScannerNDK::isThreadHalt() { + bool isThreadHalt; + MUTEX_LOCK(); + isThreadHalt = threadHalt; + MUTEX_UNLOCK(); + return isThreadHalt; + } + + void BarcodeScannerNDK::cancelScan() { + m_pParent->getLog()->warn("Cancel Scan"); + std::string event = "community.barcodescanner.codefound.native"; + std::string callbackId = cbId; + Json::FastWriter writer; + Json::Value root; + + // Scan cancelled by user + root["text"] = ""; + root["format"] = ""; + root["cancelled"] = true; + + m_pParent->NotifyEvent(callbackId + " " + event + " " + writer.write(root)); + } + + /* + * BarcodeScannerNDK::startRead + * + * This method is called to start a QR code read. A connection is opened to the device camera + * and the photo viewfinder is started. + */ + int BarcodeScannerNDK::startRead(const string &callbackId, const string &arg) { + std::string errorEvent = "community.barcodescanner.errorfound.native"; + Json::FastWriter writer; + Json::Value root; + + // Important for maintaining proper event queue support on 10.2.1 + bps_initialize(); + + std::string handle; + std::string group; + Json::Reader reader; + Json::Value input; + bool parse = reader.parse(arg, input); + + if (!parse) { + m_pParent->getLog()->error("Parse Error"); + Json::Value error; + root["state"] = "Parsing JSON object"; + root["error"] = "Cannot parse JSON object"; + root["description"] = ""; + m_pParent->NotifyEvent(callbackId + " " + errorEvent + " " + writer.write(error)); + return EIO; + } else { + handle = input["handle"].asString(); + group = input["group"].asString(); + } + + std::copy(callbackId.begin(), callbackId.end(), this->cbId); + this->cbId[callbackId.size()] = '\0'; + + this->windowHandle = handle; + m_pParent->getLog()->info("Window Handle"); + m_pParent->getLog()->info(handle.c_str()); + // the jsScreenWindowHandle of the UIWebView that we passed in + int windowPointer = (int) strtol(handle.c_str(), NULL, 10); + // As an integer is the actual window handle + screen_window_t window = (screen_window_t) windowPointer; + interrogateWindow(window, m_pParent->getLog()); + // Create a group for the main window + windowGroup = new char[group.length()+1]; + std::strcpy (windowGroup, group.c_str()); + m_pParent->getLog()->debug("Window Group using:"); + m_pParent->getLog()->debug(windowGroup); + + int getContext = screen_get_window_property_pv(window, SCREEN_PROPERTY_CONTEXT, (void **)&windowContext); + if (getContext == -1) { + m_pParent->getLog()->critical("Unable to get Context"); + root["state"] = "Get App Window Context"; + root["error"] = getContext; + root["description"] = "Unable to get application context"; + m_pParent->NotifyEvent(callbackId + " " + errorEvent + " " + writer.write(root)); + return EIO; + } + + StartEvents(); + + camera_error_t err; + // Open the camera first before running any operations on it + err = camera_open(CAMERA_UNIT_REAR,CAMERA_MODE_RW | CAMERA_MODE_ROLL,&mCameraHandle); + + if ( err != CAMERA_EOK){ + m_pParent->getLog()->error("Ran into an issue when initializing the camera"); + m_pParent->getLog()->error(getCameraErrorDesc( err )); + root["state"] = "Open Camera"; + root["error"] = err; + root["description"] = getCameraErrorDesc( err ); + m_pParent->NotifyEvent(callbackId + " " + errorEvent + " " + writer.write(root)); + return EIO; + } + + // We want maximum framerate from the viewfinder which will scan for codes + int numRates = 0; + err = camera_get_photo_vf_framerates(mCameraHandle, true, 0, &numRates, NULL, NULL); + double* camFramerates = new double[numRates]; + bool maxmin = false; + err = camera_get_photo_vf_framerates(mCameraHandle, true, numRates, &numRates, camFramerates, &maxmin); + + // do we need to rotate the viewfinder? + + err = camera_get_photovf_property(mCameraHandle, CAMERA_IMGPROP_ROTATION, &vfRotation); + m_pParent->getLog()->debug("Viewfinder Rotation"); + m_pParent->getLog()->debug(convertIntToString(vfRotation).c_str()); + + m_pParent->getLog()->debug("Camera Window Group"); + m_pParent->getLog()->debug(windowGroup); + // We're going to have the viewfinder window join our app's window group, and start an embedded window + err = camera_set_photovf_property(mCameraHandle, + CAMERA_IMGPROP_WIN_GROUPID, windowGroup, + CAMERA_IMGPROP_WIN_ID, "my_viewfinder"); + if ( err != CAMERA_EOK){ + m_pParent->getLog()->error("Ran into an issue when configuring the camera viewfinder"); + m_pParent->getLog()->error(getCameraErrorDesc( err )); + root["state"] = "Set VF Props"; + root["error"] = err; + root["description"] = getCameraErrorDesc( err ); + m_pParent->NotifyEvent(callbackId + " " + errorEvent + " " + writer.write(root)); + return EIO; + } + + // Starting viewfinder up which will call the viewfinder callback - this gets the NV12 images for scanning + err = camera_start_photo_viewfinder( mCameraHandle, &viewfinder_callback, NULL, this->cbId); + if ( err != CAMERA_EOK) { + m_pParent->getLog()->error("Ran into a strange issue when starting up the camera viewfinder"); + m_pParent->getLog()->error(getCameraErrorDesc( err )); + root["state"] = "ViewFinder Start"; + root["error"] = err; + root["description"] = getCameraErrorDesc( err ); + m_pParent->NotifyEvent(callbackId + " " + errorEvent + " " + writer.write(root)); + return EIO; + } + + // Focus mode can't be set until the viewfinder is started. We need Continuous Macro for barcodes + err = camera_set_focus_mode(mCameraHandle, CAMERA_FOCUSMODE_CONTINUOUS_MACRO); + if ( err != CAMERA_EOK){ + m_pParent->getLog()->error("Ran into an issue when setting focus mode"); + m_pParent->getLog()->error(getCameraErrorDesc( err )); + root["state"] = "Set Focus Mode"; + root["error"] = err; + root["description"] = getCameraErrorDesc( err ); + m_pParent->NotifyEvent(callbackId + " " + errorEvent + " " + writer.write(root)); + return EIO; + } + + std::string successEvent = "community.barcodescanner.started.native"; + root["successful"] = true; + m_pParent->NotifyEvent(callbackId + " " + successEvent + " " + writer.write(root)); + return EOK; + } + + + /* + * BarcodeScannerNDK::stopRead + * + * This method is called to clean up following successful detection of a barcode. + * Calling this method will stop the viewfinder and close an open connection to the device camera. + */ + int BarcodeScannerNDK::stopRead(const string &callbackId) { + std::string errorEvent = "community.barcodescanner.errorfound.native"; + Json::FastWriter writer; + Json::Value root; + camera_error_t err; + + // Stop events first so that you don't get better response from the screen + StopEvents(); + + err = camera_stop_photo_viewfinder(mCameraHandle); + if ( err != CAMERA_EOK) + { + m_pParent->getLog()->error("Error with turning off the photo viewfinder"); + m_pParent->getLog()->error(getCameraErrorDesc( err )); + root["error"] = err; + root["description"] = getCameraErrorDesc( err ); + m_pParent->NotifyEvent(callbackId + " " + errorEvent + " " + writer.write(root)); + return EIO; + } + + //check to see if the camera is open, if it is open, then close it + err = camera_close(mCameraHandle); + if ( err != CAMERA_EOK){ + m_pParent->getLog()->error("Error with closing the camera"); + m_pParent->getLog()->error(getCameraErrorDesc( err )); + root["error"] = err; + root["description"] = getCameraErrorDesc( err ); + m_pParent->NotifyEvent(callbackId + " " + errorEvent + " " + writer.write(root)); + return EIO; + } + + std::string successEvent = "community.barcodescanner.ended.native"; + root["successful"] = true; + mCameraHandle = CAMERA_HANDLE_INVALID; + m_pParent->NotifyEvent(callbackId + " " + successEvent + " " + writer.write(root)); + + // Important for maintaining proper event queue support on 10.2.1 + bps_shutdown(); + + return EOK; + } + +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_ndk.hpp b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_ndk.hpp new file mode 100644 index 0000000..9289f6a --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_ndk.hpp @@ -0,0 +1,55 @@ +/* +* Copyright 2013-2015 BlackBerry Limited. +* +* 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. +*/ + +#ifndef BARCODESCANNERNDK_HPP_ +#define BARCODESCANNERNDK_HPP_ + +#include +#include "Logger.hpp" +#include +#include + +class BarcodeScannerJS; + +namespace webworks { + +class BarcodeScannerNDK { +public: + explicit BarcodeScannerNDK(BarcodeScannerJS *parent = NULL); + virtual ~BarcodeScannerNDK(); + + int startRead(const std::string& callbackId, const std::string& handle); + int stopRead(const std::string& callbackId); + bool isThreadHalt(); + void StopEvents(); + bool StartEvents(); + Logger* getLog(); + void handleScreenEvent(bps_event_t *event, Logger* log, const char* windowGroup); + void cancelScan(); + char* windowGroup; + screen_context_t windowContext; + char* cbId; + +private: + BarcodeScannerJS *m_pParent; + camera_handle_t mCameraHandle; + bool threadHalt; + std::string windowHandle; +}; + +} // namespace webworks + +#endif /* BARCODESCANNERNDK_H_ */ diff --git a/plugins/phonegap-plugin-barcodescanner/src/blackberry10/qrcode.js b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/qrcode.js new file mode 100644 index 0000000..5cb6a7a --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/blackberry10/qrcode.js @@ -0,0 +1,622 @@ +/** + * @fileoverview + * - Using the 'QRCode for Javascript library' + * - Fixed dataset of 'QRCode for Javascript library' for support full-spec. + * - this library has no dependencies. + * + * @author davidshimjs + * @see http://www.d-project.com/ + * @see http://jeromeetienne.github.com/jquery-qrcode/ + */ +var QRCode; +//var _utils = require("../../lib/utils"); + +(function () { + //--------------------------------------------------------------------- + // QRCode for JavaScript + // + // Copyright (c) 2009 Kazuhiko Arase + // + // URL: http://www.d-project.com/ + // + // Licensed under the MIT license: + // http://www.opensource.org/licenses/mit-license.php + // + // The word "QR Code" is registered trademark of + // DENSO WAVE INCORPORATED + // http://www.denso-wave.com/qrcode/faqpatent-e.html + // + //--------------------------------------------------------------------- + function QR8bitByte(data) { + this.mode = QRMode.MODE_8BIT_BYTE; + this.data = data; + this.parsedData = []; + + // Added to support UTF-8 Characters + for (var i = 0, l = this.data.length; i < l; i++) { + var byteArray = []; + var code = this.data.charCodeAt(i); + + if (code > 0x10000) { + byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18); + byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12); + byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6); + byteArray[3] = 0x80 | (code & 0x3F); + } else if (code > 0x800) { + byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12); + byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6); + byteArray[2] = 0x80 | (code & 0x3F); + } else if (code > 0x80) { + byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6); + byteArray[1] = 0x80 | (code & 0x3F); + } else { + byteArray[0] = code; + } + + this.parsedData.push(byteArray); + } + + this.parsedData = Array.prototype.concat.apply([], this.parsedData); + + if (this.parsedData.length != this.data.length) { + this.parsedData.unshift(191); + this.parsedData.unshift(187); + this.parsedData.unshift(239); + } + } + + QR8bitByte.prototype = { + getLength: function (buffer) { + return this.parsedData.length; + }, + write: function (buffer) { + for (var i = 0, l = this.parsedData.length; i < l; i++) { + buffer.put(this.parsedData[i], 8); + } + } + }; + + function QRCodeModel(typeNumber, errorCorrectLevel) { + this.typeNumber = typeNumber; + this.errorCorrectLevel = errorCorrectLevel; + this.modules = null; + this.moduleCount = 0; + this.dataCache = null; + this.dataList = []; + } + + QRCodeModel.prototype={addData:function(data){var newData=new QR8bitByte(data);this.dataList.push(newData);this.dataCache=null;},isDark:function(row,col){if(row<0||this.moduleCount<=row||col<0||this.moduleCount<=col){throw new Error(row+","+col);} + return this.modules[row][col];},getModuleCount:function(){return this.moduleCount;},make:function(){this.makeImpl(false,this.getBestMaskPattern());},makeImpl:function(test,maskPattern){this.moduleCount=this.typeNumber*4+17;this.modules=new Array(this.moduleCount);for(var row=0;row=7){this.setupTypeNumber(test);} + if(this.dataCache==null){this.dataCache=QRCodeModel.createData(this.typeNumber,this.errorCorrectLevel,this.dataList);} + this.mapData(this.dataCache,maskPattern);},setupPositionProbePattern:function(row,col){for(var r=-1;r<=7;r++){if(row+r<=-1||this.moduleCount<=row+r)continue;for(var c=-1;c<=7;c++){if(col+c<=-1||this.moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}},getBestMaskPattern:function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i++){this.makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}} + return pattern;},createMovieClip:function(target_mc,instance_name,depth){var qr_mc=target_mc.createEmptyMovieClip(instance_name,depth);var cs=1;this.make();for(var row=0;row>i)&1)==1);this.modules[Math.floor(i/3)][i%3+this.moduleCount-8-3]=mod;} + for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[i%3+this.moduleCount-8-3][Math.floor(i/3)]=mod;}},setupTypeInfo:function(test,maskPattern){var data=(this.errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<6){this.modules[i][8]=mod;}else if(i<8){this.modules[i+1][8]=mod;}else{this.modules[this.moduleCount-15+i][8]=mod;}} + for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<8){this.modules[8][this.moduleCount-i-1]=mod;}else if(i<9){this.modules[8][15-i-1+1]=mod;}else{this.modules[8][15-i-1]=mod;}} + this.modules[this.moduleCount-8][8]=(!test);},mapData:function(data,maskPattern){var inc=-1;var row=this.moduleCount-1;var bitIndex=7;var byteIndex=0;for(var col=this.moduleCount-1;col>0;col-=2){if(col==6)col--;while(true){for(var c=0;c<2;c++){if(this.modules[row][col-c]==null){var dark=false;if(byteIndex>>bitIndex)&1)==1);} + var mask=QRUtil.getMask(maskPattern,row,col-c);if(mask){dark=!dark;} + this.modules[row][col-c]=dark;bitIndex--;if(bitIndex==-1){byteIndex++;bitIndex=7;}}} + row+=inc;if(row<0||this.moduleCount<=row){row-=inc;inc=-inc;break;}}}}};QRCodeModel.PAD0=0xEC;QRCodeModel.PAD1=0x11;QRCodeModel.createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=new QRBitBuffer();for(var i=0;itotalDataCount*8){throw new Error("code length overflow. (" + +buffer.getLengthInBits() + +">" + +totalDataCount*8 + +")");} + if(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);} + while(buffer.getLengthInBits()%8!=0){buffer.putBit(false);} + while(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;} + buffer.put(QRCodeModel.PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;} + buffer.put(QRCodeModel.PAD1,8);} + return QRCodeModel.createBytes(buffer,rsBlocks);};QRCodeModel.createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r=0)?modPoly.get(modIndex):0;}} + var totalCodeCount=0;for(var i=0;i=0){d^=(QRUtil.G15<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)));} + return((data<<10)|d)^QRUtil.G15_MASK;},getBCHTypeNumber:function(data){var d=data<<12;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)>=0){d^=(QRUtil.G18<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)));} + return(data<<12)|d;},getBCHDigit:function(data){var digit=0;while(data!=0){digit++;data>>>=1;} + return digit;},getPatternPosition:function(typeNumber){return QRUtil.PATTERN_POSITION_TABLE[typeNumber-1];},getMask:function(maskPattern,i,j){switch(maskPattern){case QRMaskPattern.PATTERN000:return(i+j)%2==0;case QRMaskPattern.PATTERN001:return i%2==0;case QRMaskPattern.PATTERN010:return j%3==0;case QRMaskPattern.PATTERN011:return(i+j)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(i/2)+Math.floor(j/3))%2==0;case QRMaskPattern.PATTERN101:return(i*j)%2+(i*j)%3==0;case QRMaskPattern.PATTERN110:return((i*j)%2+(i*j)%3)%2==0;case QRMaskPattern.PATTERN111:return((i*j)%3+(i+j)%2)%2==0;default:throw new Error("bad maskPattern:"+maskPattern);}},getErrorCorrectPolynomial:function(errorCorrectLength){var a=new QRPolynomial([1],0);for(var i=0;i5){lostPoint+=(3+sameCount-5);}}} + for(var row=0;row=256){n-=255;} + return QRMath.EXP_TABLE[n];},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var i=0;i<8;i++){QRMath.EXP_TABLE[i]=1<>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);} + if(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));} + this.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]]; + + function _isSupportCanvas() { + return typeof CanvasRenderingContext2D != "undefined"; + } + + // android 2.x doesn't support Data-URI spec + function _getAndroid() { + var android = false; + var sAgent = navigator.userAgent; + + if (/android/i.test(sAgent)) { // android + android = true; + var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i); + + if (aMat && aMat[1]) { + android = parseFloat(aMat[1]); + } + } + + return android; + } + + var svgDrawer = (function() { + + var Drawing = function (el, htOption) { + this._el = el; + this._htOption = htOption; + }; + + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption; + var _el = this._el; + var nCount = oQRCode.getModuleCount(); + var nWidth = Math.floor(_htOption.width / nCount); + var nHeight = Math.floor(_htOption.height / nCount); + + this.clear(); + + function makeSVG(tag, attrs) { + var el = document.createElementNS('http://www.w3.org/2000/svg', tag); + for (var k in attrs) + if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]); + return el; + } + + var svg = makeSVG("svg" , {'viewBox': '0 0 ' + String(nCount) + " " + String(nCount), 'width': '100%', 'height': '100%', 'fill': _htOption.colorLight}); + svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink"); + _el.appendChild(svg); + + svg.appendChild(makeSVG("rect", {"fill": _htOption.colorLight, "width": "100%", "height": "100%"})); + svg.appendChild(makeSVG("rect", {"fill": _htOption.colorDark, "width": "1", "height": "1", "id": "template"})); + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + if (oQRCode.isDark(row, col)) { + var child = makeSVG("use", {"x": String(col), "y": String(row)}); + child.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#template"); + svg.appendChild(child); + } + } + } + }; + Drawing.prototype.clear = function () { + while (this._el.hasChildNodes()) + this._el.removeChild(this._el.lastChild); + }; + return Drawing; + })(); + + var useSVG = document.documentElement.tagName.toLowerCase() === "svg"; + + // Drawing in DOM by using Table tag + var Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () { + var Drawing = function (el, htOption) { + this._el = el; + this._htOption = htOption; + }; + + /** + * Draw the QRCode + * + * @param {QRCode} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption; + var _el = this._el; + var nCount = oQRCode.getModuleCount(); + var nWidth = Math.floor(_htOption.width / nCount); + var nHeight = Math.floor(_htOption.height / nCount); + var aHTML = ['']; + + for (var row = 0; row < nCount; row++) { + aHTML.push(''); + + for (var col = 0; col < nCount; col++) { + aHTML.push(''); + } + + aHTML.push(''); + } + + aHTML.push('
'); + _el.innerHTML = aHTML.join(''); + + // Fix the margin values as real size. + var elTable = _el.childNodes[0]; + var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2; + var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2; + + if (nLeftMarginTable > 0 && nTopMarginTable > 0) { + elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px"; + } + }; + + /** + * Clear the QRCode + */ + Drawing.prototype.clear = function () { + this._el.innerHTML = ''; + }; + + return Drawing; + })() : (function () { // Drawing in Canvas + function _onMakeImage() { + this._elImage.src = this._elCanvas.toDataURL("image/png"); + this._elImage.style.display = "block"; + this._elCanvas.style.display = "none"; + } + + // Android 2.1 bug workaround + // http://code.google.com/p/android/issues/detail?id=5141 + if (this._android && this._android <= 2.1) { + var factor = 1 / window.devicePixelRatio; + var drawImage = CanvasRenderingContext2D.prototype.drawImage; + CanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) { + if (("nodeName" in image) && /img/i.test(image.nodeName)) { + for (var i = arguments.length - 1; i >= 1; i--) { + arguments[i] = arguments[i] * factor; + } + } else if (typeof dw == "undefined") { + arguments[1] *= factor; + arguments[2] *= factor; + arguments[3] *= factor; + arguments[4] *= factor; + } + + drawImage.apply(this, arguments); + }; + } + + /** + * Check whether the user's browser supports Data URI or not + * + * @private + * @param {Function} fSuccess Occurs if it supports Data URI + * @param {Function} fFail Occurs if it doesn't support Data URI + */ + function _safeSetDataURI(fSuccess, fFail) { + var self = this; + self._fFail = fFail; + self._fSuccess = fSuccess; + + // Check it just once + if (self._bSupportDataURI === null) { + var el = document.createElement("img"); + var fOnError = function() { + self._bSupportDataURI = false; + + if (self._fFail) { + self._fFail.call(self); + } + }; + var fOnSuccess = function() { + self._bSupportDataURI = true; + + if (self._fSuccess) { + self._fSuccess.call(self); + } + }; + + el.onabort = fOnError; + el.onerror = fOnError; + el.onload = fOnSuccess; + el.src = "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // the Image contains 1px data. + return; + } else if (self._bSupportDataURI === true && self._fSuccess) { + self._fSuccess.call(self); + } else if (self._bSupportDataURI === false && self._fFail) { + self._fFail.call(self); + } + }; + + /** + * Drawing QRCode by using canvas + * + * @constructor + * @param {HTMLElement} el + * @param {Object} htOption QRCode Options + */ + var Drawing = function (el, htOption) { + this._bIsPainted = false; + this._android = _getAndroid(); + + this._htOption = htOption; + this._elCanvas = document.createElement("canvas"); + this._elCanvas.width = htOption.width; + this._elCanvas.height = htOption.height; + el.appendChild(this._elCanvas); + this._el = el; + this._oContext = this._elCanvas.getContext("2d"); + this._bIsPainted = false; + this._elImage = document.createElement("img"); + this._elImage.alt = "Scan me!"; + this._elImage.style.display = "none"; + this._el.appendChild(this._elImage); + this._bSupportDataURI = null; + }; + + /** + * Draw the QRCode + * + * @param {QRCode} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _elImage = this._elImage; + var _oContext = this._oContext; + var _htOption = this._htOption; + + var nCount = oQRCode.getModuleCount(); + var nWidth = _htOption.width / nCount; + var nHeight = _htOption.height / nCount; + var nRoundedWidth = Math.round(nWidth); + var nRoundedHeight = Math.round(nHeight); + + _elImage.style.display = "none"; + this.clear(); + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + var bIsDark = oQRCode.isDark(row, col); + var nLeft = col * nWidth; + var nTop = row * nHeight; + _oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.lineWidth = 1; + _oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.fillRect(nLeft, nTop, nWidth, nHeight); + + // 안티 앨리어싱 방지 처리 + _oContext.strokeRect( + Math.floor(nLeft) + 0.5, + Math.floor(nTop) + 0.5, + nRoundedWidth, + nRoundedHeight + ); + + _oContext.strokeRect( + Math.ceil(nLeft) - 0.5, + Math.ceil(nTop) - 0.5, + nRoundedWidth, + nRoundedHeight + ); + } + } + + this._bIsPainted = true; + }; + + /** + * Make the image from Canvas if the browser supports Data URI. + */ + Drawing.prototype.makeImage = function () { + if (this._bIsPainted) { + _safeSetDataURI.call(this, _onMakeImage); + } + }; + + /** + * Return whether the QRCode is painted or not + * + * @return {Boolean} + */ + Drawing.prototype.isPainted = function () { + return this._bIsPainted; + }; + + /** + * Clear the QRCode + */ + Drawing.prototype.clear = function () { + this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height); + this._bIsPainted = false; + }; + + /** + * @private + * @param {Number} nNumber + */ + Drawing.prototype.round = function (nNumber) { + if (!nNumber) { + return nNumber; + } + + return Math.floor(nNumber * 1000) / 1000; + }; + + return Drawing; + })(); + + /** + * Get the type by string length + * + * @private + * @param {String} sText + * @param {Number} nCorrectLevel + * @return {Number} type + */ + function _getTypeNumber(sText, nCorrectLevel) { + var nType = 1; + var length = _getUTF8Length(sText); + + for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) { + var nLimit = 0; + + switch (nCorrectLevel) { + case QRErrorCorrectLevel.L : + nLimit = QRCodeLimitLength[i][0]; + break; + case QRErrorCorrectLevel.M : + nLimit = QRCodeLimitLength[i][1]; + break; + case QRErrorCorrectLevel.Q : + nLimit = QRCodeLimitLength[i][2]; + break; + case QRErrorCorrectLevel.H : + nLimit = QRCodeLimitLength[i][3]; + break; + } + + if (length <= nLimit) { + break; + } else { + nType++; + } + } + + if (nType > QRCodeLimitLength.length) { + throw new Error("Too long data"); + } + + return nType; + } + + function _getUTF8Length(sText) { + var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a'); + return replacedText.length + (replacedText.length != sText ? 3 : 0); + } + + /** + * @class QRCode + * @constructor + * @example + * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie"); + * + * @example + * var oQRCode = new QRCode("test", { + * text : "http://naver.com", + * width : 128, + * height : 128 + * }); + * + * oQRCode.clear(); // Clear the QRCode. + * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode. + * + * @param {HTMLElement|String} el target element or 'id' attribute of element. + * @param {Object|String} vOption + * @param {String} vOption.text QRCode link data + * @param {Number} [vOption.width=256] + * @param {Number} [vOption.height=256] + * @param {String} [vOption.colorDark="#000000"] + * @param {String} [vOption.colorLight="#ffffff"] + * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H] + */ + QRCode = function (el, vOption) { + this._htOption = { + width : 256, + height : 256, + typeNumber : 4, + colorDark : "#000000", + colorLight : "#ffffff", + correctLevel : QRErrorCorrectLevel.H + }; + + if (typeof vOption === 'string') { + vOption = { + text : vOption + }; + } + + // Overwrites options + if (vOption) { + for (var i in vOption) { + this._htOption[i] = vOption[i]; + } + } + + if (typeof el == "string") { + el = document.getElementById(el); + } + + if (this._htOption.useSVG) { + Drawing = svgDrawer; + } + + this._android = _getAndroid(); + this._el = el; + this._oQRCode = null; + this._oDrawing = new Drawing(this._el, this._htOption); + + if (this._htOption.text) { + this.makeCode(this._htOption.text); + } + }; + + /** + * Make the QRCode + * + * @param {String} sText link data + */ + QRCode.prototype.makeCode = function (sText) { + this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel); + this._oQRCode.addData(sText); + this._oQRCode.make(); + this._el.title = sText; + this._oDrawing.draw(this._oQRCode); + this.makeImage(); + }; + + /** + * Make the Image from Canvas element + * - It occurs automatically + * - Android below 3 doesn't support Data-URI spec. + * + * @private + */ + QRCode.prototype.makeImage = function () { + if (typeof this._oDrawing.makeImage == "function" && (!this._android || this._android >= 3)) { + this._oDrawing.makeImage(); + } + }; + + /** + * Clear the QRCode + */ + QRCode.prototype.clear = function () { + this._oDrawing.clear(); + }; + + /** + * @name QRCode.CorrectLevel + */ + QRCode.CorrectLevel = QRErrorCorrectLevel; + + module.exports = { + makeQRcode : function(el, vOption){ + var qrcode = new QRCode(el, vOption); + return qrcode._oDrawing._elCanvas.toDataURL(); + } + } +})(); diff --git a/plugins/phonegap-plugin-barcodescanner/src/browser/BarcodeScannerProxy.js b/plugins/phonegap-plugin-barcodescanner/src/browser/BarcodeScannerProxy.js new file mode 100644 index 0000000..6670dc6 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/browser/BarcodeScannerProxy.js @@ -0,0 +1,24 @@ +function scan(success, error) { + var code = window.prompt("Enter barcode value (empty value will fire the error handler):"); + if(code) { + var result = { + text:code, + format:"Fake", + cancelled:false + }; + success(result); + } else { + error("No barcode"); + } +} + +function encode(type, data, success, errorCallback) { + success(); +} + +module.exports = { + scan: scan, + encode: encode +}; + +require("cordova/exec/proxy").add("BarcodeScanner",module.exports); \ No newline at end of file diff --git a/plugins/phonegap-plugin-barcodescanner/src/ios/CDVBarcodeScanner.bundle/beep.caf b/plugins/phonegap-plugin-barcodescanner/src/ios/CDVBarcodeScanner.bundle/beep.caf new file mode 100644 index 0000000..4bce167 Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/ios/CDVBarcodeScanner.bundle/beep.caf differ diff --git a/plugins/phonegap-plugin-barcodescanner/src/ios/CDVBarcodeScanner.mm b/plugins/phonegap-plugin-barcodescanner/src/ios/CDVBarcodeScanner.mm new file mode 100644 index 0000000..b95d891 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/ios/CDVBarcodeScanner.mm @@ -0,0 +1,1118 @@ +/* + * PhoneGap is available under *either* the terms of the modified BSD license *or* the + * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. + * + * Copyright 2011 Matt Kane. All rights reserved. + * Copyright (c) 2011, IBM Corporation + */ + +#import +#import +#import +#import +#import + +//------------------------------------------------------------------------------ +// use the all-in-one version of zxing that we built +//------------------------------------------------------------------------------ +#import "zxing-all-in-one.h" +#import + + +//------------------------------------------------------------------------------ +// Delegate to handle orientation functions +//------------------------------------------------------------------------------ +@protocol CDVBarcodeScannerOrientationDelegate + +- (NSUInteger)supportedInterfaceOrientations; +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; +- (BOOL)shouldAutorotate; + +@end + +//------------------------------------------------------------------------------ +// Adds a shutter button to the UI, and changes the scan from continuous to +// only performing a scan when you click the shutter button. For testing. +//------------------------------------------------------------------------------ +#define USE_SHUTTER 0 + +//------------------------------------------------------------------------------ +@class CDVbcsProcessor; +@class CDVbcsViewController; + +//------------------------------------------------------------------------------ +// plugin class +//------------------------------------------------------------------------------ +@interface CDVBarcodeScanner : CDVPlugin {} +- (NSString*)isScanNotPossible; +- (void)scan:(CDVInvokedUrlCommand*)command; +- (void)encode:(CDVInvokedUrlCommand*)command; +- (void)returnImage:(NSString*)filePath format:(NSString*)format callback:(NSString*)callback; +- (void)returnSuccess:(NSString*)scannedText format:(NSString*)format cancelled:(BOOL)cancelled flipped:(BOOL)flipped callback:(NSString*)callback; +- (void)returnError:(NSString*)message callback:(NSString*)callback; +@end + +//------------------------------------------------------------------------------ +// class that does the grunt work +//------------------------------------------------------------------------------ +@interface CDVbcsProcessor : NSObject {} +@property (nonatomic, retain) CDVBarcodeScanner* plugin; +@property (nonatomic, retain) NSString* callback; +@property (nonatomic, retain) UIViewController* parentViewController; +@property (nonatomic, retain) CDVbcsViewController* viewController; +@property (nonatomic, retain) AVCaptureSession* captureSession; +@property (nonatomic, retain) AVCaptureVideoPreviewLayer* previewLayer; +@property (nonatomic, retain) NSString* alternateXib; +@property (nonatomic, retain) NSMutableArray* results; +@property (nonatomic, retain) NSString* formats; +@property (nonatomic) BOOL is1D; +@property (nonatomic) BOOL is2D; +@property (nonatomic) BOOL capturing; +@property (nonatomic) BOOL isFrontCamera; +@property (nonatomic) BOOL isShowFlipCameraButton; +@property (nonatomic) BOOL isFlipped; + + +- (id)initWithPlugin:(CDVBarcodeScanner*)plugin callback:(NSString*)callback parentViewController:(UIViewController*)parentViewController alterateOverlayXib:(NSString *)alternateXib; +- (void)scanBarcode; +- (void)barcodeScanSucceeded:(NSString*)text format:(NSString*)format; +- (void)barcodeScanFailed:(NSString*)message; +- (void)barcodeScanCancelled; +- (void)openDialog; +- (NSString*)setUpCaptureSession; +- (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection; +- (NSString*)formatStringFrom:(zxing::BarcodeFormat)format; +- (UIImage*)getImageFromSample:(CMSampleBufferRef)sampleBuffer; +- (zxing::Ref) getLuminanceSourceFromSample:(CMSampleBufferRef)sampleBuffer imageBytes:(uint8_t**)ptr; +- (UIImage*) getImageFromLuminanceSource:(zxing::LuminanceSource*)luminanceSource; +- (void)dumpImage:(UIImage*)image; +@end + +//------------------------------------------------------------------------------ +// Qr encoder processor +//------------------------------------------------------------------------------ +@interface CDVqrProcessor: NSObject +@property (nonatomic, retain) CDVBarcodeScanner* plugin; +@property (nonatomic, retain) NSString* callback; +@property (nonatomic, retain) NSString* stringToEncode; +@property NSInteger size; + +- (id)initWithPlugin:(CDVBarcodeScanner*)plugin callback:(NSString*)callback stringToEncode:(NSString*)stringToEncode; +- (void)generateImage; +@end + +//------------------------------------------------------------------------------ +// view controller for the ui +//------------------------------------------------------------------------------ +@interface CDVbcsViewController : UIViewController {} +@property (nonatomic, retain) CDVbcsProcessor* processor; +@property (nonatomic, retain) NSString* alternateXib; +@property (nonatomic) BOOL shutterPressed; +@property (nonatomic, retain) IBOutlet UIView* overlayView; +// unsafe_unretained is equivalent to assign - used to prevent retain cycles in the property below +@property (nonatomic, unsafe_unretained) id orientationDelegate; + +- (id)initWithProcessor:(CDVbcsProcessor*)processor alternateOverlay:(NSString *)alternateXib; +- (void)startCapturing; +- (UIView*)buildOverlayView; +- (UIImage*)buildReticleImage; +- (void)shutterButtonPressed; +- (IBAction)cancelButtonPressed:(id)sender; + +@end + +//------------------------------------------------------------------------------ +// plugin class +//------------------------------------------------------------------------------ +@implementation CDVBarcodeScanner + +//-------------------------------------------------------------------------- +- (NSString*)isScanNotPossible { + NSString* result = nil; + + Class aClass = NSClassFromString(@"AVCaptureSession"); + if (aClass == nil) { + return @"AVFoundation Framework not available"; + } + + return result; +} + +//-------------------------------------------------------------------------- +- (void)scan:(CDVInvokedUrlCommand*)command { + CDVbcsProcessor* processor; + NSString* callback; + NSString* capabilityError; + + callback = command.callbackId; + + NSDictionary* options = command.arguments.count == 0 ? [NSNull null] : [command.arguments objectAtIndex:0]; + + if ([options isKindOfClass:[NSNull class]]) { + options = [NSDictionary dictionary]; + } + BOOL preferFrontCamera = [options[@"preferFrontCamera"] boolValue]; + BOOL showFlipCameraButton = [options[@"showFlipCameraButton"] boolValue]; + // We allow the user to define an alternate xib file for loading the overlay. + NSString *overlayXib = [options objectForKey:@"overlayXib"]; + + capabilityError = [self isScanNotPossible]; + if (capabilityError) { + [self returnError:capabilityError callback:callback]; + return; + } + + processor = [[CDVbcsProcessor alloc] + initWithPlugin:self + callback:callback + parentViewController:self.viewController + alterateOverlayXib:overlayXib + ]; + // queue [processor scanBarcode] to run on the event loop + + if (preferFrontCamera) { + processor.isFrontCamera = true; + } + + if (showFlipCameraButton) { + processor.isShowFlipCameraButton = true; + } + + processor.formats = options[@"formats"]; + + [processor performSelector:@selector(scanBarcode) withObject:nil afterDelay:0]; +} + +//-------------------------------------------------------------------------- +- (void)encode:(CDVInvokedUrlCommand*)command { + if([command.arguments count] < 1) + [self returnError:@"Too few arguments!" callback:command.callbackId]; + + CDVqrProcessor* processor; + NSString* callback; + callback = command.callbackId; + + processor = [[CDVqrProcessor alloc] + initWithPlugin:self + callback:callback + stringToEncode: command.arguments[0][@"data"] + ]; + + [processor retain]; + [processor retain]; + [processor retain]; + // queue [processor generateImage] to run on the event loop + [processor performSelector:@selector(generateImage) withObject:nil afterDelay:0]; +} + +- (void)returnImage:(NSString*)filePath format:(NSString*)format callback:(NSString*)callback{ + NSMutableDictionary* resultDict = [[[NSMutableDictionary alloc] init] autorelease]; + [resultDict setObject:format forKey:@"format"]; + [resultDict setObject:filePath forKey:@"file"]; + + CDVPluginResult* result = [CDVPluginResult + resultWithStatus: CDVCommandStatus_OK + messageAsDictionary:resultDict + ]; + + [[self commandDelegate] sendPluginResult:result callbackId:callback]; +} + +//-------------------------------------------------------------------------- +- (void)returnSuccess:(NSString*)scannedText format:(NSString*)format cancelled:(BOOL)cancelled flipped:(BOOL)flipped callback:(NSString*)callback{ + NSNumber* cancelledNumber = [NSNumber numberWithInt:(cancelled?1:0)]; + + NSMutableDictionary* resultDict = [[NSMutableDictionary alloc] init]; + [resultDict setObject:scannedText forKey:@"text"]; + [resultDict setObject:format forKey:@"format"]; + [resultDict setObject:cancelledNumber forKey:@"cancelled"]; + + CDVPluginResult* result = [CDVPluginResult + resultWithStatus: CDVCommandStatus_OK + messageAsDictionary: resultDict + ]; + [self.commandDelegate sendPluginResult:result callbackId:callback]; +} + +//-------------------------------------------------------------------------- +- (void)returnError:(NSString*)message callback:(NSString*)callback { + CDVPluginResult* result = [CDVPluginResult + resultWithStatus: CDVCommandStatus_ERROR + messageAsString: message + ]; + + [self.commandDelegate sendPluginResult:result callbackId:callback]; +} + +@end + +//------------------------------------------------------------------------------ +// class that does the grunt work +//------------------------------------------------------------------------------ +@implementation CDVbcsProcessor + +@synthesize plugin = _plugin; +@synthesize callback = _callback; +@synthesize parentViewController = _parentViewController; +@synthesize viewController = _viewController; +@synthesize captureSession = _captureSession; +@synthesize previewLayer = _previewLayer; +@synthesize alternateXib = _alternateXib; +@synthesize is1D = _is1D; +@synthesize is2D = _is2D; +@synthesize capturing = _capturing; +@synthesize results = _results; + +SystemSoundID _soundFileObject; + +//-------------------------------------------------------------------------- +- (id)initWithPlugin:(CDVBarcodeScanner*)plugin + callback:(NSString*)callback +parentViewController:(UIViewController*)parentViewController + alterateOverlayXib:(NSString *)alternateXib { + self = [super init]; + if (!self) return self; + + self.plugin = plugin; + self.callback = callback; + self.parentViewController = parentViewController; + self.alternateXib = alternateXib; + + self.is1D = YES; + self.is2D = YES; + self.capturing = NO; + self.results = [NSMutableArray new]; + + CFURLRef soundFileURLRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("CDVBarcodeScanner.bundle/beep"), CFSTR ("caf"), NULL); + AudioServicesCreateSystemSoundID(soundFileURLRef, &_soundFileObject); + + return self; +} + +//-------------------------------------------------------------------------- +- (void)dealloc { + self.plugin = nil; + self.callback = nil; + self.parentViewController = nil; + self.viewController = nil; + self.captureSession = nil; + self.previewLayer = nil; + self.alternateXib = nil; + self.results = nil; + + self.capturing = NO; + + AudioServicesRemoveSystemSoundCompletion(_soundFileObject); + AudioServicesDisposeSystemSoundID(_soundFileObject); + + [super dealloc]; +} + +//-------------------------------------------------------------------------- +- (void)scanBarcode { + +// self.captureSession = nil; +// self.previewLayer = nil; + NSString* errorMessage = [self setUpCaptureSession]; + if (errorMessage) { + [self barcodeScanFailed:errorMessage]; + return; + } + + self.viewController = [[CDVbcsViewController alloc] initWithProcessor: self alternateOverlay:self.alternateXib]; + // here we set the orientation delegate to the MainViewController of the app (orientation controlled in the Project Settings) + self.viewController.orientationDelegate = self.plugin.viewController; + + // delayed [self openDialog]; + [self performSelector:@selector(openDialog) withObject:nil afterDelay:1]; +} + +//-------------------------------------------------------------------------- +- (void)openDialog { + [self.parentViewController + presentViewController:self.viewController + animated:YES completion:nil + ]; +} + +//-------------------------------------------------------------------------- +- (void)barcodeScanDone:(void (^)(void))callbackBlock { + self.capturing = NO; + [self.captureSession stopRunning]; + [self.parentViewController dismissViewControllerAnimated:YES completion:callbackBlock]; + + // viewcontroller holding onto a reference to us, release them so they + // will release us + self.viewController = nil; +} + +//-------------------------------------------------------------------------- +- (BOOL)checkResult:(NSString *)result { + [self.results addObject:result]; + + NSInteger treshold = 7; + + if (self.results.count > treshold) { + [self.results removeObjectAtIndex:0]; + } + + if (self.results.count < treshold) + { + return NO; + } + + BOOL allEqual = YES; + NSString *compareString = [self.results objectAtIndex:0]; + + for (NSString *aResult in self.results) + { + if (![compareString isEqualToString:aResult]) + { + allEqual = NO; + //NSLog(@"Did not fit: %@",self.results); + break; + } + } + + return allEqual; +} + +//-------------------------------------------------------------------------- +- (void)barcodeScanSucceeded:(NSString*)text format:(NSString*)format { + dispatch_sync(dispatch_get_main_queue(), ^{ + [self barcodeScanDone:^{ + [self.plugin returnSuccess:text format:format cancelled:FALSE flipped:FALSE callback:self.callback]; + }]; + AudioServicesPlaySystemSound(_soundFileObject); + }); +} + +//-------------------------------------------------------------------------- +- (void)barcodeScanFailed:(NSString*)message { + [self barcodeScanDone:^{ + [self.plugin returnError:message callback:self.callback]; + }]; +} + +//-------------------------------------------------------------------------- +- (void)barcodeScanCancelled { + [self barcodeScanDone:^{ + [self.plugin returnSuccess:@"" format:@"" cancelled:TRUE flipped:self.isFlipped callback:self.callback]; + }]; + if (self.isFlipped) { + self.isFlipped = NO; + } +} + +- (void)flipCamera { + self.isFlipped = YES; + self.isFrontCamera = !self.isFrontCamera; + [self barcodeScanDone]; + if (self.isFlipped) { + self.isFlipped = NO; + } + [self performSelector:@selector(scanBarcode) withObject:nil afterDelay:0.1]; +} + +//-------------------------------------------------------------------------- +- (NSString*)setUpCaptureSession { + NSError* error = nil; + + AVCaptureSession* captureSession = [[AVCaptureSession alloc] init]; + self.captureSession = captureSession; + + AVCaptureDevice* __block device = nil; + if (self.isFrontCamera) { + + NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + [devices enumerateObjectsUsingBlock:^(AVCaptureDevice *obj, NSUInteger idx, BOOL *stop) { + if (obj.position == AVCaptureDevicePositionFront) { + device = obj; + } + }]; + } else { + device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if (!device) return @"unable to obtain video capture device"; + + } + + + AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error]; + if (!input) return @"unable to obtain video capture device input"; + + AVCaptureVideoDataOutput* output = [[AVCaptureVideoDataOutput alloc] init]; + if (!output) return @"unable to obtain video capture output"; + + NSDictionary* videoOutputSettings = [NSDictionary + dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] + forKey:(id)kCVPixelBufferPixelFormatTypeKey + ]; + + output.alwaysDiscardsLateVideoFrames = YES; + output.videoSettings = videoOutputSettings; + + [output setSampleBufferDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)]; + + if ([captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) { + captureSession.sessionPreset = AVCaptureSessionPresetHigh; + } else if ([captureSession canSetSessionPreset:AVCaptureSessionPresetMedium]) { + captureSession.sessionPreset = AVCaptureSessionPresetMedium; + } else { + return @"unable to preset high nor medium quality video capture"; + } + + if ([captureSession canAddInput:input]) { + [captureSession addInput:input]; + } + else { + return @"unable to add video capture device input to session"; + } + + if ([captureSession canAddOutput:output]) { + [captureSession addOutput:output]; + } + else { + return @"unable to add video capture output to session"; + } + + // setup capture preview layer + self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession]; + + // run on next event loop pass [captureSession startRunning] + [captureSession performSelector:@selector(startRunning) withObject:nil afterDelay:0]; + + return nil; +} + +//-------------------------------------------------------------------------- +// this method gets sent the captured frames +//-------------------------------------------------------------------------- +- (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection { + + if (!self.capturing) return; + +#if USE_SHUTTER + if (!self.viewController.shutterPressed) return; + self.viewController.shutterPressed = NO; + + UIView* flashView = [[UIView alloc] initWithFrame:self.viewController.view.frame]; + [flashView setBackgroundColor:[UIColor whiteColor]]; + [self.viewController.view.window addSubview:flashView]; + + [UIView + animateWithDuration:.4f + animations:^{ + [flashView setAlpha:0.f]; + } + completion:^(BOOL finished){ + [flashView removeFromSuperview]; + } + ]; + + // [self dumpImage: [[self getImageFromSample:sampleBuffer] autorelease]]; +#endif + + + using namespace zxing; + + // LuminanceSource is pretty dumb; we have to give it a pointer to + // a byte array, but then can't get it back out again. We need to + // get it back to free it. Saving it in imageBytes. + uint8_t* imageBytes; + + // NSTimeInterval timeStart = [NSDate timeIntervalSinceReferenceDate]; + + try { + NSArray *supportedFormats = nil; + if (self.formats != nil) { + supportedFormats = [self.formats componentsSeparatedByString:@","]; + } + DecodeHints decodeHints; + if (supportedFormats == nil || [supportedFormats containsObject:[self formatStringFrom:BarcodeFormat_QR_CODE]]) { + decodeHints.addFormat(BarcodeFormat_QR_CODE); + } + if (supportedFormats == nil || [supportedFormats containsObject:[self formatStringFrom:BarcodeFormat_CODE_128]]) { + decodeHints.addFormat(BarcodeFormat_CODE_128); + } + if (supportedFormats == nil || [supportedFormats containsObject:[self formatStringFrom:BarcodeFormat_CODE_39]]) { + decodeHints.addFormat(BarcodeFormat_CODE_39); + } + if (supportedFormats == nil || [supportedFormats containsObject:[self formatStringFrom:BarcodeFormat_DATA_MATRIX]]) { + decodeHints.addFormat(BarcodeFormat_DATA_MATRIX); + } + if (supportedFormats == nil || [supportedFormats containsObject:[self formatStringFrom:BarcodeFormat_UPC_E]]) { + decodeHints.addFormat(BarcodeFormat_UPC_E); + } + if (supportedFormats == nil || [supportedFormats containsObject:[self formatStringFrom:BarcodeFormat_UPC_A]]) { + decodeHints.addFormat(BarcodeFormat_UPC_A); + } + if (supportedFormats == nil || [supportedFormats containsObject:[self formatStringFrom:BarcodeFormat_EAN_8]]) { + decodeHints.addFormat(BarcodeFormat_EAN_8); + } + if (supportedFormats == nil || [supportedFormats containsObject:[self formatStringFrom:BarcodeFormat_EAN_13]]) { + decodeHints.addFormat(BarcodeFormat_EAN_13); + } +// decodeHints.addFormat(BarcodeFormat_ITF); causing crashes + + // here's the meat of the decode process + Ref luminanceSource ([self getLuminanceSourceFromSample: sampleBuffer imageBytes:&imageBytes]); + // [self dumpImage: [[self getImageFromLuminanceSource:luminanceSource] autorelease]]; + Ref binarizer (new HybridBinarizer(luminanceSource)); + Ref bitmap (new BinaryBitmap(binarizer)); + Ref reader (new MultiFormatReader()); + Ref result (reader->decode(bitmap, decodeHints)); + Ref resultText (result->getText()); + BarcodeFormat formatVal = result->getBarcodeFormat(); + NSString* format = [self formatStringFrom:formatVal]; + + + const char* cString = resultText->getText().c_str(); + NSString* resultString = [[NSString alloc] initWithCString:cString encoding:NSUTF8StringEncoding]; + + if ([self checkResult:resultString]) { + [self barcodeScanSucceeded:resultString format:format]; + } + } + catch (zxing::ReaderException &rex) { + // NSString *message = [[[NSString alloc] initWithCString:rex.what() encoding:NSUTF8StringEncoding] autorelease]; + // NSLog(@"decoding: ReaderException: %@", message); + } + catch (zxing::IllegalArgumentException &iex) { + // NSString *message = [[[NSString alloc] initWithCString:iex.what() encoding:NSUTF8StringEncoding] autorelease]; + // NSLog(@"decoding: IllegalArgumentException: %@", message); + } + catch (...) { + // NSLog(@"decoding: unknown exception"); + // [self barcodeScanFailed:@"unknown exception decoding barcode"]; + } + + // NSTimeInterval timeElapsed = [NSDate timeIntervalSinceReferenceDate] - timeStart; + // NSLog(@"decoding completed in %dms", (int) (timeElapsed * 1000)); + + // free the buffer behind the LuminanceSource + if (imageBytes) { + free(imageBytes); + } +} + +//-------------------------------------------------------------------------- +// convert barcode format to string +//-------------------------------------------------------------------------- +- (NSString*)formatStringFrom:(zxing::BarcodeFormat)format { + if (format == zxing::BarcodeFormat_QR_CODE) return @"QR_CODE"; + if (format == zxing::BarcodeFormat_DATA_MATRIX) return @"DATA_MATRIX"; + if (format == zxing::BarcodeFormat_UPC_E) return @"UPC_E"; + if (format == zxing::BarcodeFormat_UPC_A) return @"UPC_A"; + if (format == zxing::BarcodeFormat_EAN_8) return @"EAN_8"; + if (format == zxing::BarcodeFormat_EAN_13) return @"EAN_13"; + if (format == zxing::BarcodeFormat_CODE_128) return @"CODE_128"; + if (format == zxing::BarcodeFormat_CODE_39) return @"CODE_39"; + if (format == zxing::BarcodeFormat_ITF) return @"ITF"; + return @"???"; +} + +//-------------------------------------------------------------------------- +// convert capture's sample buffer (scanned picture) into the thing that +// zxing needs. +//-------------------------------------------------------------------------- +- (zxing::Ref) getLuminanceSourceFromSample:(CMSampleBufferRef)sampleBuffer imageBytes:(uint8_t**)ptr { + CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); + CVPixelBufferLockBaseAddress(imageBuffer, 0); + + size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); + size_t width = CVPixelBufferGetWidth(imageBuffer); + size_t height = CVPixelBufferGetHeight(imageBuffer); + uint8_t* baseAddress = (uint8_t*) CVPixelBufferGetBaseAddress(imageBuffer); + + // only going to get 90% of the min(width,height) of the captured image + size_t greyWidth = 9 * MIN(width, height) / 10; + uint8_t* greyData = (uint8_t*) malloc(greyWidth * greyWidth); + + // remember this pointer so we can free it later + *ptr = greyData; + + if (!greyData) { + CVPixelBufferUnlockBaseAddress(imageBuffer,0); + throw new zxing::ReaderException("out of memory"); + } + + size_t offsetX = (width - greyWidth) / 2; + size_t offsetY = (height - greyWidth) / 2; + + // pixel-by-pixel ... + for (size_t i=0; i luminanceSource ( + new GreyscaleLuminanceSource(greyData, (int)greyWidth, (int)greyWidth, 0, 0, (int)greyWidth, (int)greyWidth) + ); + + return luminanceSource; +} + +//-------------------------------------------------------------------------- +// for debugging +//-------------------------------------------------------------------------- +- (UIImage*) getImageFromLuminanceSource:(zxing::LuminanceSource*)luminanceSource { + unsigned char* bytes = luminanceSource->getMatrix(); + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + CGContextRef context = CGBitmapContextCreate( + bytes, + luminanceSource->getWidth(), luminanceSource->getHeight(), 8, luminanceSource->getWidth(), + colorSpace, + kCGImageAlphaNone + ); + + CGImageRef cgImage = CGBitmapContextCreateImage(context); + UIImage* image = [[UIImage alloc] initWithCGImage:cgImage]; + + CGContextRelease(context); + CGColorSpaceRelease(colorSpace); + CGImageRelease(cgImage); + free(bytes); + + return image; +} + +//-------------------------------------------------------------------------- +// for debugging +//-------------------------------------------------------------------------- +- (UIImage*)getImageFromSample:(CMSampleBufferRef)sampleBuffer { + CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); + CVPixelBufferLockBaseAddress(imageBuffer, 0); + + size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); + size_t width = CVPixelBufferGetWidth(imageBuffer); + size_t height = CVPixelBufferGetHeight(imageBuffer); + + uint8_t* baseAddress = (uint8_t*) CVPixelBufferGetBaseAddress(imageBuffer); + int length = (int)(height * bytesPerRow); + uint8_t* newBaseAddress = (uint8_t*) malloc(length); + memcpy(newBaseAddress, baseAddress, length); + baseAddress = newBaseAddress; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate( + baseAddress, + width, height, 8, bytesPerRow, + colorSpace, + kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst + ); + + CGImageRef cgImage = CGBitmapContextCreateImage(context); + UIImage* image = [[UIImage alloc] initWithCGImage:cgImage]; + + CVPixelBufferUnlockBaseAddress(imageBuffer,0); + CGContextRelease(context); + CGColorSpaceRelease(colorSpace); + CGImageRelease(cgImage); + + free(baseAddress); + + return image; +} + +//-------------------------------------------------------------------------- +// for debugging +//-------------------------------------------------------------------------- +- (void)dumpImage:(UIImage*)image { + NSLog(@"writing image to library: %dx%d", (int)image.size.width, (int)image.size.height); + ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; + [assetsLibrary + writeImageToSavedPhotosAlbum:image.CGImage + orientation:ALAssetOrientationUp + completionBlock:^(NSURL* assetURL, NSError* error){ + if (error) NSLog(@" error writing image to library"); + else NSLog(@" wrote image to library %@", assetURL); + } + ]; +} + +@end + +//------------------------------------------------------------------------------ +// qr encoder processor +//------------------------------------------------------------------------------ +@implementation CDVqrProcessor +@synthesize plugin = _plugin; +@synthesize callback = _callback; +@synthesize stringToEncode = _stringToEncode; +@synthesize size = _size; + +- (id)initWithPlugin:(CDVBarcodeScanner*)plugin callback:(NSString*)callback stringToEncode:(NSString*)stringToEncode{ + self = [super init]; + if (!self) return self; + + self.plugin = plugin; + self.callback = callback; + self.stringToEncode = stringToEncode; + self.size = 300; + + return self; +} + +//-------------------------------------------------------------------------- +- (void)dealloc { + self.plugin = nil; + self.callback = nil; + self.stringToEncode = nil; + + [super dealloc]; +} +//-------------------------------------------------------------------------- +- (void)generateImage{ + /* setup qr filter */ + CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; + [filter setDefaults]; + + /* set filter's input message + * the encoding string has to be convert to a UTF-8 encoded NSData object */ + [filter setValue:[self.stringToEncode dataUsingEncoding:NSUTF8StringEncoding] + forKey:@"inputMessage"]; + + /* on ios >= 7.0 set low image error correction level */ + if (floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_7_0) + [filter setValue:@"L" forKey:@"inputCorrectionLevel"]; + + /* prepare cgImage */ + CIImage *outputImage = [filter outputImage]; + CIContext *context = [CIContext contextWithOptions:nil]; + CGImageRef cgImage = [context createCGImage:outputImage + fromRect:[outputImage extent]]; + + /* returned qr code image */ + UIImage *qrImage = [UIImage imageWithCGImage:cgImage + scale:1. + orientation:UIImageOrientationUp]; + /* resize generated image */ + CGFloat width = _size; + CGFloat height = _size; + + UIGraphicsBeginImageContext(CGSizeMake(width, height)); + + CGContextRef ctx = UIGraphicsGetCurrentContext(); + CGContextSetInterpolationQuality(ctx, kCGInterpolationNone); + [qrImage drawInRect:CGRectMake(0, 0, width, height)]; + qrImage = UIGraphicsGetImageFromCurrentImageContext(); + + /* clean up */ + UIGraphicsEndImageContext(); + CGImageRelease(cgImage); + + /* save image to file */ + NSString* filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmpqrcode.jpeg"]; + [UIImageJPEGRepresentation(qrImage, 1.0) writeToFile:filePath atomically:YES]; + + /* return file path back to cordova */ + [self.plugin returnImage:filePath format:@"QR_CODE" callback: self.callback]; +} +@end + +//------------------------------------------------------------------------------ +// view controller for the ui +//------------------------------------------------------------------------------ +@implementation CDVbcsViewController +@synthesize processor = _processor; +@synthesize shutterPressed = _shutterPressed; +@synthesize alternateXib = _alternateXib; +@synthesize overlayView = _overlayView; + +//-------------------------------------------------------------------------- +- (id)initWithProcessor:(CDVbcsProcessor*)processor alternateOverlay:(NSString *)alternateXib { + self = [super init]; + if (!self) return self; + + self.processor = processor; + self.shutterPressed = NO; + self.alternateXib = alternateXib; + self.overlayView = nil; + return self; +} + +//-------------------------------------------------------------------------- +- (void)dealloc { + self.view = nil; + self.processor = nil; + self.shutterPressed = NO; + self.alternateXib = nil; + self.overlayView = nil; + [super dealloc]; +} + +//-------------------------------------------------------------------------- +- (void)loadView { + self.view = [[UIView alloc] initWithFrame: self.processor.parentViewController.view.frame]; + + // setup capture preview layer + AVCaptureVideoPreviewLayer* previewLayer = self.processor.previewLayer; + previewLayer.frame = self.view.bounds; + previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; + + if ([previewLayer.connection isVideoOrientationSupported]) { + [previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortrait]; + } + + [self.view.layer insertSublayer:previewLayer below:[[self.view.layer sublayers] objectAtIndex:0]]; + + [self.view addSubview:[self buildOverlayView]]; +} + +//-------------------------------------------------------------------------- +- (void)viewWillAppear:(BOOL)animated { + + // set video orientation to what the camera sees + self.processor.previewLayer.connection.videoOrientation = [[UIApplication sharedApplication] statusBarOrientation]; + + // this fixes the bug when the statusbar is landscape, and the preview layer + // starts up in portrait (not filling the whole view) + self.processor.previewLayer.frame = self.view.bounds; +} + +//-------------------------------------------------------------------------- +- (void)viewDidAppear:(BOOL)animated { + [self startCapturing]; + + [super viewDidAppear:animated]; +} + +//-------------------------------------------------------------------------- +- (void)startCapturing { + self.processor.capturing = YES; +} + +//-------------------------------------------------------------------------- +- (void)shutterButtonPressed { + self.shutterPressed = YES; +} + +//-------------------------------------------------------------------------- +- (IBAction)cancelButtonPressed:(id)sender { + [self.processor performSelector:@selector(barcodeScanCancelled) withObject:nil afterDelay:0]; +} + +- (void)flipCameraButtonPressed:(id)sender +{ + [self.processor performSelector:@selector(flipCamera) withObject:nil afterDelay:0]; +} + +//-------------------------------------------------------------------------- +- (UIView *)buildOverlayViewFromXib +{ + [[NSBundle mainBundle] loadNibNamed:self.alternateXib owner:self options:NULL]; + + if ( self.overlayView == nil ) + { + NSLog(@"%@", @"An error occurred loading the overlay xib. It appears that the overlayView outlet is not set."); + return nil; + } + + return self.overlayView; +} + +//-------------------------------------------------------------------------- +- (UIView*)buildOverlayView { + + if ( nil != self.alternateXib ) + { + return [self buildOverlayViewFromXib]; + } + CGRect bounds = self.view.bounds; + bounds = CGRectMake(0, 0, bounds.size.width, bounds.size.height); + + UIView* overlayView = [[UIView alloc] initWithFrame:bounds]; + overlayView.autoresizesSubviews = YES; + overlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + overlayView.opaque = NO; + + UIToolbar* toolbar = [[UIToolbar alloc] init]; + toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; + + id cancelButton = [[UIBarButtonItem alloc] + initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:(id)self + action:@selector(cancelButtonPressed:) + ]; + + + id flexSpace = [[UIBarButtonItem alloc] + initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace + target:nil + action:nil + ]; + + id flipCamera = [[UIBarButtonItem alloc] + initWithBarButtonSystemItem:UIBarButtonSystemItemCamera + target:(id)self + action:@selector(flipCameraButtonPressed:) + ]; + +#if USE_SHUTTER + id shutterButton = [[UIBarButtonItem alloc] + initWithBarButtonSystemItem:UIBarButtonSystemItemCamera + target:(id)self + action:@selector(shutterButtonPressed) + ]; + + if (_processor.isShowFlipCameraButton) { + toolbar.items = [NSArray arrayWithObjects:flexSpace,cancelButton,flexSpace, flipCamera ,shutterButton,nil]; + } else { + toolbar.items = [NSArray arrayWithObjects:flexSpace,cancelButton,flexSpace ,shutterButton,nil]; + } +#else + if (_processor.isShowFlipCameraButton) { + toolbar.items = [NSArray arrayWithObjects:flexSpace,cancelButton,flexSpace, flipCamera,nil]; + } else { + toolbar.items = [NSArray arrayWithObjects:flexSpace,cancelButton,flexSpace,nil]; + } +#endif + bounds = overlayView.bounds; + + [toolbar sizeToFit]; + CGFloat toolbarHeight = [toolbar frame].size.height; + CGFloat rootViewHeight = CGRectGetHeight(bounds); + CGFloat rootViewWidth = CGRectGetWidth(bounds); + CGRect rectArea = CGRectMake(0, rootViewHeight - toolbarHeight, rootViewWidth, toolbarHeight); + [toolbar setFrame:rectArea]; + + [overlayView addSubview: toolbar]; + + UIImage* reticleImage = [self buildReticleImage]; + UIView* reticleView = [[UIImageView alloc] initWithImage: reticleImage]; + CGFloat minAxis = MIN(rootViewHeight, rootViewWidth); + + rectArea = CGRectMake( + 0.5 * (rootViewWidth - minAxis), + 0.5 * (rootViewHeight - minAxis), + minAxis, + minAxis + ); + + [reticleView setFrame:rectArea]; + + reticleView.opaque = NO; + reticleView.contentMode = UIViewContentModeScaleAspectFit; + reticleView.autoresizingMask = 0 + | UIViewAutoresizingFlexibleLeftMargin + | UIViewAutoresizingFlexibleRightMargin + | UIViewAutoresizingFlexibleTopMargin + | UIViewAutoresizingFlexibleBottomMargin + ; + + [overlayView addSubview: reticleView]; + + return overlayView; +} + +//-------------------------------------------------------------------------- + +#define RETICLE_SIZE 500.0f +#define RETICLE_WIDTH 10.0f +#define RETICLE_OFFSET 60.0f +#define RETICLE_ALPHA 0.4f + +//------------------------------------------------------------------------- +// builds the green box and red line +//------------------------------------------------------------------------- +- (UIImage*)buildReticleImage { + UIImage* result; + UIGraphicsBeginImageContext(CGSizeMake(RETICLE_SIZE, RETICLE_SIZE)); + CGContextRef context = UIGraphicsGetCurrentContext(); + + if (self.processor.is1D) { + UIColor* color = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:RETICLE_ALPHA]; + CGContextSetStrokeColorWithColor(context, color.CGColor); + CGContextSetLineWidth(context, RETICLE_WIDTH); + CGContextBeginPath(context); + CGFloat lineOffset = RETICLE_OFFSET+(0.5*RETICLE_WIDTH); + CGContextMoveToPoint(context, lineOffset, RETICLE_SIZE/2); + CGContextAddLineToPoint(context, RETICLE_SIZE-lineOffset, 0.5*RETICLE_SIZE); + CGContextStrokePath(context); + } + + if (self.processor.is2D) { + UIColor* color = [UIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:RETICLE_ALPHA]; + CGContextSetStrokeColorWithColor(context, color.CGColor); + CGContextSetLineWidth(context, RETICLE_WIDTH); + CGContextStrokeRect(context, + CGRectMake( + RETICLE_OFFSET, + RETICLE_OFFSET, + RETICLE_SIZE-2*RETICLE_OFFSET, + RETICLE_SIZE-2*RETICLE_OFFSET + ) + ); + } + + result = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return result; +} + +#pragma mark CDVBarcodeScannerOrientationDelegate + +- (BOOL)shouldAutorotate +{ + return YES; +} + +- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation +{ + return [[UIApplication sharedApplication] statusBarOrientation]; +} + +- (NSUInteger)supportedInterfaceOrientations +{ + return UIInterfaceOrientationMaskAll; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) { + return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation]; + } + + return YES; +} + +- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration +{ + [UIView setAnimationsEnabled:NO]; + AVCaptureVideoPreviewLayer* previewLayer = self.processor.previewLayer; + previewLayer.frame = self.view.bounds; + + if (orientation == UIInterfaceOrientationLandscapeLeft) { + [previewLayer setOrientation:AVCaptureVideoOrientationLandscapeLeft]; + } else if (orientation == UIInterfaceOrientationLandscapeRight) { + [previewLayer setOrientation:AVCaptureVideoOrientationLandscapeRight]; + } else if (orientation == UIInterfaceOrientationPortrait) { + [previewLayer setOrientation:AVCaptureVideoOrientationPortrait]; + } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { + [previewLayer setOrientation:AVCaptureVideoOrientationPortraitUpsideDown]; + } + + previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; + [UIView setAnimationsEnabled:YES]; +} + +@end diff --git a/plugins/phonegap-plugin-barcodescanner/src/ios/scannerOverlay.xib b/plugins/phonegap-plugin-barcodescanner/src/ios/scannerOverlay.xib new file mode 100644 index 0000000..765f2a8 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/ios/scannerOverlay.xib @@ -0,0 +1,185 @@ + + + + 1280 + 11C74 + 1938 + 1138.23 + 567.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 933 + + + IBUINavigationItem + IBUIBarButtonItem + IBUIView + IBUINavigationBar + IBProxyObject + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + + + + 290 + {320, 44} + + + + _NS:260 + IBCocoaTouchFramework + 1 + + + + Barcode Scanner + + Cancel + IBCocoaTouchFramework + 1 + + + IBCocoaTouchFramework + + + + + {320, 460} + + + + + 3 + MSAwAA + + 2 + + + IBCocoaTouchFramework + + + + + + + overlayView + + + + 9 + + + + + + 0 + + + + + + 1 + + + + + + + + -1 + + + File's Owner + + + -2 + + + + + 3 + + + + + + + + 4 + + + + + + + + 10 + + + + + + + PGbcsViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 11 + + + + + PGbcsViewController + UIViewController + + overlayView + UIView + + + overlayView + + overlayView + UIView + + + + IBProjectSource + ./Classes/PGbcsViewController.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + 933 + + diff --git a/plugins/phonegap-plugin-barcodescanner/src/ios/zxing-all-in-one.cpp b/plugins/phonegap-plugin-barcodescanner/src/ios/zxing-all-in-one.cpp new file mode 100644 index 0000000..86559fb --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/ios/zxing-all-in-one.cpp @@ -0,0 +1,11982 @@ + +#include "zxing-all-in-one.h" + +// file: zxing/BarcodeFormat.cpp + +// -*- 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 + +namespace zxing { + +const char *barcodeFormatNames[] = { + "None", + "QR_CODE", + "DATA_MATRIX", + "UPC_E", + "UPC_A", + "EAN_8", + "EAN_13", + "CODE_128", + "CODE_39", + "ITF" +}; + +} + +// file: zxing/Binarizer.cpp + +// -*- 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 + +namespace zxing { + + Binarizer::Binarizer(Ref source) : source_(source) { + } + + Binarizer::~Binarizer() { + } + + Ref Binarizer::getLuminanceSource() const { + return source_; + } + +} + +// file: zxing/BinaryBitmap.cpp + +/* + * 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 + +namespace zxing { + + BinaryBitmap::BinaryBitmap(Ref binarizer) : binarizer_(binarizer) { + + } + + BinaryBitmap::~BinaryBitmap() { + } + + Ref BinaryBitmap::getBlackRow(int y, Ref row) { + return binarizer_->getBlackRow(y, row); + } + + Ref BinaryBitmap::getBlackMatrix() { + return binarizer_->getBlackMatrix(); + } + + int BinaryBitmap::getWidth() const { + return getLuminanceSource()->getWidth(); + } + + int BinaryBitmap::getHeight() const { + return getLuminanceSource()->getHeight(); + } + + Ref BinaryBitmap::getLuminanceSource() const { + return binarizer_->getLuminanceSource(); + } + + + bool BinaryBitmap::isCropSupported() const { + return getLuminanceSource()->isCropSupported(); + } + + Ref BinaryBitmap::crop(int left, int top, int width, int height) { + return Ref (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->crop(left, top, width, height)))); + } + + bool BinaryBitmap::isRotateSupported() const { + return getLuminanceSource()->isRotateSupported(); + } + + Ref BinaryBitmap::rotateCounterClockwise() { + return Ref (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->rotateCounterClockwise()))); + } +} + +// file: zxing/DecodeHints.cpp + +/* + * 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 +// #include +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_QR_CODE_HINT); + +DecodeHints::DecodeHints() { + hints = 0; +} + +DecodeHints::DecodeHints(DecodeHintType init) { + hints = init; +} + +void DecodeHints::addFormat(BarcodeFormat toadd) { + switch (toadd) { + 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_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 const& _callback) { + callback = _callback; +} + +Ref DecodeHints::getResultPointCallback() const { + return callback; +} + +} /* namespace */ + +// file: zxing/Exception.cpp + +// -*- 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 + +namespace zxing { + +Exception::Exception() {} + +Exception::Exception(const char *msg) : + message(msg) { +} + +const char* Exception::what() const throw() { + return message.c_str(); +} + +Exception::~Exception() throw() { +} + +} + +// file: zxing/FormatException.cpp + +// -*- 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 + +namespace zxing { + +FormatException::FormatException() {} + +FormatException::FormatException(const char *msg) : + ReaderException(msg) { +} + +FormatException::~FormatException() throw() { +} + +} + +// file: zxing/LuminanceSource.cpp + +// -*- 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 +// #include +// #include + +namespace zxing { + +LuminanceSource::LuminanceSource() { +} + +LuminanceSource::~LuminanceSource() { +} + +bool LuminanceSource::isCropSupported() const { + return false; +} + +Ref 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::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(); +} + + + +} + +// file: zxing/MultiFormatReader.cpp + +/* + * 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 +// #include +// #include +// #include +// #include +// #include + +namespace zxing { + MultiFormatReader::MultiFormatReader() { + + } + + Ref MultiFormatReader::decode(Ref image) { + setHints(DecodeHints::DEFAULT_HINT); + return decodeInternal(image); + } + + Ref MultiFormatReader::decode(Ref image, DecodeHints hints) { + setHints(hints); + return decodeInternal(image); + } + + Ref MultiFormatReader::decodeWithState(Ref 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(new zxing::oned::MultiFormatOneDReader(hints))); + } + if (hints.containsFormat(BarcodeFormat_QR_CODE)) { + readers_.push_back(Ref(new zxing::qrcode::QRCodeReader())); + } + if (hints.containsFormat(BarcodeFormat_DATA_MATRIX)) { + readers_.push_back(Ref(new zxing::datamatrix::DataMatrixReader())); + } + //TODO: add PDF417 here once PDF417 reader is implemented + if (addOneDReader && tryHarder) { + readers_.push_back(Ref(new zxing::oned::MultiFormatOneDReader(hints))); + } + if (readers_.size() == 0) { + if (!tryHarder) { + readers_.push_back(Ref(new zxing::oned::MultiFormatOneDReader(hints))); + } + readers_.push_back(Ref(new zxing::qrcode::QRCodeReader())); + if (tryHarder) { + readers_.push_back(Ref(new zxing::oned::MultiFormatOneDReader(hints))); + } + } + } + + Ref MultiFormatReader::decodeInternal(Ref 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() { + + } +} + +// file: zxing/NotFoundException.cpp + +// -*- 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 + +namespace zxing { + + NotFoundException::NotFoundException(const char *msg) + : ReaderException(msg) {} + + NotFoundException::~NotFoundException() throw() { + } + +} + +// file: zxing/Reader.cpp + +/* + * 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 + +namespace zxing { + +Reader::~Reader() { } + +Ref Reader::decode(Ref image) { + return decode(image, DecodeHints::DEFAULT_HINT); +} + +} + +// file: zxing/ReaderException.cpp + +// -*- 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 + +namespace zxing { + +ReaderException::ReaderException() {} + +ReaderException::ReaderException(const char *msg) : + Exception(msg) { +} + +ReaderException::~ReaderException() throw() { +} + +} + +// file: zxing/Result.cpp + +// -*- 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 + +namespace zxing { +using namespace std; + +Result::Result(Ref text, ArrayRef rawBytes, std::vector > resultPoints, + BarcodeFormat format) : + text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format) { +} + +Result::~Result() { +} + +Ref Result::getText() { + return text_; +} + +ArrayRef Result::getRawBytes() { + return rawBytes_; +} + +const std::vector >& Result::getResultPoints() const { + return resultPoints_; +} + +std::vector >& 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; +} + +} + +// file: zxing/ResultPoint.cpp + +/* + * 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 +// #include + +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 other) { + return posX_ == other->getX() && posY_ == other->getY(); +} + +/** + *

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 > &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 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 temp = pointA; + pointA = pointC; + pointC = temp; + } + + patterns[0] = pointA; + patterns[1] = pointB; + patterns[2] = pointC; +} + +float ResultPoint::distance(Ref point1, Ref 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 pointA, Ref pointB, Ref pointC) { + float bX = pointB->getX(); + float bY = pointB->getY(); + return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX)); +} +} + +// file: zxing/ResultPointCallback.cpp + +/* + * 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 + +namespace zxing { + +ResultPointCallback::~ResultPointCallback() {} + +} + +// file: zxing/common/Array.cpp + +/* + * Array.cpp + * zxing + * + * Created by Christian Brunschen on 07/05/2008. + * Copyright 2008 Google UK. 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 + + +// file: zxing/common/BitArray.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 + +using namespace std; + +namespace zxing { + + +size_t BitArray::wordsForBits(size_t bits) { + int arraySize = (bits + bitsPerWord_ - 1) >> logBits_; + return arraySize; +} + +BitArray::BitArray(size_t size) : + size_(size), bits_(wordsForBits(size), (const unsigned int)0) { +} + +BitArray::~BitArray() { +} + +size_t BitArray::getSize() { + return size_; +} + +void BitArray::setBulk(size_t i, unsigned int newBits) { + bits_[i >> logBits_] = newBits; +} + +void BitArray::setRange(int start, int end) { + if (end < start) { + throw IllegalArgumentException("invalid call to BitArray::setRange"); + } + if (end == start) { + return; + } + end--; // will be easier to treat this as the last actually set bit -- inclusive + int firstInt = start >> 5; + int lastInt = end >> 5; + for (int i = firstInt; i <= lastInt; i++) { + int firstBit = i > firstInt ? 0 : start & 0x1F; + int lastBit = i < lastInt ? 31 : end & 0x1F; + int mask; + if (firstBit == 0 && lastBit == 31) { + mask = -1; + } else { + mask = 0; + for (int j = firstBit; j <= lastBit; j++) { + mask |= 1 << j; + } + } + bits_[i] |= mask; + } +} + +void BitArray::clear() { + size_t max = bits_.size(); + for (size_t i = 0; i < max; i++) { + bits_[i] = 0; + } +} + +bool BitArray::isRange(size_t start, size_t end, bool value) { + if (end < start) { + throw IllegalArgumentException("end must be after start"); + } + if (end == start) { + return true; + } + // treat the 'end' as inclusive, rather than exclusive + end--; + size_t firstWord = start >> logBits_; + size_t lastWord = end >> logBits_; + for (size_t i = firstWord; i <= lastWord; i++) { + size_t firstBit = i > firstWord ? 0 : start & bitsMask_; + size_t lastBit = i < lastWord ? bitsPerWord_ - 1: end & bitsMask_; + unsigned int mask; + if (firstBit == 0 && lastBit == bitsPerWord_ - 1) { + mask = numeric_limits::max(); + } else { + mask = 0; + for (size_t j = firstBit; j <= lastBit; j++) { + mask |= 1 << j; + } + } + if (value) { + if ((bits_[i] & mask) != mask) { + return false; + } + } else { + if ((bits_[i] & mask) != 0) { + return false; + } + } + } + return true; +} + +vector& BitArray::getBitArray() { + return bits_; +} + +void BitArray::reverse() { + std::vector newBits(bits_.size(),(const unsigned int) 0); + for (size_t i = 0; i < size_; i++) { + if (get(size_ - i - 1)) { + newBits[i >> logBits_] |= 1<< (i & bitsMask_); + } + } + bits_ = newBits; +} +} + +// file: zxing/common/BitMatrix.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 +// #include + +// #include +// #include +// #include + +using std::ostream; +using std::ostringstream; + +using zxing::BitMatrix; +using zxing::BitArray; +using zxing::Ref; + +namespace { + size_t wordsForSize(size_t width, + size_t height, + unsigned int bitsPerWord, + unsigned int logBits) { + size_t bits = width * height; + int arraySize = (bits + bitsPerWord - 1) >> logBits; + return arraySize; + } +} + +BitMatrix::BitMatrix(size_t dimension) : + width_(dimension), height_(dimension), words_(0), bits_(NULL) { + words_ = wordsForSize(width_, height_, bitsPerWord, logBits); + bits_ = new unsigned int[words_]; + clear(); +} + +BitMatrix::BitMatrix(size_t width, size_t height) : + width_(width), height_(height), words_(0), bits_(NULL) { + words_ = wordsForSize(width_, height_, bitsPerWord, logBits); + bits_ = new unsigned int[words_]; + clear(); +} + +BitMatrix::~BitMatrix() { + delete[] bits_; +} + + +void BitMatrix::flip(size_t x, size_t y) { + size_t offset = x + width_ * y; + bits_[offset >> logBits] ^= 1 << (offset & bitsMask); +} + +void BitMatrix::clear() { + std::fill(bits_, bits_+words_, 0); +} + +void BitMatrix::setRegion(size_t left, size_t top, size_t width, size_t height) { + if ((long)top < 0 || (long)left < 0) { + throw IllegalArgumentException("topI and leftJ must be nonnegative"); + } + if (height < 1 || width < 1) { + throw IllegalArgumentException("height and width must be at least 1"); + } + size_t right = left + width; + size_t bottom = top + height; + if (right > width_ || bottom > height_) { + throw IllegalArgumentException("top + height and left + width must be <= matrix dimension"); + } + for (size_t y = top; y < bottom; y++) { + int yOffset = width_ * y; + for (size_t x = left; x < right; x++) { + size_t offset = x + yOffset; + bits_[offset >> logBits] |= 1 << (offset & bitsMask); + } + } +} + +Ref BitMatrix::getRow(int y, Ref row) { + if (row.empty() || row->getSize() < width_) { + row = new BitArray(width_); + } else { + row->clear(); + } + size_t start = y * width_; + size_t end = start + width_ - 1; // end is inclusive + size_t firstWord = start >> logBits; + size_t lastWord = end >> logBits; + size_t bitOffset = start & bitsMask; + for (size_t i = firstWord; i <= lastWord; i++) { + size_t firstBit = i > firstWord ? 0 : start & bitsMask; + size_t lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask; + unsigned int mask; + if (firstBit == 0 && lastBit == logBits) { + mask = std::numeric_limits::max(); + } else { + mask = 0; + for (size_t j = firstBit; j <= lastBit; j++) { + mask |= 1 << j; + } + } + row->setBulk((i - firstWord) << logBits, (bits_[i] & mask) >> bitOffset); + if (firstBit == 0 && bitOffset != 0) { + unsigned int prevBulk = row->getBitArray()[i - firstWord - 1]; + prevBulk |= (bits_[i] & mask) << (bitsPerWord - bitOffset); + row->setBulk((i - firstWord - 1) << logBits, prevBulk); + } + } + return row; +} + +size_t BitMatrix::getWidth() const { + return width_; +} + +size_t BitMatrix::getHeight() const { + return height_; +} + +size_t BitMatrix::getDimension() const { + return width_; +} + +unsigned int* BitMatrix::getBits() const { + return bits_; +} + +namespace zxing { + ostream& operator<<(ostream &out, const BitMatrix &bm) { + for (size_t y = 0; y < bm.height_; y++) { + for (size_t x = 0; x < bm.width_; x++) { + out << (bm.get(x, y) ? "X " : " "); + } + out << "\n"; + } + return out; + } +} + +const char* BitMatrix::description() { + ostringstream out; + out << *this; + return out.str().c_str(); +} + +// file: zxing/common/BitSource.cpp + +/* + * BitSource.cpp + * zxing + * + * Created by Christian Brunschen on 09/05/2008. + * Copyright 2008 Google UK. 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 +// #include + +namespace zxing { + +int BitSource::readBits(int numBits) { + if (numBits < 0 || numBits > 32) { + throw IllegalArgumentException("cannot read <1 or >32 bits"); + } else if (numBits > available()) { + throw IllegalArgumentException("reading more bits than are available"); + } + + int result = 0; + + // First, read remainder from current byte + if (bitOffset_ > 0) { + int bitsLeft = 8 - bitOffset_; + int toRead = numBits < bitsLeft ? numBits : bitsLeft; + int bitsToNotRead = bitsLeft - toRead; + int mask = (0xFF >> (8 - toRead)) << bitsToNotRead; + result = (bytes_[byteOffset_] & mask) >> bitsToNotRead; + numBits -= toRead; + bitOffset_ += toRead; + if (bitOffset_ == 8) { + bitOffset_ = 0; + byteOffset_++; + } + } + + // Next read whole bytes + if (numBits > 0) { + while (numBits >= 8) { + result = (result << 8) | (bytes_[byteOffset_] & 0xFF); + byteOffset_++; + numBits -= 8; + } + + + // Finally read a partial byte + if (numBits > 0) { + int bitsToNotRead = 8 - numBits; + int mask = (0xFF >> bitsToNotRead) << bitsToNotRead; + result = (result << numBits) | ((bytes_[byteOffset_] & mask) >> bitsToNotRead); + bitOffset_ += numBits; + } + } + + return result; +} + +int BitSource::available() { + return 8 * (bytes_.size() - byteOffset_) - bitOffset_; +} +} + +// file: zxing/common/CharacterSetECI.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Copyright 2008-2011 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 +// #include +// #include + +using std::string; + +using zxing::common::CharacterSetECI; +using zxing::IllegalArgumentException; + +std::map CharacterSetECI::VALUE_TO_ECI; +std::map CharacterSetECI::NAME_TO_ECI; + +const bool CharacterSetECI::inited = CharacterSetECI::init_tables(); + +bool CharacterSetECI::init_tables() { + addCharacterSet(0, "Cp437"); + { char const* s[] = {"ISO8859_1", "ISO-8859-1", 0}; + addCharacterSet(1, s); } + addCharacterSet(2, "Cp437"); + { char const* s[] = {"ISO8859_1", "ISO-8859-1", 0}; + addCharacterSet(3, s); } + addCharacterSet(4, "ISO8859_2"); + addCharacterSet(5, "ISO8859_3"); + addCharacterSet(6, "ISO8859_4"); + addCharacterSet(7, "ISO8859_5"); + addCharacterSet(8, "ISO8859_6"); + addCharacterSet(9, "ISO8859_7"); + addCharacterSet(10, "ISO8859_8"); + addCharacterSet(11, "ISO8859_9"); + addCharacterSet(12, "ISO8859_10"); + addCharacterSet(13, "ISO8859_11"); + addCharacterSet(15, "ISO8859_13"); + addCharacterSet(16, "ISO8859_14"); + addCharacterSet(17, "ISO8859_15"); + addCharacterSet(18, "ISO8859_16"); + { char const* s[] = {"SJIS", "Shift_JIS", 0}; + addCharacterSet(20, s ); } + return true; +} + +CharacterSetECI::CharacterSetECI(int value, char const* encodingName_) + : ECI(value), encodingName(encodingName_) {} + +char const* CharacterSetECI::getEncodingName() { + return encodingName; +} + +void CharacterSetECI::addCharacterSet(int value, char const* encodingName) { + CharacterSetECI* eci = new CharacterSetECI(value, encodingName); + VALUE_TO_ECI[value] = eci; // can't use valueOf + NAME_TO_ECI[string(encodingName)] = eci; +} + +void CharacterSetECI::addCharacterSet(int value, char const* const* encodingNames) { + CharacterSetECI* eci = new CharacterSetECI(value, encodingNames[0]); + VALUE_TO_ECI[value] = eci; + for (int i = 0; encodingNames[i]; i++) { + NAME_TO_ECI[string(encodingNames[i])] = eci; + } +} + +CharacterSetECI* CharacterSetECI::getCharacterSetECIByValue(int value) { + if (value < 0 || value >= 900) { + std::ostringstream oss; + oss << "Bad ECI value: " << value; + throw IllegalArgumentException(oss.str().c_str()); + } + return VALUE_TO_ECI[value]; +} + +CharacterSetECI* CharacterSetECI::getCharacterSetECIByName(string const& name) { + return NAME_TO_ECI[name]; +} + +// file: zxing/common/Counted.cpp + +/* + * Counted.cpp + * zxing + * + * Created by Christian Brunschen on 07/05/2008. + * Copyright 2008 Google UK. 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 + +namespace zxing { + +using namespace std; + +template +ostream& operator<<(ostream &out, Ref& ref) { + out << "Ref(" << (ref.object_ ? (*ref.object_) : "NULL") << ")"; + return out; +} +} + +// file: zxing/common/DecoderResult.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * DecoderResult.cpp + * zxing + * + * Created by Christian Brunschen on 20/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 + +using namespace std; +using namespace zxing; + +DecoderResult::DecoderResult(ArrayRef rawBytes, + Ref text, + ArrayRef< ArrayRef >& byteSegments, + string const& ecLevel) : + rawBytes_(rawBytes), + text_(text), + byteSegments_(byteSegments), + ecLevel_(ecLevel) {} + +DecoderResult::DecoderResult(ArrayRef rawBytes, + Ref text) + : rawBytes_(rawBytes), text_(text) {} + +ArrayRef DecoderResult::getRawBytes() { + return rawBytes_; +} + +Ref DecoderResult::getText() { + return text_; +} + +// file: zxing/common/DetectorResult.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * DetectorResult.cpp + * zxing + * + * Created by Christian Brunschen on 14/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 + +namespace zxing { + +DetectorResult::DetectorResult(Ref bits, std::vector > points, Ref transform) : + bits_(bits), points_(points), transform_(transform) { +} + +Ref DetectorResult::getBits() { + return bits_; +} + +std::vector > DetectorResult::getPoints() { + return points_; +} + +Ref DetectorResult::getTransform() { + return transform_; +} + +} + +// file: zxing/common/ECI.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Copyright 2008-2011 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 +// #include +// #include +// #include + +using zxing::common::ECI; +using zxing::IllegalArgumentException; + +ECI::ECI(int value_) : value(value_) {} + +int ECI::getValue() const { + return value; +} + +ECI* ECI::getECIByValue(int value) { + if (value < 0 || value > 999999) { + std::ostringstream oss; + oss << "Bad ECI value: " << value; + throw IllegalArgumentException(oss.str().c_str()); + } + if (value < 900) { // Character set ECIs use 000000 - 000899 + return CharacterSetECI::getCharacterSetECIByValue(value); + } + return 0; +} + +// file: zxing/common/EdgeDetector.cpp + +/* + * EdgeDetector.cpp + * zxing + * + * Created by Ralf Kistner on 7/12/2009. + * 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 +// #include +// #include + +using namespace std; + +namespace zxing { +namespace EdgeDetector { + +void findEdgePoints(std::vector& points, const BitMatrix& image, Point start, Point end, bool invert, int skip, float deviation) { + float xdist = end.x - start.x; + float ydist = end.y - start.y; + float length = sqrt(xdist * xdist + ydist * ydist); + + + int var; + + if (abs(xdist) > abs(ydist)) { + // Horizontal + if (xdist < 0) + skip = -skip; + + var = int(abs(deviation * length / xdist)); + + float dy = ydist / xdist * skip; + bool left = (skip < 0) ^ invert; + int x = int(start.x); + + int steps = int(xdist / skip); + for (int i = 0; i < steps; i++) { + x += skip; + if (x < 0 || x >= (int)image.getWidth()) + continue; // In case we start off the edge + int my = int(start.y + dy * i); + int ey = min(my + var + 1, (int)image.getHeight() - 1); + int sy = max(my - var, 0); + for (int y = sy + 1; y < ey; y++) { + if (left) { + if (image.get(x, y) && !image.get(x, y + 1)) { + points.push_back(Point(x, y + 0.5f)); + } + } else { + if (!image.get(x, y) && image.get(x, y + 1)) { + points.push_back(Point(x, y + 0.5f)); + } + } + } + } + } else { + // Vertical + if (ydist < 0) + skip = -skip; + + var = int(abs(deviation * length / ydist)); + + float dx = xdist / ydist * skip; + bool down = (skip > 0) ^ invert; + int y = int(start.y); + + int steps = int(ydist / skip); + for (int i = 0; i < steps; i++) { + y += skip; + if (y < 0 || y >= (int)image.getHeight()) + continue; // In case we start off the edge + int mx = int(start.x + dx * i); + int ex = min(mx + var + 1, (int)image.getWidth() - 1); + int sx = max(mx - var, 0); + for (int x = sx + 1; x < ex; x++) { + if (down) { + if (image.get(x, y) && !image.get(x + 1, y)) { + points.push_back(Point(x + 0.5f, y)); + } + + } else { + if (!image.get(x, y) && image.get(x + 1, y)) { + points.push_back(Point(x + 0.5f, y)); + } + } + + } + } + + } +} + +Line findLine(const BitMatrix& image, Line estimate, bool invert, int deviation, float threshold, int skip) { + float t = threshold * threshold; + + Point start = estimate.start; + Point end = estimate.end; + + vector edges; + edges.clear(); + findEdgePoints(edges, image, start, end, invert, skip, deviation); + + int n = edges.size(); + + float xdist = end.x - start.x; + float ydist = end.y - start.y; + + bool horizontal = abs(xdist) > abs(ydist); + + float max = 0; + Line bestLine(start, end); // prepopulate with the given line, in case we can't find any line for some reason + + for (int i = -deviation; i < deviation; i++) { + float x1, y1; + if (horizontal) { + y1 = start.y + i; + x1 = start.x - i * ydist / xdist; + } else { + y1 = start.y - i * xdist / ydist; + x1 = start.x + i; + } + + for (int j = -deviation; j < deviation; j++) { + float x2, y2; + if (horizontal) { + y2 = end.y + j; + x2 = end.x - j * ydist / xdist; + } else { + y2 = end.y - j * xdist / ydist; + x2 = end.x + j; + } + + float dx = x1 - x2; + float dy = y1 - y2; + float length = sqrt(dx * dx + dy * dy); + + float score = 0; + + for(int k = 0; k < n; k++) { + const Point& edge = edges[k]; + float dist = ((x1 - edge.x) * dy - (y1 - edge.y) * dx) / length; + // Similar to least squares method + float s = t - dist * dist; + if (s > 0) + score += s; + } + + if (score > max) { + max = score; + bestLine.start = Point(x1, y1); + bestLine.end = Point(x2, y2); + } + } + } + + return bestLine; +} + +Point intersection(Line a, Line b) { + float dxa = a.start.x - a.end.x; + float dxb = b.start.x - b.end.x; + float dya = a.start.y - a.end.y; + float dyb = b.start.y - b.end.y; + + float p = a.start.x * a.end.y - a.start.y * a.end.x; + float q = b.start.x * b.end.y - b.start.y * b.end.x; + float denom = dxa * dyb - dya * dxb; + if(denom == 0) // Lines don't intersect + return Point(INFINITY, INFINITY); + + float x = (p * dxb - dxa * q) / denom; + float y = (p * dyb - dya * q) / denom; + + return Point(x, y); +} + +} // namespace EdgeDetector +} // namespace zxing + +// file: zxing/common/GlobalHistogramBinarizer.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * GlobalHistogramBinarizer.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 +// #include +// #include + +namespace zxing { +using namespace std; + +const int LUMINANCE_BITS_25 = 5; +const int LUMINANCE_SHIFT_25 = 8 - LUMINANCE_BITS_25; +const int LUMINANCE_BUCKETS_25 = 1 << LUMINANCE_BITS_25; + +GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref source) : + Binarizer(source), cached_matrix_(NULL), cached_row_(NULL), cached_row_num_(-1) { + +} + +GlobalHistogramBinarizer::~GlobalHistogramBinarizer() { +} + + +Ref GlobalHistogramBinarizer::getBlackRow(int y, Ref row) { + if (y == cached_row_num_) { + if (cached_row_ != NULL) { + return cached_row_; + } else { + throw IllegalArgumentException("Too little dynamic range in luminance"); + } + } + + vector histogram(LUMINANCE_BUCKETS_25, 0); + LuminanceSource& source = *getLuminanceSource(); + int width = source.getWidth(); + if (row == NULL || static_cast(row->getSize()) < width) { + row = new BitArray(width); + } else { + row->clear(); + } + + //TODO(flyashi): cache this instead of allocating and deleting per row + unsigned char* row_pixels = NULL; + try { + row_pixels = new unsigned char[width]; + row_pixels = source.getRow(y, row_pixels); + for (int x = 0; x < width; x++) { + histogram[row_pixels[x] >> LUMINANCE_SHIFT_25]++; + } + int blackPoint = estimate(histogram); + + BitArray& array = *row; + int left = row_pixels[0]; + int center = row_pixels[1]; + for (int x = 1; x < width - 1; x++) { + int right = row_pixels[x + 1]; + // A simple -1 4 -1 box filter with a weight of 2. + int luminance = ((center << 2) - left - right) >> 1; + if (luminance < blackPoint) { + array.set(x); + } + left = center; + center = right; + } + + cached_row_ = row; + cached_row_num_ = y; + delete [] row_pixels; + return row; + } catch (IllegalArgumentException const& iae) { + // Cache the fact that this row failed. + cached_row_ = NULL; + cached_row_num_ = y; + delete [] row_pixels; + throw iae; + } +} + +Ref GlobalHistogramBinarizer::getBlackMatrix() { + if (cached_matrix_ != NULL) { + return cached_matrix_; + } + + // Faster than working with the reference + LuminanceSource& source = *getLuminanceSource(); + int width = source.getWidth(); + int height = source.getHeight(); + vector histogram(LUMINANCE_BUCKETS_25, 0); + + // Quickly calculates the histogram by sampling four rows from the image. + // This proved to be more robust on the blackbox tests than sampling a + // diagonal as we used to do. + ArrayRef ref (width); + unsigned char* row = &ref[0]; + for (int y = 1; y < 5; y++) { + int rownum = height * y / 5; + int right = (width << 2) / 5; + row = source.getRow(rownum, row); + for (int x = width / 5; x < right; x++) { + histogram[row[x] >> LUMINANCE_SHIFT_25]++; + } + } + + int blackPoint = estimate(histogram); + + Ref matrix_ref(new BitMatrix(width, height)); + BitMatrix& matrix = *matrix_ref; + for (int y = 0; y < height; y++) { + row = source.getRow(y, row); + for (int x = 0; x < width; x++) { + if (row[x] < blackPoint) + matrix.set(x, y); + } + } + + cached_matrix_ = matrix_ref; + // delete [] row; + return matrix_ref; +} + +int GlobalHistogramBinarizer::estimate(vector &histogram) { + int numBuckets = histogram.size(); + int maxBucketCount = 0; + + // Find tallest peak in histogram + int firstPeak = 0; + int firstPeakSize = 0; + for (int i = 0; i < numBuckets; i++) { + if (histogram[i] > firstPeakSize) { + firstPeak = i; + firstPeakSize = histogram[i]; + } + if (histogram[i] > maxBucketCount) { + maxBucketCount = histogram[i]; + } + } + + // Find second-tallest peak -- well, another peak that is tall and not + // so close to the first one + int secondPeak = 0; + int secondPeakScore = 0; + for (int i = 0; i < numBuckets; i++) { + int distanceToBiggest = i - firstPeak; + // Encourage more distant second peaks by multiplying by square of distance + int score = histogram[i] * distanceToBiggest * distanceToBiggest; + if (score > secondPeakScore) { + secondPeak = i; + secondPeakScore = score; + } + } + + // Put firstPeak first + if (firstPeak > secondPeak) { + int temp = firstPeak; + firstPeak = secondPeak; + secondPeak = temp; + } + + // Kind of arbitrary; if the two peaks are very close, then we figure there is + // so little dynamic range in the image, that discriminating black and white + // is too error-prone. + // Decoding the image/line is either pointless, or may in some cases lead to + // a false positive for 1D formats, which are relatively lenient. + // We arbitrarily say "close" is + // "<= 1/16 of the total histogram buckets apart" + if (secondPeak - firstPeak <= numBuckets >> 4) { + throw IllegalArgumentException("Too little dynamic range in luminance"); + } + + // Find a valley between them that is low and closer to the white peak + int bestValley = secondPeak - 1; + int bestValleyScore = -1; + for (int i = secondPeak - 1; i > firstPeak; i--) { + int fromFirst = i - firstPeak; + // Favor a "valley" that is not too close to either peak -- especially not + // the black peak -- and that has a low value of course + int score = fromFirst * fromFirst * (secondPeak - i) * + (maxBucketCount - histogram[i]); + if (score > bestValleyScore) { + bestValley = i; + bestValleyScore = score; + } + } + + return bestValley << LUMINANCE_SHIFT_25; +} + +Ref GlobalHistogramBinarizer::createBinarizer(Ref source) { + return Ref (new GlobalHistogramBinarizer(source)); +} + +} // namespace zxing + +// file: zxing/common/GreyscaleLuminanceSource.cpp + +/* + * GreyscaleLuminanceSource.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 +// #include +// #include + +namespace zxing { + +GreyscaleLuminanceSource::GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth, + int dataHeight, int left, int top, int width, int height) : greyData_(greyData), + dataWidth_(dataWidth), dataHeight_(dataHeight), left_(left), top_(top), width_(width), + height_(height) { + + if (left + width > dataWidth || top + height > dataHeight || top < 0 || left < 0) { + throw IllegalArgumentException("Crop rectangle does not fit within image data."); + } +} + +unsigned char* GreyscaleLuminanceSource::getRow(int y, unsigned char* row) { + if (y < 0 || y >= this->getHeight()) { + throw IllegalArgumentException("Requested row is outside the image."); + } + int width = getWidth(); + // TODO(flyashi): determine if row has enough size. + if (row == NULL) { + row = new unsigned char[width_]; + } + int offset = (y + top_) * dataWidth_ + left_; + memcpy(row, &greyData_[offset], width); + return row; +} + +unsigned char* GreyscaleLuminanceSource::getMatrix() { + int size = width_ * height_; + unsigned char* result = new unsigned char[size]; + if (left_ == 0 && top_ == 0 && dataWidth_ == width_ && dataHeight_ == height_) { + memcpy(result, greyData_, size); + } else { + for (int row = 0; row < height_; row++) { + memcpy(result + row * width_, greyData_ + (top_ + row) * dataWidth_ + left_, width_); + } + } + return result; +} + +Ref GreyscaleLuminanceSource::rotateCounterClockwise() { + // Intentionally flip the left, top, width, and height arguments as needed. dataWidth and + // dataHeight are always kept unrotated. + return Ref (new GreyscaleRotatedLuminanceSource(greyData_, dataWidth_, + dataHeight_, top_, left_, height_, width_)); +} + +} /* namespace */ + +// file: zxing/common/GreyscaleRotatedLuminanceSource.cpp + +/* + * GreyscaleRotatedLuminanceSource.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 +// #include + +namespace zxing { + +// Note that dataWidth and dataHeight are not reversed, as we need to be able to traverse the +// greyData correctly, which does not get rotated. +GreyscaleRotatedLuminanceSource::GreyscaleRotatedLuminanceSource(unsigned char* greyData, + int dataWidth, int dataHeight, int left, int top, int width, int height) : greyData_(greyData), + dataWidth_(dataWidth), dataHeight_(dataHeight), left_(left), top_(top), width_(width), + height_(height) { + + // Intentionally comparing to the opposite dimension since we're rotated. + if (left + width > dataHeight || top + height > dataWidth) { + throw IllegalArgumentException("Crop rectangle does not fit within image data."); + } +} + +// The API asks for rows, but we're rotated, so we return columns. +unsigned char* GreyscaleRotatedLuminanceSource::getRow(int y, unsigned char* row) { + if (y < 0 || y >= getHeight()) { + throw IllegalArgumentException("Requested row is outside the image"); + } + int width = getWidth(); + if (row == NULL) { + row = new unsigned char[width]; + } + int offset = (left_ * dataWidth_) + (dataWidth_ - (y + top_)); + for (int x = 0; x < width; x++) { + row[x] = greyData_[offset]; + offset += dataWidth_; + } + return row; +} + +unsigned char* GreyscaleRotatedLuminanceSource::getMatrix() { + unsigned char* result = new unsigned char[width_ * height_]; + // This depends on getRow() honoring its second parameter. + for (int y = 0; y < height_; y++) { + getRow(y, &result[y * width_]); + } + return result; +} + +} // namespace + +// file: zxing/common/GridSampler.cpp + +/* + * GridSampler.cpp + * zxing + * + * Created by Christian Brunschen on 18/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 +// #include +// #include +// #include +// #include + +namespace zxing { +using namespace std; + +GridSampler GridSampler::gridSampler; + +GridSampler::GridSampler() { +} + +Ref GridSampler::sampleGrid(Ref image, int dimension, Ref transform) { + Ref bits(new BitMatrix(dimension)); + vector points(dimension << 1, (const float)0.0f); + for (int y = 0; y < dimension; y++) { + int max = points.size(); + float yValue = (float)y + 0.5f; + for (int x = 0; x < max; x += 2) { + points[x] = (float)(x >> 1) + 0.5f; + points[x + 1] = yValue; + } + transform->transformPoints(points); + checkAndNudgePoints(image, points); + for (int x = 0; x < max; x += 2) { + if (image->get((int)points[x], (int)points[x + 1])) { + bits->set(x >> 1, y); + } + } + } + return bits; +} + +Ref GridSampler::sampleGrid(Ref image, int dimensionX, int dimensionY, Ref transform) { + Ref bits(new BitMatrix(dimensionX, dimensionY)); + vector points(dimensionX << 1, (const float)0.0f); + for (int y = 0; y < dimensionY; y++) { + int max = points.size(); + float yValue = (float)y + 0.5f; + for (int x = 0; x < max; x += 2) { + points[x] = (float)(x >> 1) + 0.5f; + points[x + 1] = yValue; + } + transform->transformPoints(points); + checkAndNudgePoints(image, points); + for (int x = 0; x < max; x += 2) { + if (image->get((int)points[x], (int)points[x + 1])) { + bits->set(x >> 1, y); + } + } + } + return bits; +} + +Ref GridSampler::sampleGrid(Ref image, int dimension, float p1ToX, float p1ToY, float p2ToX, + float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, + float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) { + Ref transform(PerspectiveTransform::quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, + p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY)); + + return sampleGrid(image, dimension, transform); + +} + +void GridSampler::checkAndNudgePoints(Ref image, vector &points) { + int width = image->getWidth(); + int height = image->getHeight(); + + + // The Java code assumes that if the start and end points are in bounds, the rest will also be. + // However, in some unusual cases points in the middle may also be out of bounds. + // Since we can't rely on an ArrayIndexOutOfBoundsException like Java, we check every point. + + for (size_t offset = 0; offset < points.size(); offset += 2) { + int x = (int)points[offset]; + int y = (int)points[offset + 1]; + if (x < -1 || x > width || y < -1 || y > height) { + ostringstream s; + s << "Transformed point out of bounds at " << x << "," << y; + throw ReaderException(s.str().c_str()); + } + + if (x == -1) { + points[offset] = 0.0f; + } else if (x == width) { + points[offset] = width - 1; + } + if (y == -1) { + points[offset + 1] = 0.0f; + } else if (y == height) { + points[offset + 1] = height - 1; + } + } + +} + +GridSampler &GridSampler::getInstance() { + return gridSampler; +} +} + +// file: zxing/common/HybridBinarizer.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * HybridBinarizer.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 + +// #include + +using namespace std; +using namespace zxing; + +namespace { + const int BLOCK_SIZE_POWER = 3; + const int BLOCK_SIZE = 1 << BLOCK_SIZE_POWER; + const int BLOCK_SIZE_MASK = BLOCK_SIZE - 1; + const int MINIMUM_DIMENSION = BLOCK_SIZE * 5; +} + +HybridBinarizer::HybridBinarizer(Ref source) : + GlobalHistogramBinarizer(source), matrix_(NULL), cached_row_(NULL), cached_row_num_(-1) { +} + +HybridBinarizer::~HybridBinarizer() { +} + + +Ref +HybridBinarizer::createBinarizer(Ref source) { + return Ref (new HybridBinarizer(source)); +} + +Ref HybridBinarizer::getBlackMatrix() { + // Calculates the final BitMatrix once for all requests. This could + // be called once from the constructor instead, but there are some + // advantages to doing it lazily, such as making profiling easier, + // and not doing heavy lifting when callers don't expect it. + if (matrix_) { + return matrix_; + } + LuminanceSource& source = *getLuminanceSource(); + if (source.getWidth() >= MINIMUM_DIMENSION && + source.getHeight() >= MINIMUM_DIMENSION) { + unsigned char* luminances = source.getMatrix(); + int width = source.getWidth(); + int height = source.getHeight(); + int subWidth = width >> BLOCK_SIZE_POWER; + if ((width & BLOCK_SIZE_MASK) != 0) { + subWidth++; + } + int subHeight = height >> BLOCK_SIZE_POWER; + if ((height & BLOCK_SIZE_MASK) != 0) { + subHeight++; + } + int* blackPoints = + calculateBlackPoints(luminances, subWidth, subHeight, width, height); + + Ref newMatrix (new BitMatrix(width, height)); + calculateThresholdForBlock(luminances, + subWidth, + subHeight, + width, + height, + blackPoints, + newMatrix); + matrix_ = newMatrix; + + // N.B.: these deletes are inadequate if anything between the new + // and this point can throw. As of this writing, it doesn't look + // like they do. + + delete [] blackPoints; + delete [] luminances; + } else { + // If the image is too small, fall back to the global histogram approach. + matrix_ = GlobalHistogramBinarizer::getBlackMatrix(); + } + return matrix_; +} + +void +HybridBinarizer::calculateThresholdForBlock(unsigned char* luminances, + int subWidth, + int subHeight, + int width, + int height, + int blackPoints[], + Ref const& matrix) { + for (int y = 0; y < subHeight; y++) { + int yoffset = y << BLOCK_SIZE_POWER; + if (yoffset + BLOCK_SIZE >= height) { + yoffset = height - BLOCK_SIZE; + } + for (int x = 0; x < subWidth; x++) { + int xoffset = x << BLOCK_SIZE_POWER; + if (xoffset + BLOCK_SIZE >= width) { + xoffset = width - BLOCK_SIZE; + } + int left = (x > 1) ? x : 2; + left = (left < subWidth - 2) ? left : subWidth - 3; + int top = (y > 1) ? y : 2; + top = (top < subHeight - 2) ? top : subHeight - 3; + int sum = 0; + for (int z = -2; z <= 2; z++) { + int *blackRow = &blackPoints[(top + z) * subWidth]; + sum += blackRow[left - 2]; + sum += blackRow[left - 1]; + sum += blackRow[left]; + sum += blackRow[left + 1]; + sum += blackRow[left + 2]; + } + int average = sum / 25; + threshold8x8Block(luminances, xoffset, yoffset, average, width, matrix); + } + } +} + +void HybridBinarizer::threshold8x8Block(unsigned char* luminances, + int xoffset, + int yoffset, + int threshold, + int stride, + Ref const& matrix) { + for (int y = 0, offset = yoffset * stride + xoffset; + y < BLOCK_SIZE; + y++, offset += stride) { + for (int x = 0; x < BLOCK_SIZE; x++) { + int pixel = luminances[offset + x] & 0xff; + if (pixel <= threshold) { + matrix->set(xoffset + x, yoffset + y); + } + } + } +} + +namespace { + inline int getBlackPointFromNeighbors(int* blackPoints, int subWidth, int x, int y) { + return (blackPoints[(y-1)*subWidth+x] + + 2*blackPoints[y*subWidth+x-1] + + blackPoints[(y-1)*subWidth+x-1]) >> 2; + } +} + +int* HybridBinarizer::calculateBlackPoints(unsigned char* luminances, int subWidth, int subHeight, + int width, int height) { + int *blackPoints = new int[subHeight * subWidth]; + for (int y = 0; y < subHeight; y++) { + int yoffset = y << BLOCK_SIZE_POWER; + if (yoffset + BLOCK_SIZE >= height) { + yoffset = height - BLOCK_SIZE; + } + for (int x = 0; x < subWidth; x++) { + int xoffset = x << BLOCK_SIZE_POWER; + if (xoffset + BLOCK_SIZE >= width) { + xoffset = width - BLOCK_SIZE; + } + int sum = 0; + int min = 0xFF; + int max = 0; + for (int yy = 0, offset = yoffset * width + xoffset; + yy < BLOCK_SIZE; + yy++, offset += width) { + for (int xx = 0; xx < BLOCK_SIZE; xx++) { + int pixel = luminances[offset + xx] & 0xFF; + sum += pixel; + if (pixel < min) { + min = pixel; + } + if (pixel > max) { + max = pixel; + } + } + } + + // See + // http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0 + int average = sum >> 6; + if (max - min <= 24) { + average = min >> 1; + if (y > 0 && x > 0) { + int bp = getBlackPointFromNeighbors(blackPoints, subWidth, x, y); + if (min < bp) { + average = bp; + } + } + } + blackPoints[y * subWidth + x] = average; + } + } + return blackPoints; +} + + +// file: zxing/common/IllegalArgumentException.cpp + +/* + * IllegalArgumentException.cpp + * zxing + * + * Created by Christian Brunschen on 06/05/2008. + * Copyright 2008 Google UK. 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 + +namespace zxing { + +IllegalArgumentException::IllegalArgumentException(const char *msg) : + Exception(msg) { +} +IllegalArgumentException::~IllegalArgumentException() throw() { + +} +} + +// file: zxing/common/PerspectiveTransform.cpp + +/* + * PerspectiveTransform.cpp + * zxing + * + * Created by Christian Brunschen on 12/05/2008. + * Copyright 2008 Google UK. 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 + +namespace zxing { +using namespace std; + +PerspectiveTransform::PerspectiveTransform(float inA11, float inA21, + float inA31, float inA12, + float inA22, float inA32, + float inA13, float inA23, + float inA33) : + a11(inA11), a12(inA12), a13(inA13), a21(inA21), a22(inA22), a23(inA23), + a31(inA31), a32(inA32), a33(inA33) {} + +Ref PerspectiveTransform::quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, + float x3p, float y3p) { + Ref qToS = PerspectiveTransform::quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3); + Ref sToQ = + PerspectiveTransform::squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); + return sToQ->times(qToS); +} + +Ref PerspectiveTransform::squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2, + float y2, float x3, float y3) { + float dy2 = y3 - y2; + float dy3 = y0 - y1 + y2 - y3; + if (dy2 == 0.0f && dy3 == 0.0f) { + Ref result(new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0f, + 0.0f, 1.0f)); + return result; + } else { + float dx1 = x1 - x2; + float dx2 = x3 - x2; + float dx3 = x0 - x1 + x2 - x3; + float dy1 = y1 - y2; + float denominator = dx1 * dy2 - dx2 * dy1; + float a13 = (dx3 * dy2 - dx2 * dy3) / denominator; + float a23 = (dx1 * dy3 - dx3 * dy1) / denominator; + Ref result(new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0f)); + return result; + } +} + +Ref PerspectiveTransform::quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, + float y2, float x3, float y3) { + // Here, the adjoint serves as the inverse: + return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3)->buildAdjoint(); +} + +Ref PerspectiveTransform::buildAdjoint() { + // Adjoint is the transpose of the cofactor matrix: + Ref result(new PerspectiveTransform(a22 * a33 - a23 * a32, a23 * a31 - a21 * a33, a21 * a32 + - a22 * a31, a13 * a32 - a12 * a33, a11 * a33 - a13 * a31, a12 * a31 - a11 * a32, a12 * a23 - a13 * a22, + a13 * a21 - a11 * a23, a11 * a22 - a12 * a21)); + return result; +} + +Ref PerspectiveTransform::times(Ref other) { + Ref result(new PerspectiveTransform(a11 * other->a11 + a21 * other->a12 + a31 * other->a13, + a11 * other->a21 + a21 * other->a22 + a31 * other->a23, a11 * other->a31 + a21 * other->a32 + a31 + * other->a33, a12 * other->a11 + a22 * other->a12 + a32 * other->a13, a12 * other->a21 + a22 + * other->a22 + a32 * other->a23, a12 * other->a31 + a22 * other->a32 + a32 * other->a33, a13 + * other->a11 + a23 * other->a12 + a33 * other->a13, a13 * other->a21 + a23 * other->a22 + a33 + * other->a23, a13 * other->a31 + a23 * other->a32 + a33 * other->a33)); + return result; +} + +void PerspectiveTransform::transformPoints(vector &points) { + int max = points.size(); + for (int i = 0; i < max; i += 2) { + float x = points[i]; + float y = points[i + 1]; + float denominator = a13 * x + a23 * y + a33; + points[i] = (a11 * x + a21 * y + a31) / denominator; + points[i + 1] = (a12 * x + a22 * y + a32) / denominator; + } +} + +ostream& operator<<(ostream& out, const PerspectiveTransform &pt) { + out << pt.a11 << ", " << pt.a12 << ", " << pt.a13 << ", \n"; + out << pt.a21 << ", " << pt.a22 << ", " << pt.a23 << ", \n"; + out << pt.a31 << ", " << pt.a32 << ", " << pt.a33 << "\n"; + return out; +} + +} + +// file: zxing/common/Str.cpp + +/* + * String.cpp + * zxing + * + * Created by Christian Brunschen on 20/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 + +namespace zxing { +using namespace std; + +String::String(const std::string &text) : + text_(text) { +} +const std::string& String::getText() const { + return text_; +} + +ostream &operator<<(ostream &out, const String &s) { + out << s.text_; + return out; +} + +} + +// file: zxing/common/StringUtils.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +/* + * Copyright (C) 2010-2011 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 +// #include + +using namespace std; +using namespace zxing; +using namespace zxing::common; + +// N.B.: these are the iconv strings for at least some versions of iconv + +char const* const StringUtils::PLATFORM_DEFAULT_ENCODING = "UTF-8"; +char const* const StringUtils::ASCII = "ASCII"; +char const* const StringUtils::SHIFT_JIS = "SHIFT_JIS"; +char const* const StringUtils::GB2312 = "GBK"; +char const* const StringUtils::EUC_JP = "EUC-JP"; +char const* const StringUtils::UTF8 = "UTF-8"; +char const* const StringUtils::ISO88591 = "ISO8859-1"; +const bool StringUtils::ASSUME_SHIFT_JIS = false; + +string +StringUtils::guessEncoding(unsigned char* bytes, int length, Hashtable const& hints) { + Hashtable::const_iterator i = hints.find(DecodeHints::CHARACTER_SET); + if (i != hints.end()) { + return i->second; + } + // Does it start with the UTF-8 byte order mark? then guess it's UTF-8 + if (length > 3 && + bytes[0] == (unsigned char) 0xEF && + bytes[1] == (unsigned char) 0xBB && + bytes[2] == (unsigned char) 0xBF) { + return UTF8; + } + // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, + // which should be by far the most common encodings. ISO-8859-1 + // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS + // uses this as a first byte of a two-byte character. If we see this + // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS. + // If we see something else in that second byte, we'll make the risky guess + // that it's UTF-8. + bool canBeISO88591 = true; + bool canBeShiftJIS = true; + bool canBeUTF8 = true; + int utf8BytesLeft = 0; + int maybeDoubleByteCount = 0; + int maybeSingleByteKatakanaCount = 0; + bool sawLatin1Supplement = false; + bool sawUTF8Start = false; + bool lastWasPossibleDoubleByteStart = false; + + for (int i = 0; + i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8); + i++) { + + int value = bytes[i] & 0xFF; + + // UTF-8 stuff + if (value >= 0x80 && value <= 0xBF) { + if (utf8BytesLeft > 0) { + utf8BytesLeft--; + } + } else { + if (utf8BytesLeft > 0) { + canBeUTF8 = false; + } + if (value >= 0xC0 && value <= 0xFD) { + sawUTF8Start = true; + int valueCopy = value; + while ((valueCopy & 0x40) != 0) { + utf8BytesLeft++; + valueCopy <<= 1; + } + } + } + + // ISO-8859-1 stuff + + if ((value == 0xC2 || value == 0xC3) && i < length - 1) { + // This is really a poor hack. The slightly more exotic characters people might want to put in + // a QR Code, by which I mean the Latin-1 supplement characters (e.g. u-umlaut) have encodings + // that start with 0xC2 followed by [0xA0,0xBF], or start with 0xC3 followed by [0x80,0xBF]. + int nextValue = bytes[i + 1] & 0xFF; + if (nextValue <= 0xBF && + ((value == 0xC2 && nextValue >= 0xA0) || (value == 0xC3 && nextValue >= 0x80))) { + sawLatin1Supplement = true; + } + } + if (value >= 0x7F && value <= 0x9F) { + canBeISO88591 = false; + } + + // Shift_JIS stuff + + if (value >= 0xA1 && value <= 0xDF) { + // count the number of characters that might be a Shift_JIS single-byte Katakana character + if (!lastWasPossibleDoubleByteStart) { + maybeSingleByteKatakanaCount++; + } + } + if (!lastWasPossibleDoubleByteStart && + ((value >= 0xF0 && value <= 0xFF) || value == 0x80 || value == 0xA0)) { + canBeShiftJIS = false; + } + if ((value >= 0x81 && value <= 0x9F) || (value >= 0xE0 && value <= 0xEF)) { + // These start double-byte characters in Shift_JIS. Let's see if it's followed by a valid + // second byte. + if (lastWasPossibleDoubleByteStart) { + // If we just checked this and the last byte for being a valid double-byte + // char, don't check starting on this byte. If this and the last byte + // formed a valid pair, then this shouldn't be checked to see if it starts + // a double byte pair of course. + lastWasPossibleDoubleByteStart = false; + } else { + // ... otherwise do check to see if this plus the next byte form a valid + // double byte pair encoding a character. + lastWasPossibleDoubleByteStart = true; + if (i >= length - 1) { + canBeShiftJIS = false; + } else { + int nextValue = bytes[i + 1] & 0xFF; + if (nextValue < 0x40 || nextValue > 0xFC) { + canBeShiftJIS = false; + } else { + maybeDoubleByteCount++; + } + // There is some conflicting information out there about which bytes can follow which in + // double-byte Shift_JIS characters. The rule above seems to be the one that matches practice. + } + } + } else { + lastWasPossibleDoubleByteStart = false; + } + } + if (utf8BytesLeft > 0) { + canBeUTF8 = false; + } + + // Easy -- if assuming Shift_JIS and no evidence it can't be, done + if (canBeShiftJIS && ASSUME_SHIFT_JIS) { + return SHIFT_JIS; + } + if (canBeUTF8 && sawUTF8Start) { + return UTF8; + } + // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough. The crude heuristic is: + // - If we saw + // - at least 3 bytes that starts a double-byte value (bytes that are rare in ISO-8859-1), or + // - over 5% of bytes could be single-byte Katakana (also rare in ISO-8859-1), + // - and, saw no sequences that are invalid in Shift_JIS, then we conclude Shift_JIS + if (canBeShiftJIS && (maybeDoubleByteCount >= 3 || 20 * maybeSingleByteKatakanaCount > length)) { + return SHIFT_JIS; + } + // Otherwise, we default to ISO-8859-1 unless we know it can't be + if (!sawLatin1Supplement && canBeISO88591) { + return ISO88591; + } + // Otherwise, we take a wild guess with platform encoding + return PLATFORM_DEFAULT_ENCODING; +} + +// file: zxing/common/detector/MonochromeRectangleDetector.cpp + +/* + * MonochromeRectangleDetector.cpp + * y_wmk + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 y_wmk 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 +// #include +// #include + +namespace zxing { +using namespace std; + +std::vector > MonochromeRectangleDetector::detect() { + int height = image_->getHeight(); + int width = image_->getWidth(); + int halfHeight = height >> 1; + int halfWidth = width >> 1; + int deltaY = max(1, height / (MAX_MODULES << 3)); + int deltaX = max(1, width / (MAX_MODULES << 3)); + + int top = 0; + int bottom = height; + int left = 0; + int right = width; + Ref pointA(findCornerFromCenter(halfWidth, 0, left, right, + halfHeight, -deltaY, top, bottom, halfWidth >> 1)); + top = (int) pointA->getY() - 1;; + Ref pointB(findCornerFromCenter(halfWidth, -deltaX, left, right, + halfHeight, 0, top, bottom, halfHeight >> 1)); + left = (int) pointB->getX() - 1; + Ref pointC(findCornerFromCenter(halfWidth, deltaX, left, right, + halfHeight, 0, top, bottom, halfHeight >> 1)); + right = (int) pointC->getX() + 1; + Ref pointD(findCornerFromCenter(halfWidth, 0, left, right, + halfHeight, deltaY, top, bottom, halfWidth >> 1)); + bottom = (int) pointD->getY() + 1; + + // Go try to find point A again with better information -- might have been off at first. + pointA.reset(findCornerFromCenter(halfWidth, 0, left, right, + halfHeight, -deltaY, top, bottom, halfWidth >> 2)); + + std::vector > corners(4); + corners[0].reset(pointA); + corners[1].reset(pointB); + corners[2].reset(pointC); + corners[3].reset(pointD); + return corners; + } + +Ref MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right, + int centerY, int deltaY, int top, int bottom, int maxWhiteRun) { + Ref lastRange(NULL); + for (int y = centerY, x = centerX; + y < bottom && y >= top && x < right && x >= left; + y += deltaY, x += deltaX) { + Ref range(NULL); + if (deltaX == 0) { + // horizontal slices, up and down + range = blackWhiteRange(y, maxWhiteRun, left, right, true); + } else { + // vertical slices, left and right + range = blackWhiteRange(x, maxWhiteRun, top, bottom, false); + } + if (range == NULL) { + if (lastRange == NULL) { + throw NotFoundException("Couldn't find corners (lastRange = NULL) "); + } else { + // lastRange was found + if (deltaX == 0) { + int lastY = y - deltaY; + if (lastRange->start < centerX) { + if (lastRange->end > centerX) { + // straddle, choose one or the other based on direction + Ref result(new ResultPoint(deltaY > 0 ? lastRange->start : lastRange->end, lastY)); + return result; + } + Ref result(new ResultPoint(lastRange->start, lastY)); + return result; + } else { + Ref result(new ResultPoint(lastRange->end, lastY)); + return result; + } + } else { + int lastX = x - deltaX; + if (lastRange->start < centerY) { + if (lastRange->end > centerY) { + Ref result(new ResultPoint(lastX, deltaX < 0 ? lastRange->start : lastRange->end)); + return result; + } + Ref result(new ResultPoint(lastX, lastRange->start)); + return result; + } else { + Ref result(new ResultPoint(lastX, lastRange->end)); + return result; + } + } + } + } + lastRange = range; + } + throw NotFoundException("Couldn't find corners"); + } + +Ref MonochromeRectangleDetector::blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, + bool horizontal) { + + int center = (minDim + maxDim) >> 1; + + // Scan left/up first + int start = center; + while (start >= minDim) { + if (horizontal ? image_->get(start, fixedDimension) : image_->get(fixedDimension, start)) { + start--; + } else { + int whiteRunStart = start; + do { + start--; + } while (start >= minDim && !(horizontal ? image_->get(start, fixedDimension) : + image_->get(fixedDimension, start))); + int whiteRunSize = whiteRunStart - start; + if (start < minDim || whiteRunSize > maxWhiteRun) { + start = whiteRunStart; + break; + } + } + } + start++; + + // Then try right/down + int end = center; + while (end < maxDim) { + if (horizontal ? image_->get(end, fixedDimension) : image_->get(fixedDimension, end)) { + end++; + } else { + int whiteRunStart = end; + do { + end++; + } while (end < maxDim && !(horizontal ? image_->get(end, fixedDimension) : + image_->get(fixedDimension, end))); + int whiteRunSize = end - whiteRunStart; + if (end >= maxDim || whiteRunSize > maxWhiteRun) { + end = whiteRunStart; + break; + } + } + } + end--; + Ref result(NULL); + if (end > start) { + result = new TwoInts; + result->start = start; + result->end = end; + } + return result; + } +} + +// file: zxing/common/detector/WhiteRectangleDetector.cpp + +/* + * WhiteRectangleDetector.cpp + * y_wmk + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 y_wmk 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 +// #include +// #include +// #include + +namespace zxing { +using namespace std; + +int WhiteRectangleDetector::INIT_SIZE = 30; +int WhiteRectangleDetector::CORR = 1; + + +WhiteRectangleDetector::WhiteRectangleDetector(Ref image) : image_(image) { + width_ = image->getWidth(); + height_ = image->getHeight(); +} + +/** + *

+ * Detects a candidate barcode-like rectangular region within an image. It + * starts around the center of the image, increases the size of the candidate + * region until it finds a white rectangular region. + *

+ * + * @return {@link vector >} describing the corners of the rectangular + * region. The first and last points are opposed on the diagonal, as + * are the second and third. The first point will be the topmost + * point and the last, the bottommost. The second point will be + * leftmost and the third, the rightmost + * @throws NotFoundException if no Data Matrix Code can be found +*/ +std::vector > WhiteRectangleDetector::detect() { + int left = (width_ - INIT_SIZE) >> 1; + int right = (width_ + INIT_SIZE) >> 1; + int up = (height_ - INIT_SIZE) >> 1; + int down = (height_ + INIT_SIZE) >> 1; + if (up < 0 || left < 0 || down >= height_ || right >= width_) { + throw NotFoundException("Invalid dimensions WhiteRectangleDetector"); + } + + bool sizeExceeded = false; + bool aBlackPointFoundOnBorder = true; + bool atLeastOneBlackPointFoundOnBorder = false; + + while (aBlackPointFoundOnBorder) { + aBlackPointFoundOnBorder = false; + + // ..... + // . | + // ..... + bool rightBorderNotWhite = true; + while (rightBorderNotWhite && right < width_) { + rightBorderNotWhite = containsBlackPoint(up, down, right, false); + if (rightBorderNotWhite) { + right++; + aBlackPointFoundOnBorder = true; + } + } + + if (right >= width_) { + sizeExceeded = true; + break; + } + + // ..... + // . . + // .___. + bool bottomBorderNotWhite = true; + while (bottomBorderNotWhite && down < height_) { + bottomBorderNotWhite = containsBlackPoint(left, right, down, true); + if (bottomBorderNotWhite) { + down++; + aBlackPointFoundOnBorder = true; + } + } + + if (down >= height_) { + sizeExceeded = true; + break; + } + + // ..... + // | . + // ..... + bool leftBorderNotWhite = true; + while (leftBorderNotWhite && left >= 0) { + leftBorderNotWhite = containsBlackPoint(up, down, left, false); + if (leftBorderNotWhite) { + left--; + aBlackPointFoundOnBorder = true; + } + } + + if (left < 0) { + sizeExceeded = true; + break; + } + + // .___. + // . . + // ..... + bool topBorderNotWhite = true; + while (topBorderNotWhite && up >= 0) { + topBorderNotWhite = containsBlackPoint(left, right, up, true); + if (topBorderNotWhite) { + up--; + aBlackPointFoundOnBorder = true; + } + } + + if (up < 0) { + sizeExceeded = true; + break; + } + + if (aBlackPointFoundOnBorder) { + atLeastOneBlackPointFoundOnBorder = true; + } + + } + if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) { + + int maxSize = right - left; + + Ref z(NULL); + //go up right + for (int i = 1; i < maxSize; i++) { + z = getBlackPointOnSegment(left, down - i, left + i, down); + if (z != NULL) { + break; + } + } + + if (z == NULL) { + throw NotFoundException("z == NULL"); + } + + Ref t(NULL); + //go down right + for (int i = 1; i < maxSize; i++) { + t = getBlackPointOnSegment(left, up + i, left + i, up); + if (t != NULL) { + break; + } + } + + if (t == NULL) { + throw NotFoundException("t == NULL"); + } + + Ref x(NULL); + //go down left + for (int i = 1; i < maxSize; i++) { + x = getBlackPointOnSegment(right, up + i, right - i, up); + if (x != NULL) { + break; + } + } + + if (x == NULL) { + throw NotFoundException("x == NULL"); + } + + Ref y(NULL); + //go up left + for (int i = 1; i < maxSize; i++) { + y = getBlackPointOnSegment(right, down - i, right - i, down); + if (y != NULL) { + break; + } + } + + if (y == NULL) { + throw NotFoundException("y == NULL"); + } + + return centerEdges(y, z, x, t); + + } else { + throw NotFoundException("No black point found on border"); + } +} + +/** + * Ends up being a bit faster than Math.round(). This merely rounds its + * argument to the nearest int, where x.5 rounds up. + */ +int WhiteRectangleDetector::round(float d) { + return (int) (d + 0.5f); +} + +Ref WhiteRectangleDetector::getBlackPointOnSegment(float aX, float aY, float bX, float bY) { + int dist = distanceL2(aX, aY, bX, bY); + float xStep = (bX - aX) / dist; + float yStep = (bY - aY) / dist; + for (int i = 0; i < dist; i++) { + int x = round(aX + i * xStep); + int y = round(aY + i * yStep); + if (image_->get(x, y)) { + Ref point(new ResultPoint(x, y)); + return point; + } + } + Ref point(NULL); + return point; +} + +int WhiteRectangleDetector::distanceL2(float aX, float aY, float bX, float bY) { + float xDiff = aX - bX; + float yDiff = aY - bY; + return round((float)sqrt(xDiff * xDiff + yDiff * yDiff)); +} + +/** + * recenters the points of a constant distance towards the center + * + * @param y bottom most point + * @param z left most point + * @param x right most point + * @param t top most point + * @return {@link vector >} describing the corners of the rectangular + * region. The first and last points are opposed on the diagonal, as + * are the second and third. The first point will be the topmost + * point and the last, the bottommost. The second point will be + * leftmost and the third, the rightmost + */ +vector > WhiteRectangleDetector::centerEdges(Ref y, Ref z, + Ref x, Ref t) { + + // + // t t + // z x + // x OR z + // y y + // + + float yi = y->getX(); + float yj = y->getY(); + float zi = z->getX(); + float zj = z->getY(); + float xi = x->getX(); + float xj = x->getY(); + float ti = t->getX(); + float tj = t->getY(); + + std::vector > corners(4); + if (yi < (float)width_/2) { + Ref pointA(new ResultPoint(ti - CORR, tj + CORR)); + Ref pointB(new ResultPoint(zi + CORR, zj + CORR)); + Ref pointC(new ResultPoint(xi - CORR, xj - CORR)); + Ref pointD(new ResultPoint(yi + CORR, yj - CORR)); + corners[0].reset(pointA); + corners[1].reset(pointB); + corners[2].reset(pointC); + corners[3].reset(pointD); + } else { + Ref pointA(new ResultPoint(ti + CORR, tj + CORR)); + Ref pointB(new ResultPoint(zi + CORR, zj - CORR)); + Ref pointC(new ResultPoint(xi - CORR, xj + CORR)); + Ref pointD(new ResultPoint(yi - CORR, yj - CORR)); + corners[0].reset(pointA); + corners[1].reset(pointB); + corners[2].reset(pointC); + corners[3].reset(pointD); + } + return corners; +} + +/** + * Determines whether a segment contains a black point + * + * @param a min value of the scanned coordinate + * @param b max value of the scanned coordinate + * @param fixed value of fixed coordinate + * @param horizontal set to true if scan must be horizontal, false if vertical + * @return true if a black point has been found, else false. + */ +bool WhiteRectangleDetector::containsBlackPoint(int a, int b, int fixed, bool horizontal) { + if (horizontal) { + for (int x = a; x <= b; x++) { + if (image_->get(x, fixed)) { + return true; + } + } + } else { + for (int y = a; y <= b; y++) { + if (image_->get(fixed, y)) { + return true; + } + } + } + + return false; +} +} + +// file: zxing/common/reedsolomon/GF256.cpp + +/* + * GF256.cpp + * zxing + * + * Created by Christian Brunschen on 05/05/2008. + * Copyright 2008 Google UK. 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 +// #include +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +using namespace std; + +static inline ArrayRef makeArray(int value) { + ArrayRef valuesRef(new Array (value, 1)); + return valuesRef; +} + +static inline Ref refPoly(GF256 &field, int value) { + ArrayRef values(makeArray(value)); + Ref result(new GF256Poly(field, values)); + return result; +} + +GF256::GF256(int primitive) : + exp_(256, (const int)0), log_(256, (const int)0), zero_(refPoly(*this, 0)), one_(refPoly(*this, 1)) { + int x = 1; + for (int i = 0; i < 256; i++) { + exp_[i] = x; + x <<= 1; + if (x >= 0x100) { + x ^= primitive; + } + } + + // log(0) == 0, but should never be used + log_[0] = 0; + for (int i = 0; i < 255; i++) { + log_[exp_[i]] = i; + } +} + +Ref GF256::getZero() { + return zero_; +} + +Ref GF256::getOne() { + return one_; +} + +Ref GF256::buildMonomial(int degree, int coefficient) { +#ifdef DEBUG + cout << __FUNCTION__ << "\n"; +#endif + if (degree < 0) { + throw IllegalArgumentException("Degree must be non-negative"); + } + if (coefficient == 0) { + return zero_; + } + int nCoefficients = degree + 1; + ArrayRef coefficients(new Array (nCoefficients)); + coefficients[0] = coefficient; + Ref result(new GF256Poly(*this, coefficients)); + return result; +} + +int GF256::addOrSubtract(int a, int b) { + return a ^ b; +} + +int GF256::exp(int a) { + return exp_[a]; +} + +int GF256::log(int a) { + if (a == 0) { + throw IllegalArgumentException("Cannot take the logarithm of 0"); + } + return log_[a]; +} + +int GF256::inverse(int a) { + if (a == 0) { + throw IllegalArgumentException("Cannot calculate the inverse of 0"); + } + return exp_[255 - log_[a]]; +} + +int GF256::multiply(int a, int b) { + if (a == 0 || b == 0) { + return 0; + } + int logSum = log_[a] + log_[b]; + // index is a sped-up alternative to logSum % 255 since sum + // is in [0,510]. Thanks to jmsachs for the idea + return exp_[(logSum & 0xFF) + (logSum >> 8)]; +} + +GF256 GF256::QR_CODE_FIELD(0x011D); // x^8 + x^4 + x^3 + x^2 + 1 +GF256 GF256::DATA_MATRIX_FIELD(0x012D); // x^8 + x^5 + x^3 + x^2 + 1 + +ostream& operator<<(ostream& out, const GF256& field) { + out << "Field[\nexp=("; + out << field.exp_[0]; + for (int i = 1; i < 256; i++) { + out << "," << field.exp_[i]; + } + out << "),\nlog=("; + out << field.log_[0]; + for (int i = 1; i < 256; i++) { + out << "," << field.log_[i]; + } + out << ")\n]"; + return out; +} + +} + +// file: zxing/common/reedsolomon/GF256Poly.cpp + +/* + * GF256Poly.cpp + * zxing + * + * Created by Christian Brunschen on 05/05/2008. + * Copyright 2008 Google UK. 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 +// #include +// #include +// #include +// #include + +namespace zxing { +using namespace std; + +void GF256Poly::fixCoefficients() { + int coefficientsLength = coefficients.size(); + if (coefficientsLength > 1 && coefficients[0] == 0) { + // Leading term must be non-zero for anything except + // the constant polynomial "0" + int firstNonZero = 1; + while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) { + firstNonZero++; + } + if (firstNonZero == coefficientsLength) { + coefficientsLength = field.getZero()->coefficients.size(); + coefficients.reset(new Array (coefficientsLength)); + *coefficients = *(field.getZero()->coefficients); + } else { + ArrayRef c(coefficients); + coefficientsLength -= firstNonZero; + coefficients.reset(new Array (coefficientsLength)); + for (int i = 0; i < coefficientsLength; i++) { + coefficients[i] = c[i + firstNonZero]; + } + } + } +} + +GF256Poly::GF256Poly(GF256 &f, ArrayRef c) : + Counted(), field(f), coefficients(c) { + fixCoefficients(); +} + +GF256Poly::~GF256Poly() { + +} + +int GF256Poly::getDegree() { + return coefficients.size() - 1; +} + +bool GF256Poly::isZero() { + return coefficients[0] == 0; +} + +int GF256Poly::getCoefficient(int degree) { + return coefficients[coefficients.size() - 1 - degree]; +} + +int GF256Poly::evaluateAt(int a) { + if (a == 0) { + return getCoefficient(0); + } + int size = coefficients.size(); + if (a == 1) { + // Just the sum of the coefficients + int result = 0; + for (int i = 0; i < size; i++) { + result = GF256::addOrSubtract(result, coefficients[i]); + } + return result; + } + int result = coefficients[0]; + for (int i = 1; i < size; i++) { + result = GF256::addOrSubtract(field.multiply(a, result), coefficients[i]); + } + return result; +} + +Ref GF256Poly::addOrSubtract(Ref b) { + if (&field != &b->field) { + throw IllegalArgumentException("Fields must be the same"); + } + if (isZero()) { + return b; + } + if (b->isZero()) { + return Ref(this); + } + + ArrayRef largerCoefficients = coefficients; + ArrayRef smallerCoefficients = b->coefficients; + if (smallerCoefficients.size() > largerCoefficients.size()) { + ArrayRef tmp(smallerCoefficients); + smallerCoefficients = largerCoefficients; + largerCoefficients = tmp; + } + + ArrayRef sumDiff(new Array (largerCoefficients.size())); + + unsigned lengthDiff = largerCoefficients.size() - smallerCoefficients.size(); + for (unsigned i = 0; i < lengthDiff; i++) { + sumDiff[i] = largerCoefficients[i]; + } + for (unsigned i = lengthDiff; i < largerCoefficients.size(); i++) { + sumDiff[i] = GF256::addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); + } + return Ref(new GF256Poly(field, sumDiff)); +} + +Ref GF256Poly::multiply(Ref b) { + if (&field != &b->field) { + throw IllegalArgumentException("Fields must be the same"); + } + if (isZero() || b->isZero()) { + return field.getZero(); + } + ArrayRef aCoefficients = coefficients; + int aLength = aCoefficients.size(); + ArrayRef bCoefficients = b->coefficients; + int bLength = bCoefficients.size(); + int productLength = aLength + bLength - 1; + ArrayRef product(new Array (productLength)); + for (int i = 0; i < aLength; i++) { + int aCoeff = aCoefficients[i]; + for (int j = 0; j < bLength; j++) { + product[i + j] = GF256::addOrSubtract(product[i + j], field.multiply(aCoeff, bCoefficients[j])); + } + } + + return Ref(new GF256Poly(field, product)); +} + +Ref GF256Poly::multiply(int scalar) { + if (scalar == 0) { + return field.getZero(); + } + if (scalar == 1) { + return Ref(this); + } + int size = coefficients.size(); + ArrayRef product(new Array (size)); + for (int i = 0; i < size; i++) { + product[i] = field.multiply(coefficients[i], scalar); + } + return Ref(new GF256Poly(field, product)); +} + +Ref GF256Poly::multiplyByMonomial(int degree, int coefficient) { + if (degree < 0) { + throw IllegalArgumentException("Degree must be non-negative"); + } + if (coefficient == 0) { + return field.getZero(); + } + int size = coefficients.size(); + ArrayRef product(new Array (size + degree)); + for (int i = 0; i < size; i++) { + product[i] = field.multiply(coefficients[i], coefficient); + } + return Ref(new GF256Poly(field, product)); +} + +const char *GF256Poly::description() const { + ostringstream result; + result << *this; + return result.str().c_str(); +} + +ostream& operator<<(ostream& out, const GF256Poly& p) { + GF256Poly &poly = const_cast(p); + out << "Poly[" << poly.coefficients.size() << "]"; + if (poly.coefficients.size() > 0) { + out << "(" << poly.coefficients[0]; + for (unsigned i = 1; i < poly.coefficients.size(); i++) { + out << "," << poly.coefficients[i]; + } + out << ")"; + } + return out; +} + +} + +// file: zxing/common/reedsolomon/ReedSolomonDecoder.cpp + +/* + * ReedSolomonDecoder.cpp + * zxing + * + * Created by Christian Brunschen on 05/05/2008. + * Copyright 2008 Google UK. 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 + +// #include +// #include +// #include +// #include +// #include +// #include + +using namespace std; + +namespace zxing { + +ReedSolomonDecoder::ReedSolomonDecoder(GF256 &fld) : + field(fld) { +} + +ReedSolomonDecoder::~ReedSolomonDecoder() { +} + +void ReedSolomonDecoder::decode(ArrayRef received, int twoS) { + + Ref poly(new GF256Poly(field, received)); + + +#ifdef DEBUG + cout << "decoding with poly " << *poly << "\n"; +#endif + + ArrayRef syndromeCoefficients(new Array (twoS)); + + +#ifdef DEBUG + cout << "syndromeCoefficients array = " << + syndromeCoefficients.array_ << "\n"; +#endif + + bool dataMatrix = (&field == &GF256::DATA_MATRIX_FIELD); + bool noError = true; + for (int i = 0; i < twoS; i++) { + int eval = poly->evaluateAt(field.exp(dataMatrix ? i + 1 : i)); + syndromeCoefficients[syndromeCoefficients->size() - 1 - i] = eval; + if (eval != 0) { + noError = false; + } + } + if (noError) { + return; + } + + Ref syndrome(new GF256Poly(field, syndromeCoefficients)); + Ref monomial(field.buildMonomial(twoS, 1)); + vector > sigmaOmega(runEuclideanAlgorithm(monomial, syndrome, twoS)); + ArrayRef errorLocations = findErrorLocations(sigmaOmega[0]); + ArrayRef errorMagitudes = findErrorMagnitudes(sigmaOmega[1], errorLocations, dataMatrix); + for (unsigned i = 0; i < errorLocations->size(); i++) { + int position = received->size() - 1 - field.log(errorLocations[i]); + //TODO: check why the position would be invalid + if (position < 0 || (size_t)position >= received.size()) + throw IllegalArgumentException("Invalid position (ReedSolomonDecoder)"); + received[position] = GF256::addOrSubtract(received[position], errorMagitudes[i]); + } +} + +vector > ReedSolomonDecoder::runEuclideanAlgorithm(Ref a, Ref b, int R) { + // Assume a's degree is >= b's + if (a->getDegree() < b->getDegree()) { + Ref tmp = a; + a = b; + b = tmp; + } + + Ref rLast(a); + Ref r(b); + Ref sLast(field.getOne()); + Ref s(field.getZero()); + Ref tLast(field.getZero()); + Ref t(field.getOne()); + + + // Run Euclidean algorithm until r's degree is less than R/2 + while (r->getDegree() >= R / 2) { + Ref rLastLast(rLast); + Ref sLastLast(sLast); + Ref tLastLast(tLast); + rLast = r; + sLast = s; + tLast = t; + + + // Divide rLastLast by rLast, with quotient q and remainder r + if (rLast->isZero()) { + // Oops, Euclidean algorithm already terminated? + throw ReedSolomonException("r_{i-1} was zero"); + } + r = rLastLast; + Ref q(field.getZero()); + int denominatorLeadingTerm = rLast->getCoefficient(rLast->getDegree()); + int dltInverse = field.inverse(denominatorLeadingTerm); + while (r->getDegree() >= rLast->getDegree() && !r->isZero()) { + int degreeDiff = r->getDegree() - rLast->getDegree(); + int scale = field.multiply(r->getCoefficient(r->getDegree()), dltInverse); + q = q->addOrSubtract(field.buildMonomial(degreeDiff, scale)); + r = r->addOrSubtract(rLast->multiplyByMonomial(degreeDiff, scale)); + } + + s = q->multiply(sLast)->addOrSubtract(sLastLast); + t = q->multiply(tLast)->addOrSubtract(tLastLast); + } + + int sigmaTildeAtZero = t->getCoefficient(0); + if (sigmaTildeAtZero == 0) { + throw ReedSolomonException("sigmaTilde(0) was zero"); + } + + int inverse = field.inverse(sigmaTildeAtZero); + Ref sigma(t->multiply(inverse)); + Ref omega(r->multiply(inverse)); + + +#ifdef DEBUG + cout << "t = " << *t << "\n"; + cout << "r = " << *r << "\n"; + cout << "sigma = " << *sigma << "\n"; + cout << "omega = " << *omega << "\n"; +#endif + + vector > result(2); + result[0] = sigma; + result[1] = omega; + return result; +} + +ArrayRef ReedSolomonDecoder::findErrorLocations(Ref errorLocator) { + // This is a direct application of Chien's search + int numErrors = errorLocator->getDegree(); + if (numErrors == 1) { // shortcut + ArrayRef result(1); + result[0] = errorLocator->getCoefficient(1); + return result; + } + ArrayRef result(numErrors); + int e = 0; + for (int i = 1; i < 256 && e < numErrors; i++) { + // cout << "errorLocator(" << i << ") == " << errorLocator->evaluateAt(i) << "\n"; + if (errorLocator->evaluateAt(i) == 0) { + result[e] = field.inverse(i); + e++; + } + } + if (e != numErrors) { + throw ReedSolomonException("Error locator degree does not match number of roots"); + } + return result; +} + +ArrayRef ReedSolomonDecoder::findErrorMagnitudes(Ref errorEvaluator, ArrayRef errorLocations, bool dataMatrix) { + // This is directly applying Forney's Formula + int s = errorLocations.size(); + ArrayRef result(s); + for (int i = 0; i < s; i++) { + int xiInverse = field.inverse(errorLocations[i]); + int denominator = 1; + for (int j = 0; j < s; j++) { + if (i != j) { + denominator = field.multiply(denominator, GF256::addOrSubtract(1, field.multiply(errorLocations[j], + xiInverse))); + } + } + result[i] = field.multiply(errorEvaluator->evaluateAt(xiInverse), field.inverse(denominator)); + + if (dataMatrix) { + result[i] = field.multiply(result[i], xiInverse); + } + } + return result; +} +} + +// file: zxing/common/reedsolomon/ReedSolomonException.cpp + +/* + * ReedSolomonException.cpp + * zxing + * + * Created by Christian Brunschen on 06/05/2008. + * Copyright 2008 Google UK. 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 + +namespace zxing { +ReedSolomonException::ReedSolomonException(const char *msg) throw() : + Exception(msg) { +} +ReedSolomonException::~ReedSolomonException() throw() { +} + +} + +// file: zxing/datamatrix/DataMatrixReader.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * DataMatrixReader.cpp + * zxing + * + * Created 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 +// #include +// #include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +DataMatrixReader::DataMatrixReader() : + decoder_() { +} + +Ref DataMatrixReader::decode(Ref image, DecodeHints hints) { + (void)hints; +#ifdef DEBUG + cout << "decoding image " << image.object_ << ":\n" << flush; +#endif + + Detector detector(image->getBlackMatrix()); + + +#ifdef DEBUG + cout << "(1) created detector " << &detector << "\n" << flush; +#endif + + Ref detectorResult(detector.detect()); +#ifdef DEBUG + cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush; +#endif + + std::vector > points(detectorResult->getPoints()); + + +#ifdef DEBUG + cout << "(3) extracted points " << &points << "\n" << flush; + cout << "found " << points.size() << " points:\n"; + for (size_t i = 0; i < points.size(); i++) { + cout << " " << points[i]->getX() << "," << points[i]->getY() << "\n"; + } + cout << "bits:\n"; + cout << *(detectorResult->getBits()) << "\n"; +#endif + + Ref decoderResult(decoder_.decode(detectorResult->getBits())); +#ifdef DEBUG + cout << "(4) decoded, have decoderResult " << decoderResult.object_ << "\n" << flush; +#endif + + Ref result( + new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_DATA_MATRIX)); +#ifdef DEBUG + cout << "(5) created result " << result.object_ << ", returning\n" << flush; +#endif + + return result; +} + +DataMatrixReader::~DataMatrixReader() { +} + +} +} + +// file: zxing/datamatrix/Version.cpp + +/* + * Version.cpp + * zxing + * + * Created 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 +// #include +// #include + +namespace zxing { +namespace datamatrix { +using namespace std; + +ECB::ECB(int count, int dataCodewords) : + count_(count), dataCodewords_(dataCodewords) { +} + +int ECB::getCount() { + return count_; +} + +int ECB::getDataCodewords() { + return dataCodewords_; +} + +ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks) : + ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks) { +} + +ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) : + ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks1) { + ecBlocks_.push_back(ecBlocks2); +} + +int ECBlocks::getECCodewords() { + return ecCodewords_; +} + +std::vector& ECBlocks::getECBlocks() { + return ecBlocks_; +} + +ECBlocks::~ECBlocks() { + for (size_t i = 0; i < ecBlocks_.size(); i++) { + delete ecBlocks_[i]; + } +} + +vector > Version::VERSIONS; +static int N_VERSIONS = Version::buildVersions(); + +Version::Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows, + int dataRegionSizeColumns, ECBlocks* ecBlocks) : versionNumber_(versionNumber), + symbolSizeRows_(symbolSizeRows), symbolSizeColumns_(symbolSizeColumns), + dataRegionSizeRows_(dataRegionSizeRows), dataRegionSizeColumns_(dataRegionSizeColumns), + ecBlocks_(ecBlocks), totalCodewords_(0) { + // Calculate the total number of codewords + int total = 0; + int ecCodewords = ecBlocks_->getECCodewords(); + vector &ecbArray = ecBlocks_->getECBlocks(); + for (unsigned int i = 0; i < ecbArray.size(); i++) { + ECB *ecBlock = ecbArray[i]; + total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords); + } + totalCodewords_ = total; +} + +Version::~Version() { + delete ecBlocks_; +} + +int Version::getVersionNumber() { + return versionNumber_; +} + +int Version::getSymbolSizeRows() { + return symbolSizeRows_; +} + +int Version::getSymbolSizeColumns() { + return symbolSizeColumns_; +} + +int Version::getDataRegionSizeRows() { + return dataRegionSizeRows_; +} + +int Version::getDataRegionSizeColumns() { + return dataRegionSizeColumns_; +} + +int Version::getTotalCodewords() { + return totalCodewords_; +} + +ECBlocks* Version::getECBlocks() { + return ecBlocks_; +} + +Ref Version::getVersionForDimensions(int numRows, int numColumns) { + if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) { + throw ReaderException("Number of rows and columns must be even"); + } + + // TODO(bbrown): This is doing a linear search through the array of versions. + // If we interleave the rectangular versions with the square versions we could + // do a binary search. + for (int i = 0; i < N_VERSIONS; ++i){ + Ref version(VERSIONS[i]); + if (version->getSymbolSizeRows() == numRows && version->getSymbolSizeColumns() == numColumns) { + return version; + } + } + throw ReaderException("Error version not found"); + } + +/** + * See ISO 16022:2006 5.5.1 Table 7 + */ +int Version::buildVersions() { + VERSIONS.push_back(Ref(new Version(1, 10, 10, 8, 8, + new ECBlocks(5, new ECB(1, 3))))); + VERSIONS.push_back(Ref(new Version(2, 12, 12, 10, 10, + new ECBlocks(7, new ECB(1, 5))))); + VERSIONS.push_back(Ref(new Version(3, 14, 14, 12, 12, + new ECBlocks(10, new ECB(1, 8))))); + VERSIONS.push_back(Ref(new Version(4, 16, 16, 14, 14, + new ECBlocks(12, new ECB(1, 12))))); + VERSIONS.push_back(Ref(new Version(5, 18, 18, 16, 16, + new ECBlocks(14, new ECB(1, 18))))); + VERSIONS.push_back(Ref(new Version(6, 20, 20, 18, 18, + new ECBlocks(18, new ECB(1, 22))))); + VERSIONS.push_back(Ref(new Version(7, 22, 22, 20, 20, + new ECBlocks(20, new ECB(1, 30))))); + VERSIONS.push_back(Ref(new Version(8, 24, 24, 22, 22, + new ECBlocks(24, new ECB(1, 36))))); + VERSIONS.push_back(Ref(new Version(9, 26, 26, 24, 24, + new ECBlocks(28, new ECB(1, 44))))); + VERSIONS.push_back(Ref(new Version(10, 32, 32, 14, 14, + new ECBlocks(36, new ECB(1, 62))))); + VERSIONS.push_back(Ref(new Version(11, 36, 36, 16, 16, + new ECBlocks(42, new ECB(1, 86))))); + VERSIONS.push_back(Ref(new Version(12, 40, 40, 18, 18, + new ECBlocks(48, new ECB(1, 114))))); + VERSIONS.push_back(Ref(new Version(13, 44, 44, 20, 20, + new ECBlocks(56, new ECB(1, 144))))); + VERSIONS.push_back(Ref(new Version(14, 48, 48, 22, 22, + new ECBlocks(68, new ECB(1, 174))))); + VERSIONS.push_back(Ref(new Version(15, 52, 52, 24, 24, + new ECBlocks(42, new ECB(2, 102))))); + VERSIONS.push_back(Ref(new Version(16, 64, 64, 14, 14, + new ECBlocks(56, new ECB(2, 140))))); + VERSIONS.push_back(Ref(new Version(17, 72, 72, 16, 16, + new ECBlocks(36, new ECB(4, 92))))); + VERSIONS.push_back(Ref(new Version(18, 80, 80, 18, 18, + new ECBlocks(48, new ECB(4, 114))))); + VERSIONS.push_back(Ref(new Version(19, 88, 88, 20, 20, + new ECBlocks(56, new ECB(4, 144))))); + VERSIONS.push_back(Ref(new Version(20, 96, 96, 22, 22, + new ECBlocks(68, new ECB(4, 174))))); + VERSIONS.push_back(Ref(new Version(21, 104, 104, 24, 24, + new ECBlocks(56, new ECB(6, 136))))); + VERSIONS.push_back(Ref(new Version(22, 120, 120, 18, 18, + new ECBlocks(68, new ECB(6, 175))))); + VERSIONS.push_back(Ref(new Version(23, 132, 132, 20, 20, + new ECBlocks(62, new ECB(8, 163))))); + VERSIONS.push_back(Ref(new Version(24, 144, 144, 22, 22, + new ECBlocks(62, new ECB(8, 156), new ECB(2, 155))))); + VERSIONS.push_back(Ref(new Version(25, 8, 18, 6, 16, + new ECBlocks(7, new ECB(1, 5))))); + VERSIONS.push_back(Ref(new Version(26, 8, 32, 6, 14, + new ECBlocks(11, new ECB(1, 10))))); + VERSIONS.push_back(Ref(new Version(27, 12, 26, 10, 24, + new ECBlocks(14, new ECB(1, 16))))); + VERSIONS.push_back(Ref(new Version(28, 12, 36, 10, 16, + new ECBlocks(18, new ECB(1, 22))))); + VERSIONS.push_back(Ref(new Version(29, 16, 36, 14, 16, + new ECBlocks(24, new ECB(1, 32))))); + VERSIONS.push_back(Ref(new Version(30, 16, 48, 14, 22, + new ECBlocks(28, new ECB(1, 49))))); + return VERSIONS.size(); +} +} +} + +// file: zxing/datamatrix/decoder/BitMatrixParser.cpp + +/* + * BitMatrixParser.cpp + * zxing + * + * Created 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 +// #include + +// #include + +namespace zxing { +namespace datamatrix { + +int BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) { + return bitMatrix_->get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1; +} + +BitMatrixParser::BitMatrixParser(Ref bitMatrix) : bitMatrix_(NULL), + parsedVersion_(NULL), + readBitMatrix_(NULL) { + size_t dimension = bitMatrix->getDimension(); + if (dimension < 8 || dimension > 144 || (dimension & 0x01) != 0) + throw ReaderException("Dimension must be even, > 8 < 144"); + + parsedVersion_ = readVersion(bitMatrix); + bitMatrix_ = extractDataRegion(bitMatrix); + readBitMatrix_ = new BitMatrix(bitMatrix_->getWidth(), bitMatrix_->getHeight()); +} + +Ref BitMatrixParser::readVersion(Ref bitMatrix) { + if (parsedVersion_ != 0) { + return parsedVersion_; + } + + int numRows = bitMatrix->getHeight();//getDimension(); + int numColumns = bitMatrix->getWidth();//numRows; + + Ref version = parsedVersion_->getVersionForDimensions(numRows, numColumns); + if (version != 0) { + return version; + } + throw ReaderException("Couldn't decode version"); +} + +ArrayRef BitMatrixParser::readCodewords() { + ArrayRef result(parsedVersion_->getTotalCodewords()); + int resultOffset = 0; + int row = 4; + int column = 0; + + int numRows = bitMatrix_->getHeight(); + int numColumns = bitMatrix_->getWidth(); + + bool corner1Read = false; + bool corner2Read = false; + bool corner3Read = false; + bool corner4Read = false; + + // Read all of the codewords + do { + // Check the four corner cases + if ((row == numRows) && (column == 0) && !corner1Read) { + result[resultOffset++] = (unsigned char) readCorner1(numRows, numColumns); + row -= 2; + column +=2; + corner1Read = true; + } else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) { + result[resultOffset++] = (unsigned char) readCorner2(numRows, numColumns); + row -= 2; + column +=2; + corner2Read = true; + } else if ((row == numRows+4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) { + result[resultOffset++] = (unsigned char) readCorner3(numRows, numColumns); + row -= 2; + column +=2; + corner3Read = true; + } else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) { + result[resultOffset++] = (unsigned char) readCorner4(numRows, numColumns); + row -= 2; + column +=2; + corner4Read = true; + } else { + // Sweep upward diagonally to the right + do { + if ((row < numRows) && (column >= 0) && !readBitMatrix_->get(column, row)) { + result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns); + } + row -= 2; + column +=2; + } while ((row >= 0) && (column < numColumns)); + row += 1; + column +=3; + + // Sweep downward diagonally to the left + do { + if ((row >= 0) && (column < numColumns) && !readBitMatrix_->get(column, row)) { + result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns); + } + row += 2; + column -=2; + } while ((row < numRows) && (column >= 0)); + row += 3; + column +=1; + } + } while ((row < numRows) || (column < numColumns)); + + if (resultOffset != parsedVersion_->getTotalCodewords()) { + throw ReaderException("Did not read all codewords"); + } + return result; +} + +bool BitMatrixParser::readModule(int row, int column, int numRows, int numColumns) { + // Adjust the row and column indices based on boundary wrapping + if (row < 0) { + row += numRows; + column += 4 - ((numRows + 4) & 0x07); + } + if (column < 0) { + column += numColumns; + row += 4 - ((numColumns + 4) & 0x07); + } + readBitMatrix_->set(column, row); + return bitMatrix_->get(column, row); + } + +int BitMatrixParser::readUtah(int row, int column, int numRows, int numColumns) { + int currentByte = 0; + if (readModule(row - 2, column - 2, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(row - 2, column - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(row - 1, column - 2, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(row - 1, column - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(row - 1, column, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(row, column - 2, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(row, column - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(row, column, numRows, numColumns)) { + currentByte |= 1; + } + return currentByte; + } + +int BitMatrixParser::readCorner1(int numRows, int numColumns) { + int currentByte = 0; + if (readModule(numRows - 1, 0, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(numRows - 1, 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(numRows - 1, 2, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 2, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(1, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(2, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(3, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + return currentByte; + } + +int BitMatrixParser::readCorner2(int numRows, int numColumns) { + int currentByte = 0; + if (readModule(numRows - 3, 0, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(numRows - 2, 0, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(numRows - 1, 0, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 4, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 3, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 2, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(1, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + return currentByte; + } + +int BitMatrixParser::readCorner3(int numRows, int numColumns) { + int currentByte = 0; + if (readModule(numRows - 1, 0, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(numRows - 1, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 3, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 2, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(1, numColumns - 3, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(1, numColumns - 2, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(1, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + return currentByte; + } + +int BitMatrixParser::readCorner4(int numRows, int numColumns) { + int currentByte = 0; + if (readModule(numRows - 3, 0, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(numRows - 2, 0, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(numRows - 1, 0, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 2, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(0, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(1, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(2, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + currentByte <<= 1; + if (readModule(3, numColumns - 1, numRows, numColumns)) { + currentByte |= 1; + } + return currentByte; + } + +Ref BitMatrixParser::extractDataRegion(Ref bitMatrix) { + int symbolSizeRows = parsedVersion_->getSymbolSizeRows(); + int symbolSizeColumns = parsedVersion_->getSymbolSizeColumns(); + + if ((int)bitMatrix->getHeight() != symbolSizeRows) { + throw IllegalArgumentException("Dimension of bitMatrix must match the version size"); + } + + int dataRegionSizeRows = parsedVersion_->getDataRegionSizeRows(); + int dataRegionSizeColumns = parsedVersion_->getDataRegionSizeColumns(); + + int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows; + int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns; + + int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows; + int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns; + + Ref bitMatrixWithoutAlignment(new BitMatrix(sizeDataRegionColumn, sizeDataRegionRow)); + for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) { + int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows; + for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) { + int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns; + for (int i = 0; i < dataRegionSizeRows; ++i) { + int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i; + int writeRowOffset = dataRegionRowOffset + i; + for (int j = 0; j < dataRegionSizeColumns; ++j) { + int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j; + if (bitMatrix->get(readColumnOffset, readRowOffset)) { + int writeColumnOffset = dataRegionColumnOffset + j; + bitMatrixWithoutAlignment->set(writeColumnOffset, writeRowOffset); + } + } + } + } + } + return bitMatrixWithoutAlignment; +} + +} +} + +// file: zxing/datamatrix/decoder/DataBlock.cpp + +/* + * DataBlock.cpp + * zxing + * + * Created 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 +// #include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +DataBlock::DataBlock(int numDataCodewords, ArrayRef codewords) : + numDataCodewords_(numDataCodewords), codewords_(codewords) { +} + +int DataBlock::getNumDataCodewords() { + return numDataCodewords_; +} + +ArrayRef DataBlock::getCodewords() { + return codewords_; +} + +std::vector > DataBlock::getDataBlocks(ArrayRef rawCodewords, Version *version) { + // Figure out the number and size of data blocks used by this version and + // error correction level + ECBlocks* ecBlocks = version->getECBlocks(); + + // First count the total number of data blocks + int totalBlocks = 0; + vector ecBlockArray = ecBlocks->getECBlocks(); + for (size_t i = 0; i < ecBlockArray.size(); i++) { + totalBlocks += ecBlockArray[i]->getCount(); + } + + // Now establish DataBlocks of the appropriate size and number of data codewords + std::vector > result(totalBlocks); + int numResultBlocks = 0; + for (size_t j = 0; j < ecBlockArray.size(); j++) { + ECB *ecBlock = ecBlockArray[j]; + for (int i = 0; i < ecBlock->getCount(); i++) { + int numDataCodewords = ecBlock->getDataCodewords(); + int numBlockCodewords = ecBlocks->getECCodewords() + numDataCodewords; + ArrayRef buffer(numBlockCodewords); + Ref blockRef(new DataBlock(numDataCodewords, buffer)); + result[numResultBlocks++] = blockRef; + } + } + + // All blocks have the same amount of data, except that the last n + // (where n may be 0) have 1 more byte. Figure out where these start. + int shorterBlocksTotalCodewords = result[0]->codewords_.size(); + int longerBlocksStartAt = result.size() - 1; + while (longerBlocksStartAt >= 0) { + int numCodewords = result[longerBlocksStartAt]->codewords_.size(); + if (numCodewords == shorterBlocksTotalCodewords) { + break; + } + if (numCodewords != shorterBlocksTotalCodewords + 1) { + throw IllegalArgumentException("Data block sizes differ by more than 1"); + } + longerBlocksStartAt--; + } + longerBlocksStartAt++; + + int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks->getECCodewords(); + // The last elements of result may be 1 element longer; + // first fill out as many elements as all of them have + int rawCodewordsOffset = 0; + for (int i = 0; i < shorterBlocksNumDataCodewords; i++) { + for (int j = 0; j < numResultBlocks; j++) { + result[j]->codewords_[i] = rawCodewords[rawCodewordsOffset++]; + } + } + // Fill out the last data block in the longer ones + for (int j = longerBlocksStartAt; j < numResultBlocks; j++) { + result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; + } + // Now add in error correction blocks + int max = result[0]->codewords_.size(); + for (int i = shorterBlocksNumDataCodewords; i < max; i++) { + for (int j = 0; j < numResultBlocks; j++) { + int iOffset = j < longerBlocksStartAt ? i : i + 1; + result[j]->codewords_[iOffset] = rawCodewords[rawCodewordsOffset++]; + } + } + + if ((size_t)rawCodewordsOffset != rawCodewords.size()) { + throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length"); + } + + return result; +} + +} +} + +// file: zxing/datamatrix/decoder/DecodedBitStreamParser.cpp + +/* + * DecodedBitStreamParser.cpp + * zxing + * + * Created 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 +// #include +// #include +// #include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +const char DecodedBitStreamParser::C40_BASIC_SET_CHARS[] = { + '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' +}; + +const char DecodedBitStreamParser::C40_SHIFT2_SET_CHARS[] = { + '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', + '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_' +}; + +const char DecodedBitStreamParser::TEXT_BASIC_SET_CHARS[] = { + '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' +}; + +const char DecodedBitStreamParser::TEXT_SHIFT3_SET_CHARS[] = { + '\'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127 +}; + +Ref DecodedBitStreamParser::decode(ArrayRef bytes) { + Ref bits(new BitSource(bytes)); + ostringstream result; + ostringstream resultTrailer; + vector byteSegments; + int mode = ASCII_ENCODE; + do { + if (mode == ASCII_ENCODE) { + mode = decodeAsciiSegment(bits, result, resultTrailer); + } else { + switch (mode) { + case C40_ENCODE: + decodeC40Segment(bits, result); + break; + case TEXT_ENCODE: + decodeTextSegment(bits, result); + break; + case ANSIX12_ENCODE: + decodeAnsiX12Segment(bits, result); + break; + case EDIFACT_ENCODE: + decodeEdifactSegment(bits, result); + break; + case BASE256_ENCODE: + decodeBase256Segment(bits, result, byteSegments); + break; + default: + throw FormatException("Unsupported mode indicator"); + } + mode = ASCII_ENCODE; + } + } while (mode != PAD_ENCODE && bits->available() > 0); + + if (resultTrailer.str().size() > 0) { + result << resultTrailer.str(); + } + ArrayRef rawBytes(bytes); + Ref text(new String(result.str())); + return Ref(new DecoderResult(rawBytes, text)); +} + +int DecodedBitStreamParser::decodeAsciiSegment(Ref bits, ostringstream & result, + ostringstream & resultTrailer) { + bool upperShift = false; + do { + int oneByte = bits->readBits(8); + if (oneByte == 0) { + throw FormatException("Not enough bits to decode"); + } else if (oneByte <= 128) { // ASCII data (ASCII value + 1) + oneByte = upperShift ? (oneByte + 128) : oneByte; + // upperShift = false; + result << (char) (oneByte - 1); + return ASCII_ENCODE; + } else if (oneByte == 129) { // Pad + return PAD_ENCODE; + } else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130) + int value = oneByte - 130; + if (value < 10) { // padd with '0' for single digit values + result << '0'; + } + result << value; + } else if (oneByte == 230) { // Latch to C40 encodation + return C40_ENCODE; + } else if (oneByte == 231) { // Latch to Base 256 encodation + return BASE256_ENCODE; + } else if (oneByte == 232) { // FNC1 + result << ((char) 29); // translate as ASCII 29 + } else if (oneByte == 233 || oneByte == 234) { + // Structured Append, Reader Programming + // Ignore these symbols for now + // throw FormatException.getInstance(); + } else if (oneByte == 235) { // Upper Shift (shift to Extended ASCII) + upperShift = true; + } else if (oneByte == 236) { // 05 Macro + result << ("[)>RS05GS"); + resultTrailer << ("RSEOT"); + } else if (oneByte == 237) { // 06 Macro + result << ("[)>RS06GS"); + resultTrailer << ("RSEOT"); + } else if (oneByte == 238) { // Latch to ANSI X12 encodation + return ANSIX12_ENCODE; + } else if (oneByte == 239) { // Latch to Text encodation + return TEXT_ENCODE; + } else if (oneByte == 240) { // Latch to EDIFACT encodation + return EDIFACT_ENCODE; + } else if (oneByte == 241) { // ECI Character + // TODO(bbrown): I think we need to support ECI + // throw FormatException.getInstance(); + // Ignore this symbol for now + } else if (oneByte >= 242) { // Not to be used in ASCII encodation + // ... but work around encoders that end with 254, latch back to ASCII + if (oneByte == 254 && bits->available() == 0) { + // Ignore + } else { + throw FormatException("Not to be used in ASCII encodation"); + } + } + } while (bits->available() > 0); + return ASCII_ENCODE; +} + +void DecodedBitStreamParser::decodeC40Segment(Ref bits, ostringstream & result) { + // Three C40 values are encoded in a 16-bit value as + // (1600 * C1) + (40 * C2) + C3 + 1 + // TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time + bool upperShift = false; + + int* cValues = new int[3]; + int shift = 0; + do { + // If there is only one byte left then it will be encoded as ASCII + if (bits->available() == 8) { + return; + } + int firstByte = bits->readBits(8); + if (firstByte == 254) { // Unlatch codeword + return; + } + + parseTwoBytes(firstByte, bits->readBits(8), cValues); + + for (int i = 0; i < 3; i++) { + int cValue = cValues[i]; + switch (shift) { + case 0: + if (cValue < 3) { + shift = cValue + 1; + } else { + if (upperShift) { + result << (char) (C40_BASIC_SET_CHARS[cValue] + 128); + upperShift = false; + } else { + result << C40_BASIC_SET_CHARS[cValue]; + } + } + break; + case 1: + if (upperShift) { + result << (char) (cValue + 128); + upperShift = false; + } else { + result << (char) cValue; + } + shift = 0; + break; + case 2: + if (cValue < 27) { + if (upperShift) { + result << (char) (C40_SHIFT2_SET_CHARS[cValue] + 128); + upperShift = false; + } else { + result << C40_SHIFT2_SET_CHARS[cValue]; + } + } else if (cValue == 27) { // FNC1 + result << ((char) 29); // translate as ASCII 29 + } else if (cValue == 30) { // Upper Shift + upperShift = true; + } else { + throw FormatException("decodeC40Segment: Upper Shift"); + } + shift = 0; + break; + case 3: + if (upperShift) { + result << (char) (cValue + 224); + upperShift = false; + } else { + result << (char) (cValue + 96); + } + shift = 0; + break; + default: + throw FormatException("decodeC40Segment: no case"); + } + } + } while (bits->available() > 0); +} + +void DecodedBitStreamParser::decodeTextSegment(Ref bits, ostringstream & result) { + // Three Text values are encoded in a 16-bit value as + // (1600 * C1) + (40 * C2) + C3 + 1 + // TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time + bool upperShift = false; + + int* cValues = new int[3]; + int shift = 0; + do { + // If there is only one byte left then it will be encoded as ASCII + if (bits->available() == 8) { + return; + } + int firstByte = bits->readBits(8); + if (firstByte == 254) { // Unlatch codeword + return; + } + + parseTwoBytes(firstByte, bits->readBits(8), cValues); + + for (int i = 0; i < 3; i++) { + int cValue = cValues[i]; + switch (shift) { + case 0: + if (cValue < 3) { + shift = cValue + 1; + } else { + if (upperShift) { + result << (char) (TEXT_BASIC_SET_CHARS[cValue] + 128); + upperShift = false; + } else { + result << (TEXT_BASIC_SET_CHARS[cValue]); + } + } + break; + case 1: + if (upperShift) { + result << (char) (cValue + 128); + upperShift = false; + } else { + result << (char) (cValue); + } + shift = 0; + break; + case 2: + // Shift 2 for Text is the same encoding as C40 + if (cValue < 27) { + if (upperShift) { + result << (char) (C40_SHIFT2_SET_CHARS[cValue] + 128); + upperShift = false; + } else { + result << (C40_SHIFT2_SET_CHARS[cValue]); + } + } else if (cValue == 27) { // FNC1 + result << ((char) 29); // translate as ASCII 29 + } else if (cValue == 30) { // Upper Shift + upperShift = true; + } else { + throw FormatException("decodeTextSegment: Upper Shift"); + } + shift = 0; + break; + case 3: + if (upperShift) { + result << (char) (TEXT_SHIFT3_SET_CHARS[cValue] + 128); + upperShift = false; + } else { + result << (TEXT_SHIFT3_SET_CHARS[cValue]); + } + shift = 0; + break; + default: + throw FormatException("decodeTextSegment: no case"); + } + } + } while (bits->available() > 0); +} + +void DecodedBitStreamParser::decodeAnsiX12Segment(Ref bits, ostringstream & result) { + // Three ANSI X12 values are encoded in a 16-bit value as + // (1600 * C1) + (40 * C2) + C3 + 1 + + int* cValues = new int[3]; + do { + // If there is only one byte left then it will be encoded as ASCII + if (bits->available() == 8) { + return; + } + int firstByte = bits->readBits(8); + if (firstByte == 254) { // Unlatch codeword + return; + } + + parseTwoBytes(firstByte, bits->readBits(8), cValues); + + for (int i = 0; i < 3; i++) { + int cValue = cValues[i]; + if (cValue == 0) { // X12 segment terminator + result << '\r'; + } else if (cValue == 1) { // X12 segment separator * + result << '*'; + } else if (cValue == 2) { // X12 sub-element separator > + result << '>'; + } else if (cValue == 3) { // space + result << ' '; + } else if (cValue < 14) { // 0 - 9 + result << (char) (cValue + 44); + } else if (cValue < 40) { // A - Z + result << (char) (cValue + 51); + } else { + throw FormatException("decodeAnsiX12Segment: no case"); + } + } + } while (bits->available() > 0); +} + +void DecodedBitStreamParser::parseTwoBytes(int firstByte, int secondByte, int*& result) { + int fullBitValue = (firstByte << 8) + secondByte - 1; + int temp = fullBitValue / 1600; + result[0] = temp; + fullBitValue -= temp * 1600; + temp = fullBitValue / 40; + result[1] = temp; + result[2] = fullBitValue - temp * 40; +} + +void DecodedBitStreamParser::decodeEdifactSegment(Ref bits, ostringstream & result) { + bool unlatch = false; + do { + // If there is only two or less bytes left then it will be encoded as ASCII + if (bits->available() <= 16) { + return; + } + + for (int i = 0; i < 4; i++) { + int edifactValue = bits->readBits(6); + + // Check for the unlatch character + if (edifactValue == 0x2B67) { // 011111 + unlatch = true; + // If we encounter the unlatch code then continue reading because the Codeword triple + // is padded with 0's + } + + if (!unlatch) { + if ((edifactValue & 0x20) == 0) { // no 1 in the leading (6th) bit + edifactValue |= 0x40; // Add a leading 01 to the 6 bit binary value + } + result << (char)(edifactValue); + } + } + } while (!unlatch && bits->available() > 0); +} + +void DecodedBitStreamParser::decodeBase256Segment(Ref bits, ostringstream& result, vector byteSegments) { + // Figure out how long the Base 256 Segment is. + int codewordPosition = 1 + bits->getByteOffset(); // position is 1-indexed + int d1 = unrandomize255State(bits->readBits(8), codewordPosition++); + int count; + if (d1 == 0) { // Read the remainder of the symbol + count = bits->available() / 8; + } else if (d1 < 250) { + count = d1; + } else { + count = 250 * (d1 - 249) + unrandomize255State(bits->readBits(8), codewordPosition++); + } + + // We're seeing NegativeArraySizeException errors from users. + if (count < 0) { + throw FormatException("NegativeArraySizeException"); + } + + unsigned char* bytes = new unsigned char[count]; + for (int i = 0; i < count; i++) { + // Have seen this particular error in the wild, such as at + // http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2 + if (bits->available() < 8) { + throw FormatException("byteSegments"); + } + bytes[i] = unrandomize255State(bits->readBits(8), codewordPosition++); + byteSegments.push_back(bytes[i]); + result << (char)bytes[i]; + } +} +} +} + + +// file: zxing/datamatrix/decoder/Decoder.cpp + +/* + * Decoder.cpp + * zxing + * + * Created 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 +// #include +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +Decoder::Decoder() : + rsDecoder_(GF256::DATA_MATRIX_FIELD) { +} + + +void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCodewords) { + int numCodewords = codewordBytes->size(); + ArrayRef codewordInts(numCodewords); + for (int i = 0; i < numCodewords; i++) { + codewordInts[i] = codewordBytes[i] & 0xff; + } + int numECCodewords = numCodewords - numDataCodewords; + try { + rsDecoder_.decode(codewordInts, numECCodewords); + } catch (ReedSolomonException const& ex) { + ReaderException rex(ex.what()); + throw rex; + } + // Copy back into array of bytes -- only need to worry about the bytes that were data + // We don't care about errors in the error-correction codewords + for (int i = 0; i < numDataCodewords; i++) { + codewordBytes[i] = (unsigned char)codewordInts[i]; + } +} + +Ref Decoder::decode(Ref bits) { + // Construct a parser and read version, error-correction level + BitMatrixParser parser(bits); + Version *version = parser.readVersion(bits); + + // Read codewords + ArrayRef codewords(parser.readCodewords()); + // Separate into data blocks + std::vector > dataBlocks = DataBlock::getDataBlocks(codewords, version); + + int dataBlocksCount = dataBlocks.size(); + + // Count total number of data bytes + int totalBytes = 0; + for (int i = 0; i < dataBlocksCount; i++) { + totalBytes += dataBlocks[i]->getNumDataCodewords(); + } + ArrayRef resultBytes(totalBytes); + + // Error-correct and copy data blocks together into a stream of bytes + for (int j = 0; j < dataBlocksCount; j++) { + Ref dataBlock(dataBlocks[j]); + ArrayRef codewordBytes = dataBlock->getCodewords(); + int numDataCodewords = dataBlock->getNumDataCodewords(); + correctErrors(codewordBytes, numDataCodewords); + for (int i = 0; i < numDataCodewords; i++) { + // De-interlace data blocks. + resultBytes[i * dataBlocksCount + j] = codewordBytes[i]; + } + } + // Decode the contents of that stream of bytes + DecodedBitStreamParser decodedBSParser; + return Ref (decodedBSParser.decode(resultBytes)); +} +} +} + +// file: zxing/datamatrix/detector/CornerPoint.cpp + +/* + * CornerPoint.cpp + * zxing + * + * Created 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 + + +namespace zxing { + namespace datamatrix { + + using namespace std; + + CornerPoint::CornerPoint(float posX, float posY) : + ResultPoint(posX,posY), counter_(0) { + } + + int CornerPoint::getCount() const { + return counter_; + } + + void CornerPoint::incrementCount() { + counter_++; + } + + bool CornerPoint::equals(Ref other) const { + return posX_ == other->getX() && posY_ == other->getY(); + } + + } +} + +// file: zxing/datamatrix/detector/Detector.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Detector.cpp + * zxing + * + * Created 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 +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +ResultPointsAndTransitions::ResultPointsAndTransitions() { + Ref ref(new ResultPoint(0, 0)); + from_ = ref; + to_ = ref; + transitions_ = 0; +} + +ResultPointsAndTransitions::ResultPointsAndTransitions(Ref from, Ref to, + int transitions) + : to_(to), from_(from), transitions_(transitions) { +} + +Ref ResultPointsAndTransitions::getFrom() { + return from_; +} + +Ref ResultPointsAndTransitions::getTo() { + return to_; +} + +int ResultPointsAndTransitions::getTransitions() { + return transitions_; +} + +Detector::Detector(Ref image) + : image_(image) { +} + +Ref Detector::getImage() { + return image_; +} + +Ref Detector::detect() { + Ref rectangleDetector_(new WhiteRectangleDetector(image_)); + std::vector > ResultPoints = rectangleDetector_->detect(); + Ref pointA = ResultPoints[0]; + Ref pointB = ResultPoints[1]; + Ref pointC = ResultPoints[2]; + Ref pointD = ResultPoints[3]; + + // Point A and D are across the diagonal from one another, + // as are B and C. Figure out which are the solid black lines + // by counting transitions + std::vector > transitions(4); + transitions[0].reset(transitionsBetween(pointA, pointB)); + transitions[1].reset(transitionsBetween(pointA, pointC)); + transitions[2].reset(transitionsBetween(pointB, pointD)); + transitions[3].reset(transitionsBetween(pointC, pointD)); + insertionSort(transitions); + + // Sort by number of transitions. First two will be the two solid sides; last two + // will be the two alternating black/white sides + Ref lSideOne(transitions[0]); + Ref lSideTwo(transitions[1]); + + // Figure out which point is their intersection by tallying up the number of times we see the + // endpoints in the four endpoints. One will show up twice. + Ref maybeTopLeft; + Ref bottomLeft; + Ref maybeBottomRight; + if (lSideOne->getFrom()->equals(lSideOne->getTo())) { + bottomLeft = lSideOne->getFrom(); + maybeTopLeft = lSideTwo->getFrom(); + maybeBottomRight = lSideTwo->getTo(); + } else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) { + bottomLeft = lSideOne->getFrom(); + maybeTopLeft = lSideOne->getTo(); + maybeBottomRight = lSideTwo->getTo(); + } else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) { + bottomLeft = lSideOne->getFrom(); + maybeTopLeft = lSideOne->getTo(); + maybeBottomRight = lSideTwo->getFrom(); + } else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) { + bottomLeft = lSideOne->getTo(); + maybeTopLeft = lSideOne->getFrom(); + maybeBottomRight = lSideTwo->getTo(); + } else if (lSideOne->getTo()->equals(lSideTwo->getTo())) { + bottomLeft = lSideOne->getTo(); + maybeTopLeft = lSideOne->getFrom(); + maybeBottomRight = lSideTwo->getFrom(); + } else { + bottomLeft = lSideTwo->getFrom(); + maybeTopLeft = lSideOne->getTo(); + maybeBottomRight = lSideOne->getFrom(); + } + + // Bottom left is correct but top left and bottom right might be switched + std::vector > corners(3); + corners[0].reset(maybeTopLeft); + corners[1].reset(bottomLeft); + corners[2].reset(maybeBottomRight); + + // Use the dot product trick to sort them out + ResultPoint::orderBestPatterns(corners); + + // Now we know which is which: + Ref bottomRight(corners[0]); + bottomLeft = corners[1]; + Ref topLeft(corners[2]); + + // Which point didn't we find in relation to the "L" sides? that's the top right corner + Ref topRight; + if (!(pointA->equals(bottomRight) || pointA->equals(bottomLeft) || pointA->equals(topLeft))) { + topRight = pointA; + } else if (!(pointB->equals(bottomRight) || pointB->equals(bottomLeft) + || pointB->equals(topLeft))) { + topRight = pointB; + } else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft) + || pointC->equals(topLeft))) { + topRight = pointC; + } else { + topRight = pointD; + } + + // Next determine the dimension by tracing along the top or right side and counting black/white + // transitions. Since we start inside a black module, we should see a number of transitions + // equal to 1 less than the code dimension. Well, actually 2 less, because we are going to + // end on a black module: + + // The top right point is actually the corner of a module, which is one of the two black modules + // adjacent to the white module at the top right. Tracing to that corner from either the top left + // or bottom right should work here. + + int dimensionTop = transitionsBetween(topLeft, topRight)->getTransitions(); + int dimensionRight = transitionsBetween(bottomRight, topRight)->getTransitions(); + + //dimensionTop++; + if ((dimensionTop & 0x01) == 1) { + // it can't be odd, so, round... up? + dimensionTop++; + } + dimensionTop += 2; + + //dimensionRight++; + if ((dimensionRight & 0x01) == 1) { + // it can't be odd, so, round... up? + dimensionRight++; + } + dimensionRight += 2; + + Ref bits; + Ref transform; + Ref correctedTopRight; + + + // Rectanguar symbols are 6x16, 6x28, 10x24, 10x32, 14x32, or 14x44. If one dimension is more + // than twice the other, it's certainly rectangular, but to cut a bit more slack we accept it as + // rectangular if the bigger side is at least 7/4 times the other: + if (4 * dimensionTop >= 7 * dimensionRight || 4 * dimensionRight >= 7 * dimensionTop) { + // The matrix is rectangular + correctedTopRight = correctTopRightRectangular(bottomLeft, bottomRight, topLeft, topRight, + dimensionTop, dimensionRight); + if (correctedTopRight == NULL) { + correctedTopRight = topRight; + } + + dimensionTop = transitionsBetween(topLeft, correctedTopRight)->getTransitions(); + dimensionRight = transitionsBetween(bottomRight, correctedTopRight)->getTransitions(); + + if ((dimensionTop & 0x01) == 1) { + // it can't be odd, so, round... up? + dimensionTop++; + } + + if ((dimensionRight & 0x01) == 1) { + // it can't be odd, so, round... up? + dimensionRight++; + } + + transform = createTransform(topLeft, correctedTopRight, bottomLeft, bottomRight, dimensionTop, + dimensionRight); + bits = sampleGrid(image_, dimensionTop, dimensionRight, transform); + + } else { + // The matrix is square + int dimension = min(dimensionRight, dimensionTop); + + // correct top right point to match the white module + correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension); + if (correctedTopRight == NULL) { + correctedTopRight = topRight; + } + + // Redetermine the dimension using the corrected top right point + int dimensionCorrected = max(transitionsBetween(topLeft, correctedTopRight)->getTransitions(), + transitionsBetween(bottomRight, correctedTopRight)->getTransitions()); + dimensionCorrected++; + if ((dimensionCorrected & 0x01) == 1) { + dimensionCorrected++; + } + + transform = createTransform(topLeft, correctedTopRight, bottomLeft, bottomRight, + dimensionCorrected, dimensionCorrected); + bits = sampleGrid(image_, dimensionCorrected, dimensionCorrected, transform); + } + + std::vector > points(4); + points[0].reset(topLeft); + points[1].reset(bottomLeft); + points[2].reset(correctedTopRight); + points[3].reset(bottomRight); + Ref detectorResult(new DetectorResult(bits, points, transform)); + return detectorResult; +} + +/** + * Calculates the position of the white top right module using the output of the rectangle detector + * for a rectangular matrix + */ +Ref Detector::correctTopRightRectangular(Ref bottomLeft, + Ref bottomRight, Ref topLeft, Ref topRight, + int dimensionTop, int dimensionRight) { + + float corr = distance(bottomLeft, bottomRight) / (float) dimensionTop; + int norm = distance(topLeft, topRight); + float cos = (topRight->getX() - topLeft->getX()) / norm; + float sin = (topRight->getY() - topLeft->getY()) / norm; + + Ref c1( + new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); + + corr = distance(bottomLeft, topLeft) / (float) dimensionRight; + norm = distance(bottomRight, topRight); + cos = (topRight->getX() - bottomRight->getX()) / norm; + sin = (topRight->getY() - bottomRight->getY()) / norm; + + Ref c2( + new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); + + if (!isValid(c1)) { + if (isValid(c2)) { + return c2; + } + return Ref(NULL); + } + if (!isValid(c2)) { + return c1; + } + + int l1 = abs(dimensionTop - transitionsBetween(topLeft, c1)->getTransitions()) + + abs(dimensionRight - transitionsBetween(bottomRight, c1)->getTransitions()); + int l2 = abs(dimensionTop - transitionsBetween(topLeft, c2)->getTransitions()) + + abs(dimensionRight - transitionsBetween(bottomRight, c2)->getTransitions()); + + return l1 <= l2 ? c1 : c2; +} + +/** + * Calculates the position of the white top right module using the output of the rectangle detector + * for a square matrix + */ +Ref Detector::correctTopRight(Ref bottomLeft, + Ref bottomRight, Ref topLeft, Ref topRight, + int dimension) { + + float corr = distance(bottomLeft, bottomRight) / (float) dimension; + int norm = distance(topLeft, topRight); + float cos = (topRight->getX() - topLeft->getX()) / norm; + float sin = (topRight->getY() - topLeft->getY()) / norm; + + Ref c1( + new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); + + corr = distance(bottomLeft, bottomRight) / (float) dimension; + norm = distance(bottomRight, topRight); + cos = (topRight->getX() - bottomRight->getX()) / norm; + sin = (topRight->getY() - bottomRight->getY()) / norm; + + Ref c2( + new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); + + if (!isValid(c1)) { + if (isValid(c2)) { + return c2; + } + return Ref(NULL); + } + if (!isValid(c2)) { + return c1; + } + + int l1 = abs( + transitionsBetween(topLeft, c1)->getTransitions() + - transitionsBetween(bottomRight, c1)->getTransitions()); + int l2 = abs( + transitionsBetween(topLeft, c2)->getTransitions() + - transitionsBetween(bottomRight, c2)->getTransitions()); + + return l1 <= l2 ? c1 : c2; +} + +bool Detector::isValid(Ref p) { + return p->getX() >= 0 && p->getX() < image_->getWidth() && p->getY() > 0 + && p->getY() < image_->getHeight(); +} + +// L2 distance +int Detector::distance(Ref a, Ref b) { + return round( + (float) sqrt( + (double) (a->getX() - b->getX()) * (a->getX() - b->getX()) + + (a->getY() - b->getY()) * (a->getY() - b->getY()))); +} + +Ref Detector::transitionsBetween(Ref from, + Ref to) { + // See QR Code Detector, sizeOfBlackWhiteBlackRun() + int fromX = (int) from->getX(); + int fromY = (int) from->getY(); + int toX = (int) to->getX(); + int toY = (int) to->getY(); + bool steep = abs(toY - fromY) > abs(toX - fromX); + if (steep) { + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + int dx = abs(toX - fromX); + int dy = abs(toY - fromY); + int error = -dx >> 1; + int ystep = fromY < toY ? 1 : -1; + int xstep = fromX < toX ? 1 : -1; + int transitions = 0; + bool inBlack = image_->get(steep ? fromY : fromX, steep ? fromX : fromY); + for (int x = fromX, y = fromY; x != toX; x += xstep) { + bool isBlack = image_->get(steep ? y : x, steep ? x : y); + if (isBlack != inBlack) { + transitions++; + inBlack = isBlack; + } + error += dy; + if (error > 0) { + if (y == toY) { + break; + } + y += ystep; + error -= dx; + } + } + Ref result(new ResultPointsAndTransitions(from, to, transitions)); + return result; +} + +Ref Detector::createTransform(Ref topLeft, + Ref topRight, Ref bottomLeft, Ref bottomRight, + int dimensionX, int dimensionY) { + + Ref transform( + PerspectiveTransform::quadrilateralToQuadrilateral( + 0.5f, + 0.5f, + dimensionX - 0.5f, + 0.5f, + dimensionX - 0.5f, + dimensionY - 0.5f, + 0.5f, + dimensionY - 0.5f, + topLeft->getX(), + topLeft->getY(), + topRight->getX(), + topRight->getY(), + bottomRight->getX(), + bottomRight->getY(), + bottomLeft->getX(), + bottomLeft->getY())); + return transform; +} + +Ref Detector::sampleGrid(Ref image, int dimensionX, int dimensionY, + Ref transform) { + GridSampler &sampler = GridSampler::getInstance(); + return sampler.sampleGrid(image, dimensionX, dimensionY, transform); +} + +void Detector::insertionSort(std::vector > &vector) { + int max = vector.size(); + bool swapped = true; + Ref value; + Ref valueB; + do { + swapped = false; + for (int i = 1; i < max; i++) { + value = vector[i - 1]; + if (compare(value, (valueB = vector[i])) > 0){ + swapped = true; + vector[i - 1].reset(valueB); + vector[i].reset(value); + } + } + } while (swapped); +} + +int Detector::compare(Ref a, Ref b) { + return a->getTransitions() - b->getTransitions(); +} +} +} + +// file: zxing/datamatrix/detector/DetectorException.cpp + +/* + * DetectorException.cpp + * + * Created on: Aug 26, 2011 + * Author: luiz + */ + +// #include "DetectorException.h" + +namespace zxing { +namespace datamatrix { + +DetectorException::DetectorException(const char *msg) : + Exception(msg) { + +} + +DetectorException::~DetectorException() throw () { + // TODO Auto-generated destructor stub +} + +} +} /* namespace zxing */ + +// file: zxing/datamatrix/detector/MonochromeRectangleDetector.cpp + +/* + * MonochromeRectangleDetector.cpp + * zxing + * + * Created 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 +// #include +// #include + +namespace zxing { +namespace datamatrix { + +std::vector > MonochromeRectangleDetector::detect() { + int height = image_->getHeight(); + int width = image_->getWidth(); + int halfHeight = height >> 1; + int halfWidth = width >> 1; + int deltaY = max(1, height / (MAX_MODULES << 3)); + int deltaX = max(1, width / (MAX_MODULES << 3)); + + int top = 0; + int bottom = height; + int left = 0; + int right = width; + Ref pointA(findCornerFromCenter(halfWidth, 0, left, right, + halfHeight, -deltaY, top, bottom, halfWidth >> 1)); + top = (int) pointA->getY() - 1; + Ref pointB(findCornerFromCenter(halfWidth, -deltaX, left, right, + halfHeight, 0, top, bottom, halfHeight >> 1)); + left = (int) pointB->getX() - 1; + Ref pointC(findCornerFromCenter(halfWidth, deltaX, left, right, + halfHeight, 0, top, bottom, halfHeight >> 1)); + right = (int) pointC->getX() + 1; + Ref pointD(findCornerFromCenter(halfWidth, 0, left, right, + halfHeight, deltaY, top, bottom, halfWidth >> 1)); + bottom = (int) pointD->getY() + 1; + + // Go try to find point A again with better information -- might have been off at first. + pointA.reset(findCornerFromCenter(halfWidth, 0, left, right, + halfHeight, -deltaY, top, bottom, halfWidth >> 2)); + std::vector > corners(4); + + corners[0].reset(pointA); + corners[1].reset(pointB); + corners[2].reset(pointC); + corners[3].reset(pointD); + return corners; + } + +Ref MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right, + int centerY, int deltaY, int top, int bottom, int maxWhiteRun) { + Ref lastRange(NULL); + for (int y = centerY, x = centerX; + y < bottom && y >= top && x < right && x >= left; + y += deltaY, x += deltaX) { + Ref range(NULL); + if (deltaX == 0) { + // horizontal slices, up and down + range = blackWhiteRange(y, maxWhiteRun, left, right, true); + } else { + // vertical slices, left and right + range = blackWhiteRange(x, maxWhiteRun, top, bottom, false); + } + if (range == NULL) { + if (lastRange == NULL) { + throw ReaderException("Couldn't find corners (lastRange = NULL) "); + } else { + // lastRange was found + if (deltaX == 0) { + int lastY = y - deltaY; + if (lastRange->start < centerX) { + if (lastRange->end > centerX) { + // straddle, choose one or the other based on direction + Ref result(new CornerPoint(deltaY > 0 ? lastRange->start : lastRange->end, lastY)); + return result; + } + Ref result(new CornerPoint(lastRange->start, lastY)); + return result; + } else { + Ref result(new CornerPoint(lastRange->end, lastY)); + return result; + } + } else { + int lastX = x - deltaX; + if (lastRange->start < centerY) { + if (lastRange->end > centerY) { + Ref result(new CornerPoint(lastX, deltaX < 0 ? lastRange->start : lastRange->end)); + return result; + } + Ref result(new CornerPoint(lastX, lastRange->start)); + return result; + } else { + Ref result(new CornerPoint(lastX, lastRange->end)); + return result; + } + } + } + } + lastRange = range; + } + throw ReaderException("Couldn't find corners"); + } + +Ref MonochromeRectangleDetector::blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, + bool horizontal) { + + int center = (minDim + maxDim) >> 1; + + // Scan left/up first + int start = center; + while (start >= minDim) { + if (horizontal ? image_->get(start, fixedDimension) : image_->get(fixedDimension, start)) { + start--; + } else { + int whiteRunStart = start; + do { + start--; + } while (start >= minDim && !(horizontal ? image_->get(start, fixedDimension) : + image_->get(fixedDimension, start))); + int whiteRunSize = whiteRunStart - start; + if (start < minDim || whiteRunSize > maxWhiteRun) { + start = whiteRunStart; + break; + } + } + } + start++; + + // Then try right/down + int end = center; + while (end < maxDim) { + if (horizontal ? image_->get(end, fixedDimension) : image_->get(fixedDimension, end)) { + end++; + } else { + int whiteRunStart = end; + do { + end++; + } while (end < maxDim && !(horizontal ? image_->get(end, fixedDimension) : + image_->get(fixedDimension, end))); + int whiteRunSize = end - whiteRunStart; + if (end >= maxDim || whiteRunSize > maxWhiteRun) { + end = whiteRunStart; + break; + } + } + } + end--; + Ref result(NULL); + if (end > start) { + result = new TwoInts; + result->start = start; + result->end = end; + } + return result; + } +} +} + +// file: zxing/multi/ByQuadrantReader.cpp + +/* + * Copyright 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 +// #include + +namespace zxing { +namespace multi { + +ByQuadrantReader::ByQuadrantReader(Reader& delegate) : delegate_(delegate) {} + +ByQuadrantReader::~ByQuadrantReader(){} + +Ref ByQuadrantReader::decode(Ref image){ + return decode(image, DecodeHints::DEFAULT_HINT); +} + +Ref ByQuadrantReader::decode(Ref image, DecodeHints hints){ + int width = image->getWidth(); + int height = image->getHeight(); + int halfWidth = width / 2; + int halfHeight = height / 2; + Ref topLeft = image->crop(0, 0, halfWidth, halfHeight); + try { + return delegate_.decode(topLeft, hints); + } catch (ReaderException re) { + // continue + } + + Ref topRight = image->crop(halfWidth, 0, halfWidth, halfHeight); + try { + return delegate_.decode(topRight, hints); + } catch (ReaderException re) { + // continue + } + + Ref bottomLeft = image->crop(0, halfHeight, halfWidth, halfHeight); + try { + return delegate_.decode(bottomLeft, hints); + } catch (ReaderException re) { + // continue + } + + Ref bottomRight = image->crop(halfWidth, halfHeight, halfWidth, halfHeight); + try { + return delegate_.decode(bottomRight, hints); + } catch (ReaderException re) { + // continue + } + + int quarterWidth = halfWidth / 2; + int quarterHeight = halfHeight / 2; + Ref center = image->crop(quarterWidth, quarterHeight, halfWidth, halfHeight); + return delegate_.decode(center, hints); +} + +} // End zxing::multi namespace +} // End zxing namespace + +// file: zxing/multi/GenericMultipleBarcodeReader.cpp + +/* + * Copyright 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 +// #include +// #include + +namespace zxing { +namespace multi { +GenericMultipleBarcodeReader::GenericMultipleBarcodeReader(Reader& delegate) : + delegate_(delegate) +{ +} + +GenericMultipleBarcodeReader::~GenericMultipleBarcodeReader(){} + +std::vector > GenericMultipleBarcodeReader::decodeMultiple( + Ref image, DecodeHints hints) +{ + std::vector > results; + doDecodeMultiple(image, hints, results, 0, 0); + if (results.empty()){ + throw ReaderException("No code detected"); + } + return results; +} + +void GenericMultipleBarcodeReader::doDecodeMultiple(Ref image, + DecodeHints hints, std::vector >& results, int xOffset, int yOffset) +{ + Ref result; + try { + result = delegate_.decode(image, hints); + } catch (ReaderException re) { + return; + } + bool alreadyFound = false; + for (unsigned int i = 0; i < results.size(); i++) { + Ref existingResult = results[i]; + if (existingResult->getText()->getText() == result->getText()->getText()) { + alreadyFound = true; + break; + } + } + if (alreadyFound) { + return; + } + + results.push_back(translateResultPoints(result, xOffset, yOffset)); + const std::vector > resultPoints = result->getResultPoints(); + if (resultPoints.empty()) { + return; + } + + int width = image->getWidth(); + int height = image->getHeight(); + float minX = width; + float minY = height; + float maxX = 0.0f; + float maxY = 0.0f; + for (unsigned int i = 0; i < resultPoints.size(); i++) { + Ref point = resultPoints[i]; + float x = point->getX(); + float y = point->getY(); + if (x < minX) { + minX = x; + } + if (y < minY) { + minY = y; + } + if (x > maxX) { + maxX = x; + } + if (y > maxY) { + maxY = y; + } + } + + // Decode left of barcode + if (minX > MIN_DIMENSION_TO_RECUR) { + doDecodeMultiple(image->crop(0, 0, (int) minX, height), + hints, results, xOffset, yOffset); + } + // Decode above barcode + if (minY > MIN_DIMENSION_TO_RECUR) { + doDecodeMultiple(image->crop(0, 0, width, (int) minY), + hints, results, xOffset, yOffset); + } + // Decode right of barcode + if (maxX < width - MIN_DIMENSION_TO_RECUR) { + doDecodeMultiple(image->crop((int) maxX, 0, width - (int) maxX, height), + hints, results, xOffset + (int) maxX, yOffset); + } + // Decode below barcode + if (maxY < height - MIN_DIMENSION_TO_RECUR) { + doDecodeMultiple(image->crop(0, (int) maxY, width, height - (int) maxY), + hints, results, xOffset, yOffset + (int) maxY); + } +} + +Ref GenericMultipleBarcodeReader::translateResultPoints(Ref result, int xOffset, int yOffset){ + const std::vector > oldResultPoints = result->getResultPoints(); + if (oldResultPoints.empty()) { + return result; + } + std::vector > newResultPoints; + for (unsigned int i = 0; i < oldResultPoints.size(); i++) { + Ref oldPoint = oldResultPoints[i]; + newResultPoints.push_back(Ref(new ResultPoint(oldPoint->getX() + xOffset, oldPoint->getY() + yOffset))); + } + return Ref(new Result(result->getText(), result->getRawBytes(), newResultPoints, result->getBarcodeFormat())); +} + +} // End zxing::multi namespace +} // End zxing namespace + +// file: zxing/multi/MultipleBarcodeReader.cpp + +/* + * Copyright 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 + +namespace zxing { +namespace multi { + +MultipleBarcodeReader::~MultipleBarcodeReader() { } + +std::vector > MultipleBarcodeReader::decodeMultiple(Ref image) { + return decodeMultiple(image, DecodeHints::DEFAULT_HINT); +} + +} // End zxing::multi namespace +} // End zxing namespace + +// file: zxing/multi/qrcode/QRCodeMultiReader.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Copyright 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 +// #include +// #include +// #include + +namespace zxing { +namespace multi { +QRCodeMultiReader::QRCodeMultiReader(){} + +QRCodeMultiReader::~QRCodeMultiReader(){} + +std::vector > QRCodeMultiReader::decodeMultiple(Ref image, + DecodeHints hints) +{ + std::vector > results; + MultiDetector detector(image->getBlackMatrix()); + + std::vector > detectorResult = detector.detectMulti(hints); + for (unsigned int i = 0; i < detectorResult.size(); i++) { + try { + Ref decoderResult = getDecoder().decode(detectorResult[i]->getBits()); + std::vector > points = detectorResult[i]->getPoints(); + Ref result = Ref(new Result(decoderResult->getText(), + decoderResult->getRawBytes(), + points, BarcodeFormat_QR_CODE)); + // result->putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult->getByteSegments()); + // result->putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult->getECLevel().toString()); + results.push_back(result); + } catch (ReaderException re) { + // ignore and continue + } + } + if (results.empty()){ + throw ReaderException("No code detected"); + } + return results; +} + +} // End zxing::multi namespace +} // End zxing namespace + +// file: zxing/multi/qrcode/detector/MultiDetector.cpp + +/* + * Copyright 2011 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 +// #include +// #include + +namespace zxing { +namespace multi { +using namespace zxing::qrcode; + +MultiDetector::MultiDetector(Ref image) : Detector(image) {} + +MultiDetector::~MultiDetector(){} + +std::vector > MultiDetector::detectMulti(DecodeHints hints){ + Ref image = getImage(); + MultiFinderPatternFinder finder = MultiFinderPatternFinder(image, hints.getResultPointCallback()); + std::vector > info = finder.findMulti(hints); + std::vector > result; + for(unsigned int i = 0; i < info.size(); i++){ + try{ + result.push_back(processFinderPatternInfo(info[i])); + } catch (ReaderException e){ + // ignore + } + } + + return result; +} + +} // End zxing::multi namespace +} // End zxing namespace + +// file: zxing/multi/qrcode/detector/MultiFinderPatternFinder.cpp + +/* + * Copyright 2011 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 +// #include +// #include +// #include +// #include +// #include + +namespace zxing{ +namespace multi { +using namespace zxing::qrcode; + +const float MultiFinderPatternFinder::MAX_MODULE_COUNT_PER_EDGE = 180; +const float MultiFinderPatternFinder::MIN_MODULE_COUNT_PER_EDGE = 9; +const float MultiFinderPatternFinder::DIFF_MODSIZE_CUTOFF_PERCENT = 0.05f; +const float MultiFinderPatternFinder::DIFF_MODSIZE_CUTOFF = 0.5f; + +bool compareModuleSize(Ref a, Ref b){ + float value = a->getEstimatedModuleSize() - b->getEstimatedModuleSize(); + return value < 0.0; +} + + +MultiFinderPatternFinder::MultiFinderPatternFinder(Ref image, + Ref resultPointCallback) : + FinderPatternFinder(image, resultPointCallback) +{ +} + +MultiFinderPatternFinder::~MultiFinderPatternFinder(){} + +std::vector > MultiFinderPatternFinder::findMulti(DecodeHints const& hints){ + bool tryHarder = hints.getTryHarder(); + Ref image = image_; // Protected member + int maxI = image->getHeight(); + int maxJ = image->getWidth(); + // We are looking for black/white/black/white/black modules in + // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far + + // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the + // image, and then account for the center being 3 modules in size. This gives the smallest + // number of pixels the center could be, so skip this often. When trying harder, look for all + // QR versions regardless of how dense they are. + int iSkip = (int) (maxI / (MAX_MODULES * 4.0f) * 3); + if (iSkip < MIN_SKIP || tryHarder) { + iSkip = MIN_SKIP; + } + + int stateCount[5]; + for (int i = iSkip - 1; i < maxI; i += iSkip) { + // Get a row of black/white values + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + int currentState = 0; + for (int j = 0; j < maxJ; j++) { + if (image->get(j, i)) { + // Black pixel + if ((currentState & 1) == 1) { // Counting white pixels + currentState++; + } + stateCount[currentState]++; + } else { // White pixel + if ((currentState & 1) == 0) { // Counting black pixels + if (currentState == 4) { // A winner? + if (foundPatternCross(stateCount)) { // Yes + bool confirmed = handlePossibleCenter(stateCount, i, j); + if (!confirmed) { + do { // Advance to next black pixel + j++; + } while (j < maxJ && !image->get(j, i)); + j--; // back up to that last white pixel + } + // Clear state to start looking again + currentState = 0; + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + } else { // No, shift counts back by two + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + } + } else { + stateCount[++currentState]++; + } + } else { // Counting white pixels + stateCount[currentState]++; + } + } + } // for j=... + + if (foundPatternCross(stateCount)) { + handlePossibleCenter(stateCount, i, maxJ); + } // end if foundPatternCross + } // for i=iSkip-1 ... + std::vector > > patternInfo = selectBestPatterns(); + std::vector > result; + for (unsigned int i = 0; i < patternInfo.size(); i++) { + std::vector > pattern = patternInfo[i]; + FinderPatternFinder::orderBestPatterns(pattern); + result.push_back(Ref(new FinderPatternInfo(pattern))); + } + return result; +} + +std::vector > > MultiFinderPatternFinder::selectBestPatterns(){ + std::vector > possibleCenters = possibleCenters_; + + int size = possibleCenters.size(); + + if (size < 3) { + // Couldn't find enough finder patterns + throw ReaderException("No code detected"); + } + + std::vector > > results; + + /* + * Begin HE modifications to safely detect multiple codes of equal size + */ + if (size == 3) { + results.push_back(possibleCenters_); + return results; + } + + // Sort by estimated module size to speed up the upcoming checks + //TODO do a sort based on module size + std::sort(possibleCenters.begin(), possibleCenters.end(), compareModuleSize); + + /* + * Now lets start: build a list of tuples of three finder locations that + * - feature similar module sizes + * - are placed in a distance so the estimated module count is within the QR specification + * - have similar distance between upper left/right and left top/bottom finder patterns + * - form a triangle with 90° angle (checked by comparing top right/bottom left distance + * with pythagoras) + * + * Note: we allow each point to be used for more than one code region: this might seem + * counterintuitive at first, but the performance penalty is not that big. At this point, + * we cannot make a good quality decision whether the three finders actually represent + * a QR code, or are just by chance layouted so it looks like there might be a QR code there. + * So, if the layout seems right, lets have the decoder try to decode. + */ + + for (int i1 = 0; i1 < (size - 2); i1++) { + Ref p1 = possibleCenters[i1]; + for (int i2 = i1 + 1; i2 < (size - 1); i2++) { + Ref p2 = possibleCenters[i2]; + // Compare the expected module sizes; if they are really off, skip + float vModSize12 = (p1->getEstimatedModuleSize() - p2->getEstimatedModuleSize()) / std::min(p1->getEstimatedModuleSize(), p2->getEstimatedModuleSize()); + float vModSize12A = abs(p1->getEstimatedModuleSize() - p2->getEstimatedModuleSize()); + if (vModSize12A > DIFF_MODSIZE_CUTOFF && vModSize12 >= DIFF_MODSIZE_CUTOFF_PERCENT) { + // break, since elements are ordered by the module size deviation there cannot be + // any more interesting elements for the given p1. + break; + } + for (int i3 = i2 + 1; i3 < size; i3++) { + Ref p3 = possibleCenters[i3]; + // Compare the expected module sizes; if they are really off, skip + float vModSize23 = (p2->getEstimatedModuleSize() - p3->getEstimatedModuleSize()) / std::min(p2->getEstimatedModuleSize(), p3->getEstimatedModuleSize()); + float vModSize23A = abs(p2->getEstimatedModuleSize() - p3->getEstimatedModuleSize()); + if (vModSize23A > DIFF_MODSIZE_CUTOFF && vModSize23 >= DIFF_MODSIZE_CUTOFF_PERCENT) { + // break, since elements are ordered by the module size deviation there cannot be + // any more interesting elements for the given p1. + break; + } + std::vector > test; + test.push_back(p1); + test.push_back(p2); + test.push_back(p3); + FinderPatternFinder::orderBestPatterns(test); + // Calculate the distances: a = topleft-bottomleft, b=topleft-topright, c = diagonal + Ref info = Ref(new FinderPatternInfo(test)); + float dA = FinderPatternFinder::distance(info->getTopLeft(), info->getBottomLeft()); + float dC = FinderPatternFinder::distance(info->getTopRight(), info->getBottomLeft()); + float dB = FinderPatternFinder::distance(info->getTopLeft(), info->getTopRight()); + // Check the sizes + float estimatedModuleCount = (dA + dB) / (p1->getEstimatedModuleSize() * 2.0f); + if (estimatedModuleCount > MAX_MODULE_COUNT_PER_EDGE || estimatedModuleCount < MIN_MODULE_COUNT_PER_EDGE) { + continue; + } + // Calculate the difference of the edge lengths in percent + float vABBC = abs((dA - dB) / std::min(dA, dB)); + if (vABBC >= 0.1f) { + continue; + } + // Calculate the diagonal length by assuming a 90° angle at topleft + float dCpy = (float) sqrt(dA * dA + dB * dB); + // Compare to the real distance in % + float vPyC = abs((dC - dCpy) / std::min(dC, dCpy)); + if (vPyC >= 0.1f) { + continue; + } + // All tests passed! + results.push_back(test); + } // end iterate p3 + } // end iterate p2 + } // end iterate p1 + if (results.empty()){ + // Nothing found! + throw ReaderException("No code detected"); + } + return results; +} + +} // End zxing::multi namespace +} // End zxing namespace + +// file: zxing/oned/Code128Reader.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 "Code128Reader.h" +// #include +// #include +// #include +// #include +// #include +// #include + +namespace zxing { + namespace oned { + + const int CODE_PATTERNS_LENGTH = 107; + const int countersLength = 6; + static const int CODE_PATTERNS[CODE_PATTERNS_LENGTH][countersLength] = { + {2, 1, 2, 2, 2, 2}, /* 0 */ + {2, 2, 2, 1, 2, 2}, + {2, 2, 2, 2, 2, 1}, + {1, 2, 1, 2, 2, 3}, + {1, 2, 1, 3, 2, 2}, + {1, 3, 1, 2, 2, 2}, /* 5 */ + {1, 2, 2, 2, 1, 3}, + {1, 2, 2, 3, 1, 2}, + {1, 3, 2, 2, 1, 2}, + {2, 2, 1, 2, 1, 3}, + {2, 2, 1, 3, 1, 2}, /* 10 */ + {2, 3, 1, 2, 1, 2}, + {1, 1, 2, 2, 3, 2}, + {1, 2, 2, 1, 3, 2}, + {1, 2, 2, 2, 3, 1}, + {1, 1, 3, 2, 2, 2}, /* 15 */ + {1, 2, 3, 1, 2, 2}, + {1, 2, 3, 2, 2, 1}, + {2, 2, 3, 2, 1, 1}, + {2, 2, 1, 1, 3, 2}, + {2, 2, 1, 2, 3, 1}, /* 20 */ + {2, 1, 3, 2, 1, 2}, + {2, 2, 3, 1, 1, 2}, + {3, 1, 2, 1, 3, 1}, + {3, 1, 1, 2, 2, 2}, + {3, 2, 1, 1, 2, 2}, /* 25 */ + {3, 2, 1, 2, 2, 1}, + {3, 1, 2, 2, 1, 2}, + {3, 2, 2, 1, 1, 2}, + {3, 2, 2, 2, 1, 1}, + {2, 1, 2, 1, 2, 3}, /* 30 */ + {2, 1, 2, 3, 2, 1}, + {2, 3, 2, 1, 2, 1}, + {1, 1, 1, 3, 2, 3}, + {1, 3, 1, 1, 2, 3}, + {1, 3, 1, 3, 2, 1}, /* 35 */ + {1, 1, 2, 3, 1, 3}, + {1, 3, 2, 1, 1, 3}, + {1, 3, 2, 3, 1, 1}, + {2, 1, 1, 3, 1, 3}, + {2, 3, 1, 1, 1, 3}, /* 40 */ + {2, 3, 1, 3, 1, 1}, + {1, 1, 2, 1, 3, 3}, + {1, 1, 2, 3, 3, 1}, + {1, 3, 2, 1, 3, 1}, + {1, 1, 3, 1, 2, 3}, /* 45 */ + {1, 1, 3, 3, 2, 1}, + {1, 3, 3, 1, 2, 1}, + {3, 1, 3, 1, 2, 1}, + {2, 1, 1, 3, 3, 1}, + {2, 3, 1, 1, 3, 1}, /* 50 */ + {2, 1, 3, 1, 1, 3}, + {2, 1, 3, 3, 1, 1}, + {2, 1, 3, 1, 3, 1}, + {3, 1, 1, 1, 2, 3}, + {3, 1, 1, 3, 2, 1}, /* 55 */ + {3, 3, 1, 1, 2, 1}, + {3, 1, 2, 1, 1, 3}, + {3, 1, 2, 3, 1, 1}, + {3, 3, 2, 1, 1, 1}, + {3, 1, 4, 1, 1, 1}, /* 60 */ + {2, 2, 1, 4, 1, 1}, + {4, 3, 1, 1, 1, 1}, + {1, 1, 1, 2, 2, 4}, + {1, 1, 1, 4, 2, 2}, + {1, 2, 1, 1, 2, 4}, /* 65 */ + {1, 2, 1, 4, 2, 1}, + {1, 4, 1, 1, 2, 2}, + {1, 4, 1, 2, 2, 1}, + {1, 1, 2, 2, 1, 4}, + {1, 1, 2, 4, 1, 2}, /* 70 */ + {1, 2, 2, 1, 1, 4}, + {1, 2, 2, 4, 1, 1}, + {1, 4, 2, 1, 1, 2}, + {1, 4, 2, 2, 1, 1}, + {2, 4, 1, 2, 1, 1}, /* 75 */ + {2, 2, 1, 1, 1, 4}, + {4, 1, 3, 1, 1, 1}, + {2, 4, 1, 1, 1, 2}, + {1, 3, 4, 1, 1, 1}, + {1, 1, 1, 2, 4, 2}, /* 80 */ + {1, 2, 1, 1, 4, 2}, + {1, 2, 1, 2, 4, 1}, + {1, 1, 4, 2, 1, 2}, + {1, 2, 4, 1, 1, 2}, + {1, 2, 4, 2, 1, 1}, /* 85 */ + {4, 1, 1, 2, 1, 2}, + {4, 2, 1, 1, 1, 2}, + {4, 2, 1, 2, 1, 1}, + {2, 1, 2, 1, 4, 1}, + {2, 1, 4, 1, 2, 1}, /* 90 */ + {4, 1, 2, 1, 2, 1}, + {1, 1, 1, 1, 4, 3}, + {1, 1, 1, 3, 4, 1}, + {1, 3, 1, 1, 4, 1}, + {1, 1, 4, 1, 1, 3}, /* 95 */ + {1, 1, 4, 3, 1, 1}, + {4, 1, 1, 1, 1, 3}, + {4, 1, 1, 3, 1, 1}, + {1, 1, 3, 1, 4, 1}, + {1, 1, 4, 1, 3, 1}, /* 100 */ + {3, 1, 1, 1, 4, 1}, + {4, 1, 1, 1, 3, 1}, + {2, 1, 1, 4, 1, 2}, + {2, 1, 1, 2, 1, 4}, + {2, 1, 1, 2, 3, 2}, /* 105 */ + {2, 3, 3, 1, 1, 1} + }; + + + Code128Reader::Code128Reader(){ + } + + int* Code128Reader::findStartPattern(Ref row){ + int width = row->getSize(); + int rowOffset = 0; + while (rowOffset < width) { + if (row->get(rowOffset)) { + break; + } + rowOffset++; + } + + int counterPosition = 0; + int counters[countersLength] = {0,0,0,0,0,0}; + int patternStart = rowOffset; + bool isWhite = false; + int patternLength = sizeof(counters) / sizeof(int); + + for (int i = rowOffset; i < width; i++) { + bool pixel = row->get(i); + if (pixel ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + unsigned int bestVariance = MAX_AVG_VARIANCE; + int bestMatch = -1; + for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) { + unsigned int variance = patternMatchVariance(counters, sizeof(counters) / sizeof(int), + CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = startCode; + } + } + if (bestMatch >= 0) { + // Look for whitespace before start pattern, >= 50% of width of start pattern + if (row->isRange(std::max(0, patternStart - (i - patternStart) / 2), patternStart, + false)) { + int* resultValue = new int[3]; + resultValue[0] = patternStart; + resultValue[1] = i; + resultValue[2] = bestMatch; + return resultValue; + } + } + patternStart += counters[0] + counters[1]; + for (int y = 2; y < patternLength; y++) { + counters[y - 2] = counters[y]; + } + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + throw ReaderException(""); + } + + int Code128Reader::decodeCode(Ref row, int counters[], int countersCount, + int rowOffset) { + if (!recordPattern(row, rowOffset, counters, countersCount)) { + throw ReaderException(""); + } + unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + for (int d = 0; d < CODE_PATTERNS_LENGTH; d++) { + int pattern[countersLength]; + + for(int ind = 0; ind< countersLength; ind++){ + pattern[ind] = CODE_PATTERNS[d][ind]; + } +// memcpy(pattern, CODE_PATTERNS[d], countersLength); + unsigned int variance = patternMatchVariance(counters, countersCount, pattern, + MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = d; + } + } + // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6. + if (bestMatch >= 0) { + return bestMatch; + } else { + throw ReaderException(""); + } + } + + Ref Code128Reader::decodeRow(int rowNumber, Ref row) { + int* startPatternInfo = NULL; + try { + startPatternInfo = findStartPattern(row); + int startCode = startPatternInfo[2]; + int codeSet; + switch (startCode) { + case CODE_START_A: + codeSet = CODE_CODE_A; + break; + case CODE_START_B: + codeSet = CODE_CODE_B; + break; + case CODE_START_C: + codeSet = CODE_CODE_C; + break; + default: + throw ReaderException(""); + } + + bool done = false; + bool isNextShifted = false; + + std::string tmpResultString; + std::stringstream tmpResultSStr; // used if its Code 128C + + int lastStart = startPatternInfo[0]; + int nextStart = startPatternInfo[1]; + int counters[countersLength] = {0,0,0,0,0,0}; + + int lastCode = 0; + int code = 0; + int checksumTotal = startCode; + int multiplier = 0; + bool lastCharacterWasPrintable = true; + + while (!done) { + bool unshift = isNextShifted; + isNextShifted = false; + + // Save off last code + lastCode = code; + + // Decode another code from image + try { + code = decodeCode(row, counters, sizeof(counters)/sizeof(int), nextStart); + } catch (ReaderException const& re) { + throw re; + } + + // Remember whether the last code was printable or not (excluding CODE_STOP) + if (code != CODE_STOP) { + lastCharacterWasPrintable = true; + } + + // Add to checksum computation (if not CODE_STOP of course) + if (code != CODE_STOP) { + multiplier++; + checksumTotal += multiplier * code; + } + + // Advance to where the next code will to start + lastStart = nextStart; + int _countersLength = sizeof(counters) / sizeof(int); + for (int i = 0; i < _countersLength; i++) { + nextStart += counters[i]; + } + + // Take care of illegal start codes + switch (code) { + case CODE_START_A: + case CODE_START_B: + case CODE_START_C: + throw ReaderException(""); + } + + switch (codeSet) { + + case CODE_CODE_A: + if (code < 64) { + tmpResultString.append(1, (char) (' ' + code)); + } else if (code < 96) { + tmpResultString.append(1, (char) (code - 64)); + } else { + // Don't let CODE_STOP, which always appears, affect whether whether we think the + // last code was printable or not. + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + case CODE_FNC_2: + case CODE_FNC_3: + case CODE_FNC_4_A: + // do nothing? + break; + case CODE_SHIFT: + isNextShifted = true; + codeSet = CODE_CODE_B; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_B; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_C; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + case CODE_CODE_B: + if (code < 96) { + tmpResultString.append(1, (char) (' ' + code)); + } else { + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + case CODE_FNC_2: + case CODE_FNC_3: + case CODE_FNC_4_B: + // do nothing? + break; + case CODE_SHIFT: + isNextShifted = true; + codeSet = CODE_CODE_C; + break; + case CODE_CODE_A: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_C; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + case CODE_CODE_C: + tmpResultSStr.str(std::string()); + // the code read in this case is the number encoded directly + if (code < 100) { + if (code < 10) { + tmpResultSStr << '0'; + } + tmpResultSStr << code; + tmpResultString.append(tmpResultSStr.str()); + } else { + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + // do nothing? + break; + case CODE_CODE_A: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_B; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + } + + // Unshift back to another code set if we were shifted + if (unshift) { + switch (codeSet) { + case CODE_CODE_A: + codeSet = CODE_CODE_C; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_B; + break; + } + } + + } + + // Check for ample whitespace following pattern, but, to do this we first need to remember that + // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left + // to read off. Would be slightly better to properly read. Here we just skip it: + int width = row->getSize(); + while (nextStart < width && row->get(nextStart)) { + nextStart++; + } + if (!row->isRange(nextStart, + std::min(width, nextStart + (nextStart - lastStart) / 2), + false)) { + throw ReaderException(""); + } + + // Pull out from sum the value of the penultimate check code + checksumTotal -= multiplier * lastCode; + // lastCode is the checksum then: + if (checksumTotal % 103 != lastCode) { + throw ReaderException(""); + } + + // Need to pull out the check digits from string + int resultLength = tmpResultString.length(); + // Only bother if the result had at least one character, and if the checksum digit happened to + // be a printable character. If it was just interpreted as a control code, nothing to remove. + if (resultLength > 0 && lastCharacterWasPrintable) { + if (codeSet == CODE_CODE_C) { + tmpResultString.erase(resultLength - 2, resultLength); + } else { + tmpResultString.erase(resultLength - 1, resultLength); + } + } + + Ref resultString(new String(tmpResultString)); + if (tmpResultString.length() == 0) { + // Almost surely a false positive + throw ReaderException(""); + } + + float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f; + float right = (float) (nextStart + lastStart) / 2.0f; + + std::vector< Ref > resultPoints(2); + Ref resultPoint1(new OneDResultPoint(left, (float) rowNumber)); + Ref resultPoint2(new OneDResultPoint(right, (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + delete [] startPatternInfo; + ArrayRef resultBytes(1); + return Ref(new Result(resultString, resultBytes, resultPoints, + BarcodeFormat_CODE_128)); + } catch (ReaderException const& re) { + delete [] startPatternInfo; + return Ref(); + } + } + + void Code128Reader::append(char* s, char c){ + int len = strlen(s); + s[len] = c; + s[len + 1] = '\0'; + } + + Code128Reader::~Code128Reader(){ + } + } +} + +// file: zxing/oned/Code39Reader.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 "Code39Reader.h" +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace oned { + + static const char* ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"; + + + /** + * These represent the encodings of characters, as patterns of wide and narrow + * bars. + * The 9 least-significant bits of each int correspond to the pattern of wide + * and narrow, with 1s representing "wide" and 0s representing narrow. + */ + const int CHARACTER_ENCODINGS_LEN = 44; + static int CHARACTER_ENCODINGS[CHARACTER_ENCODINGS_LEN] = { + 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9 + 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J + 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T + 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, // U-* + 0x0A8, 0x0A2, 0x08A, 0x02A // $-% + }; + + static int ASTERISK_ENCODING = 0x094; + static const char* ALPHABET_STRING = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"; + + + /** + * Creates a reader that assumes all encoded data is data, and does not treat + * the final character as a check digit. It will not decoded "extended + * Code 39" sequences. + */ + Code39Reader::Code39Reader() : alphabet_string(ALPHABET_STRING), + usingCheckDigit(false), + extendedMode(false) { + } + + /** + * Creates a reader that can be configured to check the last character as a + * check digit. It will not decoded "extended Code 39" sequences. + * + * @param usingCheckDigit if true, treat the last data character as a check + * digit, not data, and verify that the checksum passes. + */ + Code39Reader::Code39Reader(bool usingCheckDigit_) : + alphabet_string(ALPHABET_STRING), + usingCheckDigit(usingCheckDigit_), + extendedMode(false) { + } + + + Code39Reader::Code39Reader(bool usingCheckDigit_, bool extendedMode_) : + alphabet_string(ALPHABET_STRING), + usingCheckDigit(usingCheckDigit_), + extendedMode(extendedMode_) { + } + + Ref Code39Reader::decodeRow(int rowNumber, Ref row) { + int* start = NULL; + try { + start = findAsteriskPattern(row); + int nextStart = start[1]; + int end = row->getSize(); + + // Read off white space + while (nextStart < end && !row->get(nextStart)) { + nextStart++; + } + + std::string tmpResultString; + + const int countersLen = 9; + int counters[countersLen]; + for (int i = 0; i < countersLen; i++) { + counters[i] = 0; + } + char decodedChar; + int lastStart; + do { + if (!recordPattern(row, nextStart, counters, countersLen)) { + throw ReaderException(""); + } + int pattern = toNarrowWidePattern(counters, countersLen); + if (pattern < 0) { + throw ReaderException("pattern < 0"); + } + decodedChar = patternToChar(pattern); + tmpResultString.append(1, decodedChar); + lastStart = nextStart; + for (int i = 0; i < countersLen; i++) { + nextStart += counters[i]; + } + // Read off white space + while (nextStart < end && !row->get(nextStart)) { + nextStart++; + } + } while (decodedChar != '*'); + tmpResultString.erase(tmpResultString.length()-1, 1);// remove asterisk + + // Look for whitespace after pattern: + int lastPatternSize = 0; + for (int i = 0; i < countersLen; i++) { + lastPatternSize += counters[i]; + } + int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize; + // If 50% of last pattern size, following last pattern, is not whitespace, + // fail (but if it's whitespace to the very end of the image, that's OK) + if (nextStart != end && whiteSpaceAfterEnd / 2 < lastPatternSize) { + throw ReaderException("too short end white space"); + } + + if (usingCheckDigit) { + int max = tmpResultString.length() - 1; + unsigned int total = 0; + for (int i = 0; i < max; i++) { + total += alphabet_string.find_first_of(tmpResultString[i], 0); + } + if (total % 43 != alphabet_string.find_first_of(tmpResultString[max], 0)) { + throw ReaderException(""); + } + tmpResultString.erase(max, 1); + } + + Ref resultString(new String(tmpResultString)); + if (extendedMode) { + resultString = decodeExtended(tmpResultString); + } + + if (tmpResultString.length() == 0) { + // Almost surely a false positive + throw ReaderException(""); + } + + float left = (float) (start[1] + start[0]) / 2.0f; + float right = (float) (nextStart + lastStart) / 2.0f; + + std::vector< Ref > resultPoints(2); + Ref resultPoint1( + new OneDResultPoint(left, (float) rowNumber)); + Ref resultPoint2( + new OneDResultPoint(right, (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + ArrayRef resultBytes(1); + + Ref res(new Result( + resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39)); + + delete [] start; + return res; + } catch (ReaderException const& re) { + delete [] start; + return Ref(); + } + } + + int* Code39Reader::findAsteriskPattern(Ref row){ + int width = row->getSize(); + int rowOffset = 0; + while (rowOffset < width) { + if (row->get(rowOffset)) { + break; + } + rowOffset++; + } + + int counterPosition = 0; + const int countersLen = 9; + int counters[countersLen]; + for (int i = 0; i < countersLen; i++) { + counters[i] = 0; + } + int patternStart = rowOffset; + bool isWhite = false; + int patternLength = countersLen; + + for (int i = rowOffset; i < width; i++) { + bool pixel = row->get(i); + if (pixel ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if (toNarrowWidePattern(counters, countersLen) == ASTERISK_ENCODING) { + // Look for whitespace before start pattern, >= 50% of width of + // start pattern. + if (row->isRange(std::max(0, patternStart - ((i - patternStart) >> 1)), patternStart, false)) { + int* resultValue = new int[2]; + resultValue[0] = patternStart; + resultValue[1] = i; + return resultValue; + } + } + patternStart += counters[0] + counters[1]; + for (int y = 2; y < patternLength; y++) { + counters[y - 2] = counters[y]; + } + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + throw ReaderException(""); + } + + // For efficiency, returns -1 on failure. Not throwing here saved as many as + // 700 exceptions per image when using some of our blackbox images. + int Code39Reader::toNarrowWidePattern(int counters[], int countersLen){ + int numCounters = countersLen; + int maxNarrowCounter = 0; + int wideCounters; + do { + int minCounter = INT_MAX; + for (int i = 0; i < numCounters; i++) { + int counter = counters[i]; + if (counter < minCounter && counter > maxNarrowCounter) { + minCounter = counter; + } + } + maxNarrowCounter = minCounter; + wideCounters = 0; + int totalWideCountersWidth = 0; + int pattern = 0; + for (int i = 0; i < numCounters; i++) { + int counter = counters[i]; + if (counters[i] > maxNarrowCounter) { + pattern |= 1 << (numCounters - 1 - i); + wideCounters++; + totalWideCountersWidth += counter; + } + } + if (wideCounters == 3) { + // Found 3 wide counters, but are they close enough in width? + // We can perform a cheap, conservative check to see if any individual + // counter is more than 1.5 times the average: + for (int i = 0; i < numCounters && wideCounters > 0; i++) { + int counter = counters[i]; + if (counters[i] > maxNarrowCounter) { + wideCounters--; + // totalWideCountersWidth = 3 * average, so this checks if + // counter >= 3/2 * average. + if ((counter << 1) >= totalWideCountersWidth) { + return -1; + } + } + } + return pattern; + } + } while (wideCounters > 3); + return -1; + } + + char Code39Reader::patternToChar(int pattern){ + for (int i = 0; i < CHARACTER_ENCODINGS_LEN; i++) { + if (CHARACTER_ENCODINGS[i] == pattern) { + return ALPHABET[i]; + } + } + throw ReaderException(""); + } + + Ref Code39Reader::decodeExtended(std::string encoded){ + int length = encoded.length(); + std::string tmpDecoded; + for (int i = 0; i < length; i++) { + char c = encoded[i]; + if (c == '+' || c == '$' || c == '%' || c == '/') { + char next = encoded[i + 1]; + char decodedChar = '\0'; + switch (c) { + case '+': + // +A to +Z map to a to z + if (next >= 'A' && next <= 'Z') { + decodedChar = (char) (next + 32); + } else { + throw ReaderException(""); + } + break; + case '$': + // $A to $Z map to control codes SH to SB + if (next >= 'A' && next <= 'Z') { + decodedChar = (char) (next - 64); + } else { + throw ReaderException(""); + } + break; + case '%': + // %A to %E map to control codes ESC to US + if (next >= 'A' && next <= 'E') { + decodedChar = (char) (next - 38); + } else if (next >= 'F' && next <= 'W') { + decodedChar = (char) (next - 11); + } else { + throw ReaderException(""); + } + break; + case '/': + // /A to /O map to ! to , and /Z maps to : + if (next >= 'A' && next <= 'O') { + decodedChar = (char) (next - 32); + } else if (next == 'Z') { + decodedChar = ':'; + } else { + throw ReaderException(""); + } + break; + } + tmpDecoded.append(1, decodedChar); + // bump up i again since we read two characters + i++; + } else { + tmpDecoded.append(1, c); + } + } + Ref decoded(new String(tmpDecoded)); + return decoded; + } +} // namespace oned +} // namespace zxing + + +// file: zxing/oned/EAN13Reader.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 "EAN13Reader.h" +// #include + +namespace zxing { + namespace oned { + + static const int FIRST_DIGIT_ENCODINGS[10] = { + 0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A + }; + + EAN13Reader::EAN13Reader() { } + + int EAN13Reader::decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, + std::string& resultString) { + (void)startGuardBegin; + const int countersLen = 4; + int counters[countersLen] = { 0, 0, 0, 0 }; + + int end = row->getSize(); + int rowOffset = startGuardEnd; + int lgPatternFound = 0; + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, + UPC_EAN_PATTERNS_L_AND_G_PATTERNS); + if (bestMatch < 0) { + return -1; + } + resultString.append(1, (char) ('0' + bestMatch % 10)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + if (bestMatch >= 10) { + lgPatternFound |= 1 << (5 - x); + } + } + + if (!determineFirstDigit(resultString, lgPatternFound)) { + return -1; + } + + int middleRangeStart; + int middleRangeEnd; + if (findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), + getMIDDLE_PATTERN_LEN(), &middleRangeStart, &middleRangeEnd)) { + rowOffset = middleRangeEnd; + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, + UPC_EAN_PATTERNS_L_PATTERNS); + if (bestMatch < 0) { + return -1; + } + resultString.append(1, (char) ('0' + bestMatch)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + } + return rowOffset; + } + return -1; + } + + bool EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound) { + for (int d = 0; d < 10; d++) { + if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) { + resultString.insert(0, 1, (char) ('0' + d)); + return true; + } + } + return false; + } + + BarcodeFormat EAN13Reader::getBarcodeFormat(){ + return BarcodeFormat_EAN_13; + } + } +} + +// file: zxing/oned/EAN8Reader.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 "EAN8Reader.h" +// #include + +namespace zxing { + namespace oned { + + EAN8Reader::EAN8Reader(){ } + + int EAN8Reader::decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, + std::string& resultString){ + (void)startGuardBegin; + const int countersLen = 4; + int counters[countersLen] = { 0, 0, 0, 0 }; + + int end = row->getSize(); + int rowOffset = startGuardEnd; + + for (int x = 0; x < 4 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, + UPC_EAN_PATTERNS_L_PATTERNS); + if (bestMatch < 0) { + return -1; + } + resultString.append(1, (char) ('0' + bestMatch)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + } + + int middleRangeStart; + int middleRangeEnd; + if (findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), + getMIDDLE_PATTERN_LEN(), &middleRangeStart, &middleRangeEnd)) { + rowOffset = middleRangeEnd; + for (int x = 0; x < 4 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, + UPC_EAN_PATTERNS_L_PATTERNS); + if (bestMatch < 0) { + return -1; + } + resultString.append(1, (char) ('0' + bestMatch)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + } + return rowOffset; + } + return -1; + } + + BarcodeFormat EAN8Reader::getBarcodeFormat(){ + return BarcodeFormat_EAN_8; + } + } +} + +// file: zxing/oned/ITFReader.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 "ITFReader.h" +// #include +// #include +// #include +// #include + +namespace zxing { + namespace oned { + + static const int W = 3; // Pixel width of a wide line + static const int N = 1; // Pixed width of a narrow line + + const int DEFAULT_ALLOWED_LENGTHS_LEN = 10; + const int DEFAULT_ALLOWED_LENGTHS[DEFAULT_ALLOWED_LENGTHS_LEN] = { 44, 24, 20, 18, 16, 14, 12, 10, 8, 6 }; + + /** + * Start/end guard pattern. + * + * Note: The end pattern is reversed because the row is reversed before + * searching for the END_PATTERN + */ + static const int START_PATTERN_LEN = 4; + static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N}; + + static const int END_PATTERN_REVERSED_LEN = 3; + static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W}; + + /** + * Patterns of Wide / Narrow lines to indicate each digit + */ + static const int PATTERNS_LEN = 10; + static const int PATTERNS[PATTERNS_LEN][5] = { + {N, N, W, W, N}, // 0 + {W, N, N, N, W}, // 1 + {N, W, N, N, W}, // 2 + {W, W, N, N, N}, // 3 + {N, N, W, N, W}, // 4 + {W, N, W, N, N}, // 5 + {N, W, W, N, N}, // 6 + {N, N, N, W, W}, // 7 + {W, N, N, W, N}, // 8 + {N, W, N, W, N} // 9 + }; + + + ITFReader::ITFReader() : narrowLineWidth(-1) { + } + + + Ref ITFReader::decodeRow(int rowNumber, Ref row) { + int* startRange = 0; + int* endRange = 0; + try { + // Find out where the Middle section (payload) starts & ends + startRange = decodeStart(row); + endRange = decodeEnd(row); + + std::string tmpResult; + decodeMiddle(row, startRange[1], endRange[0], tmpResult); + + // To avoid false positives with 2D barcodes (and other patterns), make + // an assumption that the decoded string must be a known length + int length = tmpResult.length(); + bool lengthOK = false; + for (int i = 0; i < DEFAULT_ALLOWED_LENGTHS_LEN; i++) { + if (length == DEFAULT_ALLOWED_LENGTHS[i]) { + lengthOK = true; + break; + } + } + if (!lengthOK) { + throw ReaderException("not enough characters count"); + } + + Ref resultString(new String(tmpResult)); + + std::vector< Ref > resultPoints(2); + Ref resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber)); + Ref resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + delete [] startRange; + delete [] endRange; + ArrayRef resultBytes(1); + return Ref(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF)); + } catch (ReaderException const& re) { + delete [] startRange; + delete [] endRange; + return Ref(); + } + } + + /** + * @param row row of black/white values to search + * @param payloadStart offset of start pattern + * @param resultString {@link StringBuffer} to append decoded chars to + * @throws ReaderException if decoding could not complete successfully + */ + void ITFReader::decodeMiddle(Ref row, int payloadStart, int payloadEnd, + std::string& resultString) { + // Digits are interleaved in pairs - 5 black lines for one digit, and the + // 5 + // interleaved white lines for the second digit. + // Therefore, need to scan 10 lines and then + // split these into two arrays + int counterDigitPairLen = 10; + int counterDigitPair[counterDigitPairLen]; + for (int i=0; i row) { + int endStart = skipWhiteSpace(row); + int* startPattern = 0; + try { + startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN); + + // Determine the width of a narrow line in pixels. We can do this by + // getting the width of the start pattern and dividing by 4 because its + // made up of 4 narrow lines. + narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; + validateQuietZone(row, startPattern[0]); + return startPattern; + } catch (ReaderException const& re) { + delete [] startPattern; + throw re; + } + } + + /** + * Identify where the end of the middle / payload section ends. + * + * @param row row of black/white values to search + * @return Array, containing index of start of 'end block' and end of 'end + * block' + * @throws ReaderException + */ + + int* ITFReader::decodeEnd(Ref row) { + // For convenience, reverse the row and then + // search from 'the start' for the end block + row->reverse(); + int* endPattern = 0; + try { + int endStart = skipWhiteSpace(row); + endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN); + + // The start & end patterns must be pre/post fixed by a quiet zone. This + // zone must be at least 10 times the width of a narrow line. + // ref: http://www.barcode-1.net/i25code.html + validateQuietZone(row, endPattern[0]); + + // Now recalculate the indices of where the 'endblock' starts & stops to + // accommodate + // the reversed nature of the search + int temp = endPattern[0]; + endPattern[0] = row->getSize() - endPattern[1]; + endPattern[1] = row->getSize() - temp; + + row->reverse(); + return endPattern; + } catch (ReaderException const& re) { + delete [] endPattern; + row->reverse(); + throw re; + } + } + + /** + * The start & end patterns must be pre/post fixed by a quiet zone. This + * zone must be at least 10 times the width of a narrow line. Scan back until + * we either get to the start of the barcode or match the necessary number of + * quiet zone pixels. + * + * Note: Its assumed the row is reversed when using this method to find + * quiet zone after the end pattern. + * + * ref: http://www.barcode-1.net/i25code.html + * + * @param row bit array representing the scanned barcode. + * @param startPattern index into row of the start or end pattern. + * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown. + */ + void ITFReader::validateQuietZone(Ref row, int startPattern) { + (void)row; + (void)startPattern; +//#pragma mark needs some corrections +// int quietCount = narrowLineWidth * 10; // expect to find this many pixels of quiet zone +// +// for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) { +// if (row->get(i)) { +// break; +// } +// quietCount--; +// } +// if (quietCount != 0) { +// // Unable to find the necessary number of quiet zone pixels. +// throw ReaderException("Unable to find the necessary number of quiet zone pixels"); +// } + } + + /** + * Skip all whitespace until we get to the first black line. + * + * @param row row of black/white values to search + * @return index of the first black line. + * @throws ReaderException Throws exception if no black lines are found in the row + */ + int ITFReader::skipWhiteSpace(Ref row) { + int width = row->getSize(); + int endStart = 0; + while (endStart < width) { + if (row->get(endStart)) { + break; + } + endStart++; + } + if (endStart == width) { + throw ReaderException(""); + } + return endStart; + } + + /** + * @param row row of black/white values to search + * @param rowOffset position to start search + * @param pattern pattern of counts of number of black and white pixels that are + * being searched for as a pattern + * @return start/end horizontal offset of guard pattern, as an array of two + * ints + * @throws ReaderException if pattern is not found + */ + int* ITFReader::findGuardPattern(Ref row, int rowOffset, const int pattern[], + int patternLen) { + // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be + // merged to a single method. + int patternLength = patternLen; + int counters[patternLength]; + for (int i=0; igetSize(); + bool isWhite = false; + + int counterPosition = 0; + int patternStart = rowOffset; + for (int x = rowOffset; x < width; x++) { + bool pixel = row->get(x); + if (pixel ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if (patternMatchVariance(counters, patternLength, pattern, + MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { + int* resultValue = new int[2]; + resultValue[0] = patternStart; + resultValue[1] = x; + return resultValue; + } + patternStart += counters[0] + counters[1]; + for (int y = 2; y < patternLength; y++) { + counters[y - 2] = counters[y]; + } + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + throw ReaderException(""); + } + + /** + * Attempts to decode a sequence of ITF black/white lines into single + * digit. + * + * @param counters the counts of runs of observed black/white/black/... values + * @return The decoded digit + * @throws ReaderException if digit cannot be decoded + */ + int ITFReader::decodeDigit(int counters[], int countersLen){ + unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + int max = PATTERNS_LEN; + for (int i = 0; i < max; i++) { + int pattern[countersLen]; + for(int ind = 0; ind= 0) { + return bestMatch; + } else { + throw ReaderException("digit didint found"); + } + } + + ITFReader::~ITFReader(){ + } + } +} + +// file: zxing/oned/MultiFormatOneDReader.cpp + +/* + * MultiFormatOneDReader.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 "MultiFormatOneDReader.h" + +// #include +// #include +// #include +// #include +// #include + +namespace zxing { + namespace oned { + MultiFormatOneDReader::MultiFormatOneDReader(DecodeHints hints) : readers() { + if (hints.containsFormat(BarcodeFormat_EAN_13) || + hints.containsFormat(BarcodeFormat_EAN_8) || + hints.containsFormat(BarcodeFormat_UPC_A) || + hints.containsFormat(BarcodeFormat_UPC_E)) { + readers.push_back(Ref(new MultiFormatUPCEANReader(hints))); + } + if (hints.containsFormat(BarcodeFormat_CODE_39)) { + readers.push_back(Ref(new Code39Reader())); + } + if (hints.containsFormat(BarcodeFormat_CODE_128)) { + readers.push_back(Ref(new Code128Reader())); + } + if (hints.containsFormat(BarcodeFormat_ITF)) { + readers.push_back(Ref(new ITFReader())); + } + if (readers.size() == 0) { + readers.push_back(Ref(new MultiFormatUPCEANReader(hints))); + readers.push_back(Ref(new Code39Reader())); + readers.push_back(Ref(new Code128Reader())); + readers.push_back(Ref(new ITFReader())); + } + } + + Ref MultiFormatOneDReader::decodeRow(int rowNumber, Ref row) { + int size = readers.size(); + for (int i = 0; i < size; i++) { + OneDReader* reader = readers[i]; + Ref result = reader->decodeRow(rowNumber, row); + if (!result.empty()) { + return result; + } + } + return Ref(); + } + } +} + +// file: zxing/oned/MultiFormatUPCEANReader.cpp + +/* + * MultiFormatUPCEANReader.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 "MultiFormatUPCEANReader.h" + +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +namespace zxing { + namespace oned { + + MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() { + if (hints.containsFormat(BarcodeFormat_EAN_13)) { + readers.push_back(Ref(new EAN13Reader())); + } else if (hints.containsFormat(BarcodeFormat_UPC_A)) { + readers.push_back(Ref(new UPCAReader())); + } + if (hints.containsFormat(BarcodeFormat_EAN_8)) { + readers.push_back(Ref(new EAN8Reader())); + } + if (hints.containsFormat(BarcodeFormat_UPC_E)) { + readers.push_back(Ref(new UPCEReader())); + } + if (readers.size() == 0) { + readers.push_back(Ref(new EAN13Reader())); + // UPC-A is covered by EAN-13 + readers.push_back(Ref(new EAN8Reader())); + readers.push_back(Ref(new UPCEReader())); + } + } + + Ref MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref row) { + // Compute this location once and reuse it on multiple implementations + int size = readers.size(); + for (int i = 0; i < size; i++) { + Ref reader = readers[i]; + Ref result = reader->decodeRow(rowNumber, row); + if (result.empty()) { + continue; + } + + // Special case: a 12-digit code encoded in UPC-A is identical to a "0" + // followed by those 12 digits encoded as EAN-13. Each will recognize such a code, + // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with "0". + // Individually these are correct and their readers will both read such a code + // and correctly call it EAN-13, or UPC-A, respectively. + // + // In this case, if we've been looking for both types, we'd like to call it + // a UPC-A code. But for efficiency we only run the EAN-13 decoder to also read + // UPC-A. So we special case it here, and convert an EAN-13 result to a UPC-A + // result if appropriate. + if (result->getBarcodeFormat() == BarcodeFormat_EAN_13) { + const std::string& text = (result->getText())->getText(); + if (text[0] == '0') { + Ref resultString(new String(text.substr(1))); + Ref res(new Result(resultString, result->getRawBytes(), + result->getResultPoints(), BarcodeFormat_UPC_A)); + return res; + } + } + return result; + } + return Ref(); + } + } +} + +// file: zxing/oned/OneDReader.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * OneDReader.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 "OneDReader.h" +// #include +// #include +// #include +// #include + +namespace zxing { + namespace oned { + using namespace std; + + OneDReader::OneDReader() { + } + + Ref OneDReader::decode(Ref image, DecodeHints hints) { + Ref result = doDecode(image, hints); + if (result.empty()) { // && hints.getTryHarder() && image->isRotateSupported()) { + Ref rotatedImage(image->rotateCounterClockwise()); + result = doDecode(rotatedImage, hints); + if (!result.empty()) { + /* + // Record that we found it rotated 90 degrees CCW / 270 degrees CW + Hashtable metadata = result.getResultMetadata(); + int orientation = 270; + if (metadata != null && metadata.containsKey(ResultMetadataType.ORIENTATION)) { + // But if we found it reversed in doDecode(), add in that result here: + orientation = (orientation + + ((Integer) metadata.get(ResultMetadataType.ORIENTATION)).intValue()) % 360; + } + result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(orientation)); + */ + // Update result points + std::vector >& points (result->getResultPoints()); + int height = rotatedImage->getHeight(); + for (size_t i = 0; i < points.size(); i++) { + points[i].reset(new OneDResultPoint(height - points[i]->getY() - 1, points[i]->getX())); + } + } + } + if (result.empty()) { + throw ReaderException(""); + } + return result; + } + + Ref OneDReader::doDecode(Ref image, DecodeHints hints) { + int width = image->getWidth(); + int height = image->getHeight(); + Ref row(new BitArray(width)); + int middle = height >> 1; + bool tryHarder = hints.getTryHarder(); + int rowStep = (int)fmax(1, height >> (tryHarder ? 8 : 5)); + int maxLines; + if (tryHarder) { + maxLines = height; // Look at the whole image, not just the center + } else { + maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image + } + + for (int x = 0; x < maxLines; x++) { + // Scanning from the middle out. Determine which row we're looking at next: + int rowStepsAboveOrBelow = (x + 1) >> 1; + bool isAbove = (x & 0x01) == 0; // i.e. is x even? + int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow); + if (rowNumber < 0 || rowNumber >= height) { + // Oops, if we run off the top or bottom, stop + break; + } + + // Estimate black point for this row and load it: + try { + row = image->getBlackRow(rowNumber, row); + } catch (ReaderException const& re) { + continue; + } catch (IllegalArgumentException const& re) { + continue; + } + + // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to + // handle decoding upside down barcodes. + for (int attempt = 0; attempt < 2; attempt++) { + if (attempt == 1) { + row->reverse(); // reverse the row and continue + } + + // Look for a barcode + Ref result = decodeRow(rowNumber, row); + // We found our barcode + if (!result.empty()) { + if (attempt == 1) { + // But it was upside down, so note that + // result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180)); + // And remember to flip the result points horizontally. + std::vector > points(result->getResultPoints()); + // if there's exactly two points (which there should be), flip the x coordinate + // if there's not exactly 2, I don't know what do do with it + if (points.size() == 2) { + Ref pointZero(new OneDResultPoint(width - points[0]->getX() - 1, + points[0]->getY())); + points[0] = pointZero; + + Ref pointOne(new OneDResultPoint(width - points[1]->getX() - 1, + points[1]->getY())); + points[1] = pointOne; + + result.reset(new Result(result->getText(), result->getRawBytes(), points, + result->getBarcodeFormat())); + } + } + return result; + } + } + } + return Ref(); + } + + unsigned int OneDReader::patternMatchVariance(int counters[], int countersSize, + const int pattern[], int maxIndividualVariance) { + int numCounters = countersSize; + unsigned int total = 0; + unsigned int patternLength = 0; + for (int i = 0; i < numCounters; i++) { + total += counters[i]; + patternLength += pattern[i]; + } + if (total < patternLength) { + // If we don't even have one pixel per unit of bar width, assume this is too small + // to reliably match, so fail: + return INT_MAX; + } + // We're going to fake floating-point math in integers. We just need to use more bits. + // Scale up patternLength so that intermediate values below like scaledCounter will have + // more "significant digits" + unsigned int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength; + maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT; + + unsigned int totalVariance = 0; + for (int x = 0; x < numCounters; x++) { + int counter = counters[x] << INTEGER_MATH_SHIFT; + int scaledPattern = pattern[x] * unitBarWidth; + int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter; + if (variance > maxIndividualVariance) { + return INT_MAX; + } + totalVariance += variance; + } + return totalVariance / total; + } + + bool OneDReader::recordPattern(Ref row, int start, int counters[], int countersCount) { + int numCounters = countersCount;//sizeof(counters) / sizeof(int); + for (int i = 0; i < numCounters; i++) { + counters[i] = 0; + } + int end = row->getSize(); + if (start >= end) { + return false; + } + bool isWhite = !row->get(start); + int counterPosition = 0; + int i = start; + while (i < end) { + bool pixel = row->get(i); + if (pixel ^ isWhite) { // that is, exactly one is true + counters[counterPosition]++; + } else { + counterPosition++; + if (counterPosition == numCounters) { + break; + } else { + counters[counterPosition] = 1; + isWhite ^= true; // isWhite = !isWhite; + } + } + i++; + } + // If we read fully the last section of pixels and filled up our counters -- or filled + // the last counter but ran off the side of the image, OK. Otherwise, a problem. + if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end))) { + return false; + } + return true; + } + + OneDReader::~OneDReader() { + } + } +} + +// file: zxing/oned/OneDResultPoint.cpp + +/* + * OneDResultPoint.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 "OneDResultPoint.h" + +namespace zxing { + namespace oned { + + OneDResultPoint::OneDResultPoint(float posX, float posY) : ResultPoint(posX,posY) { + } + } +} + +// file: zxing/oned/UPCAReader.cpp + +/* + * UPCAReader.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 "UPCAReader.h" +// #include + +namespace zxing { + namespace oned { + UPCAReader::UPCAReader() : ean13Reader() { + } + + Ref UPCAReader::decodeRow(int rowNumber, Ref row) { + return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row)); + } + + Ref UPCAReader::decodeRow(int rowNumber, Ref row, int startGuardBegin, + int startGuardEnd) { + return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardBegin, + startGuardEnd)); + } + + Ref UPCAReader::decode(Ref image, DecodeHints hints) { + return maybeReturnResult(ean13Reader.decode(image, hints)); + } + + int UPCAReader::decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, + std::string& resultString) { + return ean13Reader.decodeMiddle(row, startGuardBegin, startGuardEnd, resultString); + } + + Ref UPCAReader::maybeReturnResult(Ref result) { + if (result.empty()) { + return result; + } + const std::string& text = (result->getText())->getText(); + if (text[0] == '0') { + Ref resultString(new String(text.substr(1))); + Ref res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), + BarcodeFormat_UPC_A)); + return res; + } + return Ref(); + } + + BarcodeFormat UPCAReader::getBarcodeFormat(){ + return BarcodeFormat_UPC_A; + } + } +} + +// file: zxing/oned/UPCEANReader.cpp + +/* + * UPCEANReader.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 "UPCEANReader.h" +// #include +// #include + +namespace zxing { + namespace oned { + + /** + * Start/end guard pattern. + */ + static const int START_END_PATTERN[3] = {1, 1, 1}; + + /** + * Pattern marking the middle of a UPC/EAN pattern, separating the two halves. + */ + static const int MIDDLE_PATTERN_LEN = 5; + static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1}; + + /** + * "Odd", or "L" patterns used to encode UPC/EAN digits. + */ + const int L_PATTERNS_LEN = 10; + const int L_PATTERNS_SUB_LEN = 4; + const int L_PATTERNS[L_PATTERNS_LEN][L_PATTERNS_SUB_LEN] = { + {3, 2, 1, 1}, // 0 + {2, 2, 2, 1}, // 1 + {2, 1, 2, 2}, // 2 + {1, 4, 1, 1}, // 3 + {1, 1, 3, 2}, // 4 + {1, 2, 3, 1}, // 5 + {1, 1, 1, 4}, // 6 + {1, 3, 1, 2}, // 7 + {1, 2, 1, 3}, // 8 + {3, 1, 1, 2} // 9 + }; + + /** + * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits. + */ + const int L_AND_G_PATTERNS_LEN = 20; + const int L_AND_G_PATTERNS_SUB_LEN = 4; + const int L_AND_G_PATTERNS[L_AND_G_PATTERNS_LEN][L_AND_G_PATTERNS_SUB_LEN] = { + {3, 2, 1, 1}, // 0 + {2, 2, 2, 1}, // 1 + {2, 1, 2, 2}, // 2 + {1, 4, 1, 1}, // 3 + {1, 1, 3, 2}, // 4 + {1, 2, 3, 1}, // 5 + {1, 1, 1, 4}, // 6 + {1, 3, 1, 2}, // 7 + {1, 2, 1, 3}, // 8 + {3, 1, 1, 2}, // 9 + {1, 1, 2, 3}, // 10 reversed 0 + {1, 2, 2, 2}, // 11 reversed 1 + {2, 2, 1, 2}, // 12 reversed 2 + {1, 1, 4, 1}, // 13 reversed 3 + {2, 3, 1, 1}, // 14 reversed 4 + {1, 3, 2, 1}, // 15 reversed 5 + {4, 1, 1, 1}, // 16 reversed 6 + {2, 1, 3, 1}, // 17 reversed 7 + {3, 1, 2, 1}, // 18 reversed 8 + {2, 1, 1, 3} // 19 reversed 9 + }; + + + int UPCEANReader::getMIDDLE_PATTERN_LEN() { + return MIDDLE_PATTERN_LEN; + } + + const int* UPCEANReader::getMIDDLE_PATTERN() { + return MIDDLE_PATTERN; + } + + UPCEANReader::UPCEANReader() { + } + + + Ref UPCEANReader::decodeRow(int rowNumber, Ref row) { + int rangeStart; + int rangeEnd; + if (findStartGuardPattern(row, &rangeStart, &rangeEnd)) { + try { + return decodeRow(rowNumber, row, rangeStart, rangeEnd); + } catch (ReaderException const& re) { + } + } + return Ref(); + } + + Ref UPCEANReader::decodeRow(int rowNumber, Ref row, int startGuardBegin, + int startGuardEnd) { + std::string tmpResultString; + std::string& tmpResultStringRef = tmpResultString; + int endStart = decodeMiddle(row, startGuardBegin, startGuardEnd, tmpResultStringRef); + if (endStart < 0) { + return Ref(); + } + + int endGuardBegin; + int endGuardEnd; + if (!decodeEnd(row, endStart, &endGuardBegin, &endGuardEnd)) { + return Ref(); + } + + // Make sure there is a quiet zone at least as big as the end pattern after the barcode. + // The spec might want more whitespace, but in practice this is the maximum we can count on. + size_t quietEnd = endGuardEnd + (endGuardEnd - endGuardBegin); + if (quietEnd >= row->getSize() || !row->isRange(endGuardEnd, quietEnd, false)) { + return Ref(); + } + + if (!checkChecksum(tmpResultString)) { + return Ref(); + } + + Ref resultString(new String(tmpResultString)); + float left = (float) (startGuardBegin + startGuardEnd) / 2.0f; + float right = (float) (endGuardBegin + endGuardEnd) / 2.0f; + + std::vector< Ref > resultPoints(2); + Ref resultPoint1(new OneDResultPoint(left, (float) rowNumber)); + Ref resultPoint2(new OneDResultPoint(right, (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + ArrayRef resultBytes(1); + return Ref(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat())); + } + + bool UPCEANReader::findStartGuardPattern(Ref row, int* rangeStart, int* rangeEnd) { + int nextStart = 0; + while (findGuardPattern(row, nextStart, false, START_END_PATTERN, + sizeof(START_END_PATTERN) / sizeof(int), rangeStart, rangeEnd)) { + int start = *rangeStart; + nextStart = *rangeEnd; + // Make sure there is a quiet zone at least as big as the start pattern before the barcode. + // If this check would run off the left edge of the image, do not accept this barcode, + // as it is very likely to be a false positive. + int quietStart = start - (nextStart - start); + if (quietStart >= 0 && row->isRange(quietStart, start, false)) { + return true; + } + } + return false; + } + + bool UPCEANReader::findGuardPattern(Ref row, int rowOffset, bool whiteFirst, + const int pattern[], int patternLen, int* start, int* end) { + int patternLength = patternLen; + int counters[patternLength]; + int countersCount = sizeof(counters) / sizeof(int); + for (int i = 0; i < countersCount; i++) { + counters[i] = 0; + } + int width = row->getSize(); + bool isWhite = false; + while (rowOffset < width) { + isWhite = !row->get(rowOffset); + if (whiteFirst == isWhite) { + break; + } + rowOffset++; + } + + int counterPosition = 0; + int patternStart = rowOffset; + for (int x = rowOffset; x < width; x++) { + bool pixel = row->get(x); + if (pixel ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if (patternMatchVariance(counters, countersCount, pattern, + MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { + *start = patternStart; + *end = x; + return true; + } + patternStart += counters[0] + counters[1]; + for (int y = 2; y < patternLength; y++) { + counters[y - 2] = counters[y]; + } + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + return false; + } + + bool UPCEANReader::decodeEnd(Ref row, int endStart, int* endGuardBegin, + int* endGuardEnd) { + return findGuardPattern(row, endStart, false, START_END_PATTERN, + sizeof(START_END_PATTERN) / sizeof(int), endGuardBegin, endGuardEnd); + } + + int UPCEANReader::decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, + UPC_EAN_PATTERNS patternType) { + if (!recordPattern(row, rowOffset, counters, countersLen)) { + return -1; + } + unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + + int max = 0; + switch (patternType) { + case UPC_EAN_PATTERNS_L_PATTERNS: + max = L_PATTERNS_LEN; + for (int i = 0; i < max; i++) { + int pattern[countersLen]; + for(int j = 0; j< countersLen; j++){ + pattern[j] = L_PATTERNS[i][j]; + } + + unsigned int variance = patternMatchVariance(counters, countersLen, pattern, + MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = i; + } + } + break; + case UPC_EAN_PATTERNS_L_AND_G_PATTERNS: + max = L_AND_G_PATTERNS_LEN; + for (int i = 0; i < max; i++) { + int pattern[countersLen]; + for(int j = 0; j< countersLen; j++){ + pattern[j] = L_AND_G_PATTERNS[i][j]; + } + + unsigned int variance = patternMatchVariance(counters, countersLen, pattern, + MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = i; + } + } + break; + default: + break; + } + return bestMatch; + } + + /** + * @return {@link #checkStandardUPCEANChecksum(String)} + */ + bool UPCEANReader::checkChecksum(std::string s) { + return checkStandardUPCEANChecksum(s); + } + + /** + * Computes the UPC/EAN checksum on a string of digits, and reports + * whether the checksum is correct or not. + * + * @param s string of digits to check + * @return true iff string of digits passes the UPC/EAN checksum algorithm + */ + bool UPCEANReader::checkStandardUPCEANChecksum(std::string s) { + int length = s.length(); + if (length == 0) { + return false; + } + + int sum = 0; + for (int i = length - 2; i >= 0; i -= 2) { + int digit = (int) s[i] - (int) '0'; + if (digit < 0 || digit > 9) { + return false; + } + sum += digit; + } + sum *= 3; + for (int i = length - 1; i >= 0; i -= 2) { + int digit = (int) s[i] - (int) '0'; + if (digit < 0 || digit > 9) { + return false; + } + sum += digit; + } + return sum % 10 == 0; + } + + UPCEANReader::~UPCEANReader() { + } + } +} + +// file: zxing/oned/UPCEReader.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 "UPCEReader.h" +// #include + +namespace zxing { + namespace oned { + + /** + * The pattern that marks the middle, and end, of a UPC-E pattern. + * There is no "second half" to a UPC-E barcode. + */ + static const int MIDDLE_END_PATTERN[6] = {1, 1, 1, 1, 1, 1}; + + /** + * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of + * even-odd parity encodings of digits that imply both the number system (0 or 1) + * used, and the check digit. + */ + static const int NUMSYS_AND_CHECK_DIGIT_PATTERNS[2][10] = { + {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25}, + {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A} + }; + + UPCEReader::UPCEReader() { + } + + int UPCEReader::decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, + std::string& resultString) { + (void)startGuardBegin; + const int countersLen = 4; + int counters[countersLen] = { 0, 0, 0, 0 }; + + int end = row->getSize(); + int rowOffset = startGuardEnd; + int lgPatternFound = 0; + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, + UPC_EAN_PATTERNS_L_AND_G_PATTERNS); + if (bestMatch < 0) { + return -1; + } + resultString.append(1, (char) ('0' + bestMatch % 10)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + if (bestMatch >= 10) { + lgPatternFound |= 1 << (5 - x); + } + } + + if (!determineNumSysAndCheckDigit(resultString, lgPatternFound)) { + return -1; + } + return rowOffset; + } + + bool UPCEReader::decodeEnd(Ref row, int endStart, int* endGuardBegin, + int* endGuardEnd) { + return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN, + sizeof(MIDDLE_END_PATTERN) / sizeof(int), endGuardBegin, endGuardEnd); + } + + bool UPCEReader::checkChecksum(std::string s){ + return UPCEANReader::checkChecksum(convertUPCEtoUPCA(s)); + } + + + bool UPCEReader::determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound) { + for (int numSys = 0; numSys <= 1; numSys++) { + for (int d = 0; d < 10; d++) { + if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) { + resultString.insert(0, 1, (char) ('0' + numSys)); + resultString.append(1, (char) ('0' + d)); + return true; + } + } + } + return false; + } + + /** + * Expands a UPC-E value back into its full, equivalent UPC-A code value. + * + * @param upce UPC-E code as string of digits + * @return equivalent UPC-A code as string of digits + */ + std::string UPCEReader::convertUPCEtoUPCA(std::string upce) { + std::string result; + result.append(1, upce[0]); + char lastChar = upce[6]; + switch (lastChar) { + case '0': + case '1': + case '2': + result.append(upce.substr(1,2)); + result.append(1, lastChar); + result.append("0000"); + result.append(upce.substr(3,3)); + break; + case '3': + result.append(upce.substr(1,3)); + result.append("00000"); + result.append(upce.substr(4,2)); + break; + case '4': + result.append(upce.substr(1,4)); + result.append("00000"); + result.append(1, upce[5]); + break; + default: + result.append(upce.substr(1,5)); + result.append("0000"); + result.append(1, lastChar); + break; + } + result.append(1, upce[7]); + return result; + } + + + BarcodeFormat UPCEReader::getBarcodeFormat() { + return BarcodeFormat_UPC_E; + } + } +} + +// file: zxing/qrcode/ErrorCorrectionLevel.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * ErrorCorrectionLevel.cpp + * zxing + * + * Created by Christian Brunschen on 15/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 + +using std::string; + +namespace zxing { +namespace qrcode { + +ErrorCorrectionLevel::ErrorCorrectionLevel(int inOrdinal, + int bits, + char const* name) : + ordinal_(inOrdinal), bits_(bits), name_(name) {} + +int ErrorCorrectionLevel::ordinal() const { + return ordinal_; +} + +int ErrorCorrectionLevel::bits() const { + return bits_; +} + +string const& ErrorCorrectionLevel::name() const { + return name_; +} + +ErrorCorrectionLevel::operator string const& () const { + return name_; +} + +ErrorCorrectionLevel& ErrorCorrectionLevel::forBits(int bits) { + if (bits < 0 || bits >= N_LEVELS) { + throw ReaderException("Ellegal error correction level bits"); + } + return *FOR_BITS[bits]; +} + + ErrorCorrectionLevel ErrorCorrectionLevel::L(0, 0x01, "L"); + ErrorCorrectionLevel ErrorCorrectionLevel::M(1, 0x00, "M"); + ErrorCorrectionLevel ErrorCorrectionLevel::Q(2, 0x03, "Q"); + ErrorCorrectionLevel ErrorCorrectionLevel::H(3, 0x02, "H"); +ErrorCorrectionLevel *ErrorCorrectionLevel::FOR_BITS[] = { &M, &L, &H, &Q }; +int ErrorCorrectionLevel::N_LEVELS = 4; + +} +} + +// file: zxing/qrcode/FormatInformation.cpp + +/* + * FormatInformation.cpp + * zxing + * + * Created by Christian Brunschen on 18/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 +// #include + +namespace zxing { +namespace qrcode { + +using namespace std; + +int FormatInformation::FORMAT_INFO_MASK_QR = 0x5412; +int FormatInformation::FORMAT_INFO_DECODE_LOOKUP[][2] = { { 0x5412, 0x00 }, { 0x5125, 0x01 }, { 0x5E7C, 0x02 }, { + 0x5B4B, 0x03 }, { 0x45F9, 0x04 }, { 0x40CE, 0x05 }, { 0x4F97, 0x06 }, { 0x4AA0, 0x07 }, { 0x77C4, 0x08 }, { + 0x72F3, 0x09 }, { 0x7DAA, 0x0A }, { 0x789D, 0x0B }, { 0x662F, 0x0C }, { 0x6318, 0x0D }, { 0x6C41, 0x0E }, { + 0x6976, 0x0F }, { 0x1689, 0x10 }, { 0x13BE, 0x11 }, { 0x1CE7, 0x12 }, { 0x19D0, 0x13 }, { 0x0762, 0x14 }, { + 0x0255, 0x15 }, { 0x0D0C, 0x16 }, { 0x083B, 0x17 }, { 0x355F, 0x18 }, { 0x3068, 0x19 }, { 0x3F31, 0x1A }, { + 0x3A06, 0x1B }, { 0x24B4, 0x1C }, { 0x2183, 0x1D }, { 0x2EDA, 0x1E }, { 0x2BED, 0x1F }, +}; +int FormatInformation::N_FORMAT_INFO_DECODE_LOOKUPS = 32; + +int FormatInformation::BITS_SET_IN_HALF_BYTE[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + +FormatInformation::FormatInformation(int formatInfo) : + errorCorrectionLevel_(ErrorCorrectionLevel::forBits((formatInfo >> 3) & 0x03)), dataMask_( + (unsigned char)(formatInfo & 0x07)) { +} + +ErrorCorrectionLevel& FormatInformation::getErrorCorrectionLevel() { + return errorCorrectionLevel_; +} + +unsigned char FormatInformation::getDataMask() { + return dataMask_; +} + +int FormatInformation::numBitsDiffering(unsigned int a, unsigned int b) { + a ^= b; + return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(a >> 4 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 8 + & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 12 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 16 & 0x0F)] + + BITS_SET_IN_HALF_BYTE[(a >> 20 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 24 & 0x0F)] + + BITS_SET_IN_HALF_BYTE[(a >> 28 & 0x0F)]; +} + +Ref FormatInformation::decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) { + Ref result(doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2)); + if (result != 0) { + return result; + } + // Should return null, but, some QR codes apparently + // do not mask this info. Try again by actually masking the pattern + // first + return doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR, + maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR); +} +Ref FormatInformation::doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) { + // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing + int bestDifference = numeric_limits::max(); + int bestFormatInfo = 0; + for (int i = 0; i < N_FORMAT_INFO_DECODE_LOOKUPS; i++) { + int* decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i]; + int targetInfo = decodeInfo[0]; + if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) { + // Found an exact match + Ref result(new FormatInformation(decodeInfo[1])); + return result; + } + int bitsDifference = numBitsDiffering(maskedFormatInfo1, targetInfo); + if (bitsDifference < bestDifference) { + bestFormatInfo = decodeInfo[1]; + bestDifference = bitsDifference; + } + if (maskedFormatInfo1 != maskedFormatInfo2) { + // also try the other option + bitsDifference = numBitsDiffering(maskedFormatInfo2, targetInfo); + if (bitsDifference < bestDifference) { + bestFormatInfo = decodeInfo[1]; + bestDifference = bitsDifference; + } + } + } + if (bestDifference <= 3) { + Ref result(new FormatInformation(bestFormatInfo)); + return result; + } + Ref result; + return result; +} + +bool operator==(const FormatInformation &a, const FormatInformation &b) { + return &(a.errorCorrectionLevel_) == &(b.errorCorrectionLevel_) && a.dataMask_ == b.dataMask_; +} + +ostream& operator<<(ostream& out, const FormatInformation& fi) { + const FormatInformation *fip = &fi; + out << "FormatInformation @ " << fip; + return out; +} + +} +} + +// file: zxing/qrcode/QRCodeReader.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * QRCodeReader.cpp + * zxing + * + * Created by Christian Brunschen on 20/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 +// #include + +// #include + +namespace zxing { + namespace qrcode { + + using namespace std; + + QRCodeReader::QRCodeReader() :decoder_() { + } + //TODO: see if any of the other files in the qrcode tree need tryHarder + Ref QRCodeReader::decode(Ref image, DecodeHints hints) { +#ifdef DEBUG + cout << "decoding image " << image.object_ << ":\n" << flush; +#endif + + Detector detector(image->getBlackMatrix()); + + +#ifdef DEBUG + cout << "(1) created detector " << &detector << "\n" << flush; +#endif + + Ref detectorResult(detector.detect(hints)); +#ifdef DEBUG + cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush; +#endif + + std::vector > points(detectorResult->getPoints()); + + +#ifdef DEBUG + cout << "(3) extracted points " << &points << "\n" << flush; + cout << "found " << points.size() << " points:\n"; + for (size_t i = 0; i < points.size(); i++) { + cout << " " << points[i]->getX() << "," << points[i]->getY() << "\n"; + } + cout << "bits:\n"; + cout << *(detectorResult->getBits()) << "\n"; +#endif + + Ref decoderResult(decoder_.decode(detectorResult->getBits())); +#ifdef DEBUG + cout << "(4) decoded, have decoderResult " << decoderResult.object_ << "\n" << flush; +#endif + + Ref result( + new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_QR_CODE)); +#ifdef DEBUG + cout << "(5) created result " << result.object_ << ", returning\n" << flush; +#endif + + return result; + } + + QRCodeReader::~QRCodeReader() { + } + + Decoder& QRCodeReader::getDecoder() { + return decoder_; + } + } +} + +// file: zxing/qrcode/Version.cpp + +/* + * Version.cpp + * zxing + * + * Created by Christian Brunschen on 14/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 +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { +using namespace std; + +ECB::ECB(int count, int dataCodewords) : + count_(count), dataCodewords_(dataCodewords) { +} + +int ECB::getCount() { + return count_; +} + +int ECB::getDataCodewords() { + return dataCodewords_; +} + +ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks) : + ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks) { +} + +ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) : + ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks1) { + ecBlocks_.push_back(ecBlocks2); +} + +int ECBlocks::getECCodewords() { + return ecCodewords_; +} + +std::vector& ECBlocks::getECBlocks() { + return ecBlocks_; +} + +ECBlocks::~ECBlocks() { + for (size_t i = 0; i < ecBlocks_.size(); i++) { + delete ecBlocks_[i]; + } +} + +unsigned int Version::VERSION_DECODE_INFO[] = { 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 + }; +int Version::N_VERSION_DECODE_INFOS = 34; +vector > Version::VERSIONS; +static int N_VERSIONS = Version::buildVersions(); + +int Version::getVersionNumber() { + return versionNumber_; +} + +vector &Version::getAlignmentPatternCenters() { + return alignmentPatternCenters_; +} + +int Version::getTotalCodewords() { + return totalCodewords_; +} + +int Version::getDimensionForVersion() { + return 17 + 4 * versionNumber_; +} + +ECBlocks& Version::getECBlocksForLevel(ErrorCorrectionLevel &ecLevel) { + return *ecBlocks_[ecLevel.ordinal()]; +} + +Version *Version::getProvisionalVersionForDimension(int dimension) { + if (dimension % 4 != 1) { + throw ReaderException("Dimension must be 1 mod 4"); + } + return Version::getVersionForNumber((dimension - 17) >> 2); +} + +Version *Version::getVersionForNumber(int versionNumber) { + if (versionNumber < 1 || versionNumber > N_VERSIONS) { + throw ReaderException("versionNumber must be between 1 and 40"); + } + + return VERSIONS[versionNumber - 1]; +} + +Version::Version(int versionNumber, vector *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2, + ECBlocks *ecBlocks3, ECBlocks *ecBlocks4) : + versionNumber_(versionNumber), alignmentPatternCenters_(*alignmentPatternCenters), ecBlocks_(4), totalCodewords_(0) { + ecBlocks_[0] = ecBlocks1; + ecBlocks_[1] = ecBlocks2; + ecBlocks_[2] = ecBlocks3; + ecBlocks_[3] = ecBlocks4; + + int total = 0; + int ecCodewords = ecBlocks1->getECCodewords(); + vector &ecbArray = ecBlocks1->getECBlocks(); + for (size_t i = 0; i < ecbArray.size(); i++) { + ECB *ecBlock = ecbArray[i]; + total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords); + } + totalCodewords_ = total; +} + +Version::~Version() { + delete &alignmentPatternCenters_; + for (size_t i = 0; i < ecBlocks_.size(); i++) { + delete ecBlocks_[i]; + } +} + +Version *Version::decodeVersionInformation(unsigned int versionBits) { + int bestDifference = numeric_limits::max(); + size_t bestVersion = 0; + for (int i = 0; i < N_VERSION_DECODE_INFOS; i++) { + unsigned targetVersion = VERSION_DECODE_INFO[i]; + // Do the version info bits match exactly? done. + if (targetVersion == versionBits) { + return getVersionForNumber(i + 7); + } + // Otherwise see if this is the closest to a real version info bit + // string we have seen so far + int bitsDifference = FormatInformation::numBitsDiffering(versionBits, targetVersion); + if (bitsDifference < bestDifference) { + bestVersion = i + 7; + bestDifference = bitsDifference; + } + } + // We can tolerate up to 3 bits of error since no two version info codewords will + // differ in less than 4 bits. + if (bestDifference <= 3) { + return getVersionForNumber(bestVersion); + } + // If we didn't find a close enough match, fail + return 0; +} + +Ref Version::buildFunctionPattern() { + int dimension = getDimensionForVersion(); + Ref functionPattern(new BitMatrix(dimension)); + + + // Top left finder pattern + separator + format + functionPattern->setRegion(0, 0, 9, 9); + // Top right finder pattern + separator + format + functionPattern->setRegion(dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + functionPattern->setRegion(0, dimension - 8, 9, 8); + + + // Alignment patterns + size_t max = alignmentPatternCenters_.size(); + for (size_t x = 0; x < max; x++) { + int i = alignmentPatternCenters_[x] - 2; + for (size_t y = 0; y < max; y++) { + if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { + // No alignment patterns near the three finder patterns + continue; + } + functionPattern->setRegion(alignmentPatternCenters_[y] - 2, i, 5, 5); + } + } + + // Vertical timing pattern + functionPattern->setRegion(6, 9, 1, dimension - 17); + // Horizontal timing pattern + functionPattern->setRegion(9, 6, dimension - 17, 1); + + if (versionNumber_ > 6) { + // Version info, top right + functionPattern->setRegion(dimension - 11, 0, 3, 6); + // Version info, bottom left + functionPattern->setRegion(0, dimension - 11, 6, 3); + } + + + //#ifdef DEBUG + // cout << "version " << versionNumber_ << " built function pattern:\n"; + // cout << *functionPattern; + //#endif + + return functionPattern; +} + +static vector *intArray(size_t n...) { + va_list ap; + va_start(ap, n); + vector *result = new vector(n); + for (size_t i = 0; i < n; i++) { + (*result)[i] = va_arg(ap, int); + } + va_end(ap); + return result; +} + +int Version::buildVersions() { + VERSIONS.push_back(Ref(new Version(1, intArray(0), + new ECBlocks(7, new ECB(1, 19)), + new ECBlocks(10, new ECB(1, 16)), + new ECBlocks(13, new ECB(1, 13)), + new ECBlocks(17, new ECB(1, 9))))); + VERSIONS.push_back(Ref(new Version(2, intArray(2, 6, 18), + new ECBlocks(10, new ECB(1, 34)), + new ECBlocks(16, new ECB(1, 28)), + new ECBlocks(22, new ECB(1, 22)), + new ECBlocks(28, new ECB(1, 16))))); + VERSIONS.push_back(Ref(new Version(3, intArray(2, 6, 22), + new ECBlocks(15, new ECB(1, 55)), + new ECBlocks(26, new ECB(1, 44)), + new ECBlocks(18, new ECB(2, 17)), + new ECBlocks(22, new ECB(2, 13))))); + VERSIONS.push_back(Ref(new Version(4, intArray(2, 6, 26), + new ECBlocks(20, new ECB(1, 80)), + new ECBlocks(18, new ECB(2, 32)), + new ECBlocks(26, new ECB(2, 24)), + new ECBlocks(16, new ECB(4, 9))))); + VERSIONS.push_back(Ref(new Version(5, intArray(2, 6, 30), + new ECBlocks(26, new ECB(1, 108)), + new ECBlocks(24, new ECB(2, 43)), + new ECBlocks(18, new ECB(2, 15), + new ECB(2, 16)), + new ECBlocks(22, new ECB(2, 11), + new ECB(2, 12))))); + VERSIONS.push_back(Ref(new Version(6, intArray(2, 6, 34), + new ECBlocks(18, new ECB(2, 68)), + new ECBlocks(16, new ECB(4, 27)), + new ECBlocks(24, new ECB(4, 19)), + new ECBlocks(28, new ECB(4, 15))))); + VERSIONS.push_back(Ref(new Version(7, intArray(3, 6, 22, 38), + new ECBlocks(20, new ECB(2, 78)), + new ECBlocks(18, new ECB(4, 31)), + new ECBlocks(18, new ECB(2, 14), + new ECB(4, 15)), + new ECBlocks(26, new ECB(4, 13), + new ECB(1, 14))))); + VERSIONS.push_back(Ref(new Version(8, intArray(3, 6, 24, 42), + new ECBlocks(24, new ECB(2, 97)), + new ECBlocks(22, new ECB(2, 38), + new ECB(2, 39)), + new ECBlocks(22, new ECB(4, 18), + new ECB(2, 19)), + new ECBlocks(26, new ECB(4, 14), + new ECB(2, 15))))); + VERSIONS.push_back(Ref(new Version(9, intArray(3, 6, 26, 46), + new ECBlocks(30, new ECB(2, 116)), + new ECBlocks(22, new ECB(3, 36), + new ECB(2, 37)), + new ECBlocks(20, new ECB(4, 16), + new ECB(4, 17)), + new ECBlocks(24, new ECB(4, 12), + new ECB(4, 13))))); + VERSIONS.push_back(Ref(new Version(10, intArray(3, 6, 28, 50), + new ECBlocks(18, new ECB(2, 68), + new ECB(2, 69)), + new ECBlocks(26, new ECB(4, 43), + new ECB(1, 44)), + new ECBlocks(24, new ECB(6, 19), + new ECB(2, 20)), + new ECBlocks(28, new ECB(6, 15), + new ECB(2, 16))))); + VERSIONS.push_back(Ref(new Version(11, intArray(3, 6, 30, 54), + new ECBlocks(20, new ECB(4, 81)), + new ECBlocks(30, new ECB(1, 50), + new ECB(4, 51)), + new ECBlocks(28, new ECB(4, 22), + new ECB(4, 23)), + new ECBlocks(24, new ECB(3, 12), + new ECB(8, 13))))); + VERSIONS.push_back(Ref(new Version(12, intArray(3, 6, 32, 58), + new ECBlocks(24, new ECB(2, 92), + new ECB(2, 93)), + new ECBlocks(22, new ECB(6, 36), + new ECB(2, 37)), + new ECBlocks(26, new ECB(4, 20), + new ECB(6, 21)), + new ECBlocks(28, new ECB(7, 14), + new ECB(4, 15))))); + VERSIONS.push_back(Ref(new Version(13, intArray(3, 6, 34, 62), + new ECBlocks(26, new ECB(4, 107)), + new ECBlocks(22, new ECB(8, 37), + new ECB(1, 38)), + new ECBlocks(24, new ECB(8, 20), + new ECB(4, 21)), + new ECBlocks(22, new ECB(12, 11), + new ECB(4, 12))))); + VERSIONS.push_back(Ref(new Version(14, intArray(4, 6, 26, 46, 66), + new ECBlocks(30, new ECB(3, 115), + new ECB(1, 116)), + new ECBlocks(24, new ECB(4, 40), + new ECB(5, 41)), + new ECBlocks(20, new ECB(11, 16), + new ECB(5, 17)), + new ECBlocks(24, new ECB(11, 12), + new ECB(5, 13))))); + VERSIONS.push_back(Ref(new Version(15, intArray(4, 6, 26, 48, 70), + new ECBlocks(22, new ECB(5, 87), + new ECB(1, 88)), + new ECBlocks(24, new ECB(5, 41), + new ECB(5, 42)), + new ECBlocks(30, new ECB(5, 24), + new ECB(7, 25)), + new ECBlocks(24, new ECB(11, 12), + new ECB(7, 13))))); + VERSIONS.push_back(Ref(new Version(16, intArray(4, 6, 26, 50, 74), + new ECBlocks(24, new ECB(5, 98), + new ECB(1, 99)), + new ECBlocks(28, new ECB(7, 45), + new ECB(3, 46)), + new ECBlocks(24, new ECB(15, 19), + new ECB(2, 20)), + new ECBlocks(30, new ECB(3, 15), + new ECB(13, 16))))); + VERSIONS.push_back(Ref(new Version(17, intArray(4, 6, 30, 54, 78), + new ECBlocks(28, new ECB(1, 107), + new ECB(5, 108)), + new ECBlocks(28, new ECB(10, 46), + new ECB(1, 47)), + new ECBlocks(28, new ECB(1, 22), + new ECB(15, 23)), + new ECBlocks(28, new ECB(2, 14), + new ECB(17, 15))))); + VERSIONS.push_back(Ref(new Version(18, intArray(4, 6, 30, 56, 82), + new ECBlocks(30, new ECB(5, 120), + new ECB(1, 121)), + new ECBlocks(26, new ECB(9, 43), + new ECB(4, 44)), + new ECBlocks(28, new ECB(17, 22), + new ECB(1, 23)), + new ECBlocks(28, new ECB(2, 14), + new ECB(19, 15))))); + VERSIONS.push_back(Ref(new Version(19, intArray(4, 6, 30, 58, 86), + new ECBlocks(28, new ECB(3, 113), + new ECB(4, 114)), + new ECBlocks(26, new ECB(3, 44), + new ECB(11, 45)), + new ECBlocks(26, new ECB(17, 21), + new ECB(4, 22)), + new ECBlocks(26, new ECB(9, 13), + new ECB(16, 14))))); + VERSIONS.push_back(Ref(new Version(20, intArray(4, 6, 34, 62, 90), + new ECBlocks(28, new ECB(3, 107), + new ECB(5, 108)), + new ECBlocks(26, new ECB(3, 41), + new ECB(13, 42)), + new ECBlocks(30, new ECB(15, 24), + new ECB(5, 25)), + new ECBlocks(28, new ECB(15, 15), + new ECB(10, 16))))); + VERSIONS.push_back(Ref(new Version(21, intArray(5, 6, 28, 50, 72, 94), + new ECBlocks(28, new ECB(4, 116), + new ECB(4, 117)), + new ECBlocks(26, new ECB(17, 42)), + new ECBlocks(28, new ECB(17, 22), + new ECB(6, 23)), + new ECBlocks(30, new ECB(19, 16), + new ECB(6, 17))))); + VERSIONS.push_back(Ref(new Version(22, intArray(5, 6, 26, 50, 74, 98), + new ECBlocks(28, new ECB(2, 111), + new ECB(7, 112)), + new ECBlocks(28, new ECB(17, 46)), + new ECBlocks(30, new ECB(7, 24), + new ECB(16, 25)), + new ECBlocks(24, new ECB(34, 13))))); + VERSIONS.push_back(Ref(new Version(23, intArray(5, 6, 30, 54, 78, 102), + new ECBlocks(30, new ECB(4, 121), + new ECB(5, 122)), + new ECBlocks(28, new ECB(4, 47), + new ECB(14, 48)), + new ECBlocks(30, new ECB(11, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(16, 15), + new ECB(14, 16))))); + VERSIONS.push_back(Ref(new Version(24, intArray(5, 6, 28, 54, 80, 106), + new ECBlocks(30, new ECB(6, 117), + new ECB(4, 118)), + new ECBlocks(28, new ECB(6, 45), + new ECB(14, 46)), + new ECBlocks(30, new ECB(11, 24), + new ECB(16, 25)), + new ECBlocks(30, new ECB(30, 16), + new ECB(2, 17))))); + VERSIONS.push_back(Ref(new Version(25, intArray(5, 6, 32, 58, 84, 110), + new ECBlocks(26, new ECB(8, 106), + new ECB(4, 107)), + new ECBlocks(28, new ECB(8, 47), + new ECB(13, 48)), + new ECBlocks(30, new ECB(7, 24), + new ECB(22, 25)), + new ECBlocks(30, new ECB(22, 15), + new ECB(13, 16))))); + VERSIONS.push_back(Ref(new Version(26, intArray(5, 6, 30, 58, 86, 114), + new ECBlocks(28, new ECB(10, 114), + new ECB(2, 115)), + new ECBlocks(28, new ECB(19, 46), + new ECB(4, 47)), + new ECBlocks(28, new ECB(28, 22), + new ECB(6, 23)), + new ECBlocks(30, new ECB(33, 16), + new ECB(4, 17))))); + VERSIONS.push_back(Ref(new Version(27, intArray(5, 6, 34, 62, 90, 118), + new ECBlocks(30, new ECB(8, 122), + new ECB(4, 123)), + new ECBlocks(28, new ECB(22, 45), + new ECB(3, 46)), + new ECBlocks(30, new ECB(8, 23), + new ECB(26, 24)), + new ECBlocks(30, new ECB(12, 15), + new ECB(28, 16))))); + VERSIONS.push_back(Ref(new Version(28, intArray(6, 6, 26, 50, 74, 98, 122), + new ECBlocks(30, new ECB(3, 117), + new ECB(10, 118)), + new ECBlocks(28, new ECB(3, 45), + new ECB(23, 46)), + new ECBlocks(30, new ECB(4, 24), + new ECB(31, 25)), + new ECBlocks(30, new ECB(11, 15), + new ECB(31, 16))))); + VERSIONS.push_back(Ref(new Version(29, intArray(6, 6, 30, 54, 78, 102, 126), + new ECBlocks(30, new ECB(7, 116), + new ECB(7, 117)), + new ECBlocks(28, new ECB(21, 45), + new ECB(7, 46)), + new ECBlocks(30, new ECB(1, 23), + new ECB(37, 24)), + new ECBlocks(30, new ECB(19, 15), + new ECB(26, 16))))); + VERSIONS.push_back(Ref(new Version(30, intArray(6, 6, 26, 52, 78, 104, 130), + new ECBlocks(30, new ECB(5, 115), + new ECB(10, 116)), + new ECBlocks(28, new ECB(19, 47), + new ECB(10, 48)), + new ECBlocks(30, new ECB(15, 24), + new ECB(25, 25)), + new ECBlocks(30, new ECB(23, 15), + new ECB(25, 16))))); + VERSIONS.push_back(Ref(new Version(31, intArray(6, 6, 30, 56, 82, 108, 134), + new ECBlocks(30, new ECB(13, 115), + new ECB(3, 116)), + new ECBlocks(28, new ECB(2, 46), + new ECB(29, 47)), + new ECBlocks(30, new ECB(42, 24), + new ECB(1, 25)), + new ECBlocks(30, new ECB(23, 15), + new ECB(28, 16))))); + VERSIONS.push_back(Ref(new Version(32, intArray(6, 6, 34, 60, 86, 112, 138), + new ECBlocks(30, new ECB(17, 115)), + new ECBlocks(28, new ECB(10, 46), + new ECB(23, 47)), + new ECBlocks(30, new ECB(10, 24), + new ECB(35, 25)), + new ECBlocks(30, new ECB(19, 15), + new ECB(35, 16))))); + VERSIONS.push_back(Ref(new Version(33, intArray(6, 6, 30, 58, 86, 114, 142), + new ECBlocks(30, new ECB(17, 115), + new ECB(1, 116)), + new ECBlocks(28, new ECB(14, 46), + new ECB(21, 47)), + new ECBlocks(30, new ECB(29, 24), + new ECB(19, 25)), + new ECBlocks(30, new ECB(11, 15), + new ECB(46, 16))))); + VERSIONS.push_back(Ref(new Version(34, intArray(6, 6, 34, 62, 90, 118, 146), + new ECBlocks(30, new ECB(13, 115), + new ECB(6, 116)), + new ECBlocks(28, new ECB(14, 46), + new ECB(23, 47)), + new ECBlocks(30, new ECB(44, 24), + new ECB(7, 25)), + new ECBlocks(30, new ECB(59, 16), + new ECB(1, 17))))); + VERSIONS.push_back(Ref(new Version(35, intArray(7, 6, 30, 54, 78, + 102, 126, 150), + new ECBlocks(30, new ECB(12, 121), + new ECB(7, 122)), + new ECBlocks(28, new ECB(12, 47), + new ECB(26, 48)), + new ECBlocks(30, new ECB(39, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(22, 15), + new ECB(41, 16))))); + VERSIONS.push_back(Ref(new Version(36, intArray(7, 6, 24, 50, 76, + 102, 128, 154), + new ECBlocks(30, new ECB(6, 121), + new ECB(14, 122)), + new ECBlocks(28, new ECB(6, 47), + new ECB(34, 48)), + new ECBlocks(30, new ECB(46, 24), + new ECB(10, 25)), + new ECBlocks(30, new ECB(2, 15), + new ECB(64, 16))))); + VERSIONS.push_back(Ref(new Version(37, intArray(7, 6, 28, 54, 80, + 106, 132, 158), + new ECBlocks(30, new ECB(17, 122), + new ECB(4, 123)), + new ECBlocks(28, new ECB(29, 46), + new ECB(14, 47)), + new ECBlocks(30, new ECB(49, 24), + new ECB(10, 25)), + new ECBlocks(30, new ECB(24, 15), + new ECB(46, 16))))); + VERSIONS.push_back(Ref(new Version(38, intArray(7, 6, 32, 58, 84, + 110, 136, 162), + new ECBlocks(30, new ECB(4, 122), + new ECB(18, 123)), + new ECBlocks(28, new ECB(13, 46), + new ECB(32, 47)), + new ECBlocks(30, new ECB(48, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(42, 15), + new ECB(32, 16))))); + VERSIONS.push_back(Ref(new Version(39, intArray(7, 6, 26, 54, 82, + 110, 138, 166), + new ECBlocks(30, new ECB(20, 117), + new ECB(4, 118)), + new ECBlocks(28, new ECB(40, 47), + new ECB(7, 48)), + new ECBlocks(30, new ECB(43, 24), + new ECB(22, 25)), + new ECBlocks(30, new ECB(10, 15), + new ECB(67, 16))))); + VERSIONS.push_back(Ref(new Version(40, intArray(7, 6, 30, 58, 86, + 114, 142, 170), + new ECBlocks(30, new ECB(19, 118), + new ECB(6, 119)), + new ECBlocks(28, new ECB(18, 47), + new ECB(31, 48)), + new ECBlocks(30, new ECB(34, 24), + new ECB(34, 25)), + new ECBlocks(30, new ECB(20, 15), + new ECB(61, 16))))); + return VERSIONS.size(); +} +} +} + +// file: zxing/qrcode/decoder/BitMatrixParser.cpp + +/* + * BitMatrixParser.cpp + * zxing + * + * Created by Christian Brunschen on 20/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 +// #include + + +namespace zxing { +namespace qrcode { + +int BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) { + return bitMatrix_->get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1; +} + +BitMatrixParser::BitMatrixParser(Ref bitMatrix) : + bitMatrix_(bitMatrix), parsedVersion_(0), parsedFormatInfo_() { + size_t dimension = bitMatrix->getDimension(); + if ((dimension < 21) || (dimension & 0x03) != 1) { + throw ReaderException("Dimension must be 1 mod 4 and >= 21"); + } +} + +Ref BitMatrixParser::readFormatInformation() { + if (parsedFormatInfo_ != 0) { + return parsedFormatInfo_; + } + + // Read top-left format info bits + int formatInfoBits1 = 0; + for (int i = 0; i < 6; i++) { + formatInfoBits1 = copyBit(i, 8, formatInfoBits1); + } + // .. and skip a bit in the timing pattern ... + formatInfoBits1 = copyBit(7, 8, formatInfoBits1); + formatInfoBits1 = copyBit(8, 8, formatInfoBits1); + formatInfoBits1 = copyBit(8, 7, formatInfoBits1); + // .. and skip a bit in the timing pattern ... + for (int j = 5; j >= 0; j--) { + formatInfoBits1 = copyBit(8, j, formatInfoBits1); + } + + // Read the top-right/bottom-left pattern + int dimension = bitMatrix_->getDimension(); + int formatInfoBits2 = 0; + int jMin = dimension - 7; + for (int j = dimension - 1; j >= jMin; j--) { + formatInfoBits2 = copyBit(8, j, formatInfoBits2); + } + for (int i = dimension - 8; i < dimension; i++) { + formatInfoBits2 = copyBit(i, 8, formatInfoBits2); + } + + parsedFormatInfo_ = FormatInformation::decodeFormatInformation(formatInfoBits1,formatInfoBits2); + if (parsedFormatInfo_ != 0) { + return parsedFormatInfo_; + } + throw ReaderException("Could not decode format information"); +} + +Version *BitMatrixParser::readVersion() { + if (parsedVersion_ != 0) { + return parsedVersion_; + } + + int dimension = bitMatrix_->getDimension(); + + int provisionalVersion = (dimension - 17) >> 2; + if (provisionalVersion <= 6) { + return Version::getVersionForNumber(provisionalVersion); + } + + // Read top-right version info: 3 wide by 6 tall + int versionBits = 0; + for (int y = 5; y >= 0; y--) { + int xMin = dimension - 11; + for (int x = dimension - 9; x >= xMin; x--) { + versionBits = copyBit(x, y, versionBits); + } + } + + parsedVersion_ = Version::decodeVersionInformation(versionBits); + if (parsedVersion_ != 0 && parsedVersion_->getDimensionForVersion() == dimension) { + return parsedVersion_; + } + + // Hmm, failed. Try bottom left: 6 wide by 3 tall + versionBits = 0; + for (int x = 5; x >= 0; x--) { + int yMin = dimension - 11; + for (int y = dimension - 9; y >= yMin; y--) { + versionBits = copyBit(x, y, versionBits); + } + } + + parsedVersion_ = Version::decodeVersionInformation(versionBits); + if (parsedVersion_ != 0 && parsedVersion_->getDimensionForVersion() == dimension) { + return parsedVersion_; + } + throw ReaderException("Could not decode version"); +} + +ArrayRef BitMatrixParser::readCodewords() { + Ref formatInfo = readFormatInformation(); + Version *version = readVersion(); + + + // cerr << *bitMatrix_ << endl; + // cerr << bitMatrix_->getDimension() << endl; + + // Get the data mask for the format used in this QR Code. This will exclude + // some bits from reading as we wind through the bit matrix. + DataMask &dataMask = DataMask::forReference((int)formatInfo->getDataMask()); + // cout << (int)formatInfo->getDataMask() << endl; + int dimension = bitMatrix_->getDimension(); + dataMask.unmaskBitMatrix(*bitMatrix_, dimension); + + + // cerr << *bitMatrix_ << endl; + // cerr << version->getTotalCodewords() << endl; + + Ref functionPattern = version->buildFunctionPattern(); + + + // cout << *functionPattern << endl; + + bool readingUp = true; + ArrayRef result(version->getTotalCodewords()); + int resultOffset = 0; + int currentByte = 0; + int bitsRead = 0; + // Read columns in pairs, from right to left + for (int x = dimension - 1; x > 0; x -= 2) { + if (x == 6) { + // Skip whole column with vertical alignment pattern; + // saves time and makes the other code proceed more cleanly + x--; + } + // Read alternatingly from bottom to top then top to bottom + for (int counter = 0; counter < dimension; counter++) { + int y = readingUp ? dimension - 1 - counter : counter; + for (int col = 0; col < 2; col++) { + // Ignore bits covered by the function pattern + if (!functionPattern->get(x - col, y)) { + // Read a bit + bitsRead++; + currentByte <<= 1; + if (bitMatrix_->get(x - col, y)) { + currentByte |= 1; + } + // If we've made a whole byte, save it off + if (bitsRead == 8) { + result[resultOffset++] = (unsigned char)currentByte; + bitsRead = 0; + currentByte = 0; + } + } + } + } + readingUp = !readingUp; // switch directions + } + + if (resultOffset != version->getTotalCodewords()) { + throw ReaderException("Did not read all codewords"); + } + return result; +} + +} +} + +// file: zxing/qrcode/decoder/DataBlock.cpp + +/* + * DataBlock.cpp + * zxing + * + * Created by Christian Brunschen on 19/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 +// #include + +namespace zxing { +namespace qrcode { + +using namespace std; + +DataBlock::DataBlock(int numDataCodewords, ArrayRef codewords) : + numDataCodewords_(numDataCodewords), codewords_(codewords) { +} + +int DataBlock::getNumDataCodewords() { + return numDataCodewords_; +} + +ArrayRef DataBlock::getCodewords() { + return codewords_; +} + + +std::vector > DataBlock::getDataBlocks(ArrayRef rawCodewords, Version *version, + ErrorCorrectionLevel &ecLevel) { + + + // Figure out the number and size of data blocks used by this version and + // error correction level + ECBlocks &ecBlocks = version->getECBlocksForLevel(ecLevel); + + + // First count the total number of data blocks + int totalBlocks = 0; + vector ecBlockArray = ecBlocks.getECBlocks(); + for (size_t i = 0; i < ecBlockArray.size(); i++) { + totalBlocks += ecBlockArray[i]->getCount(); + } + + // Now establish DataBlocks of the appropriate size and number of data codewords + std::vector > result(totalBlocks); + int numResultBlocks = 0; + for (size_t j = 0; j < ecBlockArray.size(); j++) { + ECB *ecBlock = ecBlockArray[j]; + for (int i = 0; i < ecBlock->getCount(); i++) { + int numDataCodewords = ecBlock->getDataCodewords(); + int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords; + ArrayRef buffer(numBlockCodewords); + Ref blockRef(new DataBlock(numDataCodewords, buffer)); + result[numResultBlocks++] = blockRef; + } + } + + // All blocks have the same amount of data, except that the last n + // (where n may be 0) have 1 more byte. Figure out where these start. + int shorterBlocksTotalCodewords = result[0]->codewords_.size(); + int longerBlocksStartAt = result.size() - 1; + while (longerBlocksStartAt >= 0) { + int numCodewords = result[longerBlocksStartAt]->codewords_.size(); + if (numCodewords == shorterBlocksTotalCodewords) { + break; + } + if (numCodewords != shorterBlocksTotalCodewords + 1) { + throw IllegalArgumentException("Data block sizes differ by more than 1"); + } + longerBlocksStartAt--; + } + longerBlocksStartAt++; + + int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewords(); + // The last elements of result may be 1 element longer; + // first fill out as many elements as all of them have + int rawCodewordsOffset = 0; + for (int i = 0; i < shorterBlocksNumDataCodewords; i++) { + for (int j = 0; j < numResultBlocks; j++) { + result[j]->codewords_[i] = rawCodewords[rawCodewordsOffset++]; + } + } + // Fill out the last data block in the longer ones + for (int j = longerBlocksStartAt; j < numResultBlocks; j++) { + result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; + } + // Now add in error correction blocks + int max = result[0]->codewords_.size(); + for (int i = shorterBlocksNumDataCodewords; i < max; i++) { + for (int j = 0; j < numResultBlocks; j++) { + int iOffset = j < longerBlocksStartAt ? i : i + 1; + result[j]->codewords_[iOffset] = rawCodewords[rawCodewordsOffset++]; + } + } + + if ((size_t)rawCodewordsOffset != rawCodewords.size()) { + throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length"); + } + + return result; +} + +} +} + +// file: zxing/qrcode/decoder/DataMask.cpp + +/* + * DataMask.cpp + * zxing + * + * Created by Christian Brunschen on 19/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 + +// #include + +namespace zxing { +namespace qrcode { + +using namespace std; + +DataMask::DataMask() { +} + +DataMask::~DataMask() { +} + +vector > DataMask::DATA_MASKS; +static int N_DATA_MASKS = DataMask::buildDataMasks(); + +DataMask &DataMask::forReference(int reference) { + if (reference < 0 || reference > 7) { + throw IllegalArgumentException("reference must be between 0 and 7"); + } + return *DATA_MASKS[reference]; +} + +void DataMask::unmaskBitMatrix(BitMatrix& bits, size_t dimension) { + for (size_t y = 0; y < dimension; y++) { + for (size_t x = 0; x < dimension; x++) { + // TODO: check why the coordinates have to be swapped + if (isMasked(y, x)) { + bits.flip(x, y); + } + } + } +} + +/** + * 000: mask bits for which (x + y) mod 2 == 0 + */ +class DataMask000 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + // return ((x + y) & 0x01) == 0; + return ((x + y) % 2) == 0; + } +}; + +/** + * 001: mask bits for which x mod 2 == 0 + */ +class DataMask001 : public DataMask { +public: + bool isMasked(size_t x, size_t) { + // return (x & 0x01) == 0; + return (x % 2) == 0; + } +}; + +/** + * 010: mask bits for which y mod 3 == 0 + */ +class DataMask010 : public DataMask { +public: + bool isMasked(size_t, size_t y) { + return y % 3 == 0; + } +}; + +/** + * 011: mask bits for which (x + y) mod 3 == 0 + */ +class DataMask011 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + return (x + y) % 3 == 0; + } +}; + +/** + * 100: mask bits for which (x/2 + y/3) mod 2 == 0 + */ +class DataMask100 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + // return (((x >> 1) + (y / 3)) & 0x01) == 0; + return (((x >> 1) + (y / 3)) % 2) == 0; + } +}; + +/** + * 101: mask bits for which xy mod 2 + xy mod 3 == 0 + */ +class DataMask101 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + size_t temp = x * y; + // return (temp & 0x01) + (temp % 3) == 0; + return (temp % 2) + (temp % 3) == 0; + + } +}; + +/** + * 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0 + */ +class DataMask110 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + size_t temp = x * y; + // return (((temp & 0x01) + (temp % 3)) & 0x01) == 0; + return (((temp % 2) + (temp % 3)) % 2) == 0; + } +}; + +/** + * 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0 + */ +class DataMask111 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + // return ((((x + y) & 0x01) + ((x * y) % 3)) & 0x01) == 0; + return ((((x + y) % 2) + ((x * y) % 3)) % 2) == 0; + } +}; + +int DataMask::buildDataMasks() { + DATA_MASKS.push_back(Ref (new DataMask000())); + DATA_MASKS.push_back(Ref (new DataMask001())); + DATA_MASKS.push_back(Ref (new DataMask010())); + DATA_MASKS.push_back(Ref (new DataMask011())); + DATA_MASKS.push_back(Ref (new DataMask100())); + DATA_MASKS.push_back(Ref (new DataMask101())); + DATA_MASKS.push_back(Ref (new DataMask110())); + DATA_MASKS.push_back(Ref (new DataMask111())); + return DATA_MASKS.size(); +} + +} +} + +// file: zxing/qrcode/decoder/DecodedBitStreamParser.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * DecodedBitStreamParser.cpp + * zxing + * + * Created by Christian Brunschen on 20/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 +// #include +// #include +// #include +// #include +#ifndef NO_ICONV +// #include +#endif + +// Required for compatibility. TODO: test on Symbian +#ifdef ZXING_ICONV_CONST +#undef ICONV_CONST +#define ICONV_CONST const +#endif + +#ifndef ICONV_CONST +#define ICONV_CONST /**/ +#endif + +using namespace std; +using namespace zxing; +using namespace zxing::qrcode; +using namespace zxing::common; + +const char DecodedBitStreamParser::ALPHANUMERIC_CHARS[] = +{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':' +}; + +namespace {int GB2312_SUBSET = 1;} + +void DecodedBitStreamParser::append(std::string &result, + string const& in, + const char *src) { + append(result, (unsigned char const*)in.c_str(), in.length(), src); +} + +void DecodedBitStreamParser::append(std::string &result, + const unsigned char *bufIn, + size_t nIn, + const char *src) { +#ifndef NO_ICONV + if (nIn == 0) { + return; + } + + iconv_t cd = iconv_open(StringUtils::UTF8, src); + if (cd == (iconv_t)-1) { + result.append((const char *)bufIn, nIn); + return; + } + + const int maxOut = 4 * nIn + 1; + unsigned char* bufOut = new unsigned char[maxOut]; + + ICONV_CONST char *fromPtr = (ICONV_CONST char *)bufIn; + size_t nFrom = nIn; + char *toPtr = (char *)bufOut; + size_t nTo = maxOut; + + while (nFrom > 0) { + size_t oneway = iconv(cd, &fromPtr, &nFrom, &toPtr, &nTo); + if (oneway == (size_t)(-1)) { + iconv_close(cd); + delete[] bufOut; + throw ReaderException("error converting characters"); + } + } + iconv_close(cd); + + int nResult = maxOut - nTo; + bufOut[nResult] = '\0'; + result.append((const char *)bufOut); + delete[] bufOut; +#else + result.append((const char *)bufIn, nIn); +#endif +} + +void DecodedBitStreamParser::decodeHanziSegment(Ref bits_, + string& result, + int count) { + BitSource& bits (*bits_); + // Don't crash trying to read more bits than we have available. + if (count * 13 > bits.available()) { + throw FormatException(); + } + + // Each character will require 2 bytes. Read the characters as 2-byte pairs + // and decode as GB2312 afterwards + size_t nBytes = 2 * count; + unsigned char* buffer = new unsigned char[nBytes]; + int offset = 0; + while (count > 0) { + // Each 13 bits encodes a 2-byte character + int twoBytes = bits.readBits(13); + int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060); + if (assembledTwoBytes < 0x003BF) { + // In the 0xA1A1 to 0xAAFE range + assembledTwoBytes += 0x0A1A1; + } else { + // In the 0xB0A1 to 0xFAFE range + assembledTwoBytes += 0x0A6A1; + } + buffer[offset] = (unsigned char) ((assembledTwoBytes >> 8) & 0xFF); + buffer[offset + 1] = (unsigned char) (assembledTwoBytes & 0xFF); + offset += 2; + count--; + } + + try { + append(result, buffer, nBytes, StringUtils::GB2312); + } catch (ReaderException const& re) { + delete [] buffer; + throw FormatException(); + } + + delete [] buffer; + } + +void DecodedBitStreamParser::decodeKanjiSegment(Ref bits, std::string &result, int count) { + // Each character will require 2 bytes. Read the characters as 2-byte pairs + // and decode as Shift_JIS afterwards + size_t nBytes = 2 * count; + unsigned char* buffer = new unsigned char[nBytes]; + int offset = 0; + while (count > 0) { + // Each 13 bits encodes a 2-byte character + + int twoBytes = bits->readBits(13); + int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0); + if (assembledTwoBytes < 0x01F00) { + // In the 0x8140 to 0x9FFC range + assembledTwoBytes += 0x08140; + } else { + // In the 0xE040 to 0xEBBF range + assembledTwoBytes += 0x0C140; + } + buffer[offset] = (unsigned char)(assembledTwoBytes >> 8); + buffer[offset + 1] = (unsigned char)assembledTwoBytes; + offset += 2; + count--; + } + + append(result, buffer, nBytes, StringUtils::SHIFT_JIS); + delete[] buffer; +} + +void DecodedBitStreamParser::decodeByteSegment(Ref bits_, + string& result, + int count, + CharacterSetECI* currentCharacterSetECI, + ArrayRef< ArrayRef >& byteSegments, + Hashtable const& hints) { + int nBytes = count; + BitSource& bits (*bits_); + // Don't crash trying to read more bits than we have available. + if (count << 3 > bits.available()) { + throw FormatException(); + } + + ArrayRef bytes_ (count); + unsigned char* readBytes = &(*bytes_)[0]; + for (int i = 0; i < count; i++) { + readBytes[i] = (unsigned char) bits.readBits(8); + } + string encoding; + if (currentCharacterSetECI == 0) { + // The spec isn't clear on this mode; see + // section 6.4.5: t does not say which encoding to assuming + // upon decoding. I have seen ISO-8859-1 used as well as + // Shift_JIS -- without anything like an ECI designator to + // give a hint. + encoding = StringUtils::guessEncoding(readBytes, count, hints); + } else { + encoding = currentCharacterSetECI->getEncodingName(); + } + try { + append(result, readBytes, nBytes, encoding.c_str()); + } catch (ReaderException const& re) { + throw FormatException(); + } + byteSegments->values().push_back(bytes_); +} + +void DecodedBitStreamParser::decodeNumericSegment(Ref bits, std::string &result, int count) { + int nBytes = count; + unsigned char* bytes = new unsigned char[nBytes]; + int i = 0; + // Read three digits at a time + while (count >= 3) { + // Each 10 bits encodes three digits + if (bits->available() < 10) { + throw ReaderException("format exception"); + } + int threeDigitsBits = bits->readBits(10); + if (threeDigitsBits >= 1000) { + ostringstream s; + s << "Illegal value for 3-digit unit: " << threeDigitsBits; + delete[] bytes; + throw ReaderException(s.str().c_str()); + } + bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits / 100]; + bytes[i++] = ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10]; + bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits % 10]; + count -= 3; + } + if (count == 2) { + if (bits->available() < 7) { + throw ReaderException("format exception"); + } + // Two digits left over to read, encoded in 7 bits + int twoDigitsBits = bits->readBits(7); + if (twoDigitsBits >= 100) { + ostringstream s; + s << "Illegal value for 2-digit unit: " << twoDigitsBits; + delete[] bytes; + throw ReaderException(s.str().c_str()); + } + bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits / 10]; + bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits % 10]; + } else if (count == 1) { + if (bits->available() < 4) { + throw ReaderException("format exception"); + } + // One digit left over to read + int digitBits = bits->readBits(4); + if (digitBits >= 10) { + ostringstream s; + s << "Illegal value for digit unit: " << digitBits; + delete[] bytes; + throw ReaderException(s.str().c_str()); + } + bytes[i++] = ALPHANUMERIC_CHARS[digitBits]; + } + append(result, bytes, nBytes, StringUtils::ASCII); + delete[] bytes; +} + +char DecodedBitStreamParser::toAlphaNumericChar(size_t value) { + if (value >= sizeof(DecodedBitStreamParser::ALPHANUMERIC_CHARS)) { + throw FormatException(); + } + return ALPHANUMERIC_CHARS[value]; +} + +void DecodedBitStreamParser::decodeAlphanumericSegment(Ref bits_, + string& result, + int count, + bool fc1InEffect) { + BitSource& bits (*bits_); + ostringstream bytes; + // Read two characters at a time + while (count > 1) { + int nextTwoCharsBits = bits.readBits(11); + bytes << toAlphaNumericChar(nextTwoCharsBits / 45); + bytes << toAlphaNumericChar(nextTwoCharsBits % 45); + count -= 2; + } + if (count == 1) { + // special case: one character left + bytes << toAlphaNumericChar(bits.readBits(6)); + } + // See section 6.4.8.1, 6.4.8.2 + string s = bytes.str(); + if (fc1InEffect) { + // We need to massage the result a bit if in an FNC1 mode: + ostringstream r; + for (size_t i = 0; i < s.length(); i++) { + if (s[i] != '%') { + r << s[i]; + } else { + if (i < s.length() - 1 && s[i + 1] == '%') { + // %% is rendered as % + r << s[i++]; + } else { + // In alpha mode, % should be converted to FNC1 separator 0x1D + r << (char)0x1D; + } + } + } + s = r.str(); + } + append(result, s, StringUtils::ASCII); +} + +namespace { + int parseECIValue(BitSource bits) { + int firstByte = bits.readBits(8); + if ((firstByte & 0x80) == 0) { + // just one byte + return firstByte & 0x7F; + } + if ((firstByte & 0xC0) == 0x80) { + // two bytes + int secondByte = bits.readBits(8); + return ((firstByte & 0x3F) << 8) | secondByte; + } + if ((firstByte & 0xE0) == 0xC0) { + // three bytes + int secondThirdBytes = bits.readBits(16); + return ((firstByte & 0x1F) << 16) | secondThirdBytes; + } + throw IllegalArgumentException("Bad ECI bits starting with byte "); + } +} + +Ref +DecodedBitStreamParser::decode(ArrayRef bytes, + Version* version, + ErrorCorrectionLevel const& ecLevel, + Hashtable const& hints) { + Ref bits_ (new BitSource(bytes)); + BitSource& bits (*bits_); + string result; + CharacterSetECI* currentCharacterSetECI = 0; + bool fc1InEffect = false; + ArrayRef< ArrayRef > byteSegments (size_t(0)); + Mode* mode = 0; + do { + // While still another segment to read... + if (bits.available() < 4) { + // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here + mode = &Mode::TERMINATOR; + } else { + try { + mode = &Mode::forBits(bits.readBits(4)); // mode is encoded by 4 bits + } catch (IllegalArgumentException const& iae) { + throw iae; + // throw FormatException.getFormatInstance(); + } + } + if (mode != &Mode::TERMINATOR) { + if ((mode == &Mode::FNC1_FIRST_POSITION) || (mode == &Mode::FNC1_SECOND_POSITION)) { + // We do little with FNC1 except alter the parsed result a bit according to the spec + fc1InEffect = true; + } else if (mode == &Mode::STRUCTURED_APPEND) { + // not really supported; all we do is ignore it + // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue + bits.readBits(16); + } else if (mode == &Mode::ECI) { + // Count doesn't apply to ECI + int value = parseECIValue(bits); + currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue(value); + if (currentCharacterSetECI == 0) { + throw FormatException(); + } + } else { + // First handle Hanzi mode which does not start with character count + if (mode == &Mode::HANZI) { + //chinese mode contains a sub set indicator right after mode indicator + int subset = bits.readBits(4); + int countHanzi = bits.readBits(mode->getCharacterCountBits(version)); + if (subset == GB2312_SUBSET) { + decodeHanziSegment(bits_, result, countHanzi); + } + } else { + // "Normal" QR code modes: + // How many characters will follow, encoded in this mode? + int count = bits.readBits(mode->getCharacterCountBits(version)); + if (mode == &Mode::NUMERIC) { + decodeNumericSegment(bits_, result, count); + } else if (mode == &Mode::ALPHANUMERIC) { + decodeAlphanumericSegment(bits_, result, count, fc1InEffect); + } else if (mode == &Mode::BYTE) { + decodeByteSegment(bits_, result, count, currentCharacterSetECI, byteSegments, hints); + } else if (mode == &Mode::KANJI) { + decodeKanjiSegment(bits_, result, count); + } else { + throw FormatException(); + } + } + } + } + } while (mode != &Mode::TERMINATOR); + + return Ref(new DecoderResult(bytes, Ref(new String(result)), byteSegments, (string)ecLevel)); +} + + +// file: zxing/qrcode/decoder/Decoder.cpp + +/* + * Decoder.cpp + * zxing + * + * Created by Christian Brunschen on 20/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 +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +using namespace std; + +Decoder::Decoder() : + rsDecoder_(GF256::QR_CODE_FIELD) { +} + +void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCodewords) { + int numCodewords = codewordBytes->size(); + ArrayRef codewordInts(numCodewords); + for (int i = 0; i < numCodewords; i++) { + codewordInts[i] = codewordBytes[i] & 0xff; + } + int numECCodewords = numCodewords - numDataCodewords; + + try { + rsDecoder_.decode(codewordInts, numECCodewords); + } catch (ReedSolomonException const& ex) { + ReaderException rex(ex.what()); + throw rex; + } + + for (int i = 0; i < numDataCodewords; i++) { + codewordBytes[i] = (unsigned char)codewordInts[i]; + } +} + +Ref Decoder::decode(Ref bits) { + // Construct a parser and read version, error-correction level + BitMatrixParser parser(bits); + + Version *version = parser.readVersion(); + ErrorCorrectionLevel &ecLevel = parser.readFormatInformation()->getErrorCorrectionLevel(); + + + // Read codewords + ArrayRef codewords(parser.readCodewords()); + + + // Separate into data blocks + std::vector > dataBlocks(DataBlock::getDataBlocks(codewords, version, ecLevel)); + + + // Count total number of data bytes + int totalBytes = 0; + for (size_t i = 0; i < dataBlocks.size(); i++) { + totalBytes += dataBlocks[i]->getNumDataCodewords(); + } + ArrayRef resultBytes(totalBytes); + int resultOffset = 0; + + + // Error-correct and copy data blocks together into a stream of bytes + for (size_t j = 0; j < dataBlocks.size(); j++) { + Ref dataBlock(dataBlocks[j]); + ArrayRef codewordBytes = dataBlock->getCodewords(); + int numDataCodewords = dataBlock->getNumDataCodewords(); + correctErrors(codewordBytes, numDataCodewords); + for (int i = 0; i < numDataCodewords; i++) { + resultBytes[resultOffset++] = codewordBytes[i]; + } + } + + return DecodedBitStreamParser::decode(resultBytes, + version, + ecLevel, + DecodedBitStreamParser::Hashtable()); +} + +} +} + +// file: zxing/qrcode/decoder/Mode.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Mode.cpp + * zxing + * + * Created by Christian Brunschen on 19/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 +// #include +// #include +// #include +// #include + +using zxing::qrcode::Mode; +using std::ostringstream; + +Mode Mode::TERMINATOR(0, 0, 0, 0x00, "TERMINATOR"); +Mode Mode::NUMERIC(10, 12, 14, 0x01, "NUMERIC"); +Mode Mode::ALPHANUMERIC(9, 11, 13, 0x02, "ALPHANUMERIC"); +Mode Mode::STRUCTURED_APPEND(0, 0, 0, 0x03, "STRUCTURED_APPEND"); +Mode Mode::BYTE(8, 16, 16, 0x04, "BYTE"); +Mode Mode::ECI(0, 0, 0, 0x07, "ECI"); +Mode Mode::KANJI(8, 10, 12, 0x08, "KANJI"); +Mode Mode::FNC1_FIRST_POSITION(0, 0, 0, 0x05, "FNC1_FIRST_POSITION"); +Mode Mode::FNC1_SECOND_POSITION(0, 0, 0, 0x09, "FNC1_SECOND_POSITION"); +Mode Mode::HANZI(8, 10, 12, 0x0D, "HANZI"); + +Mode::Mode(int cbv0_9, int cbv10_26, int cbv27, int bits, char const* name) : + characterCountBitsForVersions0To9_(cbv0_9), characterCountBitsForVersions10To26_(cbv10_26), + characterCountBitsForVersions27AndHigher_(cbv27), bits_(bits), name_(name) { +} + +Mode& Mode::forBits(int bits) { + switch (bits) { + case 0x0: + return TERMINATOR; + case 0x1: + return NUMERIC; + case 0x2: + return ALPHANUMERIC; + case 0x3: + return STRUCTURED_APPEND; + case 0x4: + return BYTE; + case 0x5: + return FNC1_FIRST_POSITION; + case 0x7: + return ECI; + case 0x8: + return KANJI; + case 0x9: + return FNC1_SECOND_POSITION; + case 0xD: + // 0xD is defined in GBT 18284-2000, may not be supported in foreign country + return HANZI; + default: + ostringstream s; + s << "Illegal mode bits: " << bits; + throw ReaderException(s.str().c_str()); + } +} + +int Mode::getCharacterCountBits(Version *version) { + int number = version->getVersionNumber(); + if (number <= 9) { + return characterCountBitsForVersions0To9_; + } else if (number <= 26) { + return characterCountBitsForVersions10To26_; + } else { + return characterCountBitsForVersions27AndHigher_; + } +} + +// file: zxing/qrcode/detector/AlignmentPattern.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * AlignmentPattern.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 + +namespace zxing { +namespace qrcode { + +using namespace std; + +AlignmentPattern::AlignmentPattern(float posX, float posY, float estimatedModuleSize) : + ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize) { +} + +bool AlignmentPattern::aboutEquals(float moduleSize, float i, float j) const { + if (abs(i - getY()) <= moduleSize && abs(j - getX()) <= moduleSize) { + float moduleSizeDiff = abs(moduleSize - estimatedModuleSize_); + return moduleSizeDiff <= 1.0f || moduleSizeDiff <= estimatedModuleSize_; + } + return false; +} + +Ref AlignmentPattern::combineEstimate(float i, float j, float newModuleSize) const { + float combinedX = (getX() + j) / 2.0f; + float combinedY = (getY() + i) / 2.0f; + float combinedModuleSize = (estimatedModuleSize_ + newModuleSize) / 2.0f; + Ref result + (new AlignmentPattern(combinedX, combinedY, combinedModuleSize)); + return result; +} + +} +} + +// file: zxing/qrcode/detector/AlignmentPatternFinder.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * AlignmentPatternFinder.cpp + * zxing + * + * Created by Christian Brunschen on 14/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 "AlignmentPatternFinder.h" +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +using namespace std; + +float AlignmentPatternFinder::centerFromEnd(vector &stateCount, int end) { + return (float)(end - stateCount[2]) - stateCount[1] / 2.0f; +} + +bool AlignmentPatternFinder::foundPatternCross(vector &stateCount) { + float maxVariance = moduleSize_ / 2.0f; + for (size_t i = 0; i < 3; i++) { + if (abs(moduleSize_ - stateCount[i]) >= maxVariance) { + return false; + } + } + return true; +} + +float AlignmentPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int maxCount, + int originalStateCountTotal) { + int maxI = image_->getHeight(); + vector stateCount(3, 0); + + + // Start counting up from center + int i = startI; + while (i >= 0 && image_->get(centerJ, i) && stateCount[1] <= maxCount) { + stateCount[1]++; + i--; + } + // If already too many modules in this state or ran off the edge: + if (i < 0 || stateCount[1] > maxCount) { + return NAN; + } + while (i >= 0 && !image_->get(centerJ, i) && stateCount[0] <= maxCount) { + stateCount[0]++; + i--; + } + if (stateCount[0] > maxCount) { + return NAN; + } + + // Now also count down from center + i = startI + 1; + while (i < maxI && image_->get(centerJ, i) && stateCount[1] <= maxCount) { + stateCount[1]++; + i++; + } + if (i == maxI || stateCount[1] > maxCount) { + return NAN; + } + while (i < maxI && !image_->get(centerJ, i) && stateCount[2] <= maxCount) { + stateCount[2]++; + i++; + } + if (stateCount[2] > maxCount) { + return NAN; + } + + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; + if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { + return NAN; + } + + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : NAN; +} + +Ref AlignmentPatternFinder::handlePossibleCenter(vector &stateCount, size_t i, size_t j) { + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; + float centerJ = centerFromEnd(stateCount, j); + float centerI = crossCheckVertical(i, (int)centerJ, 2 * stateCount[1], stateCountTotal); + if (!isnan(centerI)) { + float estimatedModuleSize = (float)(stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f; + int max = possibleCenters_->size(); + for (int index = 0; index < max; index++) { + Ref center((*possibleCenters_)[index]); + // Look for about the same center and module size: + if (center->aboutEquals(estimatedModuleSize, centerI, centerJ)) { + return center->combineEstimate(centerI, centerJ, estimatedModuleSize); + } + } + AlignmentPattern *tmp = new AlignmentPattern(centerJ, centerI, estimatedModuleSize); + // Hadn't found this before; save it + tmp->retain(); + possibleCenters_->push_back(tmp); + if (callback_ != 0) { + callback_->foundPossibleResultPoint(*tmp); + } + } + Ref result; + return result; +} + +AlignmentPatternFinder::AlignmentPatternFinder(Ref image, size_t startX, size_t startY, size_t width, + size_t height, float moduleSize, + Refconst& callback) : + image_(image), possibleCenters_(new vector ()), startX_(startX), startY_(startY), + width_(width), height_(height), moduleSize_(moduleSize), callback_(callback) { +} + +AlignmentPatternFinder::~AlignmentPatternFinder() { + for (size_t i = 0; i < possibleCenters_->size(); i++) { + (*possibleCenters_)[i]->release(); + (*possibleCenters_)[i] = 0; + } + delete possibleCenters_; +} + +Ref AlignmentPatternFinder::find() { + size_t maxJ = startX_ + width_; + size_t middleI = startY_ + (height_ >> 1); + // Ref luminanceRow(new BitArray(width_)); + // We are looking for black/white/black modules in 1:1:1 ratio; + // this tracks the number of black/white/black modules seen so far + vector stateCount(3, 0); + for (size_t iGen = 0; iGen < height_; iGen++) { + // Search from middle outwards + size_t i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1)); + // image_->getBlackRow(i, luminanceRow, startX_, width_); + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + size_t j = startX_; + // Burn off leading white pixels before anything else; if we start in the middle of + // a white run, it doesn't make sense to count its length, since we don't know if the + // white run continued to the left of the start point + while (j < maxJ && !image_->get(j, i)) { + j++; + } + int currentState = 0; + while (j < maxJ) { + if (image_->get(j, i)) { + // Black pixel + if (currentState == 1) { // Counting black pixels + stateCount[currentState]++; + } else { // Counting white pixels + if (currentState == 2) { // A winner? + if (foundPatternCross(stateCount)) { // Yes + Ref confirmed(handlePossibleCenter(stateCount, i, j)); + if (confirmed != 0) { + return confirmed; + } + } + stateCount[0] = stateCount[2]; + stateCount[1] = 1; + stateCount[2] = 0; + currentState = 1; + } else { + stateCount[++currentState]++; + } + } + } else { // White pixel + if (currentState == 1) { // Counting black pixels + currentState++; + } + stateCount[currentState]++; + } + j++; + } + if (foundPatternCross(stateCount)) { + Ref confirmed(handlePossibleCenter(stateCount, i, maxJ)); + if (confirmed != 0) { + return confirmed; + } + } + + } + + // Hmm, nothing we saw was observed and confirmed twice. If we had + // any guess at all, return it. + if (possibleCenters_->size() > 0) { + Ref center((*possibleCenters_)[0]); + return center; + } + + throw zxing::ReaderException("Could not find alignment pattern"); +} + +} +} + +// file: zxing/qrcode/detector/Detector.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Detector.cpp + * zxing + * + * Created by Christian Brunschen on 14/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 +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +using namespace std; + +Detector::Detector(Ref image) : + image_(image) { +} + +Ref Detector::getImage() { + return image_; +} + +Ref Detector::detect(DecodeHints const& hints) { + callback_ = hints.getResultPointCallback(); + FinderPatternFinder finder(image_, hints.getResultPointCallback()); + Ref info(finder.find(hints)); + return processFinderPatternInfo(info); +} + +Ref Detector::processFinderPatternInfo(Ref info){ + Ref topLeft(info->getTopLeft()); + Ref topRight(info->getTopRight()); + Ref bottomLeft(info->getBottomLeft()); + + float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); + if (moduleSize < 1.0f) { + throw zxing::ReaderException("bad module size"); + } + int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); + Version *provisionalVersion = Version::getProvisionalVersionForDimension(dimension); + int modulesBetweenFPCenters = provisionalVersion->getDimensionForVersion() - 7; + + Ref alignmentPattern; + // Anything above version 1 has an alignment pattern + if (provisionalVersion->getAlignmentPatternCenters().size() > 0) { + + + // Guess where a "bottom right" finder pattern would have been + float bottomRightX = topRight->getX() - topLeft->getX() + bottomLeft->getX(); + float bottomRightY = topRight->getY() - topLeft->getY() + bottomLeft->getY(); + + + // Estimate that alignment pattern is closer by 3 modules + // from "bottom right" to known top left location + float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters; + int estAlignmentX = (int)(topLeft->getX() + correctionToTopLeft * (bottomRightX - topLeft->getX())); + int estAlignmentY = (int)(topLeft->getY() + correctionToTopLeft * (bottomRightY - topLeft->getY())); + + + // Kind of arbitrary -- expand search radius before giving up + for (int i = 4; i <= 16; i <<= 1) { + try { + alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); + break; + } catch (zxing::ReaderException const& re) { + // try next round + } + } + if (alignmentPattern == 0) { + // Try anyway + } + + } + + Ref transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); + Ref bits(sampleGrid(image_, dimension, transform)); + std::vector > points(alignmentPattern == 0 ? 3 : 4); + points[0].reset(bottomLeft); + points[1].reset(topLeft); + points[2].reset(topRight); + if (alignmentPattern != 0) { + points[3].reset(alignmentPattern); + } + + Ref result(new DetectorResult(bits, points, transform)); + return result; +} + +Ref Detector::createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension) { + + float dimMinusThree = (float)dimension - 3.5f; + float bottomRightX; + float bottomRightY; + float sourceBottomRightX; + float sourceBottomRightY; + if (alignmentPattern != 0) { + bottomRightX = alignmentPattern->getX(); + bottomRightY = alignmentPattern->getY(); + sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f; + } else { + // Don't have an alignment pattern, just make up the bottom-right point + bottomRightX = (topRight->getX() - topLeft->getX()) + bottomLeft->getX(); + bottomRightY = (topRight->getY() - topLeft->getY()) + bottomLeft->getY(); + sourceBottomRightX = sourceBottomRightY = dimMinusThree; + } + + Ref transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX, + sourceBottomRightY, 3.5f, dimMinusThree, topLeft->getX(), topLeft->getY(), topRight->getX(), + topRight->getY(), bottomRightX, bottomRightY, bottomLeft->getX(), bottomLeft->getY())); + + return transform; +} + +Ref Detector::sampleGrid(Ref image, int dimension, Ref transform) { + GridSampler &sampler = GridSampler::getInstance(); + return sampler.sampleGrid(image, dimension, transform); +} + +int Detector::computeDimension(Ref topLeft, Ref topRight, Ref bottomLeft, + float moduleSize) { + int tltrCentersDimension = int(FinderPatternFinder::distance(topLeft, topRight) / moduleSize + 0.5f); + int tlblCentersDimension = int(FinderPatternFinder::distance(topLeft, bottomLeft) / moduleSize + 0.5f); + int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; + switch (dimension & 0x03) { // mod 4 + case 0: + dimension++; + break; + // 1? do nothing + case 2: + dimension--; + break; + case 3: + ostringstream s; + s << "Bad dimension: " << dimension; + throw zxing::ReaderException(s.str().c_str()); + } + return dimension; +} + +float Detector::calculateModuleSize(Ref topLeft, Ref topRight, Ref bottomLeft) { + // Take the average + return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f; +} + +float Detector::calculateModuleSizeOneWay(Ref pattern, Ref otherPattern) { + float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern->getX(), (int)pattern->getY(), + (int)otherPattern->getX(), (int)otherPattern->getY()); + float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern->getX(), (int)otherPattern->getY(), + (int)pattern->getX(), (int)pattern->getY()); + if (isnan(moduleSizeEst1)) { + return moduleSizeEst2; + } + if (isnan(moduleSizeEst2)) { + return moduleSizeEst1; + } + // Average them, and divide by 7 since we've counted the width of 3 black modules, + // and 1 white and 1 black module on either side. Ergo, divide sum by 14. + return (moduleSizeEst1 + moduleSizeEst2) / 14.0f; +} + +float Detector::sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) { + + float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); + + // Now count other way -- don't run off image though of course + float scale = 1.0f; + int otherToX = fromX - (toX - fromX); + if (otherToX < 0) { + scale = (float) fromX / (float) (fromX - otherToX); + otherToX = 0; + } else if (otherToX >= (int)image_->getWidth()) { + scale = (float) (image_->getWidth() - 1 - fromX) / (float) (otherToX - fromX); + otherToX = image_->getWidth() - 1; + } + int otherToY = (int) (fromY - (toY - fromY) * scale); + + scale = 1.0f; + if (otherToY < 0) { + scale = (float) fromY / (float) (fromY - otherToY); + otherToY = 0; + } else if (otherToY >= (int)image_->getHeight()) { + scale = (float) (image_->getHeight() - 1 - fromY) / (float) (otherToY - fromY); + otherToY = image_->getHeight() - 1; + } + otherToX = (int) (fromX + (otherToX - fromX) * scale); + + result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); + + // Middle pixel is double-counted this way; subtract 1 + return result - 1.0f; +} + +float Detector::sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) { + // Mild variant of Bresenham's algorithm; + // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm + bool steep = abs(toY - fromY) > abs(toX - fromX); + if (steep) { + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + int dx = abs(toX - fromX); + int dy = abs(toY - fromY); + int error = -dx >> 1; + int xstep = fromX < toX ? 1 : -1; + int ystep = fromY < toY ? 1 : -1; + + // In black pixels, looking for white, first or second time. + int state = 0; + // Loop up until x == toX, but not beyond + int xLimit = toX + xstep; + for (int x = fromX, y = fromY; x != xLimit; x += xstep) { + int realX = steep ? y : x; + int realY = steep ? x : y; + + // Does current pixel mean we have moved white to black or vice versa? + if (!((state == 1) ^ image_->get(realX, realY))) { + if (state == 2) { + int diffX = x - fromX; + int diffY = y - fromY; + return (float) sqrt((double) (diffX * diffX + diffY * diffY)); + } + state++; + } + + error += dy; + if (error > 0) { + if (y == toY) { + break; + } + y += ystep; + error -= dx; + } + } + // Found black-white-black; give the benefit of the doubt that the next pixel outside the image + // is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a + // small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this. + if (state == 2) { + int diffX = toX + xstep - fromX; + int diffY = toY - fromY; + return (float) sqrt((double) (diffX * diffX + diffY * diffY)); + } + // else we didn't find even black-white-black; no estimate is really possible + return NAN; +} + +Ref Detector::findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, + float allowanceFactor) { + // Look for an alignment pattern (3 modules in size) around where it + // should be + int allowance = (int)(allowanceFactor * overallEstModuleSize); + int alignmentAreaLeftX = max(0, estAlignmentX - allowance); + int alignmentAreaRightX = min((int)(image_->getWidth() - 1), estAlignmentX + allowance); + if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) { + throw zxing::ReaderException("region too small to hold alignment pattern"); + } + int alignmentAreaTopY = max(0, estAlignmentY - allowance); + int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance); + if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) { + throw zxing::ReaderException("region too small to hold alignment pattern"); + } + + AlignmentPatternFinder alignmentFinder(image_, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX + - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, callback_); + return alignmentFinder.find(); +} + +} +} + +// file: zxing/qrcode/detector/FinderPattern.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * FinderPattern.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 + +namespace zxing { + namespace qrcode { + + using namespace std; + + FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize) : + ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(1) { + } + + FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize, int count) : + ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(count) { + } + + int FinderPattern::getCount() const { + return count_; + } + + float FinderPattern::getEstimatedModuleSize() const { + return estimatedModuleSize_; + } + + void FinderPattern::incrementCount() { + count_++; + } + +/* + bool FinderPattern::aboutEquals(float moduleSize, float i, float j) const { + return abs(i - posY_) <= moduleSize && abs(j - posX_) <= moduleSize && (abs(moduleSize - estimatedModuleSize_) + <= 1.0f || abs(moduleSize - estimatedModuleSize_) / estimatedModuleSize_ <= 0.1f); + } +*/ + bool FinderPattern::aboutEquals(float moduleSize, float i, float j) const { + if (abs(i - getY()) <= moduleSize && abs(j - getX()) <= moduleSize) { + float moduleSizeDiff = abs(moduleSize - estimatedModuleSize_); + return moduleSizeDiff <= 1.0f || moduleSizeDiff <= estimatedModuleSize_; + } + return false; + } + + Ref FinderPattern::combineEstimate(float i, float j, float newModuleSize) const { + int combinedCount = count_ + 1; + float combinedX = (count_ * getX() + j) / combinedCount; + float combinedY = (count_ * getY() + i) / combinedCount; + float combinedModuleSize = (count_ * getEstimatedModuleSize() + newModuleSize) / combinedCount; + return Ref(new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount)); + } + } +} + +// file: zxing/qrcode/detector/FinderPatternFinder.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * FinderPatternFinder.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 +// #include +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +using namespace std; + +class FurthestFromAverageComparator { +private: + const float averageModuleSize_; +public: + FurthestFromAverageComparator(float averageModuleSize) : + averageModuleSize_(averageModuleSize) { + } + bool operator()(Ref a, Ref b) { + float dA = abs(a->getEstimatedModuleSize() - averageModuleSize_); + float dB = abs(b->getEstimatedModuleSize() - averageModuleSize_); + return dA > dB; + } +}; + +class CenterComparator { + const float averageModuleSize_; +public: + CenterComparator(float averageModuleSize) : + averageModuleSize_(averageModuleSize) { + } + bool operator()(Ref a, Ref b) { + // N.B.: we want the result in descending order ... + if (a->getCount() != b->getCount()) { + return a->getCount() > b->getCount(); + } else { + float dA = abs(a->getEstimatedModuleSize() - averageModuleSize_); + float dB = abs(b->getEstimatedModuleSize() - averageModuleSize_); + return dA < dB; + } + } +}; + +int FinderPatternFinder::CENTER_QUORUM = 2; +int FinderPatternFinder::MIN_SKIP = 3; +int FinderPatternFinder::MAX_MODULES = 57; + +float FinderPatternFinder::centerFromEnd(int* stateCount, int end) { + return (float)(end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0f; +} + +bool FinderPatternFinder::foundPatternCross(int* stateCount) { + int totalModuleSize = 0; + for (int i = 0; i < 5; i++) { + if (stateCount[i] == 0) { + return false; + } + totalModuleSize += stateCount[i]; + } + if (totalModuleSize < 7) { + return false; + } + float moduleSize = (float)totalModuleSize / 7.0f; + float maxVariance = moduleSize / 2.0f; + // Allow less than 50% variance from 1-1-3-1-1 proportions + return abs(moduleSize - stateCount[0]) < maxVariance && abs(moduleSize - stateCount[1]) < maxVariance && abs(3.0f + * moduleSize - stateCount[2]) < 3.0f * maxVariance && abs(moduleSize - stateCount[3]) < maxVariance && abs( + moduleSize - stateCount[4]) < maxVariance; +} + +float FinderPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal) { + + int maxI = image_->getHeight(); + int stateCount[5]; + for (int i = 0; i < 5; i++) + stateCount[i] = 0; + + + // Start counting up from center + int i = startI; + while (i >= 0 && image_->get(centerJ, i)) { + stateCount[2]++; + i--; + } + if (i < 0) { + return NAN; + } + while (i >= 0 && !image_->get(centerJ, i) && stateCount[1] <= maxCount) { + stateCount[1]++; + i--; + } + // If already too many modules in this state or ran off the edge: + if (i < 0 || stateCount[1] > maxCount) { + return NAN; + } + while (i >= 0 && image_->get(centerJ, i) && stateCount[0] <= maxCount) { + stateCount[0]++; + i--; + } + if (stateCount[0] > maxCount) { + return NAN; + } + + // Now also count down from center + i = startI + 1; + while (i < maxI && image_->get(centerJ, i)) { + stateCount[2]++; + i++; + } + if (i == maxI) { + return NAN; + } + while (i < maxI && !image_->get(centerJ, i) && stateCount[3] < maxCount) { + stateCount[3]++; + i++; + } + if (i == maxI || stateCount[3] >= maxCount) { + return NAN; + } + while (i < maxI && image_->get(centerJ, i) && stateCount[4] < maxCount) { + stateCount[4]++; + i++; + } + if (stateCount[4] >= maxCount) { + return NAN; + } + + // If we found a finder-pattern-like section, but its size is more than 40% different than + // the original, assume it's a false positive + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { + return NAN; + } + + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : NAN; +} + +float FinderPatternFinder::crossCheckHorizontal(size_t startJ, size_t centerI, int maxCount, + int originalStateCountTotal) { + + int maxJ = image_->getWidth(); + int stateCount[5]; + for (int i = 0; i < 5; i++) + stateCount[i] = 0; + + int j = startJ; + while (j >= 0 && image_->get(j, centerI)) { + stateCount[2]++; + j--; + } + if (j < 0) { + return NAN; + } + while (j >= 0 && !image_->get(j, centerI) && stateCount[1] <= maxCount) { + stateCount[1]++; + j--; + } + if (j < 0 || stateCount[1] > maxCount) { + return NAN; + } + while (j >= 0 && image_->get(j, centerI) && stateCount[0] <= maxCount) { + stateCount[0]++; + j--; + } + if (stateCount[0] > maxCount) { + return NAN; + } + + j = startJ + 1; + while (j < maxJ && image_->get(j, centerI)) { + stateCount[2]++; + j++; + } + if (j == maxJ) { + return NAN; + } + while (j < maxJ && !image_->get(j, centerI) && stateCount[3] < maxCount) { + stateCount[3]++; + j++; + } + if (j == maxJ || stateCount[3] >= maxCount) { + return NAN; + } + while (j < maxJ && image_->get(j, centerI) && stateCount[4] < maxCount) { + stateCount[4]++; + j++; + } + if (stateCount[4] >= maxCount) { + return NAN; + } + + // If we found a finder-pattern-like section, but its size is significantly different than + // the original, assume it's a false positive + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + if (5 * abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { + return NAN; + } + + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : NAN; +} + +bool FinderPatternFinder::handlePossibleCenter(int* stateCount, size_t i, size_t j) { + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + float centerJ = centerFromEnd(stateCount, j); + float centerI = crossCheckVertical(i, (size_t)centerJ, stateCount[2], stateCountTotal); + if (!isnan(centerI)) { + // Re-cross check + centerJ = crossCheckHorizontal((size_t)centerJ, (size_t)centerI, stateCount[2], stateCountTotal); + if (!isnan(centerJ)) { + float estimatedModuleSize = (float)stateCountTotal / 7.0f; + bool found = false; + size_t max = possibleCenters_.size(); + for (size_t index = 0; index < max; index++) { + Ref center = possibleCenters_[index]; + // Look for about the same center and module size: + if (center->aboutEquals(estimatedModuleSize, centerI, centerJ)) { + possibleCenters_[index] = center->combineEstimate(centerI, centerJ, estimatedModuleSize); + found = true; + break; + } + } + if (!found) { + Ref newPattern(new FinderPattern(centerJ, centerI, estimatedModuleSize)); + possibleCenters_.push_back(newPattern); + if (callback_ != 0) { + callback_->foundPossibleResultPoint(*newPattern); + } + } + return true; + } + } + return false; +} + +int FinderPatternFinder::findRowSkip() { + size_t max = possibleCenters_.size(); + if (max <= 1) { + return 0; + } + Ref firstConfirmedCenter; + for (size_t i = 0; i < max; i++) { + Ref center = possibleCenters_[i]; + if (center->getCount() >= CENTER_QUORUM) { + if (firstConfirmedCenter == 0) { + firstConfirmedCenter = center; + } else { + // We have two confirmed centers + // How far down can we skip before resuming looking for the next + // pattern? In the worst case, only the difference between the + // difference in the x / y coordinates of the two centers. + // This is the case where you find top left first. Draw it out. + hasSkipped_ = true; + return (int)(abs(firstConfirmedCenter->getX() - center->getX()) - abs(firstConfirmedCenter->getY() + - center->getY()))/2; + } + } + } + return 0; +} + +bool FinderPatternFinder::haveMultiplyConfirmedCenters() { + int confirmedCount = 0; + float totalModuleSize = 0.0f; + size_t max = possibleCenters_.size(); + for (size_t i = 0; i < max; i++) { + Ref pattern = possibleCenters_[i]; + if (pattern->getCount() >= CENTER_QUORUM) { + confirmedCount++; + totalModuleSize += pattern->getEstimatedModuleSize(); + } + } + if (confirmedCount < 3) { + return false; + } + // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" + // and that we need to keep looking. We detect this by asking if the estimated module sizes + // vary too much. We arbitrarily say that when the total deviation from average exceeds + // 5% of the total module size estimates, it's too much. + float average = totalModuleSize / max; + float totalDeviation = 0.0f; + for (size_t i = 0; i < max; i++) { + Ref pattern = possibleCenters_[i]; + totalDeviation += abs(pattern->getEstimatedModuleSize() - average); + } + return totalDeviation <= 0.05f * totalModuleSize; +} + +vector > FinderPatternFinder::selectBestPatterns() { + size_t startSize = possibleCenters_.size(); + + if (startSize < 3) { + // Couldn't find enough finder patterns + throw zxing::ReaderException("Could not find three finder patterns"); + } + + // Filter outlier possibilities whose module size is too different + if (startSize > 3) { + // But we can only afford to do so if we have at least 4 possibilities to choose from + float totalModuleSize = 0.0f; + float square = 0.0f; + for (size_t i = 0; i < startSize; i++) { + float size = possibleCenters_[i]->getEstimatedModuleSize(); + totalModuleSize += size; + square += size * size; + } + float average = totalModuleSize / (float) startSize; + float stdDev = (float)sqrt(square / startSize - average * average); + + sort(possibleCenters_.begin(), possibleCenters_.end(), FurthestFromAverageComparator(average)); + + float limit = max(0.2f * average, stdDev); + + for (size_t i = 0; i < possibleCenters_.size() && possibleCenters_.size() > 3; i++) { + if (abs(possibleCenters_[i]->getEstimatedModuleSize() - average) > limit) { + possibleCenters_.erase(possibleCenters_.begin()+i); + i--; + } + } + } + + if (possibleCenters_.size() > 3) { + // Throw away all but those first size candidate points we found. + float totalModuleSize = 0.0f; + for (size_t i = 0; i < possibleCenters_.size(); i++) { + float size = possibleCenters_[i]->getEstimatedModuleSize(); + totalModuleSize += size; + } + float average = totalModuleSize / (float) possibleCenters_.size(); + sort(possibleCenters_.begin(), possibleCenters_.end(), CenterComparator(average)); + } + + if (possibleCenters_.size() > 3) { + possibleCenters_.erase(possibleCenters_.begin()+3,possibleCenters_.end()); + } + + vector > result(3); + result[0] = possibleCenters_[0]; + result[1] = possibleCenters_[1]; + result[2] = possibleCenters_[2]; + return result; +} + +vector > FinderPatternFinder::orderBestPatterns(vector > patterns) { + // Find distances between pattern centers + float abDistance = distance(patterns[0], patterns[1]); + float bcDistance = distance(patterns[1], patterns[2]); + float acDistance = distance(patterns[0], patterns[2]); + + Ref topLeft; + Ref topRight; + Ref bottomLeft; + // Assume one closest to other two is top left; + // topRight and bottomLeft will just be guesses below at first + if (bcDistance >= abDistance && bcDistance >= acDistance) { + topLeft = patterns[0]; + topRight = patterns[1]; + bottomLeft = patterns[2]; + } else if (acDistance >= bcDistance && acDistance >= abDistance) { + topLeft = patterns[1]; + topRight = patterns[0]; + bottomLeft = patterns[2]; + } else { + topLeft = patterns[2]; + topRight = patterns[0]; + bottomLeft = patterns[1]; + } + + // Use cross product to figure out which of other1/2 is the bottom left + // pattern. The vector "top-left -> bottom-left" x "top-left -> top-right" + // should yield a vector with positive z component + if ((bottomLeft->getY() - topLeft->getY()) * (topRight->getX() - topLeft->getX()) < (bottomLeft->getX() + - topLeft->getX()) * (topRight->getY() - topLeft->getY())) { + Ref temp = topRight; + topRight = bottomLeft; + bottomLeft = temp; + } + + vector > results(3); + results[0] = bottomLeft; + results[1] = topLeft; + results[2] = topRight; + return results; +} + +float FinderPatternFinder::distance(Ref p1, Ref p2) { + float dx = p1->getX() - p2->getX(); + float dy = p1->getY() - p2->getY(); + return (float)sqrt(dx * dx + dy * dy); +} + +FinderPatternFinder::FinderPatternFinder(Ref image, + Refconst& callback) : + image_(image), possibleCenters_(), hasSkipped_(false), callback_(callback) { +} + +Ref FinderPatternFinder::find(DecodeHints const& hints) { + bool tryHarder = hints.getTryHarder(); + + size_t maxI = image_->getHeight(); + size_t maxJ = image_->getWidth(); + + + // We are looking for black/white/black/white/black modules in + // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far + + // As this is used often, we use an integer array instead of vector + int stateCount[5]; + bool done = false; + + + // Let's assume that the maximum version QR Code we support takes up 1/4 + // the height of the image, and then account for the center being 3 + // modules in size. This gives the smallest number of pixels the center + // could be, so skip this often. When trying harder, look for all + // QR versions regardless of how dense they are. + int iSkip = (3 * maxI) / (4 * MAX_MODULES); + if (iSkip < MIN_SKIP || tryHarder) { + iSkip = MIN_SKIP; + } + + // This is slightly faster than using the Ref. Efficiency is important here + BitMatrix& matrix = *image_; + + for (size_t i = iSkip - 1; i < maxI && !done; i += iSkip) { + // Get a row of black/white values + + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + int currentState = 0; + for (size_t j = 0; j < maxJ; j++) { + if (matrix.get(j, i)) { + // Black pixel + if ((currentState & 1) == 1) { // Counting white pixels + currentState++; + } + stateCount[currentState]++; + } else { // White pixel + if ((currentState & 1) == 0) { // Counting black pixels + if (currentState == 4) { // A winner? + if (foundPatternCross(stateCount)) { // Yes + bool confirmed = handlePossibleCenter(stateCount, i, j); + if (confirmed) { + // Start examining every other line. Checking each line turned out to be too + // expensive and didn't improve performance. + iSkip = 2; + if (hasSkipped_) { + done = haveMultiplyConfirmedCenters(); + } else { + int rowSkip = findRowSkip(); + if (rowSkip > stateCount[2]) { + // Skip rows between row of lower confirmed center + // and top of presumed third confirmed center + // but back up a bit to get a full chance of detecting + // it, entire width of center of finder pattern + + // Skip by rowSkip, but back off by stateCount[2] (size + // of last center of pattern we saw) to be conservative, + // and also back off by iSkip which is about to be + // re-added + i += rowSkip - stateCount[2] - iSkip; + j = maxJ - 1; + } + } + } else { + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + continue; + } + // Clear state to start looking again + currentState = 0; + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + } else { // No, shift counts back by two + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + } + } else { + stateCount[++currentState]++; + } + } else { // Counting white pixels + stateCount[currentState]++; + } + } + } + if (foundPatternCross(stateCount)) { + bool confirmed = handlePossibleCenter(stateCount, i, maxJ); + if (confirmed) { + iSkip = stateCount[0]; + if (hasSkipped_) { + // Found a third one + done = haveMultiplyConfirmedCenters(); + } + } + } + } + + vector > patternInfo = selectBestPatterns(); + patternInfo = orderBestPatterns(patternInfo); + + Ref result(new FinderPatternInfo(patternInfo)); + return result; +} +} +} + +// file: zxing/qrcode/detector/FinderPatternInfo.cpp + +/* + * FinderPatternInfo.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 + +namespace zxing { +namespace qrcode { + +FinderPatternInfo::FinderPatternInfo(std::vector > patternCenters) : + bottomLeft_(patternCenters[0]), topLeft_(patternCenters[1]), topRight_(patternCenters[2]) { +} + +Ref FinderPatternInfo::getBottomLeft() { + return bottomLeft_; +} +Ref FinderPatternInfo::getTopLeft() { + return topLeft_; +} +Ref FinderPatternInfo::getTopRight() { + return topRight_; +} + +} +} + +// file: zxing/qrcode/detector/QREdgeDetector.cpp + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Created by Ralf Kistner on 7/12/2009. + * 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 +// #include +// #include + +using namespace std; + +namespace zxing { +namespace qrcode { + +static const float patternEdgeThreshold = 2; +static const int patternEdgeWidth = 3; +static const float patternEdgeSearchRatio = 1.1; +static const int patternEdgeSkip = 2; + +static const float accurateEdgeThreshold = 3.3; +static const int accurateEdgeWidth = 7; +static const int accurateEdgeSkip = 2; + +static Point guessLastPattern(Point topLeft, Point topRight, Point bottomLeft) { + return Point(topRight.x - topLeft.x + bottomLeft.x, topRight.y - topLeft.y + bottomLeft.y); +} + +static Point rp(Ref rp) { + return Point(rp->getX(), rp->getY()); +} + +QREdgeDetector::QREdgeDetector(Ref image) : Detector(image) { } + +Ref QREdgeDetector::createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension) { + + if(alignmentPattern == NULL) { + Point corner = findCorner(*Detector::getImage(), rp(topLeft), rp(topRight), rp(bottomLeft), dimension); + return get1CornerTransform(rp(topLeft), rp(topRight), rp(bottomLeft), corner, dimension); + } else { + return Detector::createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); + } +} + + + + +Point QREdgeDetector::findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension) { + (void)dimension; + Point bottomRight = guessLastPattern(topLeft, topRight, bottomLeft); + + Line bottomEst = findPatternEdge(image, bottomLeft, topLeft, bottomRight, false); + Line rightEst = findPatternEdge(image, topRight, topLeft, bottomRight, true); + + //return EdgeDetector::intersection(bottomEst, rightEst); + + Line bottom = EdgeDetector::findLine(image, bottomEst, false, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip); + Line right = EdgeDetector::findLine(image, rightEst, true, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip); + + + return EdgeDetector::intersection(bottom, right); +} + +Line QREdgeDetector::findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert) { + Point start = endOfReverseBlackWhiteBlackRun(image, pattern, opposite); + + float dx = pattern.x - start.x; + float dy = pattern.y - start.y; + float dist = sqrt(dx*dx + dy*dy); + + float dirX = direction.x - pattern.x; + float dirY = direction.y - pattern.y; + float dirSize = sqrt(dirX*dirX + dirY*dirY); + + float nx = dirX/dirSize; + float ny = dirY/dirSize; + + float search = dist * patternEdgeSearchRatio; + Point a(start.x + nx*search, start.y + ny*search); + Point b(start.x - nx*search, start.y - ny*search); + + return EdgeDetector::findLine(image, Line(a, b), invert, patternEdgeWidth, patternEdgeThreshold, patternEdgeSkip); +} + + +Ref QREdgeDetector::get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension) { + float dimMinusThree = (float) dimension - 3.5f; + + Ref transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, dimension, + dimension, 3.5f, dimMinusThree, topLeft.x, topLeft.y, topRight.x, + topRight.y, corner.x, corner.y, bottomLeft.x, bottomLeft.y)); + + return transform; +} + +// Adapted from "sizeOfBlackWhiteBlackRun" in zxing::qrcode::Detector +Point QREdgeDetector::endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to) { + int fromX = (int)from.x; + int fromY = (int)from.y; + int toX = (int)to.x; + int toY = (int)to.y; + + bool steep = abs(toY - fromY) > abs(toX - fromX); + if (steep) { + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + int dx = abs(toX - fromX); + int dy = abs(toY - fromY); + int error = -dx >> 1; + int ystep = fromY < toY ? -1 : 1; + int xstep = fromX < toX ? -1 : 1; + int state = 0; // In black pixels, looking for white, first or second time + + // In case there are no points, prepopulate to from + int realX = fromX; + int realY = fromY; + for (int x = fromX, y = fromY; x != toX; x += xstep) { + realX = steep ? y : x; + realY = steep ? x : y; + + if(realX < 0 || realY < 0 || realX >= (int)image.getWidth() || realY >= (int)image.getHeight()) + break; + + if (state == 1) { // In white pixels, looking for black + if (image.get(realX, realY)) { + state++; + } + } else { + if (!image.get(realX, realY)) { + state++; + } + } + + if (state == 3) { // Found black, white, black, and stumbled back onto white; done + return Point(realX, realY); + } + error += dy; + if (error > 0) { + y += ystep; + error -= dx; + } + } + + // B-W-B run not found, return the last point visited. + return Point(realX, realY); +} + +} // namespace qrcode +} // namespace zxing + diff --git a/plugins/phonegap-plugin-barcodescanner/src/ios/zxing-all-in-one.h b/plugins/phonegap-plugin-barcodescanner/src/ios/zxing-all-in-one.h new file mode 100644 index 0000000..2718ca9 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/ios/zxing-all-in-one.h @@ -0,0 +1,5007 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// file: zxing/Exception.h + +#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 +// #include + +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__ + +// file: zxing/common/IllegalArgumentException.h + +#ifndef __ILLEGAL_ARGUMENT_EXCEPTION_H__ +// #define __ILLEGAL_ARGUMENT_EXCEPTION_H__ + +/* + * IllegalArgumentException.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 + +namespace zxing { +class IllegalArgumentException : public zxing::Exception { +public: + IllegalArgumentException(const char *msg); + ~IllegalArgumentException() throw(); +}; +} + +#endif // __ILLEGAL_ARGUMENT_EXCEPTION_H__ + +// file: zxing/common/Counted.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __COUNTED_H__ +// #define __COUNTED_H__ + +/* + * 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. + */ + +//#define DEBUG_COUNTING + +// #include + +#ifdef DEBUG_COUNTING +// #include +#endif + +namespace zxing { + +/* base class for reference-counted objects */ +class Counted { +private: + unsigned int count_; +public: + Counted() : + count_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating " << typeid(*this).name() << " " << this << + " @ " << count_ << "\n"; +#endif + } + virtual ~Counted() { + } + Counted *retain() { +#ifdef DEBUG_COUNTING + cout << "retaining " << typeid(*this).name() << " " << this << + " @ " << count_; +#endif + count_++; +#ifdef DEBUG_COUNTING + cout << "->" << count_ << "\n"; +#endif + return this; + } + void release() { +#ifdef DEBUG_COUNTING + cout << "releasing " << typeid(*this).name() << " " << this << + " @ " << count_; +#endif + if (count_ == 0 || count_ == 54321) { +#ifdef DEBUG_COUNTING + cout << "\nOverreleasing already-deleted object " << this << "!!!\n"; +#endif + throw 4711; + } + count_--; +#ifdef DEBUG_COUNTING + cout << "->" << count_ << "\n"; +#endif + if (count_ == 0) { +#ifdef DEBUG_COUNTING + cout << "deleting " << typeid(*this).name() << " " << this << "\n"; +#endif + count_ = 0xDEADF001; + delete this; + } + } + + + /* return the current count for denugging purposes or similar */ + int count() const { + return count_; + } +}; + +/* counting reference to reference-counted objects */ +template class Ref { +private: +public: + T *object_; + explicit Ref(T *o = 0) : + object_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating Ref " << this << " from pointer" << o << "\n"; +#endif + reset(o); + } + + explicit Ref(const T &o) : + object_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating Ref " << this << " from reference\n"; +#endif + reset(const_cast(&o)); + } + + Ref(const Ref &other) : + object_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating Ref " << this << " from Ref " << &other << "\n"; +#endif + reset(other.object_); + } + + template + Ref(const Ref &other) : + object_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating Ref " << this << " from reference\n"; +#endif + reset(other.object_); + } + + ~Ref() { +#ifdef DEBUG_COUNTING + cout << "destroying Ref " << this << " with " << + (object_ ? typeid(*object_).name() : "NULL") << " " << object_ << "\n"; +#endif + if (object_) { + object_->release(); + } + } + + void reset(T *o) { +#ifdef DEBUG_COUNTING + cout << "resetting Ref " << this << " from " << + (object_ ? typeid(*object_).name() : "NULL") << " " << object_ << + " to " << (o ? typeid(*o).name() : "NULL") << " " << o << "\n"; +#endif + if (o) { + o->retain(); + } + if (object_ != 0) { + object_->release(); + } + object_ = o; + } + Ref& operator=(const Ref &other) { + reset(other.object_); + return *this; + } + template + Ref& operator=(const Ref &other) { + reset(other.object_); + return *this; + } + Ref& operator=(T* o) { + reset(o); + return *this; + } + template + Ref& operator=(Y* o) { + reset(o); + return *this; + } + + T& operator*() { + return *object_; + } + T* operator->() const { + return object_; + } + operator T*() const { + return object_; + } + + bool operator==(const T* that) { + return object_ == that; + } + bool operator==(const Ref &other) const { + return object_ == other.object_ || *object_ == *(other.object_); + } + template + bool operator==(const Ref &other) const { + return object_ == other.object_ || *object_ == *(other.object_); + } + + bool operator!=(const T* that) { + return !(*this == that); + } + + bool empty() const { + return object_ == 0; + } + + template + friend std::ostream& operator<<(std::ostream &out, Ref& ref); +}; +} + +#endif // __COUNTED_H__ + +// file: zxing/common/BitArray.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __BIT_ARRAY_H__ +// #define __BIT_ARRAY_H__ + +/* + * 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 +// #include +// #include +// #include + +namespace zxing { + +#define ZX_LOG_DIGITS(digits) \ + ((digits == 8) ? 3 : \ + ((digits == 16) ? 4 : \ + ((digits == 32) ? 5 : \ + ((digits == 64) ? 6 : \ + ((digits == 128) ? 7 : \ + (-1)))))) + +class BitArray : public Counted { +private: + size_t size_; + std::vector bits_; + static const unsigned int bitsPerWord_ = + std::numeric_limits::digits; + static const unsigned int logBits_ = ZX_LOG_DIGITS(bitsPerWord_); + static const unsigned int bitsMask_ = (1 << logBits_) - 1; + static size_t wordsForBits(size_t bits); + explicit BitArray(); + +public: + BitArray(size_t size); + ~BitArray(); + size_t getSize(); + + bool get(size_t i) { + return (bits_[i >> logBits_] & (1 << (i & bitsMask_))) != 0; + } + + void set(size_t i) { + bits_[i >> logBits_] |= 1 << (i & bitsMask_); + } + + void setBulk(size_t i, unsigned int newBits); + void setRange(int start, int end); + void clear(); + bool isRange(size_t start, size_t end, bool value); + std::vector& getBitArray(); + void reverse(); +}; + +} + +#endif // __BIT_ARRAY_H__ + +// file: zxing/common/BitMatrix.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __BIT_MATRIX_H__ +// #define __BIT_MATRIX_H__ + +/* + * BitMatrix.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 +// #include +// #include + +namespace zxing { + +class BitMatrix : public Counted { +private: + size_t width_; + size_t height_; + size_t words_; + unsigned int* bits_; + +#define ZX_LOG_DIGITS(digits) \ + ((digits == 8) ? 3 : \ + ((digits == 16) ? 4 : \ + ((digits == 32) ? 5 : \ + ((digits == 64) ? 6 : \ + ((digits == 128) ? 7 : \ + (-1)))))) + + static const unsigned int bitsPerWord = + std::numeric_limits::digits; + static const unsigned int logBits = ZX_LOG_DIGITS(bitsPerWord); + static const unsigned int bitsMask = (1 << logBits) - 1; + +public: + BitMatrix(size_t dimension); + BitMatrix(size_t width, size_t height); + + ~BitMatrix(); + + bool get(size_t x, size_t y) const { + size_t offset = x + width_ * y; + return ((bits_[offset >> logBits] >> (offset & bitsMask)) & 0x01) != 0; + } + + void set(size_t x, size_t y) { + size_t offset = x + width_ * y; + bits_[offset >> logBits] |= 1 << (offset & bitsMask); + } + + void flip(size_t x, size_t y); + void clear(); + void setRegion(size_t left, size_t top, size_t width, size_t height); + Ref getRow(int y, Ref row); + + size_t getDimension() const; + size_t getWidth() const; + size_t getHeight() const; + + unsigned int* getBits() const; + + friend std::ostream& operator<<(std::ostream &out, const BitMatrix &bm); + const char *description(); + +private: + BitMatrix(const BitMatrix&); + BitMatrix& operator =(const BitMatrix&); +}; + +} + +#endif // __BIT_MATRIX_H__ + +// file: zxing/common/Array.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __ARRAY_H__ +// #define __ARRAY_H__ + +/* + * Array.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 + +#ifdef DEBUG_COUNTING +// #include +// #include +#endif + +// #include + + +namespace zxing { + +template class Array : public Counted { +protected: +public: + std::vector values_; + Array(size_t n) : + Counted(), values_(n, T()) { + } + Array(T *ts, size_t n) : + Counted(), values_(ts, ts+n) { + } + Array(T v, size_t n) : + Counted(), values_(n, v) { + } + Array(std::vector &v) : + Counted(), values_(v) { + } + Array(Array &other) : + Counted(), values_(other.values_) { + } + Array(Array *other) : + Counted(), values_(other->values_) { + } + virtual ~Array() { + } + Array& operator=(const Array &other) { +#ifdef DEBUG_COUNTING + cout << "assigning values from Array " << &other << " to this Array " << this << ", "; +#endif + values_ = other.values_; +#ifdef DEBUG_COUNTING + cout << "new size = " << values_.size() << "\n"; +#endif + return *this; + } + Array& operator=(const std::vector &array) { +#ifdef DEBUG_COUNTING + cout << "assigning values from Array " << &array << " to this Array " << this << ", "; +#endif + values_ = array; +#ifdef DEBUG_COUNTING + cout << "new size = " << values_.size() << "\n"; +#endif + return *this; + } + T operator[](size_t i) const { + return values_[i]; + } + T& operator[](size_t i) { + return values_[i]; + } + size_t size() const { + return values_.size(); + } + std::vector values() const { + return values_; + } + std::vector& values() { + return values_; + } +}; + +template class ArrayRef : public Counted { +private: +public: + Array *array_; + ArrayRef() : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating empty ArrayRef " << this << "\n"; +#endif + } + ArrayRef(size_t n) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << "with size " << n << "\n"; +#endif + reset(new Array (n)); + } + ArrayRef(T *ts, size_t n) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << "with " << n << " elements at " << (void *)ts << "\n"; +#endif + reset(new Array (ts, n)); + } + ArrayRef(Array *a) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << " from pointer:\n"; +#endif + reset(a); + } + ArrayRef(const Array &a) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << " from reference to Array " << (void *)&a << ":\n"; +#endif + reset(const_cast *>(&a)); + } + ArrayRef(const ArrayRef &other) : + Counted(), array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << " from ArrayRef " << &other << ":\n"; +#endif + reset(other.array_); + } + + template + ArrayRef(const ArrayRef &other) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << " from ArrayRef " << &other << ":\n"; +#endif + reset(static_cast *>(other.array_)); + } + + ~ArrayRef() { +#ifdef DEBUG_COUNTING + cout << "destroying ArrayRef " << this << " with " << (array_ ? typeid(*array_).name() : "NULL") << " " + << array_ << "\n"; +#endif + if (array_) { + array_->release(); + } + array_ = 0; + } + + T operator[](size_t i) const { + return (*array_)[i]; + } + T& operator[](size_t i) { + return (*array_)[i]; + } + size_t size() const { + return array_->size(); + } + + void reset(Array *a) { +#ifdef DEBUG_COUNTING + cout << "resetting ArrayRef " << this << " from " << (array_ ? typeid(*array_).name() : "NULL") << " " + << array_ << " to " << (a ? typeid(*a).name() : "NULL") << " " << a << "\n"; +#endif + if (a) { + a->retain(); + } + if (array_) { + array_->release(); + } + array_ = a; + } + void reset(const ArrayRef &other) { + reset(other.array_); + } + ArrayRef& operator=(const ArrayRef &other) { + reset(other); + return *this; + } + ArrayRef& operator=(Array *a) { + reset(a); + return *this; + } + + Array& operator*() { + return *array_; + } + Array* operator->() { + return array_; + } +}; + +} // namespace zxing + +#endif // __ARRAY_H__ + +// file: zxing/common/Str.h + +#ifndef __STR_H__ +// #define __STR_H__ + +/* + * Str.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 +// #include +// #include + +namespace zxing { + +class String : public Counted { +private: + std::string text_; +public: + String(const std::string &text); + const std::string &getText() const; + friend std::ostream &operator<<(std::ostream &out, const String &s); +}; + +} + +#endif // __COMMON__STRING_H__ + +// file: zxing/common/BitSource.h + +#ifndef __BIT_SOURCE_H__ +// #define __BIT_SOURCE_H__ + +/* + * BitSource.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 + +namespace zxing { +/** + *

This provides an easy abstraction to read bits at a time from a sequence of bytes, where the + * number of bits read is not often a multiple of 8.

+ * + *

This class is not thread-safe.

+ * + * @author srowen@google.com (Sean Owen) + * @author christian.brunschen@gmail.com (Christian Brunschen) + */ +class BitSource : public Counted { + typedef unsigned char byte; +private: + ArrayRef bytes_; + int byteOffset_; + int bitOffset_; +public: + /** + * @param bytes bytes from which this will read bits. Bits will be read from the first byte first. + * Bits are read within a byte from most-significant to least-significant bit. + */ + BitSource(ArrayRef &bytes) : + bytes_(bytes), byteOffset_(0), bitOffset_(0) { + } + + int getByteOffset() { + return byteOffset_; + } + + /** + * @param numBits number of bits to read + * @return int representing the bits read. The bits will appear as the least-significant + * bits of the int + * @throws IllegalArgumentException if numBits isn't in [1,32] + */ + int readBits(int numBits); + + /** + * @return number of bits that can be read successfully + */ + int available(); +}; + +} + +#endif // __BIT_SOURCE_H__ + +// file: zxing/common/DecoderResult.h + +#ifndef __DECODER_RESULT_H__ +// #define __DECODER_RESULT_H__ + +/* + * DecoderResult.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 +// #include +// #include +// #include + +namespace zxing { + +class DecoderResult : public Counted { +private: + ArrayRef rawBytes_; + Ref text_; + ArrayRef< ArrayRef > byteSegments_; + std::string ecLevel_; + +public: + DecoderResult(ArrayRef rawBytes, + Ref text, + ArrayRef< ArrayRef >& byteSegments, + std::string const& ecLevel); + + DecoderResult(ArrayRef rawBytes, Ref text); + + ArrayRef getRawBytes(); + Ref getText(); +}; + +} + +#endif // __DECODER_RESULT_H__ + +// file: zxing/common/PerspectiveTransform.h + +#ifndef __PERSPECTIVE_TANSFORM_H__ +// #define __PERSPECTIVE_TANSFORM_H__ + +/* + * PerspectiveTransform.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 +// #include + +namespace zxing { +class PerspectiveTransform : public Counted { +private: + float a11, a12, a13, a21, a22, a23, a31, a32, a33; + PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32, float a13, float a23, + float a33); + +public: + static Ref + quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, + float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p); + static Ref squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, + float x3, float y3); + static Ref quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, float y2, + float x3, float y3); + Ref buildAdjoint(); + Ref times(Ref other); + void transformPoints(std::vector &points); + + friend std::ostream& operator<<(std::ostream& out, const PerspectiveTransform &pt); +}; +} + +#endif // __PERSPECTIVE_TANSFORM_H__ + +// file: zxing/ResultPoint.h + +// -*- 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 +// #include + +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 other); + + static void orderBestPatterns(std::vector > &patterns); + static float distance(Ref point1, Ref point2); + static float distance(float x1, float x2, float y1, float y2); + +private: + static float crossProductZ(Ref pointA, Ref pointB, Ref pointC); +}; + +} + +#endif // __RESULT_POINT_H__ + +// file: zxing/common/DetectorResult.h + +#ifndef __DETECTOR_RESULT_H__ +// #define __DETECTOR_RESULT_H__ + +/* + * DetectorResult.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 +// #include +// #include +// #include +// #include +// #include + +namespace zxing { + +class DetectorResult : public Counted { +private: + Ref bits_; + std::vector > points_; + Ref transform_; + +public: + DetectorResult(Ref bits, std::vector > points, Ref transform); + Ref getBits(); + std::vector > getPoints(); + Ref getTransform(); +}; +} + +#endif // __DETECTOR_RESULT_H__ + +// file: zxing/common/Point.h + +#ifndef __POINT_H__ +// #define __POINT_H__ + +/* + * Point.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 { +class PointI { +public: + int x; + int y; +}; + +class Point { +public: + Point() : x(0.0f), y(0.0f) {}; + Point(float x_, float y_) : x(x_), y(y_) {}; + + float x; + float y; +}; + +class Line { +public: + Line(Point start_, Point end_) : start(start_), end(end_) {}; + + Point start; + Point end; +}; +} +#endif // POINT_H_ + +// file: zxing/common/EdgeDetector.h + +#ifndef __EDGEDETECTOR_H__ +// #define __EDGEDETECTOR_H__ +/* + * EdgeDetector.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 +// #include +// #include + +namespace zxing { +namespace EdgeDetector { + +void findEdgePoints(std::vector& points, const BitMatrix& image, Point start, Point end, bool invert, int skip, float deviation); +Line findLine(const BitMatrix& image, Line estimate, bool invert, int deviation, float threshold, int skip); + +Point intersection(Line a, Line b); + +} +} +#endif /* EDGEDETECTOR_H_ */ + +// file: zxing/LuminanceSource.h + +// -*- 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 +// #include + +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 crop(int left, int top, int width, int height); + + virtual bool isRotateSupported() const; + virtual Ref rotateCounterClockwise(); + + operator std::string (); // should be const but don't want to make sure a + // large breaking change right now +}; + +} + +#endif /* LUMINANCESOURCE_H_ */ + +// file: zxing/Binarizer.h + +#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 +// #include +// #include +// #include + +namespace zxing { + +class Binarizer : public Counted { + private: + Ref source_; + + public: + Binarizer(Ref source); + virtual ~Binarizer(); + + virtual Ref getBlackRow(int y, Ref row) = 0; + virtual Ref getBlackMatrix() = 0; + + Ref getLuminanceSource() const ; + virtual Ref createBinarizer(Ref source) = 0; +}; + +} +#endif /* BINARIZER_H_ */ + +// file: zxing/common/GlobalHistogramBinarizer.h + +#ifndef __GLOBALHISTOGRAMBINARIZER_H__ +// #define __GLOBALHISTOGRAMBINARIZER_H__ +/* + * GlobalHistogramBinarizer.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 +// #include +// #include +// #include + +namespace zxing { + + class GlobalHistogramBinarizer : public Binarizer { + private: + Ref cached_matrix_; + Ref cached_row_; + int cached_row_num_; + + public: + GlobalHistogramBinarizer(Ref source); + virtual ~GlobalHistogramBinarizer(); + + virtual Ref getBlackRow(int y, Ref row); + virtual Ref getBlackMatrix(); + static int estimate(std::vector &histogram); + Ref createBinarizer(Ref source); + }; + +} + +#endif /* GLOBALHISTOGRAMBINARIZER_H_ */ + +// file: zxing/common/GreyscaleLuminanceSource.h + +#ifndef __GREYSCALE_LUMINANCE_SOURCE__ +#define __GREYSCALE_LUMINANCE_SOURCE__ +/* + * GreyscaleLuminanceSource.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 + +namespace zxing { + +class GreyscaleLuminanceSource : public LuminanceSource { + + private: + unsigned char* greyData_; + int dataWidth_; + int dataHeight_; + int left_; + int top_; + int width_; + int height_; + + public: + GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth, int dataHeight, int left, + int top, int width, int height); + + unsigned char* getRow(int y, unsigned char* row); + unsigned char* getMatrix(); + + bool isRotateSupported() const { + return true; + } + + int getWidth() const { + return width_; + } + + int getHeight() const { + return height_; + } + + Ref rotateCounterClockwise(); + +}; + +} /* namespace */ + +#endif + +// file: zxing/common/GreyscaleRotatedLuminanceSource.h + +#ifndef __GREYSCALE_ROTATED_LUMINANCE_SOURCE__ +#define __GREYSCALE_ROTATED_LUMINANCE_SOURCE__ +/* + * GreyscaleRotatedLuminanceSource.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 + +namespace zxing { + +class GreyscaleRotatedLuminanceSource : public LuminanceSource { + private: + unsigned char* greyData_; + int dataWidth_; + int dataHeight_; + int left_; + int top_; + int width_; + int height_; + +public: + GreyscaleRotatedLuminanceSource(unsigned char* greyData, int dataWidth, int dataHeight, + int left, int top, int width, int height); + + unsigned char* getRow(int y, unsigned char* row); + unsigned char* getMatrix(); + + bool isRotateSupported() const { + return false; + } + + int getWidth() const { + return width_; + } + + int getHeight() const { + return height_; + } + +}; + +} /* namespace */ + +#endif + +// file: zxing/common/GridSampler.h + +#ifndef __GRID_SAMPLER_H__ +// #define __GRID_SAMPLER_H__ + +/* + * GridSampler.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 +// #include +// #include + +namespace zxing { +class GridSampler { +private: + static GridSampler gridSampler; + GridSampler(); + +public: + Ref sampleGrid(Ref image, int dimension, Ref transform); + Ref sampleGrid(Ref image, int dimensionX, int dimensionY, Ref transform); + + Ref sampleGrid(Ref image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY, + float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, + float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY); + static void checkAndNudgePoints(Ref image, std::vector &points); + static GridSampler &getInstance(); +}; +} + +#endif // __GRID_SAMPLER_H__ + +// file: zxing/common/HybridBinarizer.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __HYBRIDBINARIZER_H__ +// #define __HYBRIDBINARIZER_H__ +/* + * HybridBinarizer.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 +// #include +// #include +// #include +// #include + +namespace zxing { + + class HybridBinarizer : public GlobalHistogramBinarizer { + private: + Ref matrix_; + Ref cached_row_; + int cached_row_num_; + + public: + HybridBinarizer(Ref source); + virtual ~HybridBinarizer(); + + virtual Ref getBlackMatrix(); + Ref createBinarizer(Ref source); + private: + // We'll be using one-D arrays because C++ can't dynamically allocate 2D + // arrays + int* calculateBlackPoints(unsigned char* luminances, + int subWidth, + int subHeight, + int width, + int height); + void calculateThresholdForBlock(unsigned char* luminances, + int subWidth, + int subHeight, + int width, + int height, + int blackPoints[], + Ref const& matrix); + void threshold8x8Block(unsigned char* luminances, + int xoffset, + int yoffset, + int threshold, + int stride, + Ref const& matrix); + }; + +} + +#endif + +// file: zxing/common/reedsolomon/GF256.h + +#ifndef __GF256_H__ +// #define __GF256_H__ + +/* + * GF256.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 +// #include +// #include + +namespace zxing { +class GF256Poly; + +class GF256 { + /** + *

This class contains utility methods for performing mathematical + * operations over the Galois Field GF(256). Operations use a given + * primitive polynomial in calculations.

+ * + *

Throughout this package, elements of GF(256) are represented as an + * int for convenience and speed (but at the cost of memory). + * Only the bottom 8 bits are really used.

+ * + * @author srowen@google.com (Sean Owen) + * @author christian.brunschen@gmail.com (Christian Brunschen) + */ +private: + std::vector exp_; + std::vector log_; + Ref zero_; + Ref one_; + + GF256(int primitive); + +public: + Ref getZero(); + Ref getOne(); + Ref buildMonomial(int degree, int coefficient); + static int addOrSubtract(int a, int b); + int exp(int a); + int log(int a); + int inverse(int a); + int multiply(int a, int b); + + static GF256 QR_CODE_FIELD; + static GF256 DATA_MATRIX_FIELD; + + friend std::ostream& operator<<(std::ostream& out, const GF256& field); +}; +} + +#endif // __GF256_H__ + +// file: zxing/common/reedsolomon/GF256Poly.h + +#ifndef __GF256_POLY_H__ +// #define __GF256_POLY_H__ + +/* + * GF256Poly.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 +// #include +// #include + +namespace zxing { +class GF256; + +class GF256Poly : public Counted { +private: + GF256 &field; + ArrayRef coefficients; + void fixCoefficients(); +public: + GF256Poly(GF256 &field, ArrayRef c); + ~GF256Poly(); + + int getDegree(); + bool isZero(); + int getCoefficient(int degree); + int evaluateAt(int a); + Ref addOrSubtract(Ref other); + Ref multiply(Ref other); + Ref multiply(int scalar); + Ref multiplyByMonomial(int degree, int coefficient); + const char *description() const; + friend std::ostream& operator<<(std::ostream& out, const GF256Poly& poly); + +}; +} + +#endif // __GF256_POLY_H__ + +// file: zxing/common/reedsolomon/ReedSolomonDecoder.h + +#ifndef __REED_SOLOMON_DECODER_H__ +// #define __REED_SOLOMON_DECODER_H__ + +/* + * ReedSolomonDecoder.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 +// #include +// #include +// #include + +namespace zxing { +class GF256; +class GF256Poly; + +class ReedSolomonDecoder { +private: + GF256 &field; +public: + ReedSolomonDecoder(GF256 &fld); + ~ReedSolomonDecoder(); + void decode(ArrayRef received, int twoS); +private: + std::vector > runEuclideanAlgorithm(Ref a, Ref b, int R); + ArrayRef findErrorLocations(Ref errorLocator); + ArrayRef findErrorMagnitudes(Ref errorEvaluator, ArrayRef errorLocations, bool dataMatrix); +}; +} + +#endif // __REED_SOLOMON_DECODER_H__ + +// file: zxing/common/reedsolomon/ReedSolomonException.h + +#ifndef __REED_SOLOMON_EXCEPTION_H__ +// #define __REED_SOLOMON_EXCEPTION_H__ + +/* + * ReedSolomonException.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 + +namespace zxing { +class ReedSolomonException : public Exception { +public: + ReedSolomonException(const char *msg) throw(); + ~ReedSolomonException() throw(); +}; +} + +#endif // __REED_SOLOMON_EXCEPTION_H__ + +// file: zxing/BarcodeFormat.h + +#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; + + /* if you update the enum, please update the name in BarcodeFormat.cpp */ + extern const char *barcodeFormatNames[]; +} + +#endif // __BARCODE_FORMAT_H__ + +// file: zxing/BinaryBitmap.h + +#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 +// #include +// #include +// #include + +namespace zxing { + + class BinaryBitmap : public Counted { + private: + Ref binarizer_; + int cached_y_; + + public: + BinaryBitmap(Ref binarizer); + virtual ~BinaryBitmap(); + + Ref getBlackRow(int y, Ref row); + Ref getBlackMatrix(); + + Ref getLuminanceSource() const; + + int getWidth() const; + int getHeight() const; + + bool isRotateSupported() const; + Ref rotateCounterClockwise(); + + bool isCropSupported() const; + Ref crop(int left, int top, int width, int height); + + }; + +} + +#endif /* BINARYBITMAP_H_ */ + +// file: zxing/ResultPointCallback.h + +#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 + +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__ + +// file: zxing/DecodeHints.h + +#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 +// #include + +namespace zxing { + +typedef unsigned int DecodeHintType; + +class DecodeHints { + + private: + + DecodeHintType hints; + + Ref 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 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 const&); + Ref getResultPointCallback() const; + +}; + +} + +#endif + +// file: zxing/Result.h + +#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 +// #include +// #include +// #include +// #include +// #include +// #include + +namespace zxing { + +class Result : public Counted { +private: + Ref text_; + ArrayRef rawBytes_; + std::vector > resultPoints_; + BarcodeFormat format_; + +public: + Result(Ref text, ArrayRef rawBytes, std::vector > resultPoints, + BarcodeFormat format); + ~Result(); + Ref getText(); + ArrayRef getRawBytes(); + const std::vector >& getResultPoints() const; + std::vector >& getResultPoints(); + BarcodeFormat getBarcodeFormat() const; + + friend std::ostream& operator<<(std::ostream &out, Result& result); +}; + +} +#endif // __RESULT_H__ + +// file: zxing/Reader.h + +#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 +// #include +// #include + +namespace zxing { + + class Reader : public Counted { + protected: + Reader() {} + public: + virtual Ref decode(Ref image); + virtual Ref decode(Ref image, DecodeHints hints) = 0; + virtual ~Reader(); +}; + +} + +#endif // __READER_H__ + +// file: zxing/MultiFormatReader.h + +#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 +// #include +// #include +// #include + +namespace zxing { + class MultiFormatReader : public Reader { + + private: + Ref decodeInternal(Ref image); + + std::vector > readers_; + DecodeHints hints_; + + public: + MultiFormatReader(); + + Ref decode(Ref image); + Ref decode(Ref image, DecodeHints hints); + Ref decodeWithState(Ref image); + void setHints(DecodeHints hints); + ~MultiFormatReader(); + }; +} + +#endif + +// file: zxing/ReaderException.h + +#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 + +namespace zxing { + +class ReaderException : public Exception { +public: + ReaderException(); + ReaderException(const char *msg); + ~ReaderException() throw(); +}; + +} +#endif // __READER_EXCEPTION_H__ + +// file: zxing/datamatrix/decoder/Decoder.h + +#ifndef __DECODER_DM_H__ +// #define __DECODER_DM_H__ + +/* + * Decoder.h + * zxing + * + * Created 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 +// #include +// #include +// #include +// #include +// #include + + +namespace zxing { +namespace datamatrix { + +class Decoder { +private: + ReedSolomonDecoder rsDecoder_; + + void correctErrors(ArrayRef bytes, int numDataCodewords); + +public: + Decoder(); + + Ref decode(Ref bits); +}; + +} +} + +#endif // __DECODER_DM_H__ + +// file: zxing/datamatrix/DataMatrixReader.h + +#ifndef __DATA_MATRIX_READER_H__ +// #define __DATA_MATRIX_READER_H__ + +/* + * DataMatrixReader.h + * zxing + * + * Created 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 +// #include +// #include + +namespace zxing { +namespace datamatrix { + +class DataMatrixReader : public Reader { +private: + Decoder decoder_; + +public: + DataMatrixReader(); + virtual Ref decode(Ref image, DecodeHints hints); + virtual ~DataMatrixReader(); + +}; + +} +} + +#endif // __DATA_MATRIX_READER_H__ + +// file: zxing/datamatrix/Version.h + +#ifndef __VERSION_H__ +// #define __VERSION_H__ + +/* + * Version.h + * zxing + * + * Created 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 +// #include +// #include +// #include + +namespace zxing { +namespace datamatrix { + +class ECB { +private: + int count_; + int dataCodewords_; +public: + ECB(int count, int dataCodewords); + int getCount(); + int getDataCodewords(); +}; + +class ECBlocks { +private: + int ecCodewords_; + std::vector ecBlocks_; +public: + ECBlocks(int ecCodewords, ECB *ecBlocks); + ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2); + int getECCodewords(); + std::vector& getECBlocks(); + ~ECBlocks(); +}; + +class Version : public Counted { +private: + int versionNumber_; + int symbolSizeRows_; + int symbolSizeColumns_; + int dataRegionSizeRows_; + int dataRegionSizeColumns_; + ECBlocks* ecBlocks_; + int totalCodewords_; + Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows, + int dataRegionSizeColumns, ECBlocks *ecBlocks); + +public: + static std::vector > VERSIONS; + + ~Version(); + int getVersionNumber(); + int getSymbolSizeRows(); + int getSymbolSizeColumns(); + int getDataRegionSizeRows(); + int getDataRegionSizeColumns(); + int getTotalCodewords(); + ECBlocks* getECBlocks(); + static int buildVersions(); + Ref getVersionForDimensions(int numRows, int numColumns); + +private: + Version(const Version&); + Version & operator=(const Version&); +}; +} +} + +#endif // __VERSION_H__ + +// file: zxing/datamatrix/decoder/BitMatrixParser.h + +#ifndef __BIT_MATRIX_PARSER_DM_H__ +// #define __BIT_MATRIX_PARSER_DM_H__ + +/* + * BitMatrixParser.h + * zxing + * + * Created 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 +// #include +// #include +// #include +// #include + +namespace zxing { +namespace datamatrix { + +class BitMatrixParser : public Counted { +private: + Ref bitMatrix_; + Ref parsedVersion_; + Ref readBitMatrix_; + + int copyBit(size_t x, size_t y, int versionBits); + +public: + BitMatrixParser(Ref bitMatrix); + Ref readVersion(Ref bitMatrix); + ArrayRef readCodewords(); + bool readModule(int row, int column, int numRows, int numColumns); + +private: + int readUtah(int row, int column, int numRows, int numColumns); + int readCorner1(int numRows, int numColumns); + int readCorner2(int numRows, int numColumns); + int readCorner3(int numRows, int numColumns); + int readCorner4(int numRows, int numColumns); + Ref extractDataRegion(Ref bitMatrix); +}; + +} +} + +#endif // __BIT_MATRIX_PARSER_DM_H__ + +// file: zxing/datamatrix/decoder/DataBlock.h + +#ifndef __DATA_BLOCK_DM_H__ +// #define __DATA_BLOCK_DM_H__ + +/* + * DataBlock.h + * zxing + * + * Created 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 +// #include +// #include +// #include + +namespace zxing { +namespace datamatrix { + +class DataBlock : public Counted { +private: + int numDataCodewords_; + ArrayRef codewords_; + + DataBlock(int numDataCodewords, ArrayRef codewords); + +public: + static std::vector > getDataBlocks(ArrayRef rawCodewords, Version *version); + + int getNumDataCodewords(); + ArrayRef getCodewords(); +}; + +} +} + +#endif // __DATA_BLOCK_DM_H__ + +// file: zxing/datamatrix/decoder/DecodedBitStreamParser.h + +#ifndef __DECODED_BIT_STREAM_PARSER_DM_H__ +// #define __DECODED_BIT_STREAM_PARSER_DM_H__ + +/* + * DecodedBitStreamParser.h + * zxing + * + * Created 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 +// #include +// #include +// #include +// #include +// #include + + +namespace zxing { +namespace datamatrix { + +class DecodedBitStreamParser { +private: + static const int PAD_ENCODE = 0; // Not really an encoding + static const int ASCII_ENCODE = 1; + static const int C40_ENCODE = 2; + static const int TEXT_ENCODE = 3; + static const int ANSIX12_ENCODE = 4; + static const int EDIFACT_ENCODE = 5; + static const int BASE256_ENCODE = 6; + + /** + * See ISO 16022:2006, Annex C Table C.1 + * The C40 Basic Character Set (*'s used for placeholders for the shift values) + */ + static const char C40_BASIC_SET_CHARS[]; + + static const char C40_SHIFT2_SET_CHARS[]; + /** + * See ISO 16022:2006, Annex C Table C.2 + * The Text Basic Character Set (*'s used for placeholders for the shift values) + */ + static const char TEXT_BASIC_SET_CHARS[]; + + static const char TEXT_SHIFT3_SET_CHARS[]; + /** + * See ISO 16022:2006, 5.2.3 and Annex C, Table C.2 + */ + int decodeAsciiSegment(Ref bits, std::ostringstream &result, std::ostringstream &resultTrailer); + /** + * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 + */ + void decodeC40Segment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 + */ + void decodeTextSegment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.7 + */ + void decodeAnsiX12Segment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.8 and Annex C Table C.3 + */ + void decodeEdifactSegment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.9 and Annex B, B.2 + */ + void decodeBase256Segment(Ref bits, std::ostringstream &result, std::vector byteSegments); + + void parseTwoBytes(int firstByte, int secondByte, int*& result); + /** + * See ISO 16022:2006, Annex B, B.2 + */ + unsigned char unrandomize255State(int randomizedBase256Codeword, + int base256CodewordPosition) { + int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1; + int tempVariable = randomizedBase256Codeword - pseudoRandomNumber; + return (unsigned char) (tempVariable >= 0 ? tempVariable : (tempVariable + 256)); + }; + void append(std::ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src); + +public: + DecodedBitStreamParser() { }; + Ref decode(ArrayRef bytes); +}; + +} +} + +#endif // __DECODED_BIT_STREAM_PARSER_DM_H__ + +// file: zxing/datamatrix/detector/CornerPoint.h + +#ifndef __CORNER_FINDER_H__ +// #define __CORNER_FINDER_H__ + +/* + * CornerPoint.h + * zxing + * + * Created 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 +// #include + +namespace zxing { + namespace datamatrix { + + class CornerPoint : public ResultPoint { + private: + int counter_; + + public: + CornerPoint(float posX, float posY); + int getCount() const; + void incrementCount(); + bool equals(Ref other) const; + }; + } +} + +#endif // __CORNER_FINDER_H__ + +// file: zxing/datamatrix/detector/MonochromeRectangleDetector.h + +#ifndef __MONOCHROMERECTANGLEDETECTOR_H__ +// #define __MONOCHROMERECTANGLEDETECTOR_H__ + +/* + * MonochromeRectangleDetector.h + * zxing + * + * Created 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 +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace datamatrix { + +struct TwoInts: public Counted { + int start; + int end; +}; + +class MonochromeRectangleDetector : public Counted { +private: + static const int MAX_MODULES = 32; + Ref image_; + +public: + MonochromeRectangleDetector(Ref image) : image_(image) { }; + + std::vector > detect(); + +private: + Ref findCornerFromCenter(int centerX, int deltaX, int left, int right, + int centerY, int deltaY, int top, int bottom, int maxWhiteRun); + + Ref blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, + bool horizontal); + + int max(int a, float b) { return (float) a > b ? a : (int) b;}; +}; +} +} + +#endif // __MONOCHROMERECTANGLEDETECTOR_H__ + +// file: zxing/datamatrix/detector/Detector.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __DETECTOR_H__ +// #define __DETECTOR_H__ + +/* + * Detector.h + * zxing + * + * Created 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 +// #include +// #include +// #include +// #include + +namespace zxing { +namespace datamatrix { + +class ResultPointsAndTransitions: public Counted { + private: + Ref to_; + Ref from_; + int transitions_; + + public: + ResultPointsAndTransitions(); + ResultPointsAndTransitions(Ref from, Ref to, int transitions); + Ref getFrom(); + Ref getTo(); + int getTransitions(); +}; + +class Detector: public Counted { + private: + Ref image_; + + protected: + Ref sampleGrid(Ref image, int dimensionX, int dimensionY, + Ref transform); + + void insertionSort(std::vector >& vector); + + Ref correctTopRightRectangular(Ref bottomLeft, + Ref bottomRight, Ref topLeft, Ref topRight, + int dimensionTop, int dimensionRight); + Ref correctTopRight(Ref bottomLeft, Ref bottomRight, + Ref topLeft, Ref topRight, int dimension); + bool isValid(Ref p); + int distance(Ref a, Ref b); + Ref transitionsBetween(Ref from, Ref to); + int min(int a, int b) { + return a > b ? b : a; + } + /** + * Ends up being a bit faster than round(). This merely rounds its + * argument to the nearest int, where x.5 rounds up. + */ + int round(float d) { + return (int) (d + 0.5f); + } + + public: + Ref getImage(); + Detector(Ref image); + + virtual Ref createTransform(Ref topLeft, + Ref topRight, Ref bottomLeft, Ref bottomRight, + int dimensionX, int dimensionY); + + Ref detect(); + + private: + int compare(Ref a, Ref b); +}; + +} +} + +#endif // __DETECTOR_H__ + +// file: zxing/oned/OneDReader.h + +#ifndef __ONED_READER_H__ +// #define __ONED_READER_H__ + +/* + * OneDReader.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 + +namespace zxing { + namespace oned { + class OneDReader : public Reader { + private: + static const int INTEGER_MATH_SHIFT = 8; + + Ref doDecode(Ref image, DecodeHints hints); + public: + static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; + + OneDReader(); + virtual Ref decode(Ref image, DecodeHints hints); + + // Implementations must not throw any exceptions. If a barcode is not found on this row, + // a empty ref should be returned e.g. return Ref(); + virtual Ref decodeRow(int rowNumber, Ref row) = 0; + + static unsigned int patternMatchVariance(int counters[], int countersSize, + const int pattern[], int maxIndividualVariance); + static bool recordPattern(Ref row, int start, int counters[], int countersCount); + virtual ~OneDReader(); + }; + } +} + +#endif + +// file: zxing/oned/Code128Reader.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __CODE_128_READER_H__ +// #define __CODE_128_READER_H__ +/* + * 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 +// #include +// #include + +namespace zxing { + namespace oned { + class Code128Reader : public OneDReader { + + private: + enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 250/1000)}; + enum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 700/1000)}; + static const int CODE_SHIFT = 98; + + static const int CODE_CODE_C = 99; + static const int CODE_CODE_B = 100; + static const int CODE_CODE_A = 101; + + static const int CODE_FNC_1 = 102; + static const int CODE_FNC_2 = 97; + static const int CODE_FNC_3 = 96; + static const int CODE_FNC_4_A = 101; + static const int CODE_FNC_4_B = 100; + + static const int CODE_START_A = 103; + static const int CODE_START_B = 104; + static const int CODE_START_C = 105; + static const int CODE_STOP = 106; + + static int* findStartPattern(Ref row); + static int decodeCode(Ref row, int counters[], int countersCount, int rowOffset); + + void append(char* s, char c); + public: + Ref decodeRow(int rowNumber, Ref row); + Code128Reader(); + ~Code128Reader(); + }; + } +} + +#endif + +// file: zxing/oned/Code39Reader.h + +#ifndef __CODE_39_READER_H__ +// #define __CODE_39_READER_H__ +/* + * Code39Reader.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 +// #include +// #include + +namespace zxing { + namespace oned { + + /** + *

Decodes Code 39 barcodes. This does not support "Full ASCII Code 39" yet.

+ * Ported form Java (author Sean Owen) + * @author Lukasz Warchol + */ + class Code39Reader : public OneDReader { + + private: + std::string alphabet_string; + + bool usingCheckDigit; + bool extendedMode; + + static int* findAsteriskPattern(Ref row); //throws ReaderException + static int toNarrowWidePattern(int counters[], int countersLen); + static char patternToChar(int pattern); //throws ReaderException + static Ref decodeExtended(std::string encoded); //throws ReaderException + + void append(char* s, char c); + public: + Code39Reader(); + Code39Reader(bool usingCheckDigit_); + Code39Reader(bool usingCheckDigit_, bool extendedMode_); + + Ref decodeRow(int rowNumber, Ref row); + }; + } +} + +#endif + +// file: zxing/oned/UPCEANReader.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __UPC_EAN_READER_H__ +// #define __UPC_EAN_READER_H__ + +/* + * 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 +// #include +// #include + +typedef enum UPC_EAN_PATTERNS { + UPC_EAN_PATTERNS_L_PATTERNS = 0, + UPC_EAN_PATTERNS_L_AND_G_PATTERNS +} UPC_EAN_PATTERNS; + +namespace zxing { + namespace oned { + class UPCEANReader : public OneDReader { + + private: + enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 420/1000)}; + enum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 700/1000)}; + + static bool findStartGuardPattern(Ref row, int* rangeStart, int* rangeEnd); + + virtual bool decodeEnd(Ref row, int endStart, int* endGuardBegin, int* endGuardEnd); + + static bool checkStandardUPCEANChecksum(std::string s); + protected: + static bool findGuardPattern(Ref row, int rowOffset, bool whiteFirst, + const int pattern[], int patternLen, int* start, int* end); + + virtual int getMIDDLE_PATTERN_LEN(); + virtual const int* getMIDDLE_PATTERN(); + + public: + UPCEANReader(); + + // Returns < 0 on failure, >= 0 on success. + virtual int decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, + std::string& resultString) = 0; + + Ref decodeRow(int rowNumber, Ref row); + + // TODO(dswitkin): Should this be virtual so that UPCAReader can override it? + Ref decodeRow(int rowNumber, Ref row, int startGuardBegin, + int startGuardEnd); + + // Returns < 0 on failure, >= 0 on success. + static int decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, + UPC_EAN_PATTERNS patternType); + + virtual bool checkChecksum(std::string s); + + virtual BarcodeFormat getBarcodeFormat() = 0; + virtual ~UPCEANReader(); + }; + } +} + +#endif + +// file: zxing/oned/EAN13Reader.h + +#ifndef __EAN_13_READER_H__ +// #define __EAN_13_READER_H__ + +/* + * EAN13Reader.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 +// #include + +namespace zxing { + namespace oned { + class EAN13Reader : public UPCEANReader { + + private: + static bool determineFirstDigit(std::string& resultString, int lgPatternFound); + + public: + EAN13Reader(); + + int decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, + std::string& resultString); + + BarcodeFormat getBarcodeFormat(); + }; + } +} + +#endif + +// file: zxing/oned/EAN8Reader.h + +#ifndef __EAN_8_READER_H__ +// #define __EAN_8_READER_H__ + +/* + * EAN8Reader.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 +// #include + +namespace zxing { + namespace oned { + class EAN8Reader : public UPCEANReader { + + public: + EAN8Reader(); + + int decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, + std::string& resultString); + + BarcodeFormat getBarcodeFormat(); + }; + } +} + +#endif + +// file: zxing/oned/ITFReader.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __ITF_READER_H__ +// #define __ITF_READER_H__ + +/* + * 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 +// #include +// #include + +namespace zxing { + namespace oned { + class ITFReader : public OneDReader { + + private: + enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 420/1000)}; + enum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 800/1000)}; + // Stores the actual narrow line width of the image being decoded. + int narrowLineWidth; + + int* decodeStart(Ref row); //throws ReaderException + int* decodeEnd(Ref row); //throws ReaderException + static void decodeMiddle(Ref row, int payloadStart, int payloadEnd, std::string& resultString); //throws ReaderException + void validateQuietZone(Ref row, int startPattern); //throws ReaderException + static int skipWhiteSpace(Ref row); //throws ReaderException + + static int* findGuardPattern(Ref row, int rowOffset, const int pattern[], int patternLen); //throws ReaderException + static int decodeDigit(int counters[], int countersLen); //throws ReaderException + + void append(char* s, char c); + public: + Ref decodeRow(int rowNumber, Ref row); ///throws ReaderException + ITFReader(); + ~ITFReader(); + }; + } +} + +#endif + +// file: zxing/oned/MultiFormatOneDReader.h + +#ifndef __MULTI_FORMAT_ONED_READER_H__ +// #define __MULTI_FORMAT_ONED_READER_H__ +/* + * MultiFormatOneDReader.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 + +namespace zxing { + namespace oned { + class MultiFormatOneDReader : public OneDReader { + + private: + std::vector > readers; + public: + MultiFormatOneDReader(DecodeHints hints); + + Ref decodeRow(int rowNumber, Ref row); + }; + } +} + +#endif + +// file: zxing/oned/MultiFormatUPCEANReader.h + +#ifndef __MULTI_FORMAT_UPC_EAN_READER_H__ +// #define __MULTI_FORMAT_UPC_EAN_READER_H__ +/* + * MultiFormatUPCEANReader.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 + +namespace zxing { + namespace oned { + class MultiFormatUPCEANReader : public OneDReader { + + private: + std::vector > readers; + public: + MultiFormatUPCEANReader(DecodeHints hints); + + Ref decodeRow(int rowNumber, Ref row); + }; + } +} + +#endif + +// file: zxing/oned/OneDResultPoint.h + +#ifndef __ONED_RESULT_POINT_H__ +// #define __ONED_RESULT_POINT_H__ +/* + * OneDResultPoint.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 +// #include + +namespace zxing { + namespace oned { + + class OneDResultPoint : public ResultPoint { + + public: + OneDResultPoint(float posX, float posY); + }; + } +} + +#endif + +// file: zxing/oned/UPCAReader.h + +#ifndef __UPCA_READER_H__ +// #define __UPCA_READER_H__ +/* + * UPCAReader.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 +// #include + +namespace zxing { + namespace oned { + class UPCAReader : public UPCEANReader { + + private: + EAN13Reader ean13Reader; + static Ref maybeReturnResult(Ref result); + + public: + UPCAReader(); + + int decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, + std::string& resultString); + + Ref decodeRow(int rowNumber, Ref row); + Ref decodeRow(int rowNumber, Ref row, int startGuardBegin, + int startGuardEnd); + Ref decode(Ref image, DecodeHints hints); + + BarcodeFormat getBarcodeFormat(); + }; + } +} + +#endif + +// file: zxing/oned/UPCEReader.h + +#ifndef __UPC_E_READER_H__ +// #define __UPC_E_READER_H__ + +/* + * 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 +// #include + +namespace zxing { + namespace oned { + class UPCEReader : public UPCEANReader { + + private: + static bool determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound); + protected: + bool decodeEnd(Ref row, int endStart, int* endGuardBegin, int* endGuardEnd); + bool checkChecksum(std::string s); + public: + UPCEReader(); + + int decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, + std::string& resultString); + static std::string convertUPCEtoUPCA(std::string upce); + + BarcodeFormat getBarcodeFormat(); + }; + } +} + +#endif + +// file: zxing/qrcode/ErrorCorrectionLevel.h + +#ifndef __ERROR_CORRECTION_LEVEL_H__ +// #define __ERROR_CORRECTION_LEVEL_H__ + +/* + * ErrorCorrectionLevel.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 + +namespace zxing { +namespace qrcode { + +class ErrorCorrectionLevel { +private: + int ordinal_; + int bits_; + std::string name_; + ErrorCorrectionLevel(int inOrdinal, int bits, char const* name); + static ErrorCorrectionLevel *FOR_BITS[]; + static int N_LEVELS; +public: + static ErrorCorrectionLevel L; + static ErrorCorrectionLevel M; + static ErrorCorrectionLevel Q; + static ErrorCorrectionLevel H; + + int ordinal() const; + int bits() const; + std::string const& name() const; + operator std::string const& () const; + + static ErrorCorrectionLevel& forBits(int bits); +}; +} +} + +#endif // __ERROR_CORRECTION_LEVEL_H__ + +// file: zxing/qrcode/FormatInformation.h + +#ifndef __FORMAT_INFORMATION_H__ +// #define __FORMAT_INFORMATION_H__ + +/* + * FormatInformation.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 +// #include +// #include + +namespace zxing { +namespace qrcode { + +class FormatInformation : public Counted { +private: + static int FORMAT_INFO_MASK_QR; + static int FORMAT_INFO_DECODE_LOOKUP[][2]; + static int N_FORMAT_INFO_DECODE_LOOKUPS; + static int BITS_SET_IN_HALF_BYTE[]; + + ErrorCorrectionLevel &errorCorrectionLevel_; + unsigned char dataMask_; + + FormatInformation(int formatInfo); + +public: + static int numBitsDiffering(unsigned int a, unsigned int b); + static Ref decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2); + static Ref doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2); + ErrorCorrectionLevel &getErrorCorrectionLevel(); + unsigned char getDataMask(); + friend bool operator==(const FormatInformation &a, const FormatInformation &b); + friend std::ostream& operator<<(std::ostream& out, const FormatInformation& fi); +}; +} +} + +#endif // __FORMAT_INFORMATION_H__ + +// file: zxing/qrcode/decoder/Decoder.h + +#ifndef __DECODER_H__ +// #define __DECODER_H__ + +/* + * Decoder.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 +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +class Decoder { +private: + ReedSolomonDecoder rsDecoder_; + + void correctErrors(ArrayRef bytes, int numDataCodewords); + +public: + Decoder(); + Ref decode(Ref bits); +}; + +} +} + +#endif // __DECODER_H__ + +// file: zxing/qrcode/QRCodeReader.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __QR_CODE_READER_H__ +// #define __QR_CODE_READER_H__ + +/* + * QRCodeReader.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 +// #include +// #include + +namespace zxing { + namespace qrcode { + + class QRCodeReader : public Reader { + private: + Decoder decoder_; + + protected: + Decoder& getDecoder(); + + public: + QRCodeReader(); + virtual Ref decode(Ref image, DecodeHints hints); + virtual ~QRCodeReader(); + + }; + } +} + +#endif // __QR_CODE_READER_H__ + +// file: zxing/qrcode/Version.h + +#ifndef __VERSION_H__ +// #define __VERSION_H__ + +/* + * Version.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 +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +class ECB { +private: + int count_; + int dataCodewords_; +public: + ECB(int count, int dataCodewords); + int getCount(); + int getDataCodewords(); +}; + +class ECBlocks { +private: + int ecCodewords_; + std::vector ecBlocks_; +public: + ECBlocks(int ecCodewords, ECB *ecBlocks); + ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2); + int getECCodewords(); + std::vector& getECBlocks(); + ~ECBlocks(); +}; + +class Version : public Counted { + +private: + int versionNumber_; + std::vector &alignmentPatternCenters_; + std::vector ecBlocks_; + int totalCodewords_; + Version(int versionNumber, std::vector *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2, + ECBlocks *ecBlocks3, ECBlocks *ecBlocks4); + +public: + static unsigned int VERSION_DECODE_INFO[]; + static int N_VERSION_DECODE_INFOS; + static std::vector > VERSIONS; + + ~Version(); + int getVersionNumber(); + std::vector &getAlignmentPatternCenters(); + int getTotalCodewords(); + int getDimensionForVersion(); + ECBlocks &getECBlocksForLevel(ErrorCorrectionLevel &ecLevel); + static Version *getProvisionalVersionForDimension(int dimension); + static Version *getVersionForNumber(int versionNumber); + static Version *decodeVersionInformation(unsigned int versionBits); + Ref buildFunctionPattern(); + static int buildVersions(); +}; +} +} + +#endif // __VERSION_H__ + +// file: zxing/qrcode/decoder/BitMatrixParser.h + +#ifndef __BIT_MATRIX_PARSER_H__ +// #define __BIT_MATRIX_PARSER_H__ + +/* + * BitMatrixParser.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 +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +class BitMatrixParser : public Counted { +private: + Ref bitMatrix_; + Version *parsedVersion_; + Ref parsedFormatInfo_; + + int copyBit(size_t x, size_t y, int versionBits); + +public: + BitMatrixParser(Ref bitMatrix); + Ref readFormatInformation(); + Version *readVersion(); + ArrayRef readCodewords(); + +private: + BitMatrixParser(const BitMatrixParser&); + BitMatrixParser& operator =(const BitMatrixParser&); + +}; + +} +} + +#endif // __BIT_MATRIX_PARSER_H__ + +// file: zxing/qrcode/decoder/DataBlock.h + +#ifndef __DATA_BLOCK_H__ +// #define __DATA_BLOCK_H__ + +/* + * DataBlock.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 +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +class DataBlock : public Counted { +private: + int numDataCodewords_; + ArrayRef codewords_; + + DataBlock(int numDataCodewords, ArrayRef codewords); + +public: + static std::vector > + getDataBlocks(ArrayRef rawCodewords, Version *version, ErrorCorrectionLevel &ecLevel); + + int getNumDataCodewords(); + ArrayRef getCodewords(); +}; + +} +} + +#endif // __DATA_BLOCK_H__ + +// file: zxing/qrcode/decoder/DataMask.h + +#ifndef __DATA_MASK_H__ +// #define __DATA_MASK_H__ + +/* + * DataMask.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 +// #include +// #include + +// #include + +namespace zxing { +namespace qrcode { + +class DataMask : public Counted { +private: + static std::vector > DATA_MASKS; + +protected: + +public: + static int buildDataMasks(); + DataMask(); + virtual ~DataMask(); + void unmaskBitMatrix(BitMatrix& matrix, size_t dimension); + virtual bool isMasked(size_t x, size_t y) = 0; + static DataMask& forReference(int reference); +}; + +} +} + +#endif // __DATA_MASK_H__ + +// file: zxing/qrcode/decoder/Mode.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __MODE_H__ +// #define __MODE_H__ + +/* + * Mode.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 +// #include + +namespace zxing { +namespace qrcode { + +class Mode { +private: + int characterCountBitsForVersions0To9_; + int characterCountBitsForVersions10To26_; + int characterCountBitsForVersions27AndHigher_; + int bits_; + std::string name_; + + Mode(int cbv0_9, int cbv10_26, int cbv27, int bits, char const* name); + +public: + static Mode TERMINATOR; + static Mode NUMERIC; + static Mode ALPHANUMERIC; + static Mode STRUCTURED_APPEND; + static Mode BYTE; + static Mode ECI; + static Mode KANJI; + static Mode FNC1_FIRST_POSITION; + static Mode FNC1_SECOND_POSITION; + static Mode HANZI; + + static Mode& forBits(int bits); + int getCharacterCountBits(Version *version); +}; +} +} + +#endif // __MODE_H__ + +// file: zxing/common/ECI.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __ECI__ +#define __ECI__ + +/* + * Copyright 2008-2011 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. + */ + +namespace zxing { + namespace common { + class ECI; + } +} +class zxing::common::ECI { +private: + const int value; + +protected: + ECI(int value); + +public: + int getValue() const; + + static ECI* getECIByValue(int value); +}; + +#endif + +// file: zxing/common/CharacterSetECI.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __CHARACTERSET_ECI__ +#define __CHARACTERSET_ECI__ + +/* + * Copyright 2008-2011 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 +// #include +// #include + +namespace zxing { + namespace common { + class CharacterSetECI; + } +} + +class zxing::common::CharacterSetECI : public ECI { +private: + static std::map VALUE_TO_ECI; + static std::map NAME_TO_ECI; + static const bool inited; + static bool init_tables(); + + char const* const encodingName; + + CharacterSetECI(int value, char const* encodingName); + + static void addCharacterSet(int value, char const* encodingName); + static void addCharacterSet(int value, char const* const* encodingNames); + +public: + char const* getEncodingName(); + + static CharacterSetECI* getCharacterSetECIByValue(int value); + static CharacterSetECI* getCharacterSetECIByName(std::string const& name); +}; + +#endif + +// file: zxing/qrcode/decoder/DecodedBitStreamParser.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __DECODED_BIT_STREAM_PARSER_H__ +// #define __DECODED_BIT_STREAM_PARSER_H__ + +/* + * DecodedBitStreamParser.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 +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +class DecodedBitStreamParser { +public: + typedef std::map Hashtable; + +private: + static char const ALPHANUMERIC_CHARS[]; + static char toAlphaNumericChar(size_t value); + + static void decodeHanziSegment(Ref bits, std::string &result, int count); + static void decodeKanjiSegment(Ref bits, std::string &result, int count); + static void decodeByteSegment(Ref bits, std::string &result, int count); + static void decodeByteSegment(Ref bits_, + std::string& result, + int count, + zxing::common::CharacterSetECI* currentCharacterSetECI, + ArrayRef< ArrayRef >& byteSegments, + Hashtable const& hints); + static void decodeAlphanumericSegment(Ref bits, std::string &result, int count, bool fc1InEffect); + static void decodeNumericSegment(Ref bits, std::string &result, int count); + + static void append(std::string &ost, const unsigned char *bufIn, size_t nIn, const char *src); + static void append(std::string &ost, std::string const& in, const char *src); + +public: + static Ref decode(ArrayRef bytes, + Version *version, + ErrorCorrectionLevel const& ecLevel, + Hashtable const& hints); +}; + +} +} + +#endif // __DECODED_BIT_STREAM_PARSER_H__ + +// file: zxing/qrcode/detector/AlignmentPattern.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __ALIGNMENT_PATTERN_H__ +// #define __ALIGNMENT_PATTERN_H__ + +/* + * AlignmentPattern.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 +// #include + +namespace zxing { + namespace qrcode { + + class AlignmentPattern : public ResultPoint { + private: + float estimatedModuleSize_; + + public: + AlignmentPattern(float posX, float posY, float estimatedModuleSize); + bool aboutEquals(float moduleSize, float i, float j) const; + Ref combineEstimate(float i, float j, + float newModuleSize) const; + }; + + } +} + +#endif // __ALIGNMENT_PATTERN_H__ + +// file: zxing/qrcode/detector/AlignmentPatternFinder.h + +#ifndef __ALIGNMENT_PATTERN_FINDER_H__ +// #define __ALIGNMENT_PATTERN_FINDER_H__ + +/* + * AlignmentPatternFinder.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 "AlignmentPattern.h" +// #include +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +class AlignmentPatternFinder : public Counted { +private: + static int CENTER_QUORUM; + static int MIN_SKIP; + static int MAX_MODULES; + + Ref image_; + std::vector *possibleCenters_; + size_t startX_; + size_t startY_; + size_t width_; + size_t height_; + float moduleSize_; + + static float centerFromEnd(std::vector &stateCount, int end); + bool foundPatternCross(std::vector &stateCount); + + float crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal); + + Ref handlePossibleCenter(std::vector &stateCount, size_t i, size_t j); + +public: + AlignmentPatternFinder(Ref image, size_t startX, size_t startY, size_t width, size_t height, + float moduleSize, Refconst& callback); + ~AlignmentPatternFinder(); + Ref find(); + +private: + AlignmentPatternFinder(const AlignmentPatternFinder&); + AlignmentPatternFinder& operator =(const AlignmentPatternFinder&); + + Ref callback_; +}; +} +} + +#endif // __ALIGNMENT_PATTERN_FINDER_H__ + +// file: zxing/qrcode/detector/FinderPattern.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __FINDER_PATTERN_H__ +// #define __FINDER_PATTERN_H__ + +/* + * FinderPattern.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 +// #include + +namespace zxing { + namespace qrcode { + + class FinderPattern : public ResultPoint { + private: + float estimatedModuleSize_; + int count_; + + public: + FinderPattern(float posX, float posY, float estimatedModuleSize); + FinderPattern(float posX, float posY, float estimatedModuleSize, int count); + int getCount() const; + float getEstimatedModuleSize() const; + void incrementCount(); + bool aboutEquals(float moduleSize, float i, float j) const; + Ref combineEstimate(float i, float j, float newModuleSize) const; + }; + } +} + +#endif // __FINDER_PATTERN_H__ + +// file: zxing/qrcode/detector/FinderPatternInfo.h + +#ifndef __FINDER_PATTERN_INFO_H__ +// #define __FINDER_PATTERN_INFO_H__ + +/* + * FinderPatternInfo.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 +// #include +// #include +// #include + +namespace zxing { +namespace qrcode { + +class FinderPatternInfo : public Counted { +private: + Ref bottomLeft_; + Ref topLeft_; + Ref topRight_; + +public: + FinderPatternInfo(std::vector > patternCenters); + + Ref getBottomLeft(); + Ref getTopLeft(); + Ref getTopRight(); +}; +} +} + +#endif // __FINDER_PATTERN_INFO_H__ + +// file: zxing/qrcode/detector/Detector.h + +#ifndef __DETECTOR_H__ +// #define __DETECTOR_H__ + +/* + * Detector.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 +// #include +// #include +// #include +// #include +// #include +// #include + +namespace zxing { + +class DecodeHints; + +namespace qrcode { + +class Detector : public Counted { +private: + Ref image_; + Ref callback_; + +protected: + Ref getImage(); + + static Ref sampleGrid(Ref image, int dimension, Ref); + static int computeDimension(Ref topLeft, Ref topRight, Ref bottomLeft, + float moduleSize); + float calculateModuleSize(Ref topLeft, Ref topRight, Ref bottomLeft); + float calculateModuleSizeOneWay(Ref pattern, Ref otherPattern); + float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY); + float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY); + Ref findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, + float allowanceFactor); + Ref processFinderPatternInfo(Ref info); +public: + + virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension); + + Detector(Ref image); + Ref detect(DecodeHints const& hints); +}; +} +} + +#endif // __DETECTOR_H__ + +// file: zxing/qrcode/detector/FinderPatternFinder.h + +#ifndef __FINDER_PATTERN_FINDER_H__ +// #define __FINDER_PATTERN_FINDER_H__ + +/* + * FinderPatternFinder.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 +// #include +// #include +// #include +// #include +// #include + +namespace zxing { + +class DecodeHints; + +namespace qrcode { + +class FinderPatternFinder { +private: + static int CENTER_QUORUM; + +protected: + static int MIN_SKIP; + static int MAX_MODULES; + + Ref image_; + std::vector > possibleCenters_; + bool hasSkipped_; + + Ref callback_; + + /** stateCount must be int[5] */ + static float centerFromEnd(int* stateCount, int end); + static bool foundPatternCross(int* stateCount); + + float crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal); + float crossCheckHorizontal(size_t startJ, size_t centerI, int maxCount, int originalStateCountTotal); + + /** stateCount must be int[5] */ + bool handlePossibleCenter(int* stateCount, size_t i, size_t j); + int findRowSkip(); + bool haveMultiplyConfirmedCenters(); + std::vector > selectBestPatterns(); + static std::vector > orderBestPatterns(std::vector > patterns); +public: + static float distance(Ref p1, Ref p2); + FinderPatternFinder(Ref image, Refconst&); + Ref find(DecodeHints const& hints); +}; +} +} + +#endif // __FINDER_PATTERN_FINDER_H__ + +// file: zxing/qrcode/detector/QREdgeDetector.h + +#ifndef __QREDGEDETECTOR_H__ +// #define __QREDGEDETECTOR_H__ +/* + * QREdgeDetector.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 +// #include + +namespace zxing { +namespace qrcode { + +class QREdgeDetector : public Detector { +public: + QREdgeDetector(Ref image); + + virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension); + +private: + Point findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension); + Line findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert); + + Point endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to); + + Ref get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension); +}; + +} +} +#endif // QREDGEDETECTOR_H_ + +// file: zxing/FormatException.h + +#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 + +namespace zxing { + +class FormatException : public ReaderException { +public: + FormatException(); + FormatException(const char *msg); + ~FormatException() throw(); +}; + +} +#endif // __FORMAT_EXCEPTION_H__ + +// file: zxing/NotFoundException.h + +// -*- 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 + +namespace zxing { + + class NotFoundException : public ReaderException { + public: + NotFoundException(const char *msg); + ~NotFoundException() throw(); + }; + +} +#endif // __NOT_FOUND_EXCEPTION_H__ + +// file: zxing/common/StringUtils.h + +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __STRING_UTILS__ +#define __STRING_UTILS__ + +/* + * Copyright (C) 2010-2011 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 +// #include +// #include + +namespace zxing { + namespace common { + class StringUtils; + } +} + +class zxing::common::StringUtils { +private: + static char const* const PLATFORM_DEFAULT_ENCODING; + + StringUtils() {} + +public: + static char const* const ASCII; + static char const* const SHIFT_JIS; + static char const* const GB2312; + static char const* const EUC_JP; + static char const* const UTF8; + static char const* const ISO88591; + static const bool ASSUME_SHIFT_JIS; + + typedef std::map Hashtable; + + static std::string guessEncoding(unsigned char* bytes, int length, Hashtable const& hints); +}; + +#endif + +// file: zxing/common/detector/MonochromeRectangleDetector.h + +#ifndef __MONOCHROMERECTANGLEDETECTOR_H__ +// #define __MONOCHROMERECTANGLEDETECTOR_H__ + +/* + * MonochromeRectangleDetector.h + * y_wmk + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 y_wmk 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 +// #include +// #include +// #include +// #include +// #include + + +namespace zxing { + +struct TwoInts: public Counted { + int start; + int end; +}; + +class MonochromeRectangleDetector : public Counted { +private: + static const int MAX_MODULES = 32; + Ref image_; + +public: + MonochromeRectangleDetector(Ref image) : image_(image) { }; + + std::vector > detect(); + +private: + Ref findCornerFromCenter(int centerX, int deltaX, int left, int right, + int centerY, int deltaY, int top, int bottom, int maxWhiteRun); + + Ref blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, + bool horizontal); + + int max(int a, float b) { return (float) a > b ? a : (int) b;}; +}; +} + +#endif // __MONOCHROMERECTANGLEDETECTOR_H__ + +// file: zxing/common/detector/WhiteRectangleDetector.h + +#ifndef __WHITERECTANGLEDETECTOR_H__ +// #define __WHITERECTANGLEDETECTOR_H__ + +/* + * WhiteRectangleDetector.h + * + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 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 +// #include +// #include +// #include +// #include +// #include + + +namespace zxing { + +class WhiteRectangleDetector : public Counted { + private: + static int INIT_SIZE; + static int CORR; + Ref image_; + int width_; + int height_; + + public: + WhiteRectangleDetector(Ref image); + std::vector > detect(); + + private: + int round(float a); + Ref getBlackPointOnSegment(float aX, float aY, float bX, float bY); + int distanceL2(float aX, float aY, float bX, float bY); + std::vector > centerEdges(Ref y, Ref z, + Ref x, Ref t); + bool containsBlackPoint(int a, int b, int fixed, bool horizontal); +}; +} + +#endif + +// file: zxing/datamatrix/detector/DetectorException.h + +/* + * DetectorException.h + * + * Created on: Aug 26, 2011 + * Author: luiz + */ + +#ifndef DETECTOREXCEPTION_H_ +#define DETECTOREXCEPTION_H_ + +// #include + +namespace zxing { +namespace datamatrix { + +class DetectorException : public Exception { + public: + DetectorException(const char *msg); + virtual ~DetectorException() throw(); +}; +} /* namespace nexxera */ +} /* namespace zxing */ +#endif /* DETECTOREXCEPTION_H_ */ + +// file: zxing/multi/ByQuadrantReader.h + +#ifndef __BY_QUADRANT_READER_H__ +// #define __BY_QUADRANT_READER_H__ + +/* + * Copyright 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 +// #include +// #include +// #include + +namespace zxing { +namespace multi { +class ByQuadrantReader : public Reader { + private: + Reader& delegate_; + + public: + ByQuadrantReader(Reader& delegate); + virtual ~ByQuadrantReader(); + virtual Ref decode(Ref image); + virtual Ref decode(Ref image, DecodeHints hints); +}; +} // End zxing::multi namespace +} // End zxing namespace + +#endif // __BY_QUADRANT_READER_H__ + +// file: zxing/multi/MultipleBarcodeReader.h + +#ifndef __MULTIPLE_BARCODE_READER_H__ +// #define __MULTIPLE_BARCODE_READER_H__ + +/* + * Copyright 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 +// #include +// #include +// #include +// #include + +namespace zxing { +namespace multi { +class MultipleBarcodeReader : public Counted { + protected: + MultipleBarcodeReader() {} + public: + virtual std::vector > decodeMultiple(Ref image); + virtual std::vector > decodeMultiple(Ref image, DecodeHints hints) = 0; + virtual ~MultipleBarcodeReader(); +}; +} // End zxing::multi namespace +} // End zxing namespace + +#endif // __MULTIPLE_BARCODE_READER_H__ + +// file: zxing/multi/GenericMultipleBarcodeReader.h + +#ifndef __GENERIC_MULTIPLE_BARCODE_READER_H__ +// #define __GENERIC_MULTIPLE_BARCODE_READER_H__ + +/* + * Copyright 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 +// #include + +namespace zxing { +namespace multi { +class GenericMultipleBarcodeReader : public MultipleBarcodeReader { + private: + static Ref translateResultPoints(Ref result, + int xOffset, + int yOffset); + void doDecodeMultiple(Ref image, + DecodeHints hints, + std::vector >& results, + int xOffset, + int yOffset); + Reader& delegate_; + static const int MIN_DIMENSION_TO_RECUR = 100; + + public: + GenericMultipleBarcodeReader(Reader& delegate); + virtual ~GenericMultipleBarcodeReader(); + virtual std::vector > decodeMultiple(Ref image, + DecodeHints hints); +}; +} // End zxing::multi namespace +} // End zxing namespace + +#endif // __GENERIC_MULTIPLE_BARCODE_READER_H__ + +// file: zxing/multi/qrcode/QRCodeMultiReader.h + +#ifndef __QRCODE_MULTI_READER_H__ +// #define __QRCODE_MULTI_READER_H__ + +/* + * Copyright 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 +// #include + +namespace zxing { +namespace multi { +class QRCodeMultiReader: public zxing::qrcode::QRCodeReader, public MultipleBarcodeReader { + public: + QRCodeMultiReader(); + virtual ~QRCodeMultiReader(); + virtual std::vector > decodeMultiple(Ref image, DecodeHints hints); +}; +} // End zxing::multi namespace +} // End zxing namespace + +#endif // __QRCODE_MULTI_READER_H__ + +// file: zxing/multi/qrcode/detector/MultiDetector.h + +#ifndef __MULTI_DETECTOR_H__ +// #define __MULTI_DETECTOR_H__ + +/* + * Copyright 2011 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 +// #include +// #include + +namespace zxing { +namespace multi { +class MultiDetector : public zxing::qrcode::Detector { + public: + MultiDetector(Ref image); + virtual ~MultiDetector(); + virtual std::vector > detectMulti(DecodeHints hints); +}; +} // End zxing::multi namespace +} // End zxing namespace + +#endif // __MULTI_DETECTOR_H__ + +// file: zxing/multi/qrcode/detector/MultiFinderPatternFinder.h + +#ifndef __MULTI_FINDER_PATTERN_FINDER_H__ +// #define __MULTI_FINDER_PATTERN_FINDER_H__ + +/* + * Copyright 2011 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 +// #include +// #include + +namespace zxing { +namespace multi { +class MultiFinderPatternFinder : zxing::qrcode::FinderPatternFinder { + private: + std::vector > > selectBestPatterns(); + + static const float MAX_MODULE_COUNT_PER_EDGE; + static const float MIN_MODULE_COUNT_PER_EDGE; + static const float DIFF_MODSIZE_CUTOFF_PERCENT; + static const float DIFF_MODSIZE_CUTOFF; + + public: + MultiFinderPatternFinder(Ref image, Ref resultPointCallback); + virtual ~MultiFinderPatternFinder(); + virtual std::vector > findMulti(DecodeHints const& hints); + + +}; +} +} + +#endif // __MULTI_FINDER_PATTERN_FINDER_H__ + diff --git a/plugins/phonegap-plugin-barcodescanner/src/windows/BarcodeScannerProxy.js b/plugins/phonegap-plugin-barcodescanner/src/windows/BarcodeScannerProxy.js new file mode 100644 index 0000000..b9b29ca --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/windows/BarcodeScannerProxy.js @@ -0,0 +1,672 @@ +/* + * Copyright (c) Microsoft Open Technologies, Inc. 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. + */ + +var urlutil = require('cordova/urlutil'); + +var CAMERA_STREAM_STATE_CHECK_RETRY_TIMEOUT = 200; // milliseconds +var OPERATION_IS_IN_PROGRESS = -2147024567; +var INITIAL_FOCUS_DELAY = 200; // milliseconds +var CHECK_PLAYING_TIMEOUT = 100; // milliseconds + +/** + * List of supported barcode formats from ZXing library. Used to return format + * name instead of number code as per plugin spec. + * + * @enum {String} + */ +var BARCODE_FORMAT = { + 1: 'AZTEC', + 2: 'CODABAR', + 4: 'CODE_39', + 8: 'CODE_93', + 16: 'CODE_128', + 32: 'DATA_MATRIX', + 64: 'EAN_8', + 128: 'EAN_13', + 256: 'ITF', + 512: 'MAXICODE', + 1024: 'PDF_417', + 2048: 'QR_CODE', + 4096: 'RSS_14', + 8192: 'RSS_EXPANDED', + 16384: 'UPC_A', + 32768: 'UPC_E', + 61918: 'All_1D', + 65536: 'UPC_EAN_EXTENSION', + 131072: 'MSI', + 262144: 'PLESSEY' +}; + +/** + * Detects the first appropriate camera located at the back panel of device. If + * there is no back cameras, returns the first available. + * + * @returns {Promise} Camera id + */ +function findCamera() { + var Devices = Windows.Devices.Enumeration; + + // Enumerate cameras and add them to the list + return Devices.DeviceInformation.findAllAsync(Devices.DeviceClass.videoCapture) + .then(function (cameras) { + + if (!cameras || cameras.length === 0) { + throw new Error("No cameras found"); + } + + var backCameras = cameras.filter(function (camera) { + return camera.enclosureLocation && camera.enclosureLocation.panel === Devices.Panel.back; + }); + + // If there is back cameras, return the id of the first, + // otherwise take the first available device's id + return (backCameras[0] || cameras[0]).id; + }); +} + +/** + * @param {Windows.Graphics.Display.DisplayOrientations} displayOrientation + * @return {Number} + */ +function videoPreviewRotationLookup(displayOrientation, isMirrored) { + var degreesToRotate; + + switch (displayOrientation) { + case Windows.Graphics.Display.DisplayOrientations.landscape: + degreesToRotate = 0; + break; + case Windows.Graphics.Display.DisplayOrientations.portrait: + if (isMirrored) { + degreesToRotate = 270; + } else { + degreesToRotate = 90; + } + break; + case Windows.Graphics.Display.DisplayOrientations.landscapeFlipped: + degreesToRotate = 180; + break; + case Windows.Graphics.Display.DisplayOrientations.portraitFlipped: + if (isMirrored) { + degreesToRotate = 90; + } else { + degreesToRotate = 270; + } + break; + default: + degreesToRotate = 0; + break; + } + + return degreesToRotate; +} + +/** + * The pure JS implementation of barcode reader from WinRTBarcodeReader.winmd. + * Works only on Windows 10 devices and more efficient than original one. + * + * @class {BarcodeReader} + */ +function BarcodeReader () { + this._promise = null; + this._cancelled = false; +} + +/** + * Returns an instance of Barcode reader, depending on capabilities of Media + * Capture API + * + * @static + * @constructs {BarcodeReader} + * + * @param {MediaCapture} mediaCaptureInstance Instance of + * Windows.Media.Capture.MediaCapture class + * + * @return {BarcodeReader} BarcodeReader instance that could be used for + * scanning + */ +BarcodeReader.get = function (mediaCaptureInstance) { + if (mediaCaptureInstance.getPreviewFrameAsync && ZXing.BarcodeReader) { + return new BarcodeReader(); + } + + // If there is no corresponding API (Win8/8.1/Phone8.1) use old approach with WinMD library + return new WinRTBarcodeReader.Reader(); + +}; + +/** + * Initializes instance of reader. + * + * @param {MediaCapture} capture Instance of + * Windows.Media.Capture.MediaCapture class, used for acquiring images/ video + * stream for barcode scanner. + * @param {Number} width Video/image frame width + * @param {Number} height Video/image frame height + */ +BarcodeReader.prototype.init = function (capture, width, height) { + this._capture = capture; + this._width = width; + this._height = height; + this._zxingReader = new ZXing.BarcodeReader(); +}; + +/** + * Starts barcode search routines asyncronously. + * + * @return {Promise} barcode scan result or null if search + * cancelled. + */ +BarcodeReader.prototype.readCode = function () { + + /** + * Grabs a frame from preview stream uning Win10-only API and tries to + * get a barcode using zxing reader provided. If there is no barcode + * found, returns null. + */ + function scanBarcodeAsync(mediaCapture, zxingReader, frameWidth, frameHeight) { + // Shortcuts for namespaces + var Imaging = Windows.Graphics.Imaging; + var Streams = Windows.Storage.Streams; + + var frame = new Windows.Media.VideoFrame(Imaging.BitmapPixelFormat.bgra8, frameWidth, frameHeight); + return mediaCapture.getPreviewFrameAsync(frame) + .then(function (capturedFrame) { + + // Copy captured frame to buffer for further deserialization + var bitmap = capturedFrame.softwareBitmap; + var rawBuffer = new Streams.Buffer(bitmap.pixelWidth * bitmap.pixelHeight * 4); + capturedFrame.softwareBitmap.copyToBuffer(rawBuffer); + capturedFrame.close(); + + // Get raw pixel data from buffer + var data = new Uint8Array(rawBuffer.length); + var dataReader = Streams.DataReader.fromBuffer(rawBuffer); + dataReader.readBytes(data); + dataReader.close(); + + return zxingReader.decode(data, frameWidth, frameHeight, ZXing.BitmapFormat.bgra32); + }); + } + + var self = this; + return scanBarcodeAsync(this._capture, this._zxingReader, this._width, this._height) + .then(function (result) { + if (self._cancelled) + return null; + + return result || (self._promise = self.readCode()); + }); +}; + +/** + * Stops barcode search + */ +BarcodeReader.prototype.stop = function () { + this._cancelled = true; +}; + +function degreesToRotation(degrees) { + switch (degrees) { + // portrait + case 90: + return Windows.Media.Capture.VideoRotation.clockwise90Degrees; + // landscape + case 0: + return Windows.Media.Capture.VideoRotation.none; + // portrait-flipped + case 270: + return Windows.Media.Capture.VideoRotation.clockwise270Degrees; + // landscape-flipped + case 180: + return Windows.Media.Capture.VideoRotation.clockwise180Degrees; + default: + // Falling back to portrait default + return Windows.Media.Capture.VideoRotation.clockwise90Degrees; + } +} + +module.exports = { + + /** + * Scans image via device camera and retieves barcode from it. + * @param {function} success Success callback + * @param {function} fail Error callback + * @param {array} args Arguments array + */ + scan: function (success, fail, args) { + var capturePreview, + capturePreviewAlignmentMark, + captureCancelButton, + navigationButtonsDiv, + previewMirroring, + closeButton, + capture, + reader; + + // Save call state for suspend/resume + BarcodeReader.scanCallArgs = { + success: success, + fail: fail, + args: args + }; + + function updatePreviewForRotation(evt) { + if (!capture) { + return; + } + + var displayInformation = (evt && evt.target) || Windows.Graphics.Display.DisplayInformation.getForCurrentView(); + var currentOrientation = displayInformation.currentOrientation; + + previewMirroring = capture.getPreviewMirroring(); + + // Lookup up the rotation degrees. + var rotDegree = videoPreviewRotationLookup(currentOrientation, previewMirroring); + + capture.setPreviewRotation(degreesToRotation(rotDegree)); + return WinJS.Promise.as(); + } + + /** + * Creates a preview frame and necessary objects + */ + function createPreview() { + + // Create fullscreen preview + var capturePreviewFrameStyle = document.createElement('link'); + capturePreviewFrameStyle.rel = "stylesheet"; + capturePreviewFrameStyle.type = "text/css"; + capturePreviewFrameStyle.href = urlutil.makeAbsolute("/www/css/plugin-barcodeScanner.css"); + + document.head.appendChild(capturePreviewFrameStyle); + + capturePreviewFrame = document.createElement('div'); + capturePreviewFrame.className = "barcode-scanner-wrap"; + + capturePreview = document.createElement("video"); + capturePreview.className = "barcode-scanner-preview"; + capturePreview.addEventListener('click', function () { + focus(); + }); + + capturePreviewAlignmentMark = document.createElement('div'); + capturePreviewAlignmentMark.className = "barcode-scanner-mark"; + + navigationButtonsDiv = document.createElement("div"); + navigationButtonsDiv.className = "barcode-scanner-app-bar"; + navigationButtonsDiv.onclick = function (e) { + e.cancelBubble = true; + }; + + closeButton = document.createElement("div"); + closeButton.innerText = "close"; + closeButton.className = "app-bar-action action-close"; + navigationButtonsDiv.appendChild(closeButton); + + BarcodeReader.scanCancelled = false; + closeButton.addEventListener("click", cancelPreview, false); + document.addEventListener('backbutton', cancelPreview, false); + + [capturePreview, capturePreviewAlignmentMark, navigationButtonsDiv].forEach(function (element) { + capturePreviewFrame.appendChild(element); + }); + } + + function focus(controller) { + + var result = WinJS.Promise.wrap(); + + if (!capturePreview || capturePreview.paused) { + // If the preview is not yet playing, there is no sense in running focus + return result; + } + + if (!controller) { + try { + controller = capture && capture.videoDeviceController; + } catch (err) { + console.log('Failed to access focus control for current camera: ' + err); + return result; + } + } + + if (!controller.focusControl || !controller.focusControl.supported) { + console.log('Focus control for current camera is not supported'); + return result; + } + + // Multiple calls to focusAsync leads to internal focusing hang on some Windows Phone 8.1 devices + if (controller.focusControl.focusState === Windows.Media.Devices.MediaCaptureFocusState.searching) { + return result; + } + + // The delay prevents focus hang on slow devices + return WinJS.Promise.timeout(INITIAL_FOCUS_DELAY) + .then(function () { + try { + return controller.focusControl.focusAsync().then(function () { + return result; + }, function (e) { + // This happens on mutliple taps + if (e.number !== OPERATION_IS_IN_PROGRESS) { + console.error('focusAsync failed: ' + e); + return WinJS.Promise.wrapError(e); + } + return result; + }); + } catch (e) { + // This happens on mutliple taps + if (e.number !== OPERATION_IS_IN_PROGRESS) { + console.error('focusAsync failed: ' + e); + return WinJS.Promise.wrapError(e); + } + return result; + } + }); + } + + function setupFocus(focusControl) { + + function supportsFocusMode(mode) { + return focusControl.supportedFocusModes.indexOf(mode).returnValue; + } + + if (!focusControl || !focusControl.supported || !focusControl.configure) { + return WinJS.Promise.wrap(); + } + + var FocusMode = Windows.Media.Devices.FocusMode; + var focusConfig = new Windows.Media.Devices.FocusSettings(); + focusConfig.autoFocusRange = Windows.Media.Devices.AutoFocusRange.normal; + + // Determine a focus position if the focus search fails: + focusConfig.disableDriverFallback = false; + + if (supportsFocusMode(FocusMode.continuous)) { + console.log("Device supports continuous focus mode"); + focusConfig.mode = FocusMode.continuous; + } else if (supportsFocusMode(FocusMode.auto)) { + console.log("Device doesn\'t support continuous focus mode, switching to autofocus mode"); + focusConfig.mode = FocusMode.auto; + } + + focusControl.configure(focusConfig); + + // Continuous focus should start only after preview has started. See 'Remarks' at + // https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.devices.focuscontrol.configure.aspx + function waitForIsPlaying() { + var isPlaying = !capturePreview.paused && !capturePreview.ended && capturePreview.readyState > 2; + + if (!isPlaying) { + return WinJS.Promise.timeout(CHECK_PLAYING_TIMEOUT) + .then(function () { + return waitForIsPlaying(); + }); + } + + return focus(); + } + + return waitForIsPlaying(); + } + + function disableZoomAndScroll() { + document.body.classList.add('no-zoom'); + document.body.classList.add('no-scroll'); + } + + function enableZoomAndScroll() { + document.body.classList.remove('no-zoom'); + document.body.classList.remove('no-scroll'); + } + + /** + * Starts stream transmission to preview frame and then run barcode search + */ + function startPreview() { + return findCamera() + .then(function (id) { + var captureSettings = new Windows.Media.Capture.MediaCaptureInitializationSettings(); + captureSettings.streamingCaptureMode = Windows.Media.Capture.StreamingCaptureMode.video; + captureSettings.photoCaptureSource = Windows.Media.Capture.PhotoCaptureSource.videoPreview; + captureSettings.videoDeviceId = id; + + capture = new Windows.Media.Capture.MediaCapture(); + return capture.initializeAsync(captureSettings); + }) + .then(function () { + + var controller = capture.videoDeviceController; + var deviceProps = controller.getAvailableMediaStreamProperties(Windows.Media.Capture.MediaStreamType.videoRecord); + + deviceProps = Array.prototype.slice.call(deviceProps); + deviceProps = deviceProps.filter(function (prop) { + // filter out streams with "unknown" subtype - causes errors on some devices + return prop.subtype !== "Unknown"; + }).sort(function (propA, propB) { + // sort properties by resolution + return propB.width - propA.width; + }); + + var maxResProps = deviceProps[0]; + return controller.setMediaStreamPropertiesAsync(Windows.Media.Capture.MediaStreamType.videoRecord, maxResProps) + .then(function () { + return { + capture: capture, + width: maxResProps.width, + height: maxResProps.height + }; + }); + }) + .then(function (captureSettings) { + + capturePreview.msZoom = true; + capturePreview.src = URL.createObjectURL(capture); + capturePreview.play(); + + // Insert preview frame and controls into page + document.body.appendChild(capturePreviewFrame); + + disableZoomAndScroll(); + + return setupFocus(captureSettings.capture.videoDeviceController.focusControl) + .then(function () { + Windows.Graphics.Display.DisplayInformation.getForCurrentView().addEventListener("orientationchanged", updatePreviewForRotation, false); + return updatePreviewForRotation(); + }) + .then(function () { + + if (!Windows.Media.Devices.CameraStreamState) { + // CameraStreamState is available starting with Windows 10 so skip this check for 8.1 + // https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.devices.camerastreamstate + return WinJS.Promise.as(); + } + + function checkCameraStreamState() { + if (capture.cameraStreamState !== Windows.Media.Devices.CameraStreamState.streaming) { + + // Using loop as MediaCapture.CameraStreamStateChanged does not fire with CameraStreamState.streaming state. + return WinJS.Promise.timeout(CAMERA_STREAM_STATE_CHECK_RETRY_TIMEOUT) + .then(function () { + return checkCameraStreamState(); + }); + } + + return WinJS.Promise.as(); + } + + // Ensure CameraStreamState is Streaming + return checkCameraStreamState(); + }) + .then(function () { + return captureSettings; + }); + }); + } + + /** + * Removes preview frame and corresponding objects from window + */ + function destroyPreview() { + var promise = WinJS.Promise.as(); + + Windows.Graphics.Display.DisplayInformation.getForCurrentView().removeEventListener("orientationchanged", updatePreviewForRotation, false); + document.removeEventListener('backbutton', cancelPreview); + + capturePreview.pause(); + capturePreview.src = null; + + if (capturePreviewFrame) { + document.body.removeChild(capturePreviewFrame); + } + capturePreviewFrame = null; + + reader && reader.stop(); + reader = null; + + if (capture) { + promise = capture.stopRecordAsync(); + } + capture = null; + + enableZoomAndScroll(); + + return promise; + } + + /** + * Stops preview and then call success callback with cancelled=true + * See https://github.com/phonegap-build/BarcodeScanner#using-the-plugin + */ + function cancelPreview() { + BarcodeReader.scanCancelled = true; + reader && reader.stop(); + } + + function checkCancelled() { + if (BarcodeReader.scanCancelled || BarcodeReader.suspended) { + throw new Error('Canceled'); + } + } + + BarcodeReader.scanPromise = WinJS.Promise.wrap(createPreview()) + .then(function () { + checkCancelled(); + return startPreview(); + }) + .then(function (captureSettings) { + checkCancelled(); + reader = BarcodeReader.get(captureSettings.capture); + reader.init(captureSettings.capture, captureSettings.width, captureSettings.height); + + // Add a small timeout before capturing first frame otherwise + // we would get an 'Invalid state' error from 'getPreviewFrameAsync' + return WinJS.Promise.timeout(200) + .then(function () { + checkCancelled(); + return reader.readCode(); + }); + }) + .then(function (result) { + // Suppress null result (cancel) on suspending + if (BarcodeReader.suspended) { + return; + } + + destroyPreview(); + success({ + text: result && result.text, + format: result && BARCODE_FORMAT[result.barcodeFormat], + cancelled: !result + }); + }, function (error) { + // Suppress null result (cancel) on suspending + if (BarcodeReader.suspended) { + return; + } + + destroyPreview(); + if (error.message == 'Canceled') { + success({ + cancelled: true + }); + } else { + fail(error); + } + }); + + BarcodeReader.videoPreviewIsVisible = function () { + return capturePreviewFrame !== null; + } + + BarcodeReader.destroyPreview = destroyPreview; + }, + + /** + * Encodes specified data into barcode + * @param {function} success Success callback + * @param {function} fail Error callback + * @param {array} args Arguments array + */ + encode: function (success, fail, args) { + fail("Not implemented yet"); + } +}; + +var app = WinJS.Application; + +function waitForScanEnd() { + return BarcodeReader.scanPromise || WinJS.Promise.as(); +} + +function suspend(args) { + BarcodeReader.suspended = true; + if (args) { + args.setPromise(BarcodeReader.destroyPreview() + .then(waitForScanEnd, waitForScanEnd)); + } else { + BarcodeReader.destroyPreview(); + } +} + +function resume() { + BarcodeReader.suspended = false; + module.exports.scan(BarcodeReader.scanCallArgs.success, BarcodeReader.scanCallArgs.fail, BarcodeReader.scanCallArgs.args); +} + +function onVisibilityChanged() { + if (document.visibilityState === 'hidden' + && BarcodeReader.videoPreviewIsVisible && BarcodeReader.videoPreviewIsVisible() && BarcodeReader.destroyPreview) { + suspend(); + } else if (BarcodeReader.suspended) { + resume(); + } +} + +// Windows 8.1 projects +document.addEventListener('msvisibilitychange', onVisibilityChanged); +// Windows 10 projects +document.addEventListener('visibilitychange', onVisibilityChanged); + +// About to be suspended +app.addEventListener('checkpoint', function (args) { + if (BarcodeReader.videoPreviewIsVisible && BarcodeReader.videoPreviewIsVisible() && BarcodeReader.destroyPreview) { + suspend(args); + } +}); + +// Resuming from a user suspension +Windows.UI.WebUI.WebUIApplication.addEventListener("resuming", function () { + if (BarcodeReader.suspended) { + resume(); + } +}, false); + +require("cordova/exec/proxy").add("BarcodeScanner", module.exports); diff --git a/plugins/phonegap-plugin-barcodescanner/src/windows/assets/plugin-barcodeScanner.css b/plugins/phonegap-plugin-barcodescanner/src/windows/assets/plugin-barcodeScanner.css new file mode 100644 index 0000000..e990703 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/windows/assets/plugin-barcodeScanner.css @@ -0,0 +1,89 @@ +.barcode-scanner-wrap { + margin: 0; + padding: 0; + outline: 0; + font-size: 100%; + vertical-align: baseline; + background: 0 0 black; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 9999999; + -ms-user-select: none; +} + +.barcode-scanner-preview { + width: auto; + height: calc(100% - 70px); + position: absolute; + top: calc(50% - 35px); + left: 50%; + transform: translateX(-50%) translateY(-50%); +} + +.barcode-scanner-mark { + position: absolute; + left: 0; + top: 50%; + width: 100%; + height: 3px; + background: red; + z-index: 9999999; +} + +.barcode-scanner-app-bar { + height: 70px; + width: 100%; + padding-top: 10px; + z-index: 9999999; + text-align: center; + user-select: none; + position: absolute; + bottom: 0px; +} + +.app-bar-action { + width: 40px; + height: 40px; + margin: 0 auto; + font-family: "Segoe UI Symbol"; + color: white; + font-size: 12px; + text-transform: lowercase; + text-align: center; + cursor: default; +} + +@media all and (orientation: landscape) { + .app-bar-action { + float: right; + margin-right: 20px; + } +} + +.app-bar-action::before { + font-size: 28px; + display: block; + height: 36px; +} + +.action-close::before { + content: "\E0C7"; + /* close icon is larger so we re-size it to fit other icons */ + font-size: 20px; + line-height: 40px; +} + +.action-close:hover::before { + content: "\E0CA"; +} + +.no-zoom { + -ms-content-zooming: none; +} + +.no-scroll { + overflow: hidden; +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/ANY/ZXing.winmd b/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/ANY/ZXing.winmd new file mode 100644 index 0000000..f8d3a68 Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/ANY/ZXing.winmd differ diff --git a/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/ARM/ZXing.winmd b/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/ARM/ZXing.winmd new file mode 100644 index 0000000..173b0cc Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/ARM/ZXing.winmd differ diff --git a/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/x64/ZXing.winmd b/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/x64/ZXing.winmd new file mode 100644 index 0000000..1f4cca0 Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/x64/ZXing.winmd differ diff --git a/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/x86/ZXing.winmd b/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/x86/ZXing.winmd new file mode 100644 index 0000000..e785f95 Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/windows/lib.UW/x86/ZXing.winmd differ diff --git a/plugins/phonegap-plugin-barcodescanner/src/windows/lib/Properties/AssemblyInfo.cs b/plugins/phonegap-plugin-barcodescanner/src/windows/lib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4ee65dd --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/windows/lib/Properties/AssemblyInfo.cs @@ -0,0 +1,39 @@ +/* + * Copyright (c) Microsoft Open Technologies, Inc. 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. + */ + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("WinRTBarcodeReader")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("WinRTBarcodeReader")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/plugins/phonegap-plugin-barcodescanner/src/windows/lib/Reader.cs b/plugins/phonegap-plugin-barcodescanner/src/windows/lib/Reader.cs new file mode 100644 index 0000000..4a11938 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/windows/lib/Reader.cs @@ -0,0 +1,173 @@ +/* + * Copyright (c) Microsoft Open Technologies, Inc. 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 WinRTBarcodeReader +{ + using System; + using System.Threading; + using System.Threading.Tasks; + + using Windows.Foundation; + using Windows.Graphics.Imaging; + using Windows.Media.Capture; + using Windows.Media.MediaProperties; + using Windows.Storage.Streams; + + using ZXing; + + /// + /// Defines the Reader type, that perform barcode search asynchronously. + /// + public sealed class Reader + { + #region Private fields + + /// + /// Data reader, used to create bitmap array. + /// + private BarcodeReader barcodeReader; + + /// + /// The cancel search flag. + /// + private CancellationTokenSource cancelSearch; + + /// + /// MediaCapture instance, used for barcode search. + /// + private MediaCapture capture; + + /// + /// Encoding properties for mediaCapture object. + /// + private ImageEncodingProperties encodingProps; + + /// + /// Flag that indicates successful barcode search. + /// + private bool barcodeFoundOrCancelled; + + /// + /// Image stream for MediaCapture content. + /// + private InMemoryRandomAccessStream imageStream; + + #endregion + + #region Constructor + + /// + /// Initializes a new instance of the class. + /// + /// MediaCapture instance. + /// Capture frame width. + /// Capture frame height. + public void Init(MediaCapture capture, uint width, uint height) + { + this.capture = capture; + encodingProps = ImageEncodingProperties.CreateJpeg(); + encodingProps.Width = width; + encodingProps.Height = height; + + barcodeReader = new BarcodeReader {Options = {TryHarder = true}}; + cancelSearch = new CancellationTokenSource(); + } + + #endregion + + #region Public methods + + /// + /// Perform async MediaCapture analysis and searches for barcode. + /// + /// IAsyncOperation object + public IAsyncOperation ReadCode() + { + return this.Read().AsAsyncOperation(); + } + + /// + /// Send signal to stop barcode search. + /// + public void Stop() + { + this.cancelSearch.Cancel(); + } + + #endregion + + #region Private methods + + /// + /// Perform async MediaCapture analysis and searches for barcode. + /// + /// Task object + private async Task Read() + { + Result result = null; + try + { + while (result == null) + { + result = await GetCameraImage(cancelSearch.Token); + } + } + catch (OperationCanceledException) { } + + return result; + } + + /// + /// Perform image capture from mediaCapture object + /// + /// + /// The cancel Token. + /// + /// + /// Decoded barcode string. + /// + private async Task GetCameraImage(CancellationToken cancelToken) + { + if (cancelToken.IsCancellationRequested) + { + throw new OperationCanceledException(cancelToken); + } + + imageStream = new InMemoryRandomAccessStream(); + + await capture.CapturePhotoToStreamAsync(encodingProps, imageStream); + await imageStream.FlushAsync(); + + var decoder = await BitmapDecoder.CreateAsync(imageStream); + + byte[] pixels = + (await + decoder.GetPixelDataAsync(BitmapPixelFormat.Rgba8, + BitmapAlphaMode.Ignore, + new BitmapTransform(), + ExifOrientationMode.IgnoreExifOrientation, + ColorManagementMode.DoNotColorManage)).DetachPixelData(); + + const BitmapFormat format = BitmapFormat.RGB32; + + imageStream.Dispose(); + + var result = + await + Task.Run( + () => barcodeReader.Decode(pixels, (int) decoder.PixelWidth, (int) decoder.PixelHeight, format), + cancelToken); + + return result; + } + + #endregion + } +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/windows/lib/WinRTBarcodeReader.csproj b/plugins/phonegap-plugin-barcodescanner/src/windows/lib/WinRTBarcodeReader.csproj new file mode 100644 index 0000000..7d3c2b3 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/windows/lib/WinRTBarcodeReader.csproj @@ -0,0 +1,137 @@ + + + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + WinRTBarcodeReader + {01412F36-3781-4AF0-903C-ACEA7552C99C} + winmdobj + Properties + WinRTBarcodeReader + WinRTBarcodeReader + en-US + 512 + {BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 8.1 + 12 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE;NETFX_CORE + prompt + 4 + + + false + None + true + bin\Release\ + TRACE;NETFX_CORE + prompt + 4 + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE + true + ;2008 + false + None + ARM + false + prompt + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE + true + ;2008 + false + None + x64 + false + prompt + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE + true + ;2008 + false + None + x86 + false + prompt + true + + + + + + + + ZXing.winmd + + + + 12.0 + + + + \ No newline at end of file diff --git a/plugins/phonegap-plugin-barcodescanner/src/windows/lib/ZXing.winmd b/plugins/phonegap-plugin-barcodescanner/src/windows/lib/ZXing.winmd new file mode 100644 index 0000000..ea21bd7 Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/windows/lib/ZXing.winmd differ diff --git a/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScanner.cs b/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScanner.cs new file mode 100644 index 0000000..fc2f540 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScanner.cs @@ -0,0 +1,117 @@ +/* + * Copyright (c) Microsoft Open Technologies, Inc. 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 WPCordovaClassLib.Cordova.Commands +{ + using System.Runtime.Serialization; + using Microsoft.Phone.Tasks; + using WPCordovaClassLib.Cordova.JSON; + using ZXing; + + /// + /// Class that extends cordova with Barcode scanner functionality. + /// + public class BarcodeScanner : BaseCommand + { + /// + /// Scans the barcode. + /// + /// Parameter is ignored. + public void scan(string options) + { + var task = new BarcodeScannerTask(); + task.Completed += this.TaskCompleted; + task.Show(); + } + + /// + /// Handler for barcode scanner task. + /// + /// The sender. + /// The scan result. + private void TaskCompleted(object sender, BarcodeScannerTask.ScanResult e) + { + PluginResult result; + + switch (e.TaskResult) + { + case TaskResult.OK: + result = new PluginResult(PluginResult.Status.OK); + result.Message = JsonHelper.Serialize(new BarcodeResult(e.Barcode)); + break; + case TaskResult.Cancel: + // If scan is cancelled we return PluginResult.Status.OK with Message contains cancelled: true + // See plugin docs https://github.com/MSOpenTech/BarcodeScanner#using-the-plugin + result = new PluginResult(PluginResult.Status.OK); + result.Message = JsonHelper.Serialize(new BarcodeResult()); + break; + default: + result = new PluginResult(PluginResult.Status.ERROR); + break; + } + + this.DispatchCommandResult(result); + } + } + + /// + /// Represents the barcode scan result, that should be serialized and passed to JS layer. + /// + [DataContract] + public sealed class BarcodeResult + { + /// + /// Initializes a new instance of the class. + /// + /// if set to true [canceled]. + public BarcodeResult(bool canceled = true) + { + this.Cancelled = canceled; + } + + /// + /// Initializes a new instance of the class. + /// + /// The barcode result. + public BarcodeResult(Result barcode) + { + this.Cancelled = false; + this.Format = barcode.BarcodeFormat.ToString(); + this.Text = barcode.Text; + } + + /// + /// Gets a value indicating whether barcode scan is cancelled. + /// + /// + /// true if cancelled; otherwise, false. + /// + [DataMember(Name = "cancelled")] + public bool Cancelled { get; private set; } + + /// + /// Gets the format of barcode. + /// + /// + /// The barcode format. + /// + [DataMember(Name = "format")] + public string Format { get; private set; } + + /// + /// Gets the barcode text. + /// + /// + /// The barcode text. + /// + [DataMember(Name = "text")] + public string Text { get; private set; } + } +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerTask.cs b/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerTask.cs new file mode 100644 index 0000000..d1bbdd7 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerTask.cs @@ -0,0 +1,103 @@ +/* + * Copyright (c) Microsoft Open Technologies, Inc. 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 WPCordovaClassLib.Cordova.Commands +{ + using System; + using System.Windows; + using System.Windows.Navigation; + + using Microsoft.Phone.Controls; + using Microsoft.Phone.Tasks; + using ZXing; + + /// + /// Class that represents barcode scanner task that mimics standart WP8 tasks. + /// + public class BarcodeScannerTask + { + /// + /// Occurs when task is [completed]. + /// + public event EventHandler Completed; + + /// + /// Shows barcode scanner interface. + /// + public void Show() + { + Deployment.Current.Dispatcher.BeginInvoke(() => + { + var root = Application.Current.RootVisual as PhoneApplicationFrame; + + if (root == null) + { + return; + } + + root.Navigated += this.OnNavigated; + root.Navigate(new Uri("/Plugins/phonegap-plugin-barcodescanner/BarcodeScannerUI.xaml", UriKind.Relative)); + }); + } + + /// + /// Called when [navigated]. + /// + /// The sender. + /// The instance containing the event data. + private void OnNavigated(object sender, NavigationEventArgs e) + { + if (!(e.Content is BarcodeScannerUI)) + { + return; + } + + var phoneApplicationFrame = Application.Current.RootVisual as PhoneApplicationFrame; + if (phoneApplicationFrame != null) + { + phoneApplicationFrame.Navigated -= this.OnNavigated; + } + + var barcodeScanner = (BarcodeScannerUI)e.Content; + + if (barcodeScanner != null) + { + barcodeScanner.Completed += this.Completed; + } + else if (this.Completed != null) + { + this.Completed(this, new ScanResult(TaskResult.Cancel)); + } + } + + /// + /// Represents barcode scan result. + /// + public class ScanResult : TaskEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// One of the enumeration values that specifies the status of the task. + public ScanResult(TaskResult taskResult) + : base(taskResult) + { + } + + /// + /// Gets the barcode scan result. + /// + /// + /// The barcode scan result. + /// + public Result Barcode { get; internal set; } + } + } +} diff --git a/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerUI.xaml b/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerUI.xaml new file mode 100644 index 0000000..329d84e --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerUI.xaml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerUI.xaml.cs b/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerUI.xaml.cs new file mode 100644 index 0000000..25329ee --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerUI.xaml.cs @@ -0,0 +1,182 @@ +/* + * Copyright (c) Microsoft Open Technologies, Inc. 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 WPCordovaClassLib.Cordova.Commands +{ + using System; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Input; + using System.Windows.Media.Imaging; + using System.Windows.Navigation; + using System.Windows.Threading; + + using Microsoft.Devices; + using Microsoft.Phone.Tasks; + + using ZXing; + + /// + /// Class that represents UI for barcode scanner. + /// + public partial class BarcodeScannerUI + { + /// + /// The result of scan operation. + /// + private BarcodeScannerTask.ScanResult result; + + /// + /// The barcode reader object + /// + private BarcodeReader reader; + + /// + /// Device camera object + /// + private PhotoCamera camera; + + private DispatcherTimer timer; + + /// + /// Initializes a new instance of the class. + /// This implementation not use camera autofocus. + /// + public BarcodeScannerUI() + { + this.InitializeComponent(); + + // Instantiate objects and start camera preview + this.camera = new PhotoCamera(); + this.reader = new BarcodeReader {Options = {TryHarder = true}}; + this.CameraBrush.SetSource(this.camera); + + // Bind events + this.camera.Initialized += this.CameraInitialized; + this.reader.ResultFound += this.ReaderResultFound; + + this.timer = new DispatcherTimer {Interval = TimeSpan.FromMilliseconds(100)}; + this.timer.Tick += (sender, args) => ScanForBarcode(); + + this.BackKeyPress += CancelScan; + + CameraButtons.ShutterKeyHalfPressed += StartCameraFocus; + camera.AutoFocusCompleted += StartCameraFocus; + + } + + private void StartCameraFocus(object sender, EventArgs eventArgs) + { + camera.Focus(); + } + + /// + /// Occurs when barcode scan is [completed]. + /// + public event EventHandler Completed; + + /// + /// Called when a page is no longer the active page in a frame. + /// + /// An object that contains the event data. + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + // If result is null, user is cancelled scan operation + this.result = this.result ?? new BarcodeScannerTask.ScanResult(TaskResult.Cancel); + this.Completed(this, this.result); + this.CleanUp(); + base.OnNavigatedFrom(e); + } + + /// + /// Called when device camera initialized. + /// + /// The sender. + /// The instance containing the event data. + private void CameraInitialized(object sender, CameraOperationCompletedEventArgs e) + { + if (e.Succeeded) + { + if (camera.IsFocusSupported) + { + camera.Focus(); + } + + // Start scan process in separate thread + this.Dispatcher.BeginInvoke(() => timer.Start()); + } + else + { + this.result = new BarcodeScannerTask.ScanResult(TaskResult.None); + NavigationService.GoBack(); + } + } + + private void ScanForBarcode() + { + var cameraBuffer = new WriteableBitmap( + (int)camera.PreviewResolution.Width, + (int)camera.PreviewResolution.Height); + + camera.GetPreviewBufferArgb32(cameraBuffer.Pixels); + cameraBuffer.Invalidate(); + + reader.Decode(cameraBuffer); + } + + /// + /// Called when reader find barcode. + /// + /// Scan result object. + private void ReaderResultFound(Result obj) + { + VibrateController.Default.Start(TimeSpan.FromMilliseconds(100)); + this.result = new BarcodeScannerTask.ScanResult(TaskResult.OK) { Barcode = obj }; + NavigationService.GoBack(); + } + + /// + /// Cleans up resources and removes unnecessary callbacks. + /// + private void CleanUp() + { + CameraButtons.ShutterKeyHalfPressed -= StartCameraFocus; + if (this.camera != null) + { + this.camera.AutoFocusCompleted -= StartCameraFocus; + this.camera.Initialized -= this.CameraInitialized; + this.camera.Dispose(); + this.camera = null; + } + + if (this.reader != null) + { + this.reader.ResultFound -= this.ReaderResultFound; + this.reader = null; + } + + if (this.timer != null) + { + this.timer.Stop(); + this.timer = null; + } + } + + private void ApplicationBarIconButton_Click(object sender, EventArgs e) + { + NavigationService.GoBack(); + } + + private void CancelScan(object sender, EventArgs eventArgs) + { + NavigationService.GoBack(); + } + } +} \ No newline at end of file diff --git a/plugins/phonegap-plugin-barcodescanner/src/wp8/assets/cancel.png b/plugins/phonegap-plugin-barcodescanner/src/wp8/assets/cancel.png new file mode 100644 index 0000000..1d7f70b Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/wp8/assets/cancel.png differ diff --git a/plugins/phonegap-plugin-barcodescanner/src/wp8/lib/zxing.wp8.0.dll b/plugins/phonegap-plugin-barcodescanner/src/wp8/lib/zxing.wp8.0.dll new file mode 100644 index 0000000..c6f294a Binary files /dev/null and b/plugins/phonegap-plugin-barcodescanner/src/wp8/lib/zxing.wp8.0.dll differ diff --git a/plugins/phonegap-plugin-barcodescanner/tests/plugin.xml b/plugins/phonegap-plugin-barcodescanner/tests/plugin.xml new file mode 100644 index 0000000..5f712ad --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/tests/plugin.xml @@ -0,0 +1,31 @@ + + + + + PhoneGap BarcodeScanner Plugin Tests + Apache 2.0 + + + + diff --git a/plugins/phonegap-plugin-barcodescanner/tests/tests.js b/plugins/phonegap-plugin-barcodescanner/tests/tests.js new file mode 100644 index 0000000..746dae3 --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/tests/tests.js @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * +*/ +exports.defineAutoTests = function() { + var scanner; + describe('cordova.require object should exist', function () { + it("should exist", function() { + expect(window.cordova).toBeDefined(); + expect(typeof cordova.require == 'function').toBe(true); + }); + + it("BarcodeScanner plugin should exist", function() { + scanner = cordova.plugins.barcodeScanner; + expect(scanner).toBeDefined(); + expect(typeof scanner == 'object').toBe(true); + }); + + it("should contain a scan function", function() { + expect(scanner.scan).toBeDefined(); + expect(typeof scanner.scan == 'function').toBe(true); + }); + + it("should contain an encode function", function() { + expect(scanner.encode).toBeDefined(); + expect(typeof scanner.encode == 'function').toBe(true); + }); + + it("should contain three DestinationType constants", function() { + expect(scanner.Encode.TEXT_TYPE).toBe("TEXT_TYPE"); + expect(scanner.Encode.EMAIL_TYPE).toBe("EMAIL_TYPE"); + expect(scanner.Encode.PHONE_TYPE).toBe("PHONE_TYPE"); + expect(scanner.Encode.SMS_TYPE).toBe("SMS_TYPE"); + }); + /* + it("should call scan successfully", function() { + scanner.scan(function() {}, function() {}); + }); + */ + }); +} diff --git a/plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js b/plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js new file mode 100644 index 0000000..1c83d0a --- /dev/null +++ b/plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js @@ -0,0 +1,147 @@ +/** + * cordova is available under *either* the terms of the modified BSD license *or* the + * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. + * + * Copyright (c) Matt Kane 2010 + * Copyright (c) 2011, IBM Corporation + */ + + + var exec = require("cordova/exec"); + + var scanInProgress = false; + + /** + * Constructor. + * + * @returns {BarcodeScanner} + */ + function BarcodeScanner() { + + /** + * Encoding constants. + * + * @type Object + */ + this.Encode = { + TEXT_TYPE: "TEXT_TYPE", + EMAIL_TYPE: "EMAIL_TYPE", + PHONE_TYPE: "PHONE_TYPE", + SMS_TYPE: "SMS_TYPE" + // CONTACT_TYPE: "CONTACT_TYPE", // TODO: not implemented, requires passing a Bundle class from Javascript to Java + // LOCATION_TYPE: "LOCATION_TYPE" // TODO: not implemented, requires passing a Bundle class from Javascript to Java + }; + + /** + * Barcode format constants, defined in ZXing library. + * + * @type Object + */ + this.format = { + "all_1D": 61918, + "aztec": 1, + "codabar": 2, + "code_128": 16, + "code_39": 4, + "code_93": 8, + "data_MATRIX": 32, + "ean_13": 128, + "ean_8": 64, + "itf": 256, + "maxicode": 512, + "msi": 131072, + "pdf_417": 1024, + "plessey": 262144, + "qr_CODE": 2048, + "rss_14": 4096, + "rss_EXPANDED": 8192, + "upc_A": 16384, + "upc_E": 32768, + "upc_EAN_EXTENSION": 65536 + }; + } + +/** + * Read code from scanner. + * + * @param {Function} successCallback This function will recieve a result object: { + * text : '12345-mock', // The code that was scanned. + * format : 'FORMAT_NAME', // Code format. + * cancelled : true/false, // Was canceled. + * } + * @param {Function} errorCallback + * @param config + */ +BarcodeScanner.prototype.scan = function (successCallback, errorCallback, config) { + + if (config instanceof Array) { + // do nothing + } else { + if (typeof(config) === 'object') { + config = [ config ]; + } else { + config = []; + } + } + + if (errorCallback == null) { + errorCallback = function () { + }; + } + + if (typeof errorCallback != "function") { + console.log("BarcodeScanner.scan failure: failure parameter not a function"); + return; + } + + if (typeof successCallback != "function") { + console.log("BarcodeScanner.scan failure: success callback parameter must be a function"); + return; + } + + if (scanInProgress) { + errorCallback('Scan is already in progress'); + return; + } + + scanInProgress = true; + + exec( + function(result) { + scanInProgress = false; + successCallback(result); + }, + function(error) { + scanInProgress = false; + errorCallback(error); + }, + 'BarcodeScanner', + 'scan', + config + ); + }; + + //------------------------------------------------------------------- + BarcodeScanner.prototype.encode = function (type, data, successCallback, errorCallback, options) { + if (errorCallback == null) { + errorCallback = function () { + }; + } + + if (typeof errorCallback != "function") { + console.log("BarcodeScanner.encode failure: failure parameter not a function"); + return; + } + + if (typeof successCallback != "function") { + console.log("BarcodeScanner.encode failure: success callback parameter must be a function"); + return; + } + + exec(successCallback, errorCallback, 'BarcodeScanner', 'encode', [ + {"type": type, "data": data, "options": options} + ]); + }; + + var barcodeScanner = new BarcodeScanner(); + module.exports = barcodeScanner; diff --git a/www/assets/qrcode.svg b/www/assets/qrcode.svg new file mode 100644 index 0000000..e4f6b54 --- /dev/null +++ b/www/assets/qrcode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/css/main.css b/www/css/main.css index 12e496f..92eb5dd 100644 --- a/www/css/main.css +++ b/www/css/main.css @@ -226,12 +226,13 @@ body { box-shadow: 0 0 5px grey; width: 60px; height: 60px; + margin-bottom: 20px; } #buttons .circlebutton img { - position: absolute; - top: 15px; - left: 15px; + position: static; + margin-top: 14px; + margin-left: 14px; width: 30px; height: 30px; } diff --git a/www/js/auth.js b/www/js/auth.js index 1c9ce5e..da40ac6 100644 --- a/www/js/auth.js +++ b/www/js/auth.js @@ -26,10 +26,10 @@ function logout() { password = null; $('#content-zone').load("screens/login.html"); } else { - alert("Error: Server did not properly acknowledge logout. You might have problems for the next few hours if you switch accounts."); + navigator.notification.alert("Server did not properly acknowledge logout. You might have problems for the next few hours if you switch accounts.", null, "Error", 'Dismiss'); } }).fail(function () { - alert("Error: Cannot connect to authentication server. Check your Internet connection and try again. If that fails, clear the app data or reinstall TerranQuest."); + navigator.notification.alert("Cannot connect to authentication server. Check your Internet connection and try again. If that fails, clear the app data or reinstall TerranQuest.", null, "Error", 'Dismiss'); }); } diff --git a/www/js/main.js b/www/js/main.js index 44c2266..a9bab5b 100644 --- a/www/js/main.js +++ b/www/js/main.js @@ -83,7 +83,18 @@ function scanCode() { cordova.plugins.barcodeScanner.scan( function (result) { if (!result.cancelled) { - navigator.notification.alert("Scanned code: " + result.text, null, "OK", 'Dismiss'); + $.getJSON(mkApiUrl('code2item', 'gs'), { + code: result.text + }, function (data) { + if (data.status === 'OK') { + navigator.notification.alert("Found one " + data.message, null, "Found an item!", 'OK'); + } else { + navigator.notification.alert(data.message, null, "Huh?", 'OK'); + } + }).fail(function () { + navigator.notification.alert("Nothing happened!", null, "Huh?", 'OK'); + }); + //navigator.notification.alert("Scanned code: " + result.text, null, "OK", 'Dismiss'); } }, function (error) { @@ -91,7 +102,7 @@ function scanCode() { } ); } catch (ex) { - alert(ex.message); + navigator.notification.alert(ex.message, null, "Error", 'Dismiss'); } } diff --git a/www/js/user.js b/www/js/user.js index 9576f31..0085c1d 100644 --- a/www/js/user.js +++ b/www/js/user.js @@ -11,7 +11,7 @@ * Syncs the user's stats with the server and calls refreshStats(). */ function syncStats() { - $.getJSON(mkApiUrl('getstats'), { + $.getJSON(mkApiUrl('getstats', 'gs'), { user: username }, function (data) { if (data.status === 'OK') { diff --git a/www/screens/chooseteam.html b/www/screens/chooseteam.html index de31813..8e3eb7e 100644 --- a/www/screens/chooseteam.html +++ b/www/screens/chooseteam.html @@ -32,7 +32,7 @@ function setTeam() { //alert($('input[name=teamChooser]:checked').val()); var team = $('input[name=teamChooser]:checked').val(); - $.getJSON(mkApiUrl('setteam', 'gs'), { + $.getJSON(mkApiUrl('setteam', 'gs'), { teamid: team }, function (data) { if (data.status === 'OK') { @@ -40,10 +40,10 @@ openscreen("home"); } else { // Error? - alert("Error: " + data.message); + navigator.notification.alert(data.message, null, "Error", 'OK'); } }).fail(function () { - alert("Something bad happened, try again later."); + navigator.notification.alert("Something went wrong, try again later.", null, "Error", 'OK'); }); } diff --git a/www/screens/home.html b/www/screens/home.html index 2d127d6..d4087f7 100644 --- a/www/screens/home.html +++ b/www/screens/home.html @@ -36,6 +36,9 @@
Menu
+
+ Scan Code +
diff --git a/www/screens/inventory.html b/www/screens/inventory.html index abaf430..f28bb3c 100644 --- a/www/screens/inventory.html +++ b/www/screens/inventory.html @@ -7,15 +7,36 @@
\ No newline at end of file