parent
f5a5d76b1e
commit
b9a66814c1
@ -0,0 +1,78 @@ |
||||
@file:Suppress("unused") |
||||
|
||||
package xyz.fycz.myreader.greendao.service |
||||
|
||||
import android.text.TextUtils |
||||
import xyz.fycz.myreader.greendao.DbManager |
||||
import xyz.fycz.myreader.greendao.entity.CookieBean |
||||
import xyz.fycz.myreader.greendao.service.api.CookieManager |
||||
import xyz.fycz.myreader.util.utils.NetworkUtils |
||||
|
||||
object CookieStore : CookieManager { |
||||
|
||||
override fun setCookie(url: String, cookie: String?) { |
||||
val cookieBean = CookieBean(NetworkUtils.getSubDomain(url), cookie ?: "") |
||||
DbManager.getDaoSession().cookieBeanDao.insertOrReplace(cookieBean) |
||||
} |
||||
|
||||
override fun replaceCookie(url: String, cookie: String) { |
||||
if (TextUtils.isEmpty(url) || TextUtils.isEmpty(cookie)) { |
||||
return |
||||
} |
||||
val oldCookie = getCookie(url) |
||||
if (TextUtils.isEmpty(oldCookie)) { |
||||
setCookie(url, cookie) |
||||
} else { |
||||
val cookieMap = cookieToMap(oldCookie) |
||||
cookieMap.putAll(cookieToMap(cookie)) |
||||
val newCookie = mapToCookie(cookieMap) |
||||
setCookie(url, newCookie) |
||||
} |
||||
} |
||||
|
||||
override fun getCookie(url: String): String { |
||||
val cookieBean = DbManager.getDaoSession().cookieBeanDao.load(NetworkUtils.getSubDomain(url)) |
||||
return cookieBean?.cookie ?: "" |
||||
} |
||||
|
||||
override fun removeCookie(url: String) { |
||||
DbManager.getDaoSession().cookieBeanDao.deleteByKey(NetworkUtils.getSubDomain(url)) |
||||
} |
||||
|
||||
override fun cookieToMap(cookie: String): MutableMap<String, String> { |
||||
val cookieMap = mutableMapOf<String, String>() |
||||
if (cookie.isBlank()) { |
||||
return cookieMap |
||||
} |
||||
val pairArray = cookie.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() |
||||
for (pair in pairArray) { |
||||
val pairs = pair.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() |
||||
if (pairs.size == 1) { |
||||
continue |
||||
} |
||||
val key = pairs[0].trim { it <= ' ' } |
||||
val value = pairs[1] |
||||
if (value.isNotBlank() || value.trim { it <= ' ' } == "null") { |
||||
cookieMap[key] = value.trim { it <= ' ' } |
||||
} |
||||
} |
||||
return cookieMap |
||||
} |
||||
|
||||
override fun mapToCookie(cookieMap: Map<String, String>?): String? { |
||||
if (cookieMap == null || cookieMap.isEmpty()) { |
||||
return null |
||||
} |
||||
val builder = StringBuilder() |
||||
for (key in cookieMap.keys) { |
||||
val value = cookieMap[key] |
||||
if (value?.isNotBlank() == true) { |
||||
builder.append(key) |
||||
.append("=") |
||||
.append(value) |
||||
.append(";") |
||||
} |
||||
} |
||||
return builder.deleteCharAt(builder.lastIndexOf(";")).toString() |
||||
} |
||||
} |
@ -0,0 +1,28 @@ |
||||
package xyz.fycz.myreader.greendao.service.api |
||||
|
||||
interface CookieManager { |
||||
|
||||
/** |
||||
* 保存cookie |
||||
*/ |
||||
fun setCookie(url: String, cookie: String?) |
||||
|
||||
/** |
||||
* 替换cookie |
||||
*/ |
||||
fun replaceCookie(url: String, cookie: String) |
||||
|
||||
/** |
||||
* 获取cookie |
||||
*/ |
||||
fun getCookie(url: String): String |
||||
|
||||
/** |
||||
* 移除cookie |
||||
*/ |
||||
fun removeCookie(url: String) |
||||
|
||||
fun cookieToMap(cookie: String): MutableMap<String, String> |
||||
|
||||
fun mapToCookie(cookieMap: Map<String, String>?): String? |
||||
} |
@ -0,0 +1,365 @@ |
||||
package xyz.fycz.myreader.util.help |
||||
|
||||
import android.util.Base64 |
||||
import android.util.Log |
||||
import androidx.annotation.Keep |
||||
import org.jsoup.Connection |
||||
import org.jsoup.Jsoup |
||||
import xyz.fycz.myreader.greendao.service.CookieStore |
||||
import xyz.fycz.myreader.model.third2.analyzeRule.AnalyzeUrl |
||||
import xyz.fycz.myreader.util.ZipUtils |
||||
import xyz.fycz.myreader.util.utils.* |
||||
import java.io.File |
||||
import java.io.IOException |
||||
import java.net.URLEncoder |
||||
import java.text.SimpleDateFormat |
||||
import java.util.* |
||||
|
||||
/** |
||||
* @author fengyue |
||||
* @date 2021/5/15 19:26 |
||||
*/ |
||||
@Keep |
||||
@Suppress("unused") |
||||
interface JSExtensions { |
||||
/** |
||||
* js实现跨域访问,不能删 |
||||
*/ |
||||
fun ajax(urlStr: String?): String? { |
||||
return try { |
||||
val analyzeUrl = AnalyzeUrl(urlStr) |
||||
OkHttpUtils.getStrResponse(analyzeUrl).blockingFirst().body() |
||||
} catch (e: Exception) { |
||||
e.localizedMessage |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* js实现压缩文件解压 |
||||
*/ |
||||
fun unzipFile(zipPath: String): String { |
||||
if (zipPath.isEmpty()) return "" |
||||
val unzipPath = FileUtils.getCachePath() + File.separator + FileUtils.getNameExcludeExtension(zipPath) |
||||
FileUtils.deleteFile(unzipPath) |
||||
val zipFile = FileUtils.getFile(zipPath) |
||||
val unzipFolder = FileUtils.getFolder(unzipPath) |
||||
ZipUtils.unzipFile(zipFile, unzipFolder) |
||||
FileUtils.deleteFile(zipPath) |
||||
return unzipPath |
||||
} |
||||
|
||||
/** |
||||
* js实现文件夹内所有文件读取 |
||||
*/ |
||||
fun getTxtInFolder(unzipPath: String): String { |
||||
if (unzipPath.isEmpty()) return "" |
||||
val unzipFolder = FileUtils.getFolder(unzipPath) |
||||
val contents = StringBuilder() |
||||
unzipFolder.listFiles().let { |
||||
if (it != null) { |
||||
for (f in it) { |
||||
val charsetName = FileUtils.getFileCharset(f) |
||||
contents.append(String(f.readBytes(), charset(charsetName))) |
||||
.append("\n") |
||||
} |
||||
contents.deleteCharAt(contents.length - 1) |
||||
} |
||||
} |
||||
FileUtils.deleteFile(unzipPath) |
||||
return contents.toString() |
||||
} |
||||
|
||||
/** |
||||
* js实现重定向拦截,不能删 |
||||
*/ |
||||
@Throws(IOException::class) |
||||
operator fun get(urlStr: String?, headers: Map<String?, String?>?): Connection.Response? { |
||||
return Jsoup.connect(urlStr) |
||||
.sslSocketFactory(SSLSocketClient.createSSLSocketFactory()) |
||||
.ignoreContentType(true) |
||||
.followRedirects(false) |
||||
.headers(headers) |
||||
.method(Connection.Method.GET) |
||||
.execute() |
||||
} |
||||
|
||||
/** |
||||
* js实现重定向拦截,不能删 |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun post( |
||||
urlStr: String?, |
||||
body: String?, |
||||
headers: Map<String?, String?>? |
||||
): Connection.Response? { |
||||
return Jsoup.connect(urlStr) |
||||
.sslSocketFactory(SSLSocketClient.createSSLSocketFactory()) |
||||
.ignoreContentType(true) |
||||
.followRedirects(false) |
||||
.requestBody(body) |
||||
.headers(headers) |
||||
.method(Connection.Method.POST) |
||||
.execute() |
||||
} |
||||
|
||||
/** |
||||
*js实现读取cookie |
||||
*/ |
||||
fun getCookie(tag: String, key: String? = null): String { |
||||
val cookie = CookieStore.getCookie(tag) |
||||
val cookieMap = CookieStore.cookieToMap(cookie) |
||||
return if (key != null) { |
||||
cookieMap[key] ?: "" |
||||
} else { |
||||
cookie |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* js实现解码,不能删 |
||||
*/ |
||||
fun base64Decode(str: String): String { |
||||
return EncoderUtils.base64Decode(str, Base64.NO_WRAP) |
||||
} |
||||
|
||||
fun base64Decode(str: String, flags: Int): String { |
||||
return EncoderUtils.base64Decode(str, flags) |
||||
} |
||||
|
||||
fun base64DecodeToByteArray(str: String?): ByteArray? { |
||||
if (str.isNullOrBlank()) { |
||||
return null |
||||
} |
||||
return Base64.decode(str, Base64.DEFAULT) |
||||
} |
||||
|
||||
fun base64DecodeToByteArray(str: String?, flags: Int): ByteArray? { |
||||
if (str.isNullOrBlank()) { |
||||
return null |
||||
} |
||||
return Base64.decode(str, flags) |
||||
} |
||||
|
||||
fun base64Encode(str: String): String? { |
||||
return EncoderUtils.base64Encode(str, Base64.NO_WRAP) |
||||
} |
||||
|
||||
fun base64Encode(str: String, flags: Int): String? { |
||||
return EncoderUtils.base64Encode(str, flags) |
||||
} |
||||
|
||||
fun md5Encode(str: String): String { |
||||
return MD5Utils.md5Encode(str) |
||||
} |
||||
|
||||
fun md5Encode16(str: String): String { |
||||
return MD5Utils.md5Encode16(str) |
||||
} |
||||
|
||||
/** |
||||
* 时间格式化 |
||||
*/ |
||||
fun timeFormat(time: Long): String { |
||||
val sdf = SimpleDateFormat("yyyy/MM/dd HH:mm") |
||||
return sdf.format(Date(time)) |
||||
} |
||||
|
||||
/** |
||||
* utf8编码转gbk编码 |
||||
*/ |
||||
fun utf8ToGbk(str: String): String { |
||||
val utf8 = String(str.toByteArray(charset("UTF-8"))) |
||||
val unicode = String(utf8.toByteArray(), charset("UTF-8")) |
||||
return String(unicode.toByteArray(charset("GBK"))) |
||||
} |
||||
|
||||
fun encodeURI(str: String): String { |
||||
return try { |
||||
URLEncoder.encode(str, "UTF-8") |
||||
} catch (e: Exception) { |
||||
"" |
||||
} |
||||
} |
||||
|
||||
fun encodeURI(str: String, enc: String): String { |
||||
return try { |
||||
URLEncoder.encode(str, enc) |
||||
} catch (e: Exception) { |
||||
"" |
||||
} |
||||
} |
||||
|
||||
fun htmlFormat(str: String): String { |
||||
return StringUtils.formatHtml(str) |
||||
} |
||||
|
||||
/** |
||||
* 读取本地文件 |
||||
*/ |
||||
fun readFile(path: String): ByteArray { |
||||
return File(path).readBytes() |
||||
} |
||||
|
||||
fun readTxtFile(path: String): String { |
||||
val f = File(path) |
||||
val charsetName = FileUtils.getFileCharset(f) |
||||
return String(f.readBytes(), charset(charsetName)) |
||||
} |
||||
|
||||
fun readTxtFile(path: String, charsetName: String): String { |
||||
return String(File(path).readBytes(), charset(charsetName)) |
||||
} |
||||
|
||||
/** |
||||
* 输出调试日志 |
||||
*/ |
||||
fun log(msg: String): String { |
||||
Log.d("JS", msg) |
||||
return msg |
||||
} |
||||
|
||||
/** |
||||
* AES 解码为 ByteArray |
||||
* @param str 传入的AES加密的数据 |
||||
* @param key AES 解密的key |
||||
* @param transformation AES加密的方式 |
||||
* @param iv ECB模式的偏移向量 |
||||
*/ |
||||
fun aesDecodeToByteArray( |
||||
str: String, |
||||
key: String, |
||||
transformation: String, |
||||
iv: String = "" |
||||
): ByteArray? { |
||||
|
||||
return EncoderUtils.decryptAES( |
||||
data = str.encodeToByteArray(), |
||||
key = key.encodeToByteArray(), |
||||
transformation, |
||||
iv.encodeToByteArray() |
||||
) |
||||
} |
||||
|
||||
/** |
||||
* AES 解码为 String |
||||
* @param str 传入的AES加密的数据 |
||||
* @param key AES 解密的key |
||||
* @param transformation AES加密的方式 |
||||
* @param iv ECB模式的偏移向量 |
||||
*/ |
||||
|
||||
fun aesDecodeToString( |
||||
str: String, |
||||
key: String, |
||||
transformation: String, |
||||
iv: String = "" |
||||
): String? { |
||||
return aesDecodeToByteArray(str, key, transformation, iv)?.let { String(it) } |
||||
} |
||||
|
||||
/** |
||||
* 已经base64的AES 解码为 ByteArray |
||||
* @param str 传入的AES Base64加密的数据 |
||||
* @param key AES 解密的key |
||||
* @param transformation AES加密的方式 |
||||
* @param iv ECB模式的偏移向量 |
||||
*/ |
||||
|
||||
fun aesBase64DecodeToByteArray( |
||||
str: String, |
||||
key: String, |
||||
transformation: String, |
||||
iv: String = "" |
||||
): ByteArray? { |
||||
return EncoderUtils.decryptBase64AES( |
||||
data = str.encodeToByteArray(), |
||||
key = key.encodeToByteArray(), |
||||
transformation, |
||||
iv.encodeToByteArray() |
||||
) |
||||
} |
||||
|
||||
/** |
||||
* 已经base64的AES 解码为 String |
||||
* @param str 传入的AES Base64加密的数据 |
||||
* @param key AES 解密的key |
||||
* @param transformation AES加密的方式 |
||||
* @param iv ECB模式的偏移向量 |
||||
*/ |
||||
|
||||
fun aesBase64DecodeToString( |
||||
str: String, |
||||
key: String, |
||||
transformation: String, |
||||
iv: String = "" |
||||
): String? { |
||||
return aesBase64DecodeToByteArray(str, key, transformation, iv)?.let { String(it) } |
||||
} |
||||
|
||||
/** |
||||
* 加密aes为ByteArray |
||||
* @param data 传入的原始数据 |
||||
* @param key AES加密的key |
||||
* @param transformation AES加密的方式 |
||||
* @param iv ECB模式的偏移向量 |
||||
*/ |
||||
fun aesEncodeToByteArray( |
||||
data: String, key: String, transformation: String, |
||||
iv: String = "" |
||||
): ByteArray? { |
||||
return EncoderUtils.encryptAES( |
||||
data.encodeToByteArray(), |
||||
key = key.encodeToByteArray(), |
||||
transformation, |
||||
iv.encodeToByteArray() |
||||
) |
||||
} |
||||
|
||||
/** |
||||
* 加密aes为String |
||||
* @param data 传入的原始数据 |
||||
* @param key AES加密的key |
||||
* @param transformation AES加密的方式 |
||||
* @param iv ECB模式的偏移向量 |
||||
*/ |
||||
fun aesEncodeToString( |
||||
data: String, key: String, transformation: String, |
||||
iv: String = "" |
||||
): String? { |
||||
return aesEncodeToByteArray(data, key, transformation, iv)?.let { String(it) } |
||||
} |
||||
|
||||
/** |
||||
* 加密aes后Base64化的ByteArray |
||||
* @param data 传入的原始数据 |
||||
* @param key AES加密的key |
||||
* @param transformation AES加密的方式 |
||||
* @param iv ECB模式的偏移向量 |
||||
*/ |
||||
fun aesEncodeToBase64ByteArray( |
||||
data: String, key: String, transformation: String, |
||||
iv: String = "" |
||||
): ByteArray? { |
||||
return EncoderUtils.encryptAES2Base64( |
||||
data.encodeToByteArray(), |
||||
key = key.encodeToByteArray(), |
||||
transformation, |
||||
iv.encodeToByteArray() |
||||
) |
||||
} |
||||
|
||||
/** |
||||
* 加密aes后Base64化的String |
||||
* @param data 传入的原始数据 |
||||
* @param key AES加密的key |
||||
* @param transformation AES加密的方式 |
||||
* @param iv ECB模式的偏移向量 |
||||
*/ |
||||
fun aesEncodeToBase64String( |
||||
data: String, key: String, transformation: String, |
||||
iv: String = "" |
||||
): String? { |
||||
return aesEncodeToBase64ByteArray(data, key, transformation, iv)?.let { String(it) } |
||||
} |
||||
} |
@ -0,0 +1,141 @@ |
||||
package xyz.fycz.myreader.util.utils |
||||
|
||||
import android.util.Base64 |
||||
import java.security.spec.AlgorithmParameterSpec |
||||
import javax.crypto.Cipher |
||||
import javax.crypto.spec.IvParameterSpec |
||||
import javax.crypto.spec.SecretKeySpec |
||||
|
||||
@Suppress("unused") |
||||
object EncoderUtils { |
||||
@JvmOverloads |
||||
fun base64Decode(str: String, flags: Int = Base64.DEFAULT): String { |
||||
val bytes = Base64.decode(str, flags) |
||||
return String(bytes) |
||||
} |
||||
|
||||
@JvmOverloads |
||||
fun base64Encode(str: String, flags: Int = Base64.NO_WRAP): String? { |
||||
return Base64.encodeToString(str.toByteArray(), flags) |
||||
} |
||||
//////////AES Start |
||||
|
||||
/** |
||||
* Return the Base64-encode bytes of AES encryption. |
||||
* |
||||
* @param data The data. |
||||
* @param key The key. |
||||
* @param transformation The name of the transformation, e.g., *DES/CBC/PKCS5Padding*. |
||||
* @param iv The buffer with the IV. The contents of the |
||||
* buffer are copied to protect against subsequent modification. |
||||
* @return the Base64-encode bytes of AES encryption |
||||
*/ |
||||
fun encryptAES2Base64( |
||||
data: ByteArray?, |
||||
key: ByteArray?, |
||||
transformation: String?, |
||||
iv: ByteArray? |
||||
): ByteArray? { |
||||
return Base64.encode(encryptAES(data, key, transformation, iv), Base64.NO_WRAP) |
||||
} |
||||
|
||||
/** |
||||
* Return the bytes of AES encryption. |
||||
* |
||||
* @param data The data. |
||||
* @param key The key. |
||||
* @param transformation The name of the transformation, e.g., *DES/CBC/PKCS5Padding*. |
||||
* @param iv The buffer with the IV. The contents of the |
||||
* buffer are copied to protect against subsequent modification. |
||||
* @return the bytes of AES encryption |
||||
*/ |
||||
fun encryptAES( |
||||
data: ByteArray?, |
||||
key: ByteArray?, |
||||
transformation: String?, |
||||
iv: ByteArray? |
||||
): ByteArray? { |
||||
return symmetricTemplate(data, key, "AES", transformation!!, iv, true) |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Return the bytes of AES decryption for Base64-encode bytes. |
||||
* |
||||
* @param data The data. |
||||
* @param key The key. |
||||
* @param transformation The name of the transformation, e.g., *DES/CBC/PKCS5Padding*. |
||||
* @param iv The buffer with the IV. The contents of the |
||||
* buffer are copied to protect against subsequent modification. |
||||
* @return the bytes of AES decryption for Base64-encode bytes |
||||
*/ |
||||
fun decryptBase64AES( |
||||
data: ByteArray?, |
||||
key: ByteArray?, |
||||
transformation: String?, |
||||
iv: ByteArray? |
||||
): ByteArray? { |
||||
return decryptAES(Base64.decode(data, Base64.NO_WRAP), key, transformation, iv) |
||||
} |
||||
|
||||
/** |
||||
* Return the bytes of AES decryption. |
||||
* |
||||
* @param data The data. |
||||
* @param key The key. |
||||
* @param transformation The name of the transformation, e.g., *DES/CBC/PKCS5Padding*. |
||||
* @param iv The buffer with the IV. The contents of the |
||||
* buffer are copied to protect against subsequent modification. |
||||
* @return the bytes of AES decryption |
||||
*/ |
||||
fun decryptAES( |
||||
data: ByteArray?, |
||||
key: ByteArray?, |
||||
transformation: String?, |
||||
iv: ByteArray? |
||||
): ByteArray? { |
||||
return symmetricTemplate(data, key, "AES", transformation!!, iv, false) |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Return the bytes of symmetric encryption or decryption. |
||||
* |
||||
* @param data The data. |
||||
* @param key The key. |
||||
* @param algorithm The name of algorithm. |
||||
* @param transformation The name of the transformation, e.g., <i>DES/CBC/PKCS5Padding</i>. |
||||
* @param isEncrypt True to encrypt, false otherwise. |
||||
* @return the bytes of symmetric encryption or decryption |
||||
*/ |
||||
|
||||
private fun symmetricTemplate( |
||||
data: ByteArray?, |
||||
key: ByteArray?, |
||||
algorithm: String, |
||||
transformation: String, |
||||
iv: ByteArray?, |
||||
isEncrypt: Boolean |
||||
): ByteArray? { |
||||
return if (data == null || data.isEmpty() || key == null || key.isEmpty()) null else try { |
||||
val keySpec = SecretKeySpec(key, algorithm) |
||||
val cipher = Cipher.getInstance(transformation) |
||||
if (iv == null || iv.isEmpty()) { |
||||
cipher.init(if (isEncrypt) Cipher.ENCRYPT_MODE else Cipher.DECRYPT_MODE, keySpec) |
||||
} else { |
||||
val params: AlgorithmParameterSpec = IvParameterSpec(iv) |
||||
cipher.init( |
||||
if (isEncrypt) Cipher.ENCRYPT_MODE else Cipher.DECRYPT_MODE, |
||||
keySpec, |
||||
params |
||||
) |
||||
} |
||||
cipher.doFinal(data) |
||||
} catch (e: Throwable) { |
||||
e.printStackTrace() |
||||
null |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -1,73 +0,0 @@ |
||||
package xyz.fycz.myreader.util.utils; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.math.BigInteger; |
||||
import java.security.MessageDigest; |
||||
import java.security.NoSuchAlgorithmException; |
||||
|
||||
import xyz.fycz.myreader.util.IOUtils; |
||||
|
||||
|
||||
public class MD5Utils { |
||||
|
||||
public static String strToMd5By32(String str) { |
||||
String reStr = null; |
||||
try { |
||||
MessageDigest md5 = MessageDigest.getInstance("MD5"); |
||||
byte[] bytes = md5.digest(str.getBytes()); |
||||
StringBuilder stringBuffer = new StringBuilder(); |
||||
for (byte b : bytes) { |
||||
int bt = b & 0xff; |
||||
if (bt < 16) { |
||||
stringBuffer.append(0); |
||||
} |
||||
stringBuffer.append(Integer.toHexString(bt)); |
||||
} |
||||
reStr = stringBuffer.toString(); |
||||
} catch (NoSuchAlgorithmException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return reStr; |
||||
} |
||||
|
||||
public static String strToMd5By16(String str) { |
||||
String reStr = strToMd5By32(str); |
||||
if (reStr != null) { |
||||
reStr = reStr.substring(8, 24); |
||||
} |
||||
return reStr; |
||||
} |
||||
|
||||
/** |
||||
* 获取单个文件的MD5值 |
||||
* @param file 文件 |
||||
* @param radix 位 16 32 64 |
||||
* |
||||
* @return |
||||
*/ |
||||
|
||||
public static String getFileMD5s(File file, int radix) { |
||||
if (!file.isFile()) { |
||||
return null; |
||||
} |
||||
MessageDigest digest = null; |
||||
FileInputStream in = null; |
||||
byte[] buffer = new byte[1024]; |
||||
int len; |
||||
try { |
||||
digest = MessageDigest.getInstance("MD5"); |
||||
in = new FileInputStream(file); |
||||
while ((len = in.read(buffer, 0, 1024)) != -1) { |
||||
digest.update(buffer, 0, len); |
||||
} |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
return null; |
||||
}finally { |
||||
IOUtils.close(in); |
||||
} |
||||
BigInteger bigInt = new BigInteger(1, digest.digest()); |
||||
return bigInt.toString(radix); |
||||
} |
||||
} |
@ -0,0 +1,76 @@ |
||||
package xyz.fycz.myreader.util.utils |
||||
|
||||
import xyz.fycz.myreader.util.IOUtils |
||||
import java.io.File |
||||
import java.io.FileInputStream |
||||
import java.math.BigInteger |
||||
import java.security.MessageDigest |
||||
import java.security.NoSuchAlgorithmException |
||||
import kotlin.experimental.and |
||||
|
||||
/** |
||||
* 将字符串转化为MD5 |
||||
*/ |
||||
@Suppress("unused") |
||||
object MD5Utils { |
||||
|
||||
fun md5Encode(str: String?): String { |
||||
if (str == null) return "" |
||||
var reStr = "" |
||||
try { |
||||
val md5: MessageDigest = MessageDigest.getInstance("MD5") |
||||
val bytes: ByteArray = md5.digest(str.toByteArray()) |
||||
val stringBuffer: StringBuilder = StringBuilder() |
||||
for (b in bytes) { |
||||
val bt: Int = b.toInt() and 0xff |
||||
if (bt < 16) { |
||||
stringBuffer.append(0) |
||||
} |
||||
stringBuffer.append(Integer.toHexString(bt)) |
||||
} |
||||
reStr = stringBuffer.toString() |
||||
} catch (e: NoSuchAlgorithmException) { |
||||
e.printStackTrace() |
||||
} |
||||
|
||||
return reStr |
||||
} |
||||
|
||||
fun md5Encode16(str: String): String { |
||||
var reStr = md5Encode(str) |
||||
reStr = reStr.substring(8, 24) |
||||
return reStr |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取单个文件的MD5值 |
||||
* @param file 文件 |
||||
* @param radix 位 16 32 64 |
||||
* |
||||
* @return |
||||
*/ |
||||
fun getFileMD5s(file: File, radix: Int): String? { |
||||
if (!file.isFile) { |
||||
return null |
||||
} |
||||
var digest: MessageDigest? = null |
||||
var `in`: FileInputStream? = null |
||||
val buffer = ByteArray(1024) |
||||
var len: Int |
||||
try { |
||||
digest = MessageDigest.getInstance("MD5") |
||||
`in` = FileInputStream(file) |
||||
while (`in`.read(buffer, 0, 1024).also { len = it } != -1) { |
||||
digest.update(buffer, 0, len) |
||||
} |
||||
} catch (e: Exception) { |
||||
e.printStackTrace() |
||||
return null |
||||
} finally { |
||||
IOUtils.close(`in`) |
||||
} |
||||
val bigInt = BigInteger(1, digest!!.digest()) |
||||
return bigInt.toString(radix) |
||||
} |
||||
} |
Loading…
Reference in new issue