commit
7b35a0dc84
@ -0,0 +1,138 @@ |
|||||||
|
package io.legado.app.model.localBook |
||||||
|
|
||||||
|
import android.net.Uri |
||||||
|
import android.util.Log |
||||||
|
import io.legado.app.data.entities.Book |
||||||
|
import io.legado.app.data.entities.BookChapter |
||||||
|
|
||||||
|
import io.legado.app.utils.FileUtils |
||||||
|
import io.legado.app.utils.MD5Utils |
||||||
|
import io.legado.app.utils.externalFilesDir |
||||||
|
import io.legado.app.utils.isContentScheme |
||||||
|
import me.ag2s.umdlib.domain.UmdBook |
||||||
|
import me.ag2s.umdlib.umd.UmdReader |
||||||
|
import splitties.init.appCtx |
||||||
|
import java.io.File |
||||||
|
import java.io.InputStream |
||||||
|
import java.util.ArrayList |
||||||
|
|
||||||
|
class UmdFile(var book: Book) { |
||||||
|
companion object { |
||||||
|
private var uFile: UmdFile? = null |
||||||
|
|
||||||
|
@Synchronized |
||||||
|
private fun getUFile(book: Book): UmdFile { |
||||||
|
|
||||||
|
if (uFile == null || uFile?.book?.bookUrl != book.bookUrl) { |
||||||
|
uFile = UmdFile(book) |
||||||
|
return uFile!! |
||||||
|
} |
||||||
|
uFile?.book = book |
||||||
|
return uFile!! |
||||||
|
} |
||||||
|
|
||||||
|
@Synchronized |
||||||
|
fun getChapterList(book: Book): ArrayList<BookChapter> { |
||||||
|
return getUFile(book).getChapterList() |
||||||
|
} |
||||||
|
|
||||||
|
@Synchronized |
||||||
|
fun getContent(book: Book, chapter: BookChapter): String? { |
||||||
|
return getUFile(book).getContent(chapter) |
||||||
|
} |
||||||
|
|
||||||
|
@Synchronized |
||||||
|
fun getImage( |
||||||
|
book: Book, |
||||||
|
href: String |
||||||
|
): InputStream? { |
||||||
|
return getUFile(book).getImage(href) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Synchronized |
||||||
|
fun upBookInfo(book: Book) { |
||||||
|
return getUFile(book).upBookInfo() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private var umdBook: UmdBook? = null |
||||||
|
get() { |
||||||
|
if (field != null) { |
||||||
|
return field |
||||||
|
} |
||||||
|
field = readUmd() |
||||||
|
return field |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
init { |
||||||
|
try { |
||||||
|
umdBook?.let { |
||||||
|
if (book.coverUrl.isNullOrEmpty()) { |
||||||
|
book.coverUrl = FileUtils.getPath( |
||||||
|
appCtx.externalFilesDir, |
||||||
|
"covers", |
||||||
|
"${MD5Utils.md5Encode16(book.bookUrl)}.jpg" |
||||||
|
) |
||||||
|
} |
||||||
|
if (!File(book.coverUrl!!).exists()) { |
||||||
|
FileUtils.writeBytes(book.coverUrl!!,it.cover.coverData) |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} catch (e: Exception) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
} |
||||||
|
private fun readUmd(): UmdBook? { |
||||||
|
val input= if (book.bookUrl.isContentScheme()) { |
||||||
|
val uri = Uri.parse(book.bookUrl) |
||||||
|
appCtx.contentResolver.openInputStream(uri) |
||||||
|
} else { |
||||||
|
File(book.bookUrl).inputStream() |
||||||
|
} |
||||||
|
return UmdReader().read(input) |
||||||
|
} |
||||||
|
|
||||||
|
private fun upBookInfo() { |
||||||
|
if(umdBook==null){ |
||||||
|
uFile = null |
||||||
|
book.intro = "书籍导入异常" |
||||||
|
}else{ |
||||||
|
val hd= umdBook!!.header |
||||||
|
book.name=hd.title; |
||||||
|
book.author=hd.author; |
||||||
|
book.kind=hd.bookType; |
||||||
|
} |
||||||
|
} |
||||||
|
private fun getContent(chapter: BookChapter): String? { |
||||||
|
return umdBook?.chapters?.getContentString(chapter.index) |
||||||
|
} |
||||||
|
|
||||||
|
private fun getChapterList(): ArrayList<BookChapter> { |
||||||
|
val chapterList = ArrayList<BookChapter>() |
||||||
|
umdBook?.chapters?.titles?.forEachIndexed { index, _ -> |
||||||
|
val title = umdBook!!.chapters.getTitle(index) |
||||||
|
val chapter = BookChapter() |
||||||
|
chapter.title=title; |
||||||
|
chapter.index = index |
||||||
|
chapter.bookUrl = book.bookUrl |
||||||
|
chapter.url = index.toString(); |
||||||
|
Log.d("UMD",chapter.url) |
||||||
|
chapterList.add(chapter) |
||||||
|
} |
||||||
|
book.latestChapterTitle = chapterList.lastOrNull()?.title |
||||||
|
book.totalChapterNum = chapterList.size |
||||||
|
return chapterList |
||||||
|
} |
||||||
|
|
||||||
|
private fun getImage(href: String): InputStream? { |
||||||
|
TODO("Not yet implemented") |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,81 @@ |
|||||||
|
package me.ag2s.umdlib.domain; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.io.OutputStream; |
||||||
|
|
||||||
|
import me.ag2s.umdlib.tool.WrapOutputStream; |
||||||
|
|
||||||
|
public class UmdBook { |
||||||
|
|
||||||
|
public int getNum() { |
||||||
|
return num; |
||||||
|
} |
||||||
|
|
||||||
|
public void setNum(int num) { |
||||||
|
this.num = num; |
||||||
|
} |
||||||
|
|
||||||
|
private int num; |
||||||
|
|
||||||
|
|
||||||
|
/** Header Part of UMD book */ |
||||||
|
private UmdHeader header = new UmdHeader(); |
||||||
|
/** |
||||||
|
* Detail chapters Part of UMD book |
||||||
|
* (include Titles & Contents of each chapter) |
||||||
|
*/ |
||||||
|
private UmdChapters chapters = new UmdChapters(); |
||||||
|
|
||||||
|
/** Cover Part of UMD book (for example, and JPEG file) */ |
||||||
|
private UmdCover cover = new UmdCover(); |
||||||
|
|
||||||
|
/** End Part of UMD book */ |
||||||
|
private UmdEnd end = new UmdEnd(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Build the UMD file. |
||||||
|
* @param os |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void buildUmd(OutputStream os) throws IOException { |
||||||
|
WrapOutputStream wos = new WrapOutputStream(os); |
||||||
|
|
||||||
|
header.buildHeader(wos); |
||||||
|
chapters.buildChapters(wos); |
||||||
|
cover.buildCover(wos); |
||||||
|
end.buildEnd(wos); |
||||||
|
} |
||||||
|
|
||||||
|
public UmdHeader getHeader() { |
||||||
|
return header; |
||||||
|
} |
||||||
|
|
||||||
|
public void setHeader(UmdHeader header) { |
||||||
|
this.header = header; |
||||||
|
} |
||||||
|
|
||||||
|
public UmdChapters getChapters() { |
||||||
|
return chapters; |
||||||
|
} |
||||||
|
|
||||||
|
public void setChapters(UmdChapters chapters) { |
||||||
|
this.chapters = chapters; |
||||||
|
} |
||||||
|
|
||||||
|
public UmdCover getCover() { |
||||||
|
return cover; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCover(UmdCover cover) { |
||||||
|
this.cover = cover; |
||||||
|
} |
||||||
|
|
||||||
|
public UmdEnd getEnd() { |
||||||
|
return end; |
||||||
|
} |
||||||
|
|
||||||
|
public void setEnd(UmdEnd end) { |
||||||
|
this.end = end; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,207 @@ |
|||||||
|
package me.ag2s.umdlib.domain; |
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream; |
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
import java.util.zip.DeflaterOutputStream; |
||||||
|
|
||||||
|
import me.ag2s.umdlib.tool.UmdUtils; |
||||||
|
import me.ag2s.umdlib.tool.WrapOutputStream; |
||||||
|
|
||||||
|
/** |
||||||
|
* It includes all titles and contents of each chapter in the UMD file. |
||||||
|
* And the content has been compressed by zlib. |
||||||
|
* |
||||||
|
* @author Ray Liang (liangguanhui@qq.com) |
||||||
|
* 2009-12-20 |
||||||
|
*/ |
||||||
|
public class UmdChapters { |
||||||
|
|
||||||
|
private static final int DEFAULT_CHUNK_INIT_SIZE = 32768; |
||||||
|
private int TotalContentLen; |
||||||
|
|
||||||
|
public List<byte[]> getTitles() { |
||||||
|
return titles; |
||||||
|
} |
||||||
|
|
||||||
|
private List<byte[]> titles = new ArrayList<>(); |
||||||
|
public List<Integer> contentLengths = new ArrayList<>(); |
||||||
|
public ByteArrayOutputStream contents = new ByteArrayOutputStream(); |
||||||
|
|
||||||
|
public void addTitle(String s){ |
||||||
|
titles.add(UmdUtils.stringToUnicodeBytes(s)); |
||||||
|
} |
||||||
|
public void addTitle(byte[] s){ |
||||||
|
titles.add(s); |
||||||
|
} |
||||||
|
public void addContentLength(Integer integer){ |
||||||
|
contentLengths.add(integer); |
||||||
|
} |
||||||
|
public int getContentLength(int index){ |
||||||
|
return contentLengths.get(index); |
||||||
|
} |
||||||
|
|
||||||
|
public byte[] getContent(int index) { |
||||||
|
int st=contentLengths.get(index); |
||||||
|
byte[] b=contents.toByteArray(); |
||||||
|
int end=index+1<contentLengths.size()?contentLengths.get(index+1): getTotalContentLen(); |
||||||
|
System.out.println("总长度:"+contents.size()); |
||||||
|
System.out.println("起始值:"+st); |
||||||
|
System.out.println("结束值:"+end); |
||||||
|
byte[] bAr=new byte[end-st]; |
||||||
|
System.arraycopy(b,st,bAr,0,bAr.length); |
||||||
|
return bAr; |
||||||
|
|
||||||
|
} |
||||||
|
public String getContentString(int index) { |
||||||
|
return UmdUtils.unicodeBytesToString(getContent(index)).replace((char) 0x2029, '\n'); |
||||||
|
|
||||||
|
} |
||||||
|
public String getTitle(int index){ |
||||||
|
return UmdUtils.unicodeBytesToString(titles.get(index)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void buildChapters(WrapOutputStream wos) throws IOException { |
||||||
|
writeChaptersHead(wos); |
||||||
|
writeChaptersContentOffset(wos); |
||||||
|
writeChaptersTitles(wos); |
||||||
|
writeChaptersChunks(wos); |
||||||
|
} |
||||||
|
|
||||||
|
private void writeChaptersHead(WrapOutputStream wos) throws IOException { |
||||||
|
wos.writeBytes('#', 0x0b, 0, 0, 0x09); |
||||||
|
wos.writeInt(contents.size()); |
||||||
|
} |
||||||
|
|
||||||
|
private void writeChaptersContentOffset(WrapOutputStream wos) throws IOException { |
||||||
|
wos.writeBytes('#', 0x83, 0, 0, 0x09); |
||||||
|
byte[] rb = UmdUtils.genRandomBytes(4); |
||||||
|
wos.writeBytes(rb); //random numbers
|
||||||
|
wos.write('$'); |
||||||
|
wos.writeBytes(rb); //random numbers
|
||||||
|
|
||||||
|
wos.writeInt(contentLengths.size() * 4 + 9); // about the count of chapters
|
||||||
|
int offset = 0; |
||||||
|
for (Integer n : contentLengths) { |
||||||
|
wos.writeInt(offset); |
||||||
|
offset += n; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void writeChaptersTitles(WrapOutputStream wos) throws IOException { |
||||||
|
wos.writeBytes('#', 0x84, 0, 0x01, 0x09); |
||||||
|
byte[] rb = UmdUtils.genRandomBytes(4); |
||||||
|
wos.writeBytes(rb); //random numbers
|
||||||
|
wos.write('$'); |
||||||
|
wos.writeBytes(rb); //random numbers
|
||||||
|
|
||||||
|
int totalTitlesLen = 0; |
||||||
|
for (byte[] t : titles) { |
||||||
|
totalTitlesLen += t.length; |
||||||
|
} |
||||||
|
|
||||||
|
// about the length of the titles
|
||||||
|
wos.writeInt(totalTitlesLen + titles.size() + 9); |
||||||
|
|
||||||
|
for (byte[] t : titles) { |
||||||
|
wos.writeByte(t.length); |
||||||
|
wos.write(t); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void writeChaptersChunks(WrapOutputStream wos) throws IOException { |
||||||
|
byte[] allContents = contents.toByteArray(); |
||||||
|
|
||||||
|
byte[] zero16 = new byte[16]; |
||||||
|
Arrays.fill(zero16, 0, zero16.length, (byte) 0); |
||||||
|
|
||||||
|
// write each package of content
|
||||||
|
int startPos = 0; |
||||||
|
int len = 0; |
||||||
|
int left = 0; |
||||||
|
int chunkCnt = 0; |
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream(DEFAULT_CHUNK_INIT_SIZE + 256); |
||||||
|
List<byte[]> chunkRbList = new ArrayList<byte[]>(); |
||||||
|
|
||||||
|
while(startPos < allContents.length) { |
||||||
|
left = allContents.length - startPos; |
||||||
|
len = DEFAULT_CHUNK_INIT_SIZE < left ? DEFAULT_CHUNK_INIT_SIZE : left; |
||||||
|
|
||||||
|
bos.reset(); |
||||||
|
DeflaterOutputStream zos = new DeflaterOutputStream(bos); |
||||||
|
zos.write(allContents, startPos, len); |
||||||
|
zos.close(); |
||||||
|
byte[] chunk = bos.toByteArray(); |
||||||
|
|
||||||
|
byte[] rb = UmdUtils.genRandomBytes(4); |
||||||
|
wos.writeByte('$'); |
||||||
|
wos.writeBytes(rb); // 4 random
|
||||||
|
chunkRbList.add(rb); |
||||||
|
wos.writeInt(chunk.length + 9); |
||||||
|
wos.write(chunk); |
||||||
|
|
||||||
|
// end of each chunk
|
||||||
|
wos.writeBytes('#', 0xF1, 0, 0, 0x15); |
||||||
|
wos.write(zero16); |
||||||
|
|
||||||
|
startPos += len; |
||||||
|
chunkCnt++; |
||||||
|
} |
||||||
|
|
||||||
|
// end of all chunks
|
||||||
|
wos.writeBytes('#', 0x81, 0, 0x01, 0x09); |
||||||
|
wos.writeBytes(0, 0, 0, 0); //random numbers
|
||||||
|
wos.write('$'); |
||||||
|
wos.writeBytes(0, 0, 0, 0); //random numbers
|
||||||
|
wos.writeInt(chunkCnt * 4 + 9); |
||||||
|
for (int i = chunkCnt - 1; i >= 0; i--) { |
||||||
|
// random. They are as the same as random numbers in the begin of each chunk
|
||||||
|
// use desc order to output these random
|
||||||
|
wos.writeBytes(chunkRbList.get(i)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void addChapter(String title, String content) { |
||||||
|
titles.add(UmdUtils.stringToUnicodeBytes(title)); |
||||||
|
byte[] b = UmdUtils.stringToUnicodeBytes(content); |
||||||
|
contentLengths.add(b.length); |
||||||
|
try { |
||||||
|
contents.write(b); |
||||||
|
} catch (IOException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void addFile(File f, String title) throws IOException { |
||||||
|
byte[] temp = UmdUtils.readFile(f); |
||||||
|
String s = new String(temp); |
||||||
|
addChapter(title, s); |
||||||
|
} |
||||||
|
|
||||||
|
public void addFile(File f) throws IOException { |
||||||
|
String s = f.getName(); |
||||||
|
int idx = s.lastIndexOf('.'); |
||||||
|
if (idx >= 0) { |
||||||
|
s = s.substring(0, idx); |
||||||
|
} |
||||||
|
addFile(f, s); |
||||||
|
} |
||||||
|
|
||||||
|
public void clearChapters() { |
||||||
|
titles.clear(); |
||||||
|
contentLengths.clear(); |
||||||
|
contents.reset(); |
||||||
|
} |
||||||
|
|
||||||
|
public int getTotalContentLen() { |
||||||
|
return TotalContentLen; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTotalContentLen(int totalContentLen) { |
||||||
|
TotalContentLen = totalContentLen; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package me.ag2s.umdlib.domain; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
import me.ag2s.umdlib.tool.WrapOutputStream; |
||||||
|
|
||||||
|
/** |
||||||
|
* End part of UMD book, nothing to be special |
||||||
|
* |
||||||
|
* @author Ray Liang (liangguanhui@qq.com) |
||||||
|
* 2009-12-20 |
||||||
|
*/ |
||||||
|
public class UmdEnd { |
||||||
|
|
||||||
|
public void buildEnd(WrapOutputStream wos) throws IOException { |
||||||
|
wos.writeBytes('#', 0x0C, 0, 0x01, 0x09); |
||||||
|
wos.writeInt(wos.getWritten() + 4); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,162 @@ |
|||||||
|
package me.ag2s.umdlib.domain; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
import me.ag2s.umdlib.tool.UmdUtils; |
||||||
|
import me.ag2s.umdlib.tool.WrapOutputStream; |
||||||
|
|
||||||
|
/** |
||||||
|
* Header of UMD file. |
||||||
|
* It includes a lot of properties of header. |
||||||
|
* All the properties are String type. |
||||||
|
* |
||||||
|
* @author Ray Liang (liangguanhui@qq.com) |
||||||
|
* 2009-12-20 |
||||||
|
*/ |
||||||
|
public class UmdHeader { |
||||||
|
public byte getUmdType() { |
||||||
|
return umdType; |
||||||
|
} |
||||||
|
|
||||||
|
public void setUmdType(byte umdType) { |
||||||
|
this.umdType = umdType; |
||||||
|
} |
||||||
|
|
||||||
|
private byte umdType; |
||||||
|
private String title; |
||||||
|
|
||||||
|
private String author; |
||||||
|
|
||||||
|
private String year; |
||||||
|
|
||||||
|
private String month; |
||||||
|
|
||||||
|
private String day; |
||||||
|
|
||||||
|
private String bookType; |
||||||
|
|
||||||
|
private String bookMan; |
||||||
|
|
||||||
|
private String shopKeeper; |
||||||
|
private final static byte B_type_umd = (byte) 0x01; |
||||||
|
private final static byte B_type_title = (byte) 0x02; |
||||||
|
private final static byte B_type_author = (byte) 0x03; |
||||||
|
private final static byte B_type_year = (byte) 0x04; |
||||||
|
private final static byte B_type_month = (byte) 0x05; |
||||||
|
private final static byte B_type_day = (byte) 0x06; |
||||||
|
private final static byte B_type_bookType = (byte) 0x07; |
||||||
|
private final static byte B_type_bookMan = (byte) 0x08; |
||||||
|
private final static byte B_type_shopKeeper = (byte) 0x09; |
||||||
|
|
||||||
|
public void buildHeader(WrapOutputStream wos) throws IOException { |
||||||
|
wos.writeBytes(0x89, 0x9b, 0x9a, 0xde); // UMD file type flags
|
||||||
|
wos.writeByte('#'); |
||||||
|
wos.writeBytes(0x01, 0x00, 0x00, 0x08); // Unknown
|
||||||
|
wos.writeByte(0x01); //0x01 is text type; while 0x02 is Image type.
|
||||||
|
wos.writeBytes(UmdUtils.genRandomBytes(2)); //random number
|
||||||
|
|
||||||
|
// start properties output
|
||||||
|
buildType(wos, B_type_title, getTitle()); |
||||||
|
buildType(wos, B_type_author, getAuthor()); |
||||||
|
buildType(wos, B_type_year, getYear()); |
||||||
|
buildType(wos, B_type_month, getMonth()); |
||||||
|
buildType(wos, B_type_day, getDay()); |
||||||
|
buildType(wos, B_type_bookType, getBookType()); |
||||||
|
buildType(wos, B_type_bookMan, getBookMan()); |
||||||
|
buildType(wos, B_type_shopKeeper, getShopKeeper()); |
||||||
|
} |
||||||
|
|
||||||
|
public void buildType(WrapOutputStream wos, byte type, String content) throws IOException { |
||||||
|
if (content == null || content.length() == 0) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
wos.writeBytes('#', type, 0, 0); |
||||||
|
|
||||||
|
byte[] temp = UmdUtils.stringToUnicodeBytes(content); |
||||||
|
wos.writeByte(temp.length + 5); |
||||||
|
wos.write(temp); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public String getTitle() { |
||||||
|
return title; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTitle(String title) { |
||||||
|
this.title = title; |
||||||
|
} |
||||||
|
|
||||||
|
public String getAuthor() { |
||||||
|
return author; |
||||||
|
} |
||||||
|
|
||||||
|
public void setAuthor(String author) { |
||||||
|
this.author = author; |
||||||
|
} |
||||||
|
|
||||||
|
public String getBookMan() { |
||||||
|
return bookMan; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBookMan(String bookMan) { |
||||||
|
this.bookMan = bookMan; |
||||||
|
} |
||||||
|
|
||||||
|
public String getShopKeeper() { |
||||||
|
return shopKeeper; |
||||||
|
} |
||||||
|
|
||||||
|
public void setShopKeeper(String shopKeeper) { |
||||||
|
this.shopKeeper = shopKeeper; |
||||||
|
} |
||||||
|
|
||||||
|
public String getYear() { |
||||||
|
return year; |
||||||
|
} |
||||||
|
|
||||||
|
public void setYear(String year) { |
||||||
|
this.year = year; |
||||||
|
} |
||||||
|
|
||||||
|
public String getMonth() { |
||||||
|
return month; |
||||||
|
} |
||||||
|
|
||||||
|
public void setMonth(String month) { |
||||||
|
this.month = month; |
||||||
|
} |
||||||
|
|
||||||
|
public String getDay() { |
||||||
|
return day; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDay(String day) { |
||||||
|
this.day = day; |
||||||
|
} |
||||||
|
|
||||||
|
public String getBookType() { |
||||||
|
return bookType; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBookType(String bookType) { |
||||||
|
this.bookType = bookType; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "UmdHeader{" + |
||||||
|
"umdType=" + umdType + |
||||||
|
", title='" + title + '\'' + |
||||||
|
", author='" + author + '\'' + |
||||||
|
", year='" + year + '\'' + |
||||||
|
", month='" + month + '\'' + |
||||||
|
", day='" + day + '\'' + |
||||||
|
", bookType='" + bookType + '\'' + |
||||||
|
", bookMan='" + bookMan + '\'' + |
||||||
|
", shopKeeper='" + shopKeeper + '\'' + |
||||||
|
'}'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,124 @@ |
|||||||
|
package me.ag2s.umdlib.tool; |
||||||
|
|
||||||
|
import java.io.FileInputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
|
||||||
|
public class StreamReader { |
||||||
|
private InputStream is; |
||||||
|
|
||||||
|
public long getOffset() { |
||||||
|
return offset; |
||||||
|
} |
||||||
|
|
||||||
|
public void setOffset(long offset) { |
||||||
|
this.offset = offset; |
||||||
|
} |
||||||
|
|
||||||
|
public long getSize() { |
||||||
|
return size; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSize(long size) { |
||||||
|
this.size = size; |
||||||
|
} |
||||||
|
|
||||||
|
private long offset; |
||||||
|
private long size; |
||||||
|
|
||||||
|
private void incCount(int value) { |
||||||
|
int temp = (int) (offset + value); |
||||||
|
if (temp < 0) { |
||||||
|
temp = Integer.MAX_VALUE; |
||||||
|
} |
||||||
|
offset = temp; |
||||||
|
} |
||||||
|
public StreamReader(InputStream inputStream) throws IOException { |
||||||
|
this.is=inputStream; |
||||||
|
//this.size=inputStream.getChannel().size();
|
||||||
|
} |
||||||
|
|
||||||
|
public short readUint8() throws IOException { |
||||||
|
byte[] b=new byte[1]; |
||||||
|
is.read(b); |
||||||
|
incCount(1); |
||||||
|
return (short) ((b[0] & 0xFF)); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public byte readByte() throws IOException { |
||||||
|
byte[] b=new byte[1]; |
||||||
|
is.read(b); |
||||||
|
incCount(1); |
||||||
|
return b[0]; |
||||||
|
} |
||||||
|
public byte[] readBytes(int len) throws IOException { |
||||||
|
if (len<1){ |
||||||
|
System.out.println(len); |
||||||
|
throw new IllegalArgumentException("Length must > 0: " + len); |
||||||
|
} |
||||||
|
byte[] b=new byte[len]; |
||||||
|
is.read(b); |
||||||
|
incCount(len); |
||||||
|
return b; |
||||||
|
} |
||||||
|
public String readHex(int len) throws IOException { |
||||||
|
if (len<1){ |
||||||
|
System.out.println(len); |
||||||
|
throw new IllegalArgumentException("Length must > 0: " + len); |
||||||
|
} |
||||||
|
byte[] b=new byte[len]; |
||||||
|
is.read(b); |
||||||
|
incCount(len); |
||||||
|
return UmdUtils.toHex(b); |
||||||
|
} |
||||||
|
|
||||||
|
public short readShort() throws IOException { |
||||||
|
byte[] b=new byte[2]; |
||||||
|
is.read(b); |
||||||
|
incCount(2); |
||||||
|
short x = (short) (((b[0] & 0xFF) << 8) | ((b[1] & 0xFF) << 0)); |
||||||
|
return x; |
||||||
|
} |
||||||
|
public short readShortLe() throws IOException { |
||||||
|
byte[] b=new byte[2]; |
||||||
|
is.read(b); |
||||||
|
incCount(2); |
||||||
|
short x = (short) (((b[1] & 0xFF) << 8) | ((b[0] & 0xFF) << 0)); |
||||||
|
return x; |
||||||
|
} |
||||||
|
public int readInt() throws IOException { |
||||||
|
byte[] b=new byte[4]; |
||||||
|
is.read(b); |
||||||
|
incCount(4); |
||||||
|
int x = ((b[0] & 0xFF) << 24) | ((b[1] & 0xFF) << 16) | |
||||||
|
((b[2] & 0xFF) << 8) | ((b[3] & 0xFF) << 0); |
||||||
|
return x; |
||||||
|
} |
||||||
|
public int readIntLe() throws IOException { |
||||||
|
byte[] b=new byte[4]; |
||||||
|
is.read(b); |
||||||
|
incCount(4); |
||||||
|
int x = ((b[3] & 0xFF) << 24) | ((b[2] & 0xFF) << 16) | |
||||||
|
((b[1] & 0xFF) << 8) | ((b[0] & 0xFF) << 0); |
||||||
|
return x; |
||||||
|
} |
||||||
|
public void skip(int len) throws IOException { |
||||||
|
readBytes(len); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public byte[] read(byte[] b) throws IOException { |
||||||
|
is.read(b); |
||||||
|
incCount(b.length); |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
public byte[] read(byte[] b, int off, int len) throws IOException { |
||||||
|
is.read(b, off, len); |
||||||
|
incCount(len); |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,159 @@ |
|||||||
|
|
||||||
|
package me.ag2s.umdlib.tool; |
||||||
|
|
||||||
|
import java.io.BufferedInputStream; |
||||||
|
import java.io.BufferedOutputStream; |
||||||
|
import java.io.ByteArrayInputStream; |
||||||
|
import java.io.ByteArrayOutputStream; |
||||||
|
import java.io.File; |
||||||
|
import java.io.FileInputStream; |
||||||
|
import java.io.FileOutputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.Random; |
||||||
|
import java.util.zip.InflaterInputStream; |
||||||
|
|
||||||
|
|
||||||
|
public class UmdUtils { |
||||||
|
|
||||||
|
private static final int EOF = -1; |
||||||
|
private static final int BUFFER_SIZE = 8 * 1024; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 将字符串编码成Unicode形式的byte[] |
||||||
|
* @param s 要编码的字符串 |
||||||
|
* @return 编码好的byte[] |
||||||
|
*/ |
||||||
|
public static byte[] stringToUnicodeBytes(String s) { |
||||||
|
if (s == null) { |
||||||
|
throw new NullPointerException(); |
||||||
|
} |
||||||
|
|
||||||
|
int len = s.length(); |
||||||
|
byte[] ret = new byte[len * 2]; |
||||||
|
int a, b, c; |
||||||
|
for (int i = 0; i < len; i++) { |
||||||
|
c = s.charAt(i); |
||||||
|
a = c >> 8; |
||||||
|
b = c & 0xFF; |
||||||
|
if (a < 0) { |
||||||
|
a += 0xFF; |
||||||
|
} |
||||||
|
if (b < 0) { |
||||||
|
b += 0xFF; |
||||||
|
} |
||||||
|
ret[i * 2] = (byte) b; |
||||||
|
ret[i * 2 + 1] = (byte) a; |
||||||
|
} |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将编码成Unicode形式的byte[]解码成原始字符串 |
||||||
|
* @param bytes 编码成Unicode形式的byte[] |
||||||
|
* @return 原始字符串 |
||||||
|
*/ |
||||||
|
public static String unicodeBytesToString(byte[] bytes){ |
||||||
|
char[] s=new char[bytes.length/2]; |
||||||
|
StringBuilder sb=new StringBuilder(); |
||||||
|
int a,b,c; |
||||||
|
for(int i=0;i<s.length;i++){ |
||||||
|
a=bytes[i*2+1]; |
||||||
|
b=bytes[i*2]; |
||||||
|
c=(a&0xff)<<8|(b&0xff); |
||||||
|
if(c<0){ |
||||||
|
c+=0xffff; |
||||||
|
} |
||||||
|
char[] c1=Character.toChars(c); |
||||||
|
sb.append(c1); |
||||||
|
|
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将byte[]转化成Hex形式 |
||||||
|
* @param bArr byte[] |
||||||
|
* @return 目标HEX字符串 |
||||||
|
*/ |
||||||
|
public static String toHex(byte[] bArr){ |
||||||
|
StringBuilder sb = new StringBuilder(bArr.length); |
||||||
|
String sTmp; |
||||||
|
|
||||||
|
for (int i = 0; i < bArr.length; i++) { |
||||||
|
sTmp = Integer.toHexString(0xFF & bArr[i]); |
||||||
|
if (sTmp.length() < 2) |
||||||
|
sb.append(0); |
||||||
|
sb.append(sTmp.toUpperCase()); |
||||||
|
} |
||||||
|
|
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 解压缩zip的byte[] |
||||||
|
* @param compress zippered byte[] |
||||||
|
* @return decompressed byte[] |
||||||
|
* @throws Exception 解码时失败时 |
||||||
|
*/ |
||||||
|
public static byte[] decompress(byte[] compress) throws Exception { |
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(compress); |
||||||
|
InflaterInputStream iis = new InflaterInputStream(bais); |
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
||||||
|
int c = 0; |
||||||
|
byte[] buf = new byte[BUFFER_SIZE]; |
||||||
|
while (true) { |
||||||
|
c = iis.read(buf); |
||||||
|
|
||||||
|
if (c == EOF) |
||||||
|
break; |
||||||
|
baos.write(buf, 0, c); |
||||||
|
} |
||||||
|
baos.flush(); |
||||||
|
return baos.toByteArray(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void saveFile(File f, byte[] content) throws IOException { |
||||||
|
FileOutputStream fos = new FileOutputStream(f); |
||||||
|
try { |
||||||
|
BufferedOutputStream bos = new BufferedOutputStream(fos); |
||||||
|
bos.write(content); |
||||||
|
bos.flush(); |
||||||
|
} finally { |
||||||
|
fos.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static byte[] readFile(File f) throws IOException { |
||||||
|
FileInputStream fis = new FileInputStream(f); |
||||||
|
try { |
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
||||||
|
BufferedInputStream bis = new BufferedInputStream(fis); |
||||||
|
int ch; |
||||||
|
while ((ch = bis.read()) >= 0) { |
||||||
|
baos.write(ch); |
||||||
|
} |
||||||
|
baos.flush(); |
||||||
|
return baos.toByteArray(); |
||||||
|
} finally { |
||||||
|
fis.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static Random random = new Random(); |
||||||
|
|
||||||
|
public static byte[] genRandomBytes(int len) { |
||||||
|
if (len <= 0) { |
||||||
|
throw new IllegalArgumentException("Length must > 0: " + len); |
||||||
|
} |
||||||
|
byte[] ret = new byte[len]; |
||||||
|
for (int i = 0; i < ret.length; i++) { |
||||||
|
ret[i] = (byte) random.nextInt(256); |
||||||
|
} |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
package me.ag2s.umdlib.tool; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.io.OutputStream; |
||||||
|
|
||||||
|
public class WrapOutputStream extends OutputStream { |
||||||
|
|
||||||
|
private OutputStream os; |
||||||
|
private int written; |
||||||
|
|
||||||
|
public WrapOutputStream(OutputStream os) { |
||||||
|
this.os = os; |
||||||
|
} |
||||||
|
|
||||||
|
private void incCount(int value) { |
||||||
|
int temp = written + value; |
||||||
|
if (temp < 0) { |
||||||
|
temp = Integer.MAX_VALUE; |
||||||
|
} |
||||||
|
written = temp; |
||||||
|
} |
||||||
|
|
||||||
|
// it is different from the writeInt of DataOutputStream
|
||||||
|
public void writeInt(int v) throws IOException { |
||||||
|
os.write((v >>> 0) & 0xFF); |
||||||
|
os.write((v >>> 8) & 0xFF); |
||||||
|
os.write((v >>> 16) & 0xFF); |
||||||
|
os.write((v >>> 24) & 0xFF); |
||||||
|
incCount(4); |
||||||
|
} |
||||||
|
|
||||||
|
public void writeByte(byte b) throws IOException { |
||||||
|
write(b); |
||||||
|
} |
||||||
|
|
||||||
|
public void writeByte(int n) throws IOException { |
||||||
|
write(n); |
||||||
|
} |
||||||
|
|
||||||
|
public void writeBytes(byte ... bytes) throws IOException { |
||||||
|
write(bytes); |
||||||
|
} |
||||||
|
|
||||||
|
public void writeBytes(int ... vals) throws IOException { |
||||||
|
for (int v : vals) { |
||||||
|
write(v); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException { |
||||||
|
os.write(b, off, len); |
||||||
|
incCount(len); |
||||||
|
} |
||||||
|
|
||||||
|
public void write(byte[] b) throws IOException { |
||||||
|
os.write(b); |
||||||
|
incCount(b.length); |
||||||
|
} |
||||||
|
|
||||||
|
public void write(int b) throws IOException { |
||||||
|
os.write(b); |
||||||
|
incCount(1); |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void close() throws IOException { |
||||||
|
os.close(); |
||||||
|
} |
||||||
|
|
||||||
|
public void flush() throws IOException { |
||||||
|
os.flush(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object obj) { |
||||||
|
return os.equals(obj); |
||||||
|
} |
||||||
|
|
||||||
|
public int hashCode() { |
||||||
|
return os.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
return os.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public int getWritten() { |
||||||
|
return written; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,222 @@ |
|||||||
|
package me.ag2s.umdlib.umd; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
|
||||||
|
|
||||||
|
import me.ag2s.umdlib.domain.UmdBook; |
||||||
|
import me.ag2s.umdlib.domain.UmdCover; |
||||||
|
import me.ag2s.umdlib.domain.UmdHeader; |
||||||
|
import me.ag2s.umdlib.tool.StreamReader; |
||||||
|
import me.ag2s.umdlib.tool.UmdUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* UMD格式的电子书解析 |
||||||
|
* 格式规范参考: |
||||||
|
* http://blog.sina.com.cn/s/blog_7c8dc2d501018o5d.html
|
||||||
|
* http://blog.sina.com.cn/s/blog_7c8dc2d501018o5l.html
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
public class UmdReader { |
||||||
|
UmdBook book; |
||||||
|
InputStream inputStream; |
||||||
|
int _AdditionalCheckNumber; |
||||||
|
int _TotalContentLen; |
||||||
|
boolean end = false; |
||||||
|
|
||||||
|
|
||||||
|
public synchronized UmdBook read(InputStream inputStream) throws Exception { |
||||||
|
|
||||||
|
book = new UmdBook(); |
||||||
|
this.inputStream=inputStream; |
||||||
|
StreamReader reader = new StreamReader(inputStream); |
||||||
|
UmdHeader umdHeader = new UmdHeader(); |
||||||
|
book.setHeader(umdHeader); |
||||||
|
if (reader.readIntLe() != 0xde9a9b89) { |
||||||
|
throw new IOException("Wrong header"); |
||||||
|
} |
||||||
|
short num1 = -1; |
||||||
|
byte ch = reader.readByte(); |
||||||
|
while (ch == 35) { |
||||||
|
//int num2=reader.readByte();
|
||||||
|
short segType = reader.readShortLe(); |
||||||
|
byte segFlag = reader.readByte(); |
||||||
|
short len = (short) (reader.readUint8() - 5); |
||||||
|
|
||||||
|
System.out.println("块标识:" + segType); |
||||||
|
//short length1 = reader.readByte();
|
||||||
|
ReadSection(segType, segFlag, len, reader, umdHeader); |
||||||
|
|
||||||
|
if ((int) segType == 241 || (int) segType == 10) { |
||||||
|
segType = num1; |
||||||
|
} |
||||||
|
for (ch = reader.readByte(); ch == 36; ch = reader.readByte()) { |
||||||
|
//int num3 = reader.readByte();
|
||||||
|
System.out.println(ch); |
||||||
|
int additionalCheckNumber = reader.readIntLe(); |
||||||
|
int length2 = (reader.readIntLe() - 9); |
||||||
|
ReadAdditionalSection(segType, additionalCheckNumber, length2, reader); |
||||||
|
} |
||||||
|
num1 = segType; |
||||||
|
|
||||||
|
} |
||||||
|
System.out.println(book.getHeader().toString()); |
||||||
|
return book; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private void ReadAdditionalSection(short segType, int additionalCheckNumber, int length, StreamReader reader) throws Exception { |
||||||
|
switch (segType) { |
||||||
|
case 14: |
||||||
|
//this._TotalImageList.Add((object) Image.FromStream((Stream) new MemoryStream(reader.ReadBytes((int) length))));
|
||||||
|
break; |
||||||
|
case 15: |
||||||
|
//this._TotalImageList.Add((object) Image.FromStream((Stream) new MemoryStream(reader.ReadBytes((int) length))));
|
||||||
|
break; |
||||||
|
case 129: |
||||||
|
reader.readBytes(length); |
||||||
|
break; |
||||||
|
case 130: |
||||||
|
//byte[] covers = reader.readBytes(length);
|
||||||
|
book.setCover(new UmdCover(reader.readBytes(length))); |
||||||
|
//this._Book.Cover = BitmapImage.FromStream((Stream) new MemoryStream(reader.ReadBytes((int) length)));
|
||||||
|
break; |
||||||
|
case 131: |
||||||
|
System.out.println(length / 4); |
||||||
|
book.setNum(length / 4); |
||||||
|
for (int i = 0; i < length / 4; ++i) { |
||||||
|
book.getChapters().addContentLength(reader.readIntLe()); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 132: |
||||||
|
//System.out.println(length/4);
|
||||||
|
System.out.println(_AdditionalCheckNumber); |
||||||
|
System.out.println(additionalCheckNumber); |
||||||
|
if (this._AdditionalCheckNumber != additionalCheckNumber) { |
||||||
|
System.out.println(length); |
||||||
|
book.getChapters().contents.write(UmdUtils.decompress(reader.readBytes(length))); |
||||||
|
book.getChapters().contents.flush(); |
||||||
|
break; |
||||||
|
} else { |
||||||
|
for (int i = 0; i < book.getNum(); i++) { |
||||||
|
short len = reader.readUint8(); |
||||||
|
byte[] title = reader.readBytes(len); |
||||||
|
//System.out.println(UmdUtils.unicodeBytesToString(title));
|
||||||
|
book.getChapters().addTitle(title); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
break; |
||||||
|
default: |
||||||
|
/*Console.WriteLine("未知内容"); |
||||||
|
Console.WriteLine("Seg Type = " + (object) segType); |
||||||
|
Console.WriteLine("Seg Len = " + (object) length); |
||||||
|
Console.WriteLine("content = " + (object) reader.ReadBytes((int) length));*/ |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void ReadSection(short segType, byte segFlag, short length, StreamReader reader, UmdHeader header) throws IOException { |
||||||
|
switch (segType) { |
||||||
|
case 1://umd文件头 DCTS_CMD_ID_VERSION
|
||||||
|
header.setUmdType(reader.readByte()); |
||||||
|
reader.readBytes(2);//Random 2
|
||||||
|
System.out.println("UMD文件类型:" + header.getUmdType()); |
||||||
|
break; |
||||||
|
case 2://文件标题 DCTS_CMD_ID_TITLE
|
||||||
|
header.setTitle(UmdUtils.unicodeBytesToString(reader.readBytes(length))); |
||||||
|
System.out.println("文件标题:" + header.getTitle()); |
||||||
|
break; |
||||||
|
case 3://作者
|
||||||
|
header.setAuthor(UmdUtils.unicodeBytesToString(reader.readBytes(length))); |
||||||
|
System.out.println("作者:" + header.getAuthor()); |
||||||
|
break; |
||||||
|
case 4://年
|
||||||
|
header.setYear(UmdUtils.unicodeBytesToString(reader.readBytes(length))); |
||||||
|
System.out.println("年:" + header.getYear()); |
||||||
|
break; |
||||||
|
case 5://月
|
||||||
|
header.setMonth(UmdUtils.unicodeBytesToString(reader.readBytes(length))); |
||||||
|
System.out.println("月:" + header.getMonth()); |
||||||
|
break; |
||||||
|
case 6://日
|
||||||
|
header.setDay(UmdUtils.unicodeBytesToString(reader.readBytes(length))); |
||||||
|
System.out.println("日:" + header.getDay()); |
||||||
|
break; |
||||||
|
case 7://小说类型
|
||||||
|
header.setBookType(UmdUtils.unicodeBytesToString(reader.readBytes(length))); |
||||||
|
System.out.println("小说类型:" + header.getBookType()); |
||||||
|
break; |
||||||
|
case 8://出版商
|
||||||
|
header.setBookMan(UmdUtils.unicodeBytesToString(reader.readBytes(length))); |
||||||
|
System.out.println("出版商:" + header.getBookMan()); |
||||||
|
break; |
||||||
|
case 9:// 零售商
|
||||||
|
header.setShopKeeper(UmdUtils.unicodeBytesToString(reader.readBytes(length))); |
||||||
|
System.out.println("零售商:" + header.getShopKeeper()); |
||||||
|
break; |
||||||
|
case 10://CONTENT ID
|
||||||
|
System.out.println("CONTENT ID:" + reader.readHex(length)); |
||||||
|
break; |
||||||
|
case 11: |
||||||
|
//内容长度 DCTS_CMD_ID_FILE_LENGTH
|
||||||
|
_TotalContentLen = reader.readIntLe(); |
||||||
|
book.getChapters().setTotalContentLen(_TotalContentLen); |
||||||
|
System.out.println("内容长度:" + _TotalContentLen); |
||||||
|
break; |
||||||
|
case 12://UMD文件结束
|
||||||
|
end = true; |
||||||
|
int num2 = reader.readIntLe(); |
||||||
|
System.out.println("整个文件长度" + num2); |
||||||
|
break; |
||||||
|
case 13: |
||||||
|
break; |
||||||
|
case 14: |
||||||
|
int num3 = (int) reader.readByte(); |
||||||
|
break; |
||||||
|
case 15: |
||||||
|
reader.readBytes(length); |
||||||
|
break; |
||||||
|
case 129://正文
|
||||||
|
case 131://章节偏移
|
||||||
|
_AdditionalCheckNumber = reader.readIntLe(); |
||||||
|
System.out.println("章节偏移:" + _AdditionalCheckNumber); |
||||||
|
break; |
||||||
|
case 132://章节标题,正文
|
||||||
|
_AdditionalCheckNumber = reader.readIntLe(); |
||||||
|
System.out.println("章节标题,正文:" + _AdditionalCheckNumber); |
||||||
|
break; |
||||||
|
case 130://封面(jpg)
|
||||||
|
int num4 = (int) reader.readByte(); |
||||||
|
_AdditionalCheckNumber = reader.readIntLe(); |
||||||
|
break; |
||||||
|
case 135://页面偏移(Page Offset)
|
||||||
|
reader.readUint8();//fontSize 一字节 字体大小
|
||||||
|
reader.readUint8();//screenWidth 屏幕宽度
|
||||||
|
reader.readBytes(4);//BlockRandom 指向一个页面偏移数据块
|
||||||
|
break; |
||||||
|
case 240://CDS KEY
|
||||||
|
break; |
||||||
|
case 241://许可证(LICENCE KEY)
|
||||||
|
//System.out.println("整个文件长度" + length);
|
||||||
|
System.out.println("许可证(LICENCE KEY):" + reader.readHex(16)); |
||||||
|
break; |
||||||
|
default: |
||||||
|
if (length > 0) { |
||||||
|
byte[] numArray = reader.readBytes(length); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "UmdReader{" + |
||||||
|
"book=" + book + |
||||||
|
'}'; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue