All Downloads are FREE. Search and download functionalities are using the official Maven repository.

util.TransformationBuilderStringUtils.kt Maven / Gradle / Ivy

package com.cloudinary.util

import com.cloudinary.util.Base64Coder.encodeString
import com.cloudinary.util.Base64Coder.encodeURLSafeString
import java.net.URI
import java.net.URLEncoder
import java.nio.charset.Charset
import java.util.*
import java.util.regex.Matcher
import java.util.regex.Pattern

/**
 * If the param is null the original string is returned unchanged.
 */
internal fun String.cldJoinWithOrReturnOriginal(separator: String, toJoin: Any?): String {
    return if (toJoin != null) this + separator + toJoin.toString() else this
}

/**
 * Checks whether this string is a valid http url.
 */
internal fun String.cldIsHttpUrl() = startsWith("https:/", true) || startsWith("http:/", true)

/**
 * Checks whether this url string has a version component in it (e.g. 'v12345')
 */
internal fun String.cldHasVersionString(): Boolean {
    var inVersion = false
    for (i in 0 until length) {
        val c = get(i)
        inVersion = if (c == 'v') {
            true
        } else if (Character.isDigit(c) && inVersion) {
            return true
        } else {
            false
        }
    }

    return false
}

/**
 * Returns this string with all duplicate slashes merged into a single slash (e.g. "abc///efg -> "abc/efg")
 */
internal fun String.cldMergeSlashedInUrl(): String {
    val builder = StringBuilder()
    var prevIsColon = false
    var inMerge = false
    for (i in 0 until length) {
        val c = get(i)
        if (c == ':') {
            prevIsColon = true
            builder.append(c)
        } else {
            if (c == '/') {
                inMerge = if (prevIsColon) {
                    builder.append(c)
                    false
                } else {
                    if (!inMerge) {
                        builder.append(c)
                    }
                    true
                }
            } else {
                inMerge = false
                builder.append(c)
            }

            prevIsColon = false
        }
    }

    return builder.toString()
}

/**
 * Merge all consecutive underscores and spaces into a single underscore, e.g. "ab___c_  _d" becomes "ab_c_d"
 */
internal fun String.cldMergeToSingleUnderscore(): String {
    val buffer = StringBuffer()
    var inMerge = false
    for (i in 0 until length) {
        val c = this[i]
        if (c == ' ' || c == '_') {
            if (!inMerge) {
                buffer.append('_')
            }
            inMerge = true

        } else {
            inMerge = false
            buffer.append(c)
        }
    }

    return buffer.toString()
}

/**
 * Encodes the url for Cloudinary use (standard url encoding + some custom replacements).
 */
internal fun String.cldSmartUrlEncode() = URLEncoder.encode(this, "UTF-8")
    .replace("%2F", "/")
    .replace("%3A", ":")
    .replace("+", "%20")


/**
 *
 */
internal fun URI.cldQueryAsMap() =
    query?.split("&")?.associate { it.split("=").run { Pair(this[0], this[1]) } } ?: emptyMap()

/**
 * Returns the base64 representation of this string
 */
internal fun String.cldToBase64(): String = encodeString(this)

/**
 * Returns the url-safe variant of the base64 representation of this string
 */
internal fun String.cldToUrlSafeBase64() = encodeURLSafeString(this)

/**
 * Encodes public id to be used in urls (such as wasm asset or layers)
 */
internal fun String.cldEncodePublicId() = replace('/', ':').replace(",", "%2c")

/**
 * Replaces the unsafe characters in url with url-encoded values.
 * This is based on [java.net.URLEncoder.encode]
 * @param unsafe Regex pattern of unsafe caracters
 * @param charset
 * @return An encoded url string
 */
internal fun String.cldUrlEncode(unsafe: Pattern, charset: Charset?): String {
    val sb = StringBuffer(length)
    val matcher = unsafe.matcher(this)
    while (matcher.find()) {
        val str = matcher.group(0)
        val bytes = str.toByteArray(charset!!)
        val escaped = java.lang.StringBuilder(str.length * 3)
        for (aByte in bytes) {
            escaped.append('%')
            var ch = Character.forDigit(((aByte.toInt()) shr 4 and 0xF), 16)
            escaped.append(ch)
            ch = Character.forDigit((aByte.toInt() and 0xF), 16)
            escaped.append(ch)
        }
        matcher.appendReplacement(sb, Matcher.quoteReplacement(escaped.toString().toLowerCase(Locale.US)))
    }
    matcher.appendTail(sb)
    return sb.toString()
}

internal fun String.cldHexStringToByteArray(): ByteArray {
    val len: Int = this.length
    val data = ByteArray(len / 2)

    require(len % 2 == 0) { "Length of string to parse must be even." }

    var i = 0
    while (i < len) {
        data[i / 2] = ((Character.digit(get(i), 16) shl 4) + Character.digit(
            get(i + 1),
            16
        )).toByte()
        i += 2
    }

    return data
}

private val HEX_ARRAY = "0123456789abcdef".toCharArray()

/**
 * Remove all consecutive chars c from the beginning of the string
 * @param c Char to search for
 * @return The string stripped from the starting chars.
 */
fun String.cldRemoveStartingChars(c: Char): String {
    var lastToRemove = -1
    for (i in indices) {
        if (this[i] == c) {
            lastToRemove = i
            continue
        }
        if (this[i] != c) {
            break
        }
    }
    return if (lastToRemove < 0) this else substring(lastToRemove + 1)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy