Skip to content
Snippets Groups Projects
Commit 885b31c4 authored by ale's avatar ale
Browse files

embed gobipocket

parent f570971f
No related branches found
No related tags found
No related merge requests found
......@@ -7,7 +7,7 @@ import (
"regexp"
"strings"
"github.com/clee/gobipocket"
"git.autistici.org/ale/liber/third_party/gobipocket"
"github.com/meskio/epubgo"
)
......
From https://github.com/clee/gobipocket, last commit pre-decompression.
package mobipocket
import (
"encoding/binary"
"fmt"
"io"
"os"
)
type Mobipocket struct {
Metadata map[string][]string
RawTextRecords [][]byte
}
// Open reads the file into memory and parses the headers to
// populate the Metadata
func Open(path string) (m *Mobipocket, e error) {
f, e := os.Open(path)
if e != nil {
return nil, e
}
m = new(Mobipocket)
m.parse(f)
return m, nil
}
func (mobi *Mobipocket) parse(r io.ReaderAt) {
exth := map[int]string{
100: "author",
101: "publisher",
103: "description",
104: "isbn",
105: "subject",
106: "pubdate",
113: "asin",
503: "title",
504: "asin",
}
compressionTypes := map[int]string{
1: "none",
2: "palmdoc",
17480: "huffcdic",
}
drmTypes := map[int]string{
0: "unencrypted",
1: "deprecated",
2: "encrypted",
}
m := make(map[string][]string)
s := makeShortReader(r)
l := makeLongReader(r)
str := makeStringReader(r)
// uint16 at 0x4C holds the number of records
// first record's offset is a uint32 at 0x4E
//recordCount := int(s(0x4C))
firstRecordOffset := int64(l(0x4E))
headerLength := int64(l(firstRecordOffset + 0x14))
mobiversion := int(l(firstRecordOffset + 0x24))
fmt.Printf("MobiPocket file version: %d\n", mobiversion)
m["compression"] = []string{compressionTypes[int(s(firstRecordOffset))]}
m["textLength"] = []string{fmt.Sprintf("%d", l(firstRecordOffset+0x04))}
firstTextRecord := 1 // int(s(firstRecordOffset + 0xC0))
numberTextRecords := int(s(firstRecordOffset + 0x08))
//fmt.Printf("PalmDB record count: %d (first text: %d, numTR: %d)\n", recordCount, firstTextRecord, numberTextRecords)
/*
for i := int(0); i < recordCount; i++ {
fmt.Printf("\trecord %d @ 0x%04x\n", i, l(0x4E + int64(i * 8)))
}
*/
mobi.RawTextRecords = make([][]byte, 0)
for i := firstTextRecord; i < firstTextRecord+numberTextRecords; i++ {
recordStart := l(0x4E + int64(i*8))
nextRecordStart := l(0x4E + int64((i+1)*8))
record := make([]byte, nextRecordStart-recordStart)
_, err := r.ReadAt(record, int64(recordStart))
if err != nil {
panic(err)
}
//fmt.Printf("read record %d @ 0x%04x, length 0x%04x bytes\n", i, recordStart, len(record))
mobi.RawTextRecords = append(mobi.RawTextRecords, record)
}
m["drm"] = []string{drmTypes[int(s(firstRecordOffset+0x0C))]}
fullTitlePos := int64(l(firstRecordOffset + 0x54))
fullTitleLength := int64(l(firstRecordOffset + 0x58))
m["title"] = []string{str(firstRecordOffset+fullTitlePos, fullTitleLength)}
extendedFlags := int64(l(firstRecordOffset + 0x80))
if extendedFlags&0x40 != 0x40 {
mobi.Metadata = m
return
}
// extended header block should start with string EXTH
if str(firstRecordOffset+headerLength+16, 4) != "EXTH" {
fmt.Printf("extended header is all wrong, man!\n")
mobi.Metadata = m
return
}
extBaseOffset := int64(firstRecordOffset + headerLength + 16)
extCount := int(l(extBaseOffset + 8))
pos := int64(12)
for i := 0; i < extCount; i++ {
recordType := int(l(extBaseOffset + pos))
recordLength := int64(l(extBaseOffset + pos + 4))
key, valid := exth[recordType]
if valid {
m[key] = append(m[key], str(extBaseOffset+pos+8, recordLength-8))
}
pos += recordLength
}
mobi.Metadata = m
return
}
func makeShortReader(r io.ReaderAt) func(int64) uint16 {
return func(o int64) uint16 {
s := make([]byte, 2)
_, err := r.ReadAt(s, o)
if err != nil {
panic(err)
}
return binary.BigEndian.Uint16(s)
}
}
func makeLongReader(r io.ReaderAt) func(int64) uint32 {
return func(o int64) uint32 {
l := make([]byte, 4)
_, err := r.ReadAt(l, o)
if err != nil {
panic(err)
}
return binary.BigEndian.Uint32(l)
}
}
func makeStringReader(r io.ReaderAt) func(int64, int64) string {
return func(o, l int64) string {
s := make([]byte, l)
_, err := r.ReadAt(s, o)
if err != nil {
panic(err)
}
return string(s)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment