lollipop版本分开,有些新特性android5.0和6.0不支持
This commit is contained in:
1 parent
0959e50f53
commit
3cf3231da5
258 files changed
+12817
-13529
No files matched your search
@@ -0,0 +1,88 @@
|
||||
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 OutputStream
|
||||
* @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,212 @@
|
||||
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<>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package me.ag2s.umdlib.domain;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import me.ag2s.umdlib.tool.UmdUtils;
|
||||
import me.ag2s.umdlib.tool.WrapOutputStream;
|
||||
|
||||
|
||||
/**
|
||||
* This is the cover part of the UMD file.
|
||||
* <p>
|
||||
* NOTICE: if the "coverData" is empty, it will be skipped when building UMD file.
|
||||
* </P>
|
||||
* There are 3 ways to load the image data:
|
||||
* <ol>
|
||||
* <li>new constructor function of UmdCover.</li>
|
||||
* <li>use UmdCover.load function.</li>
|
||||
* <li>use UmdCover.initDefaultCover, it will generate a simple image with text.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Ray Liang (liangguanhui@qq.com)
|
||||
* 2009-12-20
|
||||
*/
|
||||
public class UmdCover {
|
||||
|
||||
private static final int DEFAULT_COVER_WIDTH = 120;
|
||||
private static final int DEFAULT_COVER_HEIGHT = 160;
|
||||
|
||||
private byte[] coverData;
|
||||
|
||||
public UmdCover() {
|
||||
}
|
||||
|
||||
public UmdCover(byte[] coverData) {
|
||||
this.coverData = coverData;
|
||||
}
|
||||
|
||||
public void load(File f) throws IOException {
|
||||
this.coverData = UmdUtils.readFile(f);
|
||||
}
|
||||
|
||||
public void load(String fileName) throws IOException {
|
||||
load(new File(fileName));
|
||||
}
|
||||
|
||||
public void initDefaultCover(String title) throws IOException {
|
||||
// BufferedImage img = new BufferedImage(DEFAULT_COVER_WIDTH, DEFAULT_COVER_HEIGHT, BufferedImage.TYPE_INT_RGB);
|
||||
// Graphics g = img.getGraphics();
|
||||
// g.setColor(Color.BLACK);
|
||||
// g.fillRect(0, 0, img.getWidth(), img.getHeight());
|
||||
// g.setColor(Color.WHITE);
|
||||
// g.setFont(new Font("����", Font.PLAIN, 12));
|
||||
//
|
||||
// FontMetrics fm = g.getFontMetrics();
|
||||
// int ascent = fm.getAscent();
|
||||
// int descent = fm.getDescent();
|
||||
// int strWidth = fm.stringWidth(title);
|
||||
// int x = (img.getWidth() - strWidth) / 2;
|
||||
// int y = (img.getHeight() - ascent - descent) / 2;
|
||||
// g.drawString(title, x, y);
|
||||
// g.dispose();
|
||||
//
|
||||
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
//
|
||||
// JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(baos);
|
||||
// JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(img);
|
||||
// param.setQuality(0.5f, false);
|
||||
// encoder.setJPEGEncodeParam(param);
|
||||
// encoder.encode(img);
|
||||
//
|
||||
// coverData = baos.toByteArray();
|
||||
}
|
||||
|
||||
public void buildCover(WrapOutputStream wos) throws IOException {
|
||||
if (coverData == null || coverData.length == 0) {
|
||||
return;
|
||||
}
|
||||
wos.writeBytes('#', 0x82, 0, 0x01, 0x0A, 0x01);
|
||||
byte[] rb = UmdUtils.genRandomBytes(4);
|
||||
wos.writeBytes(rb); //random numbers
|
||||
wos.write('$');
|
||||
wos.writeBytes(rb); //random numbers
|
||||
wos.writeInt(coverData.length + 9);
|
||||
wos.write(coverData);
|
||||
}
|
||||
|
||||
public byte[] getCoverData() {
|
||||
return coverData;
|
||||
}
|
||||
|
||||
public void setCoverData(byte[] coverData) {
|
||||
this.coverData = coverData;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,164 @@
|
||||
package me.ag2s.umdlib.domain;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
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
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return "UmdHeader{" +
|
||||
"umdType=" + umdType +
|
||||
", title='" + title + '\'' +
|
||||
", author='" + author + '\'' +
|
||||
", year='" + year + '\'' +
|
||||
", month='" + month + '\'' +
|
||||
", day='" + day + '\'' +
|
||||
", bookType='" + bookType + '\'' +
|
||||
", bookMan='" + bookMan + '\'' +
|
||||
", shopKeeper='" + shopKeeper + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user