5 Commits

Author SHA1 Message Date
icefed
ad7d44f5f4 Merge ee34959d7c into 98934daee4 2023-08-15 15:36:06 +02:00
icefed
ee34959d7c update 2023-02-07 21:44:25 +08:00
icefed
2db6621bff update 2023-02-07 21:40:51 +08:00
icefed
5f78128dc6 fix review 2023-02-06 20:30:20 +08:00
icefed
aef569c33d fever api support
Fever API spec: https://github.com/DigitalDJ/tinytinyrss-fever-plugin/blob/master/fever-api.md
2023-02-06 20:26:36 +08:00
92 changed files with 3160 additions and 4865 deletions

View File

@@ -1,38 +0,0 @@
name: Publish Docker Image
on:
push:
tags: [ 'v*.*.*', 'v*.*', 'v*', 'latest' ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: nkanaev/yarr
jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a
with:
context: .
file: ./etc/dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -1,14 +1,8 @@
name: Build name: build
on: on:
push: push:
tags: tags: ['v*', 'test*']
- v*
workflow_dispatch:
workflow_run:
workflows: [Test]
types:
- completed
jobs: jobs:
build_macos: build_macos:
@@ -24,7 +18,7 @@ jobs:
with: with:
go-version: '^1.17' go-version: '^1.17'
- name: Cache Go Modules - name: Cache Go Modules
uses: actions/cache@v4 uses: actions/cache@v2
with: with:
path: ~/go/pkg/mod path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
@@ -33,7 +27,7 @@ jobs:
- name: "Build" - name: "Build"
run: make build_macos run: make build_macos
- name: Upload - name: Upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: macos name: macos
path: _output/macos/yarr.app path: _output/macos/yarr.app
@@ -51,7 +45,7 @@ jobs:
with: with:
go-version: '^1.17' go-version: '^1.17'
- name: Cache Go Modules - name: Cache Go Modules
uses: actions/cache@v4 uses: actions/cache@v2
with: with:
path: ~/go/pkg/mod path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
@@ -60,7 +54,7 @@ jobs:
- name: "Build" - name: "Build"
run: make build_windows run: make build_windows
- name: Upload - name: Upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: windows name: windows
path: _output/windows/yarr.exe path: _output/windows/yarr.exe
@@ -78,99 +72,38 @@ jobs:
with: with:
go-version: '^1.17' go-version: '^1.17'
- name: Cache Go Modules - name: Cache Go Modules
uses: actions/cache@v4 uses: actions/cache@v2
with: with:
path: ~/go/pkg/mod path: ~/go/pkg/mod
key: ${{ runner.os }}-amd64-go-${{ hashFiles('**/go.sum') }} key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: | restore-keys: |
${{ runner.os }}-go-amd64 ${{ runner.os }}-go-
- name: "Build" - name: "Build"
run: make build_linux run: make build_linux
- name: Upload - name: Upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: linux name: linux
path: _output/linux/yarr path: _output/linux/yarr
build_linux-arm:
name: Build for Linux ARM
runs-on: ubuntu-22.04
steps:
- name: Install dependencies
run: >
sudo apt-get install -y
gcc-arm-linux-gnueabihf
libc6-dev-armhf-cross
- name: "Checkout"
uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: "Setup Go"
uses: actions/setup-go@v2
with:
go-version: '^1.17'
- name: Cache Go Modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-armv7-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-armv7
- name: "Build"
env:
CC: arm-linux-gnueabihf-gcc
GOARCH: arm
GOARM: 7
run: make build_linux
- name: Upload
uses: actions/upload-artifact@v4
with:
name: linux_arm
path: _output/linux/yarr
build_linux-arm64:
name: Build for Linux ARM64
runs-on: ubuntu-22.04
steps:
- name: Install dependencies
run: >
sudo apt-get install -y
gcc-aarch64-linux-gnu
libc6-dev-arm64-cross
- name: "Checkout"
uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: "Setup Go"
uses: actions/setup-go@v2
with:
go-version: '^1.17'
- name: Cache Go Modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-arm64-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-arm64
- name: "Build"
env:
CC: aarch64-linux-gnu-gcc
GOARCH: arm64
run: make build_linux
- name: Upload
uses: actions/upload-artifact@v4
with:
name: linux_arm64
path: _output/linux/yarr
create_release: create_release:
name: Create Release name: Create Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ startsWith(github.ref, 'refs/tags/') && !contains(github.ref, 'test') }} if: ${{ !contains(github.ref, 'test') }}
needs: [build_macos, build_windows, build_linux, build_linux-arm, build_linux-arm64] needs: [build_macos, build_windows, build_linux]
steps: steps:
- name: Create Release
uses: actions/create-release@v1
id: create_release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: true
prerelease: true
- name: Download Artifacts - name: Download Artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v2
with: with:
path: . path: .
- name: Preparation - name: Preparation
@@ -178,24 +111,34 @@ jobs:
ls -R ls -R
chmod u+x macos/Contents/MacOS/yarr chmod u+x macos/Contents/MacOS/yarr
chmod u+x linux/yarr chmod u+x linux/yarr
chmod u+x linux_arm/yarr
chmod u+x linux_arm64/yarr
mv macos yarr.app && zip -r yarr-${GITHUB_REF_NAME}-macos64.zip yarr.app mv macos yarr.app && zip -r yarr-macos.zip yarr.app
( cd windows && zip ../yarr-${GITHUB_REF_NAME}-windows64.zip yarr.exe ) mv windows/yarr.exe . && zip yarr-windows.zip yarr.exe
( cd linux && zip ../yarr-${GITHUB_REF_NAME}-linux64.zip yarr ) mv linux/yarr . && zip yarr-linux.zip yarr
( cd linux_arm && zip ../yarr-${GITHUB_REF_NAME}-linux_arm.zip yarr ) - name: Upload MacOS
( cd linux_arm64 && zip ../yarr-${GITHUB_REF_NAME}-linux_arm64.zip yarr ) uses: actions/upload-release-asset@v1
- name: Upload Release
uses: softprops/action-gh-release@v2
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
draft: true upload_url: ${{ steps.create_release.outputs.upload_url }}
prerelease: true asset_path: ./yarr-macos.zip
files: | asset_name: yarr-${{ github.ref }}-macos64.zip
yarr-${{ github.ref_name }}-macos64.zip asset_content_type: application/zip
yarr-${{ github.ref_name }}-windows64.zip - name: Upload Windows
yarr-${{ github.ref_name }}-linux64.zip uses: actions/upload-release-asset@v1
yarr-${{ github.ref_name }}-linux_arm.zip env:
yarr-${{ github.ref_name }}-linux_arm64.zip GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./yarr-windows.zip
asset_name: yarr-${{ github.ref }}-windows64.zip
asset_content_type: application/zip
- name: Upload Linux
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./yarr-linux.zip
asset_name: yarr-${{ github.ref }}-linux64.zip
asset_content_type: application/zip

View File

@@ -1,19 +0,0 @@
name: Test
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '^1.18'
- name: Run tests
run: make test

2
.gitignore vendored
View File

@@ -1,7 +1,5 @@
/_output /_output
/yarr /yarr
*.db *.db
*.db-shm
*.db-wal
*.syso *.syso
versioninfo.rc versioninfo.rc

View File

@@ -18,7 +18,7 @@ Then run one of the corresponding commands:
make serve # starts a server at http://localhost:7070 make serve # starts a server at http://localhost:7070
# ... or build a docker image # ... or build a docker image
docker build -t yarr -f etc/dockerfile . docker build -t yarr .
## ARM compilation ## ARM compilation
@@ -26,7 +26,7 @@ The instructions below are to cross-compile *yarr* to `Linux/ARM*`.
Build: Build:
docker build -t yarr.arm -f etc/dockerfile.arm . docker build -t yarr.arm -f dockerfile.arm .
Test: Test:

View File

@@ -1,23 +1,3 @@
# upcoming
- (new) Fever API support (thanks to @icefed)
- (new) editable feed link (thanks to @adaszko)
- (new) switch to feed by clicking the title in the article page (thanks to @tarasglek for suggestion)
- (new) support multiple media links
- (fix) duplicate articles caused by the same feed addition (thanks to @adaszko)
- (fix) relative article links (thanks to @adazsko for the report)
- (fix) atom article links stored in id element (thanks to @adazsko for the report)
- (fix) parsing atom feed titles (thanks to @wnh)
- (fix) sorting same-day batch articles (thanks to @lamescholar for the report)
- (fix) showing login page in the selected theme (thanks to @feddiriko for the report)
- (fix) parsing atom feeds with html elements (thanks to @tillcash & @toBeOfUse for the report, @krkk for the fix)
- (fix) parsing feeds with missing guids (thanks to @hoyii for the report)
- (fix) sending actual client version to servers (thanks to @aidanholm)
- (fix) error caused by missing config dir (thanks to @timster)
- (etc) load external images with no-referrer policy (thanks to @tillcash for the report)
- (etc) open external links with no-referrer policy (thanks to @donovanglover)
- (etc) show article content in the list if title is missing (thanks to @asimpson for suggestion)
# v2.4 (2023-08-15) # v2.4 (2023-08-15)
- (new) ARM build support (thanks to @tillcash & @fenuks) - (new) ARM build support (thanks to @tillcash & @fenuks)

View File

@@ -1,19 +0,0 @@
# Fever API support
Fever API is a kind of RSS HTTP API interface, because the Fever API definition is not very clear, so the implementation of Fever server and Client may have some compatibility problems.
The Fever API implemented by Yarr is based on the Fever API spec: https://github.com/DigitalDJ/tinytinyrss-fever-plugin/blob/master/fever-api.md.
Here are some Apps that have been tested to work with yarr. Feel free to test other Clients/Apps and update the list here.
> Different apps support different URL/Address formats. Please note whether the URL entered has `http://` scheme and `/` suffix.
| App | Platforms | Config Server URL |
|:------------------------------------------------------------------------- | ---------------- |:--------------------------------------------------- |
| [Reeder](https://reederapp.com/) | MacOS<br>iOS | 127.0.0.1:7070/fever<br>http://127.0.0.1:7070/fever |
| [ReadKit](https://readkit.app/) | MacOS<br>iOS | http://127.0.0.1:7070/fever |
| [Fluent Reader](https://github.com/yang991178/fluent-reader) | MacOS<br>Windows | http://127.0.0.1:7070/fever/ |
| [Unread](https://apps.apple.com/us/app/unread-an-rss-reader/id1363637349) | iOS | http://127.0.0.1:7070/fever |
| [Fiery Feeds](https://voidstern.net/fiery-feeds) | MacOS<br>iOS | http://127.0.0.1:7070/fever |
If you are having trouble using Fever, please open an issue and @icefed, thanks.

View File

@@ -1,68 +0,0 @@
- site: https://vimeo.com/channels/staffpicks/videos
feed: https://vimeo.com/channels/staffpicks/videos/rss
tags: [vimeo, image]
- site: https://www.youtube.com/@everyframeapainting/videos
feed: https://www.youtube.com/feeds/videos.xml?channel_id=UCjFqcJQXGZ6T6sxyFB-5i6A"
tags: [youtube, image]
- site: https://iwdrm.tumblr.com/
feed: https://iwdrm.tumblr.com/rss
tags: [tumblr, image]
- site: https://falseknees.tumblr.com/
feed: https://falseknees.tumblr.com/rss
tags: [tumblr, image]
- site: https://accidentallyquadratic.tumblr.com/
feed: https://accidentallyquadratic.tumblr.com/rss
info: text blog with code sections
tags: [tumblr, text, code]
- site: https://www.flickr.com/photos/maratsafin/
feed: https://www.flickr.com/services/feeds/photos_public.gne?id=59021497@N07&lang=en-us&format=atom
tags: [flickr, image]
- site: https://www.reddit.com/r/comics
feed: https://www.reddit.com/r/comics.rss
tags: [reddit, image]
- site: https://www.reddit.com/r/AITAH
feed: https://www.reddit.com/r/AITAH.rss
tags: [reddit, text]
- site: https://idothei.wordpress.com/
feed: https://idothei.wordpress.com/feed/
tags: [wordpress, text]
- site: https://www.vidarholen.net/contents/blog/
feed: https://www.vidarholen.net/contents/blog/?feed=rss2
tags: [wordpress, text]
- site: https://blog.posthaven.com/
feed: https://blog.posthaven.com/posts.atom
tags: [posthaven, text]
- site: https://medium.com/@dailynewsletter
feed: https://medium.com/feed/@dailynewsletter
tags: [medium, text]
- site: https://thereveal.substack.com/
feed: https://thereveal.substack.com/feed
tags: [substack, text]
- site: https://tema.livejournal.com/
feed: https://tema.livejournal.com/data/rss
tags: [livejournal, text]
- site: https://mametter.hatenablog.com/
feed: https://mametter.hatenablog.com/feed
tags: [hatena, text]
- site: https://juliepowell.blogspot.com/
feed: https://juliepowell.blogspot.com/feeds/posts/default
tags: [blogger, text]
- site: https://micro.blog/val
feed: https://micro.blog/posts/val
tags: [json, microblog]

12
dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM golang:alpine AS build
RUN apk add build-base git
WORKDIR /src
COPY . .
RUN make build_linux
FROM alpine:latest
RUN apk add --no-cache ca-certificates && \
update-ca-certificates
COPY --from=build /src/_output/linux/yarr /usr/local/bin/yarr
EXPOSE 7070
CMD ["/usr/local/bin/yarr", "-addr", "0.0.0.0:7070", "-db", "/data/yarr.db"]

View File

@@ -28,17 +28,17 @@ RUN env \
CGO_ENABLED=1 \ CGO_ENABLED=1 \
GOOS=linux GOARCH=arm64 \ GOOS=linux GOARCH=arm64 \
go build \ go build \
-tags "sqlite_foreign_keys linux" \ -tags "sqlite_foreign_keys release linux" \
-ldflags="-s -w" \ -ldflags="-s -w" \
-o /root/out/yarr.arm64 ./cmd/yarr -o /root/out/yarr.arm64 src/main.go
RUN env \ RUN env \
CC=arm-linux-gnueabihf-gcc \ CC=arm-linux-gnueabihf-gcc \
CGO_ENABLED=1 \ CGO_ENABLED=1 \
GOOS=linux GOARCH=arm GOARM=7 \ GOOS=linux GOARCH=arm GOARM=7 \
go build \ go build \
-tags "sqlite_foreign_keys linux" \ -tags "sqlite_foreign_keys release linux" \
-ldflags="-s -w" \ -ldflags="-s -w" \
-o /root/out/yarr.arm7 ./cmd/yarr -o /root/out/yarr.arm7 src/main.go
CMD ["/bin/bash"] CMD ["/bin/bash"]

View File

@@ -1,14 +0,0 @@
FROM golang:alpine3.18 AS build
RUN apk add build-base git
WORKDIR /src
COPY . .
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/root/go/pkg \
make build_linux
FROM alpine:latest
RUN apk add --no-cache ca-certificates && \
update-ca-certificates
COPY --from=build /src/_output/linux/yarr /usr/local/bin/yarr
EXPOSE 7070
ENTRYPOINT ["/usr/local/bin/yarr"]
CMD ["-addr", "0.0.0.0:7070", "-db", "/data/yarr.db"]

View File

@@ -1,9 +1,5 @@
#!/bin/bash #!/bin/bash
if [[ ! -d "$HOME/.local/share/applications" ]]; then
mkdir -p "$HOME/.local/share/applications"
fi
cat >"$HOME/.local/share/applications/yarr.desktop" <<END cat >"$HOME/.local/share/applications/yarr.desktop" <<END
[Desktop Entry] [Desktop Entry]
Name=yarr Name=yarr
@@ -13,10 +9,6 @@ Type=Application
Categories=Internet; Categories=Internet;
END END
if [[ ! -d "$HOME/.local/share/icons" ]]; then
mkdir -p "$HOME/.local/share/icons"
fi
cat >"$HOME/.local/share/icons/yarr.svg" <<END cat >"$HOME/.local/share/icons/yarr.svg" <<END
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-anchor-favicon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-anchor-favicon">

8
go.mod
View File

@@ -1,11 +1,11 @@
module github.com/nkanaev/yarr module github.com/nkanaev/yarr
go 1.18 go 1.17
require ( require (
github.com/mattn/go-sqlite3 v1.14.7 github.com/mattn/go-sqlite3 v1.14.7
golang.org/x/net v0.33.0 golang.org/x/net v0.8.0
golang.org/x/sys v0.28.0 golang.org/x/sys v0.6.0
) )
require golang.org/x/text v0.21.0 // indirect require golang.org/x/text v0.8.0 // indirect

45
go.sum
View File

@@ -1,70 +1,39 @@
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA= github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -1,34 +1,33 @@
VERSION=2.4 VERSION=2.4
GITHASH=$(shell git rev-parse --short=8 HEAD) GITHASH=$(shell git rev-parse --short=8 HEAD)
GO_TAGS = sqlite_foreign_keys sqlite_json CGO_ENABLED=1
GO_LDFLAGS = -s -w -X 'main.Version=$(VERSION)' -X 'main.GitHash=$(GITHASH)'
export GOARCH ?= amd64 GO_LDFLAGS = -s -w
export CGO_ENABLED = 1 GO_LDFLAGS := $(GO_LDFLAGS) -X 'main.Version=$(VERSION)' -X 'main.GitHash=$(GITHASH)'
build_default: build_default:
mkdir -p _output mkdir -p _output
go build -tags "$(GO_TAGS)" -ldflags="$(GO_LDFLAGS)" -o _output/yarr ./cmd/yarr go build -tags "sqlite_foreign_keys release" -ldflags="$(GO_LDFLAGS)" -o _output/yarr src/main.go
build_macos: build_macos:
mkdir -p _output/macos mkdir -p _output/macos
GOOS=darwin go build -tags "$(GO_TAGS) macos" -ldflags="$(GO_LDFLAGS)" -o _output/macos/yarr ./cmd/yarr GOOS=darwin GOARCH=amd64 go build -tags "sqlite_foreign_keys release macos" -ldflags="$(GO_LDFLAGS)" -o _output/macos/yarr src/main.go
cp src/platform/icon.png _output/macos/icon.png cp src/platform/icon.png _output/macos/icon.png
go run ./cmd/package_macos -outdir _output/macos -version "$(VERSION)" go run bin/package_macos.go -outdir _output/macos -version "$(VERSION)"
build_linux: build_linux:
mkdir -p _output/linux mkdir -p _output/linux
GOOS=linux go build -tags "$(GO_TAGS) linux" -ldflags="$(GO_LDFLAGS)" -o _output/linux/yarr ./cmd/yarr GOOS=linux GOARCH=amd64 go build -tags "sqlite_foreign_keys release linux" -ldflags="$(GO_LDFLAGS)" -o _output/linux/yarr src/main.go
build_windows: build_windows:
mkdir -p _output/windows mkdir -p _output/windows
go run ./cmd/generate_versioninfo -version "$(VERSION)" -outfile src/platform/versioninfo.rc go run bin/generate_versioninfo.go -version "$(VERSION)" -outfile src/platform/versioninfo.rc
windres -i src/platform/versioninfo.rc -O coff -o src/platform/versioninfo.syso windres -i src/platform/versioninfo.rc -O coff -o src/platform/versioninfo.syso
GOOS=windows go build -tags "$(GO_TAGS) windows" -ldflags="$(GO_LDFLAGS) -H windowsgui" -o _output/windows/yarr.exe ./cmd/yarr GOOS=windows GOARCH=amd64 go build -tags "sqlite_foreign_keys release windows" -ldflags="$(GO_LDFLAGS) -H windowsgui" -o _output/windows/yarr.exe src/main.go
serve: serve:
go run -tags "$(GO_TAGS)" ./cmd/yarr -db local.db go run -tags "sqlite_foreign_keys" src/main.go -db local.db
test: test:
go test -tags "$(GO_TAGS)" ./... cd src && go test -tags "sqlite_foreign_keys release" ./...

View File

@@ -10,29 +10,25 @@ The app is a single binary with an embedded database (SQLite).
## usage ## usage
The latest prebuilt binaries for Linux/MacOS/Windows AMD64 are available The latest prebuilt binaries for Linux/MacOS/Windows AMD64 are available
[here](https://github.com/nkanaev/yarr/releases/latest). Installation instructions: [here](https://github.com/nkanaev/yarr/releases/latest).
* MacOS ### macos
Download `yarr-*-macos64.zip`, unzip it, place `yarr.app` in `/Applications` folder, [open the app][macos-open], click the anchor menu bar icon, select "Open". Download `yarr-*-macos64.zip`, unzip it, place `yarr.app` in `/Applications` folder, [open the app][macos-open], click the anchor menu bar icon, select "Open".
* Windows [macos-open]: https://support.apple.com/en-gb/guide/mac-help/mh40616/mac
### windows
Download `yarr-*-windows64.zip`, unzip it, open `yarr.exe`, click the anchor system tray icon, select "Open". Download `yarr-*-windows64.zip`, unzip it, open `yarr.exe`, click the anchor system tray icon, select "Open".
* Linux ### linux
Download `yarr-*-linux64.zip`, unzip it, place `yarr` in `$HOME/.local/bin` Download `yarr-*-linux64.zip`, unzip it, place `yarr` in `$HOME/.local/bin`
and run [the script](etc/install-linux.sh). and run [the script](etc/install-linux.sh).
[macos-open]: https://support.apple.com/en-gb/guide/mac-help/mh40616/mac
For self-hosting, see `yarr -h` for auth, tls & server configuration flags. For self-hosting, see `yarr -h` for auth, tls & server configuration flags.
For building from source code, see [build.md](build.md)
See more:
* [Building from source code](doc/build.md)
* [Fever API support](doc/fever.md)
## credits ## credits

View File

@@ -1,3 +1,6 @@
//go:build release
// +build release
package assets package assets
import "embed" import "embed"

View File

@@ -25,21 +25,18 @@
<div class="flex-grow-1"></div> <div class="flex-grow-1"></div>
<button class="toolbar-item" <button class="toolbar-item"
:class="{active: filterSelected == 'unread'}" :class="{active: filterSelected == 'unread'}"
:aria-pressed="filterSelected == 'unread'"
title="Unread" title="Unread"
@click="filterSelected = 'unread'"> @click="filterSelected = 'unread'">
<span class="icon">{% inline "circle-full.svg" %}</span> <span class="icon">{% inline "circle-full.svg" %}</span>
</button> </button>
<button class="toolbar-item" <button class="toolbar-item"
:class="{active: filterSelected == 'starred'}" :class="{active: filterSelected == 'starred'}"
:aria-pressed="filterSelected == 'starred'"
title="Starred" title="Starred"
@click="filterSelected = 'starred'"> @click="filterSelected = 'starred'">
<span class="icon">{% inline "star-full.svg" %}</span> <span class="icon">{% inline "star-full.svg" %}</span>
</button> </button>
<button class="toolbar-item" <button class="toolbar-item"
:class="{active: filterSelected == ''}" :class="{active: filterSelected == ''}"
:aria-pressed="filterSelected == ''"
title="All" title="All"
@click="filterSelected = ''"> @click="filterSelected = ''">
<span class="icon">{% inline "assorted.svg" %}</span> <span class="icon">{% inline "assorted.svg" %}</span>
@@ -62,12 +59,10 @@
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<header class="dropdown-header" role="heading" aria-level="2">Theme</header> <header class="dropdown-header">Theme</header>
<div class="row text-center m-0"> <div class="row text-center m-0">
<button class="btn btn-link col-4 px-0 rounded-0" <button class="btn btn-link col-4 px-0 rounded-0"
:class="'theme-'+t" :class="'theme-'+t"
:aria-label="t"
:aria-pressed="theme.name == t"
@click.stop="theme.name = t" @click.stop="theme.name = t"
v-for="t in ['light', 'sepia', 'night']"> v-for="t in ['light', 'sepia', 'night']">
<span class="icon" v-if="theme.name == t">{% inline "check.svg" %}</span> <span class="icon" v-if="theme.name == t">{% inline "check.svg" %}</span>
@@ -76,25 +71,25 @@
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<header class="dropdown-header" role="heading" aria-level="2">Auto Refresh</header> <header class="dropdown-header">Auto Refresh</header>
<div class="row text-center m-0"> <div class="row text-center m-0">
<button class="dropdown-item col-4 px-0" :aria-pressed="!refreshRate" :class="{active: !refreshRate}" @click.stop="refreshRate = 0">0</button> <button class="dropdown-item col-4 px-0" :class="{active: !refreshRate}" @click.stop="refreshRate = 0">0</button>
<button class="dropdown-item col-4 px-0" :aria-pressed="refreshRate == 10" :class="{active: refreshRate == 10}" @click.stop="refreshRate = 10">10m</button> <button class="dropdown-item col-4 px-0" :class="{active: refreshRate == 10}" @click.stop="refreshRate = 10">10m</button>
<button class="dropdown-item col-4 px-0" :aria-pressed="refreshRate == 30" :class="{active: refreshRate == 30}" @click.stop="refreshRate = 30">30m</button> <button class="dropdown-item col-4 px-0" :class="{active: refreshRate == 30}" @click.stop="refreshRate = 30">30m</button>
<button class="dropdown-item col-4 px-0" :aria-pressed="refreshRate == 60" :class="{active: refreshRate == 60}" @click.stop="refreshRate = 60">1h</button> <button class="dropdown-item col-4 px-0" :class="{active: refreshRate == 60}" @click.stop="refreshRate = 60">1h</button>
<button class="dropdown-item col-4 px-0" :aria-pressed="refreshRate == 120" :class="{active: refreshRate == 120}" @click.stop="refreshRate = 120">2h</button> <button class="dropdown-item col-4 px-0" :class="{active: refreshRate == 120}" @click.stop="refreshRate = 120">2h</button>
<button class="dropdown-item col-4 px-0" :aria-pressed="refreshRate == 240" :class="{active: refreshRate == 240}" @click.stop="refreshRate = 240">4h</button> <button class="dropdown-item col-4 px-0" :class="{active: refreshRate == 240}" @click.stop="refreshRate = 240">4h</button>
</div> </div>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<header class="dropdown-header" role="heading" aria-level="2">Show first</header> <header class="dropdown-header">Show first</header>
<div class="d-flex text-center"> <div class="d-flex text-center">
<button class="dropdown-item px-0" :aria-pressed="itemSortNewestFirst" :class="{active: itemSortNewestFirst}" @click.stop="itemSortNewestFirst=true">New</button> <button class="dropdown-item px-0" :class="{active: itemSortNewestFirst}" @click.stop="itemSortNewestFirst=true">New</button>
<button class="dropdown-item px-0" :aria-pressed="!itemSortNewestFirst" :class="{active: !itemSortNewestFirst}" @click.stop="itemSortNewestFirst=false">Old</button> <button class="dropdown-item px-0" :class="{active: !itemSortNewestFirst}" @click.stop="itemSortNewestFirst=false">Old</button>
</div> </div>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<header class="dropdown-header" role="heading" aria-level="2">Subscriptions</header> <header class="dropdown-header">Subscriptions</header>
<form id="opml-import-form" enctype="multipart/form-data" tabindex="-1"> <form id="opml-import-form" enctype="multipart/form-data" tabindex="-1">
<input type="file" <input type="file"
id="opml-import" id="opml-import"
@@ -211,12 +206,12 @@
<template v-slot:button> <template v-slot:button>
<span class="icon">{% inline "more-horizontal.svg" %}</span> <span class="icon">{% inline "more-horizontal.svg" %}</span>
</template> </template>
<header class="dropdown-header" role="heading" aria-level="2">{{ current.feed.title }}</header> <header class="dropdown-header">{{ current.feed.title }}</header>
<a class="dropdown-item" :href="current.feed.link" rel="noopener noreferrer" target="_blank" referrerpolicy="no-referrer" v-if="current.feed.link"> <a class="dropdown-item" :href="current.feed.link" target="_blank" v-if="current.feed.link">
<span class="icon mr-1">{% inline "globe.svg" %}</span> <span class="icon mr-1">{% inline "globe.svg" %}</span>
Website Website
</a> </a>
<a class="dropdown-item" :href="current.feed.feed_link" rel="noopener noreferrer" target="_blank" referrerpolicy="no-referrer" v-if="current.feed.feed_link"> <a class="dropdown-item" :href="current.feed.feed_link" target="_blank" v-if="current.feed.feed_link">
<span class="icon mr-1">{% inline "rss.svg" %}</span> <span class="icon mr-1">{% inline "rss.svg" %}</span>
Feed Link Feed Link
</a> </a>
@@ -225,12 +220,8 @@
<span class="icon mr-1">{% inline "edit.svg" %}</span> <span class="icon mr-1">{% inline "edit.svg" %}</span>
Rename Rename
</button> </button>
<button class="dropdown-item" @click="updateFeedLink(current.feed)" v-if="current.feed.feed_link">
<span class="icon mr-1">{% inline "edit.svg" %}</span>
Change Link
</button>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<header class="dropdown-header" role="heading" aria-level="2">Move to...</header> <header class="dropdown-header">Move to...</header>
<button class="dropdown-item" <button class="dropdown-item"
v-if="folder.id != current.feed.folder_id" v-if="folder.id != current.feed.folder_id"
v-for="folder in folders" v-for="folder in folders"
@@ -260,7 +251,7 @@
<template v-slot:button> <template v-slot:button>
<span class="icon">{% inline "more-horizontal.svg" %}</span> <span class="icon">{% inline "more-horizontal.svg" %}</span>
</template> </template>
<header class="dropdown-header" role="heading" aria-level="2">{{ current.folder.title }}</header> <header class="dropdown-header">{{ current.folder.title }}</header>
<button class="dropdown-item" @click="renameFolder(current.folder)"> <button class="dropdown-item" @click="renameFolder(current.folder)">
<span class="icon mr-1">{% inline "edit.svg" %}</span> <span class="icon mr-1">{% inline "edit.svg" %}</span>
Rename Rename
@@ -331,16 +322,10 @@
title="Read Here"> title="Read Here">
<span class="icon" :class="{'icon-loading': loading.readability}">{% inline "book-open.svg" %}</span> <span class="icon" :class="{'icon-loading': loading.readability}">{% inline "book-open.svg" %}</span>
</button> </button>
<a class="toolbar-item" :href="itemSelectedDetails.link" rel="noopener noreferrer" target="_blank" referrerpolicy="no-referrer" title="Open Link"> <a class="toolbar-item" :href="itemSelectedDetails.link" target="_blank" title="Open Link">
<span class="icon">{% inline "external-link.svg" %}</span> <span class="icon">{% inline "external-link.svg" %}</span>
</a> </a>
<div class="flex-grow-1"></div> <div class="flex-grow-1"></div>
<button class="toolbar-item" @click="navigateToItem(-1)" title="Previous Article" :disabled="itemSelected == items[0].id">
<span class="icon">{% inline "chevron-left.svg" %}</span>
</button>
<button class="toolbar-item" @click="navigateToItem(+1)" title="Next Article" :disabled="itemSelected == items[items.length - 1].id">
<span class="icon">{% inline "chevron-right.svg" %}</span>
</button>
<button class="toolbar-item" @click="itemSelected=null" title="Close Article"> <button class="toolbar-item" @click="itemSelected=null" title="Close Article">
<span class="icon">{% inline "x.svg" %}</span> <span class="icon">{% inline "x.svg" %}</span>
</button> </button>
@@ -353,23 +338,13 @@
<div class="content-wrapper"> <div class="content-wrapper">
<h1><b>{{ itemSelectedDetails.title || 'untitled' }}</b></h1> <h1><b>{{ itemSelectedDetails.title || 'untitled' }}</b></h1>
<div class="text-muted"> <div class="text-muted">
<div> <div>{{ (feedsById[itemSelectedDetails.feed_id] || {}).title }}</div>
<span class="cursor-pointer" @click="feedSelected = 'feed:'+(feedsById[itemSelectedDetails.feed_id] || {}).id">
{{ (feedsById[itemSelectedDetails.feed_id] || {}).title }}
</span>
</div>
<time>{{ formatDate(itemSelectedDetails.date) }}</time> <time>{{ formatDate(itemSelectedDetails.date) }}</time>
</div> </div>
<hr> <hr>
<div v-if="!itemSelectedReadability"> <div v-if="!itemSelectedReadability">
<div v-if="contentImages.length"> <img :src="itemSelectedDetails.image" v-if="itemSelectedDetails.image" class="mb-3">
<figure v-for="media in contentImages"> <audio class="w-100" controls v-if="itemSelectedDetails.podcast_url" :src="itemSelectedDetails.podcast_url"></audio>
<img :src="media.url" loading="lazy">
<figcaption v-if="media.description" v-html="media.description"></figcaption>
</figure>
</div>
<audio class="w-100" controls v-for="media in contentAudios" :src="media.url"></audio>
<video class="w-100" controls v-for="media in contentVideos" :src="media.url"></video>
</div> </div>
<div v-html="itemSelectedContent"></div> <div v-html="itemSelectedContent"></div>
</div> </div>

View File

@@ -2,26 +2,6 @@
var TITLE = document.title var TITLE = document.title
function scrollto(target, scroll) {
var padding = 10
var targetRect = target.getBoundingClientRect()
var scrollRect = scroll.getBoundingClientRect()
// target
var relativeOffset = targetRect.y - scrollRect.y
var absoluteOffset = relativeOffset + scroll.scrollTop
if (padding <= relativeOffset && relativeOffset + targetRect.height <= scrollRect.height - padding) return
var newPos = scroll.scrollTop
if (relativeOffset < padding) {
newPos = absoluteOffset - padding
} else {
newPos = absoluteOffset - scrollRect.height + targetRect.height + padding
}
scroll.scrollTop = Math.round(newPos)
}
var debounce = function(callback, wait) { var debounce = function(callback, wait) {
var timeout var timeout
return function() { return function() {
@@ -298,18 +278,6 @@ var vm = new Vue({
return this.itemSelectedDetails.content || '' return this.itemSelectedDetails.content || ''
}, },
contentImages: function() {
if (!this.itemSelectedDetails) return []
return (this.itemSelectedDetails.media_links || []).filter(l => l.type === 'image')
},
contentAudios: function() {
if (!this.itemSelectedDetails) return []
return (this.itemSelectedDetails.media_links || []).filter(l => l.type === 'audio')
},
contentVideos: function() {
if (!this.itemSelectedDetails) return []
return (this.itemSelectedDetails.media_links || []).filter(l => l.type === 'video')
}
}, },
watch: { watch: {
'theme': { 'theme': {
@@ -439,7 +407,7 @@ var vm = new Vue({
vm.feeds = values[1] vm.feeds = values[1]
}) })
}, },
refreshItems: function(loadMore = false) { refreshItems: function(loadMore) {
if (this.feedSelected === null) { if (this.feedSelected === null) {
vm.items = [] vm.items = []
vm.itemsHasMore = false vm.itemsHasMore = false
@@ -452,7 +420,7 @@ var vm = new Vue({
} }
this.loading.items = true this.loading.items = true
return api.items.list(query).then(function(data) { api.items.list(query).then(function(data) {
if (loadMore) { if (loadMore) {
vm.items = vm.items.concat(data.list) vm.items = vm.items.concat(data.list)
} else { } else {
@@ -475,17 +443,13 @@ var vm = new Vue({
var scale = (parseFloat(getComputedStyle(document.documentElement).fontSize) || 16) / 16 var scale = (parseFloat(getComputedStyle(document.documentElement).fontSize) || 16) / 16
var el = this.$refs.itemlist var el = this.$refs.itemlist
if (el.scrollHeight === 0) return false // element is invisible (responsive design)
var closeToBottom = (el.scrollHeight - el.scrollTop - el.offsetHeight) < bottomSpace * scale var closeToBottom = (el.scrollHeight - el.scrollTop - el.offsetHeight) < bottomSpace * scale
return closeToBottom return closeToBottom
}, },
loadMoreItems: function(event, el) { loadMoreItems: function(event, el) {
if (!this.itemsHasMore) return if (!this.itemsHasMore) return
if (this.loading.items) return if (this.loading.items) return
if (this.itemListCloseToBottom()) return this.refreshItems(true) if (this.itemListCloseToBottom()) this.refreshItems(true)
if (this.itemSelected && this.itemSelected === this.items[this.items.length - 1].id) return this.refreshItems(true)
}, },
markItemsRead: function() { markItemsRead: function() {
var query = this.getItemsQuery() var query = this.getItemsQuery()
@@ -559,14 +523,6 @@ var vm = new Vue({
}) })
} }
}, },
updateFeedLink: function(feed) {
var newLink = prompt('Enter feed link', feed.feed_link)
if (newLink) {
api.feeds.update(feed.id, {feed_link: newLink}).then(function() {
feed.feed_link = newLink
})
}
},
renameFeed: function(feed) { renameFeed: function(feed) {
var newTitle = prompt('Enter new title', feed.title) var newTitle = prompt('Enter new title', feed.title)
if (newTitle) { if (newTitle) {
@@ -719,65 +675,6 @@ var vm = new Vue({
this.filteredFolderStats = statsFolders this.filteredFolderStats = statsFolders
this.filteredTotalStats = statsTotal this.filteredTotalStats = statsTotal
}, },
// navigation helper, navigate relative to selected item
navigateToItem: function(relativePosition) {
let vm = this
if (vm.itemSelected == null) {
// if no item is selected, select first
if (vm.items.length !== 0) vm.itemSelected = vm.items[0].id
return
}
var itemPosition = vm.items.findIndex(function(x) { return x.id === vm.itemSelected })
if (itemPosition === -1) {
if (vm.items.length !== 0) vm.itemSelected = vm.items[0].id
return
}
var newPosition = itemPosition + relativePosition
if (newPosition < 0 || newPosition >= vm.items.length) return
vm.itemSelected = vm.items[newPosition].id
vm.$nextTick(function() {
var scroll = document.querySelector('#item-list-scroll')
var handle = scroll.querySelector('input[type=radio]:checked')
var target = handle && handle.parentElement
if (target && scroll) scrollto(target, scroll)
vm.loadMoreItems()
})
},
// navigation helper, navigate relative to selected feed
navigateToFeed: function(relativePosition) {
let vm = this
var navigationList = Array.from(document.querySelectorAll('#col-feed-list input[name=feed]'))
.filter(function(r) { return r.offsetParent !== null && r.value !== 'folder:null' })
.map(function(r) { return r.value })
var currentFeedPosition = navigationList.indexOf(vm.feedSelected)
if (currentFeedPosition == -1) {
vm.feedSelected = ''
return
}
var newPosition = currentFeedPosition+relativePosition
if (newPosition < 0 || newPosition >= navigationList.length) return
vm.feedSelected = navigationList[newPosition]
vm.$nextTick(function() {
var scroll = document.querySelector('#feed-list-scroll')
var handle = scroll.querySelector('input[type=radio]:checked')
var target = handle && handle.parentElement
if (target && scroll) scrollto(target, scroll)
})
},
} }
}) })

View File

@@ -1,4 +1,79 @@
function scrollto(target, scroll) {
var padding = 10
var targetRect = target.getBoundingClientRect()
var scrollRect = scroll.getBoundingClientRect()
// target
var relativeOffset = targetRect.y - scrollRect.y
var absoluteOffset = relativeOffset + scroll.scrollTop
if (padding <= relativeOffset && relativeOffset + targetRect.height <= scrollRect.height - padding) return
var newPos = scroll.scrollTop
if (relativeOffset < padding) {
newPos = absoluteOffset - padding
} else {
newPos = absoluteOffset - scrollRect.height + targetRect.height + padding
}
scroll.scrollTop = Math.round(newPos)
}
var helperFunctions = { var helperFunctions = {
// navigation helper, navigate relative to selected item
navigateToItem: function(relativePosition) {
if (vm.itemSelected == null) {
// if no item is selected, select first
if (vm.items.length !== 0) vm.itemSelected = vm.items[0].id
return
}
var itemPosition = vm.items.findIndex(function(x) { return x.id === vm.itemSelected })
if (itemPosition === -1) {
if (vm.items.length !== 0) vm.itemSelected = vm.items[0].id
return
}
var newPosition = itemPosition + relativePosition
if (newPosition < 0 || newPosition >= vm.items.length) return
vm.itemSelected = vm.items[newPosition].id
vm.$nextTick(function() {
var scroll = document.querySelector('#item-list-scroll')
var handle = scroll.querySelector('input[type=radio]:checked')
var target = handle && handle.parentElement
if (target && scroll) scrollto(target, scroll)
})
},
// navigation helper, navigate relative to selected feed
navigateToFeed: function(relativePosition) {
var navigationList = Array.from(document.querySelectorAll('#col-feed-list input[name=feed]'))
.filter(function(r) { return r.offsetParent !== null && r.value !== 'folder:null' })
.map(function(r) { return r.value })
var currentFeedPosition = navigationList.indexOf(vm.feedSelected)
if (currentFeedPosition == -1) {
vm.feedSelected = ''
return
}
var newPosition = currentFeedPosition+relativePosition
if (newPosition < 0 || newPosition >= navigationList.length) return
vm.feedSelected = navigationList[newPosition]
vm.$nextTick(function() {
var scroll = document.querySelector('#feed-list-scroll')
var handle = scroll.querySelector('input[type=radio]:checked')
var target = handle && handle.parentElement
if (target && scroll) scrollto(target, scroll)
})
},
scrollContent: function(direction) { scrollContent: function(direction) {
var padding = 40 var padding = 40
var scroll = document.querySelector('.content') var scroll = document.querySelector('.content')
@@ -17,7 +92,7 @@ var helperFunctions = {
var shortcutFunctions = { var shortcutFunctions = {
openItemLink: function() { openItemLink: function() {
if (vm.itemSelectedDetails && vm.itemSelectedDetails.link) { if (vm.itemSelectedDetails && vm.itemSelectedDetails.link) {
window.open(vm.itemSelectedDetails.link, '_blank', 'noopener,noreferrer') window.open(vm.itemSelectedDetails.link, '_blank')
} }
}, },
toggleReadability: function() { toggleReadability: function() {
@@ -43,16 +118,16 @@ var shortcutFunctions = {
document.getElementById("searchbar").focus() document.getElementById("searchbar").focus()
}, },
nextItem(){ nextItem(){
vm.navigateToItem(+1) helperFunctions.navigateToItem(+1)
}, },
previousItem() { previousItem() {
vm.navigateToItem(-1) helperFunctions.navigateToItem(-1)
}, },
nextFeed(){ nextFeed(){
vm.navigateToFeed(+1) helperFunctions.navigateToFeed(+1)
}, },
previousFeed() { previousFeed() {
vm.navigateToFeed(-1) helperFunctions.navigateToFeed(-1)
}, },
scrollForward: function() { scrollForward: function() {
helperFunctions.scrollContent(+1) helperFunctions.scrollContent(+1)

View File

@@ -22,7 +22,7 @@
} }
</style> </style>
</head> </head>
<body class="theme-{% .settings.theme_name %}"> <body>
<form action="" method="post"> <form action="" method="post">
<img src="./static/graphicarts/anchor.svg" alt=""> <img src="./static/graphicarts/anchor.svg" alt="">
{% if .error %} {% if .error %}

View File

@@ -2,7 +2,6 @@ package htmlutil
import ( import (
"net/url" "net/url"
"strings"
) )
func Any(els []string, el string, match func(string, string) bool) bool { func Any(els []string, el string, match func(string, string) bool) bool {
@@ -32,7 +31,3 @@ func URLDomain(val string) string {
} }
return val return val
} }
func IsAPossibleLink(val string) bool {
return strings.HasPrefix(val, "http://") || strings.HasPrefix(val, "https://")
}

View File

@@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"regexp" "regexp"
"strings" "strings"
"unicode"
"golang.org/x/net/html" "golang.org/x/net/html"
) )
@@ -62,16 +61,3 @@ func ExtractText(content string) string {
text = whitespaceRegex.ReplaceAllLiteralString(text, " ") text = whitespaceRegex.ReplaceAllLiteralString(text, " ")
return text return text
} }
func TruncateText(input string, size int) string {
runes := []rune(input)
if len(runes) <= size {
return input
}
for i := size - 1; i > 0; i-- {
if unicode.IsSpace(runes[i]) {
return string(runes[:i]) + " ..."
}
}
return input
}

View File

@@ -24,21 +24,3 @@ func TestExtractText(t *testing.T) {
} }
} }
} }
func TestTruncateText(t *testing.T) {
input := "Lorem ipsum — классический текст-«рыба»"
size := 30
want := "Lorem ipsum — классический ..."
have := TruncateText(input, size)
if want != have {
t.Errorf("\nsize: %d\nwant: %#v\nhave: %#v", size, want, have)
}
size = 1000
want = input
have = TruncateText(input, size)
if want != have {
t.Errorf("\nsize: %d\nwant: %#v\nhave: %#v", size, want, have)
}
}

View File

@@ -167,7 +167,7 @@ func getExtraAttributes(tagName string) ([]string, []string) {
case "iframe": case "iframe":
return []string{"sandbox", "loading"}, []string{`sandbox="allow-scripts allow-same-origin allow-popups"`, `loading="lazy"`} return []string{"sandbox", "loading"}, []string{`sandbox="allow-scripts allow-same-origin allow-popups"`, `loading="lazy"`}
case "img": case "img":
return []string{"loading"}, []string{`loading="lazy"`, `referrerpolicy="no-referrer"`} return []string{"loading"}, []string{`loading="lazy"`}
default: default:
return nil, nil return nil, nil
} }

View File

@@ -8,11 +8,10 @@ import "testing"
func TestValidInput(t *testing.T) { func TestValidInput(t *testing.T) {
input := `<p>This is a <strong>text</strong> with an image: <img src="http://example.org/" alt="Test" loading="lazy">.</p>` input := `<p>This is a <strong>text</strong> with an image: <img src="http://example.org/" alt="Test" loading="lazy">.</p>`
want := `<p>This is a <strong>text</strong> with an image: <img src="http://example.org/" alt="Test" loading="lazy" referrerpolicy="no-referrer">.</p>` output := Sanitize("http://example.org/", input)
have := Sanitize("http://example.org/", input)
if have != want { if input != output {
t.Errorf("Wrong output: \nwant: %#v\nhave: %#v", want, have) t.Errorf(`Wrong output: "%s" != "%s"`, input, output)
} }
} }
@@ -28,31 +27,31 @@ func TestImgWithTextDataURL(t *testing.T) {
func TestImgWithDataURL(t *testing.T) { func TestImgWithDataURL(t *testing.T) {
input := `<img src="data:image/gif;base64,test" alt="Example">` input := `<img src="data:image/gif;base64,test" alt="Example">`
want := `<img src="data:image/gif;base64,test" alt="Example" loading="lazy" referrerpolicy="no-referrer">` expected := `<img src="data:image/gif;base64,test" alt="Example" loading="lazy">`
have := Sanitize("http://example.org/", input) output := Sanitize("http://example.org/", input)
if have != want { if output != expected {
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have) t.Errorf(`Wrong output: %s`, output)
} }
} }
func TestImgWithSrcset(t *testing.T) { func TestImgWithSrcset(t *testing.T) {
input := `<img srcset="example-320w.jpg, example-480w.jpg 1.5x, example-640w.jpg 2x, example-640w.jpg 640w" src="example-640w.jpg" alt="Example">` input := `<img srcset="example-320w.jpg, example-480w.jpg 1.5x, example-640w.jpg 2x, example-640w.jpg 640w" src="example-640w.jpg" alt="Example">`
want := `<img srcset="http://example.org/example-320w.jpg, http://example.org/example-480w.jpg 1.5x, http://example.org/example-640w.jpg 2x, http://example.org/example-640w.jpg 640w" src="http://example.org/example-640w.jpg" alt="Example" loading="lazy" referrerpolicy="no-referrer">` expected := `<img srcset="http://example.org/example-320w.jpg, http://example.org/example-480w.jpg 1.5x, http://example.org/example-640w.jpg 2x, http://example.org/example-640w.jpg 640w" src="http://example.org/example-640w.jpg" alt="Example" loading="lazy">`
have := Sanitize("http://example.org/", input) output := Sanitize("http://example.org/", input)
if have != want { if output != expected {
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have) t.Errorf(`Wrong output: %s`, output)
} }
} }
func TestImgWithSrcsetAndDataURL(t *testing.T) { func TestImgWithSrcsetAndDataURL(t *testing.T) {
input := `<img srcset="data:image/gif;base64,test" src="http://example.org/example-320w.jpg" alt="Example">` input := `<img srcset="data:image/gif;base64,test" src="http://example.org/example-320w.jpg" alt="Example">`
want := `<img srcset="data:image/gif;base64,test" src="http://example.org/example-320w.jpg" alt="Example" loading="lazy" referrerpolicy="no-referrer">` expected := `<img srcset="data:image/gif;base64,test" src="http://example.org/example-320w.jpg" alt="Example" loading="lazy">`
have := Sanitize("http://example.org/", input) output := Sanitize("http://example.org/", input)
if have != want { if output != expected {
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have) t.Errorf(`Wrong output: %s`, output)
} }
} }
@@ -68,16 +67,16 @@ func TestSourceWithSrcsetAndMedia(t *testing.T) {
func TestMediumImgWithSrcset(t *testing.T) { func TestMediumImgWithSrcset(t *testing.T) {
input := `<img alt="Image for post" class="t u v ef aj" src="https://miro.medium.com/max/5460/1*aJ9JibWDqO81qMfNtqgqrw.jpeg" srcset="https://miro.medium.com/max/552/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 276w, https://miro.medium.com/max/1000/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 500w" sizes="500px" width="2730" height="3407">` input := `<img alt="Image for post" class="t u v ef aj" src="https://miro.medium.com/max/5460/1*aJ9JibWDqO81qMfNtqgqrw.jpeg" srcset="https://miro.medium.com/max/552/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 276w, https://miro.medium.com/max/1000/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 500w" sizes="500px" width="2730" height="3407">`
want := `<img alt="Image for post" src="https://miro.medium.com/max/5460/1*aJ9JibWDqO81qMfNtqgqrw.jpeg" srcset="https://miro.medium.com/max/552/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 276w, https://miro.medium.com/max/1000/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 500w" sizes="500px" loading="lazy" referrerpolicy="no-referrer">` expected := `<img alt="Image for post" src="https://miro.medium.com/max/5460/1*aJ9JibWDqO81qMfNtqgqrw.jpeg" srcset="https://miro.medium.com/max/552/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 276w, https://miro.medium.com/max/1000/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 500w" sizes="500px" loading="lazy">`
have := Sanitize("http://example.org/", input) output := Sanitize("http://example.org/", input)
if have != want { if output != expected {
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have) t.Errorf(`Wrong output: %s`, output)
} }
} }
func TestSelfClosingTags(t *testing.T) { func TestSelfClosingTags(t *testing.T) {
input := `<p>This <br> is a <strong>text</strong><br/>.</p>` input := `<p>This <br> is a <strong>text</strong> <br/>with an image: <img src="http://example.org/" alt="Test" loading="lazy"/>.</p>`
output := Sanitize("http://example.org/", input) output := Sanitize("http://example.org/", input)
if input != output { if input != output {
@@ -96,11 +95,11 @@ func TestTable(t *testing.T) {
func TestRelativeURL(t *testing.T) { func TestRelativeURL(t *testing.T) {
input := `This <a href="/test.html">link is relative</a> and this image: <img src="../folder/image.png"/>` input := `This <a href="/test.html">link is relative</a> and this image: <img src="../folder/image.png"/>`
want := `This <a href="http://example.org/test.html" rel="noopener noreferrer" target="_blank" referrerpolicy="no-referrer">link is relative</a> and this image: <img src="http://example.org/folder/image.png" loading="lazy" referrerpolicy="no-referrer"/>` expected := `This <a href="http://example.org/test.html" rel="noopener noreferrer" target="_blank" referrerpolicy="no-referrer">link is relative</a> and this image: <img src="http://example.org/folder/image.png" loading="lazy"/>`
have := Sanitize("http://example.org/", input) output := Sanitize("http://example.org/", input)
if want != have { if expected != output {
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have) t.Errorf(`Wrong output: "%s" != "%s"`, expected, output)
} }
} }
@@ -166,11 +165,11 @@ func TestInvalidNestedTag(t *testing.T) {
func TestValidIFrame(t *testing.T) { func TestValidIFrame(t *testing.T) {
input := `<iframe src="http://example.org/"></iframe>` input := `<iframe src="http://example.org/"></iframe>`
want := `<iframe src="http://example.org/" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy"></iframe>` expected := `<iframe src="http://example.org/" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy"></iframe>`
have := Sanitize("http://example.org/", input) output := Sanitize("http://example.org/", input)
if want != have { if expected != output {
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have) t.Errorf("Wrong output:\nwant: %s\nhave: %s", expected, output)
} }
} }

View File

@@ -1,7 +1,6 @@
package scraper package scraper
import ( import (
"net/url"
"strings" "strings"
"github.com/nkanaev/yarr/src/content/htmlutil" "github.com/nkanaev/yarr/src/content/htmlutil"
@@ -36,18 +35,6 @@ func FindFeeds(body string, base string) map[string]string {
link := htmlutil.AbsoluteUrl(href, base) link := htmlutil.AbsoluteUrl(href, base)
if link != "" { if link != "" {
candidates[link] = name candidates[link] = name
l, err := url.Parse(link)
if err == nil && l.Host == "www.youtube.com" && l.Path == "/feeds/videos.xml" {
// https://wiki.archiveteam.org/index.php/YouTube/Technical_details#Playlists
channelID, found := strings.CutPrefix(l.Query().Get("channel_id"), "UC")
if found {
const url string = "https://www.youtube.com/feeds/videos.xml?playlist_id="
candidates[url+"UULF"+channelID] = name + " - Videos"
candidates[url+"UULV"+channelID] = name + " - Live Streams"
candidates[url+"UUSH"+channelID] = name + " - Short videos"
}
}
} }
} }

View File

@@ -13,7 +13,6 @@ import (
"github.com/nkanaev/yarr/src/platform" "github.com/nkanaev/yarr/src/platform"
"github.com/nkanaev/yarr/src/server" "github.com/nkanaev/yarr/src/server"
"github.com/nkanaev/yarr/src/storage" "github.com/nkanaev/yarr/src/storage"
"github.com/nkanaev/yarr/src/worker"
) )
var Version string = "0.0" var Version string = "0.0"
@@ -90,12 +89,12 @@ func main() {
log.SetOutput(os.Stdout) log.SetOutput(os.Stdout)
} }
if db == "" {
configPath, err := os.UserConfigDir() configPath, err := os.UserConfigDir()
if err != nil { if err != nil {
log.Fatal("Failed to get config dir: ", err) log.Fatal("Failed to get config dir: ", err)
} }
if db == "" {
storagePath := filepath.Join(configPath, "yarr") storagePath := filepath.Join(configPath, "yarr")
if err := os.MkdirAll(storagePath, 0755); err != nil { if err := os.MkdirAll(storagePath, 0755); err != nil {
log.Fatal("Failed to create app config dir: ", err) log.Fatal("Failed to create app config dir: ", err)
@@ -106,7 +105,6 @@ func main() {
log.Printf("using db file %s", db) log.Printf("using db file %s", db)
var username, password string var username, password string
var err error
if authfile != "" { if authfile != "" {
f, err := os.Open(authfile) f, err := os.Open(authfile)
if err != nil { if err != nil {
@@ -133,7 +131,6 @@ func main() {
log.Fatal("Failed to initialise database: ", err) log.Fatal("Failed to initialise database: ", err)
} }
worker.SetVersion(Version)
srv := server.NewServer(store, addr) srv := server.NewServer(store, addr)
if basepath != "" { if basepath != "" {

View File

@@ -3,6 +3,7 @@ package parser
import ( import (
"encoding/xml" "encoding/xml"
"html"
"io" "io"
"strings" "strings"
@@ -46,8 +47,6 @@ type atomLinks []atomLink
func (a *atomText) Text() string { func (a *atomText) Text() string {
if a.Type == "html" { if a.Type == "html" {
return htmlutil.ExtractText(a.Data) return htmlutil.ExtractText(a.Data)
} else if a.Type == "xhtml" {
return htmlutil.ExtractText(a.XML)
} }
return a.Data return a.Data
} }
@@ -57,7 +56,7 @@ func (a *atomText) String() string {
if a.Type == "xhtml" { if a.Type == "xhtml" {
data = a.XML data = a.XML
} }
return strings.TrimSpace(data) return html.UnescapeString(strings.TrimSpace(data))
} }
func (links atomLinks) First(rel string) string { func (links atomLinks) First(rel string) string {
@@ -82,23 +81,15 @@ func ParseAtom(r io.Reader) (*Feed, error) {
SiteURL: firstNonEmpty(srcfeed.Links.First("alternate"), srcfeed.Links.First("")), SiteURL: firstNonEmpty(srcfeed.Links.First("alternate"), srcfeed.Links.First("")),
} }
for _, srcitem := range srcfeed.Entries { for _, srcitem := range srcfeed.Entries {
linkFromID := "" link := firstNonEmpty(srcitem.OrigLink, srcitem.Links.First("alternate"), srcitem.Links.First(""))
guidFromID := ""
if htmlutil.IsAPossibleLink(srcitem.ID) {
linkFromID = srcitem.ID
guidFromID = srcitem.ID + "::" + srcitem.Updated
}
mediaLinks := srcitem.mediaLinks()
link := firstNonEmpty(srcitem.OrigLink, srcitem.Links.First("alternate"), srcitem.Links.First(""), linkFromID)
dstfeed.Items = append(dstfeed.Items, Item{ dstfeed.Items = append(dstfeed.Items, Item{
GUID: firstNonEmpty(guidFromID, srcitem.ID, link), GUID: firstNonEmpty(srcitem.ID, link),
Date: dateParse(firstNonEmpty(srcitem.Published, srcitem.Updated)), Date: dateParse(firstNonEmpty(srcitem.Published, srcitem.Updated)),
URL: link, URL: link,
Title: srcitem.Title.Text(), Title: srcitem.Title.Text(),
Content: firstNonEmpty(srcitem.Content.String(), srcitem.Summary.String(), srcitem.firstMediaDescription()), Content: firstNonEmpty(srcitem.Content.String(), srcitem.Summary.String(), srcitem.firstMediaDescription()),
MediaLinks: mediaLinks, ImageURL: srcitem.firstMediaThumbnail(),
AudioURL: "",
}) })
} }
return dstfeed, nil return dstfeed, nil

View File

@@ -45,6 +45,8 @@ func TestAtom(t *testing.T) {
URL: "http://example.org/2003/12/13/atom03.html", URL: "http://example.org/2003/12/13/atom03.html",
Title: "Atom-Powered Robots Run Amok", Title: "Atom-Powered Robots Run Amok",
Content: `<div xmlns="http://www.w3.org/1999/xhtml"><p>This is the entry content.</p></div>`, Content: `<div xmlns="http://www.w3.org/1999/xhtml"><p>This is the entry content.</p></div>`,
ImageURL: "",
AudioURL: "",
}, },
}, },
} }
@@ -92,44 +94,6 @@ func TestAtomHTMLTitle(t *testing.T) {
} }
} }
func TestAtomXHTMLTitle(t *testing.T) {
feed, _ := Parse(strings.NewReader(`
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<entry><title type="xhtml">say &lt;code&gt;what&lt;/code&gt;?</entry>
</feed>
`))
have := feed.Items[0].Title
want := "say what?"
if !reflect.DeepEqual(want, have) {
t.Logf("want: %#v", want)
t.Logf("have: %#v", have)
t.FailNow()
}
}
func TestAtomXHTMLNestedTitle(t *testing.T) {
feed, _ := Parse(strings.NewReader(`
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<entry>
<title type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<a href="https://example.com">Link to Example</a>
</div>
</title>
</entry>
</feed>
`))
have := feed.Items[0].Title
want := "Link to Example"
if !reflect.DeepEqual(want, have) {
t.Logf("want: %#v", want)
t.Logf("have: %#v", have)
t.FailNow()
}
}
func TestAtomImageLink(t *testing.T) { func TestAtomImageLink(t *testing.T) {
feed, _ := Parse(strings.NewReader(` feed, _ := Parse(strings.NewReader(`
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
@@ -139,15 +103,9 @@ func TestAtomImageLink(t *testing.T) {
</entry> </entry>
</feed> </feed>
`)) `))
if len(feed.Items[0].MediaLinks) != 1 { have := feed.Items[0].ImageURL
t.Fatalf("Expected 1 media link, got: %#v", feed.Items[0].MediaLinks) want := `https://example.com/image.png?width=100&height=100`
} if want != have {
have := feed.Items[0].MediaLinks[0]
want := MediaLink{
URL: `https://example.com/image.png?width=100&height=100`,
Type: "image",
}
if !reflect.DeepEqual(want, have) {
t.Fatalf("item.image_url doesn't match\nwant: %#v\nhave: %#v\n", want, have) t.Fatalf("item.image_url doesn't match\nwant: %#v\nhave: %#v\n", want, have)
} }
} }
@@ -169,68 +127,7 @@ func TestAtomImageLinkDuplicated(t *testing.T) {
if want != have { if want != have {
t.Fatalf("want: %#v\nhave: %#v\n", want, have) t.Fatalf("want: %#v\nhave: %#v\n", want, have)
} }
if len(feed.Items[0].MediaLinks) != 0 { if feed.Items[0].ImageURL != "" {
t.Fatal("item media link must be excluded if present in the content") t.Fatal("item.image_url must be unset if present in the content")
}
}
func TestAtomLinkInID(t *testing.T) {
feed, _ := Parse(strings.NewReader(`
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
<entry>
<title>one updated</title>
<id>https://example.com/posts/1</id>
<updated>2003-12-13T09:17:51</updated>
</entry>
<entry>
<title>two</title>
<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
</entry>
<entry>
<title>one</title>
<id>https://example.com/posts/1</id>
</entry>
</feed>
`))
have := feed.Items
want := []Item{
Item{
GUID: "https://example.com/posts/1::2003-12-13T09:17:51",
Date: time.Date(2003, time.December, 13, 9, 17, 51, 0, time.UTC),
URL: "https://example.com/posts/1",
Title: "one updated",
},
Item{
GUID: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6",
Date: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), URL: "",
Title: "two",
},
Item{
GUID: "https://example.com/posts/1::",
Date: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC),
URL: "https://example.com/posts/1",
Title: "one",
Content: "",
},
}
if !reflect.DeepEqual(want, have) {
t.Fatalf("\nwant: %#v\nhave: %#v\n", want, have)
}
}
func TestAtomDoesntEscapeHTMLTags(t *testing.T) {
feed, _ := Parse(strings.NewReader(`
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<entry><summary type="html">&amp;lt;script&amp;gt;alert(1);&amp;lt;/script&amp;gt;</summary></entry>
</feed>
`))
have := feed.Items[0].Content
want := "&lt;script&gt;alert(1);&lt;/script&gt;"
if !reflect.DeepEqual(want, have) {
t.Logf("want: %#v", want)
t.Logf("have: %#v", have)
t.FailNow()
} }
} }

View File

@@ -2,7 +2,6 @@ package parser
import ( import (
"bytes" "bytes"
"crypto/sha256"
"encoding/xml" "encoding/xml"
"errors" "errors"
"fmt" "fmt"
@@ -120,7 +119,6 @@ func ParseAndFix(r io.Reader, baseURL, fallbackEncoding string) (*Feed, error) {
} }
feed.TranslateURLs(baseURL) feed.TranslateURLs(baseURL)
feed.SetMissingDatesTo(time.Now()) feed.SetMissingDatesTo(time.Now())
feed.SetMissingGUIDs()
return feed, nil return feed, nil
} }
@@ -134,14 +132,11 @@ func (feed *Feed) cleanup() {
feed.Items[i].Title = strings.TrimSpace(htmlutil.ExtractText(item.Title)) feed.Items[i].Title = strings.TrimSpace(htmlutil.ExtractText(item.Title))
feed.Items[i].Content = strings.TrimSpace(item.Content) feed.Items[i].Content = strings.TrimSpace(item.Content)
if len(feed.Items[i].MediaLinks) > 0 { if item.ImageURL != "" && strings.Contains(item.Content, item.ImageURL) {
mediaLinks := make([]MediaLink, 0) feed.Items[i].ImageURL = ""
for _, link := range item.MediaLinks {
if !strings.Contains(item.Content, link.URL) {
mediaLinks = append(mediaLinks, link)
} }
} if item.AudioURL != "" && strings.Contains(item.Content, item.AudioURL) {
feed.Items[i].MediaLinks = mediaLinks feed.Items[i].AudioURL = ""
} }
} }
} }
@@ -173,12 +168,3 @@ func (feed *Feed) TranslateURLs(base string) error {
} }
return nil return nil
} }
func (feed *Feed) SetMissingGUIDs() {
for i, item := range feed.Items {
if item.GUID == "" {
id := strings.Join([]string{item.Title, item.Date.Format(time.RFC3339), item.URL}, ";;")
feed.Items[i].GUID = fmt.Sprintf("%x", sha256.Sum256([]byte(id)))
}
}
}

View File

@@ -150,32 +150,3 @@ func TestParseCleanIllegalCharsInNonUTF8(t *testing.T) {
t.Fatalf("invalid feed, got: %v", feed) t.Fatalf("invalid feed, got: %v", feed)
} }
} }
func TestParseMissingGUID(t *testing.T) {
data := `
<?xml version="1.0" encoding="windows-1251"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<item>
<title>foo</title>
</item>
<item>
<title>bar</title>
</item>
</channel>
</rss>
`
feed, err := ParseAndFix(strings.NewReader(data), "", "")
if err != nil {
t.Fatal(err)
}
if len(feed.Items) != 2 {
t.Fatalf("expected 2 items, got %d", len(feed.Items))
}
if feed.Items[0].GUID == "" || feed.Items[1].GUID == "" {
t.Fatalf("item GUIDs are missing, got %#v", feed.Items)
}
if feed.Items[0].GUID == feed.Items[1].GUID {
t.Fatalf("item GUIDs are not unique, got %#v", feed.Items)
}
}

View File

@@ -1,9 +1,5 @@
package parser package parser
import (
"strings"
)
type media struct { type media struct {
MediaGroups []mediaGroup `xml:"http://search.yahoo.com/mrss/ group"` MediaGroups []mediaGroup `xml:"http://search.yahoo.com/mrss/ group"`
MediaContents []mediaContent `xml:"http://search.yahoo.com/mrss/ content"` MediaContents []mediaContent `xml:"http://search.yahoo.com/mrss/ content"`
@@ -12,17 +8,12 @@ type media struct {
} }
type mediaGroup struct { type mediaGroup struct {
MediaContent []mediaContent `xml:"http://search.yahoo.com/mrss/ content"`
MediaThumbnails []mediaThumbnail `xml:"http://search.yahoo.com/mrss/ thumbnail"` MediaThumbnails []mediaThumbnail `xml:"http://search.yahoo.com/mrss/ thumbnail"`
MediaDescriptions []mediaDescription `xml:"http://search.yahoo.com/mrss/ description"` MediaDescriptions []mediaDescription `xml:"http://search.yahoo.com/mrss/ description"`
} }
type mediaContent struct { type mediaContent struct {
MediaThumbnails []mediaThumbnail `xml:"http://search.yahoo.com/mrss/ thumbnail"` MediaThumbnails []mediaThumbnail `xml:"http://search.yahoo.com/mrss/ thumbnail"`
MediaType string `xml:"type,attr"`
MediaMedium string `xml:"medium,attr"`
MediaURL string `xml:"url,attr"`
MediaDescription mediaDescription `xml:"http://search.yahoo.com/mrss/ description"`
} }
type mediaThumbnail struct { type mediaThumbnail struct {
@@ -31,7 +22,7 @@ type mediaThumbnail struct {
type mediaDescription struct { type mediaDescription struct {
Type string `xml:"type,attr"` Type string `xml:"type,attr"`
Text string `xml:",chardata"` Description string `xml:",chardata"`
} }
func (m *media) firstMediaThumbnail() string { func (m *media) firstMediaThumbnail() string {
@@ -53,59 +44,12 @@ func (m *media) firstMediaThumbnail() string {
func (m *media) firstMediaDescription() string { func (m *media) firstMediaDescription() string {
for _, d := range m.MediaDescriptions { for _, d := range m.MediaDescriptions {
return plain2html(d.Text) return plain2html(d.Description)
} }
for _, g := range m.MediaGroups { for _, g := range m.MediaGroups {
for _, d := range g.MediaDescriptions { for _, d := range g.MediaDescriptions {
return plain2html(d.Text) return plain2html(d.Description)
} }
} }
return "" return ""
} }
func (m *media) mediaLinks() []MediaLink {
links := make([]MediaLink, 0)
for _, thumbnail := range m.MediaThumbnails {
links = append(links, MediaLink{URL: thumbnail.URL, Type: "image"})
}
for _, group := range m.MediaGroups {
for _, thumbnail := range group.MediaThumbnails {
links = append(links, MediaLink{
URL: thumbnail.URL,
Type: "image",
})
}
}
for _, content := range m.MediaContents {
if content.MediaURL != "" {
url := content.MediaURL
description := content.MediaDescription.Text
if strings.HasPrefix(content.MediaType, "image/") {
links = append(links, MediaLink{URL: url, Type: "image", Description: description})
} else if strings.HasPrefix(content.MediaType, "audio/") {
links = append(links, MediaLink{URL: url, Type: "audio", Description: description})
} else if strings.HasPrefix(content.MediaType, "video/") {
links = append(links, MediaLink{URL: url, Type: "video", Description: description})
} else if content.MediaMedium == "image" || content.MediaMedium == "audio" || content.MediaMedium == "video" {
links = append(links, MediaLink{URL: url, Type: content.MediaMedium, Description: description})
} else {
if len(content.MediaThumbnails) > 0 {
links = append(links, MediaLink{
URL: content.MediaThumbnails[0].URL,
Type: "image",
})
}
}
}
for _, thumbnail := range content.MediaThumbnails {
links = append(links, MediaLink{
URL: thumbnail.URL,
Type: "image",
})
}
}
if len(links) == 0 {
return nil
}
return links
}

View File

@@ -15,11 +15,6 @@ type Item struct {
Title string Title string
Content string Content string
MediaLinks []MediaLink ImageURL string
} AudioURL string
type MediaLink struct {
URL string
Type string
Description string
} }

View File

@@ -74,14 +74,14 @@ func ParseRSS(r io.Reader) (*Feed, error) {
SiteURL: srcfeed.Link, SiteURL: srcfeed.Link,
} }
for _, srcitem := range srcfeed.Items { for _, srcitem := range srcfeed.Items {
mediaLinks := srcitem.mediaLinks() podcastURL := ""
for _, e := range srcitem.Enclosures { for _, e := range srcitem.Enclosures {
if strings.HasPrefix(e.Type, "audio/") { if strings.HasPrefix(e.Type, "audio/") {
podcastURL := e.URL podcastURL = e.URL
if srcitem.OrigEnclosureLink != "" && strings.Contains(podcastURL, path.Base(srcitem.OrigEnclosureLink)) { if srcitem.OrigEnclosureLink != "" && strings.Contains(podcastURL, path.Base(srcitem.OrigEnclosureLink)) {
podcastURL = srcitem.OrigEnclosureLink podcastURL = srcitem.OrigEnclosureLink
} }
mediaLinks = append(mediaLinks, MediaLink{URL: podcastURL, Type: "audio"})
break break
} }
} }
@@ -96,8 +96,9 @@ func ParseRSS(r io.Reader) (*Feed, error) {
Date: dateParse(firstNonEmpty(srcitem.DublinCoreDate, srcitem.PubDate)), Date: dateParse(firstNonEmpty(srcitem.DublinCoreDate, srcitem.PubDate)),
URL: firstNonEmpty(srcitem.OrigLink, srcitem.Link, permalink), URL: firstNonEmpty(srcitem.OrigLink, srcitem.Link, permalink),
Title: srcitem.Title, Title: srcitem.Title,
Content: firstNonEmpty(srcitem.ContentEncoded, srcitem.Description, srcitem.firstMediaDescription()), Content: firstNonEmpty(srcitem.ContentEncoded, srcitem.Description),
MediaLinks: mediaLinks, AudioURL: podcastURL,
ImageURL: srcitem.firstMediaThumbnail(),
}) })
} }
return dstfeed, nil return dstfeed, nil

View File

@@ -75,15 +75,9 @@ func TestRSSMediaContentThumbnail(t *testing.T) {
</channel> </channel>
</rss> </rss>
`)) `))
if len(feed.Items[0].MediaLinks) != 1 { have := feed.Items[0].ImageURL
t.Fatalf("Expected 1 media link, got %#v", feed.Items[0].MediaLinks) want := "https://i.vimeocdn.com/video/1092705247_960.jpg"
} if have != want {
have := feed.Items[0].MediaLinks[0]
want := MediaLink{
URL: "https://i.vimeocdn.com/video/1092705247_960.jpg",
Type: "image",
}
if !reflect.DeepEqual(want, have) {
t.Logf("want: %#v", want) t.Logf("want: %#v", want)
t.Logf("have: %#v", have) t.Logf("have: %#v", have)
t.FailNow() t.FailNow()
@@ -133,15 +127,9 @@ func TestRSSPodcast(t *testing.T) {
</channel> </channel>
</rss> </rss>
`)) `))
if len(feed.Items[0].MediaLinks) != 1 { have := feed.Items[0].AudioURL
t.Fatal("Invalid media links") want := "http://example.com/audio.ext"
} if want != have {
have := feed.Items[0].MediaLinks[0]
want := MediaLink{
URL: "http://example.com/audio.ext",
Type: "audio",
}
if !reflect.DeepEqual(want, have) {
t.Logf("want: %#v", want) t.Logf("want: %#v", want)
t.Logf("have: %#v", have) t.Logf("have: %#v", have)
t.FailNow() t.FailNow()
@@ -159,15 +147,9 @@ func TestRSSOpusPodcast(t *testing.T) {
</channel> </channel>
</rss> </rss>
`)) `))
if len(feed.Items[0].MediaLinks) != 1 { have := feed.Items[0].AudioURL
t.Fatal("Invalid media links") want := "http://example.com/audio.ext"
} if want != have {
have := feed.Items[0].MediaLinks[0]
want := MediaLink{
URL: "http://example.com/audio.ext",
Type: "audio",
}
if !reflect.DeepEqual(want, have) {
t.Logf("want: %#v", want) t.Logf("want: %#v", want)
t.Logf("have: %#v", have) t.Logf("have: %#v", have)
t.FailNow() t.FailNow()
@@ -194,9 +176,8 @@ func TestRSSPodcastDuplicated(t *testing.T) {
if want != have { if want != have {
t.Fatalf("content doesn't match\nwant: %#v\nhave: %#v\n", want, have) t.Fatalf("content doesn't match\nwant: %#v\nhave: %#v\n", want, have)
} }
if feed.Items[0].AudioURL != "" {
if len(feed.Items[0].MediaLinks) != 0 { t.Fatal("item.audio_url must be unset if present in the content")
t.Fatal("item media must be excluded if present in the content")
} }
} }
@@ -242,47 +223,8 @@ func TestRSSIsPermalink(t *testing.T) {
}, },
} }
for i := 0; i < len(want); i++ { for i := 0; i < len(want); i++ {
if !reflect.DeepEqual(want, have) { if want[i] != have[i] {
t.Errorf("Failed to handle isPermalink\nwant: %#v\nhave: %#v\n", want[i], have[i]) t.Errorf("Failed to handle isPermalink\nwant: %#v\nhave: %#v\n", want[i], have[i])
} }
} }
} }
func TestRSSMultipleMedia(t *testing.T) {
feed, _ := Parse(strings.NewReader(`
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
<channel>
<item>
<guid isPermaLink="true">http://example.com/posts/1</guid>
<media:content url="https://example.com/path/to/image1.png" type="image/png" fileSize="1000" medium="image">
<media:description type="plain">description 1</media:description>
</media:content>
<media:content url="https://example.com/path/to/image2.png" type="image/png" fileSize="2000" medium="image">
<media:description type="plain">description 2</media:description>
</media:content>
<media:content url="https://example.com/path/to/video1.mp4" type="video/mp4" fileSize="2000" medium="image">
<media:description type="plain">video description</media:description>
</media:content>
</item>
</channel>
</rss>
`))
have := feed.Items
want := []Item{
{
GUID: "http://example.com/posts/1",
URL: "http://example.com/posts/1",
MediaLinks: []MediaLink{
{URL:"https://example.com/path/to/image1.png", Type:"image", Description:"description 1"},
{URL:"https://example.com/path/to/image2.png", Type:"image", Description:"description 2"},
{URL:"https://example.com/path/to/video1.mp4", Type:"video", Description:"video description"},
},
},
}
if !reflect.DeepEqual(want, have) {
t.Logf("want: %#v", want)
t.Logf("have: %#v", have)
t.Fatal("invalid rss")
}
}

View File

@@ -11,7 +11,6 @@ import (
func Start(s *server.Server) { func Start(s *server.Server) {
systrayOnReady := func() { systrayOnReady := func() {
systray.SetIcon(Icon) systray.SetIcon(Icon)
systray.SetTooltip("yarr")
menuOpen := systray.AddMenuItem("Open", "") menuOpen := systray.AddMenuItem("Open", "")
systray.AddSeparator() systray.AddSeparator()

View File

@@ -6,7 +6,6 @@ import (
"github.com/nkanaev/yarr/src/assets" "github.com/nkanaev/yarr/src/assets"
"github.com/nkanaev/yarr/src/server/router" "github.com/nkanaev/yarr/src/server/router"
"github.com/nkanaev/yarr/src/storage"
) )
type Middleware struct { type Middleware struct {
@@ -14,7 +13,6 @@ type Middleware struct {
Password string Password string
BasePath string BasePath string
Public []string Public []string
DB *storage.Storage
} }
func unsafeMethod(method string) bool { func unsafeMethod(method string) bool {
@@ -48,15 +46,12 @@ func (m *Middleware) Handler(c *router.Context) {
c.Redirect(rootUrl) c.Redirect(rootUrl)
return return
} else { } else {
c.HTML(http.StatusOK, assets.Template("login.html"), map[string]interface{}{ c.HTML(http.StatusOK, assets.Template("login.html"), map[string]string{
"username": username, "username": username,
"error": "Invalid username/password", "error": "Invalid username/password",
"settings": m.DB.GetSettings(),
}) })
return return
} }
} }
c.HTML(http.StatusOK, assets.Template("login.html"), map[string]interface{}{ c.HTML(http.StatusOK, assets.Template("login.html"), nil)
"settings": m.DB.GetSettings(),
})
} }

View File

@@ -54,7 +54,7 @@ type FeverFavicon struct {
} }
func writeFeverJSON(c *router.Context, data map[string]interface{}, lastRefreshed int64) { func writeFeverJSON(c *router.Context, data map[string]interface{}, lastRefreshed int64) {
data["api_version"] = 3 data["api_version"] = 1
data["auth"] = 1 data["auth"] = 1
data["last_refreshed_on_time"] = lastRefreshed data["last_refreshed_on_time"] = lastRefreshed
c.JSON(http.StatusOK, data) c.JSON(http.StatusOK, data)
@@ -77,10 +77,9 @@ func getLastRefreshedOnTime(httpStates map[int64]storage.HTTPState) int64 {
func (s *Server) feverAuth(c *router.Context) bool { func (s *Server) feverAuth(c *router.Context) bool {
if s.Username != "" && s.Password != "" { if s.Username != "" && s.Password != "" {
apiKey := c.Req.FormValue("api_key") apiKey := c.Req.FormValue("api_key")
apiKey = strings.ToLower(apiKey)
md5HashValue := md5.Sum([]byte(fmt.Sprintf("%s:%s", s.Username, s.Password))) md5HashValue := md5.Sum([]byte(fmt.Sprintf("%s:%s", s.Username, s.Password)))
hexMD5HashValue := fmt.Sprintf("%x", md5HashValue[:]) hexMD5HashValue := fmt.Sprintf("%x", md5HashValue[:])
if !auth.StringsEqual(apiKey, hexMD5HashValue) { if auth.StringsEqual(apiKey, hexMD5HashValue) {
return false return false
} }
} }
@@ -98,7 +97,7 @@ func (s *Server) handleFever(c *router.Context) {
c.Req.ParseForm() c.Req.ParseForm()
if !s.feverAuth(c) { if !s.feverAuth(c) {
c.JSON(http.StatusOK, map[string]interface{}{ c.JSON(http.StatusOK, map[string]interface{}{
"api_version": 3, "api_version": 1,
"auth": 0, "auth": 0,
"last_refreshed_on_time": 0, "last_refreshed_on_time": 0,
}) })
@@ -124,7 +123,7 @@ func (s *Server) handleFever(c *router.Context) {
s.feverMarkHandler(c) s.feverMarkHandler(c)
default: default:
c.JSON(http.StatusOK, map[string]interface{}{ c.JSON(http.StatusOK, map[string]interface{}{
"api_version": 3, "api_version": 1,
"auth": 1, "auth": 1,
"last_refreshed_on_time": getLastRefreshedOnTime(s.db.ListHTTPStates()), "last_refreshed_on_time": getLastRefreshedOnTime(s.db.ListHTTPStates()),
}) })
@@ -278,11 +277,8 @@ func (s *Server) feverItemsHandler(c *router.Context) {
} }
} }
totalItems := s.db.CountItems(storage.ItemFilter{})
writeFeverJSON(c, map[string]interface{}{ writeFeverJSON(c, map[string]interface{}{
"items": feverItems, "items": feverItems,
"total_items": totalItems,
}, getLastRefreshedOnTime(s.db.ListHTTPStates())) }, getLastRefreshedOnTime(s.db.ListHTTPStates()))
} }
@@ -386,8 +382,4 @@ func (s *Server) feverMarkHandler(c *router.Context) {
c.Out.WriteHeader(http.StatusBadRequest) c.Out.WriteHeader(http.StatusBadRequest)
return return
} }
c.JSON(http.StatusOK, map[string]interface{}{
"api_version": 3,
"auth": 1,
})
} }

View File

@@ -12,7 +12,6 @@ import (
"strings" "strings"
"github.com/nkanaev/yarr/src/assets" "github.com/nkanaev/yarr/src/assets"
"github.com/nkanaev/yarr/src/content/htmlutil"
"github.com/nkanaev/yarr/src/content/readability" "github.com/nkanaev/yarr/src/content/readability"
"github.com/nkanaev/yarr/src/content/sanitizer" "github.com/nkanaev/yarr/src/content/sanitizer"
"github.com/nkanaev/yarr/src/content/silo" "github.com/nkanaev/yarr/src/content/silo"
@@ -35,7 +34,6 @@ func (s *Server) handler() http.Handler {
Username: s.Username, Username: s.Username,
Password: s.Password, Password: s.Password,
Public: []string{"/static", "/fever"}, Public: []string{"/static", "/fever"},
DB: s.db,
} }
r.Use(a.Handler) r.Use(a.Handler)
} }
@@ -87,7 +85,7 @@ func (s *Server) handleManifest(c *router.Context) {
"short_name": "yarr", "short_name": "yarr",
"description": "yet another rss reader", "description": "yet another rss reader",
"display": "standalone", "display": "standalone",
"start_url": "/" + strings.TrimPrefix(s.BasePath, "/"), "start_url": s.BasePath,
"icons": []map[string]interface{}{ "icons": []map[string]interface{}{
{ {
"src": s.BasePath + "/static/graphicarts/favicon.png", "src": s.BasePath + "/static/graphicarts/favicon.png",
@@ -294,11 +292,6 @@ func (s *Server) handleFeed(c *router.Context) {
s.db.UpdateFeedFolder(id, &folderId) s.db.UpdateFeedFolder(id, &folderId)
} }
} }
if link, ok := body["feed_link"]; ok {
if reflect.TypeOf(link).Kind() == reflect.String {
s.db.UpdateFeedLink(id, link.(string))
}
}
c.Out.WriteHeader(http.StatusOK) c.Out.WriteHeader(http.StatusOK)
} else if c.Req.Method == "DELETE" { } else if c.Req.Method == "DELETE" {
s.db.DeleteFeed(id) s.db.DeleteFeed(id)
@@ -320,18 +313,7 @@ func (s *Server) handleItem(c *router.Context) {
c.Out.WriteHeader(http.StatusBadRequest) c.Out.WriteHeader(http.StatusBadRequest)
return return
} }
// runtime fix for relative links
if !htmlutil.IsAPossibleLink(item.Link) {
if feed := s.db.GetFeed(item.FeedId); feed != nil {
item.Link = htmlutil.AbsoluteUrl(item.Link, feed.Link)
}
}
item.Content = sanitizer.Sanitize(item.Link, item.Content) item.Content = sanitizer.Sanitize(item.Link, item.Content)
for i, link := range item.MediaLinks {
item.MediaLinks[i].Description = sanitizer.Sanitize(item.Link, link.Description)
}
c.JSON(http.StatusOK, item) c.JSON(http.StatusOK, item)
} else if c.Req.Method == "PUT" { } else if c.Req.Method == "PUT" {
@@ -374,19 +356,12 @@ func (s *Server) handleItemList(c *router.Context) {
} }
newestFirst := query.Get("oldest_first") != "true" newestFirst := query.Get("oldest_first") != "true"
items := s.db.ListItems(filter, perPage+1, newestFirst, true) items := s.db.ListItems(filter, perPage+1, newestFirst, false)
hasMore := false hasMore := false
if len(items) == perPage+1 { if len(items) == perPage+1 {
hasMore = true hasMore = true
items = items[:perPage] items = items[:perPage]
} }
for i, item := range items {
if item.Title == "" {
text := htmlutil.ExtractText(item.Content)
items[i].Title = htmlutil.TruncateText(text, 140)
}
}
c.JSON(http.StatusOK, map[string]interface{}{ c.JSON(http.StatusOK, map[string]interface{}{
"list": items, "list": items,
"has_more": hasMore, "has_more": hasMore,

View File

@@ -20,19 +20,18 @@ func (s *Storage) CreateFeed(title, description, link, feedLink string, folderId
if title == "" { if title == "" {
title = feedLink title = feedLink
} }
row := s.db.QueryRow(` result, err := s.db.Exec(`
insert into feeds (title, description, link, feed_link, folder_id) insert into feeds (title, description, link, feed_link, folder_id)
values (?, ?, ?, ?, ?) values (?, ?, ?, ?, ?)
on conflict (feed_link) do update set folder_id = ? on conflict (feed_link) do update set folder_id=?`,
returning id`,
title, description, link, feedLink, folderId, title, description, link, feedLink, folderId,
folderId, folderId,
) )
var id int64
err := row.Scan(&id)
if err != nil { if err != nil {
log.Print(err) return nil
}
id, idErr := result.LastInsertId()
if idErr != nil {
return nil return nil
} }
return &Feed{ return &Feed{
@@ -71,11 +70,6 @@ func (s *Storage) UpdateFeedFolder(feedId int64, newFolderId *int64) bool {
return err == nil return err == nil
} }
func (s *Storage) UpdateFeedLink(feedId int64, newLink string) bool {
_, err := s.db.Exec(`update feeds set feed_link = ? where id = ?`, newLink, feedId)
return err == nil
}
func (s *Storage) UpdateFeedIcon(feedId int64, icon *[]byte) bool { func (s *Storage) UpdateFeedIcon(feedId int64, icon *[]byte) bool {
_, err := s.db.Exec(`update feeds set icon = ? where id = ?`, icon, feedId) _, err := s.db.Exec(`update feeds set icon = ? where id = ?`, icon, feedId)
return err == nil return err == nil

View File

@@ -17,23 +17,6 @@ func TestCreateFeed(t *testing.T) {
} }
} }
func TestCreateFeedSameLink(t *testing.T) {
db := testDB()
feed1 := db.CreateFeed("title", "", "", "http://example1.com/feed.xml", nil)
if feed1 == nil || feed1.Id == 0 {
t.Fatal("expected feed")
}
for i := 0; i < 10; i++ {
db.CreateFeed("title", "", "", "http://example2.com/feed.xml", nil)
}
feed2 := db.CreateFeed("title", "", "http://example.com", "http://example1.com/feed.xml", nil)
if feed1.Id != feed2.Id {
t.Fatalf("expected the same feed.\nwant: %#v\nhave: %#v", feed1, feed2)
}
}
func TestReadFeed(t *testing.T) { func TestReadFeed(t *testing.T) {
db := testDB() db := testDB()
if db.GetFeed(100500) != nil { if db.GetFeed(100500) != nil {

View File

@@ -1,6 +1,7 @@
package storage package storage
import ( import (
"fmt"
"log" "log"
) )
@@ -12,21 +13,35 @@ type Folder struct {
func (s *Storage) CreateFolder(title string) *Folder { func (s *Storage) CreateFolder(title string) *Folder {
expanded := true expanded := true
row := s.db.QueryRow(` result, err := s.db.Exec(`
insert into folders (title, is_expanded) values (?, ?) insert into folders (title, is_expanded) values (?, ?)
on conflict (title) do update set title = ? on conflict (title) do nothing`,
returning id`,
title, expanded, title, expanded,
// provide title again so that we can extract row id
title,
) )
var id int64 if err != nil {
err := row.Scan(&id) fmt.Println(err)
return nil
}
var id int64
numrows, err := result.RowsAffected()
if err != nil { if err != nil {
log.Print(err) log.Print(err)
return nil return nil
} }
if numrows == 1 {
id, err = result.LastInsertId()
if err != nil {
log.Print(err)
return nil
}
} else {
err = s.db.QueryRow(`select id, is_expanded from folders where title=?`, title).Scan(&id, &expanded)
if err != nil {
log.Print(err)
return nil
}
}
return &Folder{Id: id, Title: title, IsExpanded: expanded} return &Folder{Id: id, Title: title, IsExpanded: expanded}
} }

View File

@@ -1,11 +1,9 @@
package storage package storage
import ( import (
"database/sql/driver"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log" "log"
"sort"
"strings" "strings"
"time" "time"
@@ -45,25 +43,6 @@ func (s *ItemStatus) UnmarshalJSON(b []byte) error {
return nil return nil
} }
type MediaLink struct {
URL string `json:"url"`
Type string `json:"type"`
Description string `json:"description,omitempty"`
}
type MediaLinks []MediaLink
func (m *MediaLinks) Scan(src any) error {
if data, ok := src.([]byte); ok {
return json.Unmarshal(data, m)
}
return nil
}
func (m MediaLinks) Value() (driver.Value, error) {
return json.Marshal(m)
}
type Item struct { type Item struct {
Id int64 `json:"id"` Id int64 `json:"id"`
GUID string `json:"guid"` GUID string `json:"guid"`
@@ -73,7 +52,8 @@ type Item struct {
Content string `json:"content,omitempty"` Content string `json:"content,omitempty"`
Date time.Time `json:"date"` Date time.Time `json:"date"`
Status ItemStatus `json:"status"` Status ItemStatus `json:"status"`
MediaLinks MediaLinks `json:"media_links"` ImageURL *string `json:"image"`
AudioURL *string `json:"podcast_url"`
} }
type ItemFilter struct { type ItemFilter struct {
@@ -95,24 +75,6 @@ type MarkFilter struct {
Before *time.Time Before *time.Time
} }
type ItemList []Item
func (list ItemList) Len() int {
return len(list)
}
func (list ItemList) SortKey(i int) string {
return list[i].Date.Format(time.RFC3339) + "::" + list[i].GUID
}
func (list ItemList) Less(i, j int) bool {
return list.SortKey(i) < list.SortKey(j)
}
func (list ItemList) Swap(i, j int) {
list[i], list[j] = list[j], list[i]
}
func (s *Storage) CreateItems(items []Item) bool { func (s *Storage) CreateItems(items []Item) bool {
tx, err := s.db.Begin() tx, err := s.db.Begin()
if err != nil { if err != nil {
@@ -122,24 +84,17 @@ func (s *Storage) CreateItems(items []Item) bool {
now := time.Now().UTC() now := time.Now().UTC()
itemsSorted := ItemList(items) for _, item := range items {
sort.Sort(itemsSorted)
for _, item := range itemsSorted {
_, err = tx.Exec(` _, err = tx.Exec(`
insert into items ( insert into items (
guid, feed_id, title, link, date, guid, feed_id, title, link, date,
content, media_links, content, image, podcast_url,
date_arrived, status date_arrived, status
) )
values ( values (?, ?, ?, ?, strftime('%Y-%m-%d %H:%M:%f', ?), ?, ?, ?, ?, ?)
?, ?, ?, ?, strftime('%Y-%m-%d %H:%M:%f', ?),
?, ?,
?, ?
)
on conflict (feed_id, guid) do nothing`, on conflict (feed_id, guid) do nothing`,
item.GUID, item.FeedId, item.Title, item.Link, item.Date, item.GUID, item.FeedId, item.Title, item.Link, item.Date,
item.Content, item.MediaLinks, item.Content, item.ImageURL, item.AudioURL,
now, UNREAD, now, UNREAD,
) )
if err != nil { if err != nil {
@@ -222,23 +177,6 @@ func listQueryPredicate(filter ItemFilter, newestFirst bool) (string, []interfac
return predicate, args return predicate, args
} }
func (s *Storage) CountItems(filter ItemFilter) int {
predicate, args := listQueryPredicate(filter, false)
var count int
query := fmt.Sprintf(`
select count(*)
from items
where %s
`, predicate)
err := s.db.QueryRow(query, args...).Scan(&count)
if err != nil {
log.Print(err)
return 0
}
return count
}
func (s *Storage) ListItems(filter ItemFilter, limit int, newestFirst bool, withContent bool) []Item { func (s *Storage) ListItems(filter ItemFilter, limit int, newestFirst bool, withContent bool) []Item {
predicate, args := listQueryPredicate(filter, newestFirst) predicate, args := listQueryPredicate(filter, newestFirst)
result := make([]Item, 0, 0) result := make([]Item, 0, 0)
@@ -247,14 +185,11 @@ func (s *Storage) ListItems(filter ItemFilter, limit int, newestFirst bool, with
if !newestFirst { if !newestFirst {
order = "date asc, id asc" order = "date asc, id asc"
} }
if filter.IDs != nil || filter.SinceID != nil { if filter.IDs != nil || filter.SinceID != nil || filter.MaxID != nil {
order = "i.id asc" order = "i.id asc"
} }
if filter.MaxID != nil {
order = "i.id desc"
}
selectCols := "i.id, i.guid, i.feed_id, i.title, i.link, i.date, i.status, i.media_links" selectCols := "i.id, i.guid, i.feed_id, i.title, i.link, i.date, i.status, i.image, i.podcast_url"
if withContent { if withContent {
selectCols += ", i.content" selectCols += ", i.content"
} else { } else {
@@ -277,7 +212,7 @@ func (s *Storage) ListItems(filter ItemFilter, limit int, newestFirst bool, with
err = rows.Scan( err = rows.Scan(
&x.Id, &x.GUID, &x.FeedId, &x.Id, &x.GUID, &x.FeedId,
&x.Title, &x.Link, &x.Date, &x.Title, &x.Link, &x.Date,
&x.Status, &x.MediaLinks, &x.Content, &x.Status, &x.ImageURL, &x.AudioURL, &x.Content,
) )
if err != nil { if err != nil {
log.Print(err) log.Print(err)
@@ -293,12 +228,12 @@ func (s *Storage) GetItem(id int64) *Item {
err := s.db.QueryRow(` err := s.db.QueryRow(`
select select
i.id, i.guid, i.feed_id, i.title, i.link, i.content, i.id, i.guid, i.feed_id, i.title, i.link, i.content,
i.date, i.status, i.media_links i.date, i.status, i.image, i.podcast_url
from items i from items i
where i.id = ? where i.id = ?
`, id).Scan( `, id).Scan(
&i.Id, &i.GUID, &i.FeedId, &i.Title, &i.Link, &i.Content, &i.Id, &i.GUID, &i.FeedId, &i.Title, &i.Link, &i.Content,
&i.Date, &i.Status, &i.MediaLinks, &i.Date, &i.Status, &i.ImageURL, &i.AudioURL,
) )
if err != nil { if err != nil {
log.Print(err) log.Print(err)

View File

@@ -77,12 +77,12 @@ func getItem(db *Storage, guid string) *Item {
err := db.db.QueryRow(` err := db.db.QueryRow(`
select select
i.id, i.guid, i.feed_id, i.title, i.link, i.content, i.id, i.guid, i.feed_id, i.title, i.link, i.content,
i.date, i.status, i.media_links i.date, i.status, i.image, i.podcast_url
from items i from items i
where i.guid = ? where i.guid = ?
`, guid).Scan( `, guid).Scan(
&i.Id, &i.GUID, &i.FeedId, &i.Title, &i.Link, &i.Content, &i.Id, &i.GUID, &i.FeedId, &i.Title, &i.Link, &i.Content,
&i.Date, &i.Status, &i.MediaLinks, &i.Date, &i.Status, &i.ImageURL, &i.AudioURL,
) )
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View File

@@ -16,17 +16,13 @@ var migrations = []func(*sql.Tx) error{
m06_fill_missing_dates, m06_fill_missing_dates,
m07_add_feed_size, m07_add_feed_size,
m08_normalize_datetime, m08_normalize_datetime,
m09_change_item_index,
m10_add_item_medialinks,
} }
var maxVersion = int64(len(migrations)) var maxVersion = int64(len(migrations))
func migrate(db *sql.DB) error { func migrate(db *sql.DB) error {
var version int64 var version int64
if err := db.QueryRow("pragma user_version").Scan(&version); err != nil { db.QueryRow("pragma user_version").Scan(&version)
return err
}
if version >= maxVersion { if version >= maxVersion {
return nil return nil
@@ -298,37 +294,3 @@ func m08_normalize_datetime(tx *sql.Tx) error {
_, err = tx.Exec(`update items set date = strftime('%Y-%m-%d %H:%M:%f', date);`) _, err = tx.Exec(`update items set date = strftime('%Y-%m-%d %H:%M:%f', date);`)
return err return err
} }
func m09_change_item_index(tx *sql.Tx) error {
sql := `
drop index if exists idx_item_status;
create index if not exists idx_item__date_id_status on items(date,id,status);
`
_, err := tx.Exec(sql)
return err
}
func m10_add_item_medialinks(tx *sql.Tx) error {
sql := `
alter table items add column media_links blob;
update items set media_links =
iif(
coalesce(image, '') != '' and coalesce(podcast_url, '') != '',
json_array(json_object('type', 'image', 'url', image), json_object('type', 'audio', 'url', podcast_url)),
iif(
coalesce(image, '') != '',
json_array(json_object('type', 'image', 'url', image)),
iif(
coalesce(podcast_url, '') != '',
json_array(json_object('type', 'audio', 'url', podcast_url)),
null
)
)
);
alter table items drop column image;
alter table items drop column podcast_url;
`
_, err := tx.Exec(sql)
return err
}

View File

@@ -2,9 +2,6 @@ package storage
import ( import (
"database/sql" "database/sql"
"log"
"strings"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
@@ -13,17 +10,14 @@ type Storage struct {
} }
func New(path string) (*Storage, error) { func New(path string) (*Storage, error) {
if pos := strings.IndexRune(path, '?'); pos == -1 {
params := "_journal=WAL&_sync=NORMAL&_busy_timeout=5000&cache=shared"
log.Printf("opening db with params: %s", params)
path = path + "?" + params
}
db, err := sql.Open("sqlite3", path) db, err := sql.Open("sqlite3", path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: https://foxcpp.dev/articles/the-right-way-to-use-go-sqlite3
db.SetMaxOpenConns(1)
if err = migrate(db); err != nil { if err = migrate(db); err != nil {
return nil, err return nil, err
} }

View File

@@ -1,4 +1,3 @@
//go:build darwin || windows
// +build darwin windows // +build darwin windows
/* /*

View File

@@ -1,4 +1,3 @@
//go:build never
// +build never // +build never
package systray package systray

View File

@@ -1,4 +1,3 @@
//go:build darwin
// +build darwin // +build darwin
package systray package systray

View File

@@ -1,4 +1,3 @@
//go:build windows
// +build windows // +build windows
package systray package systray

View File

@@ -1,4 +1,3 @@
//go:build windows
// +build windows // +build windows
package systray package systray

View File

@@ -32,10 +32,6 @@ func (c *Client) getConditional(url, lastModified, etag string) (*http.Response,
var client *Client var client *Client
func SetVersion(num string) {
client.userAgent = "Yarr/" + num
}
func init() { func init() {
transport := &http.Transport{ transport := &http.Transport{
Proxy: http.ProxyFromEnvironment, Proxy: http.ProxyFromEnvironment,

View File

@@ -143,9 +143,13 @@ func ConvertItems(items []parser.Item, feed storage.Feed) []storage.Item {
result := make([]storage.Item, len(items)) result := make([]storage.Item, len(items))
for i, item := range items { for i, item := range items {
item := item item := item
mediaLinks := make(storage.MediaLinks, 0) var audioURL *string = nil
for _, link := range item.MediaLinks { if item.AudioURL != "" {
mediaLinks = append(mediaLinks, storage.MediaLink(link)) audioURL = &item.AudioURL
}
var imageURL *string = nil
if item.ImageURL != "" {
imageURL = &item.ImageURL
} }
result[i] = storage.Item{ result[i] = storage.Item{
GUID: item.GUID, GUID: item.GUID,
@@ -155,7 +159,8 @@ func ConvertItems(items []parser.Item, feed storage.Feed) []storage.Item {
Content: item.Content, Content: item.Content,
Date: item.Date, Date: item.Date,
Status: storage.UNREAD, Status: storage.UNREAD,
MediaLinks: mediaLinks, ImageURL: imageURL,
AudioURL: audioURL,
} }
} }
return result return result

4
vendor/golang.org/x/net/LICENSE generated vendored
View File

@@ -1,4 +1,4 @@
Copyright 2009 The Go Authors. Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the in the documentation and/or other materials provided with the
distribution. distribution.
* Neither the name of Google LLC nor the names of its * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from contributors may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.

27
vendor/golang.org/x/net/html/doc.go generated vendored
View File

@@ -78,11 +78,16 @@ example, to process each anchor node in depth-first order:
if err != nil { if err != nil {
// ... // ...
} }
for n := range doc.Descendants() { var f func(*html.Node)
f = func(n *html.Node) {
if n.Type == html.ElementNode && n.Data == "a" { if n.Type == html.ElementNode && n.Data == "a" {
// Do something with n... // Do something with n...
} }
for c := n.FirstChild; c != nil; c = c.NextSibling {
f(c)
} }
}
f(doc)
The relevant specifications include: The relevant specifications include:
https://html.spec.whatwg.org/multipage/syntax.html and https://html.spec.whatwg.org/multipage/syntax.html and
@@ -94,20 +99,14 @@ Care should be taken when parsing and interpreting HTML, whether full documents
or fragments, within the framework of the HTML specification, especially with or fragments, within the framework of the HTML specification, especially with
regard to untrusted inputs. regard to untrusted inputs.
This package provides both a tokenizer and a parser, which implement the This package provides both a tokenizer and a parser. Only the parser constructs
tokenization, and tokenization and tree construction stages of the WHATWG HTML a DOM according to the HTML specification, resolving malformed and misplaced
parsing specification respectively. While the tokenizer parses and normalizes tags where appropriate. The tokenizer simply tokenizes the HTML presented to it,
individual HTML tokens, only the parser constructs the DOM tree from the and as such does not resolve issues that may exist in the processed HTML,
tokenized HTML, as described in the tree construction stage of the producing a literal interpretation of the input.
specification, dynamically modifying or extending the document's DOM tree.
If your use case requires semantically well-formed HTML documents, as defined by If your use case requires semantically well-formed HTML, as defined by the
the WHATWG specification, the parser should be used rather than the tokenizer. WHATWG specifiction, the parser should be used rather than the tokenizer.
In security contexts, if trust decisions are being made using the tokenized or
parsed content, the input must be re-serialized (for instance by using Render or
Token.String) in order for those trust decisions to hold, as the process of
tokenization or parsing may alter the content.
*/ */
package html // import "golang.org/x/net/html" package html // import "golang.org/x/net/html"

View File

@@ -87,7 +87,7 @@ func parseDoctype(s string) (n *Node, quirks bool) {
} }
} }
if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" && if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" &&
strings.EqualFold(lastAttr.Val, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") { strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" {
quirks = true quirks = true
} }
} }

View File

@@ -40,7 +40,8 @@ func htmlIntegrationPoint(n *Node) bool {
if n.Data == "annotation-xml" { if n.Data == "annotation-xml" {
for _, a := range n.Attr { for _, a := range n.Attr {
if a.Key == "encoding" { if a.Key == "encoding" {
if strings.EqualFold(a.Val, "text/html") || strings.EqualFold(a.Val, "application/xhtml+xml") { val := strings.ToLower(a.Val)
if val == "text/html" || val == "application/xhtml+xml" {
return true return true
} }
} }

56
vendor/golang.org/x/net/html/iter.go generated vendored
View File

@@ -1,56 +0,0 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.23
package html
import "iter"
// Ancestors returns an iterator over the ancestors of n, starting with n.Parent.
//
// Mutating a Node or its parents while iterating may have unexpected results.
func (n *Node) Ancestors() iter.Seq[*Node] {
_ = n.Parent // eager nil check
return func(yield func(*Node) bool) {
for p := n.Parent; p != nil && yield(p); p = p.Parent {
}
}
}
// ChildNodes returns an iterator over the immediate children of n,
// starting with n.FirstChild.
//
// Mutating a Node or its children while iterating may have unexpected results.
func (n *Node) ChildNodes() iter.Seq[*Node] {
_ = n.FirstChild // eager nil check
return func(yield func(*Node) bool) {
for c := n.FirstChild; c != nil && yield(c); c = c.NextSibling {
}
}
}
// Descendants returns an iterator over all nodes recursively beneath
// n, excluding n itself. Nodes are visited in depth-first preorder.
//
// Mutating a Node or its descendants while iterating may have unexpected results.
func (n *Node) Descendants() iter.Seq[*Node] {
_ = n.FirstChild // eager nil check
return func(yield func(*Node) bool) {
n.descendants(yield)
}
}
func (n *Node) descendants(yield func(*Node) bool) bool {
for c := range n.ChildNodes() {
if !yield(c) || !c.descendants(yield) {
return false
}
}
return true
}

View File

@@ -38,10 +38,6 @@ var scopeMarker = Node{Type: scopeMarkerNode}
// that it looks like "a<b" rather than "a&lt;b". For element nodes, DataAtom // that it looks like "a<b" rather than "a&lt;b". For element nodes, DataAtom
// is the atom for Data, or zero if Data is not a known tag name. // is the atom for Data, or zero if Data is not a known tag name.
// //
// Node trees may be navigated using the link fields (Parent,
// FirstChild, and so on) or a range loop over iterators such as
// [Node.Descendants].
//
// An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace. // An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace.
// Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and // Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and
// "svg" is short for "http://www.w3.org/2000/svg". // "svg" is short for "http://www.w3.org/2000/svg".

View File

@@ -840,10 +840,6 @@ func afterHeadIM(p *parser) bool {
p.parseImpliedToken(StartTagToken, a.Body, a.Body.String()) p.parseImpliedToken(StartTagToken, a.Body, a.Body.String())
p.framesetOK = true p.framesetOK = true
if p.tok.Type == ErrorToken {
// Stop parsing.
return true
}
return false return false
} }
@@ -1035,7 +1031,7 @@ func inBodyIM(p *parser) bool {
if p.tok.DataAtom == a.Input { if p.tok.DataAtom == a.Input {
for _, t := range p.tok.Attr { for _, t := range p.tok.Attr {
if t.Key == "type" { if t.Key == "type" {
if strings.EqualFold(t.Val, "hidden") { if strings.ToLower(t.Val) == "hidden" {
// Skip setting framesetOK = false // Skip setting framesetOK = false
return true return true
} }
@@ -1463,7 +1459,7 @@ func inTableIM(p *parser) bool {
return inHeadIM(p) return inHeadIM(p)
case a.Input: case a.Input:
for _, t := range p.tok.Attr { for _, t := range p.tok.Attr {
if t.Key == "type" && strings.EqualFold(t.Val, "hidden") { if t.Key == "type" && strings.ToLower(t.Val) == "hidden" {
p.addElement() p.addElement()
p.oe.pop() p.oe.pop()
return true return true

View File

@@ -194,8 +194,9 @@ func render1(w writer, n *Node) error {
} }
} }
// Render any child nodes // Render any child nodes.
if childTextNodesAreLiteral(n) { switch n.Data {
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
for c := n.FirstChild; c != nil; c = c.NextSibling { for c := n.FirstChild; c != nil; c = c.NextSibling {
if c.Type == TextNode { if c.Type == TextNode {
if _, err := w.WriteString(c.Data); err != nil { if _, err := w.WriteString(c.Data); err != nil {
@@ -212,7 +213,7 @@ func render1(w writer, n *Node) error {
// last element in the file, with no closing tag. // last element in the file, with no closing tag.
return plaintextAbort return plaintextAbort
} }
} else { default:
for c := n.FirstChild; c != nil; c = c.NextSibling { for c := n.FirstChild; c != nil; c = c.NextSibling {
if err := render1(w, c); err != nil { if err := render1(w, c); err != nil {
return err return err
@@ -230,27 +231,6 @@ func render1(w writer, n *Node) error {
return w.WriteByte('>') return w.WriteByte('>')
} }
func childTextNodesAreLiteral(n *Node) bool {
// Per WHATWG HTML 13.3, if the parent of the current node is a style,
// script, xmp, iframe, noembed, noframes, or plaintext element, and the
// current node is a text node, append the value of the node's data
// literally. The specification is not explicit about it, but we only
// enforce this if we are in the HTML namespace (i.e. when the namespace is
// "").
// NOTE: we also always include noscript elements, although the
// specification states that they should only be rendered as such if
// scripting is enabled for the node (which is not something we track).
if n.Namespace != "" {
return false
}
switch n.Data {
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
return true
default:
return false
}
}
// writeQuoted writes s to w surrounded by quotes. Normally it will use double // writeQuoted writes s to w surrounded by quotes. Normally it will use double
// quotes, but if s contains a double quote, it will use single quotes. // quotes, but if s contains a double quote, it will use single quotes.
// It is used for writing the identifiers in a doctype declaration. // It is used for writing the identifiers in a doctype declaration.

View File

@@ -910,16 +910,10 @@ func (z *Tokenizer) readTagAttrKey() {
return return
} }
switch c { switch c {
case '=': case ' ', '\n', '\r', '\t', '\f', '/':
if z.pendingAttr[0].start+1 == z.raw.end { z.pendingAttr[0].end = z.raw.end - 1
// WHATWG 13.2.5.32, if we see an equals sign before the attribute name return
// begins, we treat it as a character in the attribute name and continue. case '=', '>':
continue
}
fallthrough
case ' ', '\n', '\r', '\t', '\f', '/', '>':
// WHATWG 13.2.5.33 Attribute name state
// We need to reconsume the char in the after attribute name state to support the / character
z.raw.end-- z.raw.end--
z.pendingAttr[0].end = z.raw.end z.pendingAttr[0].end = z.raw.end
return return
@@ -938,11 +932,6 @@ func (z *Tokenizer) readTagAttrVal() {
if z.err != nil { if z.err != nil {
return return
} }
if c == '/' {
// WHATWG 13.2.5.34 After attribute name state
// U+002F SOLIDUS (/) - Switch to the self-closing start tag state.
return
}
if c != '=' { if c != '=' {
z.raw.end-- z.raw.end--
return return

4
vendor/golang.org/x/sys/LICENSE generated vendored
View File

@@ -1,4 +1,4 @@
Copyright 2009 The Go Authors. Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the in the documentation and/or other materials provided with the
distribution. distribution.
* Neither the name of Google LLC nor the names of its * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from contributors may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.

View File

@@ -0,0 +1,30 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package unsafeheader contains header declarations for the Go runtime's
// slice and string implementations.
//
// This package allows x/sys to use types equivalent to
// reflect.SliceHeader and reflect.StringHeader without introducing
// a dependency on the (relatively heavy) "reflect" package.
package unsafeheader
import (
"unsafe"
)
// Slice is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may change in a later release.
type Slice struct {
Data unsafe.Pointer
Len int
Cap int
}
// String is the runtime representation of a string.
// It cannot be used safely or portably and its representation may change in a later release.
type String struct {
Data unsafe.Pointer
Len int
}

View File

@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build windows //go:build windows && go1.9
// +build windows,go1.9
package windows package windows

View File

@@ -65,7 +65,7 @@ func LoadDLL(name string) (dll *DLL, err error) {
return d, nil return d, nil
} }
// MustLoadDLL is like LoadDLL but panics if load operation fails. // MustLoadDLL is like LoadDLL but panics if load operation failes.
func MustLoadDLL(name string) *DLL { func MustLoadDLL(name string) *DLL {
d, e := LoadDLL(name) d, e := LoadDLL(name)
if e != nil { if e != nil {

9
vendor/golang.org/x/sys/windows/empty.s generated vendored Normal file
View File

@@ -0,0 +1,9 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.12
// +build !go1.12
// This file is here to allow bodyless functions with go:linkname for Go 1.11
// and earlier (see https://golang.org/issue/23311).

View File

@@ -37,17 +37,14 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) {
return nil, err return nil, err
} }
defer DestroyEnvironmentBlock(block) defer DestroyEnvironmentBlock(block)
size := unsafe.Sizeof(*block) blockp := uintptr(unsafe.Pointer(block))
for *block != 0 { for {
// find NUL terminator entry := UTF16PtrToString((*uint16)(unsafe.Pointer(blockp)))
end := unsafe.Pointer(block) if len(entry) == 0 {
for *(*uint16)(end) != 0 { break
end = unsafe.Add(end, size)
} }
env = append(env, entry)
entry := unsafe.Slice(block, (uintptr(end)-uintptr(unsafe.Pointer(block)))/size) blockp += 2 * (uintptr(len(entry)) + 1)
env = append(env, UTF16ToString(entry))
block = (*uint16)(unsafe.Add(end, size))
} }
return env, nil return env, nil
} }

View File

@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build windows //go:build windows
// +build windows
package windows package windows

View File

@@ -22,7 +22,7 @@ import (
// but only if there is space or tab inside s. // but only if there is space or tab inside s.
func EscapeArg(s string) string { func EscapeArg(s string) string {
if len(s) == 0 { if len(s) == 0 {
return `""` return "\"\""
} }
n := len(s) n := len(s)
hasSpace := false hasSpace := false
@@ -35,7 +35,7 @@ func EscapeArg(s string) string {
} }
} }
if hasSpace { if hasSpace {
n += 2 // Reserve space for quotes. n += 2
} }
if n == len(s) { if n == len(s) {
return s return s
@@ -82,106 +82,36 @@ func EscapeArg(s string) string {
// in CreateProcess's CommandLine argument, CreateService/ChangeServiceConfig's BinaryPathName argument, // in CreateProcess's CommandLine argument, CreateService/ChangeServiceConfig's BinaryPathName argument,
// or any program that uses CommandLineToArgv. // or any program that uses CommandLineToArgv.
func ComposeCommandLine(args []string) string { func ComposeCommandLine(args []string) string {
if len(args) == 0 { var commandLine string
return "" for i := range args {
if i > 0 {
commandLine += " "
} }
commandLine += EscapeArg(args[i])
// Per https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw:
// “This function accepts command lines that contain a program name; the
// program name can be enclosed in quotation marks or not.”
//
// Unfortunately, it provides no means of escaping interior quotation marks
// within that program name, and we have no way to report them here.
prog := args[0]
mustQuote := len(prog) == 0
for i := 0; i < len(prog); i++ {
c := prog[i]
if c <= ' ' || (c == '"' && i == 0) {
// Force quotes for not only the ASCII space and tab as described in the
// MSDN article, but also ASCII control characters.
// The documentation for CommandLineToArgvW doesn't say what happens when
// the first argument is not a valid program name, but it empirically
// seems to drop unquoted control characters.
mustQuote = true
break
} }
} return commandLine
var commandLine []byte
if mustQuote {
commandLine = make([]byte, 0, len(prog)+2)
commandLine = append(commandLine, '"')
for i := 0; i < len(prog); i++ {
c := prog[i]
if c == '"' {
// This quote would interfere with our surrounding quotes.
// We have no way to report an error, so just strip out
// the offending character instead.
continue
}
commandLine = append(commandLine, c)
}
commandLine = append(commandLine, '"')
} else {
if len(args) == 1 {
// args[0] is a valid command line representing itself.
// No need to allocate a new slice or string for it.
return prog
}
commandLine = []byte(prog)
}
for _, arg := range args[1:] {
commandLine = append(commandLine, ' ')
// TODO(bcmills): since we're already appending to a slice, it would be nice
// to avoid the intermediate allocations of EscapeArg.
// Perhaps we can factor out an appendEscapedArg function.
commandLine = append(commandLine, EscapeArg(arg)...)
}
return string(commandLine)
} }
// DecomposeCommandLine breaks apart its argument command line into unescaped parts using CommandLineToArgv, // DecomposeCommandLine breaks apart its argument command line into unescaped parts using CommandLineToArgv,
// as gathered from GetCommandLine, QUERY_SERVICE_CONFIG's BinaryPathName argument, or elsewhere that // as gathered from GetCommandLine, QUERY_SERVICE_CONFIG's BinaryPathName argument, or elsewhere that
// command lines are passed around. // command lines are passed around.
// DecomposeCommandLine returns an error if commandLine contains NUL.
func DecomposeCommandLine(commandLine string) ([]string, error) { func DecomposeCommandLine(commandLine string) ([]string, error) {
if len(commandLine) == 0 { if len(commandLine) == 0 {
return []string{}, nil return []string{}, nil
} }
utf16CommandLine, err := UTF16FromString(commandLine)
if err != nil {
return nil, errorspkg.New("string with NUL passed to DecomposeCommandLine")
}
var argc int32 var argc int32
argv, err := commandLineToArgv(&utf16CommandLine[0], &argc) argv, err := CommandLineToArgv(StringToUTF16Ptr(commandLine), &argc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer LocalFree(Handle(unsafe.Pointer(argv))) defer LocalFree(Handle(unsafe.Pointer(argv)))
var args []string var args []string
for _, p := range unsafe.Slice(argv, argc) { for _, v := range (*argv)[:argc] {
args = append(args, UTF16PtrToString(p)) args = append(args, UTF16ToString((*v)[:]))
} }
return args, nil return args, nil
} }
// CommandLineToArgv parses a Unicode command line string and sets
// argc to the number of parsed arguments.
//
// The returned memory should be freed using a single call to LocalFree.
//
// Note that although the return type of CommandLineToArgv indicates 8192
// entries of up to 8192 characters each, the actual count of parsed arguments
// may exceed 8192, and the documentation for CommandLineToArgvW does not mention
// any bound on the lengths of the individual argument strings.
// (See https://go.dev/issue/63236.)
func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) {
argp, err := commandLineToArgv(cmd, argc)
argv = (*[8192]*[8192]uint16)(unsafe.Pointer(argp))
return argv, err
}
func CloseOnExec(fd Handle) { func CloseOnExec(fd Handle) {
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0) SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
} }

View File

@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build generate //go:build generate
// +build generate
package windows package windows

View File

@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build windows && race //go:build windows && race
// +build windows,race
package windows package windows

View File

@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build windows && !race //go:build windows && !race
// +build windows,!race
package windows package windows

View File

@@ -7,6 +7,8 @@ package windows
import ( import (
"syscall" "syscall"
"unsafe" "unsafe"
"golang.org/x/sys/internal/unsafeheader"
) )
const ( const (
@@ -68,7 +70,6 @@ type UserInfo10 struct {
//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo //sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
//sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation //sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation
//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree //sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
//sys NetUserEnum(serverName *uint16, level uint32, filter uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32, resumeHandle *uint32) (neterr error) = netapi32.NetUserEnum
const ( const (
// do not reorder // do not reorder
@@ -894,7 +895,7 @@ type ACL struct {
aclRevision byte aclRevision byte
sbz1 byte sbz1 byte
aclSize uint16 aclSize uint16
AceCount uint16 aceCount uint16
sbz2 uint16 sbz2 uint16
} }
@@ -1087,27 +1088,6 @@ type EXPLICIT_ACCESS struct {
Trustee TRUSTEE Trustee TRUSTEE
} }
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
type ACE_HEADER struct {
AceType uint8
AceFlags uint8
AceSize uint16
}
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-access_allowed_ace
type ACCESS_ALLOWED_ACE struct {
Header ACE_HEADER
Mask ACCESS_MASK
SidStart uint32
}
const (
// Constants for AceType
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
ACCESS_ALLOWED_ACE_TYPE = 0
ACCESS_DENIED_ACE_TYPE = 1
)
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions. // This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
type TrusteeValue uintptr type TrusteeValue uintptr
@@ -1179,7 +1159,6 @@ type OBJECTS_AND_NAME struct {
//sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD //sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD
//sys setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) = advapi32.SetEntriesInAclW //sys setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) = advapi32.SetEntriesInAclW
//sys GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (err error) = advapi32.GetAce
// Control returns the security descriptor control bits. // Control returns the security descriptor control bits.
func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) { func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) {
@@ -1362,14 +1341,21 @@ func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor()
sdLen = min sdLen = min
} }
src := unsafe.Slice((*byte)(unsafe.Pointer(selfRelativeSD)), sdLen) var src []byte
// SECURITY_DESCRIPTOR has pointers in it, which means checkptr expects for it to h := (*unsafeheader.Slice)(unsafe.Pointer(&src))
// be aligned properly. When we're copying a Windows-allocated struct to a h.Data = unsafe.Pointer(selfRelativeSD)
// Go-allocated one, make sure that the Go allocation is aligned to the h.Len = sdLen
// pointer size. h.Cap = sdLen
const psize = int(unsafe.Sizeof(uintptr(0))) const psize = int(unsafe.Sizeof(uintptr(0)))
var dst []byte
h = (*unsafeheader.Slice)(unsafe.Pointer(&dst))
alloc := make([]uintptr, (sdLen+psize-1)/psize) alloc := make([]uintptr, (sdLen+psize-1)/psize)
dst := unsafe.Slice((*byte)(unsafe.Pointer(&alloc[0])), sdLen) h.Data = (*unsafeheader.Slice)(unsafe.Pointer(&alloc)).Data
h.Len = sdLen
h.Cap = sdLen
copy(dst, src) copy(dst, src)
return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&dst[0])) return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&dst[0]))
} }

View File

@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build windows //go:build windows
// +build windows
package windows package windows
@@ -140,12 +141,6 @@ const (
SERVICE_DYNAMIC_INFORMATION_LEVEL_START_REASON = 1 SERVICE_DYNAMIC_INFORMATION_LEVEL_START_REASON = 1
) )
type ENUM_SERVICE_STATUS struct {
ServiceName *uint16
DisplayName *uint16
ServiceStatus SERVICE_STATUS
}
type SERVICE_STATUS struct { type SERVICE_STATUS struct {
ServiceType uint32 ServiceType uint32
CurrentState uint32 CurrentState uint32
@@ -217,10 +212,6 @@ type SERVICE_FAILURE_ACTIONS struct {
Actions *SC_ACTION Actions *SC_ACTION
} }
type SERVICE_FAILURE_ACTIONS_FLAG struct {
FailureActionsOnNonCrashFailures int32
}
type SC_ACTION struct { type SC_ACTION struct {
Type uint32 Type uint32
Delay uint32 Delay uint32
@@ -254,4 +245,3 @@ type QUERY_SERVICE_LOCK_STATUS struct {
//sys UnsubscribeServiceChangeNotifications(subscription uintptr) = sechost.UnsubscribeServiceChangeNotifications? //sys UnsubscribeServiceChangeNotifications(subscription uintptr) = sechost.UnsubscribeServiceChangeNotifications?
//sys RegisterServiceCtrlHandlerEx(serviceName *uint16, handlerProc uintptr, context uintptr) (handle Handle, err error) = advapi32.RegisterServiceCtrlHandlerExW //sys RegisterServiceCtrlHandlerEx(serviceName *uint16, handlerProc uintptr, context uintptr) (handle Handle, err error) = advapi32.RegisterServiceCtrlHandlerExW
//sys QueryServiceDynamicInformation(service Handle, infoLevel uint32, dynamicInfo unsafe.Pointer) (err error) = advapi32.QueryServiceDynamicInformation? //sys QueryServiceDynamicInformation(service Handle, infoLevel uint32, dynamicInfo unsafe.Pointer) (err error) = advapi32.QueryServiceDynamicInformation?
//sys EnumDependentServices(service Handle, activityState uint32, services *ENUM_SERVICE_STATUS, buffSize uint32, bytesNeeded *uint32, servicesReturned *uint32) (err error) = advapi32.EnumDependentServicesW

View File

@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build windows //go:build windows
// +build windows
package windows package windows

View File

@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build windows //go:build windows
// +build windows
// Package windows contains an interface to the low-level operating system // Package windows contains an interface to the low-level operating system
// primitives. OS details vary depending on the underlying system, and // primitives. OS details vary depending on the underlying system, and

View File

@@ -15,12 +15,12 @@ import (
"time" "time"
"unicode/utf16" "unicode/utf16"
"unsafe" "unsafe"
"golang.org/x/sys/internal/unsafeheader"
) )
type ( type Handle uintptr
Handle uintptr type HWND uintptr
HWND uintptr
)
const ( const (
InvalidHandle = ^Handle(0) InvalidHandle = ^Handle(0)
@@ -127,21 +127,22 @@ func UTF16PtrToString(p *uint16) string {
for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ { for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ {
ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p)) ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p))
} }
return UTF16ToString(unsafe.Slice(p, n))
return string(utf16.Decode(unsafe.Slice(p, n)))
} }
func Getpagesize() int { return 4096 } func Getpagesize() int { return 4096 }
// NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention. // NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention.
// This is useful when interoperating with Windows code requiring callbacks. // This is useful when interoperating with Windows code requiring callbacks.
// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. // The argument is expected to be a function with with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
func NewCallback(fn interface{}) uintptr { func NewCallback(fn interface{}) uintptr {
return syscall.NewCallback(fn) return syscall.NewCallback(fn)
} }
// NewCallbackCDecl converts a Go function to a function pointer conforming to the cdecl calling convention. // NewCallbackCDecl converts a Go function to a function pointer conforming to the cdecl calling convention.
// This is useful when interoperating with Windows code requiring callbacks. // This is useful when interoperating with Windows code requiring callbacks.
// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. // The argument is expected to be a function with with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
func NewCallbackCDecl(fn interface{}) uintptr { func NewCallbackCDecl(fn interface{}) uintptr {
return syscall.NewCallbackCDecl(fn) return syscall.NewCallbackCDecl(fn)
} }
@@ -156,8 +157,6 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, err error) = kernel32.GetModuleFileNameW //sys GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, err error) = kernel32.GetModuleFileNameW
//sys GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err error) = kernel32.GetModuleHandleExW //sys GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err error) = kernel32.GetModuleHandleExW
//sys SetDefaultDllDirectories(directoryFlags uint32) (err error) //sys SetDefaultDllDirectories(directoryFlags uint32) (err error)
//sys AddDllDirectory(path *uint16) (cookie uintptr, err error) = kernel32.AddDllDirectory
//sys RemoveDllDirectory(cookie uintptr) (err error) = kernel32.RemoveDllDirectory
//sys SetDllDirectory(path string) (err error) = kernel32.SetDllDirectoryW //sys SetDllDirectory(path string) (err error) = kernel32.SetDllDirectoryW
//sys GetVersion() (ver uint32, err error) //sys GetVersion() (ver uint32, err error)
//sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW //sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
@@ -167,9 +166,6 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile Handle) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW //sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile Handle) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
//sys CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *SecurityAttributes) (handle Handle, err error) [failretval==InvalidHandle] = CreateNamedPipeW //sys CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *SecurityAttributes) (handle Handle, err error) [failretval==InvalidHandle] = CreateNamedPipeW
//sys ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error) //sys ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error)
//sys DisconnectNamedPipe(pipe Handle) (err error)
//sys GetNamedPipeClientProcessId(pipe Handle, clientProcessID *uint32) (err error)
//sys GetNamedPipeServerProcessId(pipe Handle, serverProcessID *uint32) (err error)
//sys GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) //sys GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error)
//sys GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW //sys GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys SetNamedPipeHandleState(pipe Handle, state *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32) (err error) = SetNamedPipeHandleState //sys SetNamedPipeHandleState(pipe Handle, state *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32) (err error) = SetNamedPipeHandleState
@@ -198,7 +194,6 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW //sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW //sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys SetEndOfFile(handle Handle) (err error) //sys SetEndOfFile(handle Handle) (err error)
//sys SetFileValidData(handle Handle, validDataLength int64) (err error)
//sys GetSystemTimeAsFileTime(time *Filetime) //sys GetSystemTimeAsFileTime(time *Filetime)
//sys GetSystemTimePreciseAsFileTime(time *Filetime) //sys GetSystemTimePreciseAsFileTime(time *Filetime)
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
@@ -215,17 +210,13 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) (handle Handle, err error) //sys OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) (handle Handle, err error)
//sys ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *uint16, showCmd int32) (err error) [failretval<=32] = shell32.ShellExecuteW //sys ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *uint16, showCmd int32) (err error) [failretval<=32] = shell32.ShellExecuteW
//sys GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) = user32.GetWindowThreadProcessId //sys GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) = user32.GetWindowThreadProcessId
//sys LoadKeyboardLayout(name *uint16, flags uint32) (hkl Handle, err error) [failretval==0] = user32.LoadKeyboardLayoutW
//sys UnloadKeyboardLayout(hkl Handle) (err error) = user32.UnloadKeyboardLayout
//sys GetKeyboardLayout(tid uint32) (hkl Handle) = user32.GetKeyboardLayout
//sys ToUnicodeEx(vkey uint32, scancode uint32, keystate *byte, pwszBuff *uint16, cchBuff int32, flags uint32, hkl Handle) (ret int32) = user32.ToUnicodeEx
//sys GetShellWindow() (shellWindow HWND) = user32.GetShellWindow //sys GetShellWindow() (shellWindow HWND) = user32.GetShellWindow
//sys MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) [failretval==0] = user32.MessageBoxW //sys MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) [failretval==0] = user32.MessageBoxW
//sys ExitWindowsEx(flags uint32, reason uint32) (err error) = user32.ExitWindowsEx //sys ExitWindowsEx(flags uint32, reason uint32) (err error) = user32.ExitWindowsEx
//sys shGetKnownFolderPath(id *KNOWNFOLDERID, flags uint32, token Token, path **uint16) (ret error) = shell32.SHGetKnownFolderPath //sys shGetKnownFolderPath(id *KNOWNFOLDERID, flags uint32, token Token, path **uint16) (ret error) = shell32.SHGetKnownFolderPath
//sys TerminateProcess(handle Handle, exitcode uint32) (err error) //sys TerminateProcess(handle Handle, exitcode uint32) (err error)
//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) //sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error)
//sys getStartupInfo(startupInfo *StartupInfo) = GetStartupInfoW //sys GetStartupInfo(startupInfo *StartupInfo) (err error) = GetStartupInfoW
//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) //sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error)
//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) //sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error)
//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff] //sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff]
@@ -244,13 +235,12 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock //sys CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock
//sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock //sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock
//sys getTickCount64() (ms uint64) = kernel32.GetTickCount64 //sys getTickCount64() (ms uint64) = kernel32.GetTickCount64
//sys GetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error)
//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) //sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error)
//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW //sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW //sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW
//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW //sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW
//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW //sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW
//sys commandLineToArgv(cmd *uint16, argc *int32) (argv **uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW //sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW
//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0] //sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0]
//sys LocalAlloc(flags uint32, length uint32) (ptr uintptr, err error) //sys LocalAlloc(flags uint32, length uint32) (ptr uintptr, err error)
//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) //sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error)
@@ -309,19 +299,12 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys RegNotifyChangeKeyValue(key Handle, watchSubtree bool, notifyFilter uint32, event Handle, asynchronous bool) (regerrno error) = advapi32.RegNotifyChangeKeyValue //sys RegNotifyChangeKeyValue(key Handle, watchSubtree bool, notifyFilter uint32, event Handle, asynchronous bool) (regerrno error) = advapi32.RegNotifyChangeKeyValue
//sys GetCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId //sys GetCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
//sys ProcessIdToSessionId(pid uint32, sessionid *uint32) (err error) = kernel32.ProcessIdToSessionId //sys ProcessIdToSessionId(pid uint32, sessionid *uint32) (err error) = kernel32.ProcessIdToSessionId
//sys ClosePseudoConsole(console Handle) = kernel32.ClosePseudoConsole
//sys createPseudoConsole(size uint32, in Handle, out Handle, flags uint32, pconsole *Handle) (hr error) = kernel32.CreatePseudoConsole
//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode //sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
//sys SetConsoleMode(console Handle, mode uint32) (err error) = kernel32.SetConsoleMode //sys SetConsoleMode(console Handle, mode uint32) (err error) = kernel32.SetConsoleMode
//sys GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) = kernel32.GetConsoleScreenBufferInfo //sys GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) = kernel32.GetConsoleScreenBufferInfo
//sys setConsoleCursorPosition(console Handle, position uint32) (err error) = kernel32.SetConsoleCursorPosition //sys setConsoleCursorPosition(console Handle, position uint32) (err error) = kernel32.SetConsoleCursorPosition
//sys GetConsoleCP() (cp uint32, err error) = kernel32.GetConsoleCP
//sys GetConsoleOutputCP() (cp uint32, err error) = kernel32.GetConsoleOutputCP
//sys SetConsoleCP(cp uint32) (err error) = kernel32.SetConsoleCP
//sys SetConsoleOutputCP(cp uint32) (err error) = kernel32.SetConsoleOutputCP
//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW //sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW
//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW //sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW
//sys resizePseudoConsole(pconsole Handle, size uint32) (hr error) = kernel32.ResizePseudoConsole
//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot //sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot
//sys Module32First(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32FirstW //sys Module32First(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32FirstW
//sys Module32Next(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32NextW //sys Module32Next(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32NextW
@@ -361,19 +344,8 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys SetProcessPriorityBoost(process Handle, disable bool) (err error) = kernel32.SetProcessPriorityBoost //sys SetProcessPriorityBoost(process Handle, disable bool) (err error) = kernel32.SetProcessPriorityBoost
//sys GetProcessWorkingSetSizeEx(hProcess Handle, lpMinimumWorkingSetSize *uintptr, lpMaximumWorkingSetSize *uintptr, flags *uint32) //sys GetProcessWorkingSetSizeEx(hProcess Handle, lpMinimumWorkingSetSize *uintptr, lpMaximumWorkingSetSize *uintptr, flags *uint32)
//sys SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error) //sys SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error)
//sys ClearCommBreak(handle Handle) (err error)
//sys ClearCommError(handle Handle, lpErrors *uint32, lpStat *ComStat) (err error)
//sys EscapeCommFunction(handle Handle, dwFunc uint32) (err error)
//sys GetCommState(handle Handle, lpDCB *DCB) (err error)
//sys GetCommModemStatus(handle Handle, lpModemStat *uint32) (err error)
//sys GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) //sys GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error)
//sys PurgeComm(handle Handle, dwFlags uint32) (err error)
//sys SetCommBreak(handle Handle) (err error)
//sys SetCommMask(handle Handle, dwEvtMask uint32) (err error)
//sys SetCommState(handle Handle, lpDCB *DCB) (err error)
//sys SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) //sys SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error)
//sys SetupComm(handle Handle, dwInQueue uint32, dwOutQueue uint32) (err error)
//sys WaitCommEvent(handle Handle, lpEvtMask *uint32, lpOverlapped *Overlapped) (err error)
//sys GetActiveProcessorCount(groupNumber uint16) (ret uint32) //sys GetActiveProcessorCount(groupNumber uint16) (ret uint32)
//sys GetMaximumProcessorCount(groupNumber uint16) (ret uint32) //sys GetMaximumProcessorCount(groupNumber uint16) (ret uint32)
//sys EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) = user32.EnumWindows //sys EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) = user32.EnumWindows
@@ -433,7 +405,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys VerQueryValue(block unsafe.Pointer, subBlock string, pointerToBufferPointer unsafe.Pointer, bufSize *uint32) (err error) = version.VerQueryValueW //sys VerQueryValue(block unsafe.Pointer, subBlock string, pointerToBufferPointer unsafe.Pointer, bufSize *uint32) (err error) = version.VerQueryValueW
// Process Status API (PSAPI) // Process Status API (PSAPI)
//sys enumProcesses(processIds *uint32, nSize uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses //sys EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
//sys EnumProcessModules(process Handle, module *Handle, cb uint32, cbNeeded *uint32) (err error) = psapi.EnumProcessModules //sys EnumProcessModules(process Handle, module *Handle, cb uint32, cbNeeded *uint32) (err error) = psapi.EnumProcessModules
//sys EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *uint32, filterFlag uint32) (err error) = psapi.EnumProcessModulesEx //sys EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *uint32, filterFlag uint32) (err error) = psapi.EnumProcessModulesEx
//sys GetModuleInformation(process Handle, module Handle, modinfo *ModuleInfo, cb uint32) (err error) = psapi.GetModuleInformation //sys GetModuleInformation(process Handle, module Handle, modinfo *ModuleInfo, cb uint32) (err error) = psapi.GetModuleInformation
@@ -465,10 +437,6 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys DwmGetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) = dwmapi.DwmGetWindowAttribute //sys DwmGetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) = dwmapi.DwmGetWindowAttribute
//sys DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) = dwmapi.DwmSetWindowAttribute //sys DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) = dwmapi.DwmSetWindowAttribute
// Windows Multimedia API
//sys TimeBeginPeriod (period uint32) (err error) [failretval != 0] = winmm.timeBeginPeriod
//sys TimeEndPeriod (period uint32) (err error) [failretval != 0] = winmm.timeEndPeriod
// syscall interface implementation for other packages // syscall interface implementation for other packages
// GetCurrentProcess returns the handle for the current process. // GetCurrentProcess returns the handle for the current process.
@@ -727,12 +695,20 @@ func DurationSinceBoot() time.Duration {
} }
func Ftruncate(fd Handle, length int64) (err error) { func Ftruncate(fd Handle, length int64) (err error) {
type _FILE_END_OF_FILE_INFO struct { curoffset, e := Seek(fd, 0, 1)
EndOfFile int64 if e != nil {
return e
} }
var info _FILE_END_OF_FILE_INFO defer Seek(fd, curoffset, 0)
info.EndOfFile = length _, e = Seek(fd, length, 0)
return SetFileInformationByHandle(fd, FileEndOfFileInfo, (*byte)(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info))) if e != nil {
return e
}
e = SetEndOfFile(fd)
if e != nil {
return e
}
return nil
} }
func Gettimeofday(tv *Timeval) (err error) { func Gettimeofday(tv *Timeval) (err error) {
@@ -888,11 +864,6 @@ const socket_error = uintptr(^uint32(0))
//sys GetACP() (acp uint32) = kernel32.GetACP //sys GetACP() (acp uint32) = kernel32.GetACP
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar //sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
//sys getBestInterfaceEx(sockaddr unsafe.Pointer, pdwBestIfIndex *uint32) (errcode error) = iphlpapi.GetBestInterfaceEx //sys getBestInterfaceEx(sockaddr unsafe.Pointer, pdwBestIfIndex *uint32) (errcode error) = iphlpapi.GetBestInterfaceEx
//sys GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) = iphlpapi.GetIfEntry2Ex
//sys GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) = iphlpapi.GetUnicastIpAddressEntry
//sys NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyIpInterfaceChange
//sys NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyUnicastIpAddressChange
//sys CancelMibChangeNotify2(notificationHandle Handle) (errcode error) = iphlpapi.CancelMibChangeNotify2
// For testing: clients can set this flag to force // For testing: clients can set this flag to force
// creation of IPv6 sockets to return EAFNOSUPPORT. // creation of IPv6 sockets to return EAFNOSUPPORT.
@@ -993,8 +964,7 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
if n > 0 { if n > 0 {
sl += int32(n) + 1 sl += int32(n) + 1
} }
if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) { if sa.raw.Path[0] == '@' {
// Check sl > 3 so we don't change unnamed socket behavior.
sa.raw.Path[0] = 0 sa.raw.Path[0] = 0
// Don't count trailing NUL for abstract address. // Don't count trailing NUL for abstract address.
sl-- sl--
@@ -1377,26 +1347,13 @@ func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) {
func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) { func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) {
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4) return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4)
} }
func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) { func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) {
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq))) return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq)))
} }
func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) { func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) {
return syscall.EWINDOWS return syscall.EWINDOWS
} }
func EnumProcesses(processIds []uint32, bytesReturned *uint32) error {
// EnumProcesses syscall expects the size parameter to be in bytes, but the code generated with mksyscall uses
// the length of the processIds slice instead. Hence, this wrapper function is added to fix the discrepancy.
var p *uint32
if len(processIds) > 0 {
p = &processIds[0]
}
size := uint32(len(processIds) * 4)
return enumProcesses(p, size, bytesReturned)
}
func Getpid() (pid int) { return int(GetCurrentProcessId()) } func Getpid() (pid int) { return int(GetCurrentProcessId()) }
func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) { func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) {
@@ -1656,11 +1613,6 @@ func SetConsoleCursorPosition(console Handle, position Coord) error {
return setConsoleCursorPosition(console, *((*uint32)(unsafe.Pointer(&position)))) return setConsoleCursorPosition(console, *((*uint32)(unsafe.Pointer(&position))))
} }
func GetStartupInfo(startupInfo *StartupInfo) error {
getStartupInfo(startupInfo)
return nil
}
func (s NTStatus) Errno() syscall.Errno { func (s NTStatus) Errno() syscall.Errno {
return rtlNtStatusToDosErrorNoTeb(s) return rtlNtStatusToDosErrorNoTeb(s)
} }
@@ -1684,22 +1636,23 @@ func (s NTStatus) Error() string {
// do not use NTUnicodeString, and instead UTF16PtrFromString should be used for // do not use NTUnicodeString, and instead UTF16PtrFromString should be used for
// the more common *uint16 string type. // the more common *uint16 string type.
func NewNTUnicodeString(s string) (*NTUnicodeString, error) { func NewNTUnicodeString(s string) (*NTUnicodeString, error) {
s16, err := UTF16FromString(s) var u NTUnicodeString
s16, err := UTF16PtrFromString(s)
if err != nil { if err != nil {
return nil, err return nil, err
} }
n := uint16(len(s16) * 2) RtlInitUnicodeString(&u, s16)
return &NTUnicodeString{ return &u, nil
Length: n - 2, // subtract 2 bytes for the NULL terminator
MaximumLength: n,
Buffer: &s16[0],
}, nil
} }
// Slice returns a uint16 slice that aliases the data in the NTUnicodeString. // Slice returns a uint16 slice that aliases the data in the NTUnicodeString.
func (s *NTUnicodeString) Slice() []uint16 { func (s *NTUnicodeString) Slice() []uint16 {
slice := unsafe.Slice(s.Buffer, s.MaximumLength) var slice []uint16
return slice[:s.Length] hdr := (*unsafeheader.Slice)(unsafe.Pointer(&slice))
hdr.Data = unsafe.Pointer(s.Buffer)
hdr.Len = int(s.Length)
hdr.Cap = int(s.MaximumLength)
return slice
} }
func (s *NTUnicodeString) String() string { func (s *NTUnicodeString) String() string {
@@ -1722,8 +1675,12 @@ func NewNTString(s string) (*NTString, error) {
// Slice returns a byte slice that aliases the data in the NTString. // Slice returns a byte slice that aliases the data in the NTString.
func (s *NTString) Slice() []byte { func (s *NTString) Slice() []byte {
slice := unsafe.Slice(s.Buffer, s.MaximumLength) var slice []byte
return slice[:s.Length] hdr := (*unsafeheader.Slice)(unsafe.Pointer(&slice))
hdr.Data = unsafe.Pointer(s.Buffer)
hdr.Len = int(s.Length)
hdr.Cap = int(s.MaximumLength)
return slice
} }
func (s *NTString) String() string { func (s *NTString) String() string {
@@ -1775,7 +1732,10 @@ func LoadResourceData(module, resInfo Handle) (data []byte, err error) {
if err != nil { if err != nil {
return return
} }
data = unsafe.Slice((*byte)(unsafe.Pointer(ptr)), size) h := (*unsafeheader.Slice)(unsafe.Pointer(&data))
h.Data = unsafe.Pointer(ptr)
h.Len = int(size)
h.Cap = int(size)
return return
} }
@@ -1846,87 +1806,3 @@ type PSAPI_WORKING_SET_EX_INFORMATION struct {
// A PSAPI_WORKING_SET_EX_BLOCK union that indicates the attributes of the page at VirtualAddress. // A PSAPI_WORKING_SET_EX_BLOCK union that indicates the attributes of the page at VirtualAddress.
VirtualAttributes PSAPI_WORKING_SET_EX_BLOCK VirtualAttributes PSAPI_WORKING_SET_EX_BLOCK
} }
// CreatePseudoConsole creates a windows pseudo console.
func CreatePseudoConsole(size Coord, in Handle, out Handle, flags uint32, pconsole *Handle) error {
// We need this wrapper to manually cast Coord to uint32. The autogenerated wrappers only
// accept arguments that can be casted to uintptr, and Coord can't.
return createPseudoConsole(*((*uint32)(unsafe.Pointer(&size))), in, out, flags, pconsole)
}
// ResizePseudoConsole resizes the internal buffers of the pseudo console to the width and height specified in `size`.
func ResizePseudoConsole(pconsole Handle, size Coord) error {
// We need this wrapper to manually cast Coord to uint32. The autogenerated wrappers only
// accept arguments that can be casted to uintptr, and Coord can't.
return resizePseudoConsole(pconsole, *((*uint32)(unsafe.Pointer(&size))))
}
// DCB constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-dcb.
const (
CBR_110 = 110
CBR_300 = 300
CBR_600 = 600
CBR_1200 = 1200
CBR_2400 = 2400
CBR_4800 = 4800
CBR_9600 = 9600
CBR_14400 = 14400
CBR_19200 = 19200
CBR_38400 = 38400
CBR_57600 = 57600
CBR_115200 = 115200
CBR_128000 = 128000
CBR_256000 = 256000
DTR_CONTROL_DISABLE = 0x00000000
DTR_CONTROL_ENABLE = 0x00000010
DTR_CONTROL_HANDSHAKE = 0x00000020
RTS_CONTROL_DISABLE = 0x00000000
RTS_CONTROL_ENABLE = 0x00001000
RTS_CONTROL_HANDSHAKE = 0x00002000
RTS_CONTROL_TOGGLE = 0x00003000
NOPARITY = 0
ODDPARITY = 1
EVENPARITY = 2
MARKPARITY = 3
SPACEPARITY = 4
ONESTOPBIT = 0
ONE5STOPBITS = 1
TWOSTOPBITS = 2
)
// EscapeCommFunction constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-escapecommfunction.
const (
SETXOFF = 1
SETXON = 2
SETRTS = 3
CLRRTS = 4
SETDTR = 5
CLRDTR = 6
SETBREAK = 8
CLRBREAK = 9
)
// PurgeComm constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-purgecomm.
const (
PURGE_TXABORT = 0x0001
PURGE_RXABORT = 0x0002
PURGE_TXCLEAR = 0x0004
PURGE_RXCLEAR = 0x0008
)
// SetCommMask constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcommmask.
const (
EV_RXCHAR = 0x0001
EV_RXFLAG = 0x0002
EV_TXEMPTY = 0x0004
EV_CTS = 0x0008
EV_DSR = 0x0010
EV_RLSD = 0x0020
EV_BREAK = 0x0040
EV_ERR = 0x0080
EV_RING = 0x0100
)

View File

@@ -176,7 +176,6 @@ const (
WAIT_FAILED = 0xFFFFFFFF WAIT_FAILED = 0xFFFFFFFF
// Access rights for process. // Access rights for process.
PROCESS_ALL_ACCESS = 0xFFFF
PROCESS_CREATE_PROCESS = 0x0080 PROCESS_CREATE_PROCESS = 0x0080
PROCESS_CREATE_THREAD = 0x0002 PROCESS_CREATE_THREAD = 0x0002
PROCESS_DUP_HANDLE = 0x0040 PROCESS_DUP_HANDLE = 0x0040
@@ -248,7 +247,6 @@ const (
PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY = 0x00020007 PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY = 0x00020007
PROC_THREAD_ATTRIBUTE_UMS_THREAD = 0x00030006 PROC_THREAD_ATTRIBUTE_UMS_THREAD = 0x00030006
PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL = 0x0002000b PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL = 0x0002000b
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE = 0x00020016
) )
const ( const (
@@ -1061,7 +1059,6 @@ const (
SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6 SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6
SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4 SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4
SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12 SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12
SIO_UDP_NETRESET = IOC_IN | IOC_VENDOR | 15
// cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460 // cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460
@@ -1097,32 +1094,6 @@ const (
SOMAXCONN = 0x7fffffff SOMAXCONN = 0x7fffffff
TCP_NODELAY = 1 TCP_NODELAY = 1
TCP_EXPEDITED_1122 = 2
TCP_KEEPALIVE = 3
TCP_MAXSEG = 4
TCP_MAXRT = 5
TCP_STDURG = 6
TCP_NOURG = 7
TCP_ATMARK = 8
TCP_NOSYNRETRIES = 9
TCP_TIMESTAMPS = 10
TCP_OFFLOAD_PREFERENCE = 11
TCP_CONGESTION_ALGORITHM = 12
TCP_DELAY_FIN_ACK = 13
TCP_MAXRTMS = 14
TCP_FASTOPEN = 15
TCP_KEEPCNT = 16
TCP_KEEPIDLE = TCP_KEEPALIVE
TCP_KEEPINTVL = 17
TCP_FAIL_CONNECT_ON_ICMP_ERROR = 18
TCP_ICMP_ERROR_INFO = 19
UDP_NOCHECKSUM = 1
UDP_SEND_MSG_SIZE = 2
UDP_RECV_MAX_COALESCED_SIZE = 3
UDP_CHECKSUM_COVERAGE = 20
UDP_COALESCED_INFO = 3
SHUT_RD = 0 SHUT_RD = 0
SHUT_WR = 1 SHUT_WR = 1
@@ -2005,21 +1976,7 @@ const (
MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20 MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20
) )
// Flags for GetAdaptersAddresses, see const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
// https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses.
const (
GAA_FLAG_SKIP_UNICAST = 0x1
GAA_FLAG_SKIP_ANYCAST = 0x2
GAA_FLAG_SKIP_MULTICAST = 0x4
GAA_FLAG_SKIP_DNS_SERVER = 0x8
GAA_FLAG_INCLUDE_PREFIX = 0x10
GAA_FLAG_SKIP_FRIENDLY_NAME = 0x20
GAA_FLAG_INCLUDE_WINS_INFO = 0x40
GAA_FLAG_INCLUDE_GATEWAYS = 0x80
GAA_FLAG_INCLUDE_ALL_INTERFACES = 0x100
GAA_FLAG_INCLUDE_ALL_COMPARTMENTS = 0x200
GAA_FLAG_INCLUDE_TUNNEL_BINDINGORDER = 0x400
)
const ( const (
IF_TYPE_OTHER = 1 IF_TYPE_OTHER = 1
@@ -2033,50 +1990,6 @@ const (
IF_TYPE_IEEE1394 = 144 IF_TYPE_IEEE1394 = 144
) )
// Enum NL_PREFIX_ORIGIN for [IpAdapterUnicastAddress], see
// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_prefix_origin
const (
IpPrefixOriginOther = 0
IpPrefixOriginManual = 1
IpPrefixOriginWellKnown = 2
IpPrefixOriginDhcp = 3
IpPrefixOriginRouterAdvertisement = 4
IpPrefixOriginUnchanged = 1 << 4
)
// Enum NL_SUFFIX_ORIGIN for [IpAdapterUnicastAddress], see
// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_suffix_origin
const (
NlsoOther = 0
NlsoManual = 1
NlsoWellKnown = 2
NlsoDhcp = 3
NlsoLinkLayerAddress = 4
NlsoRandom = 5
IpSuffixOriginOther = 0
IpSuffixOriginManual = 1
IpSuffixOriginWellKnown = 2
IpSuffixOriginDhcp = 3
IpSuffixOriginLinkLayerAddress = 4
IpSuffixOriginRandom = 5
IpSuffixOriginUnchanged = 1 << 4
)
// Enum NL_DAD_STATE for [IpAdapterUnicastAddress], see
// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_dad_state
const (
NldsInvalid = 0
NldsTentative = 1
NldsDuplicate = 2
NldsDeprecated = 3
NldsPreferred = 4
IpDadStateInvalid = 0
IpDadStateTentative = 1
IpDadStateDuplicate = 2
IpDadStateDeprecated = 3
IpDadStatePreferred = 4
)
type SocketAddress struct { type SocketAddress struct {
Sockaddr *syscall.RawSockaddrAny Sockaddr *syscall.RawSockaddrAny
SockaddrLength int32 SockaddrLength int32
@@ -2204,132 +2117,6 @@ const (
IfOperStatusLowerLayerDown = 7 IfOperStatusLowerLayerDown = 7
) )
const (
IF_MAX_PHYS_ADDRESS_LENGTH = 32
IF_MAX_STRING_SIZE = 256
)
// MIB_IF_ENTRY_LEVEL enumeration from netioapi.h or
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/nf-netioapi-getifentry2ex.
const (
MibIfEntryNormal = 0
MibIfEntryNormalWithoutStatistics = 2
)
// MIB_NOTIFICATION_TYPE enumeration from netioapi.h or
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ne-netioapi-mib_notification_type.
const (
MibParameterNotification = 0
MibAddInstance = 1
MibDeleteInstance = 2
MibInitialNotification = 3
)
// MibIfRow2 stores information about a particular interface. See
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_if_row2.
type MibIfRow2 struct {
InterfaceLuid uint64
InterfaceIndex uint32
InterfaceGuid GUID
Alias [IF_MAX_STRING_SIZE + 1]uint16
Description [IF_MAX_STRING_SIZE + 1]uint16
PhysicalAddressLength uint32
PhysicalAddress [IF_MAX_PHYS_ADDRESS_LENGTH]uint8
PermanentPhysicalAddress [IF_MAX_PHYS_ADDRESS_LENGTH]uint8
Mtu uint32
Type uint32
TunnelType uint32
MediaType uint32
PhysicalMediumType uint32
AccessType uint32
DirectionType uint32
InterfaceAndOperStatusFlags uint8
OperStatus uint32
AdminStatus uint32
MediaConnectState uint32
NetworkGuid GUID
ConnectionType uint32
TransmitLinkSpeed uint64
ReceiveLinkSpeed uint64
InOctets uint64
InUcastPkts uint64
InNUcastPkts uint64
InDiscards uint64
InErrors uint64
InUnknownProtos uint64
InUcastOctets uint64
InMulticastOctets uint64
InBroadcastOctets uint64
OutOctets uint64
OutUcastPkts uint64
OutNUcastPkts uint64
OutDiscards uint64
OutErrors uint64
OutUcastOctets uint64
OutMulticastOctets uint64
OutBroadcastOctets uint64
OutQLen uint64
}
// MIB_UNICASTIPADDRESS_ROW stores information about a unicast IP address. See
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_unicastipaddress_row.
type MibUnicastIpAddressRow struct {
Address RawSockaddrInet6 // SOCKADDR_INET union
InterfaceLuid uint64
InterfaceIndex uint32
PrefixOrigin uint32
SuffixOrigin uint32
ValidLifetime uint32
PreferredLifetime uint32
OnLinkPrefixLength uint8
SkipAsSource uint8
DadState uint32
ScopeId uint32
CreationTimeStamp Filetime
}
const ScopeLevelCount = 16
// MIB_IPINTERFACE_ROW stores interface management information for a particular IP address family on a network interface.
// See https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipinterface_row.
type MibIpInterfaceRow struct {
Family uint16
InterfaceLuid uint64
InterfaceIndex uint32
MaxReassemblySize uint32
InterfaceIdentifier uint64
MinRouterAdvertisementInterval uint32
MaxRouterAdvertisementInterval uint32
AdvertisingEnabled uint8
ForwardingEnabled uint8
WeakHostSend uint8
WeakHostReceive uint8
UseAutomaticMetric uint8
UseNeighborUnreachabilityDetection uint8
ManagedAddressConfigurationSupported uint8
OtherStatefulConfigurationSupported uint8
AdvertiseDefaultRoute uint8
RouterDiscoveryBehavior uint32
DadTransmits uint32
BaseReachableTime uint32
RetransmitTime uint32
PathMtuDiscoveryTimeout uint32
LinkLocalAddressBehavior uint32
LinkLocalAddressTimeout uint32
ZoneIndices [ScopeLevelCount]uint32
SitePrefixLength uint32
Metric uint32
NlMtu uint32
Connected uint8
SupportsWakeUpPatterns uint8
SupportsNeighborDiscovery uint8
SupportsRouterDiscovery uint8
ReachableTime uint32
TransmitOffload uint32
ReceiveOffload uint32
DisableDefaultRoutes uint8
}
// Console related constants used for the mode parameter to SetConsoleMode. See // Console related constants used for the mode parameter to SetConsoleMode. See
// https://docs.microsoft.com/en-us/windows/console/setconsolemode for details. // https://docs.microsoft.com/en-us/windows/console/setconsolemode for details.
@@ -2352,12 +2139,6 @@ const (
ENABLE_LVB_GRID_WORLDWIDE = 0x10 ENABLE_LVB_GRID_WORLDWIDE = 0x10
) )
// Pseudo console related constants used for the flags parameter to
// CreatePseudoConsole. See: https://learn.microsoft.com/en-us/windows/console/createpseudoconsole
const (
PSEUDOCONSOLE_INHERIT_CURSOR = 0x1
)
type Coord struct { type Coord struct {
X int16 X int16
Y int16 Y int16
@@ -2439,23 +2220,19 @@ type JOBOBJECT_BASIC_UI_RESTRICTIONS struct {
} }
const ( const (
// JobObjectInformationClass for QueryInformationJobObject and SetInformationJobObject // JobObjectInformationClass
JobObjectAssociateCompletionPortInformation = 7 JobObjectAssociateCompletionPortInformation = 7
JobObjectBasicAccountingInformation = 1
JobObjectBasicAndIoAccountingInformation = 8
JobObjectBasicLimitInformation = 2 JobObjectBasicLimitInformation = 2
JobObjectBasicProcessIdList = 3
JobObjectBasicUIRestrictions = 4 JobObjectBasicUIRestrictions = 4
JobObjectCpuRateControlInformation = 15 JobObjectCpuRateControlInformation = 15
JobObjectEndOfJobTimeInformation = 6 JobObjectEndOfJobTimeInformation = 6
JobObjectExtendedLimitInformation = 9 JobObjectExtendedLimitInformation = 9
JobObjectGroupInformation = 11 JobObjectGroupInformation = 11
JobObjectGroupInformationEx = 14 JobObjectGroupInformationEx = 14
JobObjectLimitViolationInformation = 13 JobObjectLimitViolationInformation2 = 35
JobObjectLimitViolationInformation2 = 34
JobObjectNetRateControlInformation = 32 JobObjectNetRateControlInformation = 32
JobObjectNotificationLimitInformation = 12 JobObjectNotificationLimitInformation = 12
JobObjectNotificationLimitInformation2 = 33 JobObjectNotificationLimitInformation2 = 34
JobObjectSecurityLimitInformation = 5 JobObjectSecurityLimitInformation = 5
) )
@@ -3566,38 +3343,3 @@ type BLOB struct {
Size uint32 Size uint32
BlobData *byte BlobData *byte
} }
type ComStat struct {
Flags uint32
CBInQue uint32
CBOutQue uint32
}
type DCB struct {
DCBlength uint32
BaudRate uint32
Flags uint32
wReserved uint16
XonLim uint16
XoffLim uint16
ByteSize uint8
Parity uint8
StopBits uint8
XonChar byte
XoffChar byte
ErrorChar byte
EofChar byte
EvtChar byte
wReserved1 uint16
}
// Keyboard Layout Flags.
// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadkeyboardlayoutw
const (
KLF_ACTIVATE = 0x00000001
KLF_SUBSTITUTE_OK = 0x00000002
KLF_REORDER = 0x00000008
KLF_REPLACELANG = 0x00000010
KLF_NOTELLSHELL = 0x00000080
KLF_SETFORPROCESS = 0x00000100
)

View File

@@ -55,7 +55,6 @@ var (
moduser32 = NewLazySystemDLL("user32.dll") moduser32 = NewLazySystemDLL("user32.dll")
moduserenv = NewLazySystemDLL("userenv.dll") moduserenv = NewLazySystemDLL("userenv.dll")
modversion = NewLazySystemDLL("version.dll") modversion = NewLazySystemDLL("version.dll")
modwinmm = NewLazySystemDLL("winmm.dll")
modwintrust = NewLazySystemDLL("wintrust.dll") modwintrust = NewLazySystemDLL("wintrust.dll")
modws2_32 = NewLazySystemDLL("ws2_32.dll") modws2_32 = NewLazySystemDLL("ws2_32.dll")
modwtsapi32 = NewLazySystemDLL("wtsapi32.dll") modwtsapi32 = NewLazySystemDLL("wtsapi32.dll")
@@ -87,11 +86,9 @@ var (
procDeleteService = modadvapi32.NewProc("DeleteService") procDeleteService = modadvapi32.NewProc("DeleteService")
procDeregisterEventSource = modadvapi32.NewProc("DeregisterEventSource") procDeregisterEventSource = modadvapi32.NewProc("DeregisterEventSource")
procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx") procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx")
procEnumDependentServicesW = modadvapi32.NewProc("EnumDependentServicesW")
procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW") procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW")
procEqualSid = modadvapi32.NewProc("EqualSid") procEqualSid = modadvapi32.NewProc("EqualSid")
procFreeSid = modadvapi32.NewProc("FreeSid") procFreeSid = modadvapi32.NewProc("FreeSid")
procGetAce = modadvapi32.NewProc("GetAce")
procGetLengthSid = modadvapi32.NewProc("GetLengthSid") procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
procGetNamedSecurityInfoW = modadvapi32.NewProc("GetNamedSecurityInfoW") procGetNamedSecurityInfoW = modadvapi32.NewProc("GetNamedSecurityInfoW")
procGetSecurityDescriptorControl = modadvapi32.NewProc("GetSecurityDescriptorControl") procGetSecurityDescriptorControl = modadvapi32.NewProc("GetSecurityDescriptorControl")
@@ -181,23 +178,14 @@ var (
procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree") procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute") procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute")
procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute") procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
procCancelMibChangeNotify2 = modiphlpapi.NewProc("CancelMibChangeNotify2")
procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo") procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
procGetBestInterfaceEx = modiphlpapi.NewProc("GetBestInterfaceEx") procGetBestInterfaceEx = modiphlpapi.NewProc("GetBestInterfaceEx")
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry") procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
procGetIfEntry2Ex = modiphlpapi.NewProc("GetIfEntry2Ex")
procGetUnicastIpAddressEntry = modiphlpapi.NewProc("GetUnicastIpAddressEntry")
procNotifyIpInterfaceChange = modiphlpapi.NewProc("NotifyIpInterfaceChange")
procNotifyUnicastIpAddressChange = modiphlpapi.NewProc("NotifyUnicastIpAddressChange")
procAddDllDirectory = modkernel32.NewProc("AddDllDirectory")
procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject") procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject")
procCancelIo = modkernel32.NewProc("CancelIo") procCancelIo = modkernel32.NewProc("CancelIo")
procCancelIoEx = modkernel32.NewProc("CancelIoEx") procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procClearCommBreak = modkernel32.NewProc("ClearCommBreak")
procClearCommError = modkernel32.NewProc("ClearCommError")
procCloseHandle = modkernel32.NewProc("CloseHandle") procCloseHandle = modkernel32.NewProc("CloseHandle")
procClosePseudoConsole = modkernel32.NewProc("ClosePseudoConsole")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW") procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
procCreateEventExW = modkernel32.NewProc("CreateEventExW") procCreateEventExW = modkernel32.NewProc("CreateEventExW")
@@ -212,7 +200,6 @@ var (
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procCreatePipe = modkernel32.NewProc("CreatePipe") procCreatePipe = modkernel32.NewProc("CreatePipe")
procCreateProcessW = modkernel32.NewProc("CreateProcessW") procCreateProcessW = modkernel32.NewProc("CreateProcessW")
procCreatePseudoConsole = modkernel32.NewProc("CreatePseudoConsole")
procCreateSymbolicLinkW = modkernel32.NewProc("CreateSymbolicLinkW") procCreateSymbolicLinkW = modkernel32.NewProc("CreateSymbolicLinkW")
procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot") procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot")
procDefineDosDeviceW = modkernel32.NewProc("DefineDosDeviceW") procDefineDosDeviceW = modkernel32.NewProc("DefineDosDeviceW")
@@ -220,9 +207,7 @@ var (
procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList") procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList")
procDeleteVolumeMountPointW = modkernel32.NewProc("DeleteVolumeMountPointW") procDeleteVolumeMountPointW = modkernel32.NewProc("DeleteVolumeMountPointW")
procDeviceIoControl = modkernel32.NewProc("DeviceIoControl") procDeviceIoControl = modkernel32.NewProc("DeviceIoControl")
procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe")
procDuplicateHandle = modkernel32.NewProc("DuplicateHandle") procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
procEscapeCommFunction = modkernel32.NewProc("EscapeCommFunction")
procExitProcess = modkernel32.NewProc("ExitProcess") procExitProcess = modkernel32.NewProc("ExitProcess")
procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW") procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
procFindClose = modkernel32.NewProc("FindClose") procFindClose = modkernel32.NewProc("FindClose")
@@ -246,15 +231,11 @@ var (
procGenerateConsoleCtrlEvent = modkernel32.NewProc("GenerateConsoleCtrlEvent") procGenerateConsoleCtrlEvent = modkernel32.NewProc("GenerateConsoleCtrlEvent")
procGetACP = modkernel32.NewProc("GetACP") procGetACP = modkernel32.NewProc("GetACP")
procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount") procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount")
procGetCommModemStatus = modkernel32.NewProc("GetCommModemStatus")
procGetCommState = modkernel32.NewProc("GetCommState")
procGetCommTimeouts = modkernel32.NewProc("GetCommTimeouts") procGetCommTimeouts = modkernel32.NewProc("GetCommTimeouts")
procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
procGetComputerNameW = modkernel32.NewProc("GetComputerNameW") procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
procGetConsoleCP = modkernel32.NewProc("GetConsoleCP")
procGetConsoleMode = modkernel32.NewProc("GetConsoleMode") procGetConsoleMode = modkernel32.NewProc("GetConsoleMode")
procGetConsoleOutputCP = modkernel32.NewProc("GetConsoleOutputCP")
procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo") procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo")
procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW") procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
procGetCurrentProcessId = modkernel32.NewProc("GetCurrentProcessId") procGetCurrentProcessId = modkernel32.NewProc("GetCurrentProcessId")
@@ -268,7 +249,6 @@ var (
procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW") procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle") procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx") procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
procGetFileTime = modkernel32.NewProc("GetFileTime")
procGetFileType = modkernel32.NewProc("GetFileType") procGetFileType = modkernel32.NewProc("GetFileType")
procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW") procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW")
procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW") procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
@@ -280,10 +260,8 @@ var (
procGetMaximumProcessorCount = modkernel32.NewProc("GetMaximumProcessorCount") procGetMaximumProcessorCount = modkernel32.NewProc("GetMaximumProcessorCount")
procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW")
procGetModuleHandleExW = modkernel32.NewProc("GetModuleHandleExW") procGetModuleHandleExW = modkernel32.NewProc("GetModuleHandleExW")
procGetNamedPipeClientProcessId = modkernel32.NewProc("GetNamedPipeClientProcessId")
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
procGetNamedPipeServerProcessId = modkernel32.NewProc("GetNamedPipeServerProcessId")
procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult") procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult")
procGetPriorityClass = modkernel32.NewProc("GetPriorityClass") procGetPriorityClass = modkernel32.NewProc("GetPriorityClass")
procGetProcAddress = modkernel32.NewProc("GetProcAddress") procGetProcAddress = modkernel32.NewProc("GetProcAddress")
@@ -338,7 +316,6 @@ var (
procProcess32NextW = modkernel32.NewProc("Process32NextW") procProcess32NextW = modkernel32.NewProc("Process32NextW")
procProcessIdToSessionId = modkernel32.NewProc("ProcessIdToSessionId") procProcessIdToSessionId = modkernel32.NewProc("ProcessIdToSessionId")
procPulseEvent = modkernel32.NewProc("PulseEvent") procPulseEvent = modkernel32.NewProc("PulseEvent")
procPurgeComm = modkernel32.NewProc("PurgeComm")
procQueryDosDeviceW = modkernel32.NewProc("QueryDosDeviceW") procQueryDosDeviceW = modkernel32.NewProc("QueryDosDeviceW")
procQueryFullProcessImageNameW = modkernel32.NewProc("QueryFullProcessImageNameW") procQueryFullProcessImageNameW = modkernel32.NewProc("QueryFullProcessImageNameW")
procQueryInformationJobObject = modkernel32.NewProc("QueryInformationJobObject") procQueryInformationJobObject = modkernel32.NewProc("QueryInformationJobObject")
@@ -348,18 +325,11 @@ var (
procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory") procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory")
procReleaseMutex = modkernel32.NewProc("ReleaseMutex") procReleaseMutex = modkernel32.NewProc("ReleaseMutex")
procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW") procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
procRemoveDllDirectory = modkernel32.NewProc("RemoveDllDirectory")
procResetEvent = modkernel32.NewProc("ResetEvent") procResetEvent = modkernel32.NewProc("ResetEvent")
procResizePseudoConsole = modkernel32.NewProc("ResizePseudoConsole")
procResumeThread = modkernel32.NewProc("ResumeThread") procResumeThread = modkernel32.NewProc("ResumeThread")
procSetCommBreak = modkernel32.NewProc("SetCommBreak")
procSetCommMask = modkernel32.NewProc("SetCommMask")
procSetCommState = modkernel32.NewProc("SetCommState")
procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts") procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts")
procSetConsoleCP = modkernel32.NewProc("SetConsoleCP")
procSetConsoleCursorPosition = modkernel32.NewProc("SetConsoleCursorPosition") procSetConsoleCursorPosition = modkernel32.NewProc("SetConsoleCursorPosition")
procSetConsoleMode = modkernel32.NewProc("SetConsoleMode") procSetConsoleMode = modkernel32.NewProc("SetConsoleMode")
procSetConsoleOutputCP = modkernel32.NewProc("SetConsoleOutputCP")
procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW") procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories") procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories")
procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW") procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW")
@@ -372,7 +342,6 @@ var (
procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle") procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
procSetFilePointer = modkernel32.NewProc("SetFilePointer") procSetFilePointer = modkernel32.NewProc("SetFilePointer")
procSetFileTime = modkernel32.NewProc("SetFileTime") procSetFileTime = modkernel32.NewProc("SetFileTime")
procSetFileValidData = modkernel32.NewProc("SetFileValidData")
procSetHandleInformation = modkernel32.NewProc("SetHandleInformation") procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
procSetInformationJobObject = modkernel32.NewProc("SetInformationJobObject") procSetInformationJobObject = modkernel32.NewProc("SetInformationJobObject")
procSetNamedPipeHandleState = modkernel32.NewProc("SetNamedPipeHandleState") procSetNamedPipeHandleState = modkernel32.NewProc("SetNamedPipeHandleState")
@@ -383,7 +352,6 @@ var (
procSetStdHandle = modkernel32.NewProc("SetStdHandle") procSetStdHandle = modkernel32.NewProc("SetStdHandle")
procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW") procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW")
procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW") procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW")
procSetupComm = modkernel32.NewProc("SetupComm")
procSizeofResource = modkernel32.NewProc("SizeofResource") procSizeofResource = modkernel32.NewProc("SizeofResource")
procSleepEx = modkernel32.NewProc("SleepEx") procSleepEx = modkernel32.NewProc("SleepEx")
procTerminateJobObject = modkernel32.NewProc("TerminateJobObject") procTerminateJobObject = modkernel32.NewProc("TerminateJobObject")
@@ -402,7 +370,6 @@ var (
procVirtualQueryEx = modkernel32.NewProc("VirtualQueryEx") procVirtualQueryEx = modkernel32.NewProc("VirtualQueryEx")
procVirtualUnlock = modkernel32.NewProc("VirtualUnlock") procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
procWTSGetActiveConsoleSessionId = modkernel32.NewProc("WTSGetActiveConsoleSessionId") procWTSGetActiveConsoleSessionId = modkernel32.NewProc("WTSGetActiveConsoleSessionId")
procWaitCommEvent = modkernel32.NewProc("WaitCommEvent")
procWaitForMultipleObjects = modkernel32.NewProc("WaitForMultipleObjects") procWaitForMultipleObjects = modkernel32.NewProc("WaitForMultipleObjects")
procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject") procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
procWriteConsoleW = modkernel32.NewProc("WriteConsoleW") procWriteConsoleW = modkernel32.NewProc("WriteConsoleW")
@@ -413,7 +380,6 @@ var (
procTransmitFile = modmswsock.NewProc("TransmitFile") procTransmitFile = modmswsock.NewProc("TransmitFile")
procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree") procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation") procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation")
procNetUserEnum = modnetapi32.NewProc("NetUserEnum")
procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
procNtCreateFile = modntdll.NewProc("NtCreateFile") procNtCreateFile = modntdll.NewProc("NtCreateFile")
procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile") procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile")
@@ -489,24 +455,18 @@ var (
procGetDesktopWindow = moduser32.NewProc("GetDesktopWindow") procGetDesktopWindow = moduser32.NewProc("GetDesktopWindow")
procGetForegroundWindow = moduser32.NewProc("GetForegroundWindow") procGetForegroundWindow = moduser32.NewProc("GetForegroundWindow")
procGetGUIThreadInfo = moduser32.NewProc("GetGUIThreadInfo") procGetGUIThreadInfo = moduser32.NewProc("GetGUIThreadInfo")
procGetKeyboardLayout = moduser32.NewProc("GetKeyboardLayout")
procGetShellWindow = moduser32.NewProc("GetShellWindow") procGetShellWindow = moduser32.NewProc("GetShellWindow")
procGetWindowThreadProcessId = moduser32.NewProc("GetWindowThreadProcessId") procGetWindowThreadProcessId = moduser32.NewProc("GetWindowThreadProcessId")
procIsWindow = moduser32.NewProc("IsWindow") procIsWindow = moduser32.NewProc("IsWindow")
procIsWindowUnicode = moduser32.NewProc("IsWindowUnicode") procIsWindowUnicode = moduser32.NewProc("IsWindowUnicode")
procIsWindowVisible = moduser32.NewProc("IsWindowVisible") procIsWindowVisible = moduser32.NewProc("IsWindowVisible")
procLoadKeyboardLayoutW = moduser32.NewProc("LoadKeyboardLayoutW")
procMessageBoxW = moduser32.NewProc("MessageBoxW") procMessageBoxW = moduser32.NewProc("MessageBoxW")
procToUnicodeEx = moduser32.NewProc("ToUnicodeEx")
procUnloadKeyboardLayout = moduser32.NewProc("UnloadKeyboardLayout")
procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock") procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock")
procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock") procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock")
procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
procGetFileVersionInfoSizeW = modversion.NewProc("GetFileVersionInfoSizeW") procGetFileVersionInfoSizeW = modversion.NewProc("GetFileVersionInfoSizeW")
procGetFileVersionInfoW = modversion.NewProc("GetFileVersionInfoW") procGetFileVersionInfoW = modversion.NewProc("GetFileVersionInfoW")
procVerQueryValueW = modversion.NewProc("VerQueryValueW") procVerQueryValueW = modversion.NewProc("VerQueryValueW")
proctimeBeginPeriod = modwinmm.NewProc("timeBeginPeriod")
proctimeEndPeriod = modwinmm.NewProc("timeEndPeriod")
procWinVerifyTrustEx = modwintrust.NewProc("WinVerifyTrustEx") procWinVerifyTrustEx = modwintrust.NewProc("WinVerifyTrustEx")
procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW") procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW")
procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW") procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW")
@@ -774,14 +734,6 @@ func DuplicateTokenEx(existingToken Token, desiredAccess uint32, tokenAttributes
return return
} }
func EnumDependentServices(service Handle, activityState uint32, services *ENUM_SERVICE_STATUS, buffSize uint32, bytesNeeded *uint32, servicesReturned *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procEnumDependentServicesW.Addr(), 6, uintptr(service), uintptr(activityState), uintptr(unsafe.Pointer(services)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), uintptr(unsafe.Pointer(servicesReturned)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) { func EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) {
r1, _, e1 := syscall.Syscall12(procEnumServicesStatusExW.Addr(), 10, uintptr(mgr), uintptr(infoLevel), uintptr(serviceType), uintptr(serviceState), uintptr(unsafe.Pointer(services)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), uintptr(unsafe.Pointer(servicesReturned)), uintptr(unsafe.Pointer(resumeHandle)), uintptr(unsafe.Pointer(groupName)), 0, 0) r1, _, e1 := syscall.Syscall12(procEnumServicesStatusExW.Addr(), 10, uintptr(mgr), uintptr(infoLevel), uintptr(serviceType), uintptr(serviceState), uintptr(unsafe.Pointer(services)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), uintptr(unsafe.Pointer(servicesReturned)), uintptr(unsafe.Pointer(resumeHandle)), uintptr(unsafe.Pointer(groupName)), 0, 0)
if r1 == 0 { if r1 == 0 {
@@ -804,14 +756,6 @@ func FreeSid(sid *SID) (err error) {
return return
} }
func GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (err error) {
r1, _, e1 := syscall.Syscall(procGetAce.Addr(), 3, uintptr(unsafe.Pointer(acl)), uintptr(aceIndex), uintptr(unsafe.Pointer(pAce)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func GetLengthSid(sid *SID) (len uint32) { func GetLengthSid(sid *SID) (len uint32) {
r0, _, _ := syscall.Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) r0, _, _ := syscall.Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
len = uint32(r0) len = uint32(r0)
@@ -1613,14 +1557,6 @@ func DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, si
return return
} }
func CancelMibChangeNotify2(notificationHandle Handle) (errcode error) {
r0, _, _ := syscall.Syscall(procCancelMibChangeNotify2.Addr(), 1, uintptr(notificationHandle), 0, 0)
if r0 != 0 {
errcode = syscall.Errno(r0)
}
return
}
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) { func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0) r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0)
if r0 != 0 { if r0 != 0 {
@@ -1653,55 +1589,6 @@ func GetIfEntry(pIfRow *MibIfRow) (errcode error) {
return return
} }
func GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) {
r0, _, _ := syscall.Syscall(procGetIfEntry2Ex.Addr(), 2, uintptr(level), uintptr(unsafe.Pointer(row)), 0)
if r0 != 0 {
errcode = syscall.Errno(r0)
}
return
}
func GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) {
r0, _, _ := syscall.Syscall(procGetUnicastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0)
if r0 != 0 {
errcode = syscall.Errno(r0)
}
return
}
func NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
var _p0 uint32
if initialNotification {
_p0 = 1
}
r0, _, _ := syscall.Syscall6(procNotifyIpInterfaceChange.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0)
if r0 != 0 {
errcode = syscall.Errno(r0)
}
return
}
func NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
var _p0 uint32
if initialNotification {
_p0 = 1
}
r0, _, _ := syscall.Syscall6(procNotifyUnicastIpAddressChange.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0)
if r0 != 0 {
errcode = syscall.Errno(r0)
}
return
}
func AddDllDirectory(path *uint16) (cookie uintptr, err error) {
r0, _, e1 := syscall.Syscall(procAddDllDirectory.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
cookie = uintptr(r0)
if cookie == 0 {
err = errnoErr(e1)
}
return
}
func AssignProcessToJobObject(job Handle, process Handle) (err error) { func AssignProcessToJobObject(job Handle, process Handle) (err error) {
r1, _, e1 := syscall.Syscall(procAssignProcessToJobObject.Addr(), 2, uintptr(job), uintptr(process), 0) r1, _, e1 := syscall.Syscall(procAssignProcessToJobObject.Addr(), 2, uintptr(job), uintptr(process), 0)
if r1 == 0 { if r1 == 0 {
@@ -1726,22 +1613,6 @@ func CancelIoEx(s Handle, o *Overlapped) (err error) {
return return
} }
func ClearCommBreak(handle Handle) (err error) {
r1, _, e1 := syscall.Syscall(procClearCommBreak.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func ClearCommError(handle Handle, lpErrors *uint32, lpStat *ComStat) (err error) {
r1, _, e1 := syscall.Syscall(procClearCommError.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(lpErrors)), uintptr(unsafe.Pointer(lpStat)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func CloseHandle(handle Handle) (err error) { func CloseHandle(handle Handle) (err error) {
r1, _, e1 := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0) r1, _, e1 := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 { if r1 == 0 {
@@ -1750,11 +1621,6 @@ func CloseHandle(handle Handle) (err error) {
return return
} }
func ClosePseudoConsole(console Handle) {
syscall.Syscall(procClosePseudoConsole.Addr(), 1, uintptr(console), 0, 0)
return
}
func ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error) { func ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(overlapped)), 0) r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(overlapped)), 0)
if r1 == 0 { if r1 == 0 {
@@ -1884,14 +1750,6 @@ func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityA
return return
} }
func createPseudoConsole(size uint32, in Handle, out Handle, flags uint32, pconsole *Handle) (hr error) {
r0, _, _ := syscall.Syscall6(procCreatePseudoConsole.Addr(), 5, uintptr(size), uintptr(in), uintptr(out), uintptr(flags), uintptr(unsafe.Pointer(pconsole)), 0)
if r0 != 0 {
hr = syscall.Errno(r0)
}
return
}
func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) { func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) {
r1, _, e1 := syscall.Syscall(procCreateSymbolicLinkW.Addr(), 3, uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags)) r1, _, e1 := syscall.Syscall(procCreateSymbolicLinkW.Addr(), 3, uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags))
if r1&0xff == 0 { if r1&0xff == 0 {
@@ -1946,14 +1804,6 @@ func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBuff
return return
} }
func DisconnectNamedPipe(pipe Handle) (err error) {
r1, _, e1 := syscall.Syscall(procDisconnectNamedPipe.Addr(), 1, uintptr(pipe), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) { func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) {
var _p0 uint32 var _p0 uint32
if bInheritHandle { if bInheritHandle {
@@ -1966,14 +1816,6 @@ func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetP
return return
} }
func EscapeCommFunction(handle Handle, dwFunc uint32) (err error) {
r1, _, e1 := syscall.Syscall(procEscapeCommFunction.Addr(), 2, uintptr(handle), uintptr(dwFunc), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func ExitProcess(exitcode uint32) { func ExitProcess(exitcode uint32) {
syscall.Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0) syscall.Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0)
return return
@@ -2175,22 +2017,6 @@ func GetActiveProcessorCount(groupNumber uint16) (ret uint32) {
return return
} }
func GetCommModemStatus(handle Handle, lpModemStat *uint32) (err error) {
r1, _, e1 := syscall.Syscall(procGetCommModemStatus.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpModemStat)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func GetCommState(handle Handle, lpDCB *DCB) (err error) {
r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpDCB)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { func GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) {
r1, _, e1 := syscall.Syscall(procGetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) r1, _, e1 := syscall.Syscall(procGetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0)
if r1 == 0 { if r1 == 0 {
@@ -2221,15 +2047,6 @@ func GetComputerName(buf *uint16, n *uint32) (err error) {
return return
} }
func GetConsoleCP() (cp uint32, err error) {
r0, _, e1 := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0)
cp = uint32(r0)
if cp == 0 {
err = errnoErr(e1)
}
return
}
func GetConsoleMode(console Handle, mode *uint32) (err error) { func GetConsoleMode(console Handle, mode *uint32) (err error) {
r1, _, e1 := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0) r1, _, e1 := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0)
if r1 == 0 { if r1 == 0 {
@@ -2238,15 +2055,6 @@ func GetConsoleMode(console Handle, mode *uint32) (err error) {
return return
} }
func GetConsoleOutputCP() (cp uint32, err error) {
r0, _, e1 := syscall.Syscall(procGetConsoleOutputCP.Addr(), 0, 0, 0, 0)
cp = uint32(r0)
if cp == 0 {
err = errnoErr(e1)
}
return
}
func GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) { func GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) {
r1, _, e1 := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(info)), 0) r1, _, e1 := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(info)), 0)
if r1 == 0 { if r1 == 0 {
@@ -2349,14 +2157,6 @@ func GetFileInformationByHandleEx(handle Handle, class uint32, outBuffer *byte,
return return
} }
func GetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) {
r1, _, e1 := syscall.Syscall6(procGetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func GetFileType(filehandle Handle) (n uint32, err error) { func GetFileType(filehandle Handle) (n uint32, err error) {
r0, _, e1 := syscall.Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0) r0, _, e1 := syscall.Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0)
n = uint32(r0) n = uint32(r0)
@@ -2448,14 +2248,6 @@ func GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err er
return return
} }
func GetNamedPipeClientProcessId(pipe Handle, clientProcessID *uint32) (err error) {
r1, _, e1 := syscall.Syscall(procGetNamedPipeClientProcessId.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(clientProcessID)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { func GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
if r1 == 0 { if r1 == 0 {
@@ -2472,14 +2264,6 @@ func GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint3
return return
} }
func GetNamedPipeServerProcessId(pipe Handle, serverProcessID *uint32) (err error) {
r1, _, e1 := syscall.Syscall(procGetNamedPipeServerProcessId.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(serverProcessID)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wait bool) (err error) { func GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wait bool) (err error) {
var _p0 uint32 var _p0 uint32
if wait { if wait {
@@ -2574,8 +2358,11 @@ func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uin
return return
} }
func getStartupInfo(startupInfo *StartupInfo) { func GetStartupInfo(startupInfo *StartupInfo) (err error) {
syscall.Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0) r1, _, e1 := syscall.Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return return
} }
@@ -2977,14 +2764,6 @@ func PulseEvent(event Handle) (err error) {
return return
} }
func PurgeComm(handle Handle, dwFlags uint32) (err error) {
r1, _, e1 := syscall.Syscall(procPurgeComm.Addr(), 2, uintptr(handle), uintptr(dwFlags), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint32, err error) { func QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint32, err error) {
r0, _, e1 := syscall.Syscall(procQueryDosDeviceW.Addr(), 3, uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath)), uintptr(max)) r0, _, e1 := syscall.Syscall(procQueryDosDeviceW.Addr(), 3, uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath)), uintptr(max))
n = uint32(r0) n = uint32(r0)
@@ -3066,14 +2845,6 @@ func RemoveDirectory(path *uint16) (err error) {
return return
} }
func RemoveDllDirectory(cookie uintptr) (err error) {
r1, _, e1 := syscall.Syscall(procRemoveDllDirectory.Addr(), 1, uintptr(cookie), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func ResetEvent(event Handle) (err error) { func ResetEvent(event Handle) (err error) {
r1, _, e1 := syscall.Syscall(procResetEvent.Addr(), 1, uintptr(event), 0, 0) r1, _, e1 := syscall.Syscall(procResetEvent.Addr(), 1, uintptr(event), 0, 0)
if r1 == 0 { if r1 == 0 {
@@ -3082,14 +2853,6 @@ func ResetEvent(event Handle) (err error) {
return return
} }
func resizePseudoConsole(pconsole Handle, size uint32) (hr error) {
r0, _, _ := syscall.Syscall(procResizePseudoConsole.Addr(), 2, uintptr(pconsole), uintptr(size), 0)
if r0 != 0 {
hr = syscall.Errno(r0)
}
return
}
func ResumeThread(thread Handle) (ret uint32, err error) { func ResumeThread(thread Handle) (ret uint32, err error) {
r0, _, e1 := syscall.Syscall(procResumeThread.Addr(), 1, uintptr(thread), 0, 0) r0, _, e1 := syscall.Syscall(procResumeThread.Addr(), 1, uintptr(thread), 0, 0)
ret = uint32(r0) ret = uint32(r0)
@@ -3099,30 +2862,6 @@ func ResumeThread(thread Handle) (ret uint32, err error) {
return return
} }
func SetCommBreak(handle Handle) (err error) {
r1, _, e1 := syscall.Syscall(procSetCommBreak.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetCommMask(handle Handle, dwEvtMask uint32) (err error) {
r1, _, e1 := syscall.Syscall(procSetCommMask.Addr(), 2, uintptr(handle), uintptr(dwEvtMask), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetCommState(handle Handle, lpDCB *DCB) (err error) {
r1, _, e1 := syscall.Syscall(procSetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpDCB)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) {
r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0)
if r1 == 0 { if r1 == 0 {
@@ -3131,14 +2870,6 @@ func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) {
return return
} }
func SetConsoleCP(cp uint32) (err error) {
r1, _, e1 := syscall.Syscall(procSetConsoleCP.Addr(), 1, uintptr(cp), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func setConsoleCursorPosition(console Handle, position uint32) (err error) { func setConsoleCursorPosition(console Handle, position uint32) (err error) {
r1, _, e1 := syscall.Syscall(procSetConsoleCursorPosition.Addr(), 2, uintptr(console), uintptr(position), 0) r1, _, e1 := syscall.Syscall(procSetConsoleCursorPosition.Addr(), 2, uintptr(console), uintptr(position), 0)
if r1 == 0 { if r1 == 0 {
@@ -3155,14 +2886,6 @@ func SetConsoleMode(console Handle, mode uint32) (err error) {
return return
} }
func SetConsoleOutputCP(cp uint32) (err error) {
r1, _, e1 := syscall.Syscall(procSetConsoleOutputCP.Addr(), 1, uintptr(cp), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetCurrentDirectory(path *uint16) (err error) { func SetCurrentDirectory(path *uint16) (err error) {
r1, _, e1 := syscall.Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) r1, _, e1 := syscall.Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if r1 == 0 { if r1 == 0 {
@@ -3267,14 +2990,6 @@ func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetim
return return
} }
func SetFileValidData(handle Handle, validDataLength int64) (err error) {
r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) { func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) {
r1, _, e1 := syscall.Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags)) r1, _, e1 := syscall.Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags))
if r1 == 0 { if r1 == 0 {
@@ -3360,14 +3075,6 @@ func SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err erro
return return
} }
func SetupComm(handle Handle, dwInQueue uint32, dwOutQueue uint32) (err error) {
r1, _, e1 := syscall.Syscall(procSetupComm.Addr(), 3, uintptr(handle), uintptr(dwInQueue), uintptr(dwOutQueue))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SizeofResource(module Handle, resInfo Handle) (size uint32, err error) { func SizeofResource(module Handle, resInfo Handle) (size uint32, err error) {
r0, _, e1 := syscall.Syscall(procSizeofResource.Addr(), 2, uintptr(module), uintptr(resInfo), 0) r0, _, e1 := syscall.Syscall(procSizeofResource.Addr(), 2, uintptr(module), uintptr(resInfo), 0)
size = uint32(r0) size = uint32(r0)
@@ -3514,14 +3221,6 @@ func WTSGetActiveConsoleSessionId() (sessionID uint32) {
return return
} }
func WaitCommEvent(handle Handle, lpEvtMask *uint32, lpOverlapped *Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procWaitCommEvent.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(lpEvtMask)), uintptr(unsafe.Pointer(lpOverlapped)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) { func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) {
var _p0 uint32 var _p0 uint32
if waitAll { if waitAll {
@@ -3609,14 +3308,6 @@ func NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (nete
return return
} }
func NetUserEnum(serverName *uint16, level uint32, filter uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32, resumeHandle *uint32) (neterr error) {
r0, _, _ := syscall.Syscall9(procNetUserEnum.Addr(), 8, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(filter), uintptr(unsafe.Pointer(buf)), uintptr(prefMaxLen), uintptr(unsafe.Pointer(entriesRead)), uintptr(unsafe.Pointer(totalEntries)), uintptr(unsafe.Pointer(resumeHandle)), 0)
if r0 != 0 {
neterr = syscall.Errno(r0)
}
return
}
func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) { func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) {
r0, _, _ := syscall.Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0) r0, _, _ := syscall.Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0)
if r0 != 0 { if r0 != 0 {
@@ -3816,8 +3507,12 @@ func EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *u
return return
} }
func enumProcesses(processIds *uint32, nSize uint32, bytesReturned *uint32) (err error) { func EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) {
r1, _, e1 := syscall.Syscall(procEnumProcesses.Addr(), 3, uintptr(unsafe.Pointer(processIds)), uintptr(nSize), uintptr(unsafe.Pointer(bytesReturned))) var _p0 *uint32
if len(processIds) > 0 {
_p0 = &processIds[0]
}
r1, _, e1 := syscall.Syscall(procEnumProcesses.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(len(processIds)), uintptr(unsafe.Pointer(bytesReturned)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@@ -4120,9 +3815,9 @@ func setupUninstallOEMInf(infFileName *uint16, flags SUOI, reserved uintptr) (er
return return
} }
func commandLineToArgv(cmd *uint16, argc *int32) (argv **uint16, err error) { func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) {
r0, _, e1 := syscall.Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0) r0, _, e1 := syscall.Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0)
argv = (**uint16)(unsafe.Pointer(r0)) argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0))
if argv == nil { if argv == nil {
err = errnoErr(e1) err = errnoErr(e1)
} }
@@ -4195,12 +3890,6 @@ func GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) {
return return
} }
func GetKeyboardLayout(tid uint32) (hkl Handle) {
r0, _, _ := syscall.Syscall(procGetKeyboardLayout.Addr(), 1, uintptr(tid), 0, 0)
hkl = Handle(r0)
return
}
func GetShellWindow() (shellWindow HWND) { func GetShellWindow() (shellWindow HWND) {
r0, _, _ := syscall.Syscall(procGetShellWindow.Addr(), 0, 0, 0, 0) r0, _, _ := syscall.Syscall(procGetShellWindow.Addr(), 0, 0, 0, 0)
shellWindow = HWND(r0) shellWindow = HWND(r0)
@@ -4234,15 +3923,6 @@ func IsWindowVisible(hwnd HWND) (isVisible bool) {
return return
} }
func LoadKeyboardLayout(name *uint16, flags uint32) (hkl Handle, err error) {
r0, _, e1 := syscall.Syscall(procLoadKeyboardLayoutW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(flags), 0)
hkl = Handle(r0)
if hkl == 0 {
err = errnoErr(e1)
}
return
}
func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) { func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) {
r0, _, e1 := syscall.Syscall6(procMessageBoxW.Addr(), 4, uintptr(hwnd), uintptr(unsafe.Pointer(text)), uintptr(unsafe.Pointer(caption)), uintptr(boxtype), 0, 0) r0, _, e1 := syscall.Syscall6(procMessageBoxW.Addr(), 4, uintptr(hwnd), uintptr(unsafe.Pointer(text)), uintptr(unsafe.Pointer(caption)), uintptr(boxtype), 0, 0)
ret = int32(r0) ret = int32(r0)
@@ -4252,20 +3932,6 @@ func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret i
return return
} }
func ToUnicodeEx(vkey uint32, scancode uint32, keystate *byte, pwszBuff *uint16, cchBuff int32, flags uint32, hkl Handle) (ret int32) {
r0, _, _ := syscall.Syscall9(procToUnicodeEx.Addr(), 7, uintptr(vkey), uintptr(scancode), uintptr(unsafe.Pointer(keystate)), uintptr(unsafe.Pointer(pwszBuff)), uintptr(cchBuff), uintptr(flags), uintptr(hkl), 0, 0)
ret = int32(r0)
return
}
func UnloadKeyboardLayout(hkl Handle) (err error) {
r1, _, e1 := syscall.Syscall(procUnloadKeyboardLayout.Addr(), 1, uintptr(hkl), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) (err error) { func CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) (err error) {
var _p0 uint32 var _p0 uint32
if inheritExisting { if inheritExisting {
@@ -4346,22 +4012,6 @@ func _VerQueryValue(block unsafe.Pointer, subBlock *uint16, pointerToBufferPoint
return return
} }
func TimeBeginPeriod(period uint32) (err error) {
r1, _, e1 := syscall.Syscall(proctimeBeginPeriod.Addr(), 1, uintptr(period), 0, 0)
if r1 != 0 {
err = errnoErr(e1)
}
return
}
func TimeEndPeriod(period uint32) (err error) {
r1, _, e1 := syscall.Syscall(proctimeEndPeriod.Addr(), 1, uintptr(period), 0, 0)
if r1 != 0 {
err = errnoErr(e1)
}
return
}
func WinVerifyTrustEx(hwnd HWND, actionId *GUID, data *WinTrustData) (ret error) { func WinVerifyTrustEx(hwnd HWND, actionId *GUID, data *WinTrustData) (ret error) {
r0, _, _ := syscall.Syscall(procWinVerifyTrustEx.Addr(), 3, uintptr(hwnd), uintptr(unsafe.Pointer(actionId)), uintptr(unsafe.Pointer(data))) r0, _, _ := syscall.Syscall(procWinVerifyTrustEx.Addr(), 3, uintptr(hwnd), uintptr(unsafe.Pointer(actionId)), uintptr(unsafe.Pointer(data)))
if r0 != 0 { if r0 != 0 {

4
vendor/golang.org/x/text/LICENSE generated vendored
View File

@@ -1,4 +1,4 @@
Copyright 2009 The Go Authors. Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the in the documentation and/or other materials provided with the
distribution. distribution.
* Neither the name of Google LLC nor the names of its * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from contributors may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.

View File

@@ -790,226 +790,226 @@ const (
var coreTags = []language.CompactCoreInfo{ // 773 elements var coreTags = []language.CompactCoreInfo{ // 773 elements
// Entry 0 - 1F // Entry 0 - 1F
0x00000000, 0x01600000, 0x016000d3, 0x01600162, 0x00000000, 0x01600000, 0x016000d2, 0x01600161,
0x01c00000, 0x01c00052, 0x02100000, 0x02100081, 0x01c00000, 0x01c00052, 0x02100000, 0x02100080,
0x02700000, 0x02700070, 0x03a00000, 0x03a00001, 0x02700000, 0x0270006f, 0x03a00000, 0x03a00001,
0x03a00023, 0x03a00039, 0x03a00063, 0x03a00068, 0x03a00023, 0x03a00039, 0x03a00062, 0x03a00067,
0x03a0006c, 0x03a0006d, 0x03a0006e, 0x03a00098, 0x03a0006b, 0x03a0006c, 0x03a0006d, 0x03a00097,
0x03a0009c, 0x03a000a2, 0x03a000a9, 0x03a000ad, 0x03a0009b, 0x03a000a1, 0x03a000a8, 0x03a000ac,
0x03a000b1, 0x03a000ba, 0x03a000bb, 0x03a000ca, 0x03a000b0, 0x03a000b9, 0x03a000ba, 0x03a000c9,
0x03a000e2, 0x03a000ee, 0x03a000f4, 0x03a00109, 0x03a000e1, 0x03a000ed, 0x03a000f3, 0x03a00108,
// Entry 20 - 3F // Entry 20 - 3F
0x03a0010c, 0x03a00116, 0x03a00118, 0x03a0011d, 0x03a0010b, 0x03a00115, 0x03a00117, 0x03a0011c,
0x03a00121, 0x03a00129, 0x03a0015f, 0x04000000, 0x03a00120, 0x03a00128, 0x03a0015e, 0x04000000,
0x04300000, 0x0430009a, 0x04400000, 0x04400130, 0x04300000, 0x04300099, 0x04400000, 0x0440012f,
0x04800000, 0x0480006f, 0x05800000, 0x05820000, 0x04800000, 0x0480006e, 0x05800000, 0x05820000,
0x05820032, 0x0585b000, 0x0585b032, 0x05e00000, 0x05820032, 0x0585a000, 0x0585a032, 0x05e00000,
0x05e00052, 0x07100000, 0x07100047, 0x07500000, 0x05e00052, 0x07100000, 0x07100047, 0x07500000,
0x07500163, 0x07900000, 0x07900130, 0x07e00000, 0x07500162, 0x07900000, 0x0790012f, 0x07e00000,
0x07e00038, 0x08200000, 0x0a000000, 0x0a0000c4, 0x07e00038, 0x08200000, 0x0a000000, 0x0a0000c3,
// Entry 40 - 5F // Entry 40 - 5F
0x0a500000, 0x0a500035, 0x0a50009a, 0x0a900000, 0x0a500000, 0x0a500035, 0x0a500099, 0x0a900000,
0x0a900053, 0x0a90009a, 0x0b200000, 0x0b200079, 0x0a900053, 0x0a900099, 0x0b200000, 0x0b200078,
0x0b500000, 0x0b50009a, 0x0b700000, 0x0b720000, 0x0b500000, 0x0b500099, 0x0b700000, 0x0b720000,
0x0b720033, 0x0b75b000, 0x0b75b033, 0x0d700000, 0x0b720033, 0x0b75a000, 0x0b75a033, 0x0d700000,
0x0d700022, 0x0d70006f, 0x0d700079, 0x0d70009f, 0x0d700022, 0x0d70006e, 0x0d700078, 0x0d70009e,
0x0db00000, 0x0db00035, 0x0db0009a, 0x0dc00000, 0x0db00000, 0x0db00035, 0x0db00099, 0x0dc00000,
0x0dc00107, 0x0df00000, 0x0df00132, 0x0e500000, 0x0dc00106, 0x0df00000, 0x0df00131, 0x0e500000,
0x0e500136, 0x0e900000, 0x0e90009c, 0x0e90009d, 0x0e500135, 0x0e900000, 0x0e90009b, 0x0e90009c,
// Entry 60 - 7F // Entry 60 - 7F
0x0fa00000, 0x0fa0005f, 0x0fe00000, 0x0fe00107, 0x0fa00000, 0x0fa0005e, 0x0fe00000, 0x0fe00106,
0x10000000, 0x1000007c, 0x10100000, 0x10100064, 0x10000000, 0x1000007b, 0x10100000, 0x10100063,
0x10100083, 0x10800000, 0x108000a5, 0x10d00000, 0x10100082, 0x10800000, 0x108000a4, 0x10d00000,
0x10d0002e, 0x10d00036, 0x10d0004e, 0x10d00061, 0x10d0002e, 0x10d00036, 0x10d0004e, 0x10d00060,
0x10d0009f, 0x10d000b3, 0x10d000b8, 0x11700000, 0x10d0009e, 0x10d000b2, 0x10d000b7, 0x11700000,
0x117000d5, 0x11f00000, 0x11f00061, 0x12400000, 0x117000d4, 0x11f00000, 0x11f00060, 0x12400000,
0x12400052, 0x12800000, 0x12b00000, 0x12b00115, 0x12400052, 0x12800000, 0x12b00000, 0x12b00114,
0x12d00000, 0x12d00043, 0x12f00000, 0x12f000a5, 0x12d00000, 0x12d00043, 0x12f00000, 0x12f000a4,
// Entry 80 - 9F // Entry 80 - 9F
0x13000000, 0x13000081, 0x13000123, 0x13600000, 0x13000000, 0x13000080, 0x13000122, 0x13600000,
0x1360005e, 0x13600088, 0x13900000, 0x13900001, 0x1360005d, 0x13600087, 0x13900000, 0x13900001,
0x1390001a, 0x13900025, 0x13900026, 0x1390002d, 0x1390001a, 0x13900025, 0x13900026, 0x1390002d,
0x1390002e, 0x1390002f, 0x13900034, 0x13900036, 0x1390002e, 0x1390002f, 0x13900034, 0x13900036,
0x1390003a, 0x1390003d, 0x13900042, 0x13900046, 0x1390003a, 0x1390003d, 0x13900042, 0x13900046,
0x13900048, 0x13900049, 0x1390004a, 0x1390004e, 0x13900048, 0x13900049, 0x1390004a, 0x1390004e,
0x13900050, 0x13900052, 0x1390005d, 0x1390005e, 0x13900050, 0x13900052, 0x1390005c, 0x1390005d,
0x13900061, 0x13900062, 0x13900064, 0x13900065, 0x13900060, 0x13900061, 0x13900063, 0x13900064,
// Entry A0 - BF // Entry A0 - BF
0x1390006e, 0x13900073, 0x13900074, 0x13900075, 0x1390006d, 0x13900072, 0x13900073, 0x13900074,
0x13900076, 0x1390007c, 0x1390007d, 0x13900080, 0x13900075, 0x1390007b, 0x1390007c, 0x1390007f,
0x13900081, 0x13900082, 0x13900084, 0x1390008b, 0x13900080, 0x13900081, 0x13900083, 0x1390008a,
0x1390008d, 0x1390008e, 0x13900097, 0x13900098, 0x1390008c, 0x1390008d, 0x13900096, 0x13900097,
0x13900099, 0x1390009a, 0x1390009b, 0x139000a0, 0x13900098, 0x13900099, 0x1390009a, 0x1390009f,
0x139000a1, 0x139000a5, 0x139000a8, 0x139000aa, 0x139000a0, 0x139000a4, 0x139000a7, 0x139000a9,
0x139000ae, 0x139000b2, 0x139000b5, 0x139000b6, 0x139000ad, 0x139000b1, 0x139000b4, 0x139000b5,
0x139000c0, 0x139000c1, 0x139000c7, 0x139000c8, 0x139000bf, 0x139000c0, 0x139000c6, 0x139000c7,
// Entry C0 - DF // Entry C0 - DF
0x139000cb, 0x139000cc, 0x139000cd, 0x139000cf, 0x139000ca, 0x139000cb, 0x139000cc, 0x139000ce,
0x139000d1, 0x139000d3, 0x139000d6, 0x139000d7, 0x139000d0, 0x139000d2, 0x139000d5, 0x139000d6,
0x139000da, 0x139000de, 0x139000e0, 0x139000e1, 0x139000d9, 0x139000dd, 0x139000df, 0x139000e0,
0x139000e7, 0x139000e8, 0x139000e9, 0x139000ec, 0x139000e6, 0x139000e7, 0x139000e8, 0x139000eb,
0x139000ed, 0x139000f1, 0x13900108, 0x1390010a, 0x139000ec, 0x139000f0, 0x13900107, 0x13900109,
0x1390010b, 0x1390010c, 0x1390010d, 0x1390010e, 0x1390010a, 0x1390010b, 0x1390010c, 0x1390010d,
0x1390010f, 0x13900110, 0x13900113, 0x13900118, 0x1390010e, 0x1390010f, 0x13900112, 0x13900117,
0x1390011c, 0x1390011e, 0x13900120, 0x13900126, 0x1390011b, 0x1390011d, 0x1390011f, 0x13900125,
// Entry E0 - FF // Entry E0 - FF
0x1390012a, 0x1390012d, 0x1390012e, 0x13900130, 0x13900129, 0x1390012c, 0x1390012d, 0x1390012f,
0x13900132, 0x13900134, 0x13900136, 0x1390013a, 0x13900131, 0x13900133, 0x13900135, 0x13900139,
0x1390013d, 0x1390013e, 0x13900140, 0x13900143, 0x1390013c, 0x1390013d, 0x1390013f, 0x13900142,
0x13900162, 0x13900163, 0x13900165, 0x13c00000, 0x13900161, 0x13900162, 0x13900164, 0x13c00000,
0x13c00001, 0x13e00000, 0x13e0001f, 0x13e0002c, 0x13c00001, 0x13e00000, 0x13e0001f, 0x13e0002c,
0x13e0003f, 0x13e00041, 0x13e00048, 0x13e00051, 0x13e0003f, 0x13e00041, 0x13e00048, 0x13e00051,
0x13e00054, 0x13e00057, 0x13e0005a, 0x13e00066, 0x13e00054, 0x13e00056, 0x13e00059, 0x13e00065,
0x13e00069, 0x13e0006a, 0x13e0006f, 0x13e00087, 0x13e00068, 0x13e00069, 0x13e0006e, 0x13e00086,
// Entry 100 - 11F // Entry 100 - 11F
0x13e0008a, 0x13e00090, 0x13e00095, 0x13e000d0, 0x13e00089, 0x13e0008f, 0x13e00094, 0x13e000cf,
0x13e000d9, 0x13e000e3, 0x13e000e5, 0x13e000e8, 0x13e000d8, 0x13e000e2, 0x13e000e4, 0x13e000e7,
0x13e000ed, 0x13e000f2, 0x13e0011b, 0x13e00136, 0x13e000ec, 0x13e000f1, 0x13e0011a, 0x13e00135,
0x13e00137, 0x13e0013c, 0x14000000, 0x1400006b, 0x13e00136, 0x13e0013b, 0x14000000, 0x1400006a,
0x14500000, 0x1450006f, 0x14600000, 0x14600052, 0x14500000, 0x1450006e, 0x14600000, 0x14600052,
0x14800000, 0x14800024, 0x1480009d, 0x14e00000, 0x14800000, 0x14800024, 0x1480009c, 0x14e00000,
0x14e00052, 0x14e00085, 0x14e000ca, 0x14e00115, 0x14e00052, 0x14e00084, 0x14e000c9, 0x14e00114,
0x15100000, 0x15100073, 0x15300000, 0x153000e8, 0x15100000, 0x15100072, 0x15300000, 0x153000e7,
// Entry 120 - 13F // Entry 120 - 13F
0x15800000, 0x15800064, 0x15800077, 0x15e00000, 0x15800000, 0x15800063, 0x15800076, 0x15e00000,
0x15e00036, 0x15e00037, 0x15e0003a, 0x15e0003b, 0x15e00036, 0x15e00037, 0x15e0003a, 0x15e0003b,
0x15e0003c, 0x15e00049, 0x15e0004b, 0x15e0004c, 0x15e0003c, 0x15e00049, 0x15e0004b, 0x15e0004c,
0x15e0004d, 0x15e0004e, 0x15e0004f, 0x15e00052, 0x15e0004d, 0x15e0004e, 0x15e0004f, 0x15e00052,
0x15e00063, 0x15e00068, 0x15e00079, 0x15e0007b, 0x15e00062, 0x15e00067, 0x15e00078, 0x15e0007a,
0x15e0007f, 0x15e00085, 0x15e00086, 0x15e00087, 0x15e0007e, 0x15e00084, 0x15e00085, 0x15e00086,
0x15e00092, 0x15e000a9, 0x15e000b8, 0x15e000bb, 0x15e00091, 0x15e000a8, 0x15e000b7, 0x15e000ba,
0x15e000bc, 0x15e000bf, 0x15e000c0, 0x15e000c4, 0x15e000bb, 0x15e000be, 0x15e000bf, 0x15e000c3,
// Entry 140 - 15F // Entry 140 - 15F
0x15e000c9, 0x15e000ca, 0x15e000cd, 0x15e000d4, 0x15e000c8, 0x15e000c9, 0x15e000cc, 0x15e000d3,
0x15e000d5, 0x15e000e6, 0x15e000eb, 0x15e00103, 0x15e000d4, 0x15e000e5, 0x15e000ea, 0x15e00102,
0x15e00108, 0x15e0010b, 0x15e00115, 0x15e0011d, 0x15e00107, 0x15e0010a, 0x15e00114, 0x15e0011c,
0x15e00121, 0x15e00123, 0x15e00129, 0x15e00140, 0x15e00120, 0x15e00122, 0x15e00128, 0x15e0013f,
0x15e00141, 0x15e00160, 0x16900000, 0x1690009f, 0x15e00140, 0x15e0015f, 0x16900000, 0x1690009e,
0x16d00000, 0x16d000da, 0x16e00000, 0x16e00097, 0x16d00000, 0x16d000d9, 0x16e00000, 0x16e00096,
0x17e00000, 0x17e0007c, 0x19000000, 0x1900006f, 0x17e00000, 0x17e0007b, 0x19000000, 0x1900006e,
0x1a300000, 0x1a30004e, 0x1a300079, 0x1a3000b3, 0x1a300000, 0x1a30004e, 0x1a300078, 0x1a3000b2,
// Entry 160 - 17F // Entry 160 - 17F
0x1a400000, 0x1a40009a, 0x1a900000, 0x1ab00000, 0x1a400000, 0x1a400099, 0x1a900000, 0x1ab00000,
0x1ab000a5, 0x1ac00000, 0x1ac00099, 0x1b400000, 0x1ab000a4, 0x1ac00000, 0x1ac00098, 0x1b400000,
0x1b400081, 0x1b4000d5, 0x1b4000d7, 0x1b800000, 0x1b400080, 0x1b4000d4, 0x1b4000d6, 0x1b800000,
0x1b800136, 0x1bc00000, 0x1bc00098, 0x1be00000, 0x1b800135, 0x1bc00000, 0x1bc00097, 0x1be00000,
0x1be0009a, 0x1d100000, 0x1d100033, 0x1d100091, 0x1be00099, 0x1d100000, 0x1d100033, 0x1d100090,
0x1d200000, 0x1d200061, 0x1d500000, 0x1d500093, 0x1d200000, 0x1d200060, 0x1d500000, 0x1d500092,
0x1d700000, 0x1d700028, 0x1e100000, 0x1e100096, 0x1d700000, 0x1d700028, 0x1e100000, 0x1e100095,
0x1e700000, 0x1e7000d7, 0x1ea00000, 0x1ea00053, 0x1e700000, 0x1e7000d6, 0x1ea00000, 0x1ea00053,
// Entry 180 - 19F // Entry 180 - 19F
0x1f300000, 0x1f500000, 0x1f800000, 0x1f80009e, 0x1f300000, 0x1f500000, 0x1f800000, 0x1f80009d,
0x1f900000, 0x1f90004e, 0x1f90009f, 0x1f900114, 0x1f900000, 0x1f90004e, 0x1f90009e, 0x1f900113,
0x1f900139, 0x1fa00000, 0x1fb00000, 0x20000000, 0x1f900138, 0x1fa00000, 0x1fb00000, 0x20000000,
0x200000a3, 0x20300000, 0x20700000, 0x20700052, 0x200000a2, 0x20300000, 0x20700000, 0x20700052,
0x20800000, 0x20a00000, 0x20a00130, 0x20e00000, 0x20800000, 0x20a00000, 0x20a0012f, 0x20e00000,
0x20f00000, 0x21000000, 0x2100007e, 0x21200000, 0x20f00000, 0x21000000, 0x2100007d, 0x21200000,
0x21200068, 0x21600000, 0x21700000, 0x217000a5, 0x21200067, 0x21600000, 0x21700000, 0x217000a4,
0x21f00000, 0x22300000, 0x22300130, 0x22700000, 0x21f00000, 0x22300000, 0x2230012f, 0x22700000,
// Entry 1A0 - 1BF // Entry 1A0 - 1BF
0x2270005b, 0x23400000, 0x234000c4, 0x23900000, 0x2270005a, 0x23400000, 0x234000c3, 0x23900000,
0x239000a5, 0x24200000, 0x242000af, 0x24400000, 0x239000a4, 0x24200000, 0x242000ae, 0x24400000,
0x24400052, 0x24500000, 0x24500083, 0x24600000, 0x24400052, 0x24500000, 0x24500082, 0x24600000,
0x246000a5, 0x24a00000, 0x24a000a7, 0x25100000, 0x246000a4, 0x24a00000, 0x24a000a6, 0x25100000,
0x2510009a, 0x25400000, 0x254000ab, 0x254000ac, 0x25100099, 0x25400000, 0x254000aa, 0x254000ab,
0x25600000, 0x2560009a, 0x26a00000, 0x26a0009a, 0x25600000, 0x25600099, 0x26a00000, 0x26a00099,
0x26b00000, 0x26b00130, 0x26d00000, 0x26d00052, 0x26b00000, 0x26b0012f, 0x26d00000, 0x26d00052,
0x26e00000, 0x26e00061, 0x27400000, 0x28100000, 0x26e00000, 0x26e00060, 0x27400000, 0x28100000,
// Entry 1C0 - 1DF // Entry 1C0 - 1DF
0x2810007c, 0x28a00000, 0x28a000a6, 0x29100000, 0x2810007b, 0x28a00000, 0x28a000a5, 0x29100000,
0x29100130, 0x29500000, 0x295000b8, 0x2a300000, 0x2910012f, 0x29500000, 0x295000b7, 0x2a300000,
0x2a300132, 0x2af00000, 0x2af00136, 0x2b500000, 0x2a300131, 0x2af00000, 0x2af00135, 0x2b500000,
0x2b50002a, 0x2b50004b, 0x2b50004c, 0x2b50004d, 0x2b50002a, 0x2b50004b, 0x2b50004c, 0x2b50004d,
0x2b800000, 0x2b8000b0, 0x2bf00000, 0x2bf0009c, 0x2b800000, 0x2b8000af, 0x2bf00000, 0x2bf0009b,
0x2bf0009d, 0x2c000000, 0x2c0000b7, 0x2c200000, 0x2bf0009c, 0x2c000000, 0x2c0000b6, 0x2c200000,
0x2c20004b, 0x2c400000, 0x2c4000a5, 0x2c500000, 0x2c20004b, 0x2c400000, 0x2c4000a4, 0x2c500000,
0x2c5000a5, 0x2c700000, 0x2c7000b9, 0x2d100000, 0x2c5000a4, 0x2c700000, 0x2c7000b8, 0x2d100000,
// Entry 1E0 - 1FF // Entry 1E0 - 1FF
0x2d1000a5, 0x2d100130, 0x2e900000, 0x2e9000a5, 0x2d1000a4, 0x2d10012f, 0x2e900000, 0x2e9000a4,
0x2ed00000, 0x2ed000cd, 0x2f100000, 0x2f1000c0, 0x2ed00000, 0x2ed000cc, 0x2f100000, 0x2f1000bf,
0x2f200000, 0x2f2000d2, 0x2f400000, 0x2f400052, 0x2f200000, 0x2f2000d1, 0x2f400000, 0x2f400052,
0x2ff00000, 0x2ff000c3, 0x30400000, 0x3040009a, 0x2ff00000, 0x2ff000c2, 0x30400000, 0x30400099,
0x30b00000, 0x30b000c6, 0x31000000, 0x31b00000, 0x30b00000, 0x30b000c5, 0x31000000, 0x31b00000,
0x31b0009a, 0x31f00000, 0x31f0003e, 0x31f000d1, 0x31b00099, 0x31f00000, 0x31f0003e, 0x31f000d0,
0x31f0010e, 0x32000000, 0x320000cc, 0x32500000, 0x31f0010d, 0x32000000, 0x320000cb, 0x32500000,
0x32500052, 0x33100000, 0x331000c5, 0x33a00000, 0x32500052, 0x33100000, 0x331000c4, 0x33a00000,
// Entry 200 - 21F // Entry 200 - 21F
0x33a0009d, 0x34100000, 0x34500000, 0x345000d3, 0x33a0009c, 0x34100000, 0x34500000, 0x345000d2,
0x34700000, 0x347000db, 0x34700111, 0x34e00000, 0x34700000, 0x347000da, 0x34700110, 0x34e00000,
0x34e00165, 0x35000000, 0x35000061, 0x350000da, 0x34e00164, 0x35000000, 0x35000060, 0x350000d9,
0x35100000, 0x3510009a, 0x351000dc, 0x36700000, 0x35100000, 0x35100099, 0x351000db, 0x36700000,
0x36700030, 0x36700036, 0x36700040, 0x3670005c, 0x36700030, 0x36700036, 0x36700040, 0x3670005b,
0x367000da, 0x36700117, 0x3670011c, 0x36800000, 0x367000d9, 0x36700116, 0x3670011b, 0x36800000,
0x36800052, 0x36a00000, 0x36a000db, 0x36c00000, 0x36800052, 0x36a00000, 0x36a000da, 0x36c00000,
0x36c00052, 0x36f00000, 0x37500000, 0x37600000, 0x36c00052, 0x36f00000, 0x37500000, 0x37600000,
// Entry 220 - 23F // Entry 220 - 23F
0x37a00000, 0x38000000, 0x38000118, 0x38700000, 0x37a00000, 0x38000000, 0x38000117, 0x38700000,
0x38900000, 0x38900132, 0x39000000, 0x39000070, 0x38900000, 0x38900131, 0x39000000, 0x3900006f,
0x390000a5, 0x39500000, 0x3950009a, 0x39800000, 0x390000a4, 0x39500000, 0x39500099, 0x39800000,
0x3980007e, 0x39800107, 0x39d00000, 0x39d05000, 0x3980007d, 0x39800106, 0x39d00000, 0x39d05000,
0x39d050e9, 0x39d36000, 0x39d3609a, 0x3a100000, 0x39d050e8, 0x39d36000, 0x39d36099, 0x3a100000,
0x3b300000, 0x3b3000ea, 0x3bd00000, 0x3bd00001, 0x3b300000, 0x3b3000e9, 0x3bd00000, 0x3bd00001,
0x3be00000, 0x3be00024, 0x3c000000, 0x3c00002a, 0x3be00000, 0x3be00024, 0x3c000000, 0x3c00002a,
0x3c000041, 0x3c00004e, 0x3c00005b, 0x3c000087, 0x3c000041, 0x3c00004e, 0x3c00005a, 0x3c000086,
// Entry 240 - 25F // Entry 240 - 25F
0x3c00008c, 0x3c0000b8, 0x3c0000c7, 0x3c0000d2, 0x3c00008b, 0x3c0000b7, 0x3c0000c6, 0x3c0000d1,
0x3c0000ef, 0x3c000119, 0x3c000127, 0x3c400000, 0x3c0000ee, 0x3c000118, 0x3c000126, 0x3c400000,
0x3c40003f, 0x3c40006a, 0x3c4000e5, 0x3d400000, 0x3c40003f, 0x3c400069, 0x3c4000e4, 0x3d400000,
0x3d40004e, 0x3d900000, 0x3d90003a, 0x3dc00000, 0x3d40004e, 0x3d900000, 0x3d90003a, 0x3dc00000,
0x3dc000bd, 0x3dc00105, 0x3de00000, 0x3de00130, 0x3dc000bc, 0x3dc00104, 0x3de00000, 0x3de0012f,
0x3e200000, 0x3e200047, 0x3e2000a6, 0x3e2000af, 0x3e200000, 0x3e200047, 0x3e2000a5, 0x3e2000ae,
0x3e2000bd, 0x3e200107, 0x3e200131, 0x3e500000, 0x3e2000bc, 0x3e200106, 0x3e200130, 0x3e500000,
0x3e500108, 0x3e600000, 0x3e600130, 0x3eb00000, 0x3e500107, 0x3e600000, 0x3e60012f, 0x3eb00000,
// Entry 260 - 27F // Entry 260 - 27F
0x3eb00107, 0x3ec00000, 0x3ec000a5, 0x3f300000, 0x3eb00106, 0x3ec00000, 0x3ec000a4, 0x3f300000,
0x3f300130, 0x3fa00000, 0x3fa000e9, 0x3fc00000, 0x3f30012f, 0x3fa00000, 0x3fa000e8, 0x3fc00000,
0x3fd00000, 0x3fd00073, 0x3fd000db, 0x3fd0010d, 0x3fd00000, 0x3fd00072, 0x3fd000da, 0x3fd0010c,
0x3ff00000, 0x3ff000d2, 0x40100000, 0x401000c4, 0x3ff00000, 0x3ff000d1, 0x40100000, 0x401000c3,
0x40200000, 0x4020004c, 0x40700000, 0x40800000, 0x40200000, 0x4020004c, 0x40700000, 0x40800000,
0x4085b000, 0x4085b0bb, 0x408eb000, 0x408eb0bb, 0x4085a000, 0x4085a0ba, 0x408e8000, 0x408e80ba,
0x40c00000, 0x40c000b4, 0x41200000, 0x41200112, 0x40c00000, 0x40c000b3, 0x41200000, 0x41200111,
0x41600000, 0x41600110, 0x41c00000, 0x41d00000, 0x41600000, 0x4160010f, 0x41c00000, 0x41d00000,
// Entry 280 - 29F // Entry 280 - 29F
0x41e00000, 0x41f00000, 0x41f00073, 0x42200000, 0x41e00000, 0x41f00000, 0x41f00072, 0x42200000,
0x42300000, 0x42300165, 0x42900000, 0x42900063, 0x42300000, 0x42300164, 0x42900000, 0x42900062,
0x42900070, 0x429000a5, 0x42900116, 0x43100000, 0x4290006f, 0x429000a4, 0x42900115, 0x43100000,
0x43100027, 0x431000c3, 0x4310014e, 0x43200000, 0x43100027, 0x431000c2, 0x4310014d, 0x43200000,
0x43220000, 0x43220033, 0x432200be, 0x43220106, 0x43220000, 0x43220033, 0x432200bd, 0x43220105,
0x4322014e, 0x4325b000, 0x4325b033, 0x4325b0be, 0x4322014d, 0x4325a000, 0x4325a033, 0x4325a0bd,
0x4325b106, 0x4325b14e, 0x43700000, 0x43a00000, 0x4325a105, 0x4325a14d, 0x43700000, 0x43a00000,
0x43b00000, 0x44400000, 0x44400031, 0x44400073, 0x43b00000, 0x44400000, 0x44400031, 0x44400072,
// Entry 2A0 - 2BF // Entry 2A0 - 2BF
0x4440010d, 0x44500000, 0x4450004b, 0x445000a5, 0x4440010c, 0x44500000, 0x4450004b, 0x445000a4,
0x44500130, 0x44500132, 0x44e00000, 0x45000000, 0x4450012f, 0x44500131, 0x44e00000, 0x45000000,
0x4500009a, 0x450000b4, 0x450000d1, 0x4500010e, 0x45000099, 0x450000b3, 0x450000d0, 0x4500010d,
0x46100000, 0x4610009a, 0x46400000, 0x464000a5, 0x46100000, 0x46100099, 0x46400000, 0x464000a4,
0x46400132, 0x46700000, 0x46700125, 0x46b00000, 0x46400131, 0x46700000, 0x46700124, 0x46b00000,
0x46b00124, 0x46f00000, 0x46f0006e, 0x46f00070, 0x46b00123, 0x46f00000, 0x46f0006d, 0x46f0006f,
0x47100000, 0x47600000, 0x47600128, 0x47a00000, 0x47100000, 0x47600000, 0x47600127, 0x47a00000,
0x48000000, 0x48200000, 0x4820012a, 0x48a00000, 0x48000000, 0x48200000, 0x48200129, 0x48a00000,
// Entry 2C0 - 2DF // Entry 2C0 - 2DF
0x48a0005e, 0x48a0012c, 0x48e00000, 0x49400000, 0x48a0005d, 0x48a0012b, 0x48e00000, 0x49400000,
0x49400107, 0x4a400000, 0x4a4000d5, 0x4a900000, 0x49400106, 0x4a400000, 0x4a4000d4, 0x4a900000,
0x4a9000bb, 0x4ac00000, 0x4ac00053, 0x4ae00000, 0x4a9000ba, 0x4ac00000, 0x4ac00053, 0x4ae00000,
0x4ae00131, 0x4b400000, 0x4b40009a, 0x4b4000e9, 0x4ae00130, 0x4b400000, 0x4b400099, 0x4b4000e8,
0x4bc00000, 0x4bc05000, 0x4bc05024, 0x4bc20000, 0x4bc00000, 0x4bc05000, 0x4bc05024, 0x4bc20000,
0x4bc20138, 0x4bc5b000, 0x4bc5b138, 0x4be00000, 0x4bc20137, 0x4bc5a000, 0x4bc5a137, 0x4be00000,
0x4be5b000, 0x4be5b0b5, 0x4bef4000, 0x4bef40b5, 0x4be5a000, 0x4be5a0b4, 0x4bef1000, 0x4bef10b4,
0x4c000000, 0x4c300000, 0x4c30013f, 0x4c900000, 0x4c000000, 0x4c300000, 0x4c30013e, 0x4c900000,
// Entry 2E0 - 2FF // Entry 2E0 - 2FF
0x4c900001, 0x4cc00000, 0x4cc00130, 0x4ce00000, 0x4c900001, 0x4cc00000, 0x4cc0012f, 0x4ce00000,
0x4cf00000, 0x4cf0004e, 0x4e500000, 0x4e500115, 0x4cf00000, 0x4cf0004e, 0x4e500000, 0x4e500114,
0x4f200000, 0x4fb00000, 0x4fb00132, 0x50900000, 0x4f200000, 0x4fb00000, 0x4fb00131, 0x50900000,
0x50900052, 0x51200000, 0x51200001, 0x51800000, 0x50900052, 0x51200000, 0x51200001, 0x51800000,
0x5180003b, 0x518000d7, 0x51f00000, 0x51f3b000, 0x5180003b, 0x518000d6, 0x51f00000, 0x51f3b000,
0x51f3b053, 0x51f3c000, 0x51f3c08e, 0x52800000, 0x51f3b053, 0x51f3c000, 0x51f3c08d, 0x52800000,
0x528000bb, 0x52900000, 0x5293b000, 0x5293b053, 0x528000ba, 0x52900000, 0x5293b000, 0x5293b053,
0x5293b08e, 0x5293b0c7, 0x5293b10e, 0x5293c000, 0x5293b08d, 0x5293b0c6, 0x5293b10d, 0x5293c000,
// Entry 300 - 31F // Entry 300 - 31F
0x5293c08e, 0x5293c0c7, 0x5293c12f, 0x52f00000, 0x5293c08d, 0x5293c0c6, 0x5293c12e, 0x52f00000,
0x52f00162, 0x52f00161,
} // Size: 3116 bytes } // Size: 3116 bytes
const specialTagsStr string = "ca-ES-valencia en-US-u-va-posix" const specialTagsStr string = "ca-ES-valencia en-US-u-va-posix"
// Total table size 3147 bytes (3KiB); checksum: 5A8FFFA5 // Total table size 3147 bytes (3KiB); checksum: 6772C83C

File diff suppressed because it is too large Load Diff

View File

@@ -434,7 +434,7 @@ func newMatcher(supported []Tag, options []MatchOption) *matcher {
// (their canonicalization simply substitutes a different language code, but // (their canonicalization simply substitutes a different language code, but
// nothing else), the match confidence is Exact, otherwise it is High. // nothing else), the match confidence is Exact, otherwise it is High.
for i, lm := range language.AliasMap { for i, lm := range language.AliasMap {
// If deprecated codes match and there is no fiddling with the script // If deprecated codes match and there is no fiddling with the script or
// or region, we consider it an exact match. // or region, we consider it an exact match.
conf := Exact conf := Exact
if language.AliasTypes[i] != language.Macro { if language.AliasTypes[i] != language.Macro {

View File

@@ -23,31 +23,31 @@ const (
_419 = 31 _419 = 31
_BR = 65 _BR = 65
_CA = 73 _CA = 73
_ES = 111 _ES = 110
_GB = 124 _GB = 123
_MD = 189 _MD = 188
_PT = 239 _PT = 238
_UK = 307 _UK = 306
_US = 310 _US = 309
_ZZ = 358 _ZZ = 357
_XA = 324 _XA = 323
_XC = 326 _XC = 325
_XK = 334 _XK = 333
) )
const ( const (
_Latn = 91 _Latn = 90
_Hani = 57 _Hani = 57
_Hans = 59 _Hans = 59
_Hant = 60 _Hant = 60
_Qaaa = 149 _Qaaa = 147
_Qaai = 157 _Qaai = 155
_Qabx = 198 _Qabx = 196
_Zinh = 255 _Zinh = 252
_Zyyy = 260 _Zyyy = 257
_Zzzz = 261 _Zzzz = 258
) )
var regionToGroups = []uint8{ // 359 elements var regionToGroups = []uint8{ // 358 elements
// Entry 0 - 3F // Entry 0 - 3F
0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00,
@@ -60,51 +60,51 @@ var regionToGroups = []uint8{ // 359 elements
// Entry 40 - 7F // Entry 40 - 7F
0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x08,
0x08, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
// Entry 80 - BF // Entry 80 - BF
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00,
0x00, 0x00, 0x04, 0x01, 0x00, 0x04, 0x02, 0x00, 0x00, 0x04, 0x01, 0x00, 0x04, 0x02, 0x00, 0x04,
0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x04,
// Entry C0 - FF
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x01, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
// Entry C0 - FF
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01,
0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 100 - 13F // Entry 100 - 13F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x04,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x05, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x05, 0x00, 0x00,
// Entry 140 - 17F // Entry 140 - 17F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
} // Size: 383 bytes } // Size: 382 bytes
var paradigmLocales = [][3]uint16{ // 3 elements var paradigmLocales = [][3]uint16{ // 3 elements
0: [3]uint16{0x139, 0x0, 0x7c}, 0: [3]uint16{0x139, 0x0, 0x7b},
1: [3]uint16{0x13e, 0x0, 0x1f}, 1: [3]uint16{0x13e, 0x0, 0x1f},
2: [3]uint16{0x3c0, 0x41, 0xef}, 2: [3]uint16{0x3c0, 0x41, 0xee},
} // Size: 42 bytes } // Size: 42 bytes
type mutualIntelligibility struct { type mutualIntelligibility struct {
@@ -249,30 +249,30 @@ var matchLang = []mutualIntelligibility{ // 113 elements
// matchScript holds pairs of scriptIDs where readers of one script // matchScript holds pairs of scriptIDs where readers of one script
// can typically also read the other. Each is associated with a confidence. // can typically also read the other. Each is associated with a confidence.
var matchScript = []scriptIntelligibility{ // 26 elements var matchScript = []scriptIntelligibility{ // 26 elements
0: {wantLang: 0x432, haveLang: 0x432, wantScript: 0x5b, haveScript: 0x20, distance: 0x5}, 0: {wantLang: 0x432, haveLang: 0x432, wantScript: 0x5a, haveScript: 0x20, distance: 0x5},
1: {wantLang: 0x432, haveLang: 0x432, wantScript: 0x20, haveScript: 0x5b, distance: 0x5}, 1: {wantLang: 0x432, haveLang: 0x432, wantScript: 0x20, haveScript: 0x5a, distance: 0x5},
2: {wantLang: 0x58, haveLang: 0x3e2, wantScript: 0x5b, haveScript: 0x20, distance: 0xa}, 2: {wantLang: 0x58, haveLang: 0x3e2, wantScript: 0x5a, haveScript: 0x20, distance: 0xa},
3: {wantLang: 0xa5, haveLang: 0x139, wantScript: 0xe, haveScript: 0x5b, distance: 0xa}, 3: {wantLang: 0xa5, haveLang: 0x139, wantScript: 0xe, haveScript: 0x5a, distance: 0xa},
4: {wantLang: 0x1d7, haveLang: 0x3e2, wantScript: 0x8, haveScript: 0x20, distance: 0xa}, 4: {wantLang: 0x1d7, haveLang: 0x3e2, wantScript: 0x8, haveScript: 0x20, distance: 0xa},
5: {wantLang: 0x210, haveLang: 0x139, wantScript: 0x2e, haveScript: 0x5b, distance: 0xa}, 5: {wantLang: 0x210, haveLang: 0x139, wantScript: 0x2e, haveScript: 0x5a, distance: 0xa},
6: {wantLang: 0x24a, haveLang: 0x139, wantScript: 0x4f, haveScript: 0x5b, distance: 0xa}, 6: {wantLang: 0x24a, haveLang: 0x139, wantScript: 0x4e, haveScript: 0x5a, distance: 0xa},
7: {wantLang: 0x251, haveLang: 0x139, wantScript: 0x53, haveScript: 0x5b, distance: 0xa}, 7: {wantLang: 0x251, haveLang: 0x139, wantScript: 0x52, haveScript: 0x5a, distance: 0xa},
8: {wantLang: 0x2b8, haveLang: 0x139, wantScript: 0x58, haveScript: 0x5b, distance: 0xa}, 8: {wantLang: 0x2b8, haveLang: 0x139, wantScript: 0x57, haveScript: 0x5a, distance: 0xa},
9: {wantLang: 0x304, haveLang: 0x139, wantScript: 0x6f, haveScript: 0x5b, distance: 0xa}, 9: {wantLang: 0x304, haveLang: 0x139, wantScript: 0x6e, haveScript: 0x5a, distance: 0xa},
10: {wantLang: 0x331, haveLang: 0x139, wantScript: 0x76, haveScript: 0x5b, distance: 0xa}, 10: {wantLang: 0x331, haveLang: 0x139, wantScript: 0x75, haveScript: 0x5a, distance: 0xa},
11: {wantLang: 0x351, haveLang: 0x139, wantScript: 0x22, haveScript: 0x5b, distance: 0xa}, 11: {wantLang: 0x351, haveLang: 0x139, wantScript: 0x22, haveScript: 0x5a, distance: 0xa},
12: {wantLang: 0x395, haveLang: 0x139, wantScript: 0x83, haveScript: 0x5b, distance: 0xa}, 12: {wantLang: 0x395, haveLang: 0x139, wantScript: 0x81, haveScript: 0x5a, distance: 0xa},
13: {wantLang: 0x39d, haveLang: 0x139, wantScript: 0x36, haveScript: 0x5b, distance: 0xa}, 13: {wantLang: 0x39d, haveLang: 0x139, wantScript: 0x36, haveScript: 0x5a, distance: 0xa},
14: {wantLang: 0x3be, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5b, distance: 0xa}, 14: {wantLang: 0x3be, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5a, distance: 0xa},
15: {wantLang: 0x3fa, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5b, distance: 0xa}, 15: {wantLang: 0x3fa, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5a, distance: 0xa},
16: {wantLang: 0x40c, haveLang: 0x139, wantScript: 0xd6, haveScript: 0x5b, distance: 0xa}, 16: {wantLang: 0x40c, haveLang: 0x139, wantScript: 0xd4, haveScript: 0x5a, distance: 0xa},
17: {wantLang: 0x450, haveLang: 0x139, wantScript: 0xe6, haveScript: 0x5b, distance: 0xa}, 17: {wantLang: 0x450, haveLang: 0x139, wantScript: 0xe3, haveScript: 0x5a, distance: 0xa},
18: {wantLang: 0x461, haveLang: 0x139, wantScript: 0xe9, haveScript: 0x5b, distance: 0xa}, 18: {wantLang: 0x461, haveLang: 0x139, wantScript: 0xe6, haveScript: 0x5a, distance: 0xa},
19: {wantLang: 0x46f, haveLang: 0x139, wantScript: 0x2c, haveScript: 0x5b, distance: 0xa}, 19: {wantLang: 0x46f, haveLang: 0x139, wantScript: 0x2c, haveScript: 0x5a, distance: 0xa},
20: {wantLang: 0x476, haveLang: 0x3e2, wantScript: 0x5b, haveScript: 0x20, distance: 0xa}, 20: {wantLang: 0x476, haveLang: 0x3e2, wantScript: 0x5a, haveScript: 0x20, distance: 0xa},
21: {wantLang: 0x4b4, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5b, distance: 0xa}, 21: {wantLang: 0x4b4, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5a, distance: 0xa},
22: {wantLang: 0x4bc, haveLang: 0x3e2, wantScript: 0x5b, haveScript: 0x20, distance: 0xa}, 22: {wantLang: 0x4bc, haveLang: 0x3e2, wantScript: 0x5a, haveScript: 0x20, distance: 0xa},
23: {wantLang: 0x512, haveLang: 0x139, wantScript: 0x3e, haveScript: 0x5b, distance: 0xa}, 23: {wantLang: 0x512, haveLang: 0x139, wantScript: 0x3e, haveScript: 0x5a, distance: 0xa},
24: {wantLang: 0x529, haveLang: 0x529, wantScript: 0x3b, haveScript: 0x3c, distance: 0xf}, 24: {wantLang: 0x529, haveLang: 0x529, wantScript: 0x3b, haveScript: 0x3c, distance: 0xf},
25: {wantLang: 0x529, haveLang: 0x529, wantScript: 0x3c, haveScript: 0x3b, distance: 0x13}, 25: {wantLang: 0x529, haveLang: 0x529, wantScript: 0x3c, haveScript: 0x3b, distance: 0x13},
} // Size: 232 bytes } // Size: 232 bytes
@@ -295,4 +295,4 @@ var matchRegion = []regionIntelligibility{ // 15 elements
14: {lang: 0x529, script: 0x3c, group: 0x80, distance: 0x5}, 14: {lang: 0x529, script: 0x3c, group: 0x80, distance: 0x5},
} // Size: 114 bytes } // Size: 114 bytes
// Total table size 1473 bytes (1KiB); checksum: 7BB90B5C // Total table size 1472 bytes (1KiB); checksum: F86C669

13
vendor/modules.txt vendored
View File

@@ -1,16 +1,17 @@
# github.com/mattn/go-sqlite3 v1.14.7 # github.com/mattn/go-sqlite3 v1.14.7
## explicit; go 1.12 ## explicit; go 1.12
github.com/mattn/go-sqlite3 github.com/mattn/go-sqlite3
# golang.org/x/net v0.33.0 # golang.org/x/net v0.8.0
## explicit; go 1.18 ## explicit; go 1.17
golang.org/x/net/html golang.org/x/net/html
golang.org/x/net/html/atom golang.org/x/net/html/atom
golang.org/x/net/html/charset golang.org/x/net/html/charset
# golang.org/x/sys v0.28.0 # golang.org/x/sys v0.6.0
## explicit; go 1.18 ## explicit; go 1.17
golang.org/x/sys/internal/unsafeheader
golang.org/x/sys/windows golang.org/x/sys/windows
# golang.org/x/text v0.21.0 # golang.org/x/text v0.8.0
## explicit; go 1.18 ## explicit; go 1.17
golang.org/x/text/encoding golang.org/x/text/encoding
golang.org/x/text/encoding/charmap golang.org/x/text/encoding/charmap
golang.org/x/text/encoding/htmlindex golang.org/x/text/encoding/htmlindex