mirror of
https://github.com/fumiama/simple-dict-android.git
synced 2026-06-10 21:24:20 +08:00
v2.1
1. 适配SPB
This commit is contained in:
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CompilerConfiguration">
|
<component name="CompilerConfiguration">
|
||||||
<bytecodeTargetLevel target="1.8" />
|
<bytecodeTargetLevel target="11" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
1
.idea/dictionaries/rumia.xml
generated
1
.idea/dictionaries/rumia.xml
generated
@@ -1,6 +1,7 @@
|
|||||||
<component name="ProjectDictionaryState">
|
<component name="ProjectDictionaryState">
|
||||||
<dictionary name="rumia">
|
<dictionary name="rumia">
|
||||||
<words>
|
<words>
|
||||||
|
<w>slle</w>
|
||||||
<w>spwd</w>
|
<w>spwd</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
|
|||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|||||||
10
.idea/runConfigurations.xml
generated
Normal file
10
.idea/runConfigurations.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RunConfigurationProducerService">
|
||||||
|
<option name="ignoredProducers">
|
||||||
|
<set>
|
||||||
|
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -12,8 +12,8 @@ android {
|
|||||||
applicationId "top.fumiama.simpledict"
|
applicationId "top.fumiama.simpledict"
|
||||||
minSdkVersion 26
|
minSdkVersion 26
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 15
|
versionCode 16
|
||||||
versionName '2.0.1'
|
versionName '2.1'
|
||||||
resConfigs "zh", "zh-rCN"
|
resConfigs "zh", "zh-rCN"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|||||||
@@ -62,30 +62,58 @@ class Client(private val ip: String, private val port: Int) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun receiveRawMessage(totalSize: Int = -1, bufferSize: Int = 1048576) : ByteArray {
|
var buffer = byteArrayOf()
|
||||||
var re = byteArrayOf()
|
|
||||||
try {
|
fun receiveRawMessage(totalSize: Int = -1, bufferSize: Int = 1048576, setProgress: Boolean = false) : ByteArray {
|
||||||
if (isConnect) {
|
if(totalSize == buffer.size) {
|
||||||
Log.d("MyC", "开始接收服务端信息")
|
val re = buffer
|
||||||
val inMessage = ByteArray(bufferSize) //设置接受缓冲,避免接受数据过长占用过多内存
|
buffer = byteArrayOf()
|
||||||
var a: Int
|
return re
|
||||||
do {
|
} else {
|
||||||
a = din?.read(inMessage)?:0 //a存储返回消息的长度
|
var re = byteArrayOf()
|
||||||
if(a > 0) {
|
try {
|
||||||
re += inMessage.copyOf(a)
|
if (isConnect) {
|
||||||
Log.d("MyC", "reply length:$a")
|
Log.d("MyC", "开始接收服务端信息")
|
||||||
if(totalSize < 0 && a < bufferSize) break
|
val inMessage = ByteArray(bufferSize) //设置接受缓冲,避免接受数据过长占用过多内存
|
||||||
} else break
|
var a: Int
|
||||||
} while (totalSize > re.size)
|
do {
|
||||||
} else Log.d("MyC", "no connect to receive message")
|
a = din?.read(inMessage)?:0 //a存储返回消息的长度
|
||||||
} catch (e: IOException) {
|
if(a > 0) {
|
||||||
Log.d("MyC", "receive message failed")
|
re += inMessage.copyOf(a)
|
||||||
e.printStackTrace()
|
Log.d("MyC", "reply length:$a")
|
||||||
|
if(totalSize < 0 && a < bufferSize) break
|
||||||
|
else if(setProgress && totalSize > 0) progress?.notify(100 * re.size / totalSize)
|
||||||
|
} else break
|
||||||
|
} while (totalSize > re.size)
|
||||||
|
} else Log.d("MyC", "no connect to receive message")
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.d("MyC", "receive message failed")
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
if(totalSize > 0 && re.size > totalSize) {
|
||||||
|
Log.d("MyC", "Reduce re size from ${re.size} to $totalSize")
|
||||||
|
buffer += re.copyOfRange(totalSize, re.size)
|
||||||
|
re = re.copyOf(totalSize)
|
||||||
|
} else if(totalSize > 0 && buffer.isNotEmpty()) {
|
||||||
|
Log.d("MyC", "Increase re size.")
|
||||||
|
buffer += re
|
||||||
|
if(buffer.size > totalSize) {
|
||||||
|
re = buffer.copyOf(totalSize)
|
||||||
|
buffer = buffer.copyOfRange(totalSize, buffer.size)
|
||||||
|
} else {
|
||||||
|
re = buffer
|
||||||
|
buffer = byteArrayOf()
|
||||||
|
}
|
||||||
|
} else if(totalSize < 0 && buffer.isNotEmpty()) {
|
||||||
|
re = buffer
|
||||||
|
buffer = byteArrayOf()
|
||||||
|
Log.d("MyC", "clear buffer")
|
||||||
|
}
|
||||||
|
return re
|
||||||
}
|
}
|
||||||
return re
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun receiveMessage() = receiveRawMessage().decodeToString()
|
fun receiveMessage(totalSize: Int = -1) = receiveRawMessage(totalSize).decodeToString()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭连接
|
* 关闭连接
|
||||||
@@ -102,4 +130,10 @@ class Client(private val ip: String, private val port: Int) {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var progress: Progress? = null
|
||||||
|
|
||||||
|
interface Progress {
|
||||||
|
fun notify(progressPercentage: Int)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package top.fumiama.simpledict
|
package top.fumiama.simpledict
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import java.lang.Thread.sleep
|
|
||||||
|
|
||||||
class SimpleDict(private val client: Client, private val pwd: String, private val spwd: String?) { //must run in thread
|
class SimpleDict(private val client: Client, private val pwd: String, private val spwd: String?) { //must run in thread
|
||||||
private var dict = HashMap<String, String?>()
|
private var dict = HashMap<String, String?>()
|
||||||
@@ -16,39 +15,38 @@ class SimpleDict(private val client: Client, private val pwd: String, private va
|
|||||||
do {
|
do {
|
||||||
re = byteArrayOf()
|
re = byteArrayOf()
|
||||||
if(initDict()) {
|
if(initDict()) {
|
||||||
sendMessageWithDelay("cat", 2333)
|
sendMessage("cat")
|
||||||
try {
|
try {
|
||||||
firstRecv = client.receiveRawMessage()
|
firstRecv = client.receiveRawMessage()
|
||||||
val firstStr = firstRecv.decodeToString()
|
val firstStr = firstRecv.decodeToString()
|
||||||
var length = ""
|
var length = ""
|
||||||
|
Log.d("MySD", "first str: $firstStr")
|
||||||
for ((i, c) in firstStr.withIndex()) {
|
for ((i, c) in firstStr.withIndex()) {
|
||||||
if(c.isDigit()) length += c
|
if(c.isDigit()) length += c
|
||||||
else {
|
else {
|
||||||
if(i + 1 < firstRecv.size) re = firstRecv.copyOfRange(i, firstRecv.size)
|
if(i + 2 < firstRecv.size) re = firstRecv.copyOfRange(i + 1, firstRecv.size)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Log.d("MySD", "length: $length")
|
||||||
re += client.receiveRawMessage(length.toInt() - re.size)
|
re += client.receiveRawMessage(length.toInt() - re.size)
|
||||||
|
closeDict()
|
||||||
break
|
break
|
||||||
} catch (e: Exception){
|
} catch (e: Exception){
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
closeDict()
|
||||||
}
|
}
|
||||||
closeDict()
|
|
||||||
}
|
}
|
||||||
} while (times-- > 0)
|
} while (times-- > 0)
|
||||||
return if(re.isEmpty()) null else re
|
return if(re.isEmpty()) null else re
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendMessageWithDelay(msg: CharSequence, delay: Long = 233) = Thread{
|
private fun sendMessage(msg: CharSequence) = client.sendMessage(msg)
|
||||||
client.sendMessage(msg)
|
|
||||||
sleep(delay)
|
|
||||||
}.start()
|
|
||||||
|
|
||||||
private fun initDict(): Boolean {
|
private fun initDict(): Boolean {
|
||||||
if(client.initConnect()){
|
if(client.initConnect()){
|
||||||
if(client.sendMessage(pwd)) {
|
if(client.sendMessage(pwd)) {
|
||||||
client.receiveRawMessage()
|
client.receiveRawMessage(31)
|
||||||
sleep(233)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,19 +60,6 @@ class SimpleDict(private val client: Client, private val pwd: String, private va
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun analyzeDictBlk(dictBlock: ByteArray) {
|
|
||||||
Log.d("MySD", "Read block: ${dictBlock.decodeToString()}")
|
|
||||||
val keyLen = dictBlock[63].toInt().let { if (it > 63) 63 else it }
|
|
||||||
val dataEnd = 64 + dictBlock[127].toInt().let { if (it > 63) 63 else it }
|
|
||||||
val key = dictBlock.copyOf(keyLen).decodeToString()
|
|
||||||
val data = if (dataEnd > 64) dictBlock.copyOfRange(64, dataEnd).decodeToString() else null
|
|
||||||
if(key != "") {
|
|
||||||
dict[key] = data
|
|
||||||
latestKeys += key
|
|
||||||
}
|
|
||||||
Log.d("MySD", "Fetch $key=$data")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun filterValues(predicate: (String?) -> Boolean) = dict.filterValues(predicate)
|
fun filterValues(predicate: (String?) -> Boolean) = dict.filterValues(predicate)
|
||||||
|
|
||||||
fun fetchDict(doOnLoadFailure: ()->Unit = {
|
fun fetchDict(doOnLoadFailure: ()->Unit = {
|
||||||
@@ -82,11 +67,16 @@ class SimpleDict(private val client: Client, private val pwd: String, private va
|
|||||||
}, doOnLoadSuccess: ()->Unit = {
|
}, doOnLoadSuccess: ()->Unit = {
|
||||||
Log.d("MySD", "Fetch dict success")
|
Log.d("MySD", "Fetch dict success")
|
||||||
}, doCommon: (() -> Unit)? = null) {
|
}, doCommon: (() -> Unit)? = null) {
|
||||||
val dictBlock = ByteArray(128)
|
|
||||||
dict = hashMapOf()
|
dict = hashMapOf()
|
||||||
latestKeys = arrayOf()
|
latestKeys = arrayOf()
|
||||||
raw?.inputStream()?.let {
|
raw?.let {
|
||||||
while (it.read(dictBlock, 0, 128) == 128) analyzeDictBlk(dictBlock)
|
SimpleProtobuf.getDictArray(it).forEach { d ->
|
||||||
|
d?.apply {
|
||||||
|
val k = key.decodeToString()
|
||||||
|
dict[k] = data.decodeToString()
|
||||||
|
latestKeys += k
|
||||||
|
}
|
||||||
|
}
|
||||||
doOnLoadSuccess()
|
doOnLoadSuccess()
|
||||||
}?:doOnLoadFailure()
|
}?:doOnLoadFailure()
|
||||||
doCommon?.let { it() }
|
doCommon?.let { it() }
|
||||||
@@ -95,10 +85,11 @@ class SimpleDict(private val client: Client, private val pwd: String, private va
|
|||||||
fun del(key: String): Boolean {
|
fun del(key: String): Boolean {
|
||||||
if(spwd == null) return false
|
if(spwd == null) return false
|
||||||
else if(initDict()) {
|
else if(initDict()) {
|
||||||
sendMessageWithDelay("del$spwd")
|
val delPass = "del$spwd"
|
||||||
client.receiveMessage()
|
sendMessage(delPass)
|
||||||
sendMessageWithDelay(key)
|
client.receiveRawMessage(delPass.length)
|
||||||
if(client.receiveMessage() == "succ") {
|
sendMessage(key)
|
||||||
|
if(client.receiveMessage(4) == "succ") {
|
||||||
if(closeDict()) {
|
if(closeDict()) {
|
||||||
dict.remove(key)
|
dict.remove(key)
|
||||||
val end = latestKeys.size-1
|
val end = latestKeys.size-1
|
||||||
@@ -119,18 +110,22 @@ class SimpleDict(private val client: Client, private val pwd: String, private va
|
|||||||
operator fun get(key: String) = dict[key]
|
operator fun get(key: String) = dict[key]
|
||||||
|
|
||||||
fun set(key: String, value: String): Boolean {
|
fun set(key: String, value: String): Boolean {
|
||||||
if(spwd == null) return false
|
//if(spwd == null) return false
|
||||||
else if(initDict()) {
|
val contain = dict.containsKey(key)
|
||||||
sendMessageWithDelay("set$spwd")
|
if((contain && del(key)) || !contain) {
|
||||||
client.receiveMessage()
|
if(initDict()) {
|
||||||
sendMessageWithDelay(key)
|
val setPass = "set$spwd"
|
||||||
if(client.receiveMessage() == "data") {
|
sendMessage(setPass)
|
||||||
sendMessageWithDelay(value)
|
client.receiveRawMessage(setPass.length)
|
||||||
client.receiveMessage()
|
sendMessage(key)
|
||||||
if(closeDict()) dict[key] = value
|
if(client.receiveMessage(4) == "data") {
|
||||||
return true
|
sendMessage(value)
|
||||||
} else closeDict()
|
client.receiveMessage(4)
|
||||||
}
|
if(closeDict()) dict[key] = value
|
||||||
return false
|
return true
|
||||||
|
} else closeDict()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
} else return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
84
app/src/main/java/top/fumiama/simpledict/SimpleProtobuf.java
Normal file
84
app/src/main/java/top/fumiama/simpledict/SimpleProtobuf.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package top.fumiama.simpledict;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
public class SimpleProtobuf {
|
||||||
|
public static class Dict {
|
||||||
|
public byte[] key;
|
||||||
|
public byte[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final DictStack ds = new DictStack();
|
||||||
|
|
||||||
|
public static Dict[] getDictArray(@NotNull byte[] raw) {
|
||||||
|
int offset = 0;
|
||||||
|
SLLE s;
|
||||||
|
while (offset < raw.length) {
|
||||||
|
offset += getSLLE(raw, offset).len; //struct_len
|
||||||
|
offset += getSLLE(raw, offset).len; //type
|
||||||
|
s = getSLLE(raw, offset); //data len
|
||||||
|
Log.d("MySPB", "Data len:" + s.value);
|
||||||
|
Dict d = new Dict();
|
||||||
|
d.key = new byte[s.value];
|
||||||
|
offset += s.len;
|
||||||
|
System.arraycopy(raw, offset, d.key, 0, s.value);
|
||||||
|
offset += s.value;
|
||||||
|
offset += getSLLE(raw, offset).len; //type
|
||||||
|
s = getSLLE(raw, offset); //data len
|
||||||
|
Log.d("MySPB", "Data len:" + s.value);
|
||||||
|
d.data = new byte[s.value];
|
||||||
|
offset += s.len;
|
||||||
|
System.arraycopy(raw, offset, d.data, 0, s.value);
|
||||||
|
offset += s.value;
|
||||||
|
ds.push(d);
|
||||||
|
}
|
||||||
|
return ds.popAllData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static SLLE getSLLE(byte[] p, int start) {
|
||||||
|
SLLE s = new SLLE();
|
||||||
|
s.value = 0;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
s.value += (p[start + i] & 0x7f) << (i * 7);
|
||||||
|
if ((p[start + i] & 0x80) == 0) { //无更高位
|
||||||
|
s.len = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SLLE {
|
||||||
|
int value;
|
||||||
|
int len;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DictStack extends PopAllStack<Dict> {
|
||||||
|
public Dict[] popAllData() {
|
||||||
|
Object[] t = popAll();
|
||||||
|
if (t != null) {
|
||||||
|
Dict[] d = new Dict[t.length];
|
||||||
|
for (int i = 0; i < t.length; i++) {
|
||||||
|
d[i] = (Dict) t[i];
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
} else return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PopAllStack<T> extends Stack<T> {
|
||||||
|
public Object[] popAll() {
|
||||||
|
if (size() > 0) {
|
||||||
|
Object[] t = new Object[size()];
|
||||||
|
System.arraycopy(elementData, 0, t, 0, size());
|
||||||
|
setSize(0);
|
||||||
|
return t;
|
||||||
|
} else return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
classpath 'com.android.tools.build:gradle:4.2.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
|||||||
Reference in New Issue
Block a user