diff --git a/CHANGELOG.md b/CHANGELOG.md index ca31fe7..fdccc55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.0.0 + +- Add web support +- Support badly formatted PDFs that have only 19 byte long xref sections +- **Breaking** FileStream has moved to dart_pdf_reader_io library + ## 1.0.1 - Added funding to pubspec.yaml @@ -17,7 +23,8 @@ ## 0.5.0 - Add support for web by using the archive package. (#48) -- **Breaking**: EOFException and ParseException now no longer implement dart:io's IOException, just base Exception. (#48) +- **Breaking**: EOFException and ParseException now no longer implement dart:io's IOException, just base Exception. ( + #48) ## 0.4.3 diff --git a/analysis_options.yaml b/analysis_options.yaml index 752da3a..5d8264d 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -12,3 +12,16 @@ linter: - prefer_const_constructors - prefer_final_locals - omit_local_variable_types + - prefer_relative_imports + - avoid_print + - avoid_unnecessary_containers + - avoid_web_libraries_in_flutter + - no_logic_in_create_state + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + - sized_box_for_whitespace + - sort_child_properties_last + - use_build_context_synchronously + - use_full_hex_values_for_flutter_colors + - use_key_in_widget_constructors \ No newline at end of file diff --git a/example/example.dart b/example/example.dart index 7552659..c7ec9ac 100644 --- a/example/example.dart +++ b/example/example.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'dart:io'; import 'package:dart_pdf_reader/dart_pdf_reader.dart'; diff --git a/lib/dart_pdf_reader.dart b/lib/dart_pdf_reader.dart index 2569790..a19afe3 100644 --- a/lib/dart_pdf_reader.dart +++ b/lib/dart_pdf_reader.dart @@ -11,5 +11,4 @@ export 'src/parser/object_resolver.dart'; export 'src/parser/pdf_parser.dart' show PDFParser; export 'src/utils/byte_stream.dart'; export 'src/utils/cache/buffered_random_access_stream.dart'; -export 'src/utils/file_stream.dart'; export 'src/utils/random_access_stream.dart'; diff --git a/lib/dart_pdf_reader_io.dart b/lib/dart_pdf_reader_io.dart new file mode 100644 index 0000000..ffb029c --- /dev/null +++ b/lib/dart_pdf_reader_io.dart @@ -0,0 +1,4 @@ +library dart_pdf_reader_io; + +export 'dart_pdf_reader.dart'; +export 'src/utils/file_stream.dart'; diff --git a/lib/src/model/indirect_object_table.dart b/lib/src/model/indirect_object_table.dart index c1cb945..049b8c9 100644 --- a/lib/src/model/indirect_object_table.dart +++ b/lib/src/model/indirect_object_table.dart @@ -1,5 +1,5 @@ -import 'package:dart_pdf_reader/src/model/pdf_types.dart'; -import 'package:dart_pdf_reader/src/parser/xref_reader.dart'; +import 'pdf_types.dart'; +import '../parser/xref_reader.dart'; class IndirectObjectTable { final XRefTable _xrefTable; diff --git a/lib/src/model/pdf_constants.dart b/lib/src/model/pdf_constants.dart index 8f60e9e..2ef1bf5 100644 --- a/lib/src/model/pdf_constants.dart +++ b/lib/src/model/pdf_constants.dart @@ -1,11 +1,11 @@ -import 'package:dart_pdf_reader/src/model/pdf_types.dart'; +import 'pdf_types.dart'; import 'package:meta/meta.dart'; /// Collection of names used in PDF files @immutable final class PDFNames { // coverage:ignore-start - PDFNames._(); + const PDFNames._(); // coverage:ignore-end diff --git a/lib/src/model/pdf_document.dart b/lib/src/model/pdf_document.dart index 8784a7d..8312d67 100644 --- a/lib/src/model/pdf_document.dart +++ b/lib/src/model/pdf_document.dart @@ -1,7 +1,7 @@ -import 'package:dart_pdf_reader/src/model/pdf_constants.dart'; -import 'package:dart_pdf_reader/src/model/pdf_document_catalog.dart'; -import 'package:dart_pdf_reader/src/model/pdf_types.dart'; -import 'package:dart_pdf_reader/src/parser/object_resolver.dart'; +import 'pdf_constants.dart'; +import 'pdf_document_catalog.dart'; +import 'pdf_types.dart'; +import '../parser/object_resolver.dart'; /// Holds the data for the PDF document. class PDFDocument { diff --git a/lib/src/model/pdf_document_catalog.dart b/lib/src/model/pdf_document_catalog.dart index bf0b371..5cf92e4 100644 --- a/lib/src/model/pdf_document_catalog.dart +++ b/lib/src/model/pdf_document_catalog.dart @@ -1,9 +1,9 @@ -import 'package:dart_pdf_reader/src/model/pdf_constants.dart'; -import 'package:dart_pdf_reader/src/model/pdf_document.dart'; -import 'package:dart_pdf_reader/src/model/pdf_outline.dart'; -import 'package:dart_pdf_reader/src/model/pdf_page.dart'; -import 'package:dart_pdf_reader/src/model/pdf_types.dart'; -import 'package:dart_pdf_reader/src/parser/object_resolver.dart'; +import 'pdf_constants.dart'; +import 'pdf_document.dart'; +import 'pdf_outline.dart'; +import 'pdf_page.dart'; +import 'pdf_types.dart'; +import '../parser/object_resolver.dart'; /// The document catalog describing the document class PDFDocumentCatalog { diff --git a/lib/src/model/pdf_outline.dart b/lib/src/model/pdf_outline.dart index 0d51f82..78c660e 100644 --- a/lib/src/model/pdf_outline.dart +++ b/lib/src/model/pdf_outline.dart @@ -1,4 +1,4 @@ -import 'package:dart_pdf_reader/dart_pdf_reader.dart'; +import '../../dart_pdf_reader.dart'; import 'package:meta/meta.dart'; /// Action types for pdf outlines diff --git a/lib/src/model/pdf_page.dart b/lib/src/model/pdf_page.dart index 7f57e2e..f7c3362 100644 --- a/lib/src/model/pdf_page.dart +++ b/lib/src/model/pdf_page.dart @@ -1,10 +1,10 @@ import 'dart:math'; -import 'package:dart_pdf_reader/src/error/exceptions.dart'; -import 'package:dart_pdf_reader/src/model/pdf_constants.dart'; -import 'package:dart_pdf_reader/src/model/pdf_document.dart'; -import 'package:dart_pdf_reader/src/model/pdf_types.dart'; -import 'package:dart_pdf_reader/src/parser/object_resolver.dart'; +import '../error/exceptions.dart'; +import 'pdf_constants.dart'; +import 'pdf_document.dart'; +import 'pdf_types.dart'; +import '../parser/object_resolver.dart'; /// Pages tree root of the document class PDFPages { diff --git a/lib/src/model/pdf_types.dart b/lib/src/model/pdf_types.dart index 6527905..cfaf402 100644 --- a/lib/src/model/pdf_types.dart +++ b/lib/src/model/pdf_types.dart @@ -4,11 +4,11 @@ import 'dart:typed_data'; import 'package:charset/charset.dart'; import 'package:collection/collection.dart'; -import 'package:dart_pdf_reader/src/error/exceptions.dart'; -import 'package:dart_pdf_reader/src/model/pdf_constants.dart'; -import 'package:dart_pdf_reader/src/parser/object_resolver.dart'; -import 'package:dart_pdf_reader/src/utils/filter/stream_filter.dart'; -import 'package:dart_pdf_reader/src/utils/random_access_stream.dart'; +import '../error/exceptions.dart'; +import 'pdf_constants.dart'; +import '../parser/object_resolver.dart'; +import '../utils/filter/stream_filter.dart'; +import '../utils/random_access_stream.dart'; import 'package:meta/meta.dart'; /// Base class for all PDF objects. diff --git a/lib/src/parser/indirect_object_parser.dart b/lib/src/parser/indirect_object_parser.dart index ab6106e..54d6cf9 100644 --- a/lib/src/parser/indirect_object_parser.dart +++ b/lib/src/parser/indirect_object_parser.dart @@ -1,14 +1,14 @@ -import 'package:dart_pdf_reader/src/error/exceptions.dart'; -import 'package:dart_pdf_reader/src/model/indirect_object_table.dart'; -import 'package:dart_pdf_reader/src/model/pdf_constants.dart'; -import 'package:dart_pdf_reader/src/model/pdf_types.dart'; -import 'package:dart_pdf_reader/src/parser/object_resolver.dart'; -import 'package:dart_pdf_reader/src/parser/pdf_object_parser.dart'; -import 'package:dart_pdf_reader/src/parser/token_stream.dart'; -import 'package:dart_pdf_reader/src/parser/xref_reader.dart'; -import 'package:dart_pdf_reader/src/utils/byte_stream.dart'; -import 'package:dart_pdf_reader/src/utils/random_access_stream.dart'; -import 'package:dart_pdf_reader/src/utils/reader_helper.dart'; +import '../error/exceptions.dart'; +import '../model/indirect_object_table.dart'; +import '../model/pdf_constants.dart'; +import '../model/pdf_types.dart'; +import 'object_resolver.dart'; +import 'pdf_object_parser.dart'; +import 'token_stream.dart'; +import 'xref_reader.dart'; +import '../utils/byte_stream.dart'; +import '../utils/random_access_stream.dart'; +import '../utils/reader_helper.dart'; class IndirectObjectParser { final RandomAccessStream _buffer; diff --git a/lib/src/parser/object_resolver.dart b/lib/src/parser/object_resolver.dart index 9cb37bb..0e4c73f 100644 --- a/lib/src/parser/object_resolver.dart +++ b/lib/src/parser/object_resolver.dart @@ -1,6 +1,6 @@ -import 'package:dart_pdf_reader/src/model/indirect_object_table.dart'; -import 'package:dart_pdf_reader/src/model/pdf_types.dart'; -import 'package:dart_pdf_reader/src/parser/indirect_object_parser.dart'; +import '../model/indirect_object_table.dart'; +import '../model/pdf_types.dart'; +import 'indirect_object_parser.dart'; class ObjectResolver { final IndirectObjectParser _indirectObjectParser; diff --git a/lib/src/parser/pdf_object_parser.dart b/lib/src/parser/pdf_object_parser.dart index 30634a0..7a8ec83 100644 --- a/lib/src/parser/pdf_object_parser.dart +++ b/lib/src/parser/pdf_object_parser.dart @@ -1,8 +1,8 @@ -import 'package:dart_pdf_reader/dart_pdf_reader.dart'; -import 'package:dart_pdf_reader/src/parser/indirect_object_parser.dart'; -import 'package:dart_pdf_reader/src/parser/token_stream.dart'; -import 'package:dart_pdf_reader/src/utils/list_extensions.dart'; -import 'package:dart_pdf_reader/src/utils/reader_helper.dart'; +import '../../dart_pdf_reader.dart'; +import 'indirect_object_parser.dart'; +import 'token_stream.dart'; +import '../utils/list_extensions.dart'; +import '../utils/reader_helper.dart'; class PDFObjectParser { final RandomAccessStream _buffer; diff --git a/lib/src/parser/pdf_parser.dart b/lib/src/parser/pdf_parser.dart index b83f0df..b4ec566 100644 --- a/lib/src/parser/pdf_parser.dart +++ b/lib/src/parser/pdf_parser.dart @@ -1,13 +1,13 @@ -import 'package:dart_pdf_reader/src/model/indirect_object_table.dart'; -import 'package:dart_pdf_reader/src/model/pdf_constants.dart'; -import 'package:dart_pdf_reader/src/model/pdf_document.dart'; -import 'package:dart_pdf_reader/src/model/pdf_types.dart'; -import 'package:dart_pdf_reader/src/parser/indirect_object_parser.dart'; -import 'package:dart_pdf_reader/src/parser/object_resolver.dart'; -import 'package:dart_pdf_reader/src/parser/pdf_object_parser.dart'; -import 'package:dart_pdf_reader/src/parser/xref_reader.dart'; -import 'package:dart_pdf_reader/src/utils/random_access_stream.dart'; -import 'package:dart_pdf_reader/src/utils/reader_helper.dart'; +import '../model/indirect_object_table.dart'; +import '../model/pdf_constants.dart'; +import '../model/pdf_document.dart'; +import '../model/pdf_types.dart'; +import 'indirect_object_parser.dart'; +import 'object_resolver.dart'; +import 'pdf_object_parser.dart'; +import 'xref_reader.dart'; +import '../utils/random_access_stream.dart'; +import '../utils/reader_helper.dart'; import 'package:meta/meta.dart'; /// Parses a PDF document from a [RandomAccessStream]. @@ -30,11 +30,12 @@ class PDFParser { final objectParser = IndirectObjectParser(_buffer, table); PDFDictionary? mainTrailer; - final first = true; + var first = true; while (true) { final trailer = (first && parsedXRefTrailer != null) ? parsedXRefTrailer : await parseTrailer(objectParser, _buffer); + first = false; mainTrailer ??= trailer; final prev = trailer[PDFNames.prev] as PDFNumber?; if (prev == null) break; diff --git a/lib/src/parser/token_stream.dart b/lib/src/parser/token_stream.dart index 14395da..de28496 100644 --- a/lib/src/parser/token_stream.dart +++ b/lib/src/parser/token_stream.dart @@ -1,4 +1,4 @@ -import 'package:dart_pdf_reader/src/utils/random_access_stream.dart'; +import '../utils/random_access_stream.dart'; typedef CharCode = int; diff --git a/lib/src/parser/xref_reader.dart b/lib/src/parser/xref_reader.dart index 741007e..89ef83e 100644 --- a/lib/src/parser/xref_reader.dart +++ b/lib/src/parser/xref_reader.dart @@ -1,17 +1,17 @@ import 'dart:math'; import 'dart:typed_data'; -import 'package:dart_pdf_reader/src/error/exceptions.dart'; -import 'package:dart_pdf_reader/src/model/indirect_object_table.dart'; -import 'package:dart_pdf_reader/src/model/pdf_constants.dart'; -import 'package:dart_pdf_reader/src/model/pdf_types.dart'; -import 'package:dart_pdf_reader/src/parser/indirect_object_parser.dart'; -import 'package:dart_pdf_reader/src/parser/object_resolver.dart'; -import 'package:dart_pdf_reader/src/parser/pdf_object_parser.dart'; -import 'package:dart_pdf_reader/src/parser/token_stream.dart'; -import 'package:dart_pdf_reader/src/utils/filter/direct_byte_stream.dart'; -import 'package:dart_pdf_reader/src/utils/random_access_stream.dart'; -import 'package:dart_pdf_reader/src/utils/reader_helper.dart'; +import '../error/exceptions.dart'; +import '../model/indirect_object_table.dart'; +import '../model/pdf_constants.dart'; +import '../model/pdf_types.dart'; +import 'indirect_object_parser.dart'; +import 'object_resolver.dart'; +import 'pdf_object_parser.dart'; +import 'token_stream.dart'; +import '../utils/filter/direct_byte_stream.dart'; +import '../utils/random_access_stream.dart'; +import '../utils/reader_helper.dart'; import 'package:meta/meta.dart'; @immutable @@ -244,10 +244,22 @@ class _XRefSubsectionReader { final numEntries = int.parse(parts[1]); final entries = []; - final lineBytes = Uint8List(20); + var readSize = 20; + final lineBytes = Uint8List(readSize); var id = startIndex; for (var i = 0; i < numEntries; ++i) { - await stream.readBuffer(20, lineBytes); + await stream.readBuffer(readSize, lineBytes); + + if (i == 0) { + final last = lineBytes.last; + if (last >= 0x30 && last <= 0x39) { + // Some lines 19 bytes long even though that is not the standard + // To support this, start using 19 by tes and step 1 back + await stream.seek((await stream.position) - 1); + // Read 19 bytes from now on + readSize = 19; + } + } final offset = int.parse(String.fromCharCodes(lineBytes.getRange(0, 10))); final generation = diff --git a/lib/src/utils/byte_stream.dart b/lib/src/utils/byte_stream.dart index 3789e10..afd6634 100644 --- a/lib/src/utils/byte_stream.dart +++ b/lib/src/utils/byte_stream.dart @@ -1,7 +1,7 @@ import 'dart:math'; import 'dart:typed_data'; -import 'package:dart_pdf_reader/src/utils/random_access_stream.dart'; +import 'random_access_stream.dart'; /// Implementation of [RandomAccessStream] which reads from a list of bytes class ByteStream extends RandomAccessStream { diff --git a/lib/src/utils/cache/buffered_random_access_stream.dart b/lib/src/utils/cache/buffered_random_access_stream.dart index 4301dd2..d682234 100644 --- a/lib/src/utils/cache/buffered_random_access_stream.dart +++ b/lib/src/utils/cache/buffered_random_access_stream.dart @@ -1,9 +1,9 @@ import 'dart:math'; import 'dart:typed_data'; -import 'package:dart_pdf_reader/src/utils/byte_stream.dart'; -import 'package:dart_pdf_reader/src/utils/cache/lru_map.dart'; -import 'package:dart_pdf_reader/src/utils/random_access_stream.dart'; +import '../byte_stream.dart'; +import '../random_access_stream.dart'; +import 'lru_map.dart'; /// Implementation of [RandomAccessStream] which buffers reads from another stream /// This is useful for improving performance when reading from a slow stream @@ -30,11 +30,15 @@ class BufferedRandomAccessStream extends RandomAccessStream { int maxNumBlocks = 10, }) : _blockSize = blockSize, _cache = LRUMap(maxNumBlocks) { - if (_stream is ByteStream) { - print( - 'Warning: BufferedRandomAccessStream is not recommended for ByteStream', - ); - } + assert(() { + if (_stream is ByteStream) { + // ignore: avoid_print + print( + 'Warning: BufferedRandomAccessStream is not recommended for ByteStream', + ); + } + return true; + }()); } @override diff --git a/lib/src/utils/file_stream.dart b/lib/src/utils/file_stream.dart index 6b05e15..2a2ad93 100644 --- a/lib/src/utils/file_stream.dart +++ b/lib/src/utils/file_stream.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'dart:typed_data'; -import 'package:dart_pdf_reader/src/utils/random_access_stream.dart'; +import 'random_access_stream.dart'; /// Implementation of [RandomAccessStream] which reads from a file /// Currently this does not perform smart buffering and can be quite slow diff --git a/lib/src/utils/filter/stream_filter.dart b/lib/src/utils/filter/stream_filter.dart index c99a4db..970da93 100644 --- a/lib/src/utils/filter/stream_filter.dart +++ b/lib/src/utils/filter/stream_filter.dart @@ -1,9 +1,9 @@ import 'dart:typed_data'; -import 'package:dart_pdf_reader/dart_pdf_reader.dart'; -import 'package:dart_pdf_reader/src/utils/filter/direct_byte_stream.dart'; +import '../../../dart_pdf_reader.dart'; +import 'direct_byte_stream.dart'; import 'package:archive/archive.dart'; -import 'package:dart_pdf_reader/src/utils/list_extensions.dart'; +import '../list_extensions.dart'; part 'ascii_85_decode_filter.dart'; part 'ascii_hex_decode_filter.dart'; diff --git a/lib/src/utils/random_access_stream.dart b/lib/src/utils/random_access_stream.dart index f6b4e32..0440ee9 100644 --- a/lib/src/utils/random_access_stream.dart +++ b/lib/src/utils/random_access_stream.dart @@ -1,6 +1,6 @@ import 'dart:typed_data'; -import 'package:dart_pdf_reader/src/error/exceptions.dart'; +import '../error/exceptions.dart'; /// An abstraction of a stream of bytes that can be read from. abstract class RandomAccessStream { diff --git a/lib/src/utils/reader_helper.dart b/lib/src/utils/reader_helper.dart index b6c228e..65ff46c 100644 --- a/lib/src/utils/reader_helper.dart +++ b/lib/src/utils/reader_helper.dart @@ -1,7 +1,7 @@ import 'dart:typed_data'; -import 'package:dart_pdf_reader/dart_pdf_reader.dart'; -import 'package:dart_pdf_reader/src/parser/token_stream.dart'; +import '../../dart_pdf_reader.dart'; +import '../parser/token_stream.dart'; abstract class ReaderHelper { /// Try to read the first non-empty line from the buffer, stripping comments diff --git a/pubspec.yaml b/pubspec.yaml index fcb6a58..ec59610 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,9 +1,9 @@ name: dart_pdf_reader description: Small pure-dart library for parsing PDF files. Supports reading all pdf structures -version: 1.0.1 +version: 2.0.0 repository: https://github.com/NicolaVerbeeck/dart_pdf_reader issue_tracker: https://github.com/NicolaVerbeeck/dart_pdf_reader/issues -topics: [pdf, parser] +topics: [ pdf, parser ] environment: sdk: '>=3.0.0 <4.0.0' @@ -15,7 +15,7 @@ dependencies: meta: '>=1.9.1 < 2.0.0' dev_dependencies: - lints: ">=2.0.0 <5.0.0" + lints: ^4.0.0 test: ^1.21.0 mocktail: ^1.0.0 convert: ^3.1.1 diff --git a/test/model/indirect_object_table_test.dart b/test/model/indirect_object_table_test.dart index d0e36a5..21cd1bd 100644 --- a/test/model/indirect_object_table_test.dart +++ b/test/model/indirect_object_table_test.dart @@ -13,7 +13,7 @@ void main() { test('Test add object', () { final xrefTable = _MockXRefTable(); final sut = IndirectObjectTable(xrefTable); - final obj = const PDFIndirectObject( + const obj = PDFIndirectObject( objectId: 0, generationNumber: 0, object: PDFNumber(1337)); expect(sut[0], isNull); sut.put(0, obj); @@ -23,10 +23,10 @@ void main() { test('Test resolve object reference', () { final xrefTable = _MockXRefTable(); final sut = IndirectObjectTable(xrefTable); - final obj = const PDFObjectReference(objectId: 1, generationNumber: 0); + const obj = PDFObjectReference(objectId: 1, generationNumber: 0); expect(sut.resolve(obj), null); - final newObj = const PDFIndirectObject( + const newObj = PDFIndirectObject( objectId: 1, generationNumber: 0, object: PDFNumber(1337)); sut.put(1, newObj); expect(sut.resolve(obj), newObj.object); @@ -35,7 +35,7 @@ void main() { test('Test resolve direct object', () { final xrefTable = _MockXRefTable(); final sut = IndirectObjectTable(xrefTable); - final obj = const PDFNumber(1337); + const obj = PDFNumber(1337); expect(sut.resolve(obj), obj); }); diff --git a/test/model/pdf_types_test.dart b/test/model/pdf_types_test.dart index 95ed048..77f7d6a 100644 --- a/test/model/pdf_types_test.dart +++ b/test/model/pdf_types_test.dart @@ -14,47 +14,47 @@ void main() { group('PDF Types tests', () { group('PDFNUmber tests', () { test('Test clone PDFNumber int', () { - final pdfNumber = const PDFNumber(1); + const pdfNumber = PDFNumber(1); final pdfNumberClone = pdfNumber.clone(); expect(pdfNumberClone, isNotNull); expect(pdfNumberClone, isNot(same(pdfNumber))); expect(pdfNumberClone, equals(pdfNumber)); }); test('Test clone PDFNUmber double', () { - final pdfNumber = const PDFNumber(1.0); + const pdfNumber = PDFNumber(1.0); final pdfNumberClone = pdfNumber.clone(); expect(pdfNumberClone, isNotNull); expect(pdfNumberClone, isNot(same(pdfNumber))); expect(pdfNumberClone, equals(pdfNumber)); }); test('Test toString truncates double to int', () { - final pdfNumber = const PDFNumber(12.000000000002); + const pdfNumber = PDFNumber(12.000000000002); expect(pdfNumber.toString(), equals('12')); }); test('Test toString does not truncate double to int', () { - final pdfNumber = const PDFNumber(12.002); + const pdfNumber = PDFNumber(12.002); expect(pdfNumber.toString(), equals('12.002')); - final pdfNumber2 = const PDFNumber(12.0000000002); + const pdfNumber2 = PDFNumber(12.0000000002); expect(pdfNumber2.toString(), equals('12.0000000002')); }); test('Test toString truncates to int because of trailing zero', () { - final pdfNumber = const PDFNumber(12.00000000002); + const pdfNumber = PDFNumber(12.00000000002); expect(pdfNumber.toString(), equals('12')); }); test('Test toInt with int', () { - final pdfNumber = const PDFNumber(12); + const pdfNumber = PDFNumber(12); expect(pdfNumber.toInt(), equals(12)); }); test('Test toInt with double', () { - final pdfNumber = const PDFNumber(12.0); + const pdfNumber = PDFNumber(12.0); expect(pdfNumber.toInt(), equals(12)); }); test('Test toDouble with int', () { - final pdfNumber = const PDFNumber(12); + const pdfNumber = PDFNumber(12); expect(pdfNumber.toDouble(), equals(12.0)); }); test('Test toDouble with double', () { - final pdfNumber = const PDFNumber(12.2); + const pdfNumber = PDFNumber(12.2); expect(pdfNumber.toDouble(), equals(12.2)); }); }); @@ -183,13 +183,14 @@ void main() { expect(const PDFName('Test').value, 'Test'); }); test('Test equality', () { - final name1 = '123'; - final name2 = '123'; - final name3 = '321'; - expect(PDFName(name1), PDFName(name2)); - expect(PDFName(name1).hashCode, PDFName(name2).hashCode); - expect(PDFName(name1).hashCode == PDFName(name3).hashCode, false); - expect(PDFName(name1) == PDFName(name3), false); + const name1 = '123'; + const name2 = '123'; + const name3 = '321'; + expect(const PDFName(name1), const PDFName(name2)); + expect(const PDFName(name1).hashCode, const PDFName(name2).hashCode); + expect(const PDFName(name1).hashCode == const PDFName(name3).hashCode, + false); + expect(const PDFName(name1) == const PDFName(name3), false); }); }); group('PDFArray tests', () { @@ -213,15 +214,17 @@ void main() { expect(() => arr.length = 4, throwsArgumentError); }); test('Test equality is deep', () { - final val1 = const PDFNumber(1); - final val2 = const PDFNumber(2); - final val3 = const PDFNumber(3); - expect(PDFArray([val1, val2]), PDFArray([val1, val2])); - expect(PDFArray([val1, val2]) == PDFArray([val1, val3]), false); - expect( - PDFArray([val1, val2]).hashCode, PDFArray([val1, val2]).hashCode); + const val1 = PDFNumber(1); + const val2 = PDFNumber(2); + const val3 = PDFNumber(3); + expect(const PDFArray([val1, val2]), const PDFArray([val1, val2])); + expect(const PDFArray([val1, val2]) == const PDFArray([val1, val3]), + false); + expect(const PDFArray([val1, val2]).hashCode, + const PDFArray([val1, val2]).hashCode); expect( - PDFArray([val1, val2]).hashCode == PDFArray([val1, val3]).hashCode, + const PDFArray([val1, val2]).hashCode == + const PDFArray([val1, val3]).hashCode, false); }); }); @@ -265,27 +268,24 @@ void main() { }); group('PDFObjectReference tests', () { test('Test create reference', () { - final ref = const PDFObjectReference(objectId: 123); - final ref2 = - const PDFObjectReference(objectId: 123, generationNumber: 1); + const ref = PDFObjectReference(objectId: 123); + const ref2 = PDFObjectReference(objectId: 123, generationNumber: 1); expect(ref.objectId, 123); expect(ref.generationNumber, 0); expect(ref2.objectId, 123); expect(ref2.generationNumber, 1); }); test('Test toString', () { - final ref = const PDFObjectReference(objectId: 123); - final ref2 = - const PDFObjectReference(objectId: 123, generationNumber: 1); + const ref = PDFObjectReference(objectId: 123); + const ref2 = PDFObjectReference(objectId: 123, generationNumber: 1); expect(ref.toString(), '123 0 R'); expect(ref2.toString(), '123 1 R'); }); test('Test equality', () { - final ref = const PDFObjectReference(objectId: 123); - final ref2 = const PDFObjectReference(objectId: 123); - final ref3 = - const PDFObjectReference(objectId: 123, generationNumber: 1); + const ref = PDFObjectReference(objectId: 123); + const ref2 = PDFObjectReference(objectId: 123); + const ref3 = PDFObjectReference(objectId: 123, generationNumber: 1); expect(ref, ref2); expect(ref == ref3, false); expect(ref.hashCode, ref2.hashCode); @@ -312,7 +312,7 @@ void main() { }); group('PDFStreamObject tests', () { test('Test create stream offset 0', () async { - final dict = const PDFDictionary({}); + const dict = PDFDictionary({}); final stream = PDFStreamObject( dictionary: dict, length: 5, @@ -324,7 +324,7 @@ void main() { expect(await stream.readRaw(), [1, 2, 3, 4, 5]); }); test('Test create stream offset 0', () async { - final dict = const PDFDictionary({}); + const dict = PDFDictionary({}); final stream = PDFStreamObject( dictionary: dict, length: 4, @@ -336,7 +336,7 @@ void main() { expect(await stream.readRaw(), [2, 3, 4, 5]); }); test('Test read without filters', () async { - final dict = const PDFDictionary({}); + const dict = PDFDictionary({}); final stream = PDFStreamObject( dictionary: dict, length: 5, @@ -352,7 +352,7 @@ void main() { expect(await stream.read(mockResolver), [1, 2, 3, 4, 5]); }); test('Test read with single filter', () async { - final dict = const PDFDictionary({}); + const dict = PDFDictionary({}); final bytes = File('test/resources/ASCIIHex.bin').readAsBytesSync(); final stream = PDFStreamObject( dictionary: dict, @@ -371,7 +371,7 @@ void main() { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac malesuada tellus. Quisque a arcu semper, tristique nibh eu, convallis lacus. Donec neque justo, condimentum sed molestie ac, mollis eu nibh. Vivamus pellentesque condimentum fringilla. Nullam euismod ac risus a semper. Etiam hendrerit scelerisque sapien tristique varius.'); }); test('Test read with bad filter', () async { - final dict = const PDFDictionary({}); + const dict = PDFDictionary({}); final bytes = File('test/resources/ASCIIHex.bin').readAsBytesSync(); final stream = PDFStreamObject( dictionary: dict, @@ -389,7 +389,7 @@ void main() { expect(() => stream.read(mockResolver), throwsA(isA())); }); test('Test read with array filter', () async { - final dict = const PDFDictionary({}); + const dict = PDFDictionary({}); final bytes = File('test/resources/ASCIIHex.bin').readAsBytesSync(); final stream = PDFStreamObject( dictionary: dict, @@ -408,7 +408,7 @@ void main() { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac malesuada tellus. Quisque a arcu semper, tristique nibh eu, convallis lacus. Donec neque justo, condimentum sed molestie ac, mollis eu nibh. Vivamus pellentesque condimentum fringilla. Nullam euismod ac risus a semper. Etiam hendrerit scelerisque sapien tristique varius.'); }); test('Test equality', () { - final dict = const PDFDictionary({}); + const dict = PDFDictionary({}); final source = ByteStream(Uint8List.fromList([1, 2, 3, 4, 5])); final stream = PDFStreamObject( dictionary: dict, diff --git a/test/parser/object_resolver_test.dart b/test/parser/object_resolver_test.dart index 6984f3b..6c95cf8 100644 --- a/test/parser/object_resolver_test.dart +++ b/test/parser/object_resolver_test.dart @@ -27,11 +27,11 @@ void main() { expect(await objectResolver.resolve(null), isNull); }); test('Test resolve regular object', () async { - final object = const PDFNumber(-98.1827); + const object = PDFNumber(-98.1827); expect(await objectResolver.resolve(object), const PDFNumber(-98.1827)); }); test('Test resolve indirect object', () async { - final indirectObject = const PDFIndirectObject( + const indirectObject = PDFIndirectObject( object: PDFNumber(-98.1827), generationNumber: 0, objectId: 1, @@ -40,7 +40,7 @@ void main() { const PDFNumber(-98.1827)); }); test('Test resolve indirect object twice', () async { - final indirectObject = const PDFIndirectObject( + const indirectObject = PDFIndirectObject( object: PDFIndirectObject( object: PDFNumber(-98.1827), generationNumber: 0, diff --git a/test/parser/pdf_parser_test.dart b/test/parser/pdf_parser_test.dart index 915c435..32d8433 100644 --- a/test/parser/pdf_parser_test.dart +++ b/test/parser/pdf_parser_test.dart @@ -11,18 +11,22 @@ import 'package:test/test.dart'; void main() { group('PDFParser tests', () { - group('Parse document',() { + group('Parse document', () { test('it supports single main xref', () async { - final stream = ByteStream(Uint8List.fromList(utf8.encode('xref\n0 1\n0000000000 65535 f\r\ntrailer\n<< /Size 1 /Root 1 0 R >>\nstartxref\n0\n%%EOF'))); + final stream = ByteStream(Uint8List.fromList(utf8.encode( + 'xref\n0 1\n0000000000 65535 f\r\ntrailer\n<< /Size 1 /Root 1 0 R >>\nstartxref\n0\n%%EOF'))); final parser = PDFParser(stream); final document = await parser.parse(); - expect(document.mainTrailer, PDFDictionary({ - const PDFName('Size'): const PDFNumber(1), - const PDFName('Root'): const PDFObjectReference(objectId: 1, generationNumber: 0), - })); + expect( + document.mainTrailer, + PDFDictionary({ + const PDFName('Size'): const PDFNumber(1), + const PDFName('Root'): + const PDFObjectReference(objectId: 1, generationNumber: 0), + })); }); }); diff --git a/test/parser/xref_reader_test.dart b/test/parser/xref_reader_test.dart index 99c04f1..dbd5d87 100644 --- a/test/parser/xref_reader_test.dart +++ b/test/parser/xref_reader_test.dart @@ -48,6 +48,36 @@ startxref %%EOF '''; +const _shortLineTrailer = ''' +%randomdata +xref +1 19 +0000000016 00000 n +0000190137 00000 n +0000190405 00000 n +0000190454 00000 n +0000190591 00000 n +0000190631 00000 n +0000190874 00000 n +0000191866 00000 n +0000191971 00000 n +0000197939 00000 n +0000198518 00000 n +0000198897 00000 n +0000199330 00000 n +0000199825 00000 n +0000200577 00000 n +0000206645 00000 n +0000207066 00000 n +0000207457 00000 n +0000207758 00000 n +trailer +<> +startxref +11 +%%EOF +'''; + void main() { group('XRefReader tests', () { test('Test normal xref', () async { @@ -69,12 +99,31 @@ void main() { expect(section.getObject(12)!.id, 12); expect(section.getObject(12)!.offset, 198897); }); + test('Test short line xref', () async { + final data = Uint8List.fromList(utf8.encode(_shortLineTrailer)); + final stream = ByteStream(data); + final reader = XRefReader(stream); + final (table, dict) = await reader.parseXRef(); + expect(dict, isNull); + expect(table, isNotNull); + expect(table.sections.length, 1); + final section = table.sections[0]; + expect(section.startIndex, 1); + expect(section.endIndex, 20); + expect(section.entries.length, 19); + expect(section.entries[0].offset, 16); + expect(section.entries[18].offset, 207758); + expect(section.entries[18].id, 19); + expect(section.hasId(12), true); + expect(section.getObject(12)!.id, 12); + expect(section.getObject(12)!.offset, 198897); + }); test('Test normal parse into', () async { final data = Uint8List.fromList(utf8.encode(_normalTrailer)); final stream = ByteStream(data); await stream.seek(11); final reader = XRefReader(stream); - // ignore: prefer_const_constructors + // ignore: prefer_const_constructors, prefer_const_literals_to_create_immutables final table = XRefTable([]); await reader.parseXRefTableInto(table); diff --git a/test/utils/buffered_stream_test.dart b/test/utils/buffered_stream_test.dart index fdb9447..2995b2d 100644 --- a/test/utils/buffered_stream_test.dart +++ b/test/utils/buffered_stream_test.dart @@ -1,7 +1,11 @@ +import 'dart:async'; import 'dart:io'; +import 'dart:typed_data'; -import 'package:dart_pdf_reader/dart_pdf_reader.dart'; -import 'package:test/scaffolding.dart'; +import 'package:dart_pdf_reader/src/utils/byte_stream.dart'; +import 'package:dart_pdf_reader/src/utils/cache/buffered_random_access_stream.dart'; +import 'package:dart_pdf_reader/src/utils/file_stream.dart'; +import 'package:test/test.dart'; import 'stream_test.dart'; import 'test_utils.dart'; @@ -35,5 +39,30 @@ void main() { }); createStreamTests(() => sut); + + test('it supports ByteStream but warns', () async { + final logs = []; + await _overridePrint(logs, () async { + final sut = BufferedRandomAccessStream( + ByteStream(Uint8List.fromList([1, 2, 3])), + blockSize: 1, + maxNumBlocks: 2, + ); + expect(await sut.readByte(), 1); + expect(await sut.readByte(), 2); + expect(await sut.readByte(), 3); + }); + expect(logs, hasLength(1)); + expect(logs[0], + 'Warning: BufferedRandomAccessStream is not recommended for ByteStream'); + }); + }); +} + +Future _overridePrint(List log, Future Function() testFn) { + final spec = ZoneSpecification(print: (_, __, ___, String msg) { + // Add to log instead of printing to stdout + log.add(msg); }); + return Zone.current.fork(specification: spec).run(testFn); } diff --git a/test/utils/file_stream_test.dart b/test/utils/file_stream_test.dart index ea56a46..1520bbf 100644 --- a/test/utils/file_stream_test.dart +++ b/test/utils/file_stream_test.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:dart_pdf_reader/dart_pdf_reader.dart'; +import 'package:dart_pdf_reader/src/utils/file_stream.dart'; import 'package:test/scaffolding.dart'; import 'stream_test.dart'; diff --git a/test/utils/filter/ascii_85_decode_filter_test.dart b/test/utils/filter/ascii_85_decode_filter_test.dart index d1d1407..7d58604 100644 --- a/test/utils/filter/ascii_85_decode_filter_test.dart +++ b/test/utils/filter/ascii_85_decode_filter_test.dart @@ -16,7 +16,7 @@ void main() { const PDFDictionary({}), ); final decodedString = utf8.decode(decoded); - final expected = + const expected = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac malesuada tellus. Quisque a arcu semper, tristique nibh eu, convallis lacus. Donec neque justo, condimentum sed molestie ac, mollis eu nibh. Vivamus pellentesque condimentum fringilla. Nullam euismod ac risus a semper. Etiam hendrerit scelerisque sapien tristique varius.'; expect(decodedString, expected); }); diff --git a/test/utils/filter/ascii_hex_decode_filter_test.dart b/test/utils/filter/ascii_hex_decode_filter_test.dart index 2bde62e..1809835 100644 --- a/test/utils/filter/ascii_hex_decode_filter_test.dart +++ b/test/utils/filter/ascii_hex_decode_filter_test.dart @@ -16,7 +16,7 @@ void main() { const PDFDictionary({}), ); final decodedString = utf8.decode(decoded); - final expected = + const expected = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac malesuada tellus. Quisque a arcu semper, tristique nibh eu, convallis lacus. Donec neque justo, condimentum sed molestie ac, mollis eu nibh. Vivamus pellentesque condimentum fringilla. Nullam euismod ac risus a semper. Etiam hendrerit scelerisque sapien tristique varius.'; expect(decodedString, expected); }); diff --git a/test/utils/filter/lzw_decode_filter_test.dart b/test/utils/filter/lzw_decode_filter_test.dart index a48a2eb..7603dab 100644 --- a/test/utils/filter/lzw_decode_filter_test.dart +++ b/test/utils/filter/lzw_decode_filter_test.dart @@ -16,7 +16,7 @@ void main() { const PDFDictionary({}), ); final decodedString = utf8.decode(decoded); - final expected = '-----A---B'; + const expected = '-----A---B'; expect(decodedString, expected); }); });