mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-07 19:29:16 +08:00

* Search xref objects with tolerance both to the left and right. Try searching xref to the left only if not found to the right.
114 lines
2.5 KiB
Go
114 lines
2.5 KiB
Go
/*
|
|
* This file is subject to the terms and conditions defined in
|
|
* file 'LICENSE.md', which is part of this source code package.
|
|
*/
|
|
|
|
package core
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"io"
|
|
|
|
"github.com/unidoc/unidoc/common"
|
|
)
|
|
|
|
// Offset reader encapsulates io.ReadSeeker and offsets it by the specified
|
|
// offset, thus skipping the first offset bytes. Reading always occurs after the
|
|
// offset.
|
|
type offsetReader struct {
|
|
reader io.ReadSeeker
|
|
offset int64
|
|
}
|
|
|
|
func newOffsetReader(reader io.ReadSeeker, offset int64) (*offsetReader, error) {
|
|
r := &offsetReader{
|
|
reader: reader,
|
|
offset: offset,
|
|
}
|
|
|
|
_, err := r.Seek(0, io.SeekStart)
|
|
return r, err
|
|
}
|
|
|
|
func (r *offsetReader) Read(p []byte) (n int, err error) {
|
|
return r.reader.Read(p)
|
|
}
|
|
|
|
func (r *offsetReader) Seek(offset int64, whence int) (int64, error) {
|
|
if whence == io.SeekStart {
|
|
offset += r.offset
|
|
}
|
|
|
|
n, err := r.reader.Seek(offset, whence)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
|
|
if whence == io.SeekCurrent {
|
|
n -= r.offset
|
|
}
|
|
if n < 0 {
|
|
return 0, errors.New("core.offsetReader.Seek: negative position")
|
|
}
|
|
|
|
return n, nil
|
|
}
|
|
|
|
// ReadAtLeast reads at least n bytes into slice p.
|
|
// Returns the number of bytes read (should always be == n), and an error on failure.
|
|
func (parser *PdfParser) ReadAtLeast(p []byte, n int) (int, error) {
|
|
remaining := n
|
|
start := 0
|
|
numRounds := 0
|
|
for remaining > 0 {
|
|
nRead, err := parser.reader.Read(p[start:])
|
|
if err != nil {
|
|
common.Log.Debug("ERROR Failed reading (%d;%d) %s", nRead, numRounds, err.Error())
|
|
return start, errors.New("failed reading")
|
|
}
|
|
numRounds++
|
|
start += nRead
|
|
remaining -= nRead
|
|
}
|
|
return start, nil
|
|
}
|
|
|
|
// GetFileOffset returns the current file offset, accounting for buffered position.
|
|
func (parser *PdfParser) GetFileOffset() int64 {
|
|
offset, _ := parser.rs.Seek(0, io.SeekCurrent)
|
|
offset -= int64(parser.reader.Buffered())
|
|
return offset
|
|
}
|
|
|
|
// SetFileOffset sets the file to an offset position and resets buffer.
|
|
func (parser *PdfParser) SetFileOffset(offset int64) {
|
|
if offset < 0 {
|
|
offset = 0
|
|
}
|
|
|
|
parser.rs.Seek(offset, io.SeekStart)
|
|
parser.reader = bufio.NewReader(parser.rs)
|
|
}
|
|
|
|
// ReadBytesAt reads byte content at specific offset and length within the PDF.
|
|
func (parser *PdfParser) ReadBytesAt(offset, len int64) ([]byte, error) {
|
|
curPos := parser.GetFileOffset()
|
|
|
|
_, err := parser.rs.Seek(offset, io.SeekStart)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bb := make([]byte, len)
|
|
_, err = io.ReadAtLeast(parser.rs, bb, int(len))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Restore.
|
|
parser.SetFileOffset(curPos)
|
|
|
|
return bb, nil
|
|
}
|