mirror of
https://github.com/unidoc/unipdf.git
synced 2025-04-27 13:48:51 +08:00
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/unipdf/v3/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
|
|
}
|