Skip to content

Commit

Permalink
Removed invalid XML caracters from output gpx file.
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Misiarz committed Feb 8, 2020
1 parent ae86800 commit 2848bec
Show file tree
Hide file tree
Showing 22 changed files with 143 additions and 73 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ Once the properties are provided, signing will be enabled automatically.
* __Skip premium caches__ - If enabled the tool will simply skip premium caches __earlier__. If you are a _basic member_ and disable this option, the tool will try to load cache's details anyway and once it discovers that it can not load the cache (because you are a _basic member_), it skips it. (The tool has no idea whether you are a _basic member_ or a _premium_ one.)

## Release notes
##### 2020-02-08: core v2.0.2 & webapp v1.0.5 & android v1.0.3
* __core__
* Removing invalid XML characters from output GPX file.
* Updated dependencies.

##### 2019-03-25: core v2.0.1
* __core__
* Cache's long description is loaded successfully.
Expand Down
4 changes: 2 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

buildscript {
ext {
versionAndroidTools = '3.2.1'
versionAndroidTools = '3.5.2'
}

repositories {
Expand Down Expand Up @@ -123,7 +123,7 @@ android {
crunchPngs false

proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
proguardFiles fileTree(dir: 'proguard-rules', include: '*.pro') as File[]
proguardFiles fileTree(dir: 'proguard-rules', include: '*.pro').getFiles() as File[]
}

dev {
Expand Down
2 changes: 1 addition & 1 deletion android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#

version=1.0.2
version=1.0.3
3 changes: 3 additions & 0 deletions android/proguard-rules/proguard-kotlin.pro
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

-keep interface kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader
-keep class kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins.BuiltInsLoaderImpl
-keep class kotlin.reflect.jvm.internal.impl.load.java.FieldOverridabilityCondition
-keep class kotlin.reflect.jvm.internal.impl.load.java.ErasedOverridabilityCondition
-keep class kotlin.reflect.jvm.internal.impl.load.java.JavaIncompatibilityRulesOverridabilityCondition

-keepclassmembers class kotlin.Metadata {
public <methods>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import cz.babi.gcunicorn.core.network.service.geocachingcom.GeoCachingCom
import dagger.Binds
import dagger.Module
import dagger.Provides
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import okhttp3.ConnectionSpec
import okhttp3.OkHttpClient
import okhttp3.TlsVersion
Expand Down Expand Up @@ -71,7 +73,7 @@ abstract class ServiceModule {
@Provides
@Singleton
@JvmStatic
fun providesService(network: Network, parserWrapper: ParserWrapper) = GeoCachingCom(network, parserWrapper)
fun providesService(network: Network, parserWrapper: ParserWrapper, json: Json) = GeoCachingCom(network, parserWrapper, json)

@Provides
@Singleton
Expand Down Expand Up @@ -107,6 +109,11 @@ abstract class ServiceModule {
DegreesDecimalMinuteParser()
)

@Provides
@Singleton
@JvmStatic
fun providesJson() = Json(JsonConfiguration.Stable)

private fun applyTlsPatch(builder: OkHttpClient.Builder) {
if (Build.VERSION.SDK_INT in Build.VERSION_CODES.JELLY_BEAN..Build.VERSION_CODES.LOLLIPOP) {
try {
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ subprojects {
maintainer = 'Martin Misiarz'

// Kotlin version.
versionKotlin = '1.3.10'
versionKotlin = '1.3.61'
// Version Kotlin coroutines.
versionKotlinCoroutines = '1.0.1'
versionKotlinCoroutines = '1.3.3'
// Version Slf4J.
versionSlf4J = '1.7.25'
// Version Logback.
Expand Down
12 changes: 6 additions & 6 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ buildscript {
plugins {
id 'propdeps'
id 'propdeps-idea'
id 'org.jetbrains.kotlin.jvm' version '1.3.10'
id 'org.jetbrains.kotlin.plugin.spring' version '1.3.10'
id 'org.jetbrains.kotlin.plugin.allopen' version '1.3.10'
id 'org.jetbrains.kotlin.plugin.noarg' version '1.3.10'
id 'org.jetbrains.kotlin.jvm' version '1.3.61'
id 'org.jetbrains.kotlin.plugin.spring' version '1.3.61'
id 'org.jetbrains.kotlin.plugin.allopen' version '1.3.61'
id 'org.jetbrains.kotlin.plugin.noarg' version '1.3.61'
}

apply plugin: 'kotlinx-serialization'
Expand All @@ -44,11 +44,11 @@ ext {
// Version OkHttp.
versionOkHttp = '3.11.0'
// Version Spring.
versionSpring = '5.1.2.RELEASE'
versionSpring = '5.2.3.RELEASE'
// Version Kotlin XML Builder.
versionKotlinXmlBuilder = '1.4.4'
// Version Kotlin serialization.
versionKotlinSerialization = '0.9.0'
versionKotlinSerialization = '0.14.0'
}

dependencies {
Expand Down
2 changes: 1 addition & 1 deletion core/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#

version=2.0.1
version=2.0.2
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@

package cz.babi.gcunicorn.core.network.service.geocachingcom

import cz.babi.gcunicorn.`fun`.containsHtml
import cz.babi.gcunicorn.`fun`.format
import cz.babi.gcunicorn.`fun`.logger
import cz.babi.gcunicorn.`fun`.nullableExecute
import cz.babi.gcunicorn.`fun`.rot13
import cz.babi.gcunicorn.`fun`.*
import cz.babi.gcunicorn.core.exception.location.CoordinateParseException
import cz.babi.gcunicorn.core.exception.network.LoginException
import cz.babi.gcunicorn.core.exception.network.LogoutException
Expand All @@ -37,6 +33,7 @@ import cz.babi.gcunicorn.core.network.model.HttpParameters
import cz.babi.gcunicorn.core.network.model.Image
import cz.babi.gcunicorn.core.network.service.GeocacheLoadedListener
import cz.babi.gcunicorn.core.network.service.Service
import cz.babi.gcunicorn.core.network.service.geocachingcom.Constant.REGEX_KNOWN_INVALID_XML_CHARS
import cz.babi.gcunicorn.core.network.service.geocachingcom.model.Attribute
import cz.babi.gcunicorn.core.network.service.geocachingcom.model.AttributeType
import cz.babi.gcunicorn.core.network.service.geocachingcom.model.CacheFilter
Expand All @@ -57,7 +54,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.JsonTreeParser
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.content
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.longOrNull
Expand All @@ -77,12 +74,13 @@ import kotlin.coroutines.EmptyCoroutineContext
*
* @param network Network. It is used for communication with external sites.
* @param parser Coordination parser. Parse used for parsing geocaches' coordinates.
* @param json Json parser.
*
* @author Martin Misiarz `<dev.misiarz@gmail.com>`
* @version 1.0.0
* @since 1.0.0
*/
class GeoCachingCom(private val network: Network, private val parser: Parser) : Service {
class GeoCachingCom(private val network: Network, private val parser: Parser, private val json: Json) : Service {

companion object {
private val LOG: Logger = logger<GeoCachingCom>()
Expand Down Expand Up @@ -470,7 +468,7 @@ class GeoCachingCom(private val network: Network, private val parser: Parser) :
if(geocache.code==null) return@waypoint

element("wpt") {
waypoint.coordinates?.let {
waypoint.coordinates?.let {it ->
attributes("lat" to it.latitude, "lon" to it.longitude)
}
waypoint.prefix?.let {
Expand All @@ -497,7 +495,8 @@ class GeoCachingCom(private val network: Network, private val parser: Parser) :
}
}

return String(gpx.toString(formatOutput).toByteArray())
// return String(gpx.toString(formatOutput).toByteArray())
return gpx.toString(formatOutput).replace(REGEX_KNOWN_INVALID_XML_CHARS, "")
}

/**
Expand Down Expand Up @@ -1010,35 +1009,35 @@ class GeoCachingCom(private val network: Network, private val parser: Parser) :
val cacheLogs = network.getResponseStringBody(network.getRequest(Constant.URI_CACHE_LOGBOOK, parameters, null))

try {
val logEntries = JsonTreeParser.parse(cacheLogs)
val logEntries = json.parseJson(cacheLogs).jsonObject

if(logEntries.getOrNull(Constant.REQUEST_STATUS)?.content=="success") {
if(logEntries[Constant.REQUEST_STATUS]?.content=="success") {
val cacheLogEntries = mutableListOf<LogEntry>()

logEntries.getArrayOrNull(Constant.REQUEST_DATA)
?.forEach { jsonLogEntryElement ->
val logEntry = LogEntry()
val jsonLogEntry = jsonLogEntryElement.jsonObject

jsonLogEntry.getOrNull(Constant.LOG_ID)?.longOrNull.nullableExecute({
jsonLogEntry[Constant.LOG_ID]?.longOrNull.nullableExecute({
logEntry.id = this
}, {
LOG.warn("Can not obtain log entry's id.")
})

jsonLogEntry.getOrNull(Constant.LOG_TYPE)?.contentOrNull.nullableExecute({
jsonLogEntry[Constant.LOG_TYPE]?.contentOrNull.nullableExecute({
logEntry.type = LogType.findByType(this)
}, {
LOG.warn("Can not obtain log entry's id.")
})

jsonLogEntry.getOrNull(Constant.LOG_TEXT)?.contentOrNull?.trim()?.replace("<p>", "")?.replace("</p>", "").nullableExecute({
jsonLogEntry[Constant.LOG_TEXT]?.contentOrNull?.trim()?.replace("<p>", "")?.replace("</p>", "").nullableExecute({
logEntry.text = this
}, {
LOG.warn("Can not obtain log entry's text.")
})

jsonLogEntry.getOrNull(Constant.LOG_VISITED)?.contentOrNull.nullableExecute({
jsonLogEntry[Constant.LOG_VISITED]?.contentOrNull.nullableExecute({
try {
logEntry.visited = SimpleDateFormat(Constant.PATTERN_DATE_PAGE, Locale.ENGLISH).parse(this).time
} catch (e: ParseException) {
Expand All @@ -1048,35 +1047,35 @@ class GeoCachingCom(private val network: Network, private val parser: Parser) :
LOG.warn("Can not obtain log visited.")
})

jsonLogEntry.getOrNull(Constant.LOG_AUTHOR)?.contentOrNull.nullableExecute({
jsonLogEntry[Constant.LOG_AUTHOR]?.contentOrNull.nullableExecute({
logEntry.author = this
}, {
LOG.warn("Can not obtain log author.")
})

jsonLogEntry.getOrNull(Constant.LOG_AUTHOR_ID)?.longOrNull.nullableExecute({
jsonLogEntry[Constant.LOG_AUTHOR_ID]?.longOrNull.nullableExecute({
logEntry.authorId = this
}, {
LOG.warn("Can not obtain log author's id.")
})

val logImages = mutableListOf<Image>()
jsonLogEntry.getOrNull(Constant.LOG_IMAGES)?.jsonArray?.forEach logImageTree@ { logImageTreeElement ->
jsonLogEntry[Constant.LOG_IMAGES]?.jsonArray?.forEach logImageTree@ { logImageTreeElement ->
val logImageTree = logImageTreeElement.jsonObject
val imageFileName = logImageTree.getOrNull(Constant.LOG_IMAGE_FILENAME)?.contentOrNull ?: return@logImageTree
val imageFileName = logImageTree.get(Constant.LOG_IMAGE_FILENAME)?.contentOrNull ?: return@logImageTree

val logImage = Image(Constant.URI_IMAGE_LARGE + imageFileName)
logImage.guid = imageFileName.substringBefore(".")

logImageTree.getOrNull(Constant.LOG_IMAGE_NAME)?.contentOrNull.nullableExecute({
logImageTree[Constant.LOG_IMAGE_NAME]?.contentOrNull.nullableExecute({
if (isNotEmpty()) {
logImage.title = this
}
}, {
LOG.warn("Can not obtain log image's name.")
})

logImageTree.getOrNull(Constant.LOG_IMAGE_DESCRIPTION)?.contentOrNull.nullableExecute({
logImageTree[Constant.LOG_IMAGE_DESCRIPTION]?.contentOrNull.nullableExecute({
if (isNotEmpty()) logImage.description = this
}, {
LOG.warn("Can not obtain log image's description.")
Expand Down Expand Up @@ -1275,4 +1274,5 @@ object Constant {
@JvmField val REGEX_CACHE_WAYPOINTS_ITEM_COORDINATIONS = ">([\\s\\S]*?)&nbsp;[\\s\\S]*?</td>".toRegex()
@JvmField val REGEX_TRACKABLE_CODE = "CoordInfoCode\">(TB[0-9A-Z]+)<".toRegex()
@JvmField val REGEX_TRACKABLE_ID = "/my/watchlist\\.aspx\\?b=(\\d+)\"".toRegex()
@JvmField val REGEX_KNOWN_INVALID_XML_CHARS = "(&#8;)".toRegex()
}
41 changes: 38 additions & 3 deletions core/src/main/kotlin/cz/babi/gcunicorn/fun/String.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@

package cz.babi.gcunicorn.`fun`

object Constant {
// XML 1.0
// #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
const val XML_10 = "[^" +
"\u0009\r\n" +
"\u0020-\uD7FF" +
"\uE000-\uFFFD" +
"\ud800\udc00-\udbff\udfff" +
"]"

// XML 1.1
// [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
const val XML_11 = "[^" +
"\u0001-\uD7FF" +
"\uE000-\uFFFD" +
"\ud800\udc00-\udbff\udfff" +
"]"
}

/**
* Checks whether underlying string contains any HTML sequence.
* @return True if underlying string contains any HTML sequence. Otherwise returns false.
Expand All @@ -39,8 +58,8 @@ fun String.containsHtml() = "<[^>]+>|&+".toRegex().containsMatchIn(this)
fun String.rot13(): String {
val output = StringBuilder()

for(i in 0 until this.length) {
var c: Char = this[i]
for(element in this) {
var c: Char = element

when(c) {
in 'a'..'m' -> c += 13
Expand All @@ -53,4 +72,20 @@ fun String.rot13(): String {
}

return output.toString()
}
}

/**
* Removes invalid characters and return text compatible with XML 1.0 specification.
* @return Text compatible with XML 1.0 specification.
*/
fun String.validateXml10(): String {
return this.replace(Constant.XML_10, "")
}

/**
* Removes invalid characters and return text compatible with XML 1.1 specification.
* @return Text compatible with XML 1.1 specification.
*/
fun String.validateXml11(): String {
return this.replace(Constant.XML_11, "")
}
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
20 changes: 1 addition & 19 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
#
# gcUnicorn
# Copyright (C) 2018 Martin Misiarz
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
18 changes: 17 additions & 1 deletion gradlew
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
#!/usr/bin/env sh

#
# Copyright 2015 the original author or 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
#
# https://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.
#

##############################################################################
##
## Gradle start up script for UN*X
Expand Down Expand Up @@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
Expand Down

0 comments on commit 2848bec

Please sign in to comment.