|
|
@@ -16,56 +16,37 @@ import java.util.regex.Matcher
|
|
|
import java.util.regex.Pattern
|
|
|
import kotlin.math.min
|
|
|
|
|
|
-class TextFile(private val book: Book) {
|
|
|
+class TextFile(private var book: Book) {
|
|
|
|
|
|
+ @Suppress("ConstPropertyName")
|
|
|
companion object {
|
|
|
private val padRegex = "^[\\n\\s]+".toRegex()
|
|
|
- private const val bufferSize = 8 * 1024 * 1024
|
|
|
- private var bufferStart = -1
|
|
|
- private var bufferEnd = -1
|
|
|
- var txtBuffer: ByteArray? = null
|
|
|
- var bookUrl = ""
|
|
|
+ private const val txtBufferSize = 8 * 1024 * 1024
|
|
|
+ private var textFile: TextFile? = null
|
|
|
+
|
|
|
+ @Synchronized
|
|
|
+ private fun getTextFile(book: Book): TextFile {
|
|
|
+ if (textFile == null || textFile?.book?.bookUrl != book.bookUrl) {
|
|
|
+ textFile = TextFile(book)
|
|
|
+ return textFile!!
|
|
|
+ }
|
|
|
+ textFile?.book = book
|
|
|
+ return textFile!!
|
|
|
+ }
|
|
|
|
|
|
@Throws(FileNotFoundException::class)
|
|
|
fun getChapterList(book: Book): ArrayList<BookChapter> {
|
|
|
- return TextFile(book).getChapterList()
|
|
|
+ return getTextFile(book).getChapterList()
|
|
|
}
|
|
|
|
|
|
@Synchronized
|
|
|
@Throws(FileNotFoundException::class)
|
|
|
fun getContent(book: Book, bookChapter: BookChapter): String {
|
|
|
- if (txtBuffer == null || bookUrl != book.bookUrl || bookChapter.start!! > bufferEnd || bookChapter.end!! < bufferStart) {
|
|
|
- bookUrl = book.bookUrl
|
|
|
- LocalBook.getBookInputStream(book).use { bis ->
|
|
|
- bufferStart = bufferSize * (bookChapter.start!! / bufferSize).toInt()
|
|
|
- txtBuffer = ByteArray(min(bufferSize, bis.available() - bufferStart))
|
|
|
- bufferEnd = bufferStart + txtBuffer!!.size
|
|
|
- bis.skip(bufferStart.toLong())
|
|
|
- bis.read(txtBuffer)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- val count = (bookChapter.end!! - bookChapter.start!!).toInt()
|
|
|
- val buffer = ByteArray(count)
|
|
|
-
|
|
|
- if (bookChapter.start!! < bufferEnd && bookChapter.end!! > bufferEnd || bookChapter.start!! < bufferStart && bookChapter.end!! > bufferStart) {
|
|
|
- /** 章节内容在缓冲区交界处 */
|
|
|
- LocalBook.getBookInputStream(book).use { bis ->
|
|
|
- bis.skip(bookChapter.start!!)
|
|
|
- bis.read(buffer)
|
|
|
- }
|
|
|
- } else {
|
|
|
- /** 章节内容在缓冲区内 */
|
|
|
- txtBuffer!!.copyInto(
|
|
|
- buffer,
|
|
|
- 0,
|
|
|
- (bookChapter.start!! - bufferStart).toInt(),
|
|
|
- (bookChapter.end!! - bufferStart).toInt()
|
|
|
- )
|
|
|
- }
|
|
|
+ return getTextFile(book).getContent(bookChapter)
|
|
|
+ }
|
|
|
|
|
|
- return String(buffer, book.fileCharset()).substringAfter(bookChapter.title)
|
|
|
- .replace(padRegex, " ")
|
|
|
+ fun clear() {
|
|
|
+ textFile = null
|
|
|
}
|
|
|
|
|
|
}
|
|
|
@@ -83,10 +64,14 @@ class TextFile(private val book: Book) {
|
|
|
|
|
|
private var charset: Charset = book.fileCharset()
|
|
|
|
|
|
+ private var txtBuffer: ByteArray? = null
|
|
|
+ private var bufferStart = -1L
|
|
|
+ private var bufferEnd = -1L
|
|
|
+
|
|
|
/**
|
|
|
* 获取目录
|
|
|
*/
|
|
|
- @Throws(FileNotFoundException::class)
|
|
|
+ @Throws(FileNotFoundException::class, SecurityException::class, EmptyFileException::class)
|
|
|
fun getChapterList(): ArrayList<BookChapter> {
|
|
|
if (book.charset == null || book.tocUrl.isBlank()) {
|
|
|
LocalBook.getBookInputStream(book).use { bis ->
|
|
|
@@ -112,6 +97,43 @@ class TextFile(private val book: Book) {
|
|
|
return toc
|
|
|
}
|
|
|
|
|
|
+ fun getContent(chapter: BookChapter): String {
|
|
|
+ val start = chapter.start!!
|
|
|
+ val end = chapter.end!!
|
|
|
+ if (txtBuffer == null || start > bufferEnd || end < bufferStart) {
|
|
|
+ LocalBook.getBookInputStream(book).use { bis ->
|
|
|
+ bufferStart = txtBufferSize * (start / txtBufferSize)
|
|
|
+ txtBuffer = ByteArray(min(txtBufferSize, bis.available() - bufferStart.toInt()))
|
|
|
+ bufferEnd = bufferStart + txtBuffer!!.size
|
|
|
+ bis.skip(bufferStart)
|
|
|
+ bis.read(txtBuffer)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ val count = (end - start).toInt()
|
|
|
+ val buffer = ByteArray(count)
|
|
|
+
|
|
|
+ if (bufferEnd in start..end || bufferStart in start..end) {
|
|
|
+ /** 章节内容在缓冲区交界处 */
|
|
|
+ LocalBook.getBookInputStream(book).use { bis ->
|
|
|
+ bis.skip(start)
|
|
|
+ bis.read(buffer)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /** 章节内容在缓冲区内 */
|
|
|
+ txtBuffer!!.copyInto(
|
|
|
+ buffer,
|
|
|
+ 0,
|
|
|
+ (start - bufferStart).toInt(),
|
|
|
+ (end - bufferStart).toInt()
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ return String(buffer, charset)
|
|
|
+ .substringAfter(chapter.title)
|
|
|
+ .replace(padRegex, " ")
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 按规则解析目录
|
|
|
*/
|
|
|
@@ -162,7 +184,7 @@ class TextFile(private val book: Book) {
|
|
|
val chapterStart = matcher.start()
|
|
|
//获取章节内容
|
|
|
val chapterContent = blockContent.substring(seekPos, chapterStart)
|
|
|
- val chapterLength = chapterContent.toByteArray(charset).size
|
|
|
+ val chapterLength = chapterContent.toByteArray(charset).size.toLong()
|
|
|
val lastStart = toc.lastOrNull()?.start ?: curOffset
|
|
|
if (book.getSplitLongChapter() && curOffset + chapterLength - lastStart > maxLengthWithToc) {
|
|
|
toc.lastOrNull()?.let {
|
|
|
@@ -186,7 +208,7 @@ class TextFile(private val book: Book) {
|
|
|
curChapter.start = curOffset + chapterLength
|
|
|
toc.add(curChapter)
|
|
|
} else if (seekPos == 0 && chapterStart != 0) {
|
|
|
- /*
|
|
|
+ /**
|
|
|
* 如果 seekPos == 0 && chapterStart != 0 表示当前block处前面有一段内容
|
|
|
* 第一种情况一定是序章 第二种情况是上一个章节的内容
|
|
|
*/
|
|
|
@@ -196,13 +218,18 @@ class TextFile(private val book: Book) {
|
|
|
val qyChapter = BookChapter()
|
|
|
qyChapter.title = "前言"
|
|
|
qyChapter.start = curOffset
|
|
|
- qyChapter.end = curOffset + chapterLength.toLong()
|
|
|
+ qyChapter.end = curOffset + chapterLength
|
|
|
toc.add(qyChapter)
|
|
|
+ book.intro = if (chapterContent.length <= 500) {
|
|
|
+ chapterContent
|
|
|
+ } else {
|
|
|
+ chapterContent.substring(0, 500)
|
|
|
+ }
|
|
|
}
|
|
|
//创建当前章节
|
|
|
val curChapter = BookChapter()
|
|
|
curChapter.title = matcher.group()
|
|
|
- curChapter.start = curOffset + chapterLength.toLong()
|
|
|
+ curChapter.start = curOffset + chapterLength
|
|
|
toc.add(curChapter)
|
|
|
} else { //否则就block分割之后,上一个章节的剩余内容
|
|
|
//获取上一章节
|
|
|
@@ -210,7 +237,7 @@ class TextFile(private val book: Book) {
|
|
|
lastChapter.isVolume =
|
|
|
chapterContent.substringAfter(lastChapter.title).isBlank()
|
|
|
//将当前段落添加上一章去
|
|
|
- lastChapter.end = lastChapter.end!! + chapterLength.toLong()
|
|
|
+ lastChapter.end = lastChapter.end!! + chapterLength
|
|
|
//创建当前章节
|
|
|
val curChapter = BookChapter()
|
|
|
curChapter.title = matcher.group()
|
|
|
@@ -224,7 +251,7 @@ class TextFile(private val book: Book) {
|
|
|
lastChapter.isVolume =
|
|
|
chapterContent.substringAfter(lastChapter.title).isBlank()
|
|
|
lastChapter.end =
|
|
|
- lastChapter.start!! + chapterContent.toByteArray(charset).size.toLong()
|
|
|
+ lastChapter.start!! + chapterLength
|
|
|
//创建当前章节
|
|
|
val curChapter = BookChapter()
|
|
|
curChapter.title = matcher.group()
|