edge/pkg/bundle/zim/entry.go

139 lines
2.6 KiB
Go

package zim
import (
"encoding/binary"
"fmt"
"github.com/pkg/errors"
)
type Entry interface {
Redirect() (*ContentEntry, error)
Namespace() Namespace
URL() string
FullURL() string
Title() string
}
type BaseEntry struct {
mimeTypeIndex uint16
namespace Namespace
url string
title string
reader *Reader
}
func (e *BaseEntry) Namespace() Namespace {
return e.namespace
}
func (e *BaseEntry) Title() string {
if e.title == "" {
return e.url
}
return e.title
}
func (e *BaseEntry) URL() string {
return e.url
}
func (e *BaseEntry) FullURL() string {
return toFullURL(e.Namespace(), e.URL())
}
func (r *Reader) parseBaseEntry(offset int64) (*BaseEntry, error) {
entry := &BaseEntry{
reader: r,
}
data := make([]byte, 2)
if err := r.readRange(offset, data); err != nil {
return nil, errors.WithStack(err)
}
mimeTypeIndex, err := readUint16(data, binary.LittleEndian)
if err != nil {
return nil, errors.WithStack(err)
}
entry.mimeTypeIndex = mimeTypeIndex
data = make([]byte, 1)
if err := r.readRange(offset+3, data); err != nil {
return nil, errors.WithStack(err)
}
entry.namespace = Namespace(data[0])
return entry, nil
}
type RedirectEntry struct {
*BaseEntry
redirectIndex uint32
}
func (e *RedirectEntry) Redirect() (*ContentEntry, error) {
if e.redirectIndex >= uint32(len(e.reader.urlIndex)) {
return nil, errors.Wrapf(ErrInvalidEntryIndex, "entry index '%d' out of bounds", e.redirectIndex)
}
entryPtr := e.reader.urlIndex[e.redirectIndex]
entry, err := e.reader.parseEntryAt(int64(entryPtr))
if err != nil {
return nil, errors.WithStack(err)
}
entry, err = entry.Redirect()
if err != nil {
return nil, errors.WithStack(err)
}
contentEntry, ok := entry.(*ContentEntry)
if !ok {
return nil, errors.WithStack(ErrInvalidRedirect)
}
return contentEntry, nil
}
func (r *Reader) parseRedirectEntry(offset int64, base *BaseEntry) (*RedirectEntry, error) {
entry := &RedirectEntry{
BaseEntry: base,
}
data := make([]byte, 4)
if err := r.readRange(offset+8, data); err != nil {
return nil, errors.WithStack(err)
}
redirectIndex, err := readUint32(data, binary.LittleEndian)
if err != nil {
return nil, errors.WithStack(err)
}
entry.redirectIndex = redirectIndex
url, read, err := r.readStringAt(offset + 12)
if err != nil {
return nil, errors.WithStack(err)
}
entry.url = url
title, _, err := r.readStringAt(offset + 12 + read)
if err != nil {
return nil, errors.WithStack(err)
}
entry.title = title
return entry, nil
}
func toFullURL(ns Namespace, url string) string {
return fmt.Sprintf("%s/%s", ns, url)
}