Compare commits

..

4 Commits

Author SHA1 Message Date
EliotJones
7e370a0eab confirm tag is on master before running publish
Some checks failed
Nightly Release / Check if this commit has already been published (push) Has been cancelled
Nightly Release / tests (push) Has been cancelled
Nightly Release / build_and_publish_nightly (push) Has been cancelled
Build, test and publish draft / build (push) Has been cancelled
Build and test [MacOS] / build (push) Has been cancelled
Run Common Crawl Tests / build (0000-0001) (push) Has been cancelled
Run Common Crawl Tests / build (0002-0003) (push) Has been cancelled
Run Common Crawl Tests / build (0004-0005) (push) Has been cancelled
Run Common Crawl Tests / build (0006-0007) (push) Has been cancelled
Run Integration Tests / build (push) Has been cancelled
Tag Release / tag_if_version_changed (push) Has been cancelled
2026-02-15 18:39:45 +00:00
EliotJones
b9aa53166d replace release flow single job with pr process
since actions do not have permissions to push
directly to master and bot accounts to achieve
the same are hard to manage we will change the
release flow to work as follows.

1. manually invoke `prepare_release_pr.yml` action,
this creates a new branch with the version of all
project files updated and creates a pull request for
that version. this pr then should be merged using
rebase merge

2. `tag_release.yml` checks if the newest commit
name starts with the text "Release " and also verifies
if it changed the version of the package csproj. if
both those conditions are met it will create and
push a new tag, e.g. `v0.1.17` to master

3. `publish_nuget.yml` listens for new `v*` tags on
master and triggers the nuget deployment

this is all chat gpt code so who knows if it will work
2026-02-15 18:39:45 +00:00
BobLd
0a2b1e076f Improve HasFormXObjectCircularReference and fix #1250 2026-02-15 18:06:35 +00:00
EliotJones
f732718852 both Tj and TJ operators should increment text sequence #1241
the text sequence was added to group letters added by the same
content stream operation together for layout analysis. TJ allows for
individual letter positioning in the same operation which modifies
the text matrix while writing whereas Tj just writes the text at the current
location. both should be semantically equivalent for this sequence
number. this was originally added in #61
2026-02-15 17:50:07 +00:00
8 changed files with 215 additions and 62 deletions

View File

@@ -0,0 +1,40 @@
name: Create Release PR
on:
workflow_dispatch
permissions:
contents: write
pull-requests: write
jobs:
bump_version:
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Calculate next version
id: version
run: |
$newVer = .\tools\get-next-main-version.ps1
echo "NEW_VERSION=$newVer" >> $env:GITHUB_ENV
.\tools\set-version.ps1 $newVer -UpdateAssemblyAndFileVersion
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git checkout -b release/$newVer
git commit -am "Release $newVer"
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
branch: release/${{ env.NEW_VERSION }}
base: master
title: "Release ${{ env.NEW_VERSION }}"
body: "Automated release PR."
delete-branch: true
merge-method: rebase

53
.github/workflows/publish_nuget.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
name: Publish
on:
push:
tags:
- 'v*'
permissions:
contents: write
packages: write
jobs:
build_and_publish:
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
- name: Verify tag points to master
id: verify
run: |
TAG_COMMIT=$(git rev-list -n 1 ${{ github.ref_name }})
if ! git branch -r --contains $TAG_COMMIT | grep -q 'origin/master'; then
echo "Tag is not on master — skipping publish"
exit 78 # 78 = neutral in GitHub Actions
fi
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
2.1.x
6.0.x
8.0.x
9.0.x
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
- name: Run tests
run: dotnet test -c Release src/UglyToad.PdfPig.sln
- name: Build package
run: dotnet pack -c Release -o package tools/UglyToad.PdfPig.Package/UglyToad.PdfPig.Package.csproj -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
- name: Publish to NuGet
run: dotnet nuget push package/*.nupkg --api-key ${{secrets.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,53 +0,0 @@
name: Release Publish
on:
release:
types: [published]
permissions:
contents: write
packages: write
jobs:
build_and_publish_release:
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up dotnet core
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
2.1.x
6.0.x
8.0.x
9.0.x
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
- name: Run tests
run: dotnet test -c Release src/UglyToad.PdfPig.sln
- name: Build package
run: dotnet pack -c Release -o package tools/UglyToad.PdfPig.Package/UglyToad.PdfPig.Package.csproj -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
- name: Publish to NuGet
run: dotnet nuget push **/*.nupkg --api-key ${{secrets.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json
- name: Increment version after release
run: |
$newVer = .\tools\get-next-main-version.ps1
.\tools\set-version.ps1 $newVer -UpdateAssemblyAndFileVersion
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git fetch origin master
git checkout master
git pull
git commit -am "Increment version to $newVer"
git push

43
.github/workflows/tag_release.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Tag Release
on:
push:
branches:
- master
permissions:
contents: write
jobs:
tag_if_version_changed:
if: startsWith(github.event.head_commit.message, 'Release ')
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect version change
id: versioncheck
run: |
git fetch origin master --depth=2
$diff = git diff HEAD^ HEAD -- tools/UglyToad.PdfPig.Package/UglyToad.PdfPig.Package.csproj
if ($diff -match "<Version>") {
$version = (Select-String -Path tools/UglyToad.PdfPig.Package/UglyToad.PdfPig.Package.csproj -Pattern "<Version>(.*)</Version>").Matches.Groups[1].Value
echo "version=$version" >> $env:GITHUB_OUTPUT
echo "create=true" >> $env:GITHUB_OUTPUT
} else {
echo "create=false" >> $env:GITHUB_OUTPUT
}
- name: Create tag
if: steps.versioncheck.outputs.create == 'true'
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git tag "v${{ steps.versioncheck.outputs.version }}"
git push origin "v${{ steps.versioncheck.outputs.version }}"

View File

@@ -11,6 +11,31 @@
public class GithubIssuesTests
{
[Fact]
public void Issues1250()
{
// Issue comes from HasFormXObjectCircularReference
var path = IntegrationHelpers.GetDocumentPath("SPE8EF26T0545.pdf");
using (var document = PdfDocument.Open(path, new ParsingOptions() { UseLenientParsing = true }))
{
var page = document.GetPage(1);
Assert.NotNull(page);
Assert.NotEmpty(page.Letters);
page = document.GetPage(7);
Assert.NotNull(page);
Assert.NotEmpty(page.Letters);
}
// Ensure still no StackOverflowException
using (var document = PdfDocument.Open(IntegrationHelpers.GetDocumentPath("issue_671")))
{
var page = document.GetPage(1);
Assert.NotNull(page);
Assert.NotEmpty(page.Letters);
}
}
[Fact]
public void Issues1248()
{

View File

@@ -215,6 +215,8 @@
/// <inheritdoc/>
public void ShowText(IInputBytes bytes)
{
TextSequence++;
var currentState = GetCurrentState();
var font = currentState.FontState.FromExtendedGraphicsState
@@ -586,6 +588,7 @@
{
if (ParsingOptions.UseLenientParsing)
{
// TODO - We might be removing too much, good for the moment. See Issues1250() for examples
operations = operations.Where(o => o is not InvokeNamedXObject xo || xo.Name != xObjectName)
.ToArray();
ParsingOptions.Logger.Warn(
@@ -616,14 +619,56 @@
/// <param name="xObjectName">The form's name.</param>
/// <param name="operations">The form operations parsed from original form stream.</param>
protected virtual bool HasFormXObjectCircularReference(StreamToken formStream,
NameToken xObjectName,
NameToken? xObjectName,
IReadOnlyList<IGraphicsStateOperation> operations)
{
return xObjectName != null
&& operations.OfType<InvokeNamedXObject>()?.Any(o => o.Name == xObjectName) ==
true // operations contain another form with same name
&& ResourceStore.TryGetXObject(xObjectName, out var result)
&& result.Data.Span.SequenceEqual(formStream.Data.Span); // The form contained in the operations has identical data to current form
if (xObjectName is null)
{
return false;
}
if (operations.OfType<InvokeNamedXObject>()?.Any(o => o.Name == xObjectName) != true)
{
return false;
}
if (!TryGetXObjectToken(formStream, xObjectName, PdfScanner, out var t1))
{
return false;
}
if (!ResourceStore.TryGetXObject(xObjectName, out var resourceStream))
{
return false;
}
if (!TryGetXObjectToken(resourceStream, xObjectName, PdfScanner, out var t2))
{
return false;
}
if (t1 is null || t2 is null)
{
return false;
}
return t1.Equals(t2);
static bool TryGetXObjectToken(StreamToken streamToken, NameToken xObjectName, IPdfTokenScanner scanner, out IToken? token)
{
token = null;
if (!streamToken.StreamDictionary.TryGet<DictionaryToken>(NameToken.Resources, scanner, out var formResources))
{
return false;
}
if (!formResources.TryGet<DictionaryToken>(NameToken.Xobject, out var xObjectBase) || !xObjectBase.TryGet(xObjectName, out token))
{
return false;
}
return token is not null;
}
}
/// <inheritdoc/>

View File

@@ -64,7 +64,7 @@
operationContext.ShowText(input);
}
string? EscapeText(string? text)
private static string? EscapeText(string? text)
{
if (text is null) return null;
// Fix Issue 350 from PDF Spec 1.7 (page 408) on handling 'special characters' of '(', ')' and '\'.