Files
legado/epublib/src/main/java/me/ag2s/umdlib/domain/UmdChapters.java
2022-01-03 23:59:44 +08:00

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;
}
}