mirror of
https://github.com/gedoor/legado.git
synced 2025-08-10 00:52:30 +00:00
208 lines
5.5 KiB
Java
208 lines
5.5 KiB
Java
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 final 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 = Math.min(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;
|
|
}
|
|
}
|