forked from lug/matterbridge
		
	Compare commits
	
		
			104 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					24bc0f127b | ||
| 
						 | 
					f0f801402d | ||
| 
						 | 
					663850a2b8 | ||
| 
						 | 
					c51753cab1 | ||
| 
						 | 
					b3be2e208c | ||
| 
						 | 
					c30e90ff3f | ||
| 
						 | 
					e4c0ca0f48 | ||
| 
						 | 
					9c203327c0 | ||
| 
						 | 
					ccb5b1d075 | ||
| 
						 | 
					0dbbd0414c | ||
| 
						 | 
					e7b3ebf98a | ||
| 
						 | 
					5bc18fb780 | ||
| 
						 | 
					df30366072 | ||
| 
						 | 
					65c7ac80b5 | ||
| 
						 | 
					dd3fb32ec7 | ||
| 
						 | 
					2a3f475ff5 | ||
| 
						 | 
					7288f71201 | ||
| 
						 | 
					9c43eff753 | ||
| 
						 | 
					c8d7fdeedc | ||
| 
						 | 
					c211152e23 | ||
| 
						 | 
					ab75d5097e | ||
| 
						 | 
					c3644c8d3b | ||
| 
						 | 
					6438a3dba3 | ||
| 
						 | 
					4b226a6a63 | ||
| 
						 | 
					4801850013 | ||
| 
						 | 
					6a7412bf2b | ||
| 
						 | 
					5a1fd7dadd | ||
| 
						 | 
					ac06a26809 | ||
| 
						 | 
					61d56f26f8 | ||
| 
						 | 
					6aa05b3981 | ||
| 
						 | 
					aad60c882e | ||
| 
						 | 
					fecca57507 | ||
| 
						 | 
					2bcad846c0 | ||
| 
						 | 
					15ad0165fc | ||
| 
						 | 
					2e8ab11978 | ||
| 
						 | 
					9a8ce9b17e | ||
| 
						 | 
					16ab4c6fed | ||
| 
						 | 
					e3ee0df7ba | ||
| 
						 | 
					8f7ab280e2 | ||
| 
						 | 
					dbedc99421 | ||
| 
						 | 
					6cb359cb80 | ||
| 
						 | 
					ae2ad824a9 | ||
| 
						 | 
					02e3d7852b | ||
| 
						 | 
					3893a035be | ||
| 
						 | 
					658bdd9faa | ||
| 
						 | 
					e1eebcd4e0 | ||
| 
						 | 
					062b831e88 | ||
| 
						 | 
					b275efaeff | ||
| 
						 | 
					80d3033456 | ||
| 
						 | 
					bd0516f09a | ||
| 
						 | 
					df4d76e466 | ||
| 
						 | 
					dcbd7f8cad | ||
| 
						 | 
					73ec02ab9d | ||
| 
						 | 
					d1f8347071 | ||
| 
						 | 
					8601eedada | ||
| 
						 | 
					9afd33cdfc | ||
| 
						 | 
					5e1be8e558 | ||
| 
						 | 
					835dd2635a | ||
| 
						 | 
					f65b18c2f6 | ||
| 
						 | 
					b0e7b84f40 | ||
| 
						 | 
					1635db93c7 | ||
| 
						 | 
					c4fe462d11 | ||
| 
						 | 
					b1f403165d | ||
| 
						 | 
					46e4317b77 | ||
| 
						 | 
					e3ffbcadd8 | ||
| 
						 | 
					b7d73077e5 | ||
| 
						 | 
					77f61ee20a | ||
| 
						 | 
					8967f02fc9 | ||
| 
						 | 
					831ff6d0a9 | ||
| 
						 | 
					2199174def | ||
| 
						 | 
					55f41ddaab | ||
| 
						 | 
					21305d93bf | ||
| 
						 | 
					4478d5d904 | ||
| 
						 | 
					cc6253a6b8 | ||
| 
						 | 
					85f66853bc | ||
| 
						 | 
					7464fd149c | ||
| 
						 | 
					86f1a8019c | ||
| 
						 | 
					b98d56dcf6 | ||
| 
						 | 
					a3a8a5769d | ||
| 
						 | 
					4dd8bae5c9 | ||
| 
						 | 
					7ae45c42e7 | ||
| 
						 | 
					7551b4e7a3 | ||
| 
						 | 
					61bab22dde | ||
| 
						 | 
					6dcc23ebb6 | ||
| 
						 | 
					b06a574cc5 | ||
| 
						 | 
					b56f80b1b8 | ||
| 
						 | 
					20f6c05ec5 | ||
| 
						 | 
					57fce93af7 | ||
| 
						 | 
					110b6a1431 | ||
| 
						 | 
					53cafa9f3d | ||
| 
						 | 
					d4195deb3a | ||
| 
						 | 
					400ecfb79c | ||
| 
						 | 
					86151da271 | ||
| 
						 | 
					44f3e2557d | ||
| 
						 | 
					1f365c716e | ||
| 
						 | 
					9efcc41ab2 | ||
| 
						 | 
					13bbeeaceb | ||
| 
						 | 
					da4dcec14d | ||
| 
						 | 
					761c0b79c5 | ||
| 
						 | 
					d93ab0496f | ||
| 
						 | 
					66b6f9749d | ||
| 
						 | 
					17c2d1f26a | ||
| 
						 | 
					a79e632cdc | ||
| 
						 | 
					f36498421b | 
							
								
								
									
										16
									
								
								.github/workflows/development.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								.github/workflows/development.yml
									
									
									
									
										vendored
									
									
								
							@@ -11,12 +11,12 @@ jobs:
 | 
			
		||||
      - name: Run golangci-lint
 | 
			
		||||
        uses: golangci/golangci-lint-action@v2
 | 
			
		||||
        with:
 | 
			
		||||
          version: v1.29
 | 
			
		||||
          version: latest
 | 
			
		||||
          args: "-v --new-from-rev HEAD~5"
 | 
			
		||||
  test-build-upload:
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        go-version: [1.15.x, 1.16.x]
 | 
			
		||||
        go-version: [1.17.x]
 | 
			
		||||
        platform: [ubuntu-latest]
 | 
			
		||||
    runs-on: ${{ matrix.platform }}
 | 
			
		||||
    steps:
 | 
			
		||||
@@ -35,23 +35,23 @@ jobs:
 | 
			
		||||
      run: |
 | 
			
		||||
        mkdir -p output/{win,lin,arm,mac}
 | 
			
		||||
        VERSION=$(git describe --tags)
 | 
			
		||||
        GOOS=linux GOARCH=amd64 go build -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/lin/matterbridge-$VERSION-linux-amd64
 | 
			
		||||
        GOOS=windows GOARCH=amd64 go build -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/win/matterbridge-$VERSION-windows-amd64.exe
 | 
			
		||||
        GOOS=darwin GOARCH=amd64 go build -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/mac/matterbridge-$VERSION-darwin-amd64
 | 
			
		||||
        CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o output/lin/matterbridge-$VERSION-linux-amd64
 | 
			
		||||
        CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o output/win/matterbridge-$VERSION-windows-amd64.exe
 | 
			
		||||
        CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o output/mac/matterbridge-$VERSION-darwin-amd64
 | 
			
		||||
    - name: Upload linux 64-bit
 | 
			
		||||
      if: startsWith(matrix.go-version,'1.16')
 | 
			
		||||
      if: startsWith(matrix.go-version,'1.17')
 | 
			
		||||
      uses: actions/upload-artifact@v2
 | 
			
		||||
      with:
 | 
			
		||||
        name: matterbridge-linux-64bit
 | 
			
		||||
        path: output/lin
 | 
			
		||||
    - name: Upload windows 64-bit
 | 
			
		||||
      if: startsWith(matrix.go-version,'1.16')
 | 
			
		||||
      if: startsWith(matrix.go-version,'1.17')
 | 
			
		||||
      uses: actions/upload-artifact@v2
 | 
			
		||||
      with:
 | 
			
		||||
        name: matterbridge-windows-64bit
 | 
			
		||||
        path: output/win
 | 
			
		||||
    - name: Upload darwin 64-bit
 | 
			
		||||
      if: startsWith(matrix.go-version,'1.16')
 | 
			
		||||
      if: startsWith(matrix.go-version,'1.17')
 | 
			
		||||
      uses: actions/upload-artifact@v2
 | 
			
		||||
      with:
 | 
			
		||||
        name: matterbridge-darwin-64bit
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										68
									
								
								.github/workflows/docker.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								.github/workflows/docker.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
name: docker
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - 'master'
 | 
			
		||||
    tags:
 | 
			
		||||
      - 'v*'
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
      - 'master'
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  docker:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      -
 | 
			
		||||
        name: Checkout
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
      -
 | 
			
		||||
        name: Set up QEMU
 | 
			
		||||
        uses: docker/setup-qemu-action@v1
 | 
			
		||||
        with:
 | 
			
		||||
          platforms: amd64,arm64
 | 
			
		||||
      -
 | 
			
		||||
        name: Set up Docker Buildx
 | 
			
		||||
        uses: docker/setup-buildx-action@v1
 | 
			
		||||
      -
 | 
			
		||||
        name: Docker meta
 | 
			
		||||
        id: meta
 | 
			
		||||
        uses: docker/metadata-action@v3
 | 
			
		||||
        with:
 | 
			
		||||
          images: 42wim/matterbridge,ghcr.io/42wim/matterbridge
 | 
			
		||||
          flavor: |
 | 
			
		||||
            latest=true
 | 
			
		||||
          tags: |
 | 
			
		||||
            type=ref,event=branch
 | 
			
		||||
            type=ref,event=pr
 | 
			
		||||
            type=semver,pattern={{version}}
 | 
			
		||||
            type=semver,pattern=stable
 | 
			
		||||
            type=semver,pattern={{major}}
 | 
			
		||||
            type=semver,pattern={{major}}.{{minor}}
 | 
			
		||||
      -
 | 
			
		||||
        name: Login to DockerHub
 | 
			
		||||
        uses: docker/login-action@v1 
 | 
			
		||||
        if: github.event_name != 'pull_request'
 | 
			
		||||
        with:
 | 
			
		||||
          username: ${{ secrets.DOCKERHUB_USERNAME }}
 | 
			
		||||
          password: ${{ secrets.DOCKERHUB_TOKEN }}
 | 
			
		||||
      -
 | 
			
		||||
        name: Log into registry ghcr.io
 | 
			
		||||
        uses: docker/login-action@v1
 | 
			
		||||
        if: github.event_name != 'pull_request'
 | 
			
		||||
        with:
 | 
			
		||||
          registry: ghcr.io
 | 
			
		||||
          username: ${{ github.repository_owner }}
 | 
			
		||||
          password: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
      -
 | 
			
		||||
        name: Build and push
 | 
			
		||||
        id: docker_build
 | 
			
		||||
        uses: docker/build-push-action@v2
 | 
			
		||||
        with:
 | 
			
		||||
          context: .
 | 
			
		||||
          platforms: linux/amd64,linux/arm64
 | 
			
		||||
          push: ${{ github.event_name != 'pull_request' }}
 | 
			
		||||
          tags: ${{ steps.meta.outputs.tags }}
 | 
			
		||||
          labels: ${{ steps.meta.outputs.labels }}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -4,3 +4,6 @@
 | 
			
		||||
 | 
			
		||||
# Exclude configuration file
 | 
			
		||||
matterbridge.toml
 | 
			
		||||
 | 
			
		||||
# Exclude IDE Files
 | 
			
		||||
.vscode
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ run:
 | 
			
		||||
  # concurrency: 4
 | 
			
		||||
 | 
			
		||||
  # timeout for analysis, e.g. 30s, 5m, default is 1m
 | 
			
		||||
  deadline: 2m
 | 
			
		||||
  deadline: 5m
 | 
			
		||||
 | 
			
		||||
  # exit code when at least one issue was found, default is 1
 | 
			
		||||
  issues-exit-code: 1
 | 
			
		||||
@@ -182,7 +182,28 @@ linters:
 | 
			
		||||
    - interfacer
 | 
			
		||||
    - goheader
 | 
			
		||||
    - noctx
 | 
			
		||||
 | 
			
		||||
    - gci
 | 
			
		||||
    - errorlint
 | 
			
		||||
    - nlreturn
 | 
			
		||||
    - exhaustivestruct
 | 
			
		||||
    - forbidigo
 | 
			
		||||
    - wrapcheck
 | 
			
		||||
    - varnamelen
 | 
			
		||||
    - ireturn
 | 
			
		||||
    - errorlint
 | 
			
		||||
    - tparallel
 | 
			
		||||
    - wrapcheck
 | 
			
		||||
    - paralleltest
 | 
			
		||||
    - makezero
 | 
			
		||||
    - thelper
 | 
			
		||||
    - cyclop
 | 
			
		||||
    - revive
 | 
			
		||||
    - importas
 | 
			
		||||
    - gomoddirectives
 | 
			
		||||
    - promlinter
 | 
			
		||||
    - tagliatelle
 | 
			
		||||
    - errname
 | 
			
		||||
    - typecheck
 | 
			
		||||
# rules to deal with reported isues
 | 
			
		||||
issues:
 | 
			
		||||
  # List of regexps of issue texts to exclude, empty list by default.
 | 
			
		||||
 
 | 
			
		||||
@@ -18,8 +18,11 @@ builds:
 | 
			
		||||
    - arm
 | 
			
		||||
    - arm64
 | 
			
		||||
    - 386
 | 
			
		||||
  goarm:
 | 
			
		||||
    - 6
 | 
			
		||||
    - 7
 | 
			
		||||
  ldflags:
 | 
			
		||||
    - -s -w -X main.githash={{.ShortCommit}}
 | 
			
		||||
    - -s -w -X github.com/42wim/matterbridge/version.GitHash={{.ShortCommit}}
 | 
			
		||||
 | 
			
		||||
archives:
 | 
			
		||||
  -
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ FROM alpine AS builder
 | 
			
		||||
COPY . /go/src/matterbridge
 | 
			
		||||
RUN apk --no-cache add go git \
 | 
			
		||||
        && cd /go/src/matterbridge \
 | 
			
		||||
        && go build -mod vendor -ldflags "-X main.githash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
 | 
			
		||||
        && CGO_ENABLED=0 go build -mod vendor -ldflags "-X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
 | 
			
		||||
 | 
			
		||||
FROM alpine
 | 
			
		||||
RUN apk --no-cache add ca-certificates mailcap
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								README.md
									
									
									
									
									
								
							@@ -67,6 +67,7 @@ And more...
 | 
			
		||||
      - [Bridge slack (#general) - discord (general)](#bridge-slack-general---discord-general)
 | 
			
		||||
  - [Running](#running)
 | 
			
		||||
    - [Docker](#docker)
 | 
			
		||||
    - [Systemd](#systemd)
 | 
			
		||||
  - [Changelog](#changelog)
 | 
			
		||||
  - [FAQ](#faq)
 | 
			
		||||
  - [Related projects](#related-projects)
 | 
			
		||||
@@ -163,7 +164,7 @@ See <https://github.com/42wim/matterbridge/wiki>
 | 
			
		||||
 | 
			
		||||
### Binaries
 | 
			
		||||
 | 
			
		||||
- Latest stable release [v1.22.3](https://github.com/42wim/matterbridge/releases/latest)
 | 
			
		||||
- Latest stable release [v1.24.1](https://github.com/42wim/matterbridge/releases/latest)
 | 
			
		||||
- Development releases (follows master) can be downloaded [here](https://github.com/42wim/matterbridge/actions) selecting the latest green build and then artifacts.
 | 
			
		||||
 | 
			
		||||
To install or upgrade just download the latest [binary](https://github.com/42wim/matterbridge/releases/latest). On \*nix platforms you may need to make the binary executable - you can do this by running `chmod a+x` on the binary (example: `chmod a+x matterbridge-1.20.0-linux-64bit`). After downloading (and making the binary executable, if necessary), follow the instructions on the [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration.
 | 
			
		||||
@@ -179,10 +180,18 @@ To install or upgrade just download the latest [binary](https://github.com/42wim
 | 
			
		||||
Most people just want to use binaries, you can find those [here](https://github.com/42wim/matterbridge/releases/latest)
 | 
			
		||||
 | 
			
		||||
If you really want to build from source, follow these instructions:
 | 
			
		||||
Go 1.13+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed.
 | 
			
		||||
Go 1.17+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed.
 | 
			
		||||
 | 
			
		||||
To install the latest stable run:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
go get github.com/42wim/matterbridge
 | 
			
		||||
go install github.com/42wim/matterbridge@v1.24.1
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To install the latest dev run:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
go install github.com/42wim/matterbridge@latest
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You should now have matterbridge binary in the ~/go/bin directory:
 | 
			
		||||
@@ -286,6 +295,10 @@ Usage of ./matterbridge:
 | 
			
		||||
 | 
			
		||||
Please take a look at the [Docker Wiki page](https://github.com/42wim/matterbridge/wiki/Deploy:-Docker) for more information.
 | 
			
		||||
 | 
			
		||||
### Systemd
 | 
			
		||||
 | 
			
		||||
Please take a look at the [Service Files page](https://github.com/42wim/matterbridge/wiki/Service-files) for more information.
 | 
			
		||||
 | 
			
		||||
## Changelog
 | 
			
		||||
 | 
			
		||||
See [changelog.md](https://github.com/42wim/matterbridge/blob/master/changelog.md)
 | 
			
		||||
@@ -323,6 +336,7 @@ See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ)
 | 
			
		||||
- <https://daniele.tech/2019/02/how-to-use-matterbridge-to-connect-2-different-slack-workspaces/>
 | 
			
		||||
- <https://userlinux.net/mattermost-and-matterbridge.html>
 | 
			
		||||
- <https://nextcloud.com/blog/bridging-chat-services-in-talk/>
 | 
			
		||||
- <https://minecraftchest1.wordpress.com/2021/06/05/how-to-install-and-setup-matterbridge/>
 | 
			
		||||
- Youtube: [whatsapp - telegram bridging](https://www.youtube.com/watch?v=W-VXISoKtNc)
 | 
			
		||||
 | 
			
		||||
## Thanks
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ const (
 | 
			
		||||
	EventRejoinChannels    = "rejoin_channels"
 | 
			
		||||
	EventUserAction        = "user_action"
 | 
			
		||||
	EventMsgDelete         = "msg_delete"
 | 
			
		||||
	EventFileDelete        = "file_delete"
 | 
			
		||||
	EventAPIConnected      = "api_connected"
 | 
			
		||||
	EventUserTyping        = "user_typing"
 | 
			
		||||
	EventGetChannelMembers = "get_channel_members"
 | 
			
		||||
@@ -56,13 +57,14 @@ func (m Message) ParentValid() bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FileInfo struct {
 | 
			
		||||
	Name    string
 | 
			
		||||
	Data    *[]byte
 | 
			
		||||
	Comment string
 | 
			
		||||
	URL     string
 | 
			
		||||
	Size    int64
 | 
			
		||||
	Avatar  bool
 | 
			
		||||
	SHA     string
 | 
			
		||||
	Name     string
 | 
			
		||||
	Data     *[]byte
 | 
			
		||||
	Comment  string
 | 
			
		||||
	URL      string
 | 
			
		||||
	Size     int64
 | 
			
		||||
	Avatar   bool
 | 
			
		||||
	SHA      string
 | 
			
		||||
	NativeID string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ChannelInfo struct {
 | 
			
		||||
@@ -138,6 +140,7 @@ type Protocol struct {
 | 
			
		||||
	QuoteDisable           bool       // telegram
 | 
			
		||||
	QuoteFormat            string     // telegram
 | 
			
		||||
	QuoteLengthLimit       int        // telegram
 | 
			
		||||
	RealName               string     // IRC
 | 
			
		||||
	RejoinDelay            int        // IRC
 | 
			
		||||
	ReplaceMessages        [][]string // all protocols
 | 
			
		||||
	ReplaceNicks           [][]string // all protocols
 | 
			
		||||
@@ -167,8 +170,9 @@ type Protocol struct {
 | 
			
		||||
	UseTLS                 bool       // IRC
 | 
			
		||||
	UseDiscriminator       bool       // discord
 | 
			
		||||
	UseFirstName           bool       // telegram
 | 
			
		||||
	UseUserName            bool       // discord, matrix
 | 
			
		||||
	UseUserName            bool       // discord, matrix, mattermost
 | 
			
		||||
	UseInsecureURL         bool       // telegram
 | 
			
		||||
	UserName               string     // IRC
 | 
			
		||||
	VerboseJoinPart        bool       // IRC
 | 
			
		||||
	WebhookBindAddress     string     // mattermost, slack
 | 
			
		||||
	WebhookURL             string     // mattermost, slack
 | 
			
		||||
 
 | 
			
		||||
@@ -10,10 +10,14 @@ import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/discord/transmitter"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
	lru "github.com/hashicorp/golang-lru"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const MessageLength = 1950
 | 
			
		||||
const (
 | 
			
		||||
	MessageLength = 1950
 | 
			
		||||
	cFileUpload   = "file_upload"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Bdiscord struct {
 | 
			
		||||
	*bridge.Config
 | 
			
		||||
@@ -35,10 +39,20 @@ type Bdiscord struct {
 | 
			
		||||
	// Webhook specific logic
 | 
			
		||||
	useAutoWebhooks bool
 | 
			
		||||
	transmitter     *transmitter.Transmitter
 | 
			
		||||
	cache           *lru.Cache
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New(cfg *bridge.Config) bridge.Bridger {
 | 
			
		||||
	b := &Bdiscord{Config: cfg}
 | 
			
		||||
	newCache, err := lru.New(5000)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		cfg.Log.Fatalf("Could not create LRU cache: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b := &Bdiscord{
 | 
			
		||||
		Config: cfg,
 | 
			
		||||
		cache:  newCache,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.userMemberMap = make(map[string]*discordgo.Member)
 | 
			
		||||
	b.nickMemberMap = make(map[string]*discordgo.Member)
 | 
			
		||||
	b.channelInfoMap = make(map[string]*config.ChannelInfo)
 | 
			
		||||
@@ -75,6 +89,9 @@ func (b *Bdiscord) Connect() error {
 | 
			
		||||
	b.c.AddHandler(b.messageDeleteBulk)
 | 
			
		||||
	b.c.AddHandler(b.memberAdd)
 | 
			
		||||
	b.c.AddHandler(b.memberRemove)
 | 
			
		||||
	if b.GetInt("debuglevel") == 1 {
 | 
			
		||||
		b.c.AddHandler(b.messageEvent)
 | 
			
		||||
	}
 | 
			
		||||
	// Add privileged intent for guild member tracking. This is needed to track nicks
 | 
			
		||||
	// for display names and @mention translation
 | 
			
		||||
	b.c.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAllWithoutPrivileged |
 | 
			
		||||
@@ -153,7 +170,7 @@ func (b *Bdiscord) Connect() error {
 | 
			
		||||
		return fmt.Errorf("use of removed WebhookURL setting")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if b.GetInt("debuglevel") > 0 {
 | 
			
		||||
	if b.GetInt("debuglevel") == 2 {
 | 
			
		||||
		b.Log.Debug("enabling even more discord debug")
 | 
			
		||||
		b.c.Debug = true
 | 
			
		||||
	}
 | 
			
		||||
@@ -280,6 +297,21 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete a file
 | 
			
		||||
	if msg.Event == config.EventFileDelete {
 | 
			
		||||
		if msg.ID == "" {
 | 
			
		||||
			return "", nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if fi, ok := b.cache.Get(cFileUpload + msg.ID); ok {
 | 
			
		||||
			err := b.c.ChannelMessageDelete(channelID, fi.(string)) // nolint:forcetypeassert
 | 
			
		||||
			b.cache.Remove(cFileUpload + msg.ID)
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return "", fmt.Errorf("file %s not found", msg.ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Upload a file if it exists
 | 
			
		||||
	if msg.Extra != nil {
 | 
			
		||||
		for _, rmsg := range helper.HandleExtra(msg, b.General) {
 | 
			
		||||
@@ -327,7 +359,6 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st
 | 
			
		||||
 | 
			
		||||
// handleUploadFile handles native upload of files
 | 
			
		||||
func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (string, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	for _, f := range msg.Extra["file"] {
 | 
			
		||||
		fi := f.(config.FileInfo)
 | 
			
		||||
		file := discordgo.File{
 | 
			
		||||
@@ -340,10 +371,15 @@ func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (stri
 | 
			
		||||
			Files:           []*discordgo.File{&file},
 | 
			
		||||
			AllowedMentions: b.getAllowedMentions(),
 | 
			
		||||
		}
 | 
			
		||||
		_, err = b.c.ChannelMessageSendComplex(channelID, &m)
 | 
			
		||||
		res, err := b.c.ChannelMessageSendComplex(channelID, &m)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", fmt.Errorf("file upload failed: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// link file_upload_nativeID (file ID from the original bridge) to our upload id
 | 
			
		||||
		// so that we can remove this later when it eg needs to be deleted
 | 
			
		||||
		b.cache.Add(cFileUpload+fi.NativeID, res.ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "", nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,8 @@ package bdiscord
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
	"github.com/davecgh/go-spew/spew"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (b *Bdiscord) messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) { //nolint:unparam
 | 
			
		||||
@@ -31,6 +32,10 @@ func (b *Bdiscord) messageDeleteBulk(s *discordgo.Session, m *discordgo.MessageD
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bdiscord) messageEvent(s *discordgo.Session, m *discordgo.Event) {
 | 
			
		||||
	b.Log.Debug(spew.Sdump(m.Struct))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bdiscord) messageTyping(s *discordgo.Session, m *discordgo.TypingStart) {
 | 
			
		||||
	if !b.GetBool("ShowUserTyping") {
 | 
			
		||||
		return
 | 
			
		||||
@@ -51,7 +56,7 @@ func (b *Bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdat
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// only when message is actually edited
 | 
			
		||||
	if m.Message.EditedTimestamp != "" {
 | 
			
		||||
	if m.Message.EditedTimestamp != nil {
 | 
			
		||||
		b.Log.Debugf("Sending edit message")
 | 
			
		||||
		m.Content += b.GetString("EditSuffix")
 | 
			
		||||
		msg := &discordgo.MessageCreate{
 | 
			
		||||
@@ -82,8 +87,9 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
 | 
			
		||||
 | 
			
		||||
	rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg", UserID: m.Author.ID, ID: m.ID}
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("== Receiving event %#v", m.Message)
 | 
			
		||||
 | 
			
		||||
	if m.Content != "" {
 | 
			
		||||
		b.Log.Debugf("== Receiving event %#v", m.Message)
 | 
			
		||||
		m.Message.Content = b.replaceChannelMentions(m.Message.Content)
 | 
			
		||||
		rmsg.Text, err = m.ContentWithMoreMentionsReplaced(b.c)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ package bdiscord
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode"
 | 
			
		||||
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (b *Bdiscord) getAllowedMentions() *discordgo.MessageAllowedMentions {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ import (
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
	log "github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package transmitter
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// isDiscordPermissionError returns false for nil, and true if a Discord RESTError with code discordgo.ErrorCodeMissionPermissions
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// shouldMessageUseWebhooks checks if have a channel specific webhook, if we're not using auto webhooks
 | 
			
		||||
@@ -82,16 +82,14 @@ func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordg
 | 
			
		||||
				ContentType: "",
 | 
			
		||||
				Reader:      bytes.NewReader(*fi.Data),
 | 
			
		||||
			}
 | 
			
		||||
			content := ""
 | 
			
		||||
			if msg.Text == "" {
 | 
			
		||||
				content = fi.Comment
 | 
			
		||||
			}
 | 
			
		||||
			content := fi.Comment
 | 
			
		||||
 | 
			
		||||
			_, e2 := b.transmitter.Send(
 | 
			
		||||
				channelID,
 | 
			
		||||
				&discordgo.WebhookParams{
 | 
			
		||||
					Username:        msg.Username,
 | 
			
		||||
					AvatarURL:       msg.Avatar,
 | 
			
		||||
					File:            &file,
 | 
			
		||||
					Files:           []*discordgo.File{&file},
 | 
			
		||||
					Content:         content,
 | 
			
		||||
					AllowedMentions: b.getAllowedMentions(),
 | 
			
		||||
				},
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										252
									
								
								bridge/harmony/harmony.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								bridge/harmony/harmony.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,252 @@
 | 
			
		||||
package harmony
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/harmony-development/shibshib"
 | 
			
		||||
	chatv1 "github.com/harmony-development/shibshib/gen/chat/v1"
 | 
			
		||||
	typesv1 "github.com/harmony-development/shibshib/gen/harmonytypes/v1"
 | 
			
		||||
	profilev1 "github.com/harmony-development/shibshib/gen/profile/v1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type cachedProfile struct {
 | 
			
		||||
	data        *profilev1.GetProfileResponse
 | 
			
		||||
	lastUpdated time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Bharmony struct {
 | 
			
		||||
	*bridge.Config
 | 
			
		||||
 | 
			
		||||
	c            *shibshib.Client
 | 
			
		||||
	profileCache map[uint64]cachedProfile
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func uToStr(in uint64) string {
 | 
			
		||||
	return strconv.FormatUint(in, 10)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func strToU(in string) (uint64, error) {
 | 
			
		||||
	return strconv.ParseUint(in, 10, 64)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New(cfg *bridge.Config) bridge.Bridger {
 | 
			
		||||
	b := &Bharmony{
 | 
			
		||||
		Config:       cfg,
 | 
			
		||||
		profileCache: map[uint64]cachedProfile{},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) getProfile(u uint64) (*profilev1.GetProfileResponse, error) {
 | 
			
		||||
	if v, ok := b.profileCache[u]; ok && time.Since(v.lastUpdated) < time.Minute*10 {
 | 
			
		||||
		return v.data, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := b.c.ProfileKit.GetProfile(&profilev1.GetProfileRequest{
 | 
			
		||||
		UserId: u,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if v, ok := b.profileCache[u]; ok {
 | 
			
		||||
			return v.data, nil
 | 
			
		||||
		}
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	b.profileCache[u] = cachedProfile{
 | 
			
		||||
		data:        resp,
 | 
			
		||||
		lastUpdated: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) avatarFor(m *chatv1.Message) string {
 | 
			
		||||
	if m.Overrides != nil {
 | 
			
		||||
		return m.Overrides.GetAvatar()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	profi, err := b.getProfile(m.AuthorId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return b.c.TransformHMCURL(profi.Profile.GetUserAvatar())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) usernameFor(m *chatv1.Message) string {
 | 
			
		||||
	if m.Overrides != nil {
 | 
			
		||||
		return m.Overrides.GetUsername()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	profi, err := b.getProfile(m.AuthorId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return profi.Profile.UserName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) toMessage(msg *shibshib.LocatedMessage) config.Message {
 | 
			
		||||
	message := config.Message{}
 | 
			
		||||
	message.Account = b.Account
 | 
			
		||||
	message.UserID = uToStr(msg.Message.AuthorId)
 | 
			
		||||
	message.Avatar = b.avatarFor(msg.Message)
 | 
			
		||||
	message.Username = b.usernameFor(msg.Message)
 | 
			
		||||
	message.Channel = uToStr(msg.ChannelID)
 | 
			
		||||
	message.ID = uToStr(msg.MessageId)
 | 
			
		||||
 | 
			
		||||
	switch content := msg.Message.Content.Content.(type) {
 | 
			
		||||
	case *chatv1.Content_EmbedMessage:
 | 
			
		||||
		message.Text = "Embed"
 | 
			
		||||
	case *chatv1.Content_AttachmentMessage:
 | 
			
		||||
		var s strings.Builder
 | 
			
		||||
		for idx, attach := range content.AttachmentMessage.Files {
 | 
			
		||||
			s.WriteString(b.c.TransformHMCURL(attach.Id))
 | 
			
		||||
			if idx < len(content.AttachmentMessage.Files)-1 {
 | 
			
		||||
				s.WriteString(", ")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		message.Text = s.String()
 | 
			
		||||
	case *chatv1.Content_PhotoMessage:
 | 
			
		||||
		var s strings.Builder
 | 
			
		||||
		for idx, attach := range content.PhotoMessage.GetPhotos() {
 | 
			
		||||
			s.WriteString(attach.GetCaption().GetText())
 | 
			
		||||
			s.WriteString("\n")
 | 
			
		||||
			s.WriteString(b.c.TransformHMCURL(attach.GetHmc()))
 | 
			
		||||
			if idx < len(content.PhotoMessage.GetPhotos())-1 {
 | 
			
		||||
				s.WriteString("\n\n")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		message.Text = s.String()
 | 
			
		||||
	case *chatv1.Content_TextMessage:
 | 
			
		||||
		message.Text = content.TextMessage.Content.Text
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return message
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) outputMessages() {
 | 
			
		||||
	for {
 | 
			
		||||
		msg := <-b.c.EventsStream()
 | 
			
		||||
 | 
			
		||||
		if msg.Message.AuthorId == b.c.UserID {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		b.Remote <- b.toMessage(msg)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) GetUint64(conf string) uint64 {
 | 
			
		||||
	num, err := strToU(b.GetString(conf))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return num
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) Connect() (err error) {
 | 
			
		||||
	b.c, err = shibshib.NewClient(b.GetString("Homeserver"), b.GetString("Token"), b.GetUint64("UserID"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	b.c.SubscribeToGuild(b.GetUint64("Community"))
 | 
			
		||||
 | 
			
		||||
	go b.outputMessages()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) send(msg config.Message) (id string, err error) {
 | 
			
		||||
	msgChan, err := strToU(msg.Channel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	retID, err := b.c.ChatKit.SendMessage(&chatv1.SendMessageRequest{
 | 
			
		||||
		GuildId:   b.GetUint64("Community"),
 | 
			
		||||
		ChannelId: msgChan,
 | 
			
		||||
		Content: &chatv1.Content{
 | 
			
		||||
			Content: &chatv1.Content_TextMessage{
 | 
			
		||||
				TextMessage: &chatv1.Content_TextContent{
 | 
			
		||||
					Content: &chatv1.FormattedText{
 | 
			
		||||
						Text: msg.Text,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Overrides: &chatv1.Overrides{
 | 
			
		||||
			Username: &msg.Username,
 | 
			
		||||
			Avatar:   &msg.Avatar,
 | 
			
		||||
			Reason:   &chatv1.Overrides_Bridge{Bridge: &typesv1.Empty{}},
 | 
			
		||||
		},
 | 
			
		||||
		InReplyTo: nil,
 | 
			
		||||
		EchoId:    nil,
 | 
			
		||||
		Metadata:  nil,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = fmt.Errorf("send: error sending message: %w", err)
 | 
			
		||||
		log.Println(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return uToStr(retID.MessageId), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) delete(msg config.Message) (id string, err error) {
 | 
			
		||||
	msgChan, err := strToU(msg.Channel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msgID, err := strToU(msg.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = b.c.ChatKit.DeleteMessage(&chatv1.DeleteMessageRequest{
 | 
			
		||||
		GuildId:   b.GetUint64("Community"),
 | 
			
		||||
		ChannelId: msgChan,
 | 
			
		||||
		MessageId: msgID,
 | 
			
		||||
	})
 | 
			
		||||
	return "", err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) typing(msg config.Message) (id string, err error) {
 | 
			
		||||
	msgChan, err := strToU(msg.Channel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = b.c.ChatKit.Typing(&chatv1.TypingRequest{
 | 
			
		||||
		GuildId:   b.GetUint64("Community"),
 | 
			
		||||
		ChannelId: msgChan,
 | 
			
		||||
	})
 | 
			
		||||
	return "", err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) Send(msg config.Message) (id string, err error) {
 | 
			
		||||
	switch msg.Event {
 | 
			
		||||
	case "":
 | 
			
		||||
		return b.send(msg)
 | 
			
		||||
	case config.EventMsgDelete:
 | 
			
		||||
		return b.delete(msg)
 | 
			
		||||
	case config.EventUserTyping:
 | 
			
		||||
		return b.typing(msg)
 | 
			
		||||
	default:
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) JoinChannel(channel config.ChannelInfo) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bharmony) Disconnect() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -5,10 +5,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"image/png"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
@@ -171,17 +168,23 @@ func HandleDownloadSize(logger *logrus.Entry, msg *config.Message, name string,
 | 
			
		||||
 | 
			
		||||
// HandleDownloadData adds the data for a remote file into a Matterbridge gateway message.
 | 
			
		||||
func HandleDownloadData(logger *logrus.Entry, msg *config.Message, name, comment, url string, data *[]byte, general *config.Protocol) {
 | 
			
		||||
	HandleDownloadData2(logger, msg, name, "", comment, url, data, general)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HandleDownloadData adds the data for a remote file into a Matterbridge gateway message.
 | 
			
		||||
func HandleDownloadData2(logger *logrus.Entry, msg *config.Message, name, id, comment, url string, data *[]byte, general *config.Protocol) {
 | 
			
		||||
	var avatar bool
 | 
			
		||||
	logger.Debugf("Download OK %#v %#v", name, len(*data))
 | 
			
		||||
	if msg.Event == config.EventAvatarDownload {
 | 
			
		||||
		avatar = true
 | 
			
		||||
	}
 | 
			
		||||
	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{
 | 
			
		||||
		Name:    name,
 | 
			
		||||
		Data:    data,
 | 
			
		||||
		URL:     url,
 | 
			
		||||
		Comment: comment,
 | 
			
		||||
		Avatar:  avatar,
 | 
			
		||||
		Name:     name,
 | 
			
		||||
		Data:     data,
 | 
			
		||||
		URL:      url,
 | 
			
		||||
		Comment:  comment,
 | 
			
		||||
		Avatar:   avatar,
 | 
			
		||||
		NativeID: id,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -239,66 +242,3 @@ func ConvertWebPToPNG(data *[]byte) error {
 | 
			
		||||
	*data = w.Bytes()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CanConvertTgsToX Checks whether the external command necessary for ConvertTgsToX works.
 | 
			
		||||
func CanConvertTgsToX() error {
 | 
			
		||||
	// We depend on the fact that `lottie_convert.py --help` has exit status 0.
 | 
			
		||||
	// Hyrum's Law predicted this, and Murphy's Law predicts that this will break eventually.
 | 
			
		||||
	// However, there is no alternative like `lottie_convert.py --is-properly-installed`
 | 
			
		||||
	cmd := exec.Command("lottie_convert.py", "--help")
 | 
			
		||||
	return cmd.Run()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConvertTgsToWebP convert input data (which should be tgs format) to WebP format
 | 
			
		||||
// This relies on an external command, which is ugly, but works.
 | 
			
		||||
func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) error {
 | 
			
		||||
	// lottie can't handle input from a pipe, so write to a temporary file:
 | 
			
		||||
	tmpInFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-input-*.tgs")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	tmpInFileName := tmpInFile.Name()
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if removeErr := os.Remove(tmpInFileName); removeErr != nil {
 | 
			
		||||
			logger.Errorf("Could not delete temporary (input) file %s: %v", tmpInFileName, removeErr)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	// lottie can handle writing to a pipe, but there is no way to do that platform-independently.
 | 
			
		||||
	// "/dev/stdout" won't work on Windows, and "-" upsets Cairo for some reason. So we need another file:
 | 
			
		||||
	tmpOutFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-output-*.data")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	tmpOutFileName := tmpOutFile.Name()
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if removeErr := os.Remove(tmpOutFileName); removeErr != nil {
 | 
			
		||||
			logger.Errorf("Could not delete temporary (output) file %s: %v", tmpOutFileName, removeErr)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if _, writeErr := tmpInFile.Write(*data); writeErr != nil {
 | 
			
		||||
		return writeErr
 | 
			
		||||
	}
 | 
			
		||||
	// Must close before calling lottie to avoid data races:
 | 
			
		||||
	if closeErr := tmpInFile.Close(); closeErr != nil {
 | 
			
		||||
		return closeErr
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call lottie to transform:
 | 
			
		||||
	cmd := exec.Command("lottie_convert.py", "--input-format", "lottie", "--output-format", outputFormat, tmpInFileName, tmpOutFileName)
 | 
			
		||||
	cmd.Stdout = nil
 | 
			
		||||
	cmd.Stderr = nil
 | 
			
		||||
	// NB: lottie writes progress into to stderr in all cases.
 | 
			
		||||
	_, stderr := cmd.Output()
 | 
			
		||||
	if stderr != nil {
 | 
			
		||||
		// 'stderr' already contains some parts of Stderr, because it was set to 'nil'.
 | 
			
		||||
		return stderr
 | 
			
		||||
	}
 | 
			
		||||
	dataContents, err := ioutil.ReadFile(tmpOutFileName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*data = dataContents
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								bridge/helper/libtgsconverter.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								bridge/helper/libtgsconverter.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
//go:build cgo
 | 
			
		||||
// +build cgo
 | 
			
		||||
 | 
			
		||||
package helper
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/Benau/tgsconverter/libtgsconverter"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func CanConvertTgsToX() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConvertTgsToX convert input data (which should be tgs format) to any format supported by libtgsconverter
 | 
			
		||||
func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) error {
 | 
			
		||||
	options := libtgsconverter.NewConverterOptions()
 | 
			
		||||
	options.SetExtension(outputFormat)
 | 
			
		||||
	blob, err := libtgsconverter.ImportFromData(*data, options)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to run libtgsconverter.ImportFromData: %s", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*data = blob
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SupportsFormat(format string) bool {
 | 
			
		||||
	return libtgsconverter.SupportsExtension(format)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LottieBackend() string {
 | 
			
		||||
	return "libtgsconverter"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										89
									
								
								bridge/helper/lottie_convert.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								bridge/helper/lottie_convert.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
// +build !cgo
 | 
			
		||||
 | 
			
		||||
package helper
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CanConvertTgsToX Checks whether the external command necessary for ConvertTgsToX works.
 | 
			
		||||
func CanConvertTgsToX() error {
 | 
			
		||||
	// We depend on the fact that `lottie_convert.py --help` has exit status 0.
 | 
			
		||||
	// Hyrum's Law predicted this, and Murphy's Law predicts that this will break eventually.
 | 
			
		||||
	// However, there is no alternative like `lottie_convert.py --is-properly-installed`
 | 
			
		||||
	cmd := exec.Command("lottie_convert.py", "--help")
 | 
			
		||||
	return cmd.Run()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConvertTgsToWebP convert input data (which should be tgs format) to WebP format
 | 
			
		||||
// This relies on an external command, which is ugly, but works.
 | 
			
		||||
func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) error {
 | 
			
		||||
	// lottie can't handle input from a pipe, so write to a temporary file:
 | 
			
		||||
	tmpInFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-input-*.tgs")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	tmpInFileName := tmpInFile.Name()
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if removeErr := os.Remove(tmpInFileName); removeErr != nil {
 | 
			
		||||
			logger.Errorf("Could not delete temporary (input) file %s: %v", tmpInFileName, removeErr)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	// lottie can handle writing to a pipe, but there is no way to do that platform-independently.
 | 
			
		||||
	// "/dev/stdout" won't work on Windows, and "-" upsets Cairo for some reason. So we need another file:
 | 
			
		||||
	tmpOutFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-output-*.data")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	tmpOutFileName := tmpOutFile.Name()
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if removeErr := os.Remove(tmpOutFileName); removeErr != nil {
 | 
			
		||||
			logger.Errorf("Could not delete temporary (output) file %s: %v", tmpOutFileName, removeErr)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if _, writeErr := tmpInFile.Write(*data); writeErr != nil {
 | 
			
		||||
		return writeErr
 | 
			
		||||
	}
 | 
			
		||||
	// Must close before calling lottie to avoid data races:
 | 
			
		||||
	if closeErr := tmpInFile.Close(); closeErr != nil {
 | 
			
		||||
		return closeErr
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call lottie to transform:
 | 
			
		||||
	cmd := exec.Command("lottie_convert.py", "--input-format", "lottie", "--output-format", outputFormat, tmpInFileName, tmpOutFileName)
 | 
			
		||||
	cmd.Stdout = nil
 | 
			
		||||
	cmd.Stderr = nil
 | 
			
		||||
	// NB: lottie writes progress into to stderr in all cases.
 | 
			
		||||
	_, stderr := cmd.Output()
 | 
			
		||||
	if stderr != nil {
 | 
			
		||||
		// 'stderr' already contains some parts of Stderr, because it was set to 'nil'.
 | 
			
		||||
		return stderr
 | 
			
		||||
	}
 | 
			
		||||
	dataContents, err := ioutil.ReadFile(tmpOutFileName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*data = dataContents
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SupportsFormat(format string) bool {
 | 
			
		||||
	switch format {
 | 
			
		||||
	case "png":
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case "webp":
 | 
			
		||||
		return true
 | 
			
		||||
	default:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LottieBackend() string {
 | 
			
		||||
	return "lottie_convert.py"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								bridge/irc/charset.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								bridge/irc/charset.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
package birc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"golang.org/x/text/encoding"
 | 
			
		||||
	"golang.org/x/text/encoding/japanese"
 | 
			
		||||
	"golang.org/x/text/encoding/korean"
 | 
			
		||||
	"golang.org/x/text/encoding/simplifiedchinese"
 | 
			
		||||
	"golang.org/x/text/encoding/traditionalchinese"
 | 
			
		||||
	"golang.org/x/text/encoding/unicode"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var encoders = map[string]encoding.Encoding{
 | 
			
		||||
	"utf-8":       unicode.UTF8,
 | 
			
		||||
	"iso-2022-jp": japanese.ISO2022JP,
 | 
			
		||||
	"big5":        traditionalchinese.Big5,
 | 
			
		||||
	"gbk":         simplifiedchinese.GBK,
 | 
			
		||||
	"euc-kr":      korean.EUCKR,
 | 
			
		||||
	"gb2312":      simplifiedchinese.HZGB2312,
 | 
			
		||||
	"shift-jis":   japanese.ShiftJIS,
 | 
			
		||||
	"euc-jp":      japanese.EUCJP,
 | 
			
		||||
	"gb18030":     simplifiedchinese.GB18030,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toUTF8(from string, input string) string {
 | 
			
		||||
	enc, ok := encoders[from]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return input
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res, _ := enc.NewDecoder().String(input)
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
@@ -11,7 +11,6 @@ import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/lrstanley/girc"
 | 
			
		||||
	"github.com/missdeer/golib/ic"
 | 
			
		||||
	"github.com/paulrosania/go-charset/charset"
 | 
			
		||||
	"github.com/saintfish/chardet"
 | 
			
		||||
 | 
			
		||||
@@ -24,12 +23,12 @@ func (b *Birc) handleCharset(msg *config.Message) error {
 | 
			
		||||
	if b.GetString("Charset") != "" {
 | 
			
		||||
		switch b.GetString("Charset") {
 | 
			
		||||
		case "gbk", "gb18030", "gb2312", "big5", "euc-kr", "euc-jp", "shift-jis", "iso-2022-jp":
 | 
			
		||||
			msg.Text = ic.ConvertString("utf-8", b.GetString("Charset"), msg.Text)
 | 
			
		||||
			msg.Text = toUTF8(b.GetString("Charset"), msg.Text)
 | 
			
		||||
		default:
 | 
			
		||||
			buf := new(bytes.Buffer)
 | 
			
		||||
			w, err := charset.NewWriter(b.GetString("Charset"), buf)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Errorf("charset from utf-8 conversion failed: %s", err)
 | 
			
		||||
				b.Log.Errorf("charset to utf-8 conversion failed: %s", err)
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			fmt.Fprint(w, msg.Text)
 | 
			
		||||
@@ -227,7 +226,7 @@ func (b *Birc) handlePrivMsg(client *girc.Client, event girc.Event) {
 | 
			
		||||
	}
 | 
			
		||||
	switch mycharset {
 | 
			
		||||
	case "gbk", "gb18030", "gb2312", "big5", "euc-kr", "euc-jp", "shift-jis", "iso-2022-jp":
 | 
			
		||||
		rmsg.Text = ic.ConvertString("utf-8", b.GetString("Charset"), rmsg.Text)
 | 
			
		||||
		rmsg.Text = toUTF8(b.GetString("Charset"), rmsg.Text)
 | 
			
		||||
	default:
 | 
			
		||||
		r, err := charset.NewReader(mycharset, strings.NewReader(rmsg.Text))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package birc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"hash/crc32"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
@@ -72,6 +73,10 @@ func (b *Birc) Command(msg *config.Message) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Birc) Connect() error {
 | 
			
		||||
	if b.GetBool("UseSASL") && b.GetString("TLSClientCertificate") != "" {
 | 
			
		||||
		return errors.New("you can't enable SASL and TLSClientCertificate at the same time")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Local = make(chan config.Message, b.MessageQueue+10)
 | 
			
		||||
	b.Log.Infof("Connecting %s", b.GetString("Server"))
 | 
			
		||||
 | 
			
		||||
@@ -271,8 +276,11 @@ func (b *Birc) getClient() (*girc.Client, error) {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	user := b.GetString("UserName")
 | 
			
		||||
	if user == "" {
 | 
			
		||||
		user = b.GetString("Nick")
 | 
			
		||||
	}
 | 
			
		||||
	// fix strict user handling of girc
 | 
			
		||||
	user := b.GetString("Nick")
 | 
			
		||||
	for !girc.IsValidUser(user) {
 | 
			
		||||
		if len(user) == 1 || len(user) == 0 {
 | 
			
		||||
			user = "matterbridge"
 | 
			
		||||
@@ -280,6 +288,10 @@ func (b *Birc) getClient() (*girc.Client, error) {
 | 
			
		||||
		}
 | 
			
		||||
		user = user[1:]
 | 
			
		||||
	}
 | 
			
		||||
	realName := b.GetString("RealName")
 | 
			
		||||
	if realName == "" {
 | 
			
		||||
		realName = b.GetString("Nick")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	debug := ioutil.Discard
 | 
			
		||||
	if b.GetInt("DebugLevel") == 2 {
 | 
			
		||||
@@ -293,15 +305,21 @@ func (b *Birc) getClient() (*girc.Client, error) {
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("setting pingdelay to %s", pingDelay)
 | 
			
		||||
 | 
			
		||||
	tlsConfig, err := b.getTLSConfig()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i := girc.New(girc.Config{
 | 
			
		||||
		Server:     server,
 | 
			
		||||
		ServerPass: b.GetString("Password"),
 | 
			
		||||
		Port:       port,
 | 
			
		||||
		Nick:       b.GetString("Nick"),
 | 
			
		||||
		User:       user,
 | 
			
		||||
		Name:       b.GetString("Nick"),
 | 
			
		||||
		Name:       realName,
 | 
			
		||||
		SSL:        b.GetBool("UseTLS"),
 | 
			
		||||
		TLSConfig:  &tls.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), ServerName: server}, //nolint:gosec
 | 
			
		||||
		Bind:       b.GetString("Bind"),
 | 
			
		||||
		TLSConfig:  tlsConfig,
 | 
			
		||||
		PingDelay:  pingDelay,
 | 
			
		||||
		// skip gIRC internal rate limiting, since we have our own throttling
 | 
			
		||||
		AllowFlood:    true,
 | 
			
		||||
@@ -344,8 +362,10 @@ func (b *Birc) skipPrivMsg(event girc.Event) bool {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	// don't forward message from ourself
 | 
			
		||||
	if event.Source.Name == b.Nick {
 | 
			
		||||
		return true
 | 
			
		||||
	if event.Source != nil {
 | 
			
		||||
		if event.Source.Name == b.Nick {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// don't forward messages we sent via RELAYMSG
 | 
			
		||||
	if relayedNick, ok := event.Tags.Get("draft/relaymsg"); ok && relayedNick == b.Nick {
 | 
			
		||||
@@ -373,3 +393,23 @@ func (b *Birc) storeNames(client *girc.Client, event girc.Event) {
 | 
			
		||||
func (b *Birc) formatnicks(nicks []string) string {
 | 
			
		||||
	return strings.Join(nicks, ", ") + " currently on IRC"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Birc) getTLSConfig() (*tls.Config, error) {
 | 
			
		||||
	server, _, _ := net.SplitHostPort(b.GetString("server"))
 | 
			
		||||
 | 
			
		||||
	tlsConfig := &tls.Config{
 | 
			
		||||
		InsecureSkipVerify: b.GetBool("skiptlsverify"), //nolint:gosec
 | 
			
		||||
		ServerName:         server,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if filename := b.GetString("TLSClientCertificate"); filename != "" {
 | 
			
		||||
		cert, err := tls.LoadX509KeyPair(filename, filename)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		tlsConfig.Certificates = []tls.Certificate{cert}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tlsConfig, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -48,8 +48,10 @@ type matrixUsername struct {
 | 
			
		||||
 | 
			
		||||
// SubTextMessage represents the new content of the message in edit messages.
 | 
			
		||||
type SubTextMessage struct {
 | 
			
		||||
	MsgType string `json:"msgtype"`
 | 
			
		||||
	Body    string `json:"body"`
 | 
			
		||||
	MsgType       string `json:"msgtype"`
 | 
			
		||||
	Body          string `json:"body"`
 | 
			
		||||
	FormattedBody string `json:"formatted_body,omitempty"`
 | 
			
		||||
	Format        string `json:"format,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageRelation explains how the current message relates to a previous message.
 | 
			
		||||
@@ -65,6 +67,19 @@ type EditedMessage struct {
 | 
			
		||||
	matrix.TextMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type InReplyToRelationContent struct {
 | 
			
		||||
	EventID string `json:"event_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type InReplyToRelation struct {
 | 
			
		||||
	InReplyTo InReplyToRelationContent `json:"m.in_reply_to"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ReplyMessage struct {
 | 
			
		||||
	RelatedTo InReplyToRelation `json:"m.relates_to"`
 | 
			
		||||
	matrix.TextMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New(cfg *bridge.Config) bridge.Bridger {
 | 
			
		||||
	b := &Bmatrix{Config: cfg}
 | 
			
		||||
	b.RoomMap = make(map[string]string)
 | 
			
		||||
@@ -138,7 +153,13 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
 | 
			
		||||
		m := matrix.TextMessage{
 | 
			
		||||
			MsgType:       "m.emote",
 | 
			
		||||
			Body:          username.plain + msg.Text,
 | 
			
		||||
			FormattedBody: username.formatted + msg.Text,
 | 
			
		||||
			FormattedBody: username.formatted + helper.ParseMarkdown(msg.Text),
 | 
			
		||||
			Format:        "org.matrix.custom.html",
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if b.GetBool("HTMLDisable") {
 | 
			
		||||
			m.Format = ""
 | 
			
		||||
			m.FormattedBody = ""
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		msgID := ""
 | 
			
		||||
@@ -201,20 +222,29 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
 | 
			
		||||
 | 
			
		||||
	// Edit message if we have an ID
 | 
			
		||||
	if msg.ID != "" {
 | 
			
		||||
		rmsg := EditedMessage{TextMessage: matrix.TextMessage{
 | 
			
		||||
			Body:    username.plain + msg.Text,
 | 
			
		||||
			MsgType: "m.text",
 | 
			
		||||
		}}
 | 
			
		||||
		if b.GetBool("HTMLDisable") {
 | 
			
		||||
			rmsg.TextMessage.FormattedBody = username.formatted + "* " + msg.Text
 | 
			
		||||
		} else {
 | 
			
		||||
			rmsg.Format = "org.matrix.custom.html"
 | 
			
		||||
			rmsg.TextMessage.FormattedBody = username.formatted + "* " + helper.ParseMarkdown(msg.Text)
 | 
			
		||||
		rmsg := EditedMessage{
 | 
			
		||||
			TextMessage: matrix.TextMessage{
 | 
			
		||||
				Body:          username.plain + msg.Text,
 | 
			
		||||
				MsgType:       "m.text",
 | 
			
		||||
				Format:        "org.matrix.custom.html",
 | 
			
		||||
				FormattedBody: username.formatted + helper.ParseMarkdown(msg.Text),
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rmsg.NewContent = SubTextMessage{
 | 
			
		||||
			Body:    rmsg.TextMessage.Body,
 | 
			
		||||
			MsgType: "m.text",
 | 
			
		||||
			Body:          rmsg.TextMessage.Body,
 | 
			
		||||
			FormattedBody: rmsg.TextMessage.FormattedBody,
 | 
			
		||||
			Format:        rmsg.TextMessage.Format,
 | 
			
		||||
			MsgType:       "m.text",
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if b.GetBool("HTMLDisable") {
 | 
			
		||||
			rmsg.TextMessage.Format = ""
 | 
			
		||||
			rmsg.TextMessage.FormattedBody = ""
 | 
			
		||||
			rmsg.NewContent.Format = ""
 | 
			
		||||
			rmsg.NewContent.FormattedBody = ""
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rmsg.RelatedTo = MessageRelation{
 | 
			
		||||
			EventID: msg.ID,
 | 
			
		||||
			Type:    "m.replace",
 | 
			
		||||
@@ -238,6 +268,50 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
 | 
			
		||||
			MsgType:       "m.notice",
 | 
			
		||||
			Body:          username.plain + msg.Text,
 | 
			
		||||
			FormattedBody: username.formatted + msg.Text,
 | 
			
		||||
			Format:        "org.matrix.custom.html",
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if b.GetBool("HTMLDisable") {
 | 
			
		||||
			m.Format = ""
 | 
			
		||||
			m.FormattedBody = ""
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var (
 | 
			
		||||
			resp *matrix.RespSendEvent
 | 
			
		||||
			err  error
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		err = b.retry(func() error {
 | 
			
		||||
			resp, err = b.mc.SendMessageEvent(channel, "m.room.message", m)
 | 
			
		||||
 | 
			
		||||
			return err
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return resp.EventID, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if msg.ParentValid() {
 | 
			
		||||
		m := ReplyMessage{
 | 
			
		||||
			TextMessage: matrix.TextMessage{
 | 
			
		||||
				MsgType:       "m.text",
 | 
			
		||||
				Body:          username.plain + msg.Text,
 | 
			
		||||
				FormattedBody: username.formatted + helper.ParseMarkdown(msg.Text),
 | 
			
		||||
				Format:        "org.matrix.custom.html",
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if b.GetBool("HTMLDisable") {
 | 
			
		||||
			m.TextMessage.Format = ""
 | 
			
		||||
			m.TextMessage.FormattedBody = ""
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		m.RelatedTo = InReplyToRelation{
 | 
			
		||||
			InReplyTo: InReplyToRelationContent{
 | 
			
		||||
				EventID: msg.ParentID,
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var (
 | 
			
		||||
@@ -301,6 +375,9 @@ func (b *Bmatrix) handlematrix() {
 | 
			
		||||
	syncer.OnEventType("m.room.member", b.handleMemberChange)
 | 
			
		||||
	go func() {
 | 
			
		||||
		for {
 | 
			
		||||
			if b == nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if err := b.mc.Sync(); err != nil {
 | 
			
		||||
				b.Log.Println("Sync() returned ", err)
 | 
			
		||||
			}
 | 
			
		||||
@@ -338,6 +415,35 @@ func (b *Bmatrix) handleEdit(ev *matrix.Event, rmsg config.Message) bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bmatrix) handleReply(ev *matrix.Event, rmsg config.Message) bool {
 | 
			
		||||
	relationInterface, present := ev.Content["m.relates_to"]
 | 
			
		||||
	if !present {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var relation InReplyToRelation
 | 
			
		||||
	if err := interface2Struct(relationInterface, &relation); err != nil {
 | 
			
		||||
		// probably fine
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	body := rmsg.Text
 | 
			
		||||
	for strings.HasPrefix(body, "> ") {
 | 
			
		||||
		lineIdx := strings.IndexRune(body, '\n')
 | 
			
		||||
		if lineIdx == -1 {
 | 
			
		||||
			body = ""
 | 
			
		||||
		} else {
 | 
			
		||||
			body = body[(lineIdx + 1):]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rmsg.Text = body
 | 
			
		||||
	rmsg.ParentID = relation.InReplyTo.EventID
 | 
			
		||||
	b.Remote <- rmsg
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bmatrix) handleMemberChange(ev *matrix.Event) {
 | 
			
		||||
	// Update the displayname on join messages, according to https://matrix.org/docs/spec/client_server/r0.6.1#events-on-change-of-profile-information
 | 
			
		||||
	if ev.Content["membership"] == "join" {
 | 
			
		||||
@@ -400,6 +506,11 @@ func (b *Bmatrix) handleEvent(ev *matrix.Event) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Is it a reply?
 | 
			
		||||
		if b.handleReply(ev, rmsg) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Do we have attachments
 | 
			
		||||
		if b.containsAttachment(ev.Content) {
 | 
			
		||||
			err := b.handleDownloadFile(&rmsg, ev.Content)
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,9 @@ import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/42wim/matterbridge/matterclient"
 | 
			
		||||
	matterclient6 "github.com/matterbridge/matterclient"
 | 
			
		||||
	"github.com/mattermost/mattermost-server/v5/model"
 | 
			
		||||
	model6 "github.com/mattermost/mattermost-server/v6/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// handleDownloadAvatar downloads the avatar of userid from channel
 | 
			
		||||
@@ -21,12 +23,26 @@ func (b *Bmattermost) handleDownloadAvatar(userid string, channel string) {
 | 
			
		||||
		Extra:    make(map[string][]interface{}),
 | 
			
		||||
	}
 | 
			
		||||
	if _, ok := b.avatarMap[userid]; !ok {
 | 
			
		||||
		data, resp := b.mc.Client.GetProfileImage(userid, "")
 | 
			
		||||
		if resp.Error != nil {
 | 
			
		||||
			b.Log.Errorf("ProfileImage download failed for %#v %s", userid, resp.Error)
 | 
			
		||||
			return
 | 
			
		||||
		var (
 | 
			
		||||
			data []byte
 | 
			
		||||
			err  error
 | 
			
		||||
			resp *model.Response
 | 
			
		||||
		)
 | 
			
		||||
		if b.mc6 != nil {
 | 
			
		||||
			data, _, err = b.mc6.Client.GetProfileImage(userid, "")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Errorf("ProfileImage download failed for %#v %s", userid, err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			data, resp = b.mc.Client.GetProfileImage(userid, "")
 | 
			
		||||
			if resp.Error != nil {
 | 
			
		||||
				b.Log.Errorf("ProfileImage download failed for %#v %s", userid, resp.Error)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		err := helper.HandleDownloadSize(b.Log, &rmsg, userid+".png", int64(len(data)), b.General)
 | 
			
		||||
 | 
			
		||||
		err = helper.HandleDownloadSize(b.Log, &rmsg, userid+".png", int64(len(data)), b.General)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Error(err)
 | 
			
		||||
			return
 | 
			
		||||
@@ -38,6 +54,10 @@ func (b *Bmattermost) handleDownloadAvatar(userid string, channel string) {
 | 
			
		||||
 | 
			
		||||
// handleDownloadFile handles file download
 | 
			
		||||
func (b *Bmattermost) handleDownloadFile(rmsg *config.Message, id string) error {
 | 
			
		||||
	if b.mc6 != nil {
 | 
			
		||||
		return b.handleDownloadFile6(rmsg, id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	url, _ := b.mc.Client.GetFileLink(id)
 | 
			
		||||
	finfo, resp := b.mc.Client.GetFileInfo(id)
 | 
			
		||||
	if resp.Error != nil {
 | 
			
		||||
@@ -55,6 +75,25 @@ func (b *Bmattermost) handleDownloadFile(rmsg *config.Message, id string) error
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// nolint:wrapcheck
 | 
			
		||||
func (b *Bmattermost) handleDownloadFile6(rmsg *config.Message, id string) error {
 | 
			
		||||
	url, _, _ := b.mc6.Client.GetFileLink(id)
 | 
			
		||||
	finfo, _, err := b.mc6.Client.GetFileInfo(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = helper.HandleDownloadSize(b.Log, rmsg, finfo.Name, finfo.Size, b.General)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	data, _, err := b.mc6.Client.DownloadFile(id, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	helper.HandleDownloadData(b.Log, rmsg, finfo.Name, rmsg.Text, url, &data, b.General)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bmattermost) handleMatter() {
 | 
			
		||||
	messages := make(chan *config.Message)
 | 
			
		||||
	if b.GetString("WebhookBindAddress") != "" {
 | 
			
		||||
@@ -87,6 +126,12 @@ func (b *Bmattermost) handleMatter() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bmattermost) handleMatterClient(messages chan *config.Message) {
 | 
			
		||||
	if b.mc6 != nil {
 | 
			
		||||
		b.Log.Debug("starting matterclient6")
 | 
			
		||||
		b.handleMatterClient6(messages)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for message := range b.mc.MessageChan {
 | 
			
		||||
		b.Log.Debugf("%#v", message.Raw.Data)
 | 
			
		||||
 | 
			
		||||
@@ -95,9 +140,14 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		channelName := b.getChannelName(message.Post.ChannelId)
 | 
			
		||||
		if channelName == "" {
 | 
			
		||||
			channelName = message.Channel
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// only download avatars if we have a place to upload them (configured mediaserver)
 | 
			
		||||
		if b.General.MediaServerUpload != "" || b.General.MediaDownloadPath != "" {
 | 
			
		||||
			b.handleDownloadAvatar(message.UserID, message.Channel)
 | 
			
		||||
			b.handleDownloadAvatar(message.UserID, channelName)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		b.Log.Debugf("== Receiving event %#v", message)
 | 
			
		||||
@@ -105,7 +155,7 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) {
 | 
			
		||||
		rmsg := &config.Message{
 | 
			
		||||
			Username: message.Username,
 | 
			
		||||
			UserID:   message.UserID,
 | 
			
		||||
			Channel:  message.Channel,
 | 
			
		||||
			Channel:  channelName,
 | 
			
		||||
			Text:     message.Text,
 | 
			
		||||
			ID:       message.Post.Id,
 | 
			
		||||
			ParentID: message.Post.RootId, // ParentID is obsolete with mattermost
 | 
			
		||||
@@ -132,8 +182,72 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Use nickname instead of username if defined
 | 
			
		||||
		if nick := b.mc.GetNickName(rmsg.UserID); nick != "" {
 | 
			
		||||
			rmsg.Username = nick
 | 
			
		||||
		if !b.GetBool("useusername") {
 | 
			
		||||
			if nick := b.mc.GetNickName(rmsg.UserID); nick != "" {
 | 
			
		||||
				rmsg.Username = nick
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		messages <- rmsg
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// nolint:cyclop
 | 
			
		||||
func (b *Bmattermost) handleMatterClient6(messages chan *config.Message) {
 | 
			
		||||
	for message := range b.mc6.MessageChan {
 | 
			
		||||
		b.Log.Debugf("%#v %#v", message.Raw.GetData(), message.Raw.EventType())
 | 
			
		||||
 | 
			
		||||
		if b.skipMessage6(message) {
 | 
			
		||||
			b.Log.Debugf("Skipped message: %#v", message)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		channelName := b.getChannelName(message.Post.ChannelId)
 | 
			
		||||
		if channelName == "" {
 | 
			
		||||
			channelName = message.Channel
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// only download avatars if we have a place to upload them (configured mediaserver)
 | 
			
		||||
		if b.General.MediaServerUpload != "" || b.General.MediaDownloadPath != "" {
 | 
			
		||||
			b.handleDownloadAvatar(message.UserID, channelName)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		b.Log.Debugf("== Receiving event %#v", message)
 | 
			
		||||
 | 
			
		||||
		rmsg := &config.Message{
 | 
			
		||||
			Username: message.Username,
 | 
			
		||||
			UserID:   message.UserID,
 | 
			
		||||
			Channel:  channelName,
 | 
			
		||||
			Text:     message.Text,
 | 
			
		||||
			ID:       message.Post.Id,
 | 
			
		||||
			ParentID: message.Post.RootId, // ParentID is obsolete with mattermost
 | 
			
		||||
			Extra:    make(map[string][]interface{}),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// handle mattermost post properties (override username and attachments)
 | 
			
		||||
		b.handleProps6(rmsg, message)
 | 
			
		||||
 | 
			
		||||
		// create a text for bridges that don't support native editing
 | 
			
		||||
		if message.Raw.EventType() == model6.WebsocketEventPostEdited && !b.GetBool("EditDisable") {
 | 
			
		||||
			rmsg.Text = message.Text + b.GetString("EditSuffix")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if message.Raw.EventType() == model6.WebsocketEventPostDeleted {
 | 
			
		||||
			rmsg.Event = config.EventMsgDelete
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, id := range message.Post.FileIds {
 | 
			
		||||
			err := b.handleDownloadFile(rmsg, id)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Errorf("download failed: %s", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Use nickname instead of username if defined
 | 
			
		||||
		if !b.GetBool("useusername") {
 | 
			
		||||
			if nick := b.mc6.GetNickName(rmsg.UserID); nick != "" {
 | 
			
		||||
				rmsg.Username = nick
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		messages <- rmsg
 | 
			
		||||
@@ -144,6 +258,7 @@ func (b *Bmattermost) handleMatterHook(messages chan *config.Message) {
 | 
			
		||||
	for {
 | 
			
		||||
		message := b.mh.Receive()
 | 
			
		||||
		b.Log.Debugf("Receiving from matterhook %#v", message)
 | 
			
		||||
 | 
			
		||||
		messages <- &config.Message{
 | 
			
		||||
			UserID:   message.UserID,
 | 
			
		||||
			Username: message.UserName,
 | 
			
		||||
@@ -155,9 +270,13 @@ func (b *Bmattermost) handleMatterHook(messages chan *config.Message) {
 | 
			
		||||
 | 
			
		||||
// handleUploadFile handles native upload of files
 | 
			
		||||
func (b *Bmattermost) handleUploadFile(msg *config.Message) (string, error) {
 | 
			
		||||
	if b.mc6 != nil {
 | 
			
		||||
		return b.handleUploadFile6(msg)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	var res, id string
 | 
			
		||||
	channelID := b.mc.GetChannelId(msg.Channel, b.TeamID)
 | 
			
		||||
	channelID := b.getChannelID(msg.Channel)
 | 
			
		||||
	for _, f := range msg.Extra["file"] {
 | 
			
		||||
		fi := f.(config.FileInfo)
 | 
			
		||||
		id, err = b.mc.UploadFile(*fi.Data, channelID, fi.Name)
 | 
			
		||||
@@ -173,6 +292,26 @@ func (b *Bmattermost) handleUploadFile(msg *config.Message) (string, error) {
 | 
			
		||||
	return res, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// nolint:forcetypeassert,wrapcheck
 | 
			
		||||
func (b *Bmattermost) handleUploadFile6(msg *config.Message) (string, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var res, id string
 | 
			
		||||
	channelID := b.getChannelID(msg.Channel)
 | 
			
		||||
	for _, f := range msg.Extra["file"] {
 | 
			
		||||
		fi := f.(config.FileInfo)
 | 
			
		||||
		id, err = b.mc6.UploadFile(*fi.Data, channelID, fi.Name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		msg.Text = fi.Comment
 | 
			
		||||
		if b.GetBool("PrefixMessagesWithNick") {
 | 
			
		||||
			msg.Text = msg.Username + msg.Text
 | 
			
		||||
		}
 | 
			
		||||
		res, err = b.mc6.PostMessageWithFiles(channelID, msg.Text, msg.ParentID, []string{id})
 | 
			
		||||
	}
 | 
			
		||||
	return res, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bmattermost) handleProps(rmsg *config.Message, message *matterclient.Message) {
 | 
			
		||||
	props := message.Post.Props
 | 
			
		||||
	if props == nil {
 | 
			
		||||
@@ -197,3 +336,31 @@ func (b *Bmattermost) handleProps(rmsg *config.Message, message *matterclient.Me
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// nolint:forcetypeassert
 | 
			
		||||
func (b *Bmattermost) handleProps6(rmsg *config.Message, message *matterclient6.Message) {
 | 
			
		||||
	props := message.Post.Props
 | 
			
		||||
	if props == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if _, ok := props["override_username"].(string); ok {
 | 
			
		||||
		rmsg.Username = props["override_username"].(string)
 | 
			
		||||
	}
 | 
			
		||||
	if _, ok := props["attachments"].([]interface{}); ok {
 | 
			
		||||
		rmsg.Extra["attachments"] = props["attachments"].([]interface{})
 | 
			
		||||
		if rmsg.Text != "" {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, attachment := range rmsg.Extra["attachments"] {
 | 
			
		||||
			attach := attachment.(map[string]interface{})
 | 
			
		||||
			if attach["text"].(string) != "" {
 | 
			
		||||
				rmsg.Text += attach["text"].(string)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if attach["fallback"].(string) != "" {
 | 
			
		||||
				rmsg.Text += attach["fallback"].(string)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,16 @@
 | 
			
		||||
package bmattermost
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/42wim/matterbridge/matterclient"
 | 
			
		||||
	"github.com/42wim/matterbridge/matterhook"
 | 
			
		||||
	matterclient6 "github.com/matterbridge/matterclient"
 | 
			
		||||
	"github.com/mattermost/mattermost-server/v5/model"
 | 
			
		||||
	model6 "github.com/mattermost/mattermost-server/v6/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (b *Bmattermost) doConnectWebhookBind() error {
 | 
			
		||||
@@ -15,25 +18,47 @@ func (b *Bmattermost) doConnectWebhookBind() error {
 | 
			
		||||
	case b.GetString("WebhookURL") != "":
 | 
			
		||||
		b.Log.Info("Connecting using webhookurl (sending) and webhookbindaddress (receiving)")
 | 
			
		||||
		b.mh = matterhook.New(b.GetString("WebhookURL"),
 | 
			
		||||
			matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"),
 | 
			
		||||
				BindAddress: b.GetString("WebhookBindAddress")})
 | 
			
		||||
			matterhook.Config{
 | 
			
		||||
				InsecureSkipVerify: b.GetBool("SkipTLSVerify"),
 | 
			
		||||
				BindAddress:        b.GetString("WebhookBindAddress"),
 | 
			
		||||
			})
 | 
			
		||||
	case b.GetString("Token") != "":
 | 
			
		||||
		b.Log.Info("Connecting using token (sending)")
 | 
			
		||||
		err := b.apiLogin()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		b.Log.Infof("Using mattermost v6 methods: %t", b.v6)
 | 
			
		||||
 | 
			
		||||
		if b.v6 {
 | 
			
		||||
			err := b.apiLogin6()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			err := b.apiLogin()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case b.GetString("Login") != "":
 | 
			
		||||
		b.Log.Info("Connecting using login/password (sending)")
 | 
			
		||||
		err := b.apiLogin()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		b.Log.Infof("Using mattermost v6 methods: %t", b.v6)
 | 
			
		||||
 | 
			
		||||
		if b.v6 {
 | 
			
		||||
			err := b.apiLogin6()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			err := b.apiLogin()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		b.Log.Info("Connecting using webhookbindaddress (receiving)")
 | 
			
		||||
		b.mh = matterhook.New(b.GetString("WebhookURL"),
 | 
			
		||||
			matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"),
 | 
			
		||||
				BindAddress: b.GetString("WebhookBindAddress")})
 | 
			
		||||
			matterhook.Config{
 | 
			
		||||
				InsecureSkipVerify: b.GetBool("SkipTLSVerify"),
 | 
			
		||||
				BindAddress:        b.GetString("WebhookBindAddress"),
 | 
			
		||||
			})
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -41,19 +66,39 @@ func (b *Bmattermost) doConnectWebhookBind() error {
 | 
			
		||||
func (b *Bmattermost) doConnectWebhookURL() error {
 | 
			
		||||
	b.Log.Info("Connecting using webhookurl (sending)")
 | 
			
		||||
	b.mh = matterhook.New(b.GetString("WebhookURL"),
 | 
			
		||||
		matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"),
 | 
			
		||||
			DisableServer: true})
 | 
			
		||||
		matterhook.Config{
 | 
			
		||||
			InsecureSkipVerify: b.GetBool("SkipTLSVerify"),
 | 
			
		||||
			DisableServer:      true,
 | 
			
		||||
		})
 | 
			
		||||
	if b.GetString("Token") != "" {
 | 
			
		||||
		b.Log.Info("Connecting using token (receiving)")
 | 
			
		||||
		err := b.apiLogin()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		b.Log.Infof("Using mattermost v6 methods: %t", b.v6)
 | 
			
		||||
 | 
			
		||||
		if b.v6 {
 | 
			
		||||
			err := b.apiLogin6()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			err := b.apiLogin()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if b.GetString("Login") != "" {
 | 
			
		||||
		b.Log.Info("Connecting using login/password (receiving)")
 | 
			
		||||
		err := b.apiLogin()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		b.Log.Infof("Using mattermost v6 methods: %t", b.v6)
 | 
			
		||||
 | 
			
		||||
		if b.v6 {
 | 
			
		||||
			err := b.apiLogin6()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			err := b.apiLogin()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
@@ -84,6 +129,31 @@ func (b *Bmattermost) apiLogin() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// nolint:wrapcheck
 | 
			
		||||
func (b *Bmattermost) apiLogin6() error {
 | 
			
		||||
	password := b.GetString("Password")
 | 
			
		||||
	if b.GetString("Token") != "" {
 | 
			
		||||
		password = "token=" + b.GetString("Token")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.mc6 = matterclient6.New(b.GetString("Login"), password, b.GetString("Team"), b.GetString("Server"), "")
 | 
			
		||||
	if b.GetBool("debug") {
 | 
			
		||||
		b.mc6.SetLogLevel("debug")
 | 
			
		||||
	}
 | 
			
		||||
	b.mc6.SkipTLSVerify = b.GetBool("SkipTLSVerify")
 | 
			
		||||
	b.mc6.SkipVersionCheck = b.GetBool("SkipVersionCheck")
 | 
			
		||||
	b.mc6.NoTLS = b.GetBool("NoTLS")
 | 
			
		||||
	b.Log.Infof("Connecting %s (team: %s) on %s", b.GetString("Login"), b.GetString("Team"), b.GetString("Server"))
 | 
			
		||||
 | 
			
		||||
	if err := b.mc6.Login(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Log.Info("Connection succeeded")
 | 
			
		||||
	b.TeamID = b.mc6.GetTeamID()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// replaceAction replace the message with the correct action (/me) code
 | 
			
		||||
func (b *Bmattermost) replaceAction(text string) (string, bool) {
 | 
			
		||||
	if strings.HasPrefix(text, "*") && strings.HasSuffix(text, "*") {
 | 
			
		||||
@@ -171,11 +241,17 @@ func (b *Bmattermost) skipMessage(message *matterclient.Message) bool {
 | 
			
		||||
		if b.GetBool("nosendjoinpart") {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		channelName := b.getChannelName(message.Post.ChannelId)
 | 
			
		||||
		if channelName == "" {
 | 
			
		||||
			channelName = message.Channel
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		b.Log.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
 | 
			
		||||
		b.Remote <- config.Message{
 | 
			
		||||
			Username: "system",
 | 
			
		||||
			Text:     message.Text,
 | 
			
		||||
			Channel:  message.Channel,
 | 
			
		||||
			Channel:  channelName,
 | 
			
		||||
			Account:  b.Account,
 | 
			
		||||
			Event:    config.EventJoinLeave,
 | 
			
		||||
		}
 | 
			
		||||
@@ -223,3 +299,119 @@ func (b *Bmattermost) skipMessage(message *matterclient.Message) bool {
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// skipMessages returns true if this message should not be handled
 | 
			
		||||
// nolint:gocyclo,cyclop
 | 
			
		||||
func (b *Bmattermost) skipMessage6(message *matterclient6.Message) bool {
 | 
			
		||||
	// Handle join/leave
 | 
			
		||||
	if message.Type == "system_join_leave" ||
 | 
			
		||||
		message.Type == "system_join_channel" ||
 | 
			
		||||
		message.Type == "system_leave_channel" {
 | 
			
		||||
		if b.GetBool("nosendjoinpart") {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		channelName := b.getChannelName(message.Post.ChannelId)
 | 
			
		||||
		if channelName == "" {
 | 
			
		||||
			channelName = message.Channel
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		b.Log.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
 | 
			
		||||
		b.Remote <- config.Message{
 | 
			
		||||
			Username: "system",
 | 
			
		||||
			Text:     message.Text,
 | 
			
		||||
			Channel:  channelName,
 | 
			
		||||
			Account:  b.Account,
 | 
			
		||||
			Event:    config.EventJoinLeave,
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Handle edited messages
 | 
			
		||||
	if (message.Raw.EventType() == model6.WebsocketEventPostEdited) && b.GetBool("EditDisable") {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Ignore non-post messages
 | 
			
		||||
	if message.Post == nil {
 | 
			
		||||
		b.Log.Debugf("ignoring nil message.Post: %#v", message)
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Ignore messages sent from matterbridge
 | 
			
		||||
	if message.Post.Props != nil {
 | 
			
		||||
		if _, ok := message.Post.Props["matterbridge_"+b.uuid].(bool); ok {
 | 
			
		||||
			b.Log.Debug("sent by matterbridge, ignoring")
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Ignore messages sent from a user logged in as the bot
 | 
			
		||||
	if b.mc6.User.Username == message.Username {
 | 
			
		||||
		b.Log.Debug("message from same user as bot, ignoring")
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if the message has reactions don't repost it (for now, until we can correlate reaction with message)
 | 
			
		||||
	if message.Post.HasReactions {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// ignore messages from other teams than ours
 | 
			
		||||
	if message.Raw.GetData()["team_id"].(string) != b.TeamID {
 | 
			
		||||
		b.Log.Debug("message from other team, ignoring")
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// only handle posted, edited or deleted events
 | 
			
		||||
	if !(message.Raw.EventType() == "posted" || message.Raw.EventType() == model6.WebsocketEventPostEdited ||
 | 
			
		||||
		message.Raw.EventType() == model6.WebsocketEventPostDeleted) {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bmattermost) getVersion() string {
 | 
			
		||||
	proto := "https"
 | 
			
		||||
 | 
			
		||||
	if b.GetBool("notls") {
 | 
			
		||||
		proto = "http"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := http.Get(proto + "://" + b.GetString("server"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Error("failed getting version")
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	return resp.Header.Get("X-Version-Id")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bmattermost) getChannelID(name string) string {
 | 
			
		||||
	idcheck := strings.Split(name, "ID:")
 | 
			
		||||
	if len(idcheck) > 1 {
 | 
			
		||||
		return idcheck[1]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if b.mc6 != nil {
 | 
			
		||||
		return b.mc6.GetChannelID(name, b.TeamID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return b.mc.GetChannelId(name, b.TeamID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bmattermost) getChannelName(id string) string {
 | 
			
		||||
	b.channelsMutex.RLock()
 | 
			
		||||
	defer b.channelsMutex.RUnlock()
 | 
			
		||||
 | 
			
		||||
	for _, c := range b.channelInfoMap {
 | 
			
		||||
		if c.Name == "ID:"+id {
 | 
			
		||||
			// if we have ID: specified in our gateway configuration return this
 | 
			
		||||
			return c.Name
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,29 +3,43 @@ package bmattermost
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/42wim/matterbridge/matterclient"
 | 
			
		||||
	"github.com/42wim/matterbridge/matterhook"
 | 
			
		||||
	matterclient6 "github.com/matterbridge/matterclient"
 | 
			
		||||
	"github.com/rs/xid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Bmattermost struct {
 | 
			
		||||
	mh     *matterhook.Client
 | 
			
		||||
	mc     *matterclient.MMClient
 | 
			
		||||
	mc6    *matterclient6.Client
 | 
			
		||||
	v6     bool
 | 
			
		||||
	uuid   string
 | 
			
		||||
	TeamID string
 | 
			
		||||
	*bridge.Config
 | 
			
		||||
	avatarMap map[string]string
 | 
			
		||||
	avatarMap      map[string]string
 | 
			
		||||
	channelsMutex  sync.RWMutex
 | 
			
		||||
	channelInfoMap map[string]*config.ChannelInfo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const mattermostPlugin = "mattermost.plugin"
 | 
			
		||||
 | 
			
		||||
func New(cfg *bridge.Config) bridge.Bridger {
 | 
			
		||||
	b := &Bmattermost{Config: cfg, avatarMap: make(map[string]string)}
 | 
			
		||||
	b := &Bmattermost{
 | 
			
		||||
		Config:         cfg,
 | 
			
		||||
		avatarMap:      make(map[string]string),
 | 
			
		||||
		channelInfoMap: make(map[string]*config.ChannelInfo),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.v6 = b.GetBool("v6")
 | 
			
		||||
	b.uuid = xid.New().String()
 | 
			
		||||
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -37,6 +51,13 @@ func (b *Bmattermost) Connect() error {
 | 
			
		||||
	if b.Account == mattermostPlugin {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if strings.HasPrefix(b.getVersion(), "6.") {
 | 
			
		||||
		if !b.v6 {
 | 
			
		||||
			b.v6 = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if b.GetString("WebhookBindAddress") != "" {
 | 
			
		||||
		if err := b.doConnectWebhookBind(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
@@ -53,16 +74,34 @@ func (b *Bmattermost) Connect() error {
 | 
			
		||||
		return nil
 | 
			
		||||
	case b.GetString("Token") != "":
 | 
			
		||||
		b.Log.Info("Connecting using token (sending and receiving)")
 | 
			
		||||
		err := b.apiLogin()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		b.Log.Infof("Using mattermost v6 methods: %t", b.v6)
 | 
			
		||||
 | 
			
		||||
		if b.v6 {
 | 
			
		||||
			err := b.apiLogin6()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			err := b.apiLogin()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		go b.handleMatter()
 | 
			
		||||
	case b.GetString("Login") != "":
 | 
			
		||||
		b.Log.Info("Connecting using login/password (sending and receiving)")
 | 
			
		||||
		err := b.apiLogin()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		b.Log.Infof("Using mattermost v6 methods: %t", b.v6)
 | 
			
		||||
 | 
			
		||||
		if b.v6 {
 | 
			
		||||
			err := b.apiLogin6()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			err := b.apiLogin()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		go b.handleMatter()
 | 
			
		||||
	}
 | 
			
		||||
@@ -81,14 +120,25 @@ func (b *Bmattermost) JoinChannel(channel config.ChannelInfo) error {
 | 
			
		||||
	if b.Account == mattermostPlugin {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.channelsMutex.Lock()
 | 
			
		||||
	b.channelInfoMap[channel.ID] = &channel
 | 
			
		||||
	b.channelsMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	// we can only join channels using the API
 | 
			
		||||
	if b.GetString("WebhookURL") == "" && b.GetString("WebhookBindAddress") == "" {
 | 
			
		||||
		id := b.mc.GetChannelId(channel.Name, b.TeamID)
 | 
			
		||||
		id := b.getChannelID(channel.Name)
 | 
			
		||||
		if id == "" {
 | 
			
		||||
			return fmt.Errorf("Could not find channel ID for channel %s", channel.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if b.mc6 != nil {
 | 
			
		||||
			return b.mc6.JoinChannel(id) // nolint:wrapcheck
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return b.mc.JoinChannel(id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -118,6 +168,10 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) {
 | 
			
		||||
		if msg.ID == "" {
 | 
			
		||||
			return "", nil
 | 
			
		||||
		}
 | 
			
		||||
		if b.mc6 != nil {
 | 
			
		||||
			return msg.ID, b.mc6.DeleteMessage(msg.ID) // nolint:wrapcheck
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return msg.ID, b.mc.DeleteMessage(msg.ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -129,18 +183,36 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) {
 | 
			
		||||
 | 
			
		||||
	// we only can reply to the root of the thread, not to a specific ID (like discord for example does)
 | 
			
		||||
	if msg.ParentID != "" {
 | 
			
		||||
		post, res := b.mc.Client.GetPost(msg.ParentID, "")
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			b.Log.Errorf("getting post %s failed: %s", msg.ParentID, res.Error.DetailedError)
 | 
			
		||||
		if b.mc6 != nil {
 | 
			
		||||
			post, _, err := b.mc6.Client.GetPost(msg.ParentID, "")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Errorf("getting post %s failed: %s", msg.ParentID, err)
 | 
			
		||||
			}
 | 
			
		||||
			if post.RootId != "" {
 | 
			
		||||
				msg.ParentID = post.RootId
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			post, res := b.mc.Client.GetPost(msg.ParentID, "")
 | 
			
		||||
			if res.Error != nil {
 | 
			
		||||
				b.Log.Errorf("getting post %s failed: %s", msg.ParentID, res.Error.DetailedError)
 | 
			
		||||
			}
 | 
			
		||||
			if post.RootId != "" {
 | 
			
		||||
				msg.ParentID = post.RootId
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		msg.ParentID = post.RootId
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Upload a file if it exists
 | 
			
		||||
	if msg.Extra != nil {
 | 
			
		||||
		for _, rmsg := range helper.HandleExtra(&msg, b.General) {
 | 
			
		||||
			if _, err := b.mc.PostMessage(b.mc.GetChannelId(rmsg.Channel, b.TeamID), rmsg.Username+rmsg.Text, msg.ParentID); err != nil {
 | 
			
		||||
				b.Log.Errorf("PostMessage failed: %s", err)
 | 
			
		||||
			if b.mc6 != nil {
 | 
			
		||||
				if _, err := b.mc6.PostMessage(b.getChannelID(rmsg.Channel), rmsg.Username+rmsg.Text, msg.ParentID); err != nil {
 | 
			
		||||
					b.Log.Errorf("PostMessage failed: %s", err)
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				if _, err := b.mc.PostMessage(b.getChannelID(rmsg.Channel), rmsg.Username+rmsg.Text, msg.ParentID); err != nil {
 | 
			
		||||
					b.Log.Errorf("PostMessage failed: %s", err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if len(msg.Extra["file"]) > 0 {
 | 
			
		||||
@@ -155,9 +227,17 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) {
 | 
			
		||||
 | 
			
		||||
	// Edit message if we have an ID
 | 
			
		||||
	if msg.ID != "" {
 | 
			
		||||
		if b.mc6 != nil {
 | 
			
		||||
			return b.mc6.EditMessage(msg.ID, msg.Text) // nolint:wrapcheck
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return b.mc.EditMessage(msg.ID, msg.Text)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Post normal message
 | 
			
		||||
	return b.mc.PostMessage(b.mc.GetChannelId(msg.Channel, b.TeamID), msg.Text, msg.ParentID)
 | 
			
		||||
	if b.mc6 != nil {
 | 
			
		||||
		return b.mc6.PostMessage(b.getChannelID(msg.Channel), msg.Text, msg.ParentID) // nolint:wrapcheck
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return b.mc.PostMessage(b.getChannelID(msg.Channel), msg.Text, msg.ParentID)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,10 @@ import (
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var defaultScopes = []string{"openid", "profile", "offline_access", "Group.Read.All", "Group.ReadWrite.All"}
 | 
			
		||||
var attachRE = regexp.MustCompile(`<attachment id=.*?attachment>`)
 | 
			
		||||
var (
 | 
			
		||||
	defaultScopes = []string{"openid", "profile", "offline_access", "Group.Read.All", "Group.ReadWrite.All"}
 | 
			
		||||
	attachRE      = regexp.MustCompile(`<attachment id=.*?attachment>`)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Bmsteams struct {
 | 
			
		||||
	gc    *msgraph.GraphServiceRequestBuilder
 | 
			
		||||
@@ -50,7 +52,7 @@ func (b *Bmsteams) Connect() error {
 | 
			
		||||
		b.Log.Errorf("Couldn't save sessionfile in %s: %s", tokenCachePath, err)
 | 
			
		||||
	}
 | 
			
		||||
	// make file readable only for matterbridge user
 | 
			
		||||
	err = os.Chmod(tokenCachePath, 0600)
 | 
			
		||||
	err = os.Chmod(tokenCachePath, 0o600)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("Couldn't change permissions for %s: %s", tokenCachePath, err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -168,7 +170,7 @@ func (b *Bmsteams) poll(channelName string) error {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// skip non-user message for now.
 | 
			
		||||
			if msg.From.User == nil {
 | 
			
		||||
			if msg.From == nil || msg.From.User == nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										70
									
								
								bridge/mumble/codec.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								bridge/mumble/codec.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
package bmumble
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"layeh.com/gumble/gumble"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This is a dummy implementation of a Gumble audio codec which claims
 | 
			
		||||
// to implement Opus, but does not actually do anything.  This serves
 | 
			
		||||
// as a workaround until https://github.com/layeh/gumble/pull/61 is
 | 
			
		||||
// merged.
 | 
			
		||||
// See https://github.com/42wim/matterbridge/issues/1750 for details.
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	audioCodecIDOpus = 4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func registerNullCodecAsOpus() {
 | 
			
		||||
	codec := &NullCodec{
 | 
			
		||||
		encoder: &NullAudioEncoder{},
 | 
			
		||||
		decoder: &NullAudioDecoder{},
 | 
			
		||||
	}
 | 
			
		||||
	gumble.RegisterAudioCodec(audioCodecIDOpus, codec)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type NullCodec struct {
 | 
			
		||||
	encoder *NullAudioEncoder
 | 
			
		||||
	decoder *NullAudioDecoder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *NullCodec) ID() int {
 | 
			
		||||
	return audioCodecIDOpus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *NullCodec) NewEncoder() gumble.AudioEncoder {
 | 
			
		||||
	e := &NullAudioEncoder{}
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *NullCodec) NewDecoder() gumble.AudioDecoder {
 | 
			
		||||
	d := &NullAudioDecoder{}
 | 
			
		||||
	return d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type NullAudioEncoder struct{}
 | 
			
		||||
 | 
			
		||||
func (e *NullAudioEncoder) ID() int {
 | 
			
		||||
	return audioCodecIDOpus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *NullAudioEncoder) Encode(pcm []int16, mframeSize, maxDataBytes int) ([]byte, error) {
 | 
			
		||||
	return nil, fmt.Errorf("not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *NullAudioEncoder) Reset() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type NullAudioDecoder struct{}
 | 
			
		||||
 | 
			
		||||
func (d *NullAudioDecoder) ID() int {
 | 
			
		||||
	return audioCodecIDOpus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *NullAudioDecoder) Decode(data []byte, frameSize int) ([]int16, error) {
 | 
			
		||||
	return nil, fmt.Errorf("not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *NullAudioDecoder) Reset() {
 | 
			
		||||
}
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"layeh.com/gumble/gumble"
 | 
			
		||||
@@ -184,6 +185,7 @@ func (b *Bmumble) doConnect() error {
 | 
			
		||||
		gumbleConfig.Password = password
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	registerNullCodecAsOpus()
 | 
			
		||||
	client, err := gumble.DialWithDialer(new(net.Dialer), b.GetString("Server"), gumbleConfig, &b.tlsConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
@@ -252,8 +254,10 @@ func (b *Bmumble) processMessage(msg *config.Message) {
 | 
			
		||||
	} else {
 | 
			
		||||
		msgLines = helper.GetSubLines(msg.Text, 0, b.GetString("MessageClipped"))
 | 
			
		||||
	}
 | 
			
		||||
	// Send the individual lindes
 | 
			
		||||
	// Send the individual lines
 | 
			
		||||
	for i := range msgLines {
 | 
			
		||||
		// Remove unnecessary newline character, since either way we're sending it as individual lines
 | 
			
		||||
		msgLines[i] = strings.TrimSuffix(msgLines[i], "\n")
 | 
			
		||||
		b.client.Self.Channel.Send(msg.Username+msgLines[i], false)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -85,7 +85,7 @@ func (b *Btalk) JoinChannel(channel config.ChannelInfo) error {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Ignore messages that are from the bot user
 | 
			
		||||
			if msg.ActorID == b.user.User {
 | 
			
		||||
			if msg.ActorID == b.user.User || msg.ActorType == "bridged" {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -123,7 +123,7 @@ func (b *Btalk) Send(msg config.Message) (string, error) {
 | 
			
		||||
			return "", nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sentMessage, err := r.room.SendMessage(msg.Username + msg.Text)
 | 
			
		||||
		sentMessage, err := b.sendText(r, &msg, msg.Text)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Errorf("Could not send message to room %v from %v: %v", msg.Channel, msg.Username, err)
 | 
			
		||||
 | 
			
		||||
@@ -158,6 +158,17 @@ func (b *Btalk) getRoom(token string) *Broom {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Btalk) sendText(r *Broom, msg *config.Message, text string) (*ocs.TalkRoomMessageData, error) {
 | 
			
		||||
	messageToSend := &room.Message{Message: msg.Username + text}
 | 
			
		||||
 | 
			
		||||
	if b.GetBool("SeparateDisplayName") {
 | 
			
		||||
		messageToSend.Message = text
 | 
			
		||||
		messageToSend.ActorDisplayName = msg.Username
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r.room.SendComplexMessage(messageToSend)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Btalk) handleFiles(mmsg *config.Message, message *ocs.TalkRoomMessageData) error {
 | 
			
		||||
	for _, parameter := range message.MessageParameters {
 | 
			
		||||
		if parameter.Type == ocs.ROSTypeFile {
 | 
			
		||||
@@ -190,12 +201,12 @@ func (b *Btalk) handleSendingFile(msg *config.Message, r *Broom) error {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		message := msg.Username
 | 
			
		||||
		message := ""
 | 
			
		||||
		if fi.Comment != "" {
 | 
			
		||||
			message += fi.Comment + " "
 | 
			
		||||
		}
 | 
			
		||||
		message += fi.URL
 | 
			
		||||
		_, err := r.room.SendMessage(message)
 | 
			
		||||
		_, err := b.sendText(r, msg, message)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,8 @@ func (b *Bslack) handleSlack() {
 | 
			
		||||
	b.Log.Debug("Start listening for Slack messages")
 | 
			
		||||
	for message := range messages {
 | 
			
		||||
		// don't do any action on deleted/typing messages
 | 
			
		||||
		if message.Event != config.EventUserTyping && message.Event != config.EventMsgDelete {
 | 
			
		||||
		if message.Event != config.EventUserTyping && message.Event != config.EventMsgDelete &&
 | 
			
		||||
			message.Event != config.EventFileDelete {
 | 
			
		||||
			b.Log.Debugf("<= Sending message from %s on %s to gateway", message.Username, b.Account)
 | 
			
		||||
			// cleanup the message
 | 
			
		||||
			message.Text = b.replaceMention(message.Text)
 | 
			
		||||
@@ -76,6 +77,13 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			messages <- rmsg
 | 
			
		||||
		case *slack.FileDeletedEvent:
 | 
			
		||||
			rmsg, err := b.handleFileDeletedEvent(ev)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Errorf("%#v", err)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			messages <- rmsg
 | 
			
		||||
		case *slack.OutgoingErrorEvent:
 | 
			
		||||
			b.Log.Debugf("%#v", ev.Error())
 | 
			
		||||
		case *slack.ChannelJoinedEvent:
 | 
			
		||||
@@ -95,6 +103,8 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) {
 | 
			
		||||
			b.users.populateUser(ev.User)
 | 
			
		||||
		case *slack.HelloEvent, *slack.LatencyReport, *slack.ConnectingEvent:
 | 
			
		||||
			continue
 | 
			
		||||
		case *slack.UserChangeEvent:
 | 
			
		||||
			b.users.invalidateUser(ev.User.ID)
 | 
			
		||||
		default:
 | 
			
		||||
			b.Log.Debugf("Unhandled incoming event: %T", ev)
 | 
			
		||||
		}
 | 
			
		||||
@@ -220,6 +230,26 @@ func (b *Bslack) handleMessageEvent(ev *slack.MessageEvent) (*config.Message, er
 | 
			
		||||
	return rmsg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) handleFileDeletedEvent(ev *slack.FileDeletedEvent) (*config.Message, error) {
 | 
			
		||||
	if rawChannel, ok := b.cache.Get(cfileDownloadChannel + ev.FileID); ok {
 | 
			
		||||
		channel, err := b.channels.getChannelByID(rawChannel.(string))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return &config.Message{
 | 
			
		||||
			Event:    config.EventFileDelete,
 | 
			
		||||
			Text:     config.EventFileDelete,
 | 
			
		||||
			Channel:  channel.Name,
 | 
			
		||||
			Account:  b.Account,
 | 
			
		||||
			ID:       ev.FileID,
 | 
			
		||||
			Protocol: b.Protocol,
 | 
			
		||||
		}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, fmt.Errorf("channel ID for file ID %s not found", ev.FileID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) handleStatusEvent(ev *slack.MessageEvent, rmsg *config.Message) bool {
 | 
			
		||||
	switch ev.SubType {
 | 
			
		||||
	case sChannelJoined, sMemberJoined:
 | 
			
		||||
@@ -279,6 +309,8 @@ func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message)
 | 
			
		||||
 | 
			
		||||
	// If we have files attached, download them (in memory) and put a pointer to it in msg.Extra.
 | 
			
		||||
	for i := range ev.Files {
 | 
			
		||||
		// keep reference in cache on which channel we added this file
 | 
			
		||||
		b.cache.Add(cfileDownloadChannel+ev.Files[i].ID, ev.Channel)
 | 
			
		||||
		if err := b.handleDownloadFile(rmsg, &ev.Files[i], false); err != nil {
 | 
			
		||||
			b.Log.Errorf("Could not download incoming file: %#v", err)
 | 
			
		||||
		}
 | 
			
		||||
@@ -328,7 +360,7 @@ func (b *Bslack) handleDownloadFile(rmsg *config.Message, file *slack.File, retr
 | 
			
		||||
	// that the comment is not duplicated.
 | 
			
		||||
	comment := rmsg.Text
 | 
			
		||||
	rmsg.Text = ""
 | 
			
		||||
	helper.HandleDownloadData(b.Log, rmsg, file.Name, comment, file.URLPrivateDownload, data, b.General)
 | 
			
		||||
	helper.HandleDownloadData2(b.Log, rmsg, file.Name, file.ID, comment, file.URLPrivateDownload, data, b.General)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -36,24 +36,25 @@ type Bslack struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	sHello           = "hello"
 | 
			
		||||
	sChannelJoin     = "channel_join"
 | 
			
		||||
	sChannelLeave    = "channel_leave"
 | 
			
		||||
	sChannelJoined   = "channel_joined"
 | 
			
		||||
	sMemberJoined    = "member_joined_channel"
 | 
			
		||||
	sMessageChanged  = "message_changed"
 | 
			
		||||
	sMessageDeleted  = "message_deleted"
 | 
			
		||||
	sSlackAttachment = "slack_attachment"
 | 
			
		||||
	sPinnedItem      = "pinned_item"
 | 
			
		||||
	sUnpinnedItem    = "unpinned_item"
 | 
			
		||||
	sChannelTopic    = "channel_topic"
 | 
			
		||||
	sChannelPurpose  = "channel_purpose"
 | 
			
		||||
	sFileComment     = "file_comment"
 | 
			
		||||
	sMeMessage       = "me_message"
 | 
			
		||||
	sUserTyping      = "user_typing"
 | 
			
		||||
	sLatencyReport   = "latency_report"
 | 
			
		||||
	sSystemUser      = "system"
 | 
			
		||||
	sSlackBotUser    = "slackbot"
 | 
			
		||||
	sHello               = "hello"
 | 
			
		||||
	sChannelJoin         = "channel_join"
 | 
			
		||||
	sChannelLeave        = "channel_leave"
 | 
			
		||||
	sChannelJoined       = "channel_joined"
 | 
			
		||||
	sMemberJoined        = "member_joined_channel"
 | 
			
		||||
	sMessageChanged      = "message_changed"
 | 
			
		||||
	sMessageDeleted      = "message_deleted"
 | 
			
		||||
	sSlackAttachment     = "slack_attachment"
 | 
			
		||||
	sPinnedItem          = "pinned_item"
 | 
			
		||||
	sUnpinnedItem        = "unpinned_item"
 | 
			
		||||
	sChannelTopic        = "channel_topic"
 | 
			
		||||
	sChannelPurpose      = "channel_purpose"
 | 
			
		||||
	sFileComment         = "file_comment"
 | 
			
		||||
	sMeMessage           = "me_message"
 | 
			
		||||
	sUserTyping          = "user_typing"
 | 
			
		||||
	sLatencyReport       = "latency_report"
 | 
			
		||||
	sSystemUser          = "system"
 | 
			
		||||
	sSlackBotUser        = "slackbot"
 | 
			
		||||
	cfileDownloadChannel = "file_download_channel"
 | 
			
		||||
 | 
			
		||||
	tokenConfig           = "Token"
 | 
			
		||||
	incomingWebhookConfig = "WebhookBindAddress"
 | 
			
		||||
@@ -459,7 +460,7 @@ func (b *Bslack) uploadFile(msg *config.Message, channelID string) {
 | 
			
		||||
		b.cache.Add("filename"+fi.Name, ts)
 | 
			
		||||
		initialComment := fmt.Sprintf("File from %s", msg.Username)
 | 
			
		||||
		if fi.Comment != "" {
 | 
			
		||||
			initialComment += fmt.Sprintf("with comment: %s", fi.Comment)
 | 
			
		||||
			initialComment += fmt.Sprintf(" with comment: %s", fi.Comment)
 | 
			
		||||
		}
 | 
			
		||||
		res, err := b.sc.UploadFile(slack.FileUploadParameters{
 | 
			
		||||
			Reader:          bytes.NewReader(*fi.Data),
 | 
			
		||||
 
 | 
			
		||||
@@ -113,6 +113,12 @@ func (b *users) populateUser(userID string) {
 | 
			
		||||
	b.users[userID] = user
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *users) invalidateUser(userID string) {
 | 
			
		||||
	b.usersMutex.Lock()
 | 
			
		||||
	defer b.usersMutex.Unlock()
 | 
			
		||||
	delete(b.users, userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *users) populateUsers(wait bool) {
 | 
			
		||||
	b.refreshMutex.Lock()
 | 
			
		||||
	if !wait && (time.Now().Before(b.earliestRefresh) || b.refreshInProgress) {
 | 
			
		||||
@@ -285,6 +291,7 @@ func (b *channels) populateChannels(wait bool) {
 | 
			
		||||
	queryParams := &slack.GetConversationsParameters{
 | 
			
		||||
		ExcludeArchived: true,
 | 
			
		||||
		Types:           []string{"public_channel,private_channel"},
 | 
			
		||||
		Limit:           1000,
 | 
			
		||||
	}
 | 
			
		||||
	for {
 | 
			
		||||
		channels, nextCursor, err := b.sc.GetConversations(queryParams)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package btelegram
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"html"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
@@ -9,14 +10,27 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
 | 
			
		||||
	"github.com/davecgh/go-spew/spew"
 | 
			
		||||
	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (b *Btelegram) handleUpdate(rmsg *config.Message, message, posted, edited *tgbotapi.Message) *tgbotapi.Message {
 | 
			
		||||
	// handle channels
 | 
			
		||||
	if posted != nil {
 | 
			
		||||
		message = posted
 | 
			
		||||
		rmsg.Text = message.Text
 | 
			
		||||
		if posted.Text == "/chatId" {
 | 
			
		||||
			chatID := strconv.FormatInt(posted.Chat.ID, 10)
 | 
			
		||||
 | 
			
		||||
			_, err := b.Send(config.Message{
 | 
			
		||||
				Channel: chatID,
 | 
			
		||||
				Text:    fmt.Sprintf("ID of this chat: %s", chatID),
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Warnf("Unable to send chatID to %s", chatID)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			message = posted
 | 
			
		||||
			rmsg.Text = message.Text
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// edited channel message
 | 
			
		||||
@@ -43,6 +57,11 @@ func (b *Btelegram) handleForwarded(rmsg *config.Message, message *tgbotapi.Mess
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if message.ForwardFromChat != nil && message.ForwardFrom == nil {
 | 
			
		||||
		rmsg.Text = "Forwarded from " + message.ForwardFromChat.Title + ": " + rmsg.Text
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if message.ForwardFrom == nil {
 | 
			
		||||
		rmsg.Text = "Forwarded from " + unknownUser + ": " + rmsg.Text
 | 
			
		||||
		return
 | 
			
		||||
@@ -94,7 +113,7 @@ func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Messag
 | 
			
		||||
// handleUsername handles the correct setting of the username
 | 
			
		||||
func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Message) {
 | 
			
		||||
	if message.From != nil {
 | 
			
		||||
		rmsg.UserID = strconv.Itoa(message.From.ID)
 | 
			
		||||
		rmsg.UserID = strconv.FormatInt(message.From.ID, 10)
 | 
			
		||||
		if b.GetBool("UseFirstName") {
 | 
			
		||||
			rmsg.Username = message.From.FirstName
 | 
			
		||||
		}
 | 
			
		||||
@@ -110,6 +129,25 @@ func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Messa
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if message.SenderChat != nil { //nolint:nestif
 | 
			
		||||
		rmsg.UserID = strconv.FormatInt(message.SenderChat.ID, 10)
 | 
			
		||||
		if b.GetBool("UseFirstName") {
 | 
			
		||||
			rmsg.Username = message.SenderChat.FirstName
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if rmsg.Username == "" || rmsg.Username == "Channel_Bot" {
 | 
			
		||||
			rmsg.Username = message.SenderChat.UserName
 | 
			
		||||
 | 
			
		||||
			if rmsg.Username == "" || rmsg.Username == "Channel_Bot" {
 | 
			
		||||
				rmsg.Username = message.SenderChat.FirstName
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// only download avatars if we have a place to upload them (configured mediaserver)
 | 
			
		||||
		if b.General.MediaServerUpload != "" || (b.General.MediaServerDownload != "" && b.General.MediaDownloadPath != "") {
 | 
			
		||||
			b.handleDownloadAvatar(message.SenderChat.ID, rmsg.Channel)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if we really didn't find a username, set it to unknown
 | 
			
		||||
	if rmsg.Username == "" {
 | 
			
		||||
		rmsg.Username = unknownUser
 | 
			
		||||
@@ -126,6 +164,10 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if b.GetInt("debuglevel") == 1 {
 | 
			
		||||
			spew.Dump(update.Message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var message *tgbotapi.Message
 | 
			
		||||
 | 
			
		||||
		rmsg := config.Message{Account: b.Account, Extra: make(map[string][]interface{})}
 | 
			
		||||
@@ -145,6 +187,9 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
 | 
			
		||||
		rmsg.ID = strconv.Itoa(message.MessageID)
 | 
			
		||||
		rmsg.Channel = strconv.FormatInt(message.Chat.ID, 10)
 | 
			
		||||
 | 
			
		||||
		// handle entities (adding URLs)
 | 
			
		||||
		b.handleEntities(&rmsg, message)
 | 
			
		||||
 | 
			
		||||
		// handle username
 | 
			
		||||
		b.handleUsername(&rmsg, message)
 | 
			
		||||
 | 
			
		||||
@@ -160,14 +205,12 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
 | 
			
		||||
		// quote the previous message
 | 
			
		||||
		b.handleQuoting(&rmsg, message)
 | 
			
		||||
 | 
			
		||||
		// handle entities (adding URLs)
 | 
			
		||||
		b.handleEntities(&rmsg, message)
 | 
			
		||||
 | 
			
		||||
		if rmsg.Text != "" || len(rmsg.Extra) > 0 {
 | 
			
		||||
			rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text)
 | 
			
		||||
			// Comment the next line out due to avoid removing empty lines in Telegram
 | 
			
		||||
			// rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text)
 | 
			
		||||
			// channels don't have (always?) user information. see #410
 | 
			
		||||
			if message.From != nil {
 | 
			
		||||
				rmsg.Avatar = helper.GetAvatar(b.avatarMap, strconv.Itoa(message.From.ID), b.General)
 | 
			
		||||
				rmsg.Avatar = helper.GetAvatar(b.avatarMap, strconv.FormatInt(message.From.ID, 10), b.General)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
 | 
			
		||||
@@ -180,60 +223,52 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
 | 
			
		||||
// handleDownloadAvatar downloads the avatar of userid from channel
 | 
			
		||||
// sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful.
 | 
			
		||||
// logs an error message if it fails
 | 
			
		||||
func (b *Btelegram) handleDownloadAvatar(userid int, channel string) {
 | 
			
		||||
func (b *Btelegram) handleDownloadAvatar(userid int64, channel string) {
 | 
			
		||||
	rmsg := config.Message{
 | 
			
		||||
		Username: "system",
 | 
			
		||||
		Text:     "avatar",
 | 
			
		||||
		Channel:  channel,
 | 
			
		||||
		Account:  b.Account,
 | 
			
		||||
		UserID:   strconv.Itoa(userid),
 | 
			
		||||
		UserID:   strconv.FormatInt(userid, 10),
 | 
			
		||||
		Event:    config.EventAvatarDownload,
 | 
			
		||||
		Extra:    make(map[string][]interface{}),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, ok := b.avatarMap[strconv.Itoa(userid)]; !ok {
 | 
			
		||||
		photos, err := b.c.GetUserProfilePhotos(tgbotapi.UserProfilePhotosConfig{UserID: userid, Limit: 1})
 | 
			
		||||
	if _, ok := b.avatarMap[strconv.FormatInt(userid, 10)]; ok {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	photos, err := b.c.GetUserProfilePhotos(tgbotapi.UserProfilePhotosConfig{UserID: userid, Limit: 1})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("Userprofile download failed for %#v %s", userid, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(photos.Photos) > 0 {
 | 
			
		||||
		photo := photos.Photos[0][0]
 | 
			
		||||
		url := b.getFileDirectURL(photo.FileID)
 | 
			
		||||
		name := strconv.FormatInt(userid, 10) + ".png"
 | 
			
		||||
		b.Log.Debugf("trying to download %#v fileid %#v with size %#v", name, photo.FileID, photo.FileSize)
 | 
			
		||||
 | 
			
		||||
		err := helper.HandleDownloadSize(b.Log, &rmsg, name, int64(photo.FileSize), b.General)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Errorf("Userprofile download failed for %#v %s", userid, err)
 | 
			
		||||
			b.Log.Error(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(photos.Photos) > 0 {
 | 
			
		||||
			photo := photos.Photos[0][0]
 | 
			
		||||
			url := b.getFileDirectURL(photo.FileID)
 | 
			
		||||
			name := strconv.Itoa(userid) + ".png"
 | 
			
		||||
			b.Log.Debugf("trying to download %#v fileid %#v with size %#v", name, photo.FileID, photo.FileSize)
 | 
			
		||||
 | 
			
		||||
			err := helper.HandleDownloadSize(b.Log, &rmsg, name, int64(photo.FileSize), b.General)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Error(err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			data, err := helper.DownloadFile(url)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Errorf("download %s failed %#v", url, err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			helper.HandleDownloadData(b.Log, &rmsg, name, rmsg.Text, "", data, b.General)
 | 
			
		||||
			b.Remote <- rmsg
 | 
			
		||||
		data, err := helper.DownloadFile(url)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Errorf("download %s failed %#v", url, err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		helper.HandleDownloadData(b.Log, &rmsg, name, rmsg.Text, "", data, b.General)
 | 
			
		||||
		b.Remote <- rmsg
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Btelegram) maybeConvertTgs(name *string, data *[]byte) {
 | 
			
		||||
	var format string
 | 
			
		||||
	switch b.GetString("MediaConvertTgs") {
 | 
			
		||||
	case FormatWebp:
 | 
			
		||||
		b.Log.Debugf("Tgs to WebP conversion enabled, converting %v", name)
 | 
			
		||||
		format = FormatWebp
 | 
			
		||||
	case FormatPng:
 | 
			
		||||
		// The WebP to PNG converter can't handle animated webp files yet,
 | 
			
		||||
		// and I'm not going to write a path for x/image/webp.
 | 
			
		||||
		// The error message would be:
 | 
			
		||||
		//     conversion failed: webp: non-Alpha VP8X is not implemented
 | 
			
		||||
		// So instead, we tell lottie to directly go to PNG.
 | 
			
		||||
		b.Log.Debugf("Tgs to PNG conversion enabled, converting %v", name)
 | 
			
		||||
		format = FormatPng
 | 
			
		||||
	default:
 | 
			
		||||
	format := b.GetString("MediaConvertTgs")
 | 
			
		||||
	if helper.SupportsFormat(format) {
 | 
			
		||||
		b.Log.Debugf("Format supported by %s, converting %v", helper.LottieBackend(), name)
 | 
			
		||||
	} else {
 | 
			
		||||
		// Otherwise, no conversion was requested. Trying to run the usual webp
 | 
			
		||||
		// converter would fail, because '.tgs.webp' is actually a gzipped JSON
 | 
			
		||||
		// file, and has nothing to do with WebP.
 | 
			
		||||
@@ -282,7 +317,7 @@ func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Messa
 | 
			
		||||
		name = message.Document.FileName
 | 
			
		||||
		text = " " + message.Document.FileName + " : " + url
 | 
			
		||||
	case message.Photo != nil:
 | 
			
		||||
		photos := *message.Photo
 | 
			
		||||
		photos := message.Photo
 | 
			
		||||
		size = photos[len(photos)-1].FileSize
 | 
			
		||||
		text, name, url = b.getDownloadInfo(photos[len(photos)-1].FileID, "", true)
 | 
			
		||||
	}
 | 
			
		||||
@@ -341,11 +376,15 @@ func (b *Btelegram) handleDelete(msg *config.Message, chatid int64) (string, err
 | 
			
		||||
	if msg.ID == "" {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msgid, err := strconv.Atoi(msg.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = b.c.DeleteMessage(tgbotapi.DeleteMessageConfig{ChatID: chatid, MessageID: msgid})
 | 
			
		||||
 | 
			
		||||
	cfg := tgbotapi.NewDeleteMessage(chatid, msgid)
 | 
			
		||||
	_, err = b.c.Send(cfg)
 | 
			
		||||
 | 
			
		||||
	return "", err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -393,23 +432,23 @@ func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string {
 | 
			
		||||
		}
 | 
			
		||||
		switch filepath.Ext(fi.Name) {
 | 
			
		||||
		case ".jpg", ".jpe", ".png":
 | 
			
		||||
			pc := tgbotapi.NewPhotoUpload(chatid, file)
 | 
			
		||||
			pc := tgbotapi.NewPhoto(chatid, file)
 | 
			
		||||
			pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			c = pc
 | 
			
		||||
		case ".mp4", ".m4v":
 | 
			
		||||
			vc := tgbotapi.NewVideoUpload(chatid, file)
 | 
			
		||||
			vc := tgbotapi.NewVideo(chatid, file)
 | 
			
		||||
			vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			c = vc
 | 
			
		||||
		case ".mp3", ".oga":
 | 
			
		||||
			ac := tgbotapi.NewAudioUpload(chatid, file)
 | 
			
		||||
			ac := tgbotapi.NewAudio(chatid, file)
 | 
			
		||||
			ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			c = ac
 | 
			
		||||
		case ".ogg":
 | 
			
		||||
			voc := tgbotapi.NewVoiceUpload(chatid, file)
 | 
			
		||||
			voc := tgbotapi.NewVoice(chatid, file)
 | 
			
		||||
			voc.Caption, voc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			c = voc
 | 
			
		||||
		default:
 | 
			
		||||
			dc := tgbotapi.NewDocumentUpload(chatid, file)
 | 
			
		||||
			dc := tgbotapi.NewDocument(chatid, file)
 | 
			
		||||
			dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			c = dc
 | 
			
		||||
		}
 | 
			
		||||
@@ -445,21 +484,56 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa
 | 
			
		||||
	if message.Entities == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	indexMovedBy := 0
 | 
			
		||||
 | 
			
		||||
	// for now only do URL replacements
 | 
			
		||||
	for _, e := range *message.Entities {
 | 
			
		||||
	for _, e := range message.Entities {
 | 
			
		||||
 | 
			
		||||
		asRunes := utf16.Encode([]rune(rmsg.Text))
 | 
			
		||||
 | 
			
		||||
		if e.Type == "text_link" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			url, err := e.ParseURL()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Errorf("entity text_link url parse failed: %s", err)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			utfEncodedString := utf16.Encode([]rune(rmsg.Text))
 | 
			
		||||
			if e.Offset+e.Length > len(utfEncodedString) {
 | 
			
		||||
				b.Log.Errorf("entity length is too long %d > %d", e.Offset+e.Length, len(utfEncodedString))
 | 
			
		||||
			if offset+e.Length > len(utfEncodedString) {
 | 
			
		||||
				b.Log.Errorf("entity length is too long %d > %d", offset+e.Length, len(utfEncodedString))
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			link := utf16.Decode(utfEncodedString[e.Offset : e.Offset+e.Length])
 | 
			
		||||
			rmsg.Text = strings.Replace(rmsg.Text, string(link), url.String(), 1)
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset+e.Length])) + " (" + url.String() + ")" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += len(url.String()) + 3
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if e.Type == "code" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset])) + "`" + string(utf16.Decode(asRunes[offset:offset+e.Length])) + "`" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += 2
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if e.Type == "pre" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset])) + "```\n" + string(utf16.Decode(asRunes[offset:offset+e.Length])) + "```\n" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += 8
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if e.Type == "bold" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset])) + "*" + string(utf16.Decode(asRunes[offset:offset+e.Length])) + "*" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += 2
 | 
			
		||||
		}
 | 
			
		||||
		if e.Type == "italic" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset])) + "_" + string(utf16.Decode(asRunes[offset:offset+e.Length])) + "_" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += 2
 | 
			
		||||
		}
 | 
			
		||||
		if e.Type == "strike" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset])) + "~" + string(utf16.Decode(asRunes[offset:offset+e.Length])) + "~" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += 2
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
 | 
			
		||||
	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -17,8 +17,6 @@ const (
 | 
			
		||||
	HTMLFormat  = "HTML"
 | 
			
		||||
	HTMLNick    = "htmlnick"
 | 
			
		||||
	MarkdownV2  = "MarkdownV2"
 | 
			
		||||
	FormatPng   = "png"
 | 
			
		||||
	FormatWebp  = "webp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Btelegram struct {
 | 
			
		||||
@@ -32,10 +30,10 @@ func New(cfg *bridge.Config) bridge.Bridger {
 | 
			
		||||
	if tgsConvertFormat != "" {
 | 
			
		||||
		err := helper.CanConvertTgsToX()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but lottie does not appear to work:\n%#v", tgsConvertFormat, err)
 | 
			
		||||
			log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but %s does not appear to work:\n%#v", tgsConvertFormat, helper.LottieBackend(), err)
 | 
			
		||||
		}
 | 
			
		||||
		if tgsConvertFormat != FormatPng && tgsConvertFormat != FormatWebp {
 | 
			
		||||
			log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but only '%s' and '%s' are supported.", FormatPng, FormatWebp, tgsConvertFormat)
 | 
			
		||||
		if !helper.SupportsFormat(tgsConvertFormat) {
 | 
			
		||||
			log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but %s doesn't support it.", tgsConvertFormat, helper.LottieBackend())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return &Btelegram{Config: cfg, avatarMap: make(map[string]string)}
 | 
			
		||||
@@ -51,11 +49,7 @@ func (b *Btelegram) Connect() error {
 | 
			
		||||
	}
 | 
			
		||||
	u := tgbotapi.NewUpdate(0)
 | 
			
		||||
	u.Timeout = 60
 | 
			
		||||
	updates, err := b.c.GetUpdatesChan(u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Debugf("%#v", err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	updates := b.c.GetUpdatesChan(u)
 | 
			
		||||
	b.Log.Info("Connection succeeded")
 | 
			
		||||
	go b.handleRecv(updates)
 | 
			
		||||
	return nil
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@ type user struct {
 | 
			
		||||
 | 
			
		||||
type Bvk struct {
 | 
			
		||||
	c            *api.VK
 | 
			
		||||
	lp           *longpoll.LongPoll
 | 
			
		||||
	usernamesMap map[int]user // cache of user names and avatar URLs
 | 
			
		||||
	*bridge.Config
 | 
			
		||||
}
 | 
			
		||||
@@ -45,21 +46,23 @@ func New(cfg *bridge.Config) bridge.Bridger {
 | 
			
		||||
func (b *Bvk) Connect() error {
 | 
			
		||||
	b.Log.Info("Connecting")
 | 
			
		||||
	b.c = api.NewVK(b.GetString("Token"))
 | 
			
		||||
	lp, err := longpoll.NewLongPoll(b.c, b.GetInt("GroupID"))
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	b.lp, err = longpoll.NewLongPollCommunity(b.c)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Debugf("%#v", err)
 | 
			
		||||
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lp.MessageNew(func(ctx context.Context, obj events.MessageNewObject) {
 | 
			
		||||
	b.lp.MessageNew(func(ctx context.Context, obj events.MessageNewObject) {
 | 
			
		||||
		b.handleMessage(obj.Message, false)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	b.Log.Info("Connection succeeded")
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		err := lp.Run()
 | 
			
		||||
		err := b.lp.Run()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Fatal("Enable longpoll in group management")
 | 
			
		||||
		}
 | 
			
		||||
@@ -69,6 +72,8 @@ func (b *Bvk) Connect() error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bvk) Disconnect() error {
 | 
			
		||||
	b.lp.Shutdown()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -293,7 +293,11 @@ func (b *Bwhatsapp) Send(msg config.Message) (string, error) {
 | 
			
		||||
	if msg.ID != "" {
 | 
			
		||||
		b.Log.Debugf("updating message with id %s", msg.ID)
 | 
			
		||||
 | 
			
		||||
		msg.Text += " (edited)"
 | 
			
		||||
		if b.GetString("editsuffix") != "" {
 | 
			
		||||
			msg.Text += b.GetString("EditSuffix")
 | 
			
		||||
		} else {
 | 
			
		||||
			msg.Text += " (edited)"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Handle Upload a file
 | 
			
		||||
 
 | 
			
		||||
@@ -128,7 +128,6 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) {
 | 
			
		||||
	var msgReplaceID string
 | 
			
		||||
	msgID := xid.New().String()
 | 
			
		||||
	if msg.ID != "" {
 | 
			
		||||
		msgID = msg.ID
 | 
			
		||||
		msgReplaceID = msg.ID
 | 
			
		||||
	}
 | 
			
		||||
	b.Log.Debugf("=> Sending message %#v", msg)
 | 
			
		||||
@@ -169,11 +168,21 @@ func (b *Bxmpp) postSlackCompatibleWebhook(msg config.Message) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bxmpp) createXMPP() error {
 | 
			
		||||
	if !strings.Contains(b.GetString("Jid"), "@") {
 | 
			
		||||
		return fmt.Errorf("the Jid %s doesn't contain an @", b.GetString("Jid"))
 | 
			
		||||
	var serverName string
 | 
			
		||||
	switch {
 | 
			
		||||
	case !b.GetBool("Anonymous"):
 | 
			
		||||
		if !strings.Contains(b.GetString("Jid"), "@") {
 | 
			
		||||
			return fmt.Errorf("the Jid %s doesn't contain an @", b.GetString("Jid"))
 | 
			
		||||
		}
 | 
			
		||||
		serverName = strings.Split(b.GetString("Jid"), "@")[1]
 | 
			
		||||
	case !strings.Contains(b.GetString("Server"), ":"):
 | 
			
		||||
		serverName = strings.Split(b.GetString("Server"), ":")[0]
 | 
			
		||||
	default:
 | 
			
		||||
		serverName = b.GetString("Server")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tc := &tls.Config{
 | 
			
		||||
		ServerName:         strings.Split(b.GetString("Jid"), "@")[1],
 | 
			
		||||
		ServerName:         serverName,
 | 
			
		||||
		InsecureSkipVerify: b.GetBool("SkipTLSVerify"), // nolint: gosec
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -274,7 +283,13 @@ func (b *Bxmpp) handleXMPP() error {
 | 
			
		||||
	for {
 | 
			
		||||
		m, err := b.xc.Recv()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
			// An error together with AvatarData is non-fatal
 | 
			
		||||
			switch m.(type) {
 | 
			
		||||
			case xmpp.AvatarData:
 | 
			
		||||
				continue
 | 
			
		||||
			default:
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch v := m.(type) {
 | 
			
		||||
@@ -385,7 +400,7 @@ func (b *Bxmpp) handleUploadFile(msg *config.Message) error {
 | 
			
		||||
 | 
			
		||||
func (b *Bxmpp) parseNick(remote string) string {
 | 
			
		||||
	s := strings.Split(remote, "@")
 | 
			
		||||
	if len(s) > 0 {
 | 
			
		||||
	if len(s) > 1 {
 | 
			
		||||
		s = strings.Split(s[1], "/")
 | 
			
		||||
		if len(s) == 2 {
 | 
			
		||||
			return s[1] // nick
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package bzulip
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
@@ -11,6 +12,7 @@ import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/42wim/matterbridge/version"
 | 
			
		||||
	gzb "github.com/matterbridge/gozulipbot"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -27,7 +29,7 @@ func New(cfg *bridge.Config) bridge.Bridger {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bzulip) Connect() error {
 | 
			
		||||
	bot := gzb.Bot{APIKey: b.GetString("token"), APIURL: b.GetString("server") + "/api/v1/", Email: b.GetString("login")}
 | 
			
		||||
	bot := gzb.Bot{APIKey: b.GetString("token"), APIURL: b.GetString("server") + "/api/v1/", Email: b.GetString("login"), UserAgent: fmt.Sprintf("matterbridge/%s", version.Release)}
 | 
			
		||||
	bot.Init()
 | 
			
		||||
	q, err := bot.RegisterAll()
 | 
			
		||||
	b.q = q
 | 
			
		||||
@@ -125,6 +127,7 @@ func (b *Bzulip) handleQueue() error {
 | 
			
		||||
			b.Log.Debug("heartbeat received.")
 | 
			
		||||
		default:
 | 
			
		||||
			b.Log.Debugf("receiving error: %#v", err)
 | 
			
		||||
			time.Sleep(time.Second * 10)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										110
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,3 +1,113 @@
 | 
			
		||||
# v1.24.1
 | 
			
		||||
 | 
			
		||||
## Enhancements
 | 
			
		||||
 | 
			
		||||
- discord: Switch to discordgo upstream again (#1759)
 | 
			
		||||
- general: Update dependencies and vendor (#1761)
 | 
			
		||||
- general: Create inmessage-logger.tengo (#1688) (#1747)
 | 
			
		||||
- general: Add OpenRC service file (#1746)
 | 
			
		||||
- irc: Refactor utf-8 conversion (irc) (#1767)
 | 
			
		||||
 | 
			
		||||
## Bugfixes
 | 
			
		||||
 | 
			
		||||
- irc: Fix panic in irc. Closes #1751 (#1760)
 | 
			
		||||
- mumble: Implement a workaround to signal Opus support (mumble) (#1764)
 | 
			
		||||
- telegram: Fix for complex-formatted Telegram text (#1765)
 | 
			
		||||
- telegram: Fix Telegram channel title in forwards (#1753)
 | 
			
		||||
- telegram: Fix Telegram Problem (unforwarded formatting and skipping of linebreaks) (#1749)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@s3lph, @ValdikSS, @reckel-jm, @CyberTailor
 | 
			
		||||
 | 
			
		||||
# v1.24.0
 | 
			
		||||
 | 
			
		||||
## New features
 | 
			
		||||
 | 
			
		||||
- harmony: new protocol added: Add support for Harmony (#1656)
 | 
			
		||||
- irc: Allow binding to IP on IRC (#1640)
 | 
			
		||||
- irc: Add support for client certificate (irc) (#1710)
 | 
			
		||||
- mattermost: Add UseUsername option (mattermost). Fixes #1665 (#1714)
 | 
			
		||||
- mattermost: Add support for using ID in channel config (mattermost) (#1715)
 | 
			
		||||
- matrix: Reply support for Matrix (#1664)
 | 
			
		||||
- telegram: Add Telegram Bot Command /chatId (telegram) (#1703)
 | 
			
		||||
 | 
			
		||||
## Enhancements
 | 
			
		||||
 | 
			
		||||
- general: Update dependencies/vendor (#1659)
 | 
			
		||||
- discord: Add more debug options for discord (#1712)
 | 
			
		||||
- docker: Use Alpine stable again in Dockerfile (#1643)
 | 
			
		||||
- mattermost: Log eventtype in debug (mattermost) (#1676)
 | 
			
		||||
- mattermost: Add more ignore debug messages (mattermost) (#1678)
 | 
			
		||||
- slack: Add support for deleting files from slack to discord. Fixes #1705 (#1709)
 | 
			
		||||
- telegram: Add support for code blocks in telegram (#1650)
 | 
			
		||||
- telegram: Update telegram-bot-api to v5 (#1660)
 | 
			
		||||
- telegram: Add comments to messages (telegram) (#1652)
 | 
			
		||||
- telegram: Add support for sender_chat (telegram) (#1677)
 | 
			
		||||
- vk: Remove GroupID (vk) (#1668)
 | 
			
		||||
 | 
			
		||||
## Bugfix
 | 
			
		||||
 | 
			
		||||
- mattermost: Use current parentID if rootId is not set (mattermost) (#1675)
 | 
			
		||||
- matrix: Make HTMLDisable work correct (matrix) (#1716)
 | 
			
		||||
- whatsapp: Make EditSuffix option actually work (whatsapp). Fixes #1510 (#1728)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@DavyJohnesev, @GoliathLabs, @pontaoski, @PeGaSuS-Coder, @dependabot[bot], @vpzomtrrfrt, @SevereCloud, @soloam, @YashRE42, @danwalmsley, @SuperSandro2000, @inzanity
 | 
			
		||||
 | 
			
		||||
# v1.23.2
 | 
			
		||||
 | 
			
		||||
If you're running whatsapp you should update.
 | 
			
		||||
 | 
			
		||||
## Bugfix
 | 
			
		||||
 | 
			
		||||
- whatsapp: Update go-whatsapp version (#1630)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@snikpic
 | 
			
		||||
 | 
			
		||||
# v1.23.1
 | 
			
		||||
 | 
			
		||||
If you're running mattermost 6 you should update.
 | 
			
		||||
 | 
			
		||||
## Bugfix
 | 
			
		||||
 | 
			
		||||
- mattermost: Do not check cache on deleted messages (mattermost). Fixes #1555 (#1624)
 | 
			
		||||
- mattermost: Fix crash on users updating info. Update matterclient dep. Fixes #1617
 | 
			
		||||
- matrix: Keep the logger on a disabled bridge. Fixes #1616 (#1621)
 | 
			
		||||
- msteams: Fix panic in msteams. Fixes #1588 (#1622)
 | 
			
		||||
- xmpp: Do not fail on no avatar data (xmpp) #1529 (#1627)
 | 
			
		||||
- xmpp: Use a new msgID when replacing messages (xmpp). Fixes #1584 (#1623)
 | 
			
		||||
- zulip: Add better error handling on Zulip (#1589)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@Polynomdivision, @minecraftchest1, @alexmv
 | 
			
		||||
 | 
			
		||||
# v1.23.0
 | 
			
		||||
 | 
			
		||||
## New features
 | 
			
		||||
 | 
			
		||||
- irc: Add UserName and RealName options for IRC (#1590)
 | 
			
		||||
- mattermost: Add support for mattermost v6
 | 
			
		||||
- nctalk: Add support for separate display name (nctalk) (#1506)
 | 
			
		||||
- xmpp: Add support for anonymous connection (xmpp) (#1548)
 | 
			
		||||
 | 
			
		||||
## Enhancements
 | 
			
		||||
 | 
			
		||||
- general: Update vendored libraries
 | 
			
		||||
- docker: Use github actions to build dockerhub/ghcr.io images
 | 
			
		||||
- docker: Update GH actions to multi arch (arm64) (#1614)
 | 
			
		||||
- telegram: Convert .tgs with go libraries (and cgo) (telegram) (#1569)
 | 
			
		||||
 | 
			
		||||
## Bugfix
 | 
			
		||||
 | 
			
		||||
- mumble: Remove newline character in bridge multiline messages (mumble) (#1572)
 | 
			
		||||
- slack: Add space before file upload comment (slack) (#1554)
 | 
			
		||||
- slack: Invalidate user in cache on user change event (#1604)
 | 
			
		||||
- xmpp: Fix XMPP parseNick function (#1547)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@powerjungle, @gary-kim, @KingPin, @Benau, @keenan-v1, @tytan652, @KidA001,@minecraftchest1, @irydacea
 | 
			
		||||
 | 
			
		||||
# v1.22.3
 | 
			
		||||
 | 
			
		||||
## Bugfixes
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								contrib/inmessage-logger.tengo
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								contrib/inmessage-logger.tengo
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
fmt := import("fmt")
 | 
			
		||||
os := import("os")
 | 
			
		||||
times := import("times")
 | 
			
		||||
 | 
			
		||||
if msgText != "" && msgUsername != "system" {
 | 
			
		||||
    os.chdir("/var/www/matterbridge")
 | 
			
		||||
    file := os.open_file("inmessage.log", os.o_append|os.o_wronly|os.o_create, 0644)
 | 
			
		||||
    file.write_string(fmt.sprintf(
 | 
			
		||||
        "[%s] <%s> %s\n",
 | 
			
		||||
        times.time_format(times.now(), times.format_rfc1123),
 | 
			
		||||
        msgUsername,
 | 
			
		||||
        msgText
 | 
			
		||||
    ))
 | 
			
		||||
    file.close()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								contrib/matterbridge.openrc
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										19
									
								
								contrib/matterbridge.openrc
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
#!/sbin/openrc-run
 | 
			
		||||
# Copyright 2021-2022 Gentoo Authors
 | 
			
		||||
# Distributed under the terms of the GNU General Public License v2
 | 
			
		||||
 | 
			
		||||
command=/usr/bin/matterbridge
 | 
			
		||||
command_args="-conf ${MATTERBRIDGE_CONF:-/etc/matterbridge/bridge.toml} ${MATTERBRIDGE_ARGS}"
 | 
			
		||||
command_user="matterbridge:matterbridge"
 | 
			
		||||
pidfile="/run/${RC_SVCNAME}.pid"
 | 
			
		||||
command_background=1
 | 
			
		||||
output_log="/var/log/${RC_SVCNAME}.log"
 | 
			
		||||
error_log="${output_log}"
 | 
			
		||||
 | 
			
		||||
depend() {
 | 
			
		||||
	need net
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
start_pre() {
 | 
			
		||||
	checkpath -f "${output_log}" -o "${command_user}" || return 1
 | 
			
		||||
}
 | 
			
		||||
@@ -1,9 +1,10 @@
 | 
			
		||||
FROM alpine:edge as certs
 | 
			
		||||
RUN apk --update add ca-certificates
 | 
			
		||||
ARG VERSION=1.22.3
 | 
			
		||||
ADD https://github.com/42wim/matterbridge/releases/download/v${VERSION}/matterbridge-${VERSION}-linux-arm64 /bin/matterbridge
 | 
			
		||||
RUN chmod +x /bin/matterbridge
 | 
			
		||||
 | 
			
		||||
FROM scratch
 | 
			
		||||
ARG VERSION=1.12.3
 | 
			
		||||
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
 | 
			
		||||
ADD https://github.com/42wim/matterbridge/releases/download/v${VERSION}/matterbridge-linux-arm /bin/matterbridge
 | 
			
		||||
RUN chmod +x /bin/matterbridge
 | 
			
		||||
COPY --from=certs /bin/matterbridge /bin/matterbridge
 | 
			
		||||
ENTRYPOINT ["/bin/matterbridge"]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								gateway/bridgemap/bharmony.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								gateway/bridgemap/bharmony.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
//go:build !noharmony
 | 
			
		||||
// +build !noharmony
 | 
			
		||||
 | 
			
		||||
package bridgemap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	bharmony "github.com/42wim/matterbridge/bridge/harmony"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	FullMap["harmony"] = bharmony.New
 | 
			
		||||
}
 | 
			
		||||
@@ -66,7 +66,7 @@ func New(rootLogger *logrus.Logger, cfg *config.Gateway, r *Router) *Gateway {
 | 
			
		||||
func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string {
 | 
			
		||||
	ID := protocol + " " + mID
 | 
			
		||||
	if gw.Messages.Contains(ID) {
 | 
			
		||||
		return mID
 | 
			
		||||
		return ID
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If not keyed, iterate through cache for downstream, and infer upstream.
 | 
			
		||||
@@ -75,7 +75,7 @@ func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string {
 | 
			
		||||
		ids := v.([]*BrMsgID)
 | 
			
		||||
		for _, downstreamMsgObj := range ids {
 | 
			
		||||
			if ID == downstreamMsgObj.ID {
 | 
			
		||||
				return strings.Replace(mid.(string), protocol+" ", "", 1)
 | 
			
		||||
				return mid.(string)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -447,16 +447,19 @@ func (gw *Gateway) SendMessage(
 | 
			
		||||
	msg.Avatar = gw.modifyAvatar(rmsg, dest)
 | 
			
		||||
	msg.Username = gw.modifyUsername(rmsg, dest)
 | 
			
		||||
 | 
			
		||||
	msg.ID = gw.getDestMsgID(rmsg.Protocol+" "+rmsg.ID, dest, channel)
 | 
			
		||||
	// exclude file delete event as the msg ID here is the native file ID that needs to be deleted
 | 
			
		||||
	if msg.Event != config.EventFileDelete {
 | 
			
		||||
		msg.ID = gw.getDestMsgID(rmsg.Protocol+" "+rmsg.ID, dest, channel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// for api we need originchannel as channel
 | 
			
		||||
	if dest.Protocol == apiProtocol {
 | 
			
		||||
		msg.Channel = rmsg.Channel
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msg.ParentID = gw.getDestMsgID(rmsg.Protocol+" "+canonicalParentMsgID, dest, channel)
 | 
			
		||||
	msg.ParentID = gw.getDestMsgID(canonicalParentMsgID, dest, channel)
 | 
			
		||||
	if msg.ParentID == "" {
 | 
			
		||||
		msg.ParentID = canonicalParentMsgID
 | 
			
		||||
		msg.ParentID = strings.Replace(canonicalParentMsgID, dest.Protocol+" ", "", 1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if the parentID is still empty and we have a parentID set in the original message
 | 
			
		||||
 
 | 
			
		||||
@@ -110,7 +110,9 @@ func (r *Router) disableBridge(br *bridge.Bridge, err error) bool {
 | 
			
		||||
	if r.BridgeValues().General.IgnoreFailureOnStart {
 | 
			
		||||
		r.logger.Error(err)
 | 
			
		||||
		// setting this bridge empty
 | 
			
		||||
		*br = bridge.Bridge{}
 | 
			
		||||
		*br = bridge.Bridge{
 | 
			
		||||
			Log: br.Log,
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										144
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								go.mod
									
									
									
									
									
								
							@@ -3,37 +3,35 @@ module github.com/42wim/matterbridge
 | 
			
		||||
require (
 | 
			
		||||
	github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557
 | 
			
		||||
	github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
 | 
			
		||||
	github.com/Jeffail/gabs v1.4.0 // indirect
 | 
			
		||||
	github.com/Benau/tgsconverter v0.0.0-20210809170556-99f4a4f6337f
 | 
			
		||||
	github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560
 | 
			
		||||
	github.com/Rhymen/go-whatsapp v0.1.2-0.20210615184944-2b8a3e9b8aa2
 | 
			
		||||
	github.com/SevereCloud/vksdk/v2 v2.10.0
 | 
			
		||||
	github.com/d5/tengo/v2 v2.7.0
 | 
			
		||||
	github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c
 | 
			
		||||
	github.com/SevereCloud/vksdk/v2 v2.13.1
 | 
			
		||||
	github.com/bwmarrin/discordgo v0.24.0
 | 
			
		||||
	github.com/d5/tengo/v2 v2.10.1
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.1
 | 
			
		||||
	github.com/fsnotify/fsnotify v1.4.9
 | 
			
		||||
	github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81
 | 
			
		||||
	github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7
 | 
			
		||||
	github.com/google/gops v0.3.18
 | 
			
		||||
	github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect
 | 
			
		||||
	github.com/fsnotify/fsnotify v1.5.1
 | 
			
		||||
	github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
 | 
			
		||||
	github.com/gomarkdown/markdown v0.0.0-20220310201231-552c6011c0b8
 | 
			
		||||
	github.com/google/gops v0.3.22
 | 
			
		||||
	github.com/gorilla/schema v1.2.0
 | 
			
		||||
	github.com/gorilla/websocket v1.4.2
 | 
			
		||||
	github.com/gorilla/websocket v1.5.0
 | 
			
		||||
	github.com/harmony-development/shibshib v0.0.0-20220101224523-c98059d09cfa
 | 
			
		||||
	github.com/hashicorp/golang-lru v0.5.4
 | 
			
		||||
	github.com/jpillora/backoff v1.0.0
 | 
			
		||||
	github.com/keybase/go-keybase-chat-bot v0.0.0-20200505163032-5cacf52379da
 | 
			
		||||
	github.com/kyokomi/emoji/v2 v2.2.8
 | 
			
		||||
	github.com/labstack/echo/v4 v4.3.0
 | 
			
		||||
	github.com/lrstanley/girc v0.0.0-20210611213246-771323f1624b
 | 
			
		||||
	github.com/keybase/go-keybase-chat-bot v0.0.0-20211201215354-ee4b23828b55
 | 
			
		||||
	github.com/kyokomi/emoji/v2 v2.2.9
 | 
			
		||||
	github.com/labstack/echo/v4 v4.7.0
 | 
			
		||||
	github.com/lrstanley/girc v0.0.0-20211023233735-147f0ff77566
 | 
			
		||||
	github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
 | 
			
		||||
	github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20210403163225-761e8622445d
 | 
			
		||||
	github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7
 | 
			
		||||
	github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050
 | 
			
		||||
	github.com/matterbridge/gozulipbot v0.0.0-20200820220548-be5824faa913
 | 
			
		||||
	github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696
 | 
			
		||||
	github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be
 | 
			
		||||
	github.com/matterbridge/gozulipbot v0.0.0-20211023205727-a19d6c1f3b75
 | 
			
		||||
	github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba
 | 
			
		||||
	github.com/mattermost/mattermost-server/v5 v5.30.1
 | 
			
		||||
	github.com/matterbridge/matterclient v0.0.0-20211107234719-faca3cd42315
 | 
			
		||||
	github.com/mattermost/mattermost-server/v5 v5.39.3
 | 
			
		||||
	github.com/mattermost/mattermost-server/v6 v6.4.2
 | 
			
		||||
	github.com/mattn/godown v0.0.1
 | 
			
		||||
	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
 | 
			
		||||
	github.com/missdeer/golib v1.0.4
 | 
			
		||||
	github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d // indirect
 | 
			
		||||
	github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect
 | 
			
		||||
	github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9
 | 
			
		||||
	github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
 | 
			
		||||
	github.com/rs/xid v1.3.0
 | 
			
		||||
@@ -41,20 +39,102 @@ require (
 | 
			
		||||
	github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
 | 
			
		||||
	github.com/shazow/ssh-chat v1.10.1
 | 
			
		||||
	github.com/sirupsen/logrus v1.8.1
 | 
			
		||||
	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
 | 
			
		||||
	github.com/slack-go/slack v0.9.1
 | 
			
		||||
	github.com/spf13/viper v1.8.0
 | 
			
		||||
	github.com/slack-go/slack v0.10.2
 | 
			
		||||
	github.com/spf13/viper v1.10.1
 | 
			
		||||
	github.com/stretchr/testify v1.7.0
 | 
			
		||||
	github.com/vincent-petithory/dataurl v0.0.0-20191104211930-d1553a71de50
 | 
			
		||||
	github.com/vincent-petithory/dataurl v1.0.0
 | 
			
		||||
	github.com/writeas/go-strip-markdown v2.0.1+incompatible
 | 
			
		||||
	github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
 | 
			
		||||
	github.com/yaegashi/msgraph.go v0.1.4
 | 
			
		||||
	github.com/zfjagann/golang-ring v0.0.0-20210116075443-7c86fdb43134
 | 
			
		||||
	golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9
 | 
			
		||||
	golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1
 | 
			
		||||
	gomod.garykim.dev/nc-talk v0.2.2
 | 
			
		||||
	golang.org/x/image v0.0.0-20220302094943-723b81ca9867
 | 
			
		||||
	golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
 | 
			
		||||
	golang.org/x/text v0.3.7
 | 
			
		||||
	gomod.garykim.dev/nc-talk v0.3.0
 | 
			
		||||
	gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376
 | 
			
		||||
	layeh.com/gumble v0.0.0-20200818122324-146f9205029b
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
go 1.15
 | 
			
		||||
require (
 | 
			
		||||
	github.com/Benau/go_rlottie v0.0.0-20210807002906-98c1b2421989 // indirect
 | 
			
		||||
	github.com/Jeffail/gabs v1.4.0 // indirect
 | 
			
		||||
	github.com/apex/log v1.9.0 // indirect
 | 
			
		||||
	github.com/av-elier/go-decimal-to-rational v0.0.0-20191127152832-89e6aad02ecf // indirect
 | 
			
		||||
	github.com/blang/semver v3.5.1+incompatible // indirect
 | 
			
		||||
	github.com/dustin/go-humanize v1.0.0 // indirect
 | 
			
		||||
	github.com/dyatlov/go-opengraph v0.0.0-20210112100619-dae8665a5b09 // indirect
 | 
			
		||||
	github.com/francoispqt/gojay v1.2.13 // indirect
 | 
			
		||||
	github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
 | 
			
		||||
	github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
 | 
			
		||||
	github.com/golang/protobuf v1.5.2 // indirect
 | 
			
		||||
	github.com/google/uuid v1.3.0 // indirect
 | 
			
		||||
	github.com/gopackage/ddp v0.0.3 // indirect
 | 
			
		||||
	github.com/hashicorp/errwrap v1.1.0 // indirect
 | 
			
		||||
	github.com/hashicorp/go-multierror v1.1.1 // indirect
 | 
			
		||||
	github.com/hashicorp/hcl v1.0.0 // indirect
 | 
			
		||||
	github.com/json-iterator/go v1.1.12 // indirect
 | 
			
		||||
	github.com/kettek/apng v0.0.0-20191108220231-414630eed80f // indirect
 | 
			
		||||
	github.com/klauspost/compress v1.14.2 // indirect
 | 
			
		||||
	github.com/klauspost/cpuid/v2 v2.0.9 // indirect
 | 
			
		||||
	github.com/labstack/gommon v0.3.1 // indirect
 | 
			
		||||
	github.com/magiconair/properties v1.8.5 // indirect
 | 
			
		||||
	github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect
 | 
			
		||||
	github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d // indirect
 | 
			
		||||
	github.com/mattermost/logr v1.0.13 // indirect
 | 
			
		||||
	github.com/mattermost/logr/v2 v2.0.15 // indirect
 | 
			
		||||
	github.com/mattn/go-colorable v0.1.12 // indirect
 | 
			
		||||
	github.com/mattn/go-isatty v0.0.14 // indirect
 | 
			
		||||
	github.com/mattn/go-runewidth v0.0.13 // indirect
 | 
			
		||||
	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
 | 
			
		||||
	github.com/minio/md5-simd v1.1.2 // indirect
 | 
			
		||||
	github.com/minio/minio-go/v7 v7.0.16 // indirect
 | 
			
		||||
	github.com/minio/sha256-simd v1.0.0 // indirect
 | 
			
		||||
	github.com/mitchellh/go-homedir v1.1.0 // indirect
 | 
			
		||||
	github.com/mitchellh/mapstructure v1.4.3 // indirect
 | 
			
		||||
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 | 
			
		||||
	github.com/modern-go/reflect2 v1.0.2 // indirect
 | 
			
		||||
	github.com/monaco-io/request v1.0.5 // indirect
 | 
			
		||||
	github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d // indirect
 | 
			
		||||
	github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect
 | 
			
		||||
	github.com/pborman/uuid v1.2.1 // indirect
 | 
			
		||||
	github.com/pelletier/go-toml v1.9.4 // indirect
 | 
			
		||||
	github.com/philhofer/fwd v1.1.1 // indirect
 | 
			
		||||
	github.com/pkg/errors v0.9.1 // indirect
 | 
			
		||||
	github.com/pmezard/go-difflib v1.0.0 // indirect
 | 
			
		||||
	github.com/rickb777/date v1.12.4 // indirect
 | 
			
		||||
	github.com/rickb777/plural v1.2.0 // indirect
 | 
			
		||||
	github.com/rivo/uniseg v0.2.0 // indirect
 | 
			
		||||
	github.com/shazow/rateio v0.0.0-20200113175441-4461efc8bdc4 // indirect
 | 
			
		||||
	github.com/sizeofint/webpanimation v0.0.0-20210809145948-1d2b32119882 // indirect
 | 
			
		||||
	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
 | 
			
		||||
	github.com/spf13/afero v1.6.0 // indirect
 | 
			
		||||
	github.com/spf13/cast v1.4.1 // indirect
 | 
			
		||||
	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 | 
			
		||||
	github.com/spf13/pflag v1.0.5 // indirect
 | 
			
		||||
	github.com/subosito/gotenv v1.2.0 // indirect
 | 
			
		||||
	github.com/tinylib/msgp v1.1.6 // indirect
 | 
			
		||||
	github.com/valyala/bytebufferpool v1.0.0 // indirect
 | 
			
		||||
	github.com/valyala/fasttemplate v1.2.1 // indirect
 | 
			
		||||
	github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
 | 
			
		||||
	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
 | 
			
		||||
	github.com/wiggin77/cfg v1.0.2 // indirect
 | 
			
		||||
	github.com/wiggin77/merror v1.0.3 // indirect
 | 
			
		||||
	github.com/wiggin77/srslog v1.0.1 // indirect
 | 
			
		||||
	go.uber.org/atomic v1.9.0 // indirect
 | 
			
		||||
	go.uber.org/multierr v1.7.0 // indirect
 | 
			
		||||
	go.uber.org/zap v1.17.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect
 | 
			
		||||
	golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
 | 
			
		||||
	golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
 | 
			
		||||
	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
 | 
			
		||||
	golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
 | 
			
		||||
	google.golang.org/appengine v1.6.7 // indirect
 | 
			
		||||
	google.golang.org/protobuf v1.27.1 // indirect
 | 
			
		||||
	gopkg.in/ini.v1 v1.66.2 // indirect
 | 
			
		||||
	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
 | 
			
		||||
	gopkg.in/yaml.v2 v2.4.0 // indirect
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
replace github.com/matrix-org/gomatrix => github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419
 | 
			
		||||
 | 
			
		||||
go 1.17
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ import (
 | 
			
		||||
	"log"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"regexp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Message for rocketchat outgoing webhook.
 | 
			
		||||
@@ -68,7 +69,6 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	}
 | 
			
		||||
	msg := Message{}
 | 
			
		||||
	body, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
	log.Println(string(body))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println(err)
 | 
			
		||||
		http.NotFound(w, r)
 | 
			
		||||
@@ -89,7 +89,11 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	msg.ChannelName = "#" + msg.ChannelName
 | 
			
		||||
	if c.Token != "" {
 | 
			
		||||
		if msg.Token != c.Token {
 | 
			
		||||
			log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr)
 | 
			
		||||
			if regexp.MustCompile(`[^a-zA-Z0-9]+`).MatchString(msg.Token) {
 | 
			
		||||
				log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr)
 | 
			
		||||
			} else {
 | 
			
		||||
				log.Println("invalid token from " + r.RemoteAddr)
 | 
			
		||||
			}
 | 
			
		||||
			http.NotFound(w, r)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,15 +10,13 @@ import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/gateway"
 | 
			
		||||
	"github.com/42wim/matterbridge/gateway/bridgemap"
 | 
			
		||||
	"github.com/42wim/matterbridge/version"
 | 
			
		||||
	"github.com/google/gops/agent"
 | 
			
		||||
	prefixed "github.com/matterbridge/logrus-prefixed-formatter"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	version = "1.22.3"
 | 
			
		||||
	githash string
 | 
			
		||||
 | 
			
		||||
	flagConfig  = flag.String("conf", "matterbridge.toml", "config file")
 | 
			
		||||
	flagDebug   = flag.Bool("debug", false, "enable debug")
 | 
			
		||||
	flagVersion = flag.Bool("version", false, "show version")
 | 
			
		||||
@@ -28,7 +26,7 @@ var (
 | 
			
		||||
func main() {
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	if *flagVersion {
 | 
			
		||||
		fmt.Printf("version: %s %s\n", version, githash)
 | 
			
		||||
		fmt.Printf("version: %s %s\n", version.Release, version.GitHash)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -43,8 +41,8 @@ func main() {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logger.Printf("Running version %s %s", version, githash)
 | 
			
		||||
	if strings.Contains(version, "-dev") {
 | 
			
		||||
	logger.Printf("Running version %s %s", version.Release, version.GitHash)
 | 
			
		||||
	if strings.Contains(version.Release, "-dev") {
 | 
			
		||||
		logger.Println("WARNING: THIS IS A DEVELOPMENT VERSION. Things may break.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,13 @@ Password=""
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
UseTLS=false
 | 
			
		||||
 | 
			
		||||
#Use client certificate - see CertFP https://libera.chat/guides/certfp.html
 | 
			
		||||
#Specify filename which contains private key and cert
 | 
			
		||||
#OPTIONAL (default "")
 | 
			
		||||
#
 | 
			
		||||
#TLSClientCertificate="cert.pem"
 | 
			
		||||
TLSClientCertificate=""
 | 
			
		||||
 | 
			
		||||
#Enable SASL (PLAIN) authentication. (libera requires this from eg AWS hosts)
 | 
			
		||||
#It uses NickServNick and NickServPassword as login and password
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
@@ -34,6 +41,11 @@ UseSASL=false
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
SkipTLSVerify=true
 | 
			
		||||
 | 
			
		||||
#Local address to use for server connection
 | 
			
		||||
#Note that Server and Bind must resolve to addresses of the same family.
 | 
			
		||||
#OPTIONAL (default "")
 | 
			
		||||
Bind=""
 | 
			
		||||
 | 
			
		||||
#If you know your charset, you can specify it manually.
 | 
			
		||||
#Otherwise it tries to detect this automatically. Select one below
 | 
			
		||||
# "iso-8859-2:1987", "iso-8859-9:1989", "866", "latin9", "iso-8859-10:1992", "iso-ir-109", "hebrew",
 | 
			
		||||
@@ -55,6 +67,14 @@ Charset=""
 | 
			
		||||
#REQUIRED
 | 
			
		||||
Nick="matterbot"
 | 
			
		||||
 | 
			
		||||
#Real name/gecos displayed in e.g. /WHOIS and /WHO
 | 
			
		||||
#OPTIONAL (defaults to the nick)
 | 
			
		||||
RealName="Matterbridge instance on IRC"
 | 
			
		||||
 | 
			
		||||
#IRC username/ident preceding the hostname in hostmasks and /WHOIS
 | 
			
		||||
#OPTIONAL (defaults to the nick)
 | 
			
		||||
UserName="bridge"
 | 
			
		||||
 | 
			
		||||
#If you registered your bot with a service like Nickserv on libera.
 | 
			
		||||
#Also being used when UseSASL=true
 | 
			
		||||
#
 | 
			
		||||
@@ -223,12 +243,16 @@ UseRelayMsg=false
 | 
			
		||||
#REQUIRED
 | 
			
		||||
Server="jabber.example.com:5222"
 | 
			
		||||
 | 
			
		||||
#Use anonymous MUC login
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
Anonymous=false
 | 
			
		||||
 | 
			
		||||
#Jid
 | 
			
		||||
#REQUIRED
 | 
			
		||||
#REQUIRED if Anonymous=false
 | 
			
		||||
Jid="user@example.com"
 | 
			
		||||
 | 
			
		||||
#Password
 | 
			
		||||
#REQUIRED
 | 
			
		||||
#REQUIRED if Anonymous=false
 | 
			
		||||
Password="yourpass"
 | 
			
		||||
 | 
			
		||||
#MUC
 | 
			
		||||
@@ -384,6 +408,10 @@ SkipTLSVerify=true
 | 
			
		||||
## RELOADABLE SETTINGS
 | 
			
		||||
## Settings below can be reloaded by editing the file
 | 
			
		||||
 | 
			
		||||
# UseUserName shows the username instead of the server nickname
 | 
			
		||||
# OPTIONAL (default false)
 | 
			
		||||
UseUserName=false
 | 
			
		||||
 | 
			
		||||
#how to format the list of IRC nicks when displayed in mattermost.
 | 
			
		||||
#Possible options are "table" and "plain"
 | 
			
		||||
#OPTIONAL (default plain)
 | 
			
		||||
@@ -1284,13 +1312,6 @@ HTMLDisable=false
 | 
			
		||||
# UseUserName shows the username instead of the server nickname
 | 
			
		||||
UseUserName=false
 | 
			
		||||
 | 
			
		||||
#Whether to prefix messages from other bridges to matrix with the sender's nick.
 | 
			
		||||
#Useful if username overrides for incoming webhooks isn't enabled on the
 | 
			
		||||
#matrix server. If you set PrefixMessagesWithNick to true, each message
 | 
			
		||||
#from bridge to matrix will by default be prefixed by the RemoteNickFormat setting. i
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
PrefixMessagesWithNick=false
 | 
			
		||||
 | 
			
		||||
#Nicks you want to ignore.
 | 
			
		||||
#Regular expressions supported
 | 
			
		||||
#Messages from those users will not be sent to other bridges.
 | 
			
		||||
@@ -1469,6 +1490,9 @@ Password = "talkuserpass"
 | 
			
		||||
# Suffix for Guest Users
 | 
			
		||||
GuestSuffix = " (Guest)"
 | 
			
		||||
 | 
			
		||||
# Separate display name (Note: needs to be configured from Nextcloud Talk to work)
 | 
			
		||||
SeparateDisplayName=false
 | 
			
		||||
 | 
			
		||||
###################################################################
 | 
			
		||||
# Mumble
 | 
			
		||||
###################################################################
 | 
			
		||||
@@ -1526,10 +1550,6 @@ MessageClipped="<clipped message>"
 | 
			
		||||
#See https://vk.com/dev/bots_docs
 | 
			
		||||
Token="Yourtokenhere"
 | 
			
		||||
 | 
			
		||||
#Group ID
 | 
			
		||||
#For example in URL https://vk.com/public168963511 group ID is 168963511
 | 
			
		||||
GroupID=123456789
 | 
			
		||||
 | 
			
		||||
###################################################################
 | 
			
		||||
# WhatsApp
 | 
			
		||||
###################################################################
 | 
			
		||||
@@ -1647,6 +1667,18 @@ StripNick=false
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
ShowTopicChange=false
 | 
			
		||||
 | 
			
		||||
###################################################################
 | 
			
		||||
# Harmony
 | 
			
		||||
###################################################################
 | 
			
		||||
 | 
			
		||||
[harmony.chat_harmonyapp_io]
 | 
			
		||||
Homeserver = "https://chat.harmonyapp.io:2289"
 | 
			
		||||
Token = "your token goes here"
 | 
			
		||||
UserID = "user id of the bot account"
 | 
			
		||||
Community = "community id that channels will be located in"
 | 
			
		||||
UseUserName = true
 | 
			
		||||
RemoteNickFormat = "{NICK}"
 | 
			
		||||
 | 
			
		||||
###################################################################
 | 
			
		||||
#API
 | 
			
		||||
###################################################################
 | 
			
		||||
@@ -1692,6 +1724,7 @@ RemoteNickFormat="{NICK}"
 | 
			
		||||
 | 
			
		||||
#RemoteNickFormat defines how remote users appear on this bridge
 | 
			
		||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick.
 | 
			
		||||
#The string "{NOPINGNICK}" (case sensitive) will be replaced by the actual nick / username, but with a ZWSP inside the nick, so the irc user with the same nick won't get pinged.
 | 
			
		||||
#The string "{USERID}" (case sensitive) will be replaced by the user ID.
 | 
			
		||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
			
		||||
#The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge
 | 
			
		||||
@@ -1718,7 +1751,7 @@ StripNick=false
 | 
			
		||||
#The MediaServerDownload will be used so that bridges without native uploading support:
 | 
			
		||||
#gitter, irc and xmpp will be shown links to the files on MediaServerDownload
 | 
			
		||||
#
 | 
			
		||||
#More information https://github.com/42wim/matterbridge/wiki/Mediaserver-setup-%5Badvanced%5D
 | 
			
		||||
#More information https://github.com/42wim/matterbridge/wiki/Mediaserver-setup-%28advanced%29
 | 
			
		||||
#OPTIONAL (default empty)
 | 
			
		||||
MediaServerUpload="https://user:pass@yourserver.com/upload"
 | 
			
		||||
#OPTIONAL (default empty)
 | 
			
		||||
@@ -1864,7 +1897,8 @@ enable=true
 | 
			
		||||
    # -------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
    #    irc     |      channel       |            #general           | The # symbol is required and should be lowercase!
 | 
			
		||||
    # -------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
    # mattermost |      channel       |            general            | This is the channel name as seen in the URL, not the display name
 | 
			
		||||
    #            |      channel       |            general            | This is the channel name as seen in the URL, not the display name
 | 
			
		||||
    # mattermost |    channel id      | ID:oc4wifyuojgw5f3nsuweesmz8w | This is the channel ID (only use if you know what you're doing)
 | 
			
		||||
    # -------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
    #   matrix   | #channel:server    |    #yourchannel:matrix.org    | Encrypted rooms are not supported in matrix
 | 
			
		||||
    # -------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
@@ -1883,14 +1917,14 @@ enable=true
 | 
			
		||||
    # -------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
    #  telegram  |      chatid        |          -123456789           | A large negative number. see https://www.linkedin.com/pulse/telegram-bots-beginners-marco-frau
 | 
			
		||||
    # -------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
    #  vk        |      peerid        |          2000000002           | A number that starts form 2000000000. Use --debug and send any message in chat to get PeerID in the logs 
 | 
			
		||||
    #  vk        |      peerid        |          2000000002           | A number that starts form 2000000000. Use --debug and send any message in chat to get PeerID in the logs
 | 
			
		||||
    # -------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
    #  whatsapp  |     group JID      | 48111222333-123455678999@g.us | A unique group JID. If you specify an empty string, bridge will list all the possibilities
 | 
			
		||||
    #            |    "Group Name"    |         "Family Chat"         | if you specify a group name, the bridge will find hint the JID to specify. Names can change over time and are not stable.
 | 
			
		||||
    # -------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
    #    xmpp    |      channel       |            general            | The room name
 | 
			
		||||
    # -------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
    #   zulip    | stream/topic:topic |     general/off-topic:food    | Do not use the # when specifying a topic
 | 
			
		||||
    #   zulip    | stream/topic:topic |      general/topic:food       | Do not use the # when specifying a topic
 | 
			
		||||
    # -------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
@@ -1939,6 +1973,10 @@ enable=true
 | 
			
		||||
    account="zulip.streamchat"
 | 
			
		||||
    channel="general/topic:mytopic"
 | 
			
		||||
 | 
			
		||||
    [[gateway.inout]]
 | 
			
		||||
    account="harmony.chat_harmonyapp_io"
 | 
			
		||||
    channel="channel id goes here"
 | 
			
		||||
 | 
			
		||||
    #API example
 | 
			
		||||
    #[[gateway.inout]]
 | 
			
		||||
    #account="api.local"
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ import (
 | 
			
		||||
func (m *MMClient) parseActionPost(rmsg *Message) {
 | 
			
		||||
	// add post to cache, if it already exists don't relay this again.
 | 
			
		||||
	// this should fix reposts
 | 
			
		||||
	if ok, _ := m.lruCache.ContainsOrAdd(digestString(rmsg.Raw.Data["post"].(string)), true); ok {
 | 
			
		||||
	if ok, _ := m.lruCache.ContainsOrAdd(digestString(rmsg.Raw.Data["post"].(string)), true); ok && rmsg.Raw.Event != model.WEBSOCKET_EVENT_POST_DELETED {
 | 
			
		||||
		m.logger.Debugf("message %#v in cache, not processing again", rmsg.Raw.Data["post"].(string))
 | 
			
		||||
		rmsg.Text = ""
 | 
			
		||||
		return
 | 
			
		||||
@@ -111,7 +111,7 @@ func (m *MMClient) GetFileLinks(filenames []string) []string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) GetPosts(channelId string, limit int) *model.PostList { //nolint:golint
 | 
			
		||||
	res, resp := m.Client.GetPostsForChannel(channelId, 0, limit, "")
 | 
			
		||||
	res, resp := m.Client.GetPostsForChannel(channelId, 0, limit, "", true)
 | 
			
		||||
	if resp.Error != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
@@ -119,7 +119,7 @@ func (m *MMClient) GetPosts(channelId string, limit int) *model.PostList { //nol
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) GetPostsSince(channelId string, time int64) *model.PostList { //nolint:golint
 | 
			
		||||
	res, resp := m.Client.GetPostsSince(channelId, time)
 | 
			
		||||
	res, resp := m.Client.GetPostsSince(channelId, time, true)
 | 
			
		||||
	if resp.Error != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ RUN apk add \
 | 
			
		||||
    go \
 | 
			
		||||
    git \
 | 
			
		||||
  && cd /go/src/matterbridge \
 | 
			
		||||
  && go build -mod vendor -ldflags "-X main.githash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
 | 
			
		||||
  && CGO_ENABLED=0 go build -mod vendor -ldflags "-X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
 | 
			
		||||
 | 
			
		||||
FROM alpine
 | 
			
		||||
RUN apk --no-cache add \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/github.com/Benau/go_rlottie/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/Benau/go_rlottie/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
The MIT License
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2021, (see AUTHORS)
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person
 | 
			
		||||
obtaining a copy of this software and associated documentation
 | 
			
		||||
files (the "Software"), to deal in the Software without
 | 
			
		||||
restriction, including without limitation the rights to use,
 | 
			
		||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the
 | 
			
		||||
Software is furnished to do so, subject to the following
 | 
			
		||||
conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be
 | 
			
		||||
included in all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 | 
			
		||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
			
		||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 | 
			
		||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 | 
			
		||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
			
		||||
OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Benau/go_rlottie/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Benau/go_rlottie/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
Go binding for https://github.com/Samsung/rlottie, example at https://github.com/Benau/tgsconverter
 | 
			
		||||
							
								
								
									
										284
									
								
								vendor/github.com/Benau/go_rlottie/binding_c_lottieanimation_capi.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								vendor/github.com/Benau/go_rlottie/binding_c_lottieanimation_capi.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,284 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rlottie.h"
 | 
			
		||||
#include "rlottie_capi.h"
 | 
			
		||||
#include "vector_vdebug.h"
 | 
			
		||||
 | 
			
		||||
using namespace rlottie;
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
struct Lottie_Animation_S
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<Animation>      mAnimation;
 | 
			
		||||
    std::future<Surface>            mRenderTask;
 | 
			
		||||
    uint32_t                       *mBufferRef;
 | 
			
		||||
    LOTMarkerList                  *mMarkerList;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API Lottie_Animation_S *lottie_animation_from_file(const char *path)
 | 
			
		||||
{
 | 
			
		||||
    if (auto animation = Animation::loadFromFile(path) ) {
 | 
			
		||||
        Lottie_Animation_S *handle = new Lottie_Animation_S();
 | 
			
		||||
        handle->mAnimation = std::move(animation);
 | 
			
		||||
        return handle;
 | 
			
		||||
    } else {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API Lottie_Animation_S *lottie_animation_from_data(const char *data, const char *key, const char *resourcePath)
 | 
			
		||||
{
 | 
			
		||||
    if (auto animation = Animation::loadFromData(data, key, resourcePath) ) {
 | 
			
		||||
        Lottie_Animation_S *handle = new Lottie_Animation_S();
 | 
			
		||||
        handle->mAnimation = std::move(animation);
 | 
			
		||||
        return handle;
 | 
			
		||||
    } else {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API void lottie_animation_destroy(Lottie_Animation_S *animation)
 | 
			
		||||
{
 | 
			
		||||
    if (animation) {
 | 
			
		||||
        if (animation->mMarkerList) {
 | 
			
		||||
            for(size_t i = 0; i < animation->mMarkerList->size; i++) {
 | 
			
		||||
                if (animation->mMarkerList->ptr[i].name) free(animation->mMarkerList->ptr[i].name);
 | 
			
		||||
            }
 | 
			
		||||
            delete[] animation->mMarkerList->ptr;
 | 
			
		||||
            delete animation->mMarkerList;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (animation->mRenderTask.valid()) {
 | 
			
		||||
            animation->mRenderTask.get();
 | 
			
		||||
        }
 | 
			
		||||
        animation->mAnimation = nullptr;
 | 
			
		||||
        delete animation;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API void lottie_animation_get_size(const Lottie_Animation_S *animation, size_t *width, size_t *height)
 | 
			
		||||
{
 | 
			
		||||
   if (!animation) return;
 | 
			
		||||
 | 
			
		||||
   animation->mAnimation->size(*width, *height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API double lottie_animation_get_duration(const Lottie_Animation_S *animation)
 | 
			
		||||
{
 | 
			
		||||
   if (!animation) return 0;
 | 
			
		||||
 | 
			
		||||
   return animation->mAnimation->duration();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API size_t lottie_animation_get_totalframe(const Lottie_Animation_S *animation)
 | 
			
		||||
{
 | 
			
		||||
   if (!animation) return 0;
 | 
			
		||||
 | 
			
		||||
   return animation->mAnimation->totalFrame();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API double lottie_animation_get_framerate(const Lottie_Animation_S *animation)
 | 
			
		||||
{
 | 
			
		||||
   if (!animation) return 0;
 | 
			
		||||
 | 
			
		||||
   return animation->mAnimation->frameRate();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API const LOTLayerNode * lottie_animation_render_tree(Lottie_Animation_S *animation, size_t frame_num, size_t width, size_t height)
 | 
			
		||||
{
 | 
			
		||||
    if (!animation) return nullptr;
 | 
			
		||||
 | 
			
		||||
    return animation->mAnimation->renderTree(frame_num, width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API size_t
 | 
			
		||||
lottie_animation_get_frame_at_pos(const Lottie_Animation_S *animation, float pos)
 | 
			
		||||
{
 | 
			
		||||
    if (!animation) return 0;
 | 
			
		||||
 | 
			
		||||
    return animation->mAnimation->frameAtPos(pos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API void
 | 
			
		||||
lottie_animation_render(Lottie_Animation_S *animation,
 | 
			
		||||
                        size_t frame_number,
 | 
			
		||||
                        uint32_t *buffer,
 | 
			
		||||
                        size_t width,
 | 
			
		||||
                        size_t height,
 | 
			
		||||
                        size_t bytes_per_line)
 | 
			
		||||
{
 | 
			
		||||
    if (!animation) return;
 | 
			
		||||
 | 
			
		||||
    rlottie::Surface surface(buffer, width, height, bytes_per_line);
 | 
			
		||||
    animation->mAnimation->renderSync(frame_number, surface);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API void
 | 
			
		||||
lottie_animation_render_async(Lottie_Animation_S *animation,
 | 
			
		||||
                              size_t frame_number,
 | 
			
		||||
                              uint32_t *buffer,
 | 
			
		||||
                              size_t width,
 | 
			
		||||
                              size_t height,
 | 
			
		||||
                              size_t bytes_per_line)
 | 
			
		||||
{
 | 
			
		||||
    if (!animation) return;
 | 
			
		||||
 | 
			
		||||
    rlottie::Surface surface(buffer, width, height, bytes_per_line);
 | 
			
		||||
    animation->mRenderTask = animation->mAnimation->render(frame_number, surface);
 | 
			
		||||
    animation->mBufferRef = buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API uint32_t *
 | 
			
		||||
lottie_animation_render_flush(Lottie_Animation_S *animation)
 | 
			
		||||
{
 | 
			
		||||
    if (!animation) return nullptr;
 | 
			
		||||
 | 
			
		||||
    if (animation->mRenderTask.valid()) {
 | 
			
		||||
        animation->mRenderTask.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return animation->mBufferRef;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API void
 | 
			
		||||
lottie_animation_property_override(Lottie_Animation_S *animation,
 | 
			
		||||
                                   const Lottie_Animation_Property type,
 | 
			
		||||
                                   const char *keypath,
 | 
			
		||||
                                   ...)
 | 
			
		||||
{
 | 
			
		||||
    va_list prop;
 | 
			
		||||
    va_start(prop, keypath);
 | 
			
		||||
    const int arg_count = [type](){
 | 
			
		||||
                             switch (type) {
 | 
			
		||||
                              case LOTTIE_ANIMATION_PROPERTY_FILLCOLOR:
 | 
			
		||||
                              case LOTTIE_ANIMATION_PROPERTY_STROKECOLOR:
 | 
			
		||||
                                return 3;
 | 
			
		||||
                              case LOTTIE_ANIMATION_PROPERTY_FILLOPACITY:
 | 
			
		||||
                              case LOTTIE_ANIMATION_PROPERTY_STROKEOPACITY:
 | 
			
		||||
                              case LOTTIE_ANIMATION_PROPERTY_STROKEWIDTH:
 | 
			
		||||
                              case LOTTIE_ANIMATION_PROPERTY_TR_ROTATION:
 | 
			
		||||
                                return 1;
 | 
			
		||||
                              case LOTTIE_ANIMATION_PROPERTY_TR_POSITION:
 | 
			
		||||
                              case LOTTIE_ANIMATION_PROPERTY_TR_SCALE:
 | 
			
		||||
                                return 2;
 | 
			
		||||
                              default:
 | 
			
		||||
                                return 0;
 | 
			
		||||
                             }
 | 
			
		||||
                          }();
 | 
			
		||||
    double v[3] = {0};
 | 
			
		||||
    for (int i = 0; i < arg_count ; i++) {
 | 
			
		||||
      v[i] = va_arg(prop, double);
 | 
			
		||||
    }
 | 
			
		||||
    va_end(prop);
 | 
			
		||||
 | 
			
		||||
    switch(type) {
 | 
			
		||||
    case LOTTIE_ANIMATION_PROPERTY_FILLCOLOR: {
 | 
			
		||||
        double r = v[0];
 | 
			
		||||
        double g = v[1];
 | 
			
		||||
        double b = v[2];
 | 
			
		||||
        if (r > 1 || r < 0 || g > 1 || g < 0 || b > 1 || b < 0) break;
 | 
			
		||||
        animation->mAnimation->setValue<rlottie::Property::FillColor>(keypath, rlottie::Color(r, g, b));
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case LOTTIE_ANIMATION_PROPERTY_FILLOPACITY: {
 | 
			
		||||
        double opacity = v[0];
 | 
			
		||||
        if (opacity > 100 || opacity < 0) break;
 | 
			
		||||
        animation->mAnimation->setValue<rlottie::Property::FillOpacity>(keypath, (float)opacity);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case LOTTIE_ANIMATION_PROPERTY_STROKECOLOR: {
 | 
			
		||||
        double r = v[0];
 | 
			
		||||
        double g = v[1];
 | 
			
		||||
        double b = v[2];
 | 
			
		||||
        if (r > 1 || r < 0 || g > 1 || g < 0 || b > 1 || b < 0) break;
 | 
			
		||||
        animation->mAnimation->setValue<rlottie::Property::StrokeColor>(keypath, rlottie::Color(r, g, b));
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case LOTTIE_ANIMATION_PROPERTY_STROKEOPACITY: {
 | 
			
		||||
        double opacity = v[0];
 | 
			
		||||
        if (opacity > 100 || opacity < 0) break;
 | 
			
		||||
        animation->mAnimation->setValue<rlottie::Property::StrokeOpacity>(keypath, (float)opacity);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case LOTTIE_ANIMATION_PROPERTY_STROKEWIDTH: {
 | 
			
		||||
        double width = v[0];
 | 
			
		||||
        if (width < 0) break;
 | 
			
		||||
        animation->mAnimation->setValue<rlottie::Property::StrokeWidth>(keypath, (float)width);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case LOTTIE_ANIMATION_PROPERTY_TR_POSITION: {
 | 
			
		||||
        double x = v[0];
 | 
			
		||||
        double y = v[1];
 | 
			
		||||
        animation->mAnimation->setValue<rlottie::Property::TrPosition>(keypath, rlottie::Point((float)x, (float)y));
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case LOTTIE_ANIMATION_PROPERTY_TR_SCALE: {
 | 
			
		||||
        double w = v[0];
 | 
			
		||||
        double h = v[1];
 | 
			
		||||
        animation->mAnimation->setValue<rlottie::Property::TrScale>(keypath, rlottie::Size((float)w, (float)h));
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case LOTTIE_ANIMATION_PROPERTY_TR_ROTATION: {
 | 
			
		||||
        double r = v[0];
 | 
			
		||||
        animation->mAnimation->setValue<rlottie::Property::TrRotation>(keypath, (float)r);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case LOTTIE_ANIMATION_PROPERTY_TR_ANCHOR:
 | 
			
		||||
    case LOTTIE_ANIMATION_PROPERTY_TR_OPACITY:
 | 
			
		||||
        //@TODO handle propery update.
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API const LOTMarkerList*
 | 
			
		||||
lottie_animation_get_markerlist(Lottie_Animation_S *animation)
 | 
			
		||||
{
 | 
			
		||||
   if (!animation) return nullptr;
 | 
			
		||||
 | 
			
		||||
   auto markers = animation->mAnimation->markers();
 | 
			
		||||
   if (markers.size() == 0) return nullptr;
 | 
			
		||||
   if (animation->mMarkerList) return (const LOTMarkerList*)animation->mMarkerList;
 | 
			
		||||
 | 
			
		||||
   animation->mMarkerList = new LOTMarkerList();
 | 
			
		||||
   animation->mMarkerList->size = markers.size();
 | 
			
		||||
   animation->mMarkerList->ptr = new LOTMarker[markers.size()]();
 | 
			
		||||
 | 
			
		||||
   for(size_t i = 0; i < markers.size(); i++) {
 | 
			
		||||
       animation->mMarkerList->ptr[i].name = strdup(std::get<0>(markers[i]).c_str());
 | 
			
		||||
       animation->mMarkerList->ptr[i].startframe= std::get<1>(markers[i]);
 | 
			
		||||
       animation->mMarkerList->ptr[i].endframe= std::get<2>(markers[i]);
 | 
			
		||||
   }
 | 
			
		||||
   return (const LOTMarkerList*)animation->mMarkerList;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API void
 | 
			
		||||
lottie_configure_model_cache_size(size_t cacheSize)
 | 
			
		||||
{
 | 
			
		||||
   rlottie::configureModelCacheSize(cacheSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								vendor/github.com/Benau/go_rlottie/config.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/Benau/go_rlottie/config.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
#ifndef GO_RLOTTIE_HPP
 | 
			
		||||
#define GO_RLOTTIE_HPP
 | 
			
		||||
#ifndef __APPLE__
 | 
			
		||||
#ifdef __ARM_NEON__
 | 
			
		||||
#define USE_ARM_NEON
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
#define LOTTIE_THREAD_SUPPORT
 | 
			
		||||
#define LOTTIE_CACHE_SUPPORT
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										122
									
								
								vendor/github.com/Benau/go_rlottie/generate_from_rlottie.py
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								vendor/github.com/Benau/go_rlottie/generate_from_rlottie.py
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
			
		||||
#!/usr/bin/python3
 | 
			
		||||
# ./generate_from_rlottie.py /path/to/clean/rlottie/src/ /path/to/clean/rlottie/inc/
 | 
			
		||||
import glob
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
FILE_KEYS = {}
 | 
			
		||||
 | 
			
		||||
def get_closest_local_header(header):
 | 
			
		||||
    for full_path, local in FILE_KEYS.items():
 | 
			
		||||
        if os.path.basename(full_path) == header:
 | 
			
		||||
            return local
 | 
			
		||||
    return ''
 | 
			
		||||
 | 
			
		||||
def fix_headers(code_text):
 | 
			
		||||
    out = ''
 | 
			
		||||
    has_neon = False
 | 
			
		||||
    for line in code_text:
 | 
			
		||||
        # Special fixes
 | 
			
		||||
        if line == '#include <vpoint.h>':
 | 
			
		||||
            line = '#include "vpoint.h"'
 | 
			
		||||
        if line == '#include <vsharedptr.h>':
 | 
			
		||||
            line = '#include "vsharedptr.h"'
 | 
			
		||||
        if line == '#include <vglobal.h>':
 | 
			
		||||
            line = '#include "vglobal.h"'
 | 
			
		||||
        if line == '#include <vrect.h>':
 | 
			
		||||
            line = '#include "vrect.h"'
 | 
			
		||||
        # ARM on apple fixes
 | 
			
		||||
        if '__ARM_NEON__' in line:
 | 
			
		||||
            has_neon = True
 | 
			
		||||
            line = line.replace('__ARM_NEON__', 'USE_ARM_NEON')
 | 
			
		||||
        header_file = re.match('#include\s+["]([^"]+)["].*', line)
 | 
			
		||||
        # regex to search for <, > too
 | 
			
		||||
        #header_file = re.match('#include\s+[<"]([^>"]+)[>"].*', line)
 | 
			
		||||
        if header_file:
 | 
			
		||||
            header = header_file.groups()[0]
 | 
			
		||||
            abs_header = os.path.abspath(header)
 | 
			
		||||
            header_exists = os.path.exists(abs_header)
 | 
			
		||||
            if header_exists and abs_header in FILE_KEYS:
 | 
			
		||||
                out += '#include "' + FILE_KEYS[abs_header] + '"\n'
 | 
			
		||||
            else:
 | 
			
		||||
                local = get_closest_local_header(header)
 | 
			
		||||
                if local != '':
 | 
			
		||||
                    out += '#include "' + local + '"\n'
 | 
			
		||||
                else:
 | 
			
		||||
                    out += line + '\n'
 | 
			
		||||
        else:
 | 
			
		||||
            out += line + '\n'
 | 
			
		||||
    if has_neon:
 | 
			
		||||
        out = '#include "config.h"\n' + out
 | 
			
		||||
    return out
 | 
			
		||||
 | 
			
		||||
if len(sys.argv) < 2:
 | 
			
		||||
    print('usage: ./generate_from_rlottie.py /path/to/clean/rlottie/src/ /path/to/clean/rlottie/inc/')
 | 
			
		||||
    os._exit(1)
 | 
			
		||||
 | 
			
		||||
code = ['.c', '.s', '.S', '.sx', 'cc', 'cpp', 'cpp' ]
 | 
			
		||||
header = ['.h', '.hh', '.hpp', '.hxx' ]
 | 
			
		||||
 | 
			
		||||
# Remove old files
 | 
			
		||||
files = os.listdir('.')
 | 
			
		||||
for file in files:
 | 
			
		||||
    if file.endswith(tuple(code)) or file.endswith(tuple(header)):
 | 
			
		||||
        os.remove(os.path.join('.', file))
 | 
			
		||||
 | 
			
		||||
paths = []
 | 
			
		||||
it = iter(sys.argv)
 | 
			
		||||
next(it, None)
 | 
			
		||||
for argv in it:
 | 
			
		||||
    paths.append(argv)
 | 
			
		||||
 | 
			
		||||
for path in paths:
 | 
			
		||||
    for file in glob.iglob(path + '/**', recursive=True):
 | 
			
		||||
        # Ignore msvc config.h and wasm file
 | 
			
		||||
        if file.endswith('config.h') or 'wasm' in file:
 | 
			
		||||
            continue
 | 
			
		||||
        if file.endswith(tuple(code)) or file.endswith(tuple(header)):
 | 
			
		||||
            key = os.path.abspath(file)
 | 
			
		||||
            val = file.replace(path, '').replace('/', '_')
 | 
			
		||||
            FILE_KEYS[key] = val
 | 
			
		||||
 | 
			
		||||
header_check = []
 | 
			
		||||
for full_path, local in FILE_KEYS.items():
 | 
			
		||||
    header_file = os.path.basename(full_path)
 | 
			
		||||
    if header_file.endswith(tuple(code)):
 | 
			
		||||
        continue
 | 
			
		||||
    if not header_file in header_check:
 | 
			
		||||
        header_check.append(header_file)
 | 
			
		||||
    else:
 | 
			
		||||
        print('WARNING: ' + header_file + ' has multiple reference in subdirectories')
 | 
			
		||||
 | 
			
		||||
cur_dir = os.path.abspath('.')
 | 
			
		||||
for full_path, local in FILE_KEYS.items():
 | 
			
		||||
    os.chdir(os.path.dirname(full_path))
 | 
			
		||||
    with open(full_path) as code:
 | 
			
		||||
        code_text = code.read().splitlines() 
 | 
			
		||||
    code.close()
 | 
			
		||||
    fixed = fix_headers(code_text)
 | 
			
		||||
    os.chdir(cur_dir)
 | 
			
		||||
    local_file = open(local, "w")
 | 
			
		||||
    local_file.write(fixed)
 | 
			
		||||
    local_file.close()
 | 
			
		||||
 | 
			
		||||
# Write config.h
 | 
			
		||||
config = '#ifndef GO_RLOTTIE_HPP\n#define GO_RLOTTIE_HPP\n'
 | 
			
		||||
# ARM on apple won't compile
 | 
			
		||||
config += '#ifndef __APPLE__\n#ifdef __ARM_NEON__\n#define USE_ARM_NEON\n#endif\n#endif\n'
 | 
			
		||||
config += '#define LOTTIE_THREAD_SUPPORT\n#define LOTTIE_CACHE_SUPPORT\n'
 | 
			
		||||
config += '#endif\n'
 | 
			
		||||
config_file = open('config.h', "w")
 | 
			
		||||
config_file.write(config)
 | 
			
		||||
config_file.close()
 | 
			
		||||
 | 
			
		||||
# Fix vector_pixman_pixman-arm-neon-asm.S
 | 
			
		||||
with open('vector_pixman_pixman-arm-neon-asm.S') as code:
 | 
			
		||||
    assembly = code.read()
 | 
			
		||||
code.close()
 | 
			
		||||
assembly = '#include "config.h"\n#ifdef USE_ARM_NEON\n' + assembly + '#endif\n'
 | 
			
		||||
fixed_assembly = open('vector_pixman_pixman-arm-neon-asm.S', "w")
 | 
			
		||||
fixed_assembly.write(assembly)
 | 
			
		||||
fixed_assembly.close()
 | 
			
		||||
							
								
								
									
										56
									
								
								vendor/github.com/Benau/go_rlottie/go_rlottie.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/Benau/go_rlottie/go_rlottie.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
package go_rlottie
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#cgo !windows LDFLAGS: -lm
 | 
			
		||||
#cgo windows CFLAGS: -DRLOTTIE_BUILD=0
 | 
			
		||||
#cgo windows CXXFLAGS: -DRLOTTIE_BUILD=0
 | 
			
		||||
#cgo CXXFLAGS: -std=c++14 -fno-exceptions -fno-asynchronous-unwind-tables -fno-rtti -Wall -fvisibility=hidden -Wnon-virtual-dtor -Woverloaded-virtual -Wno-unused-parameter
 | 
			
		||||
#include "rlottie_capi.h"
 | 
			
		||||
void lottie_configure_model_cache_size(size_t cacheSize);
 | 
			
		||||
*/
 | 
			
		||||
import "C"
 | 
			
		||||
import "unsafe"
 | 
			
		||||
 | 
			
		||||
type Lottie_Animation *C.Lottie_Animation
 | 
			
		||||
 | 
			
		||||
func LottieConfigureModelCacheSize(size uint) {
 | 
			
		||||
	C.lottie_configure_model_cache_size(C.size_t(size))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LottieAnimationFromData(data string, key string, resource_path string) Lottie_Animation {
 | 
			
		||||
	var animation Lottie_Animation
 | 
			
		||||
	animation = C.lottie_animation_from_data(C.CString(data), C.CString(key), C.CString(resource_path))
 | 
			
		||||
	return animation
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LottieAnimationDestroy(animation Lottie_Animation) {
 | 
			
		||||
	C.lottie_animation_destroy(animation)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LottieAnimationGetSize(animation Lottie_Animation) (uint, uint) {
 | 
			
		||||
	var width C.size_t
 | 
			
		||||
	var height C.size_t
 | 
			
		||||
	C.lottie_animation_get_size(animation, &width, &height)
 | 
			
		||||
	return uint(width), uint(height)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LottieAnimationGetTotalframe(animation Lottie_Animation) uint {
 | 
			
		||||
	return uint(C.lottie_animation_get_totalframe(animation))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LottieAnimationGetFramerate(animation Lottie_Animation) float64 {
 | 
			
		||||
	return float64(C.lottie_animation_get_framerate(animation))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LottieAnimationGetFrameAtPos(animation Lottie_Animation, pos float32) uint {
 | 
			
		||||
	return uint(C.lottie_animation_get_frame_at_pos(animation, C.float(pos)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LottieAnimationGetDuration(animation Lottie_Animation) float64 {
 | 
			
		||||
	return float64(C.lottie_animation_get_duration(animation))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LottieAnimationRender(animation Lottie_Animation, frame_num uint, buffer []byte, width uint, height uint, bytes_per_line uint) {
 | 
			
		||||
	var ptr *C.uint32_t = (*C.uint32_t)(unsafe.Pointer(&buffer[0]));
 | 
			
		||||
	C.lottie_animation_render(animation, C.size_t(frame_num), ptr, C.size_t(width), C.size_t(height), C.size_t(bytes_per_line))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										457
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieanimation.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										457
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieanimation.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,457 @@
 | 
			
		||||
#include "config.h"
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "lottie_lottieitem.h"
 | 
			
		||||
#include "lottie_lottiemodel.h"
 | 
			
		||||
#include "rlottie.h"
 | 
			
		||||
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
using namespace rlottie;
 | 
			
		||||
using namespace rlottie::internal;
 | 
			
		||||
 | 
			
		||||
RLOTTIE_API void rlottie::configureModelCacheSize(size_t cacheSize)
 | 
			
		||||
{
 | 
			
		||||
    internal::model::configureModelCacheSize(cacheSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct RenderTask {
 | 
			
		||||
    RenderTask() { receiver = sender.get_future(); }
 | 
			
		||||
    std::promise<Surface> sender;
 | 
			
		||||
    std::future<Surface>  receiver;
 | 
			
		||||
    AnimationImpl *       playerImpl{nullptr};
 | 
			
		||||
    size_t                frameNo{0};
 | 
			
		||||
    Surface               surface;
 | 
			
		||||
    bool                  keepAspectRatio{true};
 | 
			
		||||
};
 | 
			
		||||
using SharedRenderTask = std::shared_ptr<RenderTask>;
 | 
			
		||||
 | 
			
		||||
class AnimationImpl {
 | 
			
		||||
public:
 | 
			
		||||
    void    init(std::shared_ptr<model::Composition> composition);
 | 
			
		||||
    bool    update(size_t frameNo, const VSize &size, bool keepAspectRatio);
 | 
			
		||||
    VSize   size() const { return mModel->size(); }
 | 
			
		||||
    double  duration() const { return mModel->duration(); }
 | 
			
		||||
    double  frameRate() const { return mModel->frameRate(); }
 | 
			
		||||
    size_t  totalFrame() const { return mModel->totalFrame(); }
 | 
			
		||||
    size_t  frameAtPos(double pos) const { return mModel->frameAtPos(pos); }
 | 
			
		||||
    Surface render(size_t frameNo, const Surface &surface,
 | 
			
		||||
                   bool keepAspectRatio);
 | 
			
		||||
    std::future<Surface> renderAsync(size_t frameNo, Surface &&surface,
 | 
			
		||||
                                     bool keepAspectRatio);
 | 
			
		||||
    const LOTLayerNode * renderTree(size_t frameNo, const VSize &size);
 | 
			
		||||
 | 
			
		||||
    const LayerInfoList &layerInfoList() const
 | 
			
		||||
    {
 | 
			
		||||
        if (mLayerList.empty()) {
 | 
			
		||||
            mLayerList = mModel->layerInfoList();
 | 
			
		||||
        }
 | 
			
		||||
        return mLayerList;
 | 
			
		||||
    }
 | 
			
		||||
    const MarkerList &markers() const { return mModel->markers(); }
 | 
			
		||||
    void              setValue(const std::string &keypath, LOTVariant &&value);
 | 
			
		||||
    void              removeFilter(const std::string &keypath, Property prop);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    mutable LayerInfoList                  mLayerList;
 | 
			
		||||
    model::Composition *                   mModel;
 | 
			
		||||
    SharedRenderTask                       mTask;
 | 
			
		||||
    std::atomic<bool>                      mRenderInProgress;
 | 
			
		||||
    std::unique_ptr<renderer::Composition> mRenderer{nullptr};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void AnimationImpl::setValue(const std::string &keypath, LOTVariant &&value)
 | 
			
		||||
{
 | 
			
		||||
    if (keypath.empty()) return;
 | 
			
		||||
    mRenderer->setValue(keypath, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const LOTLayerNode *AnimationImpl::renderTree(size_t frameNo, const VSize &size)
 | 
			
		||||
{
 | 
			
		||||
    if (update(frameNo, size, true)) {
 | 
			
		||||
        mRenderer->buildRenderTree();
 | 
			
		||||
    }
 | 
			
		||||
    return mRenderer->renderTree();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AnimationImpl::update(size_t frameNo, const VSize &size,
 | 
			
		||||
                           bool keepAspectRatio)
 | 
			
		||||
{
 | 
			
		||||
    frameNo += mModel->startFrame();
 | 
			
		||||
 | 
			
		||||
    if (frameNo > mModel->endFrame()) frameNo = mModel->endFrame();
 | 
			
		||||
 | 
			
		||||
    if (frameNo < mModel->startFrame()) frameNo = mModel->startFrame();
 | 
			
		||||
 | 
			
		||||
    return mRenderer->update(int(frameNo), size, keepAspectRatio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Surface AnimationImpl::render(size_t frameNo, const Surface &surface,
 | 
			
		||||
                              bool keepAspectRatio)
 | 
			
		||||
{
 | 
			
		||||
    bool renderInProgress = mRenderInProgress.load();
 | 
			
		||||
    if (renderInProgress) {
 | 
			
		||||
        vCritical << "Already Rendering Scheduled for this Animation";
 | 
			
		||||
        return surface;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mRenderInProgress.store(true);
 | 
			
		||||
    update(
 | 
			
		||||
        frameNo,
 | 
			
		||||
        VSize(int(surface.drawRegionWidth()), int(surface.drawRegionHeight())),
 | 
			
		||||
        keepAspectRatio);
 | 
			
		||||
    mRenderer->render(surface);
 | 
			
		||||
    mRenderInProgress.store(false);
 | 
			
		||||
 | 
			
		||||
    return surface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AnimationImpl::init(std::shared_ptr<model::Composition> composition)
 | 
			
		||||
{
 | 
			
		||||
    mModel = composition.get();
 | 
			
		||||
    mRenderer = std::make_unique<renderer::Composition>(composition);
 | 
			
		||||
    mRenderInProgress = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef LOTTIE_THREAD_SUPPORT
 | 
			
		||||
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include "vector_vtaskqueue.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Implement a task stealing schduler to perform render task
 | 
			
		||||
 * As each player draws into its own buffer we can delegate this
 | 
			
		||||
 * task to a slave thread. The scheduler creates a threadpool depending
 | 
			
		||||
 * on the number of cores available in the system and does a simple fair
 | 
			
		||||
 * scheduling by assigning the task in a round-robin fashion. Each thread
 | 
			
		||||
 * in the threadpool has its own queue. once it finishes all the task on its
 | 
			
		||||
 * own queue it goes through rest of the queue and looks for task if it founds
 | 
			
		||||
 * one it steals the task from it and executes. if it couldn't find one then it
 | 
			
		||||
 * just waits for new task on its own queue.
 | 
			
		||||
 */
 | 
			
		||||
class RenderTaskScheduler {
 | 
			
		||||
    const unsigned           _count{std::thread::hardware_concurrency()};
 | 
			
		||||
    std::vector<std::thread> _threads;
 | 
			
		||||
    std::vector<TaskQueue<SharedRenderTask>> _q{_count};
 | 
			
		||||
    std::atomic<unsigned>                    _index{0};
 | 
			
		||||
 | 
			
		||||
    void run(unsigned i)
 | 
			
		||||
    {
 | 
			
		||||
        while (true) {
 | 
			
		||||
            bool             success = false;
 | 
			
		||||
            SharedRenderTask task;
 | 
			
		||||
            for (unsigned n = 0; n != _count * 2; ++n) {
 | 
			
		||||
                if (_q[(i + n) % _count].try_pop(task)) {
 | 
			
		||||
                    success = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (!success && !_q[i].pop(task)) break;
 | 
			
		||||
 | 
			
		||||
            auto result = task->playerImpl->render(task->frameNo, task->surface,
 | 
			
		||||
                                                   task->keepAspectRatio);
 | 
			
		||||
            task->sender.set_value(result);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    RenderTaskScheduler()
 | 
			
		||||
    {
 | 
			
		||||
        for (unsigned n = 0; n != _count; ++n) {
 | 
			
		||||
            _threads.emplace_back([&, n] { run(n); });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static RenderTaskScheduler &instance()
 | 
			
		||||
    {
 | 
			
		||||
        static RenderTaskScheduler singleton;
 | 
			
		||||
        return singleton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~RenderTaskScheduler()
 | 
			
		||||
    {
 | 
			
		||||
        for (auto &e : _q) e.done();
 | 
			
		||||
 | 
			
		||||
        for (auto &e : _threads) e.join();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::future<Surface> process(SharedRenderTask task)
 | 
			
		||||
    {
 | 
			
		||||
        auto receiver = std::move(task->receiver);
 | 
			
		||||
        auto i = _index++;
 | 
			
		||||
 | 
			
		||||
        for (unsigned n = 0; n != _count; ++n) {
 | 
			
		||||
            if (_q[(i + n) % _count].try_push(std::move(task))) return receiver;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (_count > 0) {
 | 
			
		||||
            _q[i % _count].push(std::move(task));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return receiver;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
class RenderTaskScheduler {
 | 
			
		||||
public:
 | 
			
		||||
    static RenderTaskScheduler &instance()
 | 
			
		||||
    {
 | 
			
		||||
        static RenderTaskScheduler singleton;
 | 
			
		||||
        return singleton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::future<Surface> process(SharedRenderTask task)
 | 
			
		||||
    {
 | 
			
		||||
        auto result = task->playerImpl->render(task->frameNo, task->surface,
 | 
			
		||||
                                               task->keepAspectRatio);
 | 
			
		||||
        task->sender.set_value(result);
 | 
			
		||||
        return std::move(task->receiver);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
std::future<Surface> AnimationImpl::renderAsync(size_t    frameNo,
 | 
			
		||||
                                                Surface &&surface,
 | 
			
		||||
                                                bool      keepAspectRatio)
 | 
			
		||||
{
 | 
			
		||||
    if (!mTask) {
 | 
			
		||||
        mTask = std::make_shared<RenderTask>();
 | 
			
		||||
    } else {
 | 
			
		||||
        mTask->sender = std::promise<Surface>();
 | 
			
		||||
        mTask->receiver = mTask->sender.get_future();
 | 
			
		||||
    }
 | 
			
		||||
    mTask->playerImpl = this;
 | 
			
		||||
    mTask->frameNo = frameNo;
 | 
			
		||||
    mTask->surface = std::move(surface);
 | 
			
		||||
    mTask->keepAspectRatio = keepAspectRatio;
 | 
			
		||||
 | 
			
		||||
    return RenderTaskScheduler::instance().process(mTask);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \breif Brief abput the Api.
 | 
			
		||||
 * Description about the setFilePath Api
 | 
			
		||||
 * @param path  add the details
 | 
			
		||||
 */
 | 
			
		||||
std::unique_ptr<Animation> Animation::loadFromData(
 | 
			
		||||
    std::string jsonData, const std::string &key,
 | 
			
		||||
    const std::string &resourcePath, bool cachePolicy)
 | 
			
		||||
{
 | 
			
		||||
    if (jsonData.empty()) {
 | 
			
		||||
        vWarning << "jason data is empty";
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto composition = model::loadFromData(std::move(jsonData), key,
 | 
			
		||||
                                           resourcePath, cachePolicy);
 | 
			
		||||
    if (composition) {
 | 
			
		||||
        auto animation = std::unique_ptr<Animation>(new Animation);
 | 
			
		||||
        animation->d->init(std::move(composition));
 | 
			
		||||
        return animation;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<Animation> Animation::loadFromData(std::string jsonData,
 | 
			
		||||
                                                   std::string resourcePath,
 | 
			
		||||
                                                   ColorFilter filter)
 | 
			
		||||
{
 | 
			
		||||
    if (jsonData.empty()) {
 | 
			
		||||
        vWarning << "jason data is empty";
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto composition = model::loadFromData(
 | 
			
		||||
        std::move(jsonData), std::move(resourcePath), std::move(filter));
 | 
			
		||||
    if (composition) {
 | 
			
		||||
        auto animation = std::unique_ptr<Animation>(new Animation);
 | 
			
		||||
        animation->d->init(std::move(composition));
 | 
			
		||||
        return animation;
 | 
			
		||||
    }
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<Animation> Animation::loadFromFile(const std::string &path,
 | 
			
		||||
                                                   bool cachePolicy)
 | 
			
		||||
{
 | 
			
		||||
    if (path.empty()) {
 | 
			
		||||
        vWarning << "File path is empty";
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto composition = model::loadFromFile(path, cachePolicy);
 | 
			
		||||
    if (composition) {
 | 
			
		||||
        auto animation = std::unique_ptr<Animation>(new Animation);
 | 
			
		||||
        animation->d->init(std::move(composition));
 | 
			
		||||
        return animation;
 | 
			
		||||
    }
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animation::size(size_t &width, size_t &height) const
 | 
			
		||||
{
 | 
			
		||||
    VSize sz = d->size();
 | 
			
		||||
 | 
			
		||||
    width = sz.width();
 | 
			
		||||
    height = sz.height();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double Animation::duration() const
 | 
			
		||||
{
 | 
			
		||||
    return d->duration();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double Animation::frameRate() const
 | 
			
		||||
{
 | 
			
		||||
    return d->frameRate();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t Animation::totalFrame() const
 | 
			
		||||
{
 | 
			
		||||
    return d->totalFrame();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t Animation::frameAtPos(double pos)
 | 
			
		||||
{
 | 
			
		||||
    return d->frameAtPos(pos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const LOTLayerNode *Animation::renderTree(size_t frameNo, size_t width,
 | 
			
		||||
                                          size_t height) const
 | 
			
		||||
{
 | 
			
		||||
    return d->renderTree(frameNo, VSize(int(width), int(height)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::future<Surface> Animation::render(size_t frameNo, Surface surface,
 | 
			
		||||
                                       bool keepAspectRatio)
 | 
			
		||||
{
 | 
			
		||||
    return d->renderAsync(frameNo, std::move(surface), keepAspectRatio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animation::renderSync(size_t frameNo, Surface surface,
 | 
			
		||||
                           bool keepAspectRatio)
 | 
			
		||||
{
 | 
			
		||||
    d->render(frameNo, surface, keepAspectRatio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const LayerInfoList &Animation::layers() const
 | 
			
		||||
{
 | 
			
		||||
    return d->layerInfoList();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MarkerList &Animation::markers() const
 | 
			
		||||
{
 | 
			
		||||
    return d->markers();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animation::setValue(Color_Type, Property prop, const std::string &keypath,
 | 
			
		||||
                         Color value)
 | 
			
		||||
{
 | 
			
		||||
    d->setValue(keypath,
 | 
			
		||||
                LOTVariant(prop, [value](const FrameInfo &) { return value; }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animation::setValue(Float_Type, Property prop, const std::string &keypath,
 | 
			
		||||
                         float value)
 | 
			
		||||
{
 | 
			
		||||
    d->setValue(keypath,
 | 
			
		||||
                LOTVariant(prop, [value](const FrameInfo &) { return value; }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animation::setValue(Size_Type, Property prop, const std::string &keypath,
 | 
			
		||||
                         Size value)
 | 
			
		||||
{
 | 
			
		||||
    d->setValue(keypath,
 | 
			
		||||
                LOTVariant(prop, [value](const FrameInfo &) { return value; }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animation::setValue(Point_Type, Property prop, const std::string &keypath,
 | 
			
		||||
                         Point value)
 | 
			
		||||
{
 | 
			
		||||
    d->setValue(keypath,
 | 
			
		||||
                LOTVariant(prop, [value](const FrameInfo &) { return value; }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animation::setValue(Color_Type, Property prop, const std::string &keypath,
 | 
			
		||||
                         std::function<Color(const FrameInfo &)> &&value)
 | 
			
		||||
{
 | 
			
		||||
    d->setValue(keypath, LOTVariant(prop, value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animation::setValue(Float_Type, Property prop, const std::string &keypath,
 | 
			
		||||
                         std::function<float(const FrameInfo &)> &&value)
 | 
			
		||||
{
 | 
			
		||||
    d->setValue(keypath, LOTVariant(prop, value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animation::setValue(Size_Type, Property prop, const std::string &keypath,
 | 
			
		||||
                         std::function<Size(const FrameInfo &)> &&value)
 | 
			
		||||
{
 | 
			
		||||
    d->setValue(keypath, LOTVariant(prop, value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animation::setValue(Point_Type, Property prop, const std::string &keypath,
 | 
			
		||||
                         std::function<Point(const FrameInfo &)> &&value)
 | 
			
		||||
{
 | 
			
		||||
    d->setValue(keypath, LOTVariant(prop, value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Animation::~Animation() = default;
 | 
			
		||||
Animation::Animation() : d(std::make_unique<AnimationImpl>()) {}
 | 
			
		||||
 | 
			
		||||
Surface::Surface(uint32_t *buffer, size_t width, size_t height,
 | 
			
		||||
                 size_t bytesPerLine)
 | 
			
		||||
    : mBuffer(buffer),
 | 
			
		||||
      mWidth(width),
 | 
			
		||||
      mHeight(height),
 | 
			
		||||
      mBytesPerLine(bytesPerLine)
 | 
			
		||||
{
 | 
			
		||||
    mDrawArea.w = mWidth;
 | 
			
		||||
    mDrawArea.h = mHeight;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Surface::setDrawRegion(size_t x, size_t y, size_t width, size_t height)
 | 
			
		||||
{
 | 
			
		||||
    if ((x + width > mWidth) || (y + height > mHeight)) return;
 | 
			
		||||
 | 
			
		||||
    mDrawArea.x = x;
 | 
			
		||||
    mDrawArea.y = y;
 | 
			
		||||
    mDrawArea.w = width;
 | 
			
		||||
    mDrawArea.h = height;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef LOTTIE_LOGGING_SUPPORT
 | 
			
		||||
void initLogging()
 | 
			
		||||
{
 | 
			
		||||
#if defined(USE_ARM_NEON)
 | 
			
		||||
    set_log_level(LogLevel::OFF);
 | 
			
		||||
#else
 | 
			
		||||
    initialize(GuaranteedLogger(), "/tmp/", "rlottie", 1);
 | 
			
		||||
    set_log_level(LogLevel::INFO);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
V_CONSTRUCTOR_FUNCTION(initLogging)
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										435
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottiefiltermodel.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										435
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottiefiltermodel.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,435 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LOTTIEFILTERMODEL_H
 | 
			
		||||
#define LOTTIEFILTERMODEL_H
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include "lottie_lottiemodel.h"
 | 
			
		||||
#include "rlottie.h"
 | 
			
		||||
 | 
			
		||||
using namespace rlottie::internal;
 | 
			
		||||
// Naive way to implement std::variant
 | 
			
		||||
// refactor it when we move to c++17
 | 
			
		||||
// users should make sure proper combination
 | 
			
		||||
// of id and value are passed while creating the object.
 | 
			
		||||
class LOTVariant {
 | 
			
		||||
public:
 | 
			
		||||
    using ValueFunc = std::function<float(const rlottie::FrameInfo&)>;
 | 
			
		||||
    using ColorFunc = std::function<rlottie::Color(const rlottie::FrameInfo&)>;
 | 
			
		||||
    using PointFunc = std::function<rlottie::Point(const rlottie::FrameInfo&)>;
 | 
			
		||||
    using SizeFunc = std::function<rlottie::Size(const rlottie::FrameInfo&)>;
 | 
			
		||||
 | 
			
		||||
    LOTVariant(rlottie::Property prop, const ValueFunc& v)
 | 
			
		||||
        : mPropery(prop), mTag(Value)
 | 
			
		||||
    {
 | 
			
		||||
        construct(impl.valueFunc, v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOTVariant(rlottie::Property prop, ValueFunc&& v)
 | 
			
		||||
        : mPropery(prop), mTag(Value)
 | 
			
		||||
    {
 | 
			
		||||
        moveConstruct(impl.valueFunc, std::move(v));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOTVariant(rlottie::Property prop, const ColorFunc& v)
 | 
			
		||||
        : mPropery(prop), mTag(Color)
 | 
			
		||||
    {
 | 
			
		||||
        construct(impl.colorFunc, v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOTVariant(rlottie::Property prop, ColorFunc&& v)
 | 
			
		||||
        : mPropery(prop), mTag(Color)
 | 
			
		||||
    {
 | 
			
		||||
        moveConstruct(impl.colorFunc, std::move(v));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOTVariant(rlottie::Property prop, const PointFunc& v)
 | 
			
		||||
        : mPropery(prop), mTag(Point)
 | 
			
		||||
    {
 | 
			
		||||
        construct(impl.pointFunc, v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOTVariant(rlottie::Property prop, PointFunc&& v)
 | 
			
		||||
        : mPropery(prop), mTag(Point)
 | 
			
		||||
    {
 | 
			
		||||
        moveConstruct(impl.pointFunc, std::move(v));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOTVariant(rlottie::Property prop, const SizeFunc& v)
 | 
			
		||||
        : mPropery(prop), mTag(Size)
 | 
			
		||||
    {
 | 
			
		||||
        construct(impl.sizeFunc, v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOTVariant(rlottie::Property prop, SizeFunc&& v)
 | 
			
		||||
        : mPropery(prop), mTag(Size)
 | 
			
		||||
    {
 | 
			
		||||
        moveConstruct(impl.sizeFunc, std::move(v));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rlottie::Property property() const { return mPropery; }
 | 
			
		||||
 | 
			
		||||
    const ColorFunc& color() const
 | 
			
		||||
    {
 | 
			
		||||
        assert(mTag == Color);
 | 
			
		||||
        return impl.colorFunc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const ValueFunc& value() const
 | 
			
		||||
    {
 | 
			
		||||
        assert(mTag == Value);
 | 
			
		||||
        return impl.valueFunc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const PointFunc& point() const
 | 
			
		||||
    {
 | 
			
		||||
        assert(mTag == Point);
 | 
			
		||||
        return impl.pointFunc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const SizeFunc& size() const
 | 
			
		||||
    {
 | 
			
		||||
        assert(mTag == Size);
 | 
			
		||||
        return impl.sizeFunc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOTVariant() = default;
 | 
			
		||||
    ~LOTVariant() noexcept { Destroy(); }
 | 
			
		||||
    LOTVariant(const LOTVariant& other) { Copy(other); }
 | 
			
		||||
    LOTVariant(LOTVariant&& other) noexcept { Move(std::move(other)); }
 | 
			
		||||
    LOTVariant& operator=(LOTVariant&& other)
 | 
			
		||||
    {
 | 
			
		||||
        Destroy();
 | 
			
		||||
        Move(std::move(other));
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    LOTVariant& operator=(const LOTVariant& other)
 | 
			
		||||
    {
 | 
			
		||||
        Destroy();
 | 
			
		||||
        Copy(other);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void construct(T& member, const T& val)
 | 
			
		||||
    {
 | 
			
		||||
        new (&member) T(val);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void moveConstruct(T& member, T&& val)
 | 
			
		||||
    {
 | 
			
		||||
        new (&member) T(std::move(val));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Move(LOTVariant&& other)
 | 
			
		||||
    {
 | 
			
		||||
        switch (other.mTag) {
 | 
			
		||||
        case Type::Value:
 | 
			
		||||
            moveConstruct(impl.valueFunc, std::move(other.impl.valueFunc));
 | 
			
		||||
            break;
 | 
			
		||||
        case Type::Color:
 | 
			
		||||
            moveConstruct(impl.colorFunc, std::move(other.impl.colorFunc));
 | 
			
		||||
            break;
 | 
			
		||||
        case Type::Point:
 | 
			
		||||
            moveConstruct(impl.pointFunc, std::move(other.impl.pointFunc));
 | 
			
		||||
            break;
 | 
			
		||||
        case Type::Size:
 | 
			
		||||
            moveConstruct(impl.sizeFunc, std::move(other.impl.sizeFunc));
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        mTag = other.mTag;
 | 
			
		||||
        mPropery = other.mPropery;
 | 
			
		||||
        other.mTag = MonoState;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Copy(const LOTVariant& other)
 | 
			
		||||
    {
 | 
			
		||||
        switch (other.mTag) {
 | 
			
		||||
        case Type::Value:
 | 
			
		||||
            construct(impl.valueFunc, other.impl.valueFunc);
 | 
			
		||||
            break;
 | 
			
		||||
        case Type::Color:
 | 
			
		||||
            construct(impl.colorFunc, other.impl.colorFunc);
 | 
			
		||||
            break;
 | 
			
		||||
        case Type::Point:
 | 
			
		||||
            construct(impl.pointFunc, other.impl.pointFunc);
 | 
			
		||||
            break;
 | 
			
		||||
        case Type::Size:
 | 
			
		||||
            construct(impl.sizeFunc, other.impl.sizeFunc);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        mTag = other.mTag;
 | 
			
		||||
        mPropery = other.mPropery;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Destroy()
 | 
			
		||||
    {
 | 
			
		||||
        switch (mTag) {
 | 
			
		||||
        case MonoState: {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case Value: {
 | 
			
		||||
            impl.valueFunc.~ValueFunc();
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case Color: {
 | 
			
		||||
            impl.colorFunc.~ColorFunc();
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case Point: {
 | 
			
		||||
            impl.pointFunc.~PointFunc();
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case Size: {
 | 
			
		||||
            impl.sizeFunc.~SizeFunc();
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum Type { MonoState, Value, Color, Point, Size };
 | 
			
		||||
    rlottie::Property mPropery;
 | 
			
		||||
    Type              mTag{MonoState};
 | 
			
		||||
    union details {
 | 
			
		||||
        ColorFunc colorFunc;
 | 
			
		||||
        ValueFunc valueFunc;
 | 
			
		||||
        PointFunc pointFunc;
 | 
			
		||||
        SizeFunc  sizeFunc;
 | 
			
		||||
        details() {}
 | 
			
		||||
        ~details() noexcept {}
 | 
			
		||||
    } impl;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace rlottie {
 | 
			
		||||
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
namespace model {
 | 
			
		||||
 | 
			
		||||
class FilterData {
 | 
			
		||||
public:
 | 
			
		||||
    void addValue(LOTVariant& value)
 | 
			
		||||
    {
 | 
			
		||||
        uint index = static_cast<uint>(value.property());
 | 
			
		||||
        if (mBitset.test(index)) {
 | 
			
		||||
            std::replace_if(mFilters.begin(), mFilters.end(),
 | 
			
		||||
                            [&value](const LOTVariant& e) {
 | 
			
		||||
                                return e.property() == value.property();
 | 
			
		||||
                            },
 | 
			
		||||
                            value);
 | 
			
		||||
        } else {
 | 
			
		||||
            mBitset.set(index);
 | 
			
		||||
            mFilters.push_back(value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void removeValue(LOTVariant& value)
 | 
			
		||||
    {
 | 
			
		||||
        uint index = static_cast<uint>(value.property());
 | 
			
		||||
        if (mBitset.test(index)) {
 | 
			
		||||
            mBitset.reset(index);
 | 
			
		||||
            mFilters.erase(std::remove_if(mFilters.begin(), mFilters.end(),
 | 
			
		||||
                                          [&value](const LOTVariant& e) {
 | 
			
		||||
                                              return e.property() ==
 | 
			
		||||
                                                     value.property();
 | 
			
		||||
                                          }),
 | 
			
		||||
                           mFilters.end());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    bool hasFilter(rlottie::Property prop) const
 | 
			
		||||
    {
 | 
			
		||||
        return mBitset.test(static_cast<uint>(prop));
 | 
			
		||||
    }
 | 
			
		||||
    model::Color color(rlottie::Property prop, int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        rlottie::FrameInfo info(frame);
 | 
			
		||||
        rlottie::Color     col = data(prop).color()(info);
 | 
			
		||||
        return model::Color(col.r(), col.g(), col.b());
 | 
			
		||||
    }
 | 
			
		||||
    VPointF point(rlottie::Property prop, int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        rlottie::FrameInfo info(frame);
 | 
			
		||||
        rlottie::Point     pt = data(prop).point()(info);
 | 
			
		||||
        return VPointF(pt.x(), pt.y());
 | 
			
		||||
    }
 | 
			
		||||
    VSize scale(rlottie::Property prop, int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        rlottie::FrameInfo info(frame);
 | 
			
		||||
        rlottie::Size      sz = data(prop).size()(info);
 | 
			
		||||
        return VSize(sz.w(), sz.h());
 | 
			
		||||
    }
 | 
			
		||||
    float opacity(rlottie::Property prop, int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        rlottie::FrameInfo info(frame);
 | 
			
		||||
        float              val = data(prop).value()(info);
 | 
			
		||||
        return val / 100;
 | 
			
		||||
    }
 | 
			
		||||
    float value(rlottie::Property prop, int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        rlottie::FrameInfo info(frame);
 | 
			
		||||
        return data(prop).value()(info);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    const LOTVariant& data(rlottie::Property prop) const
 | 
			
		||||
    {
 | 
			
		||||
        auto result = std::find_if(
 | 
			
		||||
            mFilters.begin(), mFilters.end(),
 | 
			
		||||
            [prop](const LOTVariant& e) { return e.property() == prop; });
 | 
			
		||||
        return *result;
 | 
			
		||||
    }
 | 
			
		||||
    std::bitset<32>         mBitset{0};
 | 
			
		||||
    std::vector<LOTVariant> mFilters;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct FilterBase
 | 
			
		||||
{
 | 
			
		||||
    FilterBase(T *model): model_(model){}
 | 
			
		||||
 | 
			
		||||
    const char*  name() const { return model_->name(); }
 | 
			
		||||
 | 
			
		||||
    FilterData* filter() {
 | 
			
		||||
        if (!filterData_) filterData_ = std::make_unique<FilterData>();
 | 
			
		||||
        return filterData_.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const FilterData * filter() const { return filterData_.get(); }
 | 
			
		||||
    const T* model() const { return model_;}
 | 
			
		||||
 | 
			
		||||
    bool hasFilter(rlottie::Property prop) const {
 | 
			
		||||
        return filterData_ ? filterData_->hasFilter(prop)
 | 
			
		||||
                         : false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    T*                           model_{nullptr};
 | 
			
		||||
    std::unique_ptr<FilterData>  filterData_{nullptr};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
class Filter : public FilterBase<T> {
 | 
			
		||||
public:
 | 
			
		||||
    Filter(T* model): FilterBase<T>(model){}
 | 
			
		||||
    model::Color color(int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        if (this->hasFilter(rlottie::Property::StrokeColor)) {
 | 
			
		||||
            return this->filter()->color(rlottie::Property::StrokeColor, frame);
 | 
			
		||||
        }
 | 
			
		||||
        return this->model()->color(frame);
 | 
			
		||||
    }
 | 
			
		||||
    float opacity(int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        if (this->hasFilter(rlottie::Property::StrokeOpacity)) {
 | 
			
		||||
            return this->filter()->opacity(rlottie::Property::StrokeOpacity, frame);
 | 
			
		||||
        }
 | 
			
		||||
        return this->model()->opacity(frame);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float strokeWidth(int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        if (this->hasFilter(rlottie::Property::StrokeWidth)) {
 | 
			
		||||
            return this->filter()->value(rlottie::Property::StrokeWidth, frame);
 | 
			
		||||
        }
 | 
			
		||||
        return this->model()->strokeWidth(frame);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float     miterLimit() const { return this->model()->miterLimit(); }
 | 
			
		||||
    CapStyle  capStyle() const { return this->model()->capStyle(); }
 | 
			
		||||
    JoinStyle joinStyle() const { return this->model()->joinStyle(); }
 | 
			
		||||
    bool      hasDashInfo() const { return this->model()->hasDashInfo(); }
 | 
			
		||||
    void      getDashInfo(int frameNo, std::vector<float>& result) const
 | 
			
		||||
    {
 | 
			
		||||
        return this->model()->getDashInfo(frameNo, result);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
class Filter<model::Fill>: public FilterBase<model::Fill>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Filter(model::Fill* model) : FilterBase<model::Fill>(model) {}
 | 
			
		||||
 | 
			
		||||
    model::Color color(int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        if (this->hasFilter(rlottie::Property::FillColor)) {
 | 
			
		||||
            return this->filter()->color(rlottie::Property::FillColor, frame);
 | 
			
		||||
        }
 | 
			
		||||
        return this->model()->color(frame);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float opacity(int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        if (this->hasFilter(rlottie::Property::FillOpacity)) {
 | 
			
		||||
            return this->filter()->opacity(rlottie::Property::FillOpacity, frame);
 | 
			
		||||
        }
 | 
			
		||||
        return this->model()->opacity(frame);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    FillRule fillRule() const { return this->model()->fillRule(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
class Filter<model::Group> : public FilterBase<model::Group>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Filter(model::Group* model = nullptr) : FilterBase<model::Group>(model) {}
 | 
			
		||||
 | 
			
		||||
    bool   hasModel() const { return this->model() ? true : false; }
 | 
			
		||||
 | 
			
		||||
    model::Transform* transform() const { return this->model() ? this->model()->mTransform : nullptr; }
 | 
			
		||||
    VMatrix           matrix(int frame) const
 | 
			
		||||
    {
 | 
			
		||||
        VMatrix mS, mR, mT;
 | 
			
		||||
        if (this->hasFilter(rlottie::Property::TrScale)) {
 | 
			
		||||
            VSize s = this->filter()->scale(rlottie::Property::TrScale, frame);
 | 
			
		||||
            mS.scale(s.width() / 100.0, s.height() / 100.0);
 | 
			
		||||
        }
 | 
			
		||||
        if (this->hasFilter(rlottie::Property::TrRotation)) {
 | 
			
		||||
            mR.rotate(this->filter()->value(rlottie::Property::TrRotation, frame));
 | 
			
		||||
        }
 | 
			
		||||
        if (this->hasFilter(rlottie::Property::TrPosition)) {
 | 
			
		||||
            mT.translate(this->filter()->point(rlottie::Property::TrPosition, frame));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this->model()->mTransform->matrix(frame) * mS * mR * mT;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}  // namespace model
 | 
			
		||||
 | 
			
		||||
}  // namespace internal
 | 
			
		||||
 | 
			
		||||
}  // namespace rlottie
 | 
			
		||||
 | 
			
		||||
#endif  // LOTTIEFILTERMODEL_H
 | 
			
		||||
							
								
								
									
										1491
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieitem.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1491
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieitem.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										626
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieitem.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										626
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieitem.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,626 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LOTTIEITEM_H
 | 
			
		||||
#define LOTTIEITEM_H
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
#include "lottie_lottiekeypath.h"
 | 
			
		||||
#include "lottie_lottiefiltermodel.h"
 | 
			
		||||
#include "rlottie.h"
 | 
			
		||||
#include "rlottiecommon.h"
 | 
			
		||||
#include "vector_varenaalloc.h"
 | 
			
		||||
#include "vector_vdrawable.h"
 | 
			
		||||
#include "vector_vmatrix.h"
 | 
			
		||||
#include "vector_vpainter.h"
 | 
			
		||||
#include "vector_vpath.h"
 | 
			
		||||
#include "vector_vpathmesure.h"
 | 
			
		||||
#include "vector_vpoint.h"
 | 
			
		||||
 | 
			
		||||
V_USE_NAMESPACE
 | 
			
		||||
 | 
			
		||||
namespace rlottie {
 | 
			
		||||
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
class VSpan {
 | 
			
		||||
public:
 | 
			
		||||
    using reference = T &;
 | 
			
		||||
    using pointer = T *;
 | 
			
		||||
    using const_pointer = T const *;
 | 
			
		||||
    using const_reference = T const &;
 | 
			
		||||
    using index_type = size_t;
 | 
			
		||||
 | 
			
		||||
    using iterator = pointer;
 | 
			
		||||
    using const_iterator = const_pointer;
 | 
			
		||||
 | 
			
		||||
    VSpan() = default;
 | 
			
		||||
    VSpan(pointer data, index_type size) : _data(data), _size(size) {}
 | 
			
		||||
 | 
			
		||||
    constexpr pointer        data() const noexcept { return _data; }
 | 
			
		||||
    constexpr index_type     size() const noexcept { return _size; }
 | 
			
		||||
    constexpr bool           empty() const noexcept { return size() == 0; }
 | 
			
		||||
    constexpr iterator       begin() const noexcept { return data(); }
 | 
			
		||||
    constexpr iterator       end() const noexcept { return data() + size(); }
 | 
			
		||||
    constexpr const_iterator cbegin() const noexcept { return data(); }
 | 
			
		||||
    constexpr const_iterator cend() const noexcept { return data() + size(); }
 | 
			
		||||
    constexpr reference      operator[](index_type idx) const
 | 
			
		||||
    {
 | 
			
		||||
        return *(data() + idx);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    pointer    _data{nullptr};
 | 
			
		||||
    index_type _size{0};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace renderer {
 | 
			
		||||
 | 
			
		||||
using DrawableList = VSpan<VDrawable *>;
 | 
			
		||||
 | 
			
		||||
enum class DirtyFlagBit : uchar {
 | 
			
		||||
    None = 0x00,
 | 
			
		||||
    Matrix = 0x01,
 | 
			
		||||
    Alpha = 0x02,
 | 
			
		||||
    All = (Matrix | Alpha)
 | 
			
		||||
};
 | 
			
		||||
typedef vFlag<DirtyFlagBit> DirtyFlag;
 | 
			
		||||
 | 
			
		||||
class SurfaceCache {
 | 
			
		||||
public:
 | 
			
		||||
    SurfaceCache() { mCache.reserve(10); }
 | 
			
		||||
 | 
			
		||||
    VBitmap make_surface(
 | 
			
		||||
        size_t width, size_t height,
 | 
			
		||||
        VBitmap::Format format = VBitmap::Format::ARGB32_Premultiplied)
 | 
			
		||||
    {
 | 
			
		||||
        if (mCache.empty()) return {width, height, format};
 | 
			
		||||
 | 
			
		||||
        auto surface = mCache.back();
 | 
			
		||||
        surface.reset(width, height, format);
 | 
			
		||||
 | 
			
		||||
        mCache.pop_back();
 | 
			
		||||
        return surface;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void release_surface(VBitmap &surface) { mCache.push_back(surface); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::vector<VBitmap> mCache;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Drawable final : public VDrawable {
 | 
			
		||||
public:
 | 
			
		||||
    void sync();
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    std::unique_ptr<LOTNode> mCNode{nullptr};
 | 
			
		||||
 | 
			
		||||
    ~Drawable() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (mCNode && mCNode->mGradient.stopPtr)
 | 
			
		||||
            free(mCNode->mGradient.stopPtr);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct CApiData {
 | 
			
		||||
    CApiData();
 | 
			
		||||
    LOTLayerNode                mLayer;
 | 
			
		||||
    std::vector<LOTMask>        mMasks;
 | 
			
		||||
    std::vector<LOTLayerNode *> mLayers;
 | 
			
		||||
    std::vector<LOTNode *>      mCNodeList;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Clipper {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Clipper(VSize size) : mSize(size) {}
 | 
			
		||||
    void update(const VMatrix &matrix);
 | 
			
		||||
    void preprocess(const VRect &clip);
 | 
			
		||||
    VRle rle(const VRle &mask);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    VSize       mSize;
 | 
			
		||||
    VPath       mPath;
 | 
			
		||||
    VRle        mMaskedRle;
 | 
			
		||||
    VRasterizer mRasterizer;
 | 
			
		||||
    bool        mRasterRequest{false};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Mask {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Mask(model::Mask *data) : mData(data) {}
 | 
			
		||||
    void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
 | 
			
		||||
                const DirtyFlag &flag);
 | 
			
		||||
    model::Mask::Mode maskMode() const { return mData->mMode; }
 | 
			
		||||
    VRle              rle();
 | 
			
		||||
    void              preprocess(const VRect &clip);
 | 
			
		||||
    bool              inverted() const { return mData->mInv; }
 | 
			
		||||
public:
 | 
			
		||||
    model::Mask *mData{nullptr};
 | 
			
		||||
    VPath        mLocalPath;
 | 
			
		||||
    VPath        mFinalPath;
 | 
			
		||||
    VRasterizer  mRasterizer;
 | 
			
		||||
    float        mCombinedAlpha{0};
 | 
			
		||||
    bool         mRasterRequest{false};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Handels mask property of a layer item
 | 
			
		||||
 */
 | 
			
		||||
class LayerMask {
 | 
			
		||||
public:
 | 
			
		||||
    explicit LayerMask(model::Layer *layerData);
 | 
			
		||||
    void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
 | 
			
		||||
                const DirtyFlag &flag);
 | 
			
		||||
    bool isStatic() const { return mStatic; }
 | 
			
		||||
    VRle maskRle(const VRect &clipRect);
 | 
			
		||||
    void preprocess(const VRect &clip);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    std::vector<Mask> mMasks;
 | 
			
		||||
    VRle              mRle;
 | 
			
		||||
    bool              mStatic{true};
 | 
			
		||||
    bool              mDirty{true};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Layer;
 | 
			
		||||
 | 
			
		||||
class Composition {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Composition(std::shared_ptr<model::Composition> composition);
 | 
			
		||||
    bool  update(int frameNo, const VSize &size, bool keepAspectRatio);
 | 
			
		||||
    VSize size() const { return mViewSize; }
 | 
			
		||||
    void  buildRenderTree();
 | 
			
		||||
    const LOTLayerNode *renderTree() const;
 | 
			
		||||
    bool                render(const rlottie::Surface &surface);
 | 
			
		||||
    void                setValue(const std::string &keypath, LOTVariant &value);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    SurfaceCache                        mSurfaceCache;
 | 
			
		||||
    VBitmap                             mSurface;
 | 
			
		||||
    VMatrix                             mScaleMatrix;
 | 
			
		||||
    VSize                               mViewSize;
 | 
			
		||||
    std::shared_ptr<model::Composition> mModel;
 | 
			
		||||
    Layer *                             mRootLayer{nullptr};
 | 
			
		||||
    VArenaAlloc                         mAllocator{2048};
 | 
			
		||||
    int                                 mCurFrameNo;
 | 
			
		||||
    bool                                mKeepAspectRatio{true};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Layer {
 | 
			
		||||
public:
 | 
			
		||||
    virtual ~Layer() = default;
 | 
			
		||||
    Layer &operator=(Layer &&) noexcept = delete;
 | 
			
		||||
    Layer(model::Layer *layerData);
 | 
			
		||||
    int          id() const { return mLayerData->id(); }
 | 
			
		||||
    int          parentId() const { return mLayerData->parentId(); }
 | 
			
		||||
    void         setParentLayer(Layer *parent) { mParentLayer = parent; }
 | 
			
		||||
    void         setComplexContent(bool value) { mComplexContent = value; }
 | 
			
		||||
    bool         complexContent() const { return mComplexContent; }
 | 
			
		||||
    virtual void update(int frameNo, const VMatrix &parentMatrix,
 | 
			
		||||
                        float parentAlpha);
 | 
			
		||||
    VMatrix      matrix(int frameNo) const;
 | 
			
		||||
    void         preprocess(const VRect &clip);
 | 
			
		||||
    virtual DrawableList renderList() { return {}; }
 | 
			
		||||
    virtual void         render(VPainter *painter, const VRle &mask,
 | 
			
		||||
                                const VRle &matteRle, SurfaceCache &cache);
 | 
			
		||||
    bool                 hasMatte()
 | 
			
		||||
    {
 | 
			
		||||
        if (mLayerData->mMatteType == model::MatteType::None) return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    model::MatteType matteType() const { return mLayerData->mMatteType; }
 | 
			
		||||
    bool             visible() const;
 | 
			
		||||
    virtual void     buildLayerNode();
 | 
			
		||||
    LOTLayerNode &   clayer() { return mCApiData->mLayer; }
 | 
			
		||||
    std::vector<LOTLayerNode *> &clayers() { return mCApiData->mLayers; }
 | 
			
		||||
    std::vector<LOTMask> &       cmasks() { return mCApiData->mMasks; }
 | 
			
		||||
    std::vector<LOTNode *> &     cnodes() { return mCApiData->mCNodeList; }
 | 
			
		||||
    const char *                 name() const { return mLayerData->name(); }
 | 
			
		||||
    virtual bool                 resolveKeyPath(LOTKeyPath &keyPath, uint depth,
 | 
			
		||||
                                                LOTVariant &value);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    virtual void   preprocessStage(const VRect &clip) = 0;
 | 
			
		||||
    virtual void   updateContent() = 0;
 | 
			
		||||
    inline VMatrix combinedMatrix() const { return mCombinedMatrix; }
 | 
			
		||||
    inline int     frameNo() const { return mFrameNo; }
 | 
			
		||||
    inline float   combinedAlpha() const { return mCombinedAlpha; }
 | 
			
		||||
    inline bool    isStatic() const { return mLayerData->isStatic(); }
 | 
			
		||||
    float opacity(int frameNo) const { return mLayerData->opacity(frameNo); }
 | 
			
		||||
    inline DirtyFlag flag() const { return mDirtyFlag; }
 | 
			
		||||
    bool             skipRendering() const
 | 
			
		||||
    {
 | 
			
		||||
        return (!visible() || vIsZero(combinedAlpha()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    std::unique_ptr<LayerMask> mLayerMask;
 | 
			
		||||
    model::Layer *             mLayerData{nullptr};
 | 
			
		||||
    Layer *                    mParentLayer{nullptr};
 | 
			
		||||
    VMatrix                    mCombinedMatrix;
 | 
			
		||||
    float                      mCombinedAlpha{0.0};
 | 
			
		||||
    int                        mFrameNo{-1};
 | 
			
		||||
    DirtyFlag                  mDirtyFlag{DirtyFlagBit::All};
 | 
			
		||||
    bool                       mComplexContent{false};
 | 
			
		||||
    std::unique_ptr<CApiData>  mCApiData;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class CompLayer final : public Layer {
 | 
			
		||||
public:
 | 
			
		||||
    explicit CompLayer(model::Layer *layerData, VArenaAlloc *allocator);
 | 
			
		||||
 | 
			
		||||
    void render(VPainter *painter, const VRle &mask, const VRle &matteRle,
 | 
			
		||||
                SurfaceCache &cache) final;
 | 
			
		||||
    void buildLayerNode() final;
 | 
			
		||||
    bool resolveKeyPath(LOTKeyPath &keyPath, uint depth,
 | 
			
		||||
                        LOTVariant &value) override;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void preprocessStage(const VRect &clip) final;
 | 
			
		||||
    void updateContent() final;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void renderHelper(VPainter *painter, const VRle &mask, const VRle &matteRle,
 | 
			
		||||
                      SurfaceCache &cache);
 | 
			
		||||
    void renderMatteLayer(VPainter *painter, const VRle &inheritMask,
 | 
			
		||||
                          const VRle &matteRle, Layer *layer, Layer *src,
 | 
			
		||||
                          SurfaceCache &cache);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::vector<Layer *>     mLayers;
 | 
			
		||||
    std::unique_ptr<Clipper> mClipper;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SolidLayer final : public Layer {
 | 
			
		||||
public:
 | 
			
		||||
    explicit SolidLayer(model::Layer *layerData);
 | 
			
		||||
    void         buildLayerNode() final;
 | 
			
		||||
    DrawableList renderList() final;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void preprocessStage(const VRect &clip) final;
 | 
			
		||||
    void updateContent() final;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Drawable   mRenderNode;
 | 
			
		||||
    VPath      mPath;
 | 
			
		||||
    VDrawable *mDrawableList{nullptr};  // to work with the Span api
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Group;
 | 
			
		||||
 | 
			
		||||
class ShapeLayer final : public Layer {
 | 
			
		||||
public:
 | 
			
		||||
    explicit ShapeLayer(model::Layer *layerData, VArenaAlloc *allocator);
 | 
			
		||||
    DrawableList renderList() final;
 | 
			
		||||
    void         buildLayerNode() final;
 | 
			
		||||
    bool         resolveKeyPath(LOTKeyPath &keyPath, uint depth,
 | 
			
		||||
                                LOTVariant &value) override;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void                     preprocessStage(const VRect &clip) final;
 | 
			
		||||
    void                     updateContent() final;
 | 
			
		||||
    std::vector<VDrawable *> mDrawableList;
 | 
			
		||||
    Group *                  mRoot{nullptr};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class NullLayer final : public Layer {
 | 
			
		||||
public:
 | 
			
		||||
    explicit NullLayer(model::Layer *layerData);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void preprocessStage(const VRect &) final {}
 | 
			
		||||
    void updateContent() final;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ImageLayer final : public Layer {
 | 
			
		||||
public:
 | 
			
		||||
    explicit ImageLayer(model::Layer *layerData);
 | 
			
		||||
    void         buildLayerNode() final;
 | 
			
		||||
    DrawableList renderList() final;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void preprocessStage(const VRect &clip) final;
 | 
			
		||||
    void updateContent() final;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Drawable   mRenderNode;
 | 
			
		||||
    VTexture   mTexture;
 | 
			
		||||
    VPath      mPath;
 | 
			
		||||
    VDrawable *mDrawableList{nullptr};  // to work with the Span api
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Object {
 | 
			
		||||
public:
 | 
			
		||||
    enum class Type : uchar { Unknown, Group, Shape, Paint, Trim };
 | 
			
		||||
    virtual ~Object() = default;
 | 
			
		||||
    Object &     operator=(Object &&) noexcept = delete;
 | 
			
		||||
    virtual void update(int frameNo, const VMatrix &parentMatrix,
 | 
			
		||||
                        float parentAlpha, const DirtyFlag &flag) = 0;
 | 
			
		||||
    virtual void renderList(std::vector<VDrawable *> &) {}
 | 
			
		||||
    virtual bool resolveKeyPath(LOTKeyPath &, uint, LOTVariant &)
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    virtual Object::Type type() const { return Object::Type::Unknown; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Shape;
 | 
			
		||||
class Group : public Object {
 | 
			
		||||
public:
 | 
			
		||||
    Group() = default;
 | 
			
		||||
    explicit Group(model::Group *data, VArenaAlloc *allocator);
 | 
			
		||||
    void addChildren(model::Group *data, VArenaAlloc *allocator);
 | 
			
		||||
    void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
 | 
			
		||||
                const DirtyFlag &flag) override;
 | 
			
		||||
    void applyTrim();
 | 
			
		||||
    void processTrimItems(std::vector<Shape *> &list);
 | 
			
		||||
    void processPaintItems(std::vector<Shape *> &list);
 | 
			
		||||
    void renderList(std::vector<VDrawable *> &list) override;
 | 
			
		||||
    Object::Type   type() const final { return Object::Type::Group; }
 | 
			
		||||
    const VMatrix &matrix() const { return mMatrix; }
 | 
			
		||||
    const char *   name() const
 | 
			
		||||
    {
 | 
			
		||||
        static const char *TAG = "__";
 | 
			
		||||
        return mModel.hasModel() ? mModel.name() : TAG;
 | 
			
		||||
    }
 | 
			
		||||
    bool resolveKeyPath(LOTKeyPath &keyPath, uint depth,
 | 
			
		||||
                        LOTVariant &value) override;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    std::vector<Object *> mContents;
 | 
			
		||||
    VMatrix               mMatrix;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    model::Filter<model::Group> mModel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Shape : public Object {
 | 
			
		||||
public:
 | 
			
		||||
    Shape(bool staticPath) : mStaticPath(staticPath) {}
 | 
			
		||||
    void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
 | 
			
		||||
                const DirtyFlag &flag) final;
 | 
			
		||||
    Object::Type type() const final { return Object::Type::Shape; }
 | 
			
		||||
    bool         dirty() const { return mDirtyPath; }
 | 
			
		||||
    const VPath &localPath() const { return mTemp; }
 | 
			
		||||
    void         finalPath(VPath &result);
 | 
			
		||||
    void         updatePath(const VPath &path)
 | 
			
		||||
    {
 | 
			
		||||
        mTemp = path;
 | 
			
		||||
        mDirtyPath = true;
 | 
			
		||||
    }
 | 
			
		||||
    bool   staticPath() const { return mStaticPath; }
 | 
			
		||||
    void   setParent(Group *parent) { mParent = parent; }
 | 
			
		||||
    Group *parent() const { return mParent; }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    virtual void updatePath(VPath &path, int frameNo) = 0;
 | 
			
		||||
    virtual bool hasChanged(int prevFrame, int curFrame) = 0;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool hasChanged(int frameNo)
 | 
			
		||||
    {
 | 
			
		||||
        int prevFrame = mFrameNo;
 | 
			
		||||
        mFrameNo = frameNo;
 | 
			
		||||
        if (prevFrame == -1) return true;
 | 
			
		||||
        if (mStaticPath || (prevFrame == frameNo)) return false;
 | 
			
		||||
        return hasChanged(prevFrame, frameNo);
 | 
			
		||||
    }
 | 
			
		||||
    Group *mParent{nullptr};
 | 
			
		||||
    VPath  mLocalPath;
 | 
			
		||||
    VPath  mTemp;
 | 
			
		||||
    int    mFrameNo{-1};
 | 
			
		||||
    bool   mDirtyPath{true};
 | 
			
		||||
    bool   mStaticPath;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Rect final : public Shape {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Rect(model::Rect *data);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void         updatePath(VPath &path, int frameNo) final;
 | 
			
		||||
    model::Rect *mData{nullptr};
 | 
			
		||||
 | 
			
		||||
    bool hasChanged(int prevFrame, int curFrame) final
 | 
			
		||||
    {
 | 
			
		||||
        return (mData->mPos.changed(prevFrame, curFrame) ||
 | 
			
		||||
                mData->mSize.changed(prevFrame, curFrame) ||
 | 
			
		||||
                mData->roundnessChanged(prevFrame, curFrame));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Ellipse final : public Shape {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Ellipse(model::Ellipse *data);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void            updatePath(VPath &path, int frameNo) final;
 | 
			
		||||
    model::Ellipse *mData{nullptr};
 | 
			
		||||
    bool            hasChanged(int prevFrame, int curFrame) final
 | 
			
		||||
    {
 | 
			
		||||
        return (mData->mPos.changed(prevFrame, curFrame) ||
 | 
			
		||||
                mData->mSize.changed(prevFrame, curFrame));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Path final : public Shape {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Path(model::Path *data);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void         updatePath(VPath &path, int frameNo) final;
 | 
			
		||||
    model::Path *mData{nullptr};
 | 
			
		||||
    bool         hasChanged(int prevFrame, int curFrame) final
 | 
			
		||||
    {
 | 
			
		||||
        return mData->mShape.changed(prevFrame, curFrame);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Polystar final : public Shape {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Polystar(model::Polystar *data);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void             updatePath(VPath &path, int frameNo) final;
 | 
			
		||||
    model::Polystar *mData{nullptr};
 | 
			
		||||
 | 
			
		||||
    bool hasChanged(int prevFrame, int curFrame) final
 | 
			
		||||
    {
 | 
			
		||||
        return (mData->mPos.changed(prevFrame, curFrame) ||
 | 
			
		||||
                mData->mPointCount.changed(prevFrame, curFrame) ||
 | 
			
		||||
                mData->mInnerRadius.changed(prevFrame, curFrame) ||
 | 
			
		||||
                mData->mOuterRadius.changed(prevFrame, curFrame) ||
 | 
			
		||||
                mData->mInnerRoundness.changed(prevFrame, curFrame) ||
 | 
			
		||||
                mData->mOuterRoundness.changed(prevFrame, curFrame) ||
 | 
			
		||||
                mData->mRotation.changed(prevFrame, curFrame));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Paint : public Object {
 | 
			
		||||
public:
 | 
			
		||||
    Paint(bool staticContent);
 | 
			
		||||
    void addPathItems(std::vector<Shape *> &list, size_t startOffset);
 | 
			
		||||
    void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
 | 
			
		||||
                const DirtyFlag &flag) override;
 | 
			
		||||
    void renderList(std::vector<VDrawable *> &list) final;
 | 
			
		||||
    Object::Type type() const final { return Object::Type::Paint; }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    virtual bool updateContent(int frameNo, const VMatrix &matrix,
 | 
			
		||||
                               float alpha) = 0;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void updateRenderNode();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    std::vector<Shape *> mPathItems;
 | 
			
		||||
    Drawable             mDrawable;
 | 
			
		||||
    VPath                mPath;
 | 
			
		||||
    DirtyFlag            mFlag;
 | 
			
		||||
    bool                 mStaticContent;
 | 
			
		||||
    bool                 mRenderNodeUpdate{true};
 | 
			
		||||
    bool                 mContentToRender{true};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Fill final : public Paint {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Fill(model::Fill *data);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final;
 | 
			
		||||
    bool resolveKeyPath(LOTKeyPath &keyPath, uint depth,
 | 
			
		||||
                        LOTVariant &value) final;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    model::Filter<model::Fill> mModel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GradientFill final : public Paint {
 | 
			
		||||
public:
 | 
			
		||||
    explicit GradientFill(model::GradientFill *data);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    model::GradientFill *      mData{nullptr};
 | 
			
		||||
    std::unique_ptr<VGradient> mGradient;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Stroke : public Paint {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Stroke(model::Stroke *data);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final;
 | 
			
		||||
    bool resolveKeyPath(LOTKeyPath &keyPath, uint depth,
 | 
			
		||||
                        LOTVariant &value) final;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    model::Filter<model::Stroke> mModel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GradientStroke final : public Paint {
 | 
			
		||||
public:
 | 
			
		||||
    explicit GradientStroke(model::GradientStroke *data);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    model::GradientStroke *    mData{nullptr};
 | 
			
		||||
    std::unique_ptr<VGradient> mGradient;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Trim final : public Object {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Trim(model::Trim *data) : mData(data) {}
 | 
			
		||||
    void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
 | 
			
		||||
                const DirtyFlag &flag) final;
 | 
			
		||||
    Object::Type type() const final { return Object::Type::Trim; }
 | 
			
		||||
    void         update();
 | 
			
		||||
    void         addPathItems(std::vector<Shape *> &list, size_t startOffset);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool pathDirty() const
 | 
			
		||||
    {
 | 
			
		||||
        for (auto &i : mPathItems) {
 | 
			
		||||
            if (i->dirty()) return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    struct Cache {
 | 
			
		||||
        int                  mFrameNo{-1};
 | 
			
		||||
        model::Trim::Segment mSegment{};
 | 
			
		||||
    };
 | 
			
		||||
    Cache                mCache;
 | 
			
		||||
    std::vector<Shape *> mPathItems;
 | 
			
		||||
    model::Trim *        mData{nullptr};
 | 
			
		||||
    VPathMesure          mPathMesure;
 | 
			
		||||
    bool                 mDirty{true};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Repeater final : public Group {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Repeater(model::Repeater *data, VArenaAlloc *allocator);
 | 
			
		||||
    void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
 | 
			
		||||
                const DirtyFlag &flag) final;
 | 
			
		||||
    void renderList(std::vector<VDrawable *> &list) final;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    model::Repeater *mRepeaterData{nullptr};
 | 
			
		||||
    bool             mHidden{false};
 | 
			
		||||
    int              mCopies{0};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace renderer
 | 
			
		||||
 | 
			
		||||
}  // namespace internal
 | 
			
		||||
 | 
			
		||||
}  // namespace rlottie
 | 
			
		||||
 | 
			
		||||
#endif  // LOTTIEITEM_H
 | 
			
		||||
							
								
								
									
										339
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieitem_capi.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieitem_capi.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,339 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Implements LottieItem functions needed
 | 
			
		||||
 * to support renderTree() api.
 | 
			
		||||
 * Moving all those implementation to its own
 | 
			
		||||
 * file make clear separation as well easy of
 | 
			
		||||
 * maintenance.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lottie_lottieitem.h"
 | 
			
		||||
#include "vector_vdasher.h"
 | 
			
		||||
 | 
			
		||||
using namespace rlottie::internal;
 | 
			
		||||
 | 
			
		||||
renderer::CApiData::CApiData()
 | 
			
		||||
{
 | 
			
		||||
    mLayer.mMaskList.ptr = nullptr;
 | 
			
		||||
    mLayer.mMaskList.size = 0;
 | 
			
		||||
    mLayer.mLayerList.ptr = nullptr;
 | 
			
		||||
    mLayer.mLayerList.size = 0;
 | 
			
		||||
    mLayer.mNodeList.ptr = nullptr;
 | 
			
		||||
    mLayer.mNodeList.size = 0;
 | 
			
		||||
    mLayer.mMatte = MatteNone;
 | 
			
		||||
    mLayer.mVisible = 0;
 | 
			
		||||
    mLayer.mAlpha = 255;
 | 
			
		||||
    mLayer.mClipPath.ptPtr = nullptr;
 | 
			
		||||
    mLayer.mClipPath.elmPtr = nullptr;
 | 
			
		||||
    mLayer.mClipPath.ptCount = 0;
 | 
			
		||||
    mLayer.mClipPath.elmCount = 0;
 | 
			
		||||
    mLayer.keypath = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void renderer::Composition::buildRenderTree()
 | 
			
		||||
{
 | 
			
		||||
    mRootLayer->buildLayerNode();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const LOTLayerNode *renderer::Composition::renderTree() const
 | 
			
		||||
{
 | 
			
		||||
    return &mRootLayer->clayer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void renderer::CompLayer::buildLayerNode()
 | 
			
		||||
{
 | 
			
		||||
    renderer::Layer::buildLayerNode();
 | 
			
		||||
    if (mClipper) {
 | 
			
		||||
        const auto &elm = mClipper->mPath.elements();
 | 
			
		||||
        const auto &pts = mClipper->mPath.points();
 | 
			
		||||
        auto        ptPtr = reinterpret_cast<const float *>(pts.data());
 | 
			
		||||
        auto        elmPtr = reinterpret_cast<const char *>(elm.data());
 | 
			
		||||
        clayer().mClipPath.ptPtr = ptPtr;
 | 
			
		||||
        clayer().mClipPath.elmPtr = elmPtr;
 | 
			
		||||
        clayer().mClipPath.ptCount = 2 * pts.size();
 | 
			
		||||
        clayer().mClipPath.elmCount = elm.size();
 | 
			
		||||
    }
 | 
			
		||||
    if (mLayers.size() != clayers().size()) {
 | 
			
		||||
        for (const auto &layer : mLayers) {
 | 
			
		||||
            layer->buildLayerNode();
 | 
			
		||||
            clayers().push_back(&layer->clayer());
 | 
			
		||||
        }
 | 
			
		||||
        clayer().mLayerList.ptr = clayers().data();
 | 
			
		||||
        clayer().mLayerList.size = clayers().size();
 | 
			
		||||
    } else {
 | 
			
		||||
        for (const auto &layer : mLayers) {
 | 
			
		||||
            layer->buildLayerNode();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void renderer::ShapeLayer::buildLayerNode()
 | 
			
		||||
{
 | 
			
		||||
    renderer::Layer::buildLayerNode();
 | 
			
		||||
 | 
			
		||||
    auto renderlist = renderList();
 | 
			
		||||
 | 
			
		||||
    cnodes().clear();
 | 
			
		||||
    for (auto &i : renderlist) {
 | 
			
		||||
        auto lotDrawable = static_cast<renderer::Drawable *>(i);
 | 
			
		||||
        lotDrawable->sync();
 | 
			
		||||
        cnodes().push_back(lotDrawable->mCNode.get());
 | 
			
		||||
    }
 | 
			
		||||
    clayer().mNodeList.ptr = cnodes().data();
 | 
			
		||||
    clayer().mNodeList.size = cnodes().size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void renderer::Layer::buildLayerNode()
 | 
			
		||||
{
 | 
			
		||||
    if (!mCApiData) {
 | 
			
		||||
        mCApiData = std::make_unique<renderer::CApiData>();
 | 
			
		||||
        clayer().keypath = name();
 | 
			
		||||
    }
 | 
			
		||||
    if (complexContent()) clayer().mAlpha = uchar(combinedAlpha() * 255.f);
 | 
			
		||||
    clayer().mVisible = visible();
 | 
			
		||||
    // update matte
 | 
			
		||||
    if (hasMatte()) {
 | 
			
		||||
        switch (mLayerData->mMatteType) {
 | 
			
		||||
        case model::MatteType::Alpha:
 | 
			
		||||
            clayer().mMatte = MatteAlpha;
 | 
			
		||||
            break;
 | 
			
		||||
        case model::MatteType::AlphaInv:
 | 
			
		||||
            clayer().mMatte = MatteAlphaInv;
 | 
			
		||||
            break;
 | 
			
		||||
        case model::MatteType::Luma:
 | 
			
		||||
            clayer().mMatte = MatteLuma;
 | 
			
		||||
            break;
 | 
			
		||||
        case model::MatteType::LumaInv:
 | 
			
		||||
            clayer().mMatte = MatteLumaInv;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            clayer().mMatte = MatteNone;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (mLayerMask) {
 | 
			
		||||
        cmasks().clear();
 | 
			
		||||
        cmasks().resize(mLayerMask->mMasks.size());
 | 
			
		||||
        size_t i = 0;
 | 
			
		||||
        for (const auto &mask : mLayerMask->mMasks) {
 | 
			
		||||
            auto &      cNode = cmasks()[i++];
 | 
			
		||||
            const auto &elm = mask.mFinalPath.elements();
 | 
			
		||||
            const auto &pts = mask.mFinalPath.points();
 | 
			
		||||
            auto        ptPtr = reinterpret_cast<const float *>(pts.data());
 | 
			
		||||
            auto        elmPtr = reinterpret_cast<const char *>(elm.data());
 | 
			
		||||
            cNode.mPath.ptPtr = ptPtr;
 | 
			
		||||
            cNode.mPath.ptCount = 2 * pts.size();
 | 
			
		||||
            cNode.mPath.elmPtr = elmPtr;
 | 
			
		||||
            cNode.mPath.elmCount = elm.size();
 | 
			
		||||
            cNode.mAlpha = uchar(mask.mCombinedAlpha * 255.0f);
 | 
			
		||||
            switch (mask.maskMode()) {
 | 
			
		||||
            case model::Mask::Mode::Add:
 | 
			
		||||
                cNode.mMode = MaskAdd;
 | 
			
		||||
                break;
 | 
			
		||||
            case model::Mask::Mode::Substarct:
 | 
			
		||||
                cNode.mMode = MaskSubstract;
 | 
			
		||||
                break;
 | 
			
		||||
            case model::Mask::Mode::Intersect:
 | 
			
		||||
                cNode.mMode = MaskIntersect;
 | 
			
		||||
                break;
 | 
			
		||||
            case model::Mask::Mode::Difference:
 | 
			
		||||
                cNode.mMode = MaskDifference;
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                cNode.mMode = MaskAdd;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        clayer().mMaskList.ptr = cmasks().data();
 | 
			
		||||
        clayer().mMaskList.size = cmasks().size();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void renderer::SolidLayer::buildLayerNode()
 | 
			
		||||
{
 | 
			
		||||
    renderer::Layer::buildLayerNode();
 | 
			
		||||
 | 
			
		||||
    auto renderlist = renderList();
 | 
			
		||||
 | 
			
		||||
    cnodes().clear();
 | 
			
		||||
    for (auto &i : renderlist) {
 | 
			
		||||
        auto lotDrawable = static_cast<renderer::Drawable *>(i);
 | 
			
		||||
        lotDrawable->sync();
 | 
			
		||||
        cnodes().push_back(lotDrawable->mCNode.get());
 | 
			
		||||
    }
 | 
			
		||||
    clayer().mNodeList.ptr = cnodes().data();
 | 
			
		||||
    clayer().mNodeList.size = cnodes().size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void renderer::ImageLayer::buildLayerNode()
 | 
			
		||||
{
 | 
			
		||||
    renderer::Layer::buildLayerNode();
 | 
			
		||||
 | 
			
		||||
    auto renderlist = renderList();
 | 
			
		||||
 | 
			
		||||
    cnodes().clear();
 | 
			
		||||
    for (auto &i : renderlist) {
 | 
			
		||||
        auto lotDrawable = static_cast<renderer::Drawable *>(i);
 | 
			
		||||
        lotDrawable->sync();
 | 
			
		||||
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.data =
 | 
			
		||||
            lotDrawable->mBrush.mTexture->mBitmap.data();
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.width =
 | 
			
		||||
            int(lotDrawable->mBrush.mTexture->mBitmap.width());
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.height =
 | 
			
		||||
            int(lotDrawable->mBrush.mTexture->mBitmap.height());
 | 
			
		||||
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.mMatrix.m11 = combinedMatrix().m_11();
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.mMatrix.m12 = combinedMatrix().m_12();
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.mMatrix.m13 = combinedMatrix().m_13();
 | 
			
		||||
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.mMatrix.m21 = combinedMatrix().m_21();
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.mMatrix.m22 = combinedMatrix().m_22();
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.mMatrix.m23 = combinedMatrix().m_23();
 | 
			
		||||
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.mMatrix.m31 = combinedMatrix().m_tx();
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.mMatrix.m32 = combinedMatrix().m_ty();
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.mMatrix.m33 = combinedMatrix().m_33();
 | 
			
		||||
 | 
			
		||||
        // Alpha calculation already combined.
 | 
			
		||||
        lotDrawable->mCNode->mImageInfo.mAlpha =
 | 
			
		||||
            uchar(lotDrawable->mBrush.mTexture->mAlpha);
 | 
			
		||||
 | 
			
		||||
        cnodes().push_back(lotDrawable->mCNode.get());
 | 
			
		||||
    }
 | 
			
		||||
    clayer().mNodeList.ptr = cnodes().data();
 | 
			
		||||
    clayer().mNodeList.size = cnodes().size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void updateGStops(LOTNode *n, const VGradient *grad)
 | 
			
		||||
{
 | 
			
		||||
    if (grad->mStops.size() != n->mGradient.stopCount) {
 | 
			
		||||
        if (n->mGradient.stopCount) free(n->mGradient.stopPtr);
 | 
			
		||||
        n->mGradient.stopCount = grad->mStops.size();
 | 
			
		||||
        n->mGradient.stopPtr = (LOTGradientStop *)malloc(
 | 
			
		||||
            n->mGradient.stopCount * sizeof(LOTGradientStop));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOTGradientStop *ptr = n->mGradient.stopPtr;
 | 
			
		||||
    for (const auto &i : grad->mStops) {
 | 
			
		||||
        ptr->pos = i.first;
 | 
			
		||||
        ptr->a = uchar(i.second.alpha() * grad->alpha());
 | 
			
		||||
        ptr->r = i.second.red();
 | 
			
		||||
        ptr->g = i.second.green();
 | 
			
		||||
        ptr->b = i.second.blue();
 | 
			
		||||
        ptr++;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void renderer::Drawable::sync()
 | 
			
		||||
{
 | 
			
		||||
    if (!mCNode) {
 | 
			
		||||
        mCNode = std::make_unique<LOTNode>();
 | 
			
		||||
        mCNode->mGradient.stopPtr = nullptr;
 | 
			
		||||
        mCNode->mGradient.stopCount = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mCNode->mFlag = ChangeFlagNone;
 | 
			
		||||
    if (mFlag & DirtyState::None) return;
 | 
			
		||||
 | 
			
		||||
    if (mFlag & DirtyState::Path) {
 | 
			
		||||
        applyDashOp();
 | 
			
		||||
        const std::vector<VPath::Element> &elm = mPath.elements();
 | 
			
		||||
        const std::vector<VPointF> &       pts = mPath.points();
 | 
			
		||||
        const float *ptPtr = reinterpret_cast<const float *>(pts.data());
 | 
			
		||||
        const char * elmPtr = reinterpret_cast<const char *>(elm.data());
 | 
			
		||||
        mCNode->mPath.elmPtr = elmPtr;
 | 
			
		||||
        mCNode->mPath.elmCount = elm.size();
 | 
			
		||||
        mCNode->mPath.ptPtr = ptPtr;
 | 
			
		||||
        mCNode->mPath.ptCount = 2 * pts.size();
 | 
			
		||||
        mCNode->mFlag |= ChangeFlagPath;
 | 
			
		||||
        mCNode->keypath = name();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (mStrokeInfo) {
 | 
			
		||||
        mCNode->mStroke.width = mStrokeInfo->width;
 | 
			
		||||
        mCNode->mStroke.miterLimit = mStrokeInfo->miterLimit;
 | 
			
		||||
        mCNode->mStroke.enable = 1;
 | 
			
		||||
 | 
			
		||||
        switch (mStrokeInfo->cap) {
 | 
			
		||||
        case CapStyle::Flat:
 | 
			
		||||
            mCNode->mStroke.cap = LOTCapStyle::CapFlat;
 | 
			
		||||
            break;
 | 
			
		||||
        case CapStyle::Square:
 | 
			
		||||
            mCNode->mStroke.cap = LOTCapStyle::CapSquare;
 | 
			
		||||
            break;
 | 
			
		||||
        case CapStyle::Round:
 | 
			
		||||
            mCNode->mStroke.cap = LOTCapStyle::CapRound;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (mStrokeInfo->join) {
 | 
			
		||||
        case JoinStyle::Miter:
 | 
			
		||||
            mCNode->mStroke.join = LOTJoinStyle::JoinMiter;
 | 
			
		||||
            break;
 | 
			
		||||
        case JoinStyle::Bevel:
 | 
			
		||||
            mCNode->mStroke.join = LOTJoinStyle::JoinBevel;
 | 
			
		||||
            break;
 | 
			
		||||
        case JoinStyle::Round:
 | 
			
		||||
            mCNode->mStroke.join = LOTJoinStyle::JoinRound;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            mCNode->mStroke.join = LOTJoinStyle::JoinMiter;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        mCNode->mStroke.enable = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (mFillRule) {
 | 
			
		||||
    case FillRule::EvenOdd:
 | 
			
		||||
        mCNode->mFillRule = LOTFillRule::FillEvenOdd;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        mCNode->mFillRule = LOTFillRule::FillWinding;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (mBrush.type()) {
 | 
			
		||||
    case VBrush::Type::Solid:
 | 
			
		||||
        mCNode->mBrushType = LOTBrushType::BrushSolid;
 | 
			
		||||
        mCNode->mColor.r = mBrush.mColor.r;
 | 
			
		||||
        mCNode->mColor.g = mBrush.mColor.g;
 | 
			
		||||
        mCNode->mColor.b = mBrush.mColor.b;
 | 
			
		||||
        mCNode->mColor.a = mBrush.mColor.a;
 | 
			
		||||
        break;
 | 
			
		||||
    case VBrush::Type::LinearGradient: {
 | 
			
		||||
        mCNode->mBrushType = LOTBrushType::BrushGradient;
 | 
			
		||||
        mCNode->mGradient.type = LOTGradientType::GradientLinear;
 | 
			
		||||
        VPointF s = mBrush.mGradient->mMatrix.map(
 | 
			
		||||
            {mBrush.mGradient->linear.x1, mBrush.mGradient->linear.y1});
 | 
			
		||||
        VPointF e = mBrush.mGradient->mMatrix.map(
 | 
			
		||||
            {mBrush.mGradient->linear.x2, mBrush.mGradient->linear.y2});
 | 
			
		||||
        mCNode->mGradient.start.x = s.x();
 | 
			
		||||
        mCNode->mGradient.start.y = s.y();
 | 
			
		||||
        mCNode->mGradient.end.x = e.x();
 | 
			
		||||
        mCNode->mGradient.end.y = e.y();
 | 
			
		||||
        updateGStops(mCNode.get(), mBrush.mGradient);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case VBrush::Type::RadialGradient: {
 | 
			
		||||
        mCNode->mBrushType = LOTBrushType::BrushGradient;
 | 
			
		||||
        mCNode->mGradient.type = LOTGradientType::GradientRadial;
 | 
			
		||||
        VPointF c = mBrush.mGradient->mMatrix.map(
 | 
			
		||||
            {mBrush.mGradient->radial.cx, mBrush.mGradient->radial.cy});
 | 
			
		||||
        VPointF f = mBrush.mGradient->mMatrix.map(
 | 
			
		||||
            {mBrush.mGradient->radial.fx, mBrush.mGradient->radial.fy});
 | 
			
		||||
        mCNode->mGradient.center.x = c.x();
 | 
			
		||||
        mCNode->mGradient.center.y = c.y();
 | 
			
		||||
        mCNode->mGradient.focal.x = f.x();
 | 
			
		||||
        mCNode->mGradient.focal.y = f.y();
 | 
			
		||||
 | 
			
		||||
        float scale = mBrush.mGradient->mMatrix.scale();
 | 
			
		||||
        mCNode->mGradient.cradius = mBrush.mGradient->radial.cradius * scale;
 | 
			
		||||
        mCNode->mGradient.fradius = mBrush.mGradient->radial.fradius * scale;
 | 
			
		||||
        updateGStops(mCNode.get(), mBrush.mGradient);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottiekeypath.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottiekeypath.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
#include "lottie_lottiekeypath.h"
 | 
			
		||||
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
LOTKeyPath::LOTKeyPath(const std::string &keyPath)
 | 
			
		||||
{
 | 
			
		||||
    std::stringstream ss(keyPath);
 | 
			
		||||
    std::string       item;
 | 
			
		||||
 | 
			
		||||
    while (getline(ss, item, '.')) {
 | 
			
		||||
        mKeys.push_back(item);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LOTKeyPath::matches(const std::string &key, uint depth)
 | 
			
		||||
{
 | 
			
		||||
    if (skip(key)) {
 | 
			
		||||
        // This is an object we programatically create.
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (depth > size()) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if ((mKeys[depth] == key) || (mKeys[depth] == "*") ||
 | 
			
		||||
        (mKeys[depth] == "**")) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint LOTKeyPath::nextDepth(const std::string key, uint depth)
 | 
			
		||||
{
 | 
			
		||||
    if (skip(key)) {
 | 
			
		||||
        // If it's a container then we added programatically and it isn't a part
 | 
			
		||||
        // of the keypath.
 | 
			
		||||
        return depth;
 | 
			
		||||
    }
 | 
			
		||||
    if (mKeys[depth] != "**") {
 | 
			
		||||
        // If it's not a globstar then it is part of the keypath.
 | 
			
		||||
        return depth + 1;
 | 
			
		||||
    }
 | 
			
		||||
    if (depth == size()) {
 | 
			
		||||
        // The last key is a globstar.
 | 
			
		||||
        return depth;
 | 
			
		||||
    }
 | 
			
		||||
    if (mKeys[depth + 1] == key) {
 | 
			
		||||
        // We are a globstar and the next key is our current key so consume
 | 
			
		||||
        // both.
 | 
			
		||||
        return depth + 2;
 | 
			
		||||
    }
 | 
			
		||||
    return depth;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LOTKeyPath::fullyResolvesTo(const std::string key, uint depth)
 | 
			
		||||
{
 | 
			
		||||
    if (depth > mKeys.size()) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool isLastDepth = (depth == size());
 | 
			
		||||
 | 
			
		||||
    if (!isGlobstar(depth)) {
 | 
			
		||||
        bool matches = (mKeys[depth] == key) || isGlob(depth);
 | 
			
		||||
        return (isLastDepth || (depth == size() - 1 && endsWithGlobstar())) &&
 | 
			
		||||
               matches;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool isGlobstarButNextKeyMatches = !isLastDepth && mKeys[depth + 1] == key;
 | 
			
		||||
    if (isGlobstarButNextKeyMatches) {
 | 
			
		||||
        return depth == size() - 1 ||
 | 
			
		||||
               (depth == size() - 2 && endsWithGlobstar());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (isLastDepth) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (depth + 1 < size()) {
 | 
			
		||||
        // We are a globstar but there is more than 1 key after the globstar we
 | 
			
		||||
        // we can't fully match.
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    // Return whether the next key (which we now know is the last one) is the
 | 
			
		||||
    // same as the current key.
 | 
			
		||||
    return mKeys[depth + 1] == key;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottiekeypath.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottiekeypath.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LOTTIEKEYPATH_H
 | 
			
		||||
#define LOTTIEKEYPATH_H
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "vector_vglobal.h"
 | 
			
		||||
 | 
			
		||||
class LOTKeyPath {
 | 
			
		||||
public:
 | 
			
		||||
    LOTKeyPath(const std::string &keyPath);
 | 
			
		||||
    bool matches(const std::string &key, uint depth);
 | 
			
		||||
    uint nextDepth(const std::string key, uint depth);
 | 
			
		||||
    bool fullyResolvesTo(const std::string key, uint depth);
 | 
			
		||||
 | 
			
		||||
    bool propagate(const std::string key, uint depth)
 | 
			
		||||
    {
 | 
			
		||||
        return skip(key) ? true : (depth < size()) || (mKeys[depth] == "**");
 | 
			
		||||
    }
 | 
			
		||||
    bool skip(const std::string &key) const { return key == "__"; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool   isGlobstar(uint depth) const { return mKeys[depth] == "**"; }
 | 
			
		||||
    bool   isGlob(uint depth) const { return mKeys[depth] == "*"; }
 | 
			
		||||
    bool   endsWithGlobstar() const { return mKeys.back() == "**"; }
 | 
			
		||||
    size_t size() const { return mKeys.size() - 1; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::vector<std::string> mKeys;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif  // LOTTIEKEYPATH_H
 | 
			
		||||
							
								
								
									
										169
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieloader.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieloader.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
#include "lottie_lottiemodel.h"
 | 
			
		||||
 | 
			
		||||
using namespace rlottie::internal;
 | 
			
		||||
 | 
			
		||||
#ifdef LOTTIE_CACHE_SUPPORT
 | 
			
		||||
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
class ModelCache {
 | 
			
		||||
public:
 | 
			
		||||
    static ModelCache &instance()
 | 
			
		||||
    {
 | 
			
		||||
        static ModelCache singleton;
 | 
			
		||||
        return singleton;
 | 
			
		||||
    }
 | 
			
		||||
    std::shared_ptr<model::Composition> find(const std::string &key)
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> guard(mMutex);
 | 
			
		||||
 | 
			
		||||
        if (!mcacheSize) return nullptr;
 | 
			
		||||
 | 
			
		||||
        auto search = mHash.find(key);
 | 
			
		||||
 | 
			
		||||
        return (search != mHash.end()) ? search->second : nullptr;
 | 
			
		||||
    }
 | 
			
		||||
    void add(const std::string &key, std::shared_ptr<model::Composition> value)
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> guard(mMutex);
 | 
			
		||||
 | 
			
		||||
        if (!mcacheSize) return;
 | 
			
		||||
 | 
			
		||||
        //@TODO just remove the 1st element
 | 
			
		||||
        // not the best of LRU logic
 | 
			
		||||
        if (mcacheSize == mHash.size()) mHash.erase(mHash.cbegin());
 | 
			
		||||
 | 
			
		||||
        mHash[key] = std::move(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void configureCacheSize(size_t cacheSize)
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> guard(mMutex);
 | 
			
		||||
        mcacheSize = cacheSize;
 | 
			
		||||
 | 
			
		||||
        if (!mcacheSize) mHash.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ModelCache() = default;
 | 
			
		||||
 | 
			
		||||
    std::unordered_map<std::string, std::shared_ptr<model::Composition>> mHash;
 | 
			
		||||
    std::mutex                                                           mMutex;
 | 
			
		||||
    size_t mcacheSize{10};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
class ModelCache {
 | 
			
		||||
public:
 | 
			
		||||
    static ModelCache &instance()
 | 
			
		||||
    {
 | 
			
		||||
        static ModelCache singleton;
 | 
			
		||||
        return singleton;
 | 
			
		||||
    }
 | 
			
		||||
    std::shared_ptr<model::Composition> find(const std::string &)
 | 
			
		||||
    {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
    void add(const std::string &, std::shared_ptr<model::Composition>) {}
 | 
			
		||||
    void configureCacheSize(size_t) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static std::string dirname(const std::string &path)
 | 
			
		||||
{
 | 
			
		||||
    const char *ptr = strrchr(path.c_str(), '/');
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    if (ptr) ptr = strrchr(ptr + 1, '\\');
 | 
			
		||||
#endif
 | 
			
		||||
    int len = int(ptr + 1 - path.c_str());  // +1 to include '/'
 | 
			
		||||
    return std::string(path, 0, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model::configureModelCacheSize(size_t cacheSize)
 | 
			
		||||
{
 | 
			
		||||
    ModelCache::instance().configureCacheSize(cacheSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<model::Composition> model::loadFromFile(const std::string &path,
 | 
			
		||||
                                                        bool cachePolicy)
 | 
			
		||||
{
 | 
			
		||||
    if (cachePolicy) {
 | 
			
		||||
        auto obj = ModelCache::instance().find(path);
 | 
			
		||||
        if (obj) return obj;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::ifstream f;
 | 
			
		||||
    f.open(path);
 | 
			
		||||
 | 
			
		||||
    if (!f.is_open()) {
 | 
			
		||||
        vCritical << "failed to open file = " << path.c_str();
 | 
			
		||||
        return {};
 | 
			
		||||
    } else {
 | 
			
		||||
        std::string content;
 | 
			
		||||
 | 
			
		||||
        std::getline(f, content, '\0');
 | 
			
		||||
        f.close();
 | 
			
		||||
 | 
			
		||||
        if (content.empty()) return {};
 | 
			
		||||
 | 
			
		||||
        auto obj = internal::model::parse(const_cast<char *>(content.c_str()),
 | 
			
		||||
                                          dirname(path));
 | 
			
		||||
 | 
			
		||||
        if (obj && cachePolicy) ModelCache::instance().add(path, obj);
 | 
			
		||||
 | 
			
		||||
        return obj;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<model::Composition> model::loadFromData(
 | 
			
		||||
    std::string jsonData, const std::string &key, std::string resourcePath,
 | 
			
		||||
    bool cachePolicy)
 | 
			
		||||
{
 | 
			
		||||
    if (cachePolicy) {
 | 
			
		||||
        auto obj = ModelCache::instance().find(key);
 | 
			
		||||
        if (obj) return obj;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto obj = internal::model::parse(const_cast<char *>(jsonData.c_str()),
 | 
			
		||||
                                      std::move(resourcePath));
 | 
			
		||||
 | 
			
		||||
    if (obj && cachePolicy) ModelCache::instance().add(key, obj);
 | 
			
		||||
 | 
			
		||||
    return obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<model::Composition> model::loadFromData(
 | 
			
		||||
    std::string jsonData, std::string resourcePath, model::ColorFilter filter)
 | 
			
		||||
{
 | 
			
		||||
    return internal::model::parse(const_cast<char *>(jsonData.c_str()),
 | 
			
		||||
                                  std::move(resourcePath), std::move(filter));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										390
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottiemodel.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottiemodel.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,390 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lottie_lottiemodel.h"
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <stack>
 | 
			
		||||
#include "vector_vimageloader.h"
 | 
			
		||||
#include "vector_vline.h"
 | 
			
		||||
 | 
			
		||||
using namespace rlottie::internal;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * We process the iterator objects in the children list
 | 
			
		||||
 * by iterating from back to front. when we find a repeater object
 | 
			
		||||
 * we remove the objects from satrt till repeater object and then place
 | 
			
		||||
 * under a new shape group object which we add it as children to the repeater
 | 
			
		||||
 * object.
 | 
			
		||||
 * Then we visit the childrens of the newly created shape group object to
 | 
			
		||||
 * process the remaining repeater object(when children list contains more than
 | 
			
		||||
 * one repeater).
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
class LottieRepeaterProcesser {
 | 
			
		||||
public:
 | 
			
		||||
    void visitChildren(model::Group *obj)
 | 
			
		||||
    {
 | 
			
		||||
        for (auto i = obj->mChildren.rbegin(); i != obj->mChildren.rend();
 | 
			
		||||
             ++i) {
 | 
			
		||||
            auto child = (*i);
 | 
			
		||||
            if (child->type() == model::Object::Type::Repeater) {
 | 
			
		||||
                model::Repeater *repeater =
 | 
			
		||||
                    static_cast<model::Repeater *>(child);
 | 
			
		||||
                // check if this repeater is already processed
 | 
			
		||||
                // can happen if the layer is an asset and referenced by
 | 
			
		||||
                // multiple layer.
 | 
			
		||||
                if (repeater->processed()) continue;
 | 
			
		||||
 | 
			
		||||
                repeater->markProcessed();
 | 
			
		||||
 | 
			
		||||
                auto content = repeater->content();
 | 
			
		||||
                // 1. increment the reverse iterator to point to the
 | 
			
		||||
                //   object before the repeater
 | 
			
		||||
                ++i;
 | 
			
		||||
                // 2. move all the children till repater to the group
 | 
			
		||||
                std::move(obj->mChildren.begin(), i.base(),
 | 
			
		||||
                          back_inserter(content->mChildren));
 | 
			
		||||
                // 3. erase the objects from the original children list
 | 
			
		||||
                obj->mChildren.erase(obj->mChildren.begin(), i.base());
 | 
			
		||||
 | 
			
		||||
                // 5. visit newly created group to process remaining repeater
 | 
			
		||||
                // object.
 | 
			
		||||
                visitChildren(content);
 | 
			
		||||
                // 6. exit the loop as the current iterators are invalid
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            visit(child);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void visit(model::Object *obj)
 | 
			
		||||
    {
 | 
			
		||||
        switch (obj->type()) {
 | 
			
		||||
        case model::Object::Type::Group:
 | 
			
		||||
        case model::Object::Type::Layer: {
 | 
			
		||||
            visitChildren(static_cast<model::Group *>(obj));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class LottieUpdateStatVisitor {
 | 
			
		||||
    model::Composition::Stats *stat;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit LottieUpdateStatVisitor(model::Composition::Stats *s) : stat(s) {}
 | 
			
		||||
    void visitChildren(model::Group *obj)
 | 
			
		||||
    {
 | 
			
		||||
        for (const auto &child : obj->mChildren) {
 | 
			
		||||
            if (child) visit(child);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    void visitLayer(model::Layer *layer)
 | 
			
		||||
    {
 | 
			
		||||
        switch (layer->mLayerType) {
 | 
			
		||||
        case model::Layer::Type::Precomp:
 | 
			
		||||
            stat->precompLayerCount++;
 | 
			
		||||
            break;
 | 
			
		||||
        case model::Layer::Type::Null:
 | 
			
		||||
            stat->nullLayerCount++;
 | 
			
		||||
            break;
 | 
			
		||||
        case model::Layer::Type::Shape:
 | 
			
		||||
            stat->shapeLayerCount++;
 | 
			
		||||
            break;
 | 
			
		||||
        case model::Layer::Type::Solid:
 | 
			
		||||
            stat->solidLayerCount++;
 | 
			
		||||
            break;
 | 
			
		||||
        case model::Layer::Type::Image:
 | 
			
		||||
            stat->imageLayerCount++;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        visitChildren(layer);
 | 
			
		||||
    }
 | 
			
		||||
    void visit(model::Object *obj)
 | 
			
		||||
    {
 | 
			
		||||
        switch (obj->type()) {
 | 
			
		||||
        case model::Object::Type::Layer: {
 | 
			
		||||
            visitLayer(static_cast<model::Layer *>(obj));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case model::Object::Type::Repeater: {
 | 
			
		||||
            visitChildren(static_cast<model::Repeater *>(obj)->content());
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case model::Object::Type::Group: {
 | 
			
		||||
            visitChildren(static_cast<model::Group *>(obj));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void model::Composition::processRepeaterObjects()
 | 
			
		||||
{
 | 
			
		||||
    LottieRepeaterProcesser visitor;
 | 
			
		||||
    visitor.visit(mRootLayer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model::Composition::updateStats()
 | 
			
		||||
{
 | 
			
		||||
    LottieUpdateStatVisitor visitor(&mStats);
 | 
			
		||||
    visitor.visit(mRootLayer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VMatrix model::Repeater::Transform::matrix(int frameNo, float multiplier) const
 | 
			
		||||
{
 | 
			
		||||
    VPointF scale = mScale.value(frameNo) / 100.f;
 | 
			
		||||
    scale.setX(std::pow(scale.x(), multiplier));
 | 
			
		||||
    scale.setY(std::pow(scale.y(), multiplier));
 | 
			
		||||
    VMatrix m;
 | 
			
		||||
    m.translate(mPosition.value(frameNo) * multiplier)
 | 
			
		||||
        .translate(mAnchor.value(frameNo))
 | 
			
		||||
        .scale(scale)
 | 
			
		||||
        .rotate(mRotation.value(frameNo) * multiplier)
 | 
			
		||||
        .translate(-mAnchor.value(frameNo));
 | 
			
		||||
 | 
			
		||||
    return m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VMatrix model::Transform::Data::matrix(int frameNo, bool autoOrient) const
 | 
			
		||||
{
 | 
			
		||||
    VMatrix m;
 | 
			
		||||
    VPointF position;
 | 
			
		||||
    if (mExtra && mExtra->mSeparate) {
 | 
			
		||||
        position.setX(mExtra->mSeparateX.value(frameNo));
 | 
			
		||||
        position.setY(mExtra->mSeparateY.value(frameNo));
 | 
			
		||||
    } else {
 | 
			
		||||
        position = mPosition.value(frameNo);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float angle = autoOrient ? mPosition.angle(frameNo) : 0;
 | 
			
		||||
    if (mExtra && mExtra->m3DData) {
 | 
			
		||||
        m.translate(position)
 | 
			
		||||
            .rotate(mExtra->m3DRz.value(frameNo) + angle)
 | 
			
		||||
            .rotate(mExtra->m3DRy.value(frameNo), VMatrix::Axis::Y)
 | 
			
		||||
            .rotate(mExtra->m3DRx.value(frameNo), VMatrix::Axis::X)
 | 
			
		||||
            .scale(mScale.value(frameNo) / 100.f)
 | 
			
		||||
            .translate(-mAnchor.value(frameNo));
 | 
			
		||||
    } else {
 | 
			
		||||
        m.translate(position)
 | 
			
		||||
            .rotate(mRotation.value(frameNo) + angle)
 | 
			
		||||
            .scale(mScale.value(frameNo) / 100.f)
 | 
			
		||||
            .translate(-mAnchor.value(frameNo));
 | 
			
		||||
    }
 | 
			
		||||
    return m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model::Dash::getDashInfo(int frameNo, std::vector<float> &result) const
 | 
			
		||||
{
 | 
			
		||||
    result.clear();
 | 
			
		||||
 | 
			
		||||
    if (mData.size() <= 1) return;
 | 
			
		||||
 | 
			
		||||
    if (result.capacity() < mData.size()) result.reserve(mData.size() + 1);
 | 
			
		||||
 | 
			
		||||
    for (const auto &elm : mData) result.push_back(elm.value(frameNo));
 | 
			
		||||
 | 
			
		||||
    // if the size is even then we are missing last
 | 
			
		||||
    // gap information which is same as the last dash value
 | 
			
		||||
    // copy it from the last dash value.
 | 
			
		||||
    // NOTE: last value is the offset and last-1 is the last dash value.
 | 
			
		||||
    auto size = result.size();
 | 
			
		||||
    if ((size % 2) == 0) {
 | 
			
		||||
        // copy offset value to end.
 | 
			
		||||
        result.push_back(result.back());
 | 
			
		||||
        // copy dash value to gap.
 | 
			
		||||
        result[size - 1] = result[size - 2];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Both the color stops and opacity stops are in the same array.
 | 
			
		||||
 * There are {@link #colorPoints} colors sequentially as:
 | 
			
		||||
 * [
 | 
			
		||||
 *     ...,
 | 
			
		||||
 *     position,
 | 
			
		||||
 *     red,
 | 
			
		||||
 *     green,
 | 
			
		||||
 *     blue,
 | 
			
		||||
 *     ...
 | 
			
		||||
 * ]
 | 
			
		||||
 *
 | 
			
		||||
 * The remainder of the array is the opacity stops sequentially as:
 | 
			
		||||
 * [
 | 
			
		||||
 *     ...,
 | 
			
		||||
 *     position,
 | 
			
		||||
 *     opacity,
 | 
			
		||||
 *     ...
 | 
			
		||||
 * ]
 | 
			
		||||
 */
 | 
			
		||||
void model::Gradient::populate(VGradientStops &stops, int frameNo)
 | 
			
		||||
{
 | 
			
		||||
    model::Gradient::Data gradData = mGradient.value(frameNo);
 | 
			
		||||
    auto                  size = gradData.mGradient.size();
 | 
			
		||||
    float *               ptr = gradData.mGradient.data();
 | 
			
		||||
    int                   colorPoints = mColorPoints;
 | 
			
		||||
    if (colorPoints == -1) {  // for legacy bodymovin (ref: lottie-android)
 | 
			
		||||
        colorPoints = int(size / 4);
 | 
			
		||||
    }
 | 
			
		||||
    auto   opacityArraySize = size - colorPoints * 4;
 | 
			
		||||
    float *opacityPtr = ptr + (colorPoints * 4);
 | 
			
		||||
    stops.clear();
 | 
			
		||||
    size_t j = 0;
 | 
			
		||||
    for (int i = 0; i < colorPoints; i++) {
 | 
			
		||||
        float        colorStop = ptr[0];
 | 
			
		||||
        model::Color color = model::Color(ptr[1], ptr[2], ptr[3]);
 | 
			
		||||
        if (opacityArraySize) {
 | 
			
		||||
            if (j == opacityArraySize) {
 | 
			
		||||
                // already reached the end
 | 
			
		||||
                float stop1 = opacityPtr[j - 4];
 | 
			
		||||
                float op1 = opacityPtr[j - 3];
 | 
			
		||||
                float stop2 = opacityPtr[j - 2];
 | 
			
		||||
                float op2 = opacityPtr[j - 1];
 | 
			
		||||
                if (colorStop > stop2) {
 | 
			
		||||
                    stops.push_back(
 | 
			
		||||
                        std::make_pair(colorStop, color.toColor(op2)));
 | 
			
		||||
                } else {
 | 
			
		||||
                    float progress = (colorStop - stop1) / (stop2 - stop1);
 | 
			
		||||
                    float opacity = op1 + progress * (op2 - op1);
 | 
			
		||||
                    stops.push_back(
 | 
			
		||||
                        std::make_pair(colorStop, color.toColor(opacity)));
 | 
			
		||||
                }
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            for (; j < opacityArraySize; j += 2) {
 | 
			
		||||
                float opacityStop = opacityPtr[j];
 | 
			
		||||
                if (opacityStop < colorStop) {
 | 
			
		||||
                    // add a color using opacity stop
 | 
			
		||||
                    stops.push_back(std::make_pair(
 | 
			
		||||
                        opacityStop, color.toColor(opacityPtr[j + 1])));
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                // add a color using color stop
 | 
			
		||||
                if (j == 0) {
 | 
			
		||||
                    stops.push_back(std::make_pair(
 | 
			
		||||
                        colorStop, color.toColor(opacityPtr[j + 1])));
 | 
			
		||||
                } else {
 | 
			
		||||
                    float progress = (colorStop - opacityPtr[j - 2]) /
 | 
			
		||||
                                     (opacityPtr[j] - opacityPtr[j - 2]);
 | 
			
		||||
                    float opacity =
 | 
			
		||||
                        opacityPtr[j - 1] +
 | 
			
		||||
                        progress * (opacityPtr[j + 1] - opacityPtr[j - 1]);
 | 
			
		||||
                    stops.push_back(
 | 
			
		||||
                        std::make_pair(colorStop, color.toColor(opacity)));
 | 
			
		||||
                }
 | 
			
		||||
                j += 2;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            stops.push_back(std::make_pair(colorStop, color.toColor()));
 | 
			
		||||
        }
 | 
			
		||||
        ptr += 4;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model::Gradient::update(std::unique_ptr<VGradient> &grad, int frameNo)
 | 
			
		||||
{
 | 
			
		||||
    bool init = false;
 | 
			
		||||
    if (!grad) {
 | 
			
		||||
        if (mGradientType == 1)
 | 
			
		||||
            grad = std::make_unique<VGradient>(VGradient::Type::Linear);
 | 
			
		||||
        else
 | 
			
		||||
            grad = std::make_unique<VGradient>(VGradient::Type::Radial);
 | 
			
		||||
        grad->mSpread = VGradient::Spread::Pad;
 | 
			
		||||
        init = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!mGradient.isStatic() || init) {
 | 
			
		||||
        populate(grad->mStops, frameNo);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (mGradientType == 1) {  // linear gradient
 | 
			
		||||
        VPointF start = mStartPoint.value(frameNo);
 | 
			
		||||
        VPointF end = mEndPoint.value(frameNo);
 | 
			
		||||
        grad->linear.x1 = start.x();
 | 
			
		||||
        grad->linear.y1 = start.y();
 | 
			
		||||
        grad->linear.x2 = end.x();
 | 
			
		||||
        grad->linear.y2 = end.y();
 | 
			
		||||
    } else {  // radial gradient
 | 
			
		||||
        VPointF start = mStartPoint.value(frameNo);
 | 
			
		||||
        VPointF end = mEndPoint.value(frameNo);
 | 
			
		||||
        grad->radial.cx = start.x();
 | 
			
		||||
        grad->radial.cy = start.y();
 | 
			
		||||
        grad->radial.cradius =
 | 
			
		||||
            VLine::length(start.x(), start.y(), end.x(), end.y());
 | 
			
		||||
        /*
 | 
			
		||||
         * Focal point is the point lives in highlight length distance from
 | 
			
		||||
         * center along the line (start, end)  and rotated by highlight angle.
 | 
			
		||||
         * below calculation first finds the quadrant(angle) on which the point
 | 
			
		||||
         * lives by applying inverse slope formula then adds the rotation angle
 | 
			
		||||
         * to find the final angle. then point is retrived using circle equation
 | 
			
		||||
         * of center, angle and distance.
 | 
			
		||||
         */
 | 
			
		||||
        float progress = mHighlightLength.value(frameNo) / 100.0f;
 | 
			
		||||
        if (vCompare(progress, 1.0f)) progress = 0.99f;
 | 
			
		||||
        float                  startAngle = VLine(start, end).angle();
 | 
			
		||||
        float                  highlightAngle = mHighlightAngle.value(frameNo);
 | 
			
		||||
        static constexpr float K_PI = 3.1415926f;
 | 
			
		||||
        float angle = (startAngle + highlightAngle) * (K_PI / 180.0f);
 | 
			
		||||
        grad->radial.fx =
 | 
			
		||||
            grad->radial.cx + std::cos(angle) * progress * grad->radial.cradius;
 | 
			
		||||
        grad->radial.fy =
 | 
			
		||||
            grad->radial.cy + std::sin(angle) * progress * grad->radial.cradius;
 | 
			
		||||
        // Lottie dosen't have any focal radius concept.
 | 
			
		||||
        grad->radial.fradius = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model::Asset::loadImageData(std::string data)
 | 
			
		||||
{
 | 
			
		||||
    if (!data.empty())
 | 
			
		||||
        mBitmap = VImageLoader::instance().load(data.c_str(), data.length());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model::Asset::loadImagePath(std::string path)
 | 
			
		||||
{
 | 
			
		||||
    if (!path.empty()) mBitmap = VImageLoader::instance().load(path.c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<LayerInfo> model::Composition::layerInfoList() const
 | 
			
		||||
{
 | 
			
		||||
    if (!mRootLayer || mRootLayer->mChildren.empty()) return {};
 | 
			
		||||
 | 
			
		||||
    std::vector<LayerInfo> result;
 | 
			
		||||
 | 
			
		||||
    result.reserve(mRootLayer->mChildren.size());
 | 
			
		||||
 | 
			
		||||
    for (auto it : mRootLayer->mChildren) {
 | 
			
		||||
        auto layer = static_cast<model::Layer *>(it);
 | 
			
		||||
        result.emplace_back(layer->name(), layer->mInFrame, layer->mOutFrame);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1148
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottiemodel.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1148
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottiemodel.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2390
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieparser.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2390
									
								
								vendor/github.com/Benau/go_rlottie/lottie_lottieparser.cpp
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										284
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_allocators.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_allocators.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,284 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_ALLOCATORS_H_
 | 
			
		||||
#define RAPIDJSON_ALLOCATORS_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Allocator
 | 
			
		||||
 | 
			
		||||
/*! \class rapidjson::Allocator
 | 
			
		||||
    \brief Concept for allocating, resizing and freeing memory block.
 | 
			
		||||
    
 | 
			
		||||
    Note that Malloc() and Realloc() are non-static but Free() is static.
 | 
			
		||||
    
 | 
			
		||||
    So if an allocator need to support Free(), it needs to put its pointer in 
 | 
			
		||||
    the header of memory block.
 | 
			
		||||
 | 
			
		||||
\code
 | 
			
		||||
concept Allocator {
 | 
			
		||||
    static const bool kNeedFree;    //!< Whether this allocator needs to call Free().
 | 
			
		||||
 | 
			
		||||
    // Allocate a memory block.
 | 
			
		||||
    // \param size of the memory block in bytes.
 | 
			
		||||
    // \returns pointer to the memory block.
 | 
			
		||||
    void* Malloc(size_t size);
 | 
			
		||||
 | 
			
		||||
    // Resize a memory block.
 | 
			
		||||
    // \param originalPtr The pointer to current memory block. Null pointer is permitted.
 | 
			
		||||
    // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
 | 
			
		||||
    // \param newSize the new size in bytes.
 | 
			
		||||
    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
 | 
			
		||||
 | 
			
		||||
    // Free a memory block.
 | 
			
		||||
    // \param pointer to the memory block. Null pointer is permitted.
 | 
			
		||||
    static void Free(void *ptr);
 | 
			
		||||
};
 | 
			
		||||
\endcode
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
 | 
			
		||||
    \ingroup RAPIDJSON_CONFIG
 | 
			
		||||
    \brief User-defined kDefaultChunkCapacity definition.
 | 
			
		||||
 | 
			
		||||
    User can define this as any \c size that is a power of 2.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
 | 
			
		||||
#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// CrtAllocator
 | 
			
		||||
 | 
			
		||||
//! C-runtime library allocator.
 | 
			
		||||
/*! This class is just wrapper for standard C library memory routines.
 | 
			
		||||
    \note implements Allocator concept
 | 
			
		||||
*/
 | 
			
		||||
class CrtAllocator {
 | 
			
		||||
public:
 | 
			
		||||
    static const bool kNeedFree = true;
 | 
			
		||||
    void* Malloc(size_t size) { 
 | 
			
		||||
        if (size) //  behavior of malloc(0) is implementation defined.
 | 
			
		||||
            return RAPIDJSON_MALLOC(size);
 | 
			
		||||
        else
 | 
			
		||||
            return NULL; // standardize to returning NULL.
 | 
			
		||||
    }
 | 
			
		||||
    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
 | 
			
		||||
        (void)originalSize;
 | 
			
		||||
        if (newSize == 0) {
 | 
			
		||||
            RAPIDJSON_FREE(originalPtr);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        return RAPIDJSON_REALLOC(originalPtr, newSize);
 | 
			
		||||
    }
 | 
			
		||||
    static void Free(void *ptr) { RAPIDJSON_FREE(ptr); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// MemoryPoolAllocator
 | 
			
		||||
 | 
			
		||||
//! Default memory allocator used by the parser and DOM.
 | 
			
		||||
/*! This allocator allocate memory blocks from pre-allocated memory chunks. 
 | 
			
		||||
 | 
			
		||||
    It does not free memory blocks. And Realloc() only allocate new memory.
 | 
			
		||||
 | 
			
		||||
    The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
 | 
			
		||||
 | 
			
		||||
    User may also supply a buffer as the first chunk.
 | 
			
		||||
 | 
			
		||||
    If the user-buffer is full then additional chunks are allocated by BaseAllocator.
 | 
			
		||||
 | 
			
		||||
    The user-buffer is not deallocated by this allocator.
 | 
			
		||||
 | 
			
		||||
    \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
 | 
			
		||||
    \note implements Allocator concept
 | 
			
		||||
*/
 | 
			
		||||
template <typename BaseAllocator = CrtAllocator>
 | 
			
		||||
class MemoryPoolAllocator {
 | 
			
		||||
public:
 | 
			
		||||
    static const bool kNeedFree = false;    //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
 | 
			
		||||
 | 
			
		||||
    //! Constructor with chunkSize.
 | 
			
		||||
    /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
 | 
			
		||||
        \param baseAllocator The allocator for allocating memory chunks.
 | 
			
		||||
    */
 | 
			
		||||
    MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 
 | 
			
		||||
        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Constructor with user-supplied buffer.
 | 
			
		||||
    /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
 | 
			
		||||
 | 
			
		||||
        The user buffer will not be deallocated when this allocator is destructed.
 | 
			
		||||
 | 
			
		||||
        \param buffer User supplied buffer.
 | 
			
		||||
        \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
 | 
			
		||||
        \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
 | 
			
		||||
        \param baseAllocator The allocator for allocating memory chunks.
 | 
			
		||||
    */
 | 
			
		||||
    MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
 | 
			
		||||
        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
 | 
			
		||||
    {
 | 
			
		||||
        RAPIDJSON_ASSERT(buffer != 0);
 | 
			
		||||
        RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
 | 
			
		||||
        chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
 | 
			
		||||
        chunkHead_->capacity = size - sizeof(ChunkHeader);
 | 
			
		||||
        chunkHead_->size = 0;
 | 
			
		||||
        chunkHead_->next = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Destructor.
 | 
			
		||||
    /*! This deallocates all memory chunks, excluding the user-supplied buffer.
 | 
			
		||||
    */
 | 
			
		||||
    ~MemoryPoolAllocator() {
 | 
			
		||||
        Clear();
 | 
			
		||||
        RAPIDJSON_DELETE(ownBaseAllocator_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Deallocates all memory chunks, excluding the user-supplied buffer.
 | 
			
		||||
    void Clear() {
 | 
			
		||||
        while (chunkHead_ && chunkHead_ != userBuffer_) {
 | 
			
		||||
            ChunkHeader* next = chunkHead_->next;
 | 
			
		||||
            baseAllocator_->Free(chunkHead_);
 | 
			
		||||
            chunkHead_ = next;
 | 
			
		||||
        }
 | 
			
		||||
        if (chunkHead_ && chunkHead_ == userBuffer_)
 | 
			
		||||
            chunkHead_->size = 0; // Clear user buffer
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Computes the total capacity of allocated memory chunks.
 | 
			
		||||
    /*! \return total capacity in bytes.
 | 
			
		||||
    */
 | 
			
		||||
    size_t Capacity() const {
 | 
			
		||||
        size_t capacity = 0;
 | 
			
		||||
        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
 | 
			
		||||
            capacity += c->capacity;
 | 
			
		||||
        return capacity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Computes the memory blocks allocated.
 | 
			
		||||
    /*! \return total used bytes.
 | 
			
		||||
    */
 | 
			
		||||
    size_t Size() const {
 | 
			
		||||
        size_t size = 0;
 | 
			
		||||
        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
 | 
			
		||||
            size += c->size;
 | 
			
		||||
        return size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Allocates a memory block. (concept Allocator)
 | 
			
		||||
    void* Malloc(size_t size) {
 | 
			
		||||
        if (!size)
 | 
			
		||||
            return NULL;
 | 
			
		||||
 | 
			
		||||
        size = RAPIDJSON_ALIGN(size);
 | 
			
		||||
        if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
 | 
			
		||||
            if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
 | 
			
		||||
                return NULL;
 | 
			
		||||
 | 
			
		||||
        void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
 | 
			
		||||
        chunkHead_->size += size;
 | 
			
		||||
        return buffer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Resizes a memory block (concept Allocator)
 | 
			
		||||
    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
 | 
			
		||||
        if (originalPtr == 0)
 | 
			
		||||
            return Malloc(newSize);
 | 
			
		||||
 | 
			
		||||
        if (newSize == 0)
 | 
			
		||||
            return NULL;
 | 
			
		||||
 | 
			
		||||
        originalSize = RAPIDJSON_ALIGN(originalSize);
 | 
			
		||||
        newSize = RAPIDJSON_ALIGN(newSize);
 | 
			
		||||
 | 
			
		||||
        // Do not shrink if new size is smaller than original
 | 
			
		||||
        if (originalSize >= newSize)
 | 
			
		||||
            return originalPtr;
 | 
			
		||||
 | 
			
		||||
        // Simply expand it if it is the last allocation and there is sufficient space
 | 
			
		||||
        if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
 | 
			
		||||
            size_t increment = static_cast<size_t>(newSize - originalSize);
 | 
			
		||||
            if (chunkHead_->size + increment <= chunkHead_->capacity) {
 | 
			
		||||
                chunkHead_->size += increment;
 | 
			
		||||
                return originalPtr;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Realloc process: allocate and copy memory, do not free original buffer.
 | 
			
		||||
        if (void* newBuffer = Malloc(newSize)) {
 | 
			
		||||
            if (originalSize)
 | 
			
		||||
                std::memcpy(newBuffer, originalPtr, originalSize);
 | 
			
		||||
            return newBuffer;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Frees a memory block (concept Allocator)
 | 
			
		||||
    static void Free(void *ptr) { (void)ptr; } // Do nothing
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //! Copy constructor is not permitted.
 | 
			
		||||
    MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
 | 
			
		||||
    //! Copy assignment operator is not permitted.
 | 
			
		||||
    MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
 | 
			
		||||
 | 
			
		||||
    //! Creates a new chunk.
 | 
			
		||||
    /*! \param capacity Capacity of the chunk in bytes.
 | 
			
		||||
        \return true if success.
 | 
			
		||||
    */
 | 
			
		||||
    bool AddChunk(size_t capacity) {
 | 
			
		||||
        if (!baseAllocator_)
 | 
			
		||||
            ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
 | 
			
		||||
        if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
 | 
			
		||||
            chunk->capacity = capacity;
 | 
			
		||||
            chunk->size = 0;
 | 
			
		||||
            chunk->next = chunkHead_;
 | 
			
		||||
            chunkHead_ =  chunk;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
 | 
			
		||||
 | 
			
		||||
    //! Chunk header for perpending to each chunk.
 | 
			
		||||
    /*! Chunks are stored as a singly linked list.
 | 
			
		||||
    */
 | 
			
		||||
    struct ChunkHeader {
 | 
			
		||||
        size_t capacity;    //!< Capacity of the chunk in bytes (excluding the header itself).
 | 
			
		||||
        size_t size;        //!< Current size of allocated memory in bytes.
 | 
			
		||||
        ChunkHeader *next;  //!< Next chunk in the linked list.
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ChunkHeader *chunkHead_;    //!< Head of the chunk linked-list. Only the head chunk serves allocation.
 | 
			
		||||
    size_t chunk_capacity_;     //!< The minimum capacity of chunk when they are allocated.
 | 
			
		||||
    void *userBuffer_;          //!< User supplied buffer.
 | 
			
		||||
    BaseAllocator* baseAllocator_;  //!< base allocator for allocating memory chunks.
 | 
			
		||||
    BaseAllocator* ownBaseAllocator_;   //!< base allocator created by this object.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_ENCODINGS_H_
 | 
			
		||||
							
								
								
									
										78
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_cursorstreamwrapper.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_cursorstreamwrapper.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_
 | 
			
		||||
#define RAPIDJSON_CURSORSTREAMWRAPPER_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_stream.h"
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__)
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(effc++)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(4702)  // unreachable code
 | 
			
		||||
RAPIDJSON_DIAG_OFF(4512)  // assignment operator could not be generated
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//! Cursor stream wrapper for counting line and column number if error exists.
 | 
			
		||||
/*!
 | 
			
		||||
    \tparam InputStream     Any stream that implements Stream Concept
 | 
			
		||||
*/
 | 
			
		||||
template <typename InputStream, typename Encoding = UTF8<> >
 | 
			
		||||
class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
 | 
			
		||||
public:
 | 
			
		||||
    typedef typename Encoding::Ch Ch;
 | 
			
		||||
 | 
			
		||||
    CursorStreamWrapper(InputStream& is):
 | 
			
		||||
        GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}
 | 
			
		||||
 | 
			
		||||
    // counting line and column number
 | 
			
		||||
    Ch Take() {
 | 
			
		||||
        Ch ch = this->is_.Take();
 | 
			
		||||
        if(ch == '\n') {
 | 
			
		||||
            line_ ++;
 | 
			
		||||
            col_ = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            col_ ++;
 | 
			
		||||
        }
 | 
			
		||||
        return ch;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Get the error line number, if error exists.
 | 
			
		||||
    size_t GetLine() const { return line_; }
 | 
			
		||||
    //! Get the error column number, if error exists.
 | 
			
		||||
    size_t GetColumn() const { return col_; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    size_t line_;   //!< Current Line
 | 
			
		||||
    size_t col_;    //!< Current Column
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__)
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_
 | 
			
		||||
							
								
								
									
										2732
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_document.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2732
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_document.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										299
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_encodedstream.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_encodedstream.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,299 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
 | 
			
		||||
#define RAPIDJSON_ENCODEDSTREAM_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_stream.h"
 | 
			
		||||
#include "lottie_rapidjson_memorystream.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(effc++)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(padded)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
//! Input byte stream wrapper with a statically bound encoding.
 | 
			
		||||
/*!
 | 
			
		||||
    \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
 | 
			
		||||
    \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
 | 
			
		||||
*/
 | 
			
		||||
template <typename Encoding, typename InputByteStream>
 | 
			
		||||
class EncodedInputStream {
 | 
			
		||||
    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
public:
 | 
			
		||||
    typedef typename Encoding::Ch Ch;
 | 
			
		||||
 | 
			
		||||
    EncodedInputStream(InputByteStream& is) : is_(is) { 
 | 
			
		||||
        current_ = Encoding::TakeBOM(is_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ch Peek() const { return current_; }
 | 
			
		||||
    Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
 | 
			
		||||
    size_t Tell() const { return is_.Tell(); }
 | 
			
		||||
 | 
			
		||||
    // Not implemented
 | 
			
		||||
    void Put(Ch) { RAPIDJSON_ASSERT(false); }
 | 
			
		||||
    void Flush() { RAPIDJSON_ASSERT(false); } 
 | 
			
		||||
    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    EncodedInputStream(const EncodedInputStream&);
 | 
			
		||||
    EncodedInputStream& operator=(const EncodedInputStream&);
 | 
			
		||||
 | 
			
		||||
    InputByteStream& is_;
 | 
			
		||||
    Ch current_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! Specialized for UTF8 MemoryStream.
 | 
			
		||||
template <>
 | 
			
		||||
class EncodedInputStream<UTF8<>, MemoryStream> {
 | 
			
		||||
public:
 | 
			
		||||
    typedef UTF8<>::Ch Ch;
 | 
			
		||||
 | 
			
		||||
    EncodedInputStream(MemoryStream& is) : is_(is) {
 | 
			
		||||
        if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
 | 
			
		||||
        if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
 | 
			
		||||
        if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
 | 
			
		||||
    }
 | 
			
		||||
    Ch Peek() const { return is_.Peek(); }
 | 
			
		||||
    Ch Take() { return is_.Take(); }
 | 
			
		||||
    size_t Tell() const { return is_.Tell(); }
 | 
			
		||||
 | 
			
		||||
    // Not implemented
 | 
			
		||||
    void Put(Ch) {}
 | 
			
		||||
    void Flush() {} 
 | 
			
		||||
    Ch* PutBegin() { return 0; }
 | 
			
		||||
    size_t PutEnd(Ch*) { return 0; }
 | 
			
		||||
 | 
			
		||||
    MemoryStream& is_;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    EncodedInputStream(const EncodedInputStream&);
 | 
			
		||||
    EncodedInputStream& operator=(const EncodedInputStream&);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! Output byte stream wrapper with statically bound encoding.
 | 
			
		||||
/*!
 | 
			
		||||
    \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
 | 
			
		||||
    \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
 | 
			
		||||
*/
 | 
			
		||||
template <typename Encoding, typename OutputByteStream>
 | 
			
		||||
class EncodedOutputStream {
 | 
			
		||||
    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
public:
 | 
			
		||||
    typedef typename Encoding::Ch Ch;
 | 
			
		||||
 | 
			
		||||
    EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { 
 | 
			
		||||
        if (putBOM)
 | 
			
		||||
            Encoding::PutBOM(os_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Put(Ch c) { Encoding::Put(os_, c);  }
 | 
			
		||||
    void Flush() { os_.Flush(); }
 | 
			
		||||
 | 
			
		||||
    // Not implemented
 | 
			
		||||
    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
 | 
			
		||||
    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
 | 
			
		||||
    size_t Tell() const { RAPIDJSON_ASSERT(false);  return 0; }
 | 
			
		||||
    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    EncodedOutputStream(const EncodedOutputStream&);
 | 
			
		||||
    EncodedOutputStream& operator=(const EncodedOutputStream&);
 | 
			
		||||
 | 
			
		||||
    OutputByteStream& os_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
 | 
			
		||||
 | 
			
		||||
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
 | 
			
		||||
/*!
 | 
			
		||||
    \tparam CharType Type of character for reading.
 | 
			
		||||
    \tparam InputByteStream type of input byte stream to be wrapped.
 | 
			
		||||
*/
 | 
			
		||||
template <typename CharType, typename InputByteStream>
 | 
			
		||||
class AutoUTFInputStream {
 | 
			
		||||
    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
public:
 | 
			
		||||
    typedef CharType Ch;
 | 
			
		||||
 | 
			
		||||
    //! Constructor.
 | 
			
		||||
    /*!
 | 
			
		||||
        \param is input stream to be wrapped.
 | 
			
		||||
        \param type UTF encoding type if it is not detected from the stream.
 | 
			
		||||
    */
 | 
			
		||||
    AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
 | 
			
		||||
        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);        
 | 
			
		||||
        DetectType();
 | 
			
		||||
        static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
 | 
			
		||||
        takeFunc_ = f[type_];
 | 
			
		||||
        current_ = takeFunc_(*is_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    UTFType GetType() const { return type_; }
 | 
			
		||||
    bool HasBOM() const { return hasBOM_; }
 | 
			
		||||
 | 
			
		||||
    Ch Peek() const { return current_; }
 | 
			
		||||
    Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
 | 
			
		||||
    size_t Tell() const { return is_->Tell(); }
 | 
			
		||||
 | 
			
		||||
    // Not implemented
 | 
			
		||||
    void Put(Ch) { RAPIDJSON_ASSERT(false); }
 | 
			
		||||
    void Flush() { RAPIDJSON_ASSERT(false); } 
 | 
			
		||||
    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    AutoUTFInputStream(const AutoUTFInputStream&);
 | 
			
		||||
    AutoUTFInputStream& operator=(const AutoUTFInputStream&);
 | 
			
		||||
 | 
			
		||||
    // Detect encoding type with BOM or RFC 4627
 | 
			
		||||
    void DetectType() {
 | 
			
		||||
        // BOM (Byte Order Mark):
 | 
			
		||||
        // 00 00 FE FF  UTF-32BE
 | 
			
		||||
        // FF FE 00 00  UTF-32LE
 | 
			
		||||
        // FE FF        UTF-16BE
 | 
			
		||||
        // FF FE        UTF-16LE
 | 
			
		||||
        // EF BB BF     UTF-8
 | 
			
		||||
 | 
			
		||||
        const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
 | 
			
		||||
        if (!c)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
 | 
			
		||||
        hasBOM_ = false;
 | 
			
		||||
        if (bom == 0xFFFE0000)                  { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
 | 
			
		||||
        else if (bom == 0x0000FEFF)             { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
 | 
			
		||||
        else if ((bom & 0xFFFF) == 0xFFFE)      { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take();                           }
 | 
			
		||||
        else if ((bom & 0xFFFF) == 0xFEFF)      { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take();                           }
 | 
			
		||||
        else if ((bom & 0xFFFFFF) == 0xBFBBEF)  { type_ = kUTF8;    hasBOM_ = true; is_->Take(); is_->Take(); is_->Take();              }
 | 
			
		||||
 | 
			
		||||
        // RFC 4627: Section 3
 | 
			
		||||
        // "Since the first two characters of a JSON text will always be ASCII
 | 
			
		||||
        // characters [RFC0020], it is possible to determine whether an octet
 | 
			
		||||
        // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
 | 
			
		||||
        // at the pattern of nulls in the first four octets."
 | 
			
		||||
        // 00 00 00 xx  UTF-32BE
 | 
			
		||||
        // 00 xx 00 xx  UTF-16BE
 | 
			
		||||
        // xx 00 00 00  UTF-32LE
 | 
			
		||||
        // xx 00 xx 00  UTF-16LE
 | 
			
		||||
        // xx xx xx xx  UTF-8
 | 
			
		||||
 | 
			
		||||
        if (!hasBOM_) {
 | 
			
		||||
            int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
 | 
			
		||||
            switch (pattern) {
 | 
			
		||||
            case 0x08: type_ = kUTF32BE; break;
 | 
			
		||||
            case 0x0A: type_ = kUTF16BE; break;
 | 
			
		||||
            case 0x01: type_ = kUTF32LE; break;
 | 
			
		||||
            case 0x05: type_ = kUTF16LE; break;
 | 
			
		||||
            case 0x0F: type_ = kUTF8;    break;
 | 
			
		||||
            default: break; // Use type defined by user.
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
 | 
			
		||||
        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
 | 
			
		||||
        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    typedef Ch (*TakeFunc)(InputByteStream& is);
 | 
			
		||||
    InputByteStream* is_;
 | 
			
		||||
    UTFType type_;
 | 
			
		||||
    Ch current_;
 | 
			
		||||
    TakeFunc takeFunc_;
 | 
			
		||||
    bool hasBOM_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
 | 
			
		||||
/*!
 | 
			
		||||
    \tparam CharType Type of character for writing.
 | 
			
		||||
    \tparam OutputByteStream type of output byte stream to be wrapped.
 | 
			
		||||
*/
 | 
			
		||||
template <typename CharType, typename OutputByteStream>
 | 
			
		||||
class AutoUTFOutputStream {
 | 
			
		||||
    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
public:
 | 
			
		||||
    typedef CharType Ch;
 | 
			
		||||
 | 
			
		||||
    //! Constructor.
 | 
			
		||||
    /*!
 | 
			
		||||
        \param os output stream to be wrapped.
 | 
			
		||||
        \param type UTF encoding type.
 | 
			
		||||
        \param putBOM Whether to write BOM at the beginning of the stream.
 | 
			
		||||
    */
 | 
			
		||||
    AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
 | 
			
		||||
        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
 | 
			
		||||
 | 
			
		||||
        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
 | 
			
		||||
        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
 | 
			
		||||
        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
 | 
			
		||||
 | 
			
		||||
        static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
 | 
			
		||||
        putFunc_ = f[type_];
 | 
			
		||||
 | 
			
		||||
        if (putBOM)
 | 
			
		||||
            PutBOM();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    UTFType GetType() const { return type_; }
 | 
			
		||||
 | 
			
		||||
    void Put(Ch c) { putFunc_(*os_, c); }
 | 
			
		||||
    void Flush() { os_->Flush(); } 
 | 
			
		||||
 | 
			
		||||
    // Not implemented
 | 
			
		||||
    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
 | 
			
		||||
    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
 | 
			
		||||
    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    AutoUTFOutputStream(const AutoUTFOutputStream&);
 | 
			
		||||
    AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
 | 
			
		||||
 | 
			
		||||
    void PutBOM() { 
 | 
			
		||||
        typedef void (*PutBOMFunc)(OutputByteStream&);
 | 
			
		||||
        static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
 | 
			
		||||
        f[type_](*os_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    typedef void (*PutFunc)(OutputByteStream&, Ch);
 | 
			
		||||
 | 
			
		||||
    OutputByteStream* os_;
 | 
			
		||||
    UTFType type_;
 | 
			
		||||
    PutFunc putFunc_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#undef RAPIDJSON_ENCODINGS_FUNC
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_FILESTREAM_H_
 | 
			
		||||
							
								
								
									
										716
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_encodings.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										716
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_encodings.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,716 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_ENCODINGS_H_
 | 
			
		||||
#define RAPIDJSON_ENCODINGS_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && !defined(__clang__)
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
 | 
			
		||||
RAPIDJSON_DIAG_OFF(4702)  // unreachable code
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(effc++)
 | 
			
		||||
RAPIDJSON_DIAG_OFF(overflow)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Encoding
 | 
			
		||||
 | 
			
		||||
/*! \class rapidjson::Encoding
 | 
			
		||||
    \brief Concept for encoding of Unicode characters.
 | 
			
		||||
 | 
			
		||||
\code
 | 
			
		||||
concept Encoding {
 | 
			
		||||
    typename Ch;    //! Type of character. A "character" is actually a code unit in unicode's definition.
 | 
			
		||||
 | 
			
		||||
    enum { supportUnicode = 1 }; // or 0 if not supporting unicode
 | 
			
		||||
 | 
			
		||||
    //! \brief Encode a Unicode codepoint to an output stream.
 | 
			
		||||
    //! \param os Output stream.
 | 
			
		||||
    //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static void Encode(OutputStream& os, unsigned codepoint);
 | 
			
		||||
 | 
			
		||||
    //! \brief Decode a Unicode codepoint from an input stream.
 | 
			
		||||
    //! \param is Input stream.
 | 
			
		||||
    //! \param codepoint Output of the unicode codepoint.
 | 
			
		||||
    //! \return true if a valid codepoint can be decoded from the stream.
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    static bool Decode(InputStream& is, unsigned* codepoint);
 | 
			
		||||
 | 
			
		||||
    //! \brief Validate one Unicode codepoint from an encoded stream.
 | 
			
		||||
    //! \param is Input stream to obtain codepoint.
 | 
			
		||||
    //! \param os Output for copying one codepoint.
 | 
			
		||||
    //! \return true if it is valid.
 | 
			
		||||
    //! \note This function just validating and copying the codepoint without actually decode it.
 | 
			
		||||
    template <typename InputStream, typename OutputStream>
 | 
			
		||||
    static bool Validate(InputStream& is, OutputStream& os);
 | 
			
		||||
 | 
			
		||||
    // The following functions are deal with byte streams.
 | 
			
		||||
 | 
			
		||||
    //! Take a character from input byte stream, skip BOM if exist.
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType TakeBOM(InputByteStream& is);
 | 
			
		||||
 | 
			
		||||
    //! Take a character from input byte stream.
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static Ch Take(InputByteStream& is);
 | 
			
		||||
 | 
			
		||||
    //! Put BOM to output byte stream.
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void PutBOM(OutputByteStream& os);
 | 
			
		||||
 | 
			
		||||
    //! Put a character to output byte stream.
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void Put(OutputByteStream& os, Ch c);
 | 
			
		||||
};
 | 
			
		||||
\endcode
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// UTF8
 | 
			
		||||
 | 
			
		||||
//! UTF-8 encoding.
 | 
			
		||||
/*! http://en.wikipedia.org/wiki/UTF-8
 | 
			
		||||
    http://tools.ietf.org/html/rfc3629
 | 
			
		||||
    \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
 | 
			
		||||
    \note implements Encoding concept
 | 
			
		||||
*/
 | 
			
		||||
template<typename CharType = char>
 | 
			
		||||
struct UTF8 {
 | 
			
		||||
    typedef CharType Ch;
 | 
			
		||||
 | 
			
		||||
    enum { supportUnicode = 1 };
 | 
			
		||||
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static void Encode(OutputStream& os, unsigned codepoint) {
 | 
			
		||||
        if (codepoint <= 0x7F) 
 | 
			
		||||
            os.Put(static_cast<Ch>(codepoint & 0xFF));
 | 
			
		||||
        else if (codepoint <= 0x7FF) {
 | 
			
		||||
            os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
 | 
			
		||||
            os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
 | 
			
		||||
        }
 | 
			
		||||
        else if (codepoint <= 0xFFFF) {
 | 
			
		||||
            os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
 | 
			
		||||
            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
 | 
			
		||||
            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
 | 
			
		||||
            os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
 | 
			
		||||
            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
 | 
			
		||||
            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
 | 
			
		||||
            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
 | 
			
		||||
        if (codepoint <= 0x7F) 
 | 
			
		||||
            PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
 | 
			
		||||
        else if (codepoint <= 0x7FF) {
 | 
			
		||||
            PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
 | 
			
		||||
            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
 | 
			
		||||
        }
 | 
			
		||||
        else if (codepoint <= 0xFFFF) {
 | 
			
		||||
            PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
 | 
			
		||||
            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
 | 
			
		||||
            PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
 | 
			
		||||
            PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
 | 
			
		||||
            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
 | 
			
		||||
            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
 | 
			
		||||
            PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    static bool Decode(InputStream& is, unsigned* codepoint) {
 | 
			
		||||
#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
 | 
			
		||||
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
 | 
			
		||||
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
 | 
			
		||||
        typename InputStream::Ch c = is.Take();
 | 
			
		||||
        if (!(c & 0x80)) {
 | 
			
		||||
            *codepoint = static_cast<unsigned char>(c);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        unsigned char type = GetRange(static_cast<unsigned char>(c));
 | 
			
		||||
        if (type >= 32) {
 | 
			
		||||
            *codepoint = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            *codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);
 | 
			
		||||
        }
 | 
			
		||||
        bool result = true;
 | 
			
		||||
        switch (type) {
 | 
			
		||||
        case 2: RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        default: return false;
 | 
			
		||||
        }
 | 
			
		||||
#undef RAPIDJSON_COPY
 | 
			
		||||
#undef RAPIDJSON_TRANS
 | 
			
		||||
#undef RAPIDJSON_TAIL
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream, typename OutputStream>
 | 
			
		||||
    static bool Validate(InputStream& is, OutputStream& os) {
 | 
			
		||||
#define RAPIDJSON_COPY() os.Put(c = is.Take())
 | 
			
		||||
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
 | 
			
		||||
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
 | 
			
		||||
        Ch c;
 | 
			
		||||
        RAPIDJSON_COPY();
 | 
			
		||||
        if (!(c & 0x80))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        bool result = true;
 | 
			
		||||
        switch (GetRange(static_cast<unsigned char>(c))) {
 | 
			
		||||
        case 2: RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
 | 
			
		||||
        default: return false;
 | 
			
		||||
        }
 | 
			
		||||
#undef RAPIDJSON_COPY
 | 
			
		||||
#undef RAPIDJSON_TRANS
 | 
			
		||||
#undef RAPIDJSON_TAIL
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static unsigned char GetRange(unsigned char c) {
 | 
			
		||||
        // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
 | 
			
		||||
        // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
 | 
			
		||||
        static const unsigned char type[] = {
 | 
			
		||||
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 | 
			
		||||
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 | 
			
		||||
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 | 
			
		||||
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 | 
			
		||||
            0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
 | 
			
		||||
            0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
 | 
			
		||||
            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
 | 
			
		||||
            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
 | 
			
		||||
            8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
 | 
			
		||||
            10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
 | 
			
		||||
        };
 | 
			
		||||
        return type[c];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType TakeBOM(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        typename InputByteStream::Ch c = Take(is);
 | 
			
		||||
        if (static_cast<unsigned char>(c) != 0xEFu) return c;
 | 
			
		||||
        c = is.Take();
 | 
			
		||||
        if (static_cast<unsigned char>(c) != 0xBBu) return c;
 | 
			
		||||
        c = is.Take();
 | 
			
		||||
        if (static_cast<unsigned char>(c) != 0xBFu) return c;
 | 
			
		||||
        c = is.Take();
 | 
			
		||||
        return c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static Ch Take(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        return static_cast<Ch>(is.Take());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void PutBOM(OutputByteStream& os) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void Put(OutputByteStream& os, Ch c) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(c));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// UTF16
 | 
			
		||||
 | 
			
		||||
//! UTF-16 encoding.
 | 
			
		||||
/*! http://en.wikipedia.org/wiki/UTF-16
 | 
			
		||||
    http://tools.ietf.org/html/rfc2781
 | 
			
		||||
    \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
 | 
			
		||||
    \note implements Encoding concept
 | 
			
		||||
 | 
			
		||||
    \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
 | 
			
		||||
    For streaming, use UTF16LE and UTF16BE, which handle endianness.
 | 
			
		||||
*/
 | 
			
		||||
template<typename CharType = wchar_t>
 | 
			
		||||
struct UTF16 {
 | 
			
		||||
    typedef CharType Ch;
 | 
			
		||||
    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
 | 
			
		||||
 | 
			
		||||
    enum { supportUnicode = 1 };
 | 
			
		||||
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static void Encode(OutputStream& os, unsigned codepoint) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
 | 
			
		||||
        if (codepoint <= 0xFFFF) {
 | 
			
		||||
            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair 
 | 
			
		||||
            os.Put(static_cast<typename OutputStream::Ch>(codepoint));
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
 | 
			
		||||
            unsigned v = codepoint - 0x10000;
 | 
			
		||||
            os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
 | 
			
		||||
            os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
 | 
			
		||||
        if (codepoint <= 0xFFFF) {
 | 
			
		||||
            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair 
 | 
			
		||||
            PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
 | 
			
		||||
            unsigned v = codepoint - 0x10000;
 | 
			
		||||
            PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
 | 
			
		||||
            PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    static bool Decode(InputStream& is, unsigned* codepoint) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
 | 
			
		||||
        typename InputStream::Ch c = is.Take();
 | 
			
		||||
        if (c < 0xD800 || c > 0xDFFF) {
 | 
			
		||||
            *codepoint = static_cast<unsigned>(c);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else if (c <= 0xDBFF) {
 | 
			
		||||
            *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
 | 
			
		||||
            c = is.Take();
 | 
			
		||||
            *codepoint |= (static_cast<unsigned>(c) & 0x3FF);
 | 
			
		||||
            *codepoint += 0x10000;
 | 
			
		||||
            return c >= 0xDC00 && c <= 0xDFFF;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream, typename OutputStream>
 | 
			
		||||
    static bool Validate(InputStream& is, OutputStream& os) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
 | 
			
		||||
        typename InputStream::Ch c;
 | 
			
		||||
        os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
 | 
			
		||||
        if (c < 0xD800 || c > 0xDFFF)
 | 
			
		||||
            return true;
 | 
			
		||||
        else if (c <= 0xDBFF) {
 | 
			
		||||
            os.Put(c = is.Take());
 | 
			
		||||
            return c >= 0xDC00 && c <= 0xDFFF;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! UTF-16 little endian encoding.
 | 
			
		||||
template<typename CharType = wchar_t>
 | 
			
		||||
struct UTF16LE : UTF16<CharType> {
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType TakeBOM(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        CharType c = Take(is);
 | 
			
		||||
        return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType Take(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        unsigned c = static_cast<uint8_t>(is.Take());
 | 
			
		||||
        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
 | 
			
		||||
        return static_cast<CharType>(c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void PutBOM(OutputByteStream& os) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void Put(OutputByteStream& os, CharType c) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! UTF-16 big endian encoding.
 | 
			
		||||
template<typename CharType = wchar_t>
 | 
			
		||||
struct UTF16BE : UTF16<CharType> {
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType TakeBOM(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        CharType c = Take(is);
 | 
			
		||||
        return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType Take(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
 | 
			
		||||
        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
 | 
			
		||||
        return static_cast<CharType>(c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void PutBOM(OutputByteStream& os) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void Put(OutputByteStream& os, CharType c) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// UTF32
 | 
			
		||||
 | 
			
		||||
//! UTF-32 encoding. 
 | 
			
		||||
/*! http://en.wikipedia.org/wiki/UTF-32
 | 
			
		||||
    \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
 | 
			
		||||
    \note implements Encoding concept
 | 
			
		||||
 | 
			
		||||
    \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
 | 
			
		||||
    For streaming, use UTF32LE and UTF32BE, which handle endianness.
 | 
			
		||||
*/
 | 
			
		||||
template<typename CharType = unsigned>
 | 
			
		||||
struct UTF32 {
 | 
			
		||||
    typedef CharType Ch;
 | 
			
		||||
    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
 | 
			
		||||
 | 
			
		||||
    enum { supportUnicode = 1 };
 | 
			
		||||
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static void Encode(OutputStream& os, unsigned codepoint) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
 | 
			
		||||
        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
 | 
			
		||||
        os.Put(codepoint);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
 | 
			
		||||
        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
 | 
			
		||||
        PutUnsafe(os, codepoint);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    static bool Decode(InputStream& is, unsigned* codepoint) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
 | 
			
		||||
        Ch c = is.Take();
 | 
			
		||||
        *codepoint = c;
 | 
			
		||||
        return c <= 0x10FFFF;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream, typename OutputStream>
 | 
			
		||||
    static bool Validate(InputStream& is, OutputStream& os) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
 | 
			
		||||
        Ch c;
 | 
			
		||||
        os.Put(c = is.Take());
 | 
			
		||||
        return c <= 0x10FFFF;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! UTF-32 little endian enocoding.
 | 
			
		||||
template<typename CharType = unsigned>
 | 
			
		||||
struct UTF32LE : UTF32<CharType> {
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType TakeBOM(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        CharType c = Take(is);
 | 
			
		||||
        return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType Take(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        unsigned c = static_cast<uint8_t>(is.Take());
 | 
			
		||||
        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
 | 
			
		||||
        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
 | 
			
		||||
        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
 | 
			
		||||
        return static_cast<CharType>(c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void PutBOM(OutputByteStream& os) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void Put(OutputByteStream& os, CharType c) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! UTF-32 big endian encoding.
 | 
			
		||||
template<typename CharType = unsigned>
 | 
			
		||||
struct UTF32BE : UTF32<CharType> {
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType TakeBOM(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        CharType c = Take(is);
 | 
			
		||||
        return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c; 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType Take(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
 | 
			
		||||
        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
 | 
			
		||||
        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
 | 
			
		||||
        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
 | 
			
		||||
        return static_cast<CharType>(c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void PutBOM(OutputByteStream& os) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void Put(OutputByteStream& os, CharType c) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// ASCII
 | 
			
		||||
 | 
			
		||||
//! ASCII encoding.
 | 
			
		||||
/*! http://en.wikipedia.org/wiki/ASCII
 | 
			
		||||
    \tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
 | 
			
		||||
    \note implements Encoding concept
 | 
			
		||||
*/
 | 
			
		||||
template<typename CharType = char>
 | 
			
		||||
struct ASCII {
 | 
			
		||||
    typedef CharType Ch;
 | 
			
		||||
 | 
			
		||||
    enum { supportUnicode = 0 };
 | 
			
		||||
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static void Encode(OutputStream& os, unsigned codepoint) {
 | 
			
		||||
        RAPIDJSON_ASSERT(codepoint <= 0x7F);
 | 
			
		||||
        os.Put(static_cast<Ch>(codepoint & 0xFF));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
 | 
			
		||||
        RAPIDJSON_ASSERT(codepoint <= 0x7F);
 | 
			
		||||
        PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    static bool Decode(InputStream& is, unsigned* codepoint) {
 | 
			
		||||
        uint8_t c = static_cast<uint8_t>(is.Take());
 | 
			
		||||
        *codepoint = c;
 | 
			
		||||
        return c <= 0X7F;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream, typename OutputStream>
 | 
			
		||||
    static bool Validate(InputStream& is, OutputStream& os) {
 | 
			
		||||
        uint8_t c = static_cast<uint8_t>(is.Take());
 | 
			
		||||
        os.Put(static_cast<typename OutputStream::Ch>(c));
 | 
			
		||||
        return c <= 0x7F;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static CharType TakeBOM(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        uint8_t c = static_cast<uint8_t>(Take(is));
 | 
			
		||||
        return static_cast<Ch>(c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputByteStream>
 | 
			
		||||
    static Ch Take(InputByteStream& is) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
 | 
			
		||||
        return static_cast<Ch>(is.Take());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void PutBOM(OutputByteStream& os) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        (void)os;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename OutputByteStream>
 | 
			
		||||
    static void Put(OutputByteStream& os, Ch c) {
 | 
			
		||||
        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
 | 
			
		||||
        os.Put(static_cast<typename OutputByteStream::Ch>(c));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// AutoUTF
 | 
			
		||||
 | 
			
		||||
//! Runtime-specified UTF encoding type of a stream.
 | 
			
		||||
enum UTFType {
 | 
			
		||||
    kUTF8 = 0,      //!< UTF-8.
 | 
			
		||||
    kUTF16LE = 1,   //!< UTF-16 little endian.
 | 
			
		||||
    kUTF16BE = 2,   //!< UTF-16 big endian.
 | 
			
		||||
    kUTF32LE = 3,   //!< UTF-32 little endian.
 | 
			
		||||
    kUTF32BE = 4    //!< UTF-32 big endian.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
 | 
			
		||||
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
 | 
			
		||||
*/
 | 
			
		||||
template<typename CharType>
 | 
			
		||||
struct AutoUTF {
 | 
			
		||||
    typedef CharType Ch;
 | 
			
		||||
 | 
			
		||||
    enum { supportUnicode = 1 };
 | 
			
		||||
 | 
			
		||||
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
 | 
			
		||||
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {
 | 
			
		||||
        typedef void (*EncodeFunc)(OutputStream&, unsigned);
 | 
			
		||||
        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
 | 
			
		||||
        (*f[os.GetType()])(os, codepoint);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename OutputStream>
 | 
			
		||||
    static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
 | 
			
		||||
        typedef void (*EncodeFunc)(OutputStream&, unsigned);
 | 
			
		||||
        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
 | 
			
		||||
        (*f[os.GetType()])(os, codepoint);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) {
 | 
			
		||||
        typedef bool (*DecodeFunc)(InputStream&, unsigned*);
 | 
			
		||||
        static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
 | 
			
		||||
        return (*f[is.GetType()])(is, codepoint);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream, typename OutputStream>
 | 
			
		||||
    static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
 | 
			
		||||
        typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
 | 
			
		||||
        static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
 | 
			
		||||
        return (*f[is.GetType()])(is, os);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#undef RAPIDJSON_ENCODINGS_FUNC
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Transcoder
 | 
			
		||||
 | 
			
		||||
//! Encoding conversion.
 | 
			
		||||
template<typename SourceEncoding, typename TargetEncoding>
 | 
			
		||||
struct Transcoder {
 | 
			
		||||
    //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
 | 
			
		||||
    template<typename InputStream, typename OutputStream>
 | 
			
		||||
    static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
 | 
			
		||||
        unsigned codepoint;
 | 
			
		||||
        if (!SourceEncoding::Decode(is, &codepoint))
 | 
			
		||||
            return false;
 | 
			
		||||
        TargetEncoding::Encode(os, codepoint);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename InputStream, typename OutputStream>
 | 
			
		||||
    static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
 | 
			
		||||
        unsigned codepoint;
 | 
			
		||||
        if (!SourceEncoding::Decode(is, &codepoint))
 | 
			
		||||
            return false;
 | 
			
		||||
        TargetEncoding::EncodeUnsafe(os, codepoint);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Validate one Unicode codepoint from an encoded stream.
 | 
			
		||||
    template<typename InputStream, typename OutputStream>
 | 
			
		||||
    static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
 | 
			
		||||
        return Transcode(is, os);   // Since source/target encoding is different, must transcode.
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Forward declaration.
 | 
			
		||||
template<typename Stream>
 | 
			
		||||
inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
 | 
			
		||||
 | 
			
		||||
//! Specialization of Transcoder with same source and target encoding.
 | 
			
		||||
template<typename Encoding>
 | 
			
		||||
struct Transcoder<Encoding, Encoding> {
 | 
			
		||||
    template<typename InputStream, typename OutputStream>
 | 
			
		||||
    static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
 | 
			
		||||
        os.Put(is.Take());  // Just copy one code unit. This semantic is different from primary template class.
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<typename InputStream, typename OutputStream>
 | 
			
		||||
    static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
 | 
			
		||||
        PutUnsafe(os, is.Take());  // Just copy one code unit. This semantic is different from primary template class.
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<typename InputStream, typename OutputStream>
 | 
			
		||||
    static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
 | 
			
		||||
        return Encoding::Validate(is, os);  // source/target encoding are the same
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__))
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_ENCODINGS_H_
 | 
			
		||||
							
								
								
									
										74
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_error_en.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_error_en.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_ERROR_EN_H_
 | 
			
		||||
#define RAPIDJSON_ERROR_EN_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_error_error.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(switch-enum)
 | 
			
		||||
RAPIDJSON_DIAG_OFF(covered-switch-default)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
//! Maps error code of parsing into error message.
 | 
			
		||||
/*!
 | 
			
		||||
    \ingroup RAPIDJSON_ERRORS
 | 
			
		||||
    \param parseErrorCode Error code obtained in parsing.
 | 
			
		||||
    \return the error message.
 | 
			
		||||
    \note User can make a copy of this function for localization.
 | 
			
		||||
        Using switch-case is safer for future modification of error codes.
 | 
			
		||||
*/
 | 
			
		||||
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
 | 
			
		||||
    switch (parseErrorCode) {
 | 
			
		||||
        case kParseErrorNone:                           return RAPIDJSON_ERROR_STRING("No error.");
 | 
			
		||||
 | 
			
		||||
        case kParseErrorDocumentEmpty:                  return RAPIDJSON_ERROR_STRING("The document is empty.");
 | 
			
		||||
        case kParseErrorDocumentRootNotSingular:        return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
 | 
			
		||||
    
 | 
			
		||||
        case kParseErrorValueInvalid:                   return RAPIDJSON_ERROR_STRING("Invalid value.");
 | 
			
		||||
    
 | 
			
		||||
        case kParseErrorObjectMissName:                 return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
 | 
			
		||||
        case kParseErrorObjectMissColon:                return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
 | 
			
		||||
        case kParseErrorObjectMissCommaOrCurlyBracket:  return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
 | 
			
		||||
    
 | 
			
		||||
        case kParseErrorArrayMissCommaOrSquareBracket:  return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
 | 
			
		||||
 | 
			
		||||
        case kParseErrorStringUnicodeEscapeInvalidHex:  return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
 | 
			
		||||
        case kParseErrorStringUnicodeSurrogateInvalid:  return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
 | 
			
		||||
        case kParseErrorStringEscapeInvalid:            return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
 | 
			
		||||
        case kParseErrorStringMissQuotationMark:        return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
 | 
			
		||||
        case kParseErrorStringInvalidEncoding:          return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
 | 
			
		||||
 | 
			
		||||
        case kParseErrorNumberTooBig:                   return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
 | 
			
		||||
        case kParseErrorNumberMissFraction:             return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
 | 
			
		||||
        case kParseErrorNumberMissExponent:             return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
 | 
			
		||||
 | 
			
		||||
        case kParseErrorTermination:                    return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
 | 
			
		||||
        case kParseErrorUnspecificSyntaxError:          return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
 | 
			
		||||
 | 
			
		||||
        default:                                        return RAPIDJSON_ERROR_STRING("Unknown error.");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_ERROR_EN_H_
 | 
			
		||||
							
								
								
									
										161
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_error_error.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_error_error.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_ERROR_ERROR_H_
 | 
			
		||||
#define RAPIDJSON_ERROR_ERROR_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(padded)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*! \file error.h */
 | 
			
		||||
 | 
			
		||||
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// RAPIDJSON_ERROR_CHARTYPE
 | 
			
		||||
 | 
			
		||||
//! Character type of error messages.
 | 
			
		||||
/*! \ingroup RAPIDJSON_ERRORS
 | 
			
		||||
    The default character type is \c char.
 | 
			
		||||
    On Windows, user can define this macro as \c TCHAR for supporting both
 | 
			
		||||
    unicode/non-unicode settings.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef RAPIDJSON_ERROR_CHARTYPE
 | 
			
		||||
#define RAPIDJSON_ERROR_CHARTYPE char
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// RAPIDJSON_ERROR_STRING
 | 
			
		||||
 | 
			
		||||
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
 | 
			
		||||
/*! \ingroup RAPIDJSON_ERRORS
 | 
			
		||||
    By default this conversion macro does nothing.
 | 
			
		||||
    On Windows, user can define this macro as \c _T(x) for supporting both
 | 
			
		||||
    unicode/non-unicode settings.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef RAPIDJSON_ERROR_STRING
 | 
			
		||||
#define RAPIDJSON_ERROR_STRING(x) x
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// ParseErrorCode
 | 
			
		||||
 | 
			
		||||
//! Error code of parsing.
 | 
			
		||||
/*! \ingroup RAPIDJSON_ERRORS
 | 
			
		||||
    \see GenericReader::Parse, GenericReader::GetParseErrorCode
 | 
			
		||||
*/
 | 
			
		||||
enum ParseErrorCode {
 | 
			
		||||
    kParseErrorNone = 0,                        //!< No error.
 | 
			
		||||
 | 
			
		||||
    kParseErrorDocumentEmpty,                   //!< The document is empty.
 | 
			
		||||
    kParseErrorDocumentRootNotSingular,         //!< The document root must not follow by other values.
 | 
			
		||||
 | 
			
		||||
    kParseErrorValueInvalid,                    //!< Invalid value.
 | 
			
		||||
 | 
			
		||||
    kParseErrorObjectMissName,                  //!< Missing a name for object member.
 | 
			
		||||
    kParseErrorObjectMissColon,                 //!< Missing a colon after a name of object member.
 | 
			
		||||
    kParseErrorObjectMissCommaOrCurlyBracket,   //!< Missing a comma or '}' after an object member.
 | 
			
		||||
 | 
			
		||||
    kParseErrorArrayMissCommaOrSquareBracket,   //!< Missing a comma or ']' after an array element.
 | 
			
		||||
 | 
			
		||||
    kParseErrorStringUnicodeEscapeInvalidHex,   //!< Incorrect hex digit after \\u escape in string.
 | 
			
		||||
    kParseErrorStringUnicodeSurrogateInvalid,   //!< The surrogate pair in string is invalid.
 | 
			
		||||
    kParseErrorStringEscapeInvalid,             //!< Invalid escape character in string.
 | 
			
		||||
    kParseErrorStringMissQuotationMark,         //!< Missing a closing quotation mark in string.
 | 
			
		||||
    kParseErrorStringInvalidEncoding,           //!< Invalid encoding in string.
 | 
			
		||||
 | 
			
		||||
    kParseErrorNumberTooBig,                    //!< Number too big to be stored in double.
 | 
			
		||||
    kParseErrorNumberMissFraction,              //!< Miss fraction part in number.
 | 
			
		||||
    kParseErrorNumberMissExponent,              //!< Miss exponent in number.
 | 
			
		||||
 | 
			
		||||
    kParseErrorTermination,                     //!< Parsing was terminated.
 | 
			
		||||
    kParseErrorUnspecificSyntaxError            //!< Unspecific syntax error.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! Result of parsing (wraps ParseErrorCode)
 | 
			
		||||
/*!
 | 
			
		||||
    \ingroup RAPIDJSON_ERRORS
 | 
			
		||||
    \code
 | 
			
		||||
        Document doc;
 | 
			
		||||
        ParseResult ok = doc.Parse("[42]");
 | 
			
		||||
        if (!ok) {
 | 
			
		||||
            fprintf(stderr, "JSON parse error: %s (%u)",
 | 
			
		||||
                    GetParseError_En(ok.Code()), ok.Offset());
 | 
			
		||||
            exit(EXIT_FAILURE);
 | 
			
		||||
        }
 | 
			
		||||
    \endcode
 | 
			
		||||
    \see GenericReader::Parse, GenericDocument::Parse
 | 
			
		||||
*/
 | 
			
		||||
struct ParseResult {
 | 
			
		||||
    //!! Unspecified boolean type
 | 
			
		||||
    typedef bool (ParseResult::*BooleanType)() const;
 | 
			
		||||
public:
 | 
			
		||||
    //! Default constructor, no error.
 | 
			
		||||
    ParseResult() : code_(kParseErrorNone), offset_(0) {}
 | 
			
		||||
    //! Constructor to set an error.
 | 
			
		||||
    ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
 | 
			
		||||
 | 
			
		||||
    //! Get the error code.
 | 
			
		||||
    ParseErrorCode Code() const { return code_; }
 | 
			
		||||
    //! Get the error offset, if \ref IsError(), 0 otherwise.
 | 
			
		||||
    size_t Offset() const { return offset_; }
 | 
			
		||||
 | 
			
		||||
    //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
 | 
			
		||||
    operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
 | 
			
		||||
    //! Whether the result is an error.
 | 
			
		||||
    bool IsError() const { return code_ != kParseErrorNone; }
 | 
			
		||||
 | 
			
		||||
    bool operator==(const ParseResult& that) const { return code_ == that.code_; }
 | 
			
		||||
    bool operator==(ParseErrorCode code) const { return code_ == code; }
 | 
			
		||||
    friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
 | 
			
		||||
 | 
			
		||||
    bool operator!=(const ParseResult& that) const { return !(*this == that); }
 | 
			
		||||
    bool operator!=(ParseErrorCode code) const { return !(*this == code); }
 | 
			
		||||
    friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }
 | 
			
		||||
 | 
			
		||||
    //! Reset error code.
 | 
			
		||||
    void Clear() { Set(kParseErrorNone); }
 | 
			
		||||
    //! Update error code and offset.
 | 
			
		||||
    void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ParseErrorCode code_;
 | 
			
		||||
    size_t offset_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! Function pointer type of GetParseError().
 | 
			
		||||
/*! \ingroup RAPIDJSON_ERRORS
 | 
			
		||||
 | 
			
		||||
    This is the prototype for \c GetParseError_X(), where \c X is a locale.
 | 
			
		||||
    User can dynamically change locale in runtime, e.g.:
 | 
			
		||||
\code
 | 
			
		||||
    GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
 | 
			
		||||
    const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
 | 
			
		||||
\endcode
 | 
			
		||||
*/
 | 
			
		||||
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_ERROR_ERROR_H_
 | 
			
		||||
							
								
								
									
										99
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_filereadstream.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_filereadstream.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_FILEREADSTREAM_H_
 | 
			
		||||
#define RAPIDJSON_FILEREADSTREAM_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_stream.h"
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(padded)
 | 
			
		||||
RAPIDJSON_DIAG_OFF(unreachable-code)
 | 
			
		||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
//! File byte stream for input using fread().
 | 
			
		||||
/*!
 | 
			
		||||
    \note implements Stream concept
 | 
			
		||||
*/
 | 
			
		||||
class FileReadStream {
 | 
			
		||||
public:
 | 
			
		||||
    typedef char Ch;    //!< Character type (byte).
 | 
			
		||||
 | 
			
		||||
    //! Constructor.
 | 
			
		||||
    /*!
 | 
			
		||||
        \param fp File pointer opened for read.
 | 
			
		||||
        \param buffer user-supplied buffer.
 | 
			
		||||
        \param bufferSize size of buffer in bytes. Must >=4 bytes.
 | 
			
		||||
    */
 | 
			
		||||
    FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 
 | 
			
		||||
        RAPIDJSON_ASSERT(fp_ != 0);
 | 
			
		||||
        RAPIDJSON_ASSERT(bufferSize >= 4);
 | 
			
		||||
        Read();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ch Peek() const { return *current_; }
 | 
			
		||||
    Ch Take() { Ch c = *current_; Read(); return c; }
 | 
			
		||||
    size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
 | 
			
		||||
 | 
			
		||||
    // Not implemented
 | 
			
		||||
    void Put(Ch) { RAPIDJSON_ASSERT(false); }
 | 
			
		||||
    void Flush() { RAPIDJSON_ASSERT(false); } 
 | 
			
		||||
    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
 | 
			
		||||
    // For encoding detection only.
 | 
			
		||||
    const Ch* Peek4() const {
 | 
			
		||||
        return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void Read() {
 | 
			
		||||
        if (current_ < bufferLast_)
 | 
			
		||||
            ++current_;
 | 
			
		||||
        else if (!eof_) {
 | 
			
		||||
            count_ += readCount_;
 | 
			
		||||
            readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
 | 
			
		||||
            bufferLast_ = buffer_ + readCount_ - 1;
 | 
			
		||||
            current_ = buffer_;
 | 
			
		||||
 | 
			
		||||
            if (readCount_ < bufferSize_) {
 | 
			
		||||
                buffer_[readCount_] = '\0';
 | 
			
		||||
                ++bufferLast_;
 | 
			
		||||
                eof_ = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::FILE* fp_;
 | 
			
		||||
    Ch *buffer_;
 | 
			
		||||
    size_t bufferSize_;
 | 
			
		||||
    Ch *bufferLast_;
 | 
			
		||||
    Ch *current_;
 | 
			
		||||
    size_t readCount_;
 | 
			
		||||
    size_t count_;  //!< Number of characters read
 | 
			
		||||
    bool eof_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_FILESTREAM_H_
 | 
			
		||||
							
								
								
									
										104
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_filewritestream.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_filewritestream.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
 | 
			
		||||
#define RAPIDJSON_FILEWRITESTREAM_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_stream.h"
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(unreachable-code)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
//! Wrapper of C file stream for output using fwrite().
 | 
			
		||||
/*!
 | 
			
		||||
    \note implements Stream concept
 | 
			
		||||
*/
 | 
			
		||||
class FileWriteStream {
 | 
			
		||||
public:
 | 
			
		||||
    typedef char Ch;    //!< Character type. Only support char.
 | 
			
		||||
 | 
			
		||||
    FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 
 | 
			
		||||
        RAPIDJSON_ASSERT(fp_ != 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Put(char c) { 
 | 
			
		||||
        if (current_ >= bufferEnd_)
 | 
			
		||||
            Flush();
 | 
			
		||||
 | 
			
		||||
        *current_++ = c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PutN(char c, size_t n) {
 | 
			
		||||
        size_t avail = static_cast<size_t>(bufferEnd_ - current_);
 | 
			
		||||
        while (n > avail) {
 | 
			
		||||
            std::memset(current_, c, avail);
 | 
			
		||||
            current_ += avail;
 | 
			
		||||
            Flush();
 | 
			
		||||
            n -= avail;
 | 
			
		||||
            avail = static_cast<size_t>(bufferEnd_ - current_);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (n > 0) {
 | 
			
		||||
            std::memset(current_, c, n);
 | 
			
		||||
            current_ += n;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Flush() {
 | 
			
		||||
        if (current_ != buffer_) {
 | 
			
		||||
            size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
 | 
			
		||||
            if (result < static_cast<size_t>(current_ - buffer_)) {
 | 
			
		||||
                // failure deliberately ignored at this time
 | 
			
		||||
                // added to avoid warn_unused_result build errors
 | 
			
		||||
            }
 | 
			
		||||
            current_ = buffer_;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Not implemented
 | 
			
		||||
    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    char Take() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // Prohibit copy constructor & assignment operator.
 | 
			
		||||
    FileWriteStream(const FileWriteStream&);
 | 
			
		||||
    FileWriteStream& operator=(const FileWriteStream&);
 | 
			
		||||
 | 
			
		||||
    std::FILE* fp_;
 | 
			
		||||
    char *buffer_;
 | 
			
		||||
    char *bufferEnd_;
 | 
			
		||||
    char *current_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//! Implement specialized version of PutN() with memset() for better performance.
 | 
			
		||||
template<>
 | 
			
		||||
inline void PutN(FileWriteStream& stream, char c, size_t n) {
 | 
			
		||||
    stream.PutN(c, n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_FILESTREAM_H_
 | 
			
		||||
							
								
								
									
										151
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_fwd.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_fwd.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_FWD_H_
 | 
			
		||||
#define RAPIDJSON_FWD_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
// encodings.h
 | 
			
		||||
 | 
			
		||||
template<typename CharType> struct UTF8;
 | 
			
		||||
template<typename CharType> struct UTF16;
 | 
			
		||||
template<typename CharType> struct UTF16BE;
 | 
			
		||||
template<typename CharType> struct UTF16LE;
 | 
			
		||||
template<typename CharType> struct UTF32;
 | 
			
		||||
template<typename CharType> struct UTF32BE;
 | 
			
		||||
template<typename CharType> struct UTF32LE;
 | 
			
		||||
template<typename CharType> struct ASCII;
 | 
			
		||||
template<typename CharType> struct AutoUTF;
 | 
			
		||||
 | 
			
		||||
template<typename SourceEncoding, typename TargetEncoding>
 | 
			
		||||
struct Transcoder;
 | 
			
		||||
 | 
			
		||||
// allocators.h
 | 
			
		||||
 | 
			
		||||
class CrtAllocator;
 | 
			
		||||
 | 
			
		||||
template <typename BaseAllocator>
 | 
			
		||||
class MemoryPoolAllocator;
 | 
			
		||||
 | 
			
		||||
// stream.h
 | 
			
		||||
 | 
			
		||||
template <typename Encoding>
 | 
			
		||||
struct GenericStringStream;
 | 
			
		||||
 | 
			
		||||
typedef GenericStringStream<UTF8<char> > StringStream;
 | 
			
		||||
 | 
			
		||||
template <typename Encoding>
 | 
			
		||||
struct GenericInsituStringStream;
 | 
			
		||||
 | 
			
		||||
typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
 | 
			
		||||
 | 
			
		||||
// stringbuffer.h
 | 
			
		||||
 | 
			
		||||
template <typename Encoding, typename Allocator>
 | 
			
		||||
class GenericStringBuffer;
 | 
			
		||||
 | 
			
		||||
typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
 | 
			
		||||
 | 
			
		||||
// filereadstream.h
 | 
			
		||||
 | 
			
		||||
class FileReadStream;
 | 
			
		||||
 | 
			
		||||
// filewritestream.h
 | 
			
		||||
 | 
			
		||||
class FileWriteStream;
 | 
			
		||||
 | 
			
		||||
// memorybuffer.h
 | 
			
		||||
 | 
			
		||||
template <typename Allocator>
 | 
			
		||||
struct GenericMemoryBuffer;
 | 
			
		||||
 | 
			
		||||
typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
 | 
			
		||||
 | 
			
		||||
// memorystream.h
 | 
			
		||||
 | 
			
		||||
struct MemoryStream;
 | 
			
		||||
 | 
			
		||||
// reader.h
 | 
			
		||||
 | 
			
		||||
template<typename Encoding, typename Derived>
 | 
			
		||||
struct BaseReaderHandler;
 | 
			
		||||
 | 
			
		||||
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
 | 
			
		||||
class GenericReader;
 | 
			
		||||
 | 
			
		||||
typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
 | 
			
		||||
 | 
			
		||||
// writer.h
 | 
			
		||||
 | 
			
		||||
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
 | 
			
		||||
class Writer;
 | 
			
		||||
 | 
			
		||||
// prettywriter.h
 | 
			
		||||
 | 
			
		||||
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
 | 
			
		||||
class PrettyWriter;
 | 
			
		||||
 | 
			
		||||
// document.h
 | 
			
		||||
 | 
			
		||||
template <typename Encoding, typename Allocator> 
 | 
			
		||||
class GenericMember;
 | 
			
		||||
 | 
			
		||||
template <bool Const, typename Encoding, typename Allocator>
 | 
			
		||||
class GenericMemberIterator;
 | 
			
		||||
 | 
			
		||||
template<typename CharType>
 | 
			
		||||
struct GenericStringRef;
 | 
			
		||||
 | 
			
		||||
template <typename Encoding, typename Allocator> 
 | 
			
		||||
class GenericValue;
 | 
			
		||||
 | 
			
		||||
typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
 | 
			
		||||
 | 
			
		||||
template <typename Encoding, typename Allocator, typename StackAllocator>
 | 
			
		||||
class GenericDocument;
 | 
			
		||||
 | 
			
		||||
typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
 | 
			
		||||
 | 
			
		||||
// pointer.h
 | 
			
		||||
 | 
			
		||||
template <typename ValueType, typename Allocator>
 | 
			
		||||
class GenericPointer;
 | 
			
		||||
 | 
			
		||||
typedef GenericPointer<Value, CrtAllocator> Pointer;
 | 
			
		||||
 | 
			
		||||
// schema.h
 | 
			
		||||
 | 
			
		||||
template <typename SchemaDocumentType>
 | 
			
		||||
class IGenericRemoteSchemaDocumentProvider;
 | 
			
		||||
 | 
			
		||||
template <typename ValueT, typename Allocator>
 | 
			
		||||
class GenericSchemaDocument;
 | 
			
		||||
 | 
			
		||||
typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
 | 
			
		||||
typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
 | 
			
		||||
 | 
			
		||||
template <
 | 
			
		||||
    typename SchemaDocumentType,
 | 
			
		||||
    typename OutputHandler,
 | 
			
		||||
    typename StateAllocator>
 | 
			
		||||
class GenericSchemaValidator;
 | 
			
		||||
 | 
			
		||||
typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_RAPIDJSONFWD_H_
 | 
			
		||||
							
								
								
									
										290
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_biginteger.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_biginteger.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,290 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_BIGINTEGER_H_
 | 
			
		||||
#define RAPIDJSON_BIGINTEGER_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64)
 | 
			
		||||
#include <intrin.h> // for _umul128
 | 
			
		||||
#pragma intrinsic(_umul128)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
class BigInteger {
 | 
			
		||||
public:
 | 
			
		||||
    typedef uint64_t Type;
 | 
			
		||||
 | 
			
		||||
    BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
 | 
			
		||||
        std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    explicit BigInteger(uint64_t u) : count_(1) {
 | 
			
		||||
        digits_[0] = u;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BigInteger(const char* decimals, size_t length) : count_(1) {
 | 
			
		||||
        RAPIDJSON_ASSERT(length > 0);
 | 
			
		||||
        digits_[0] = 0;
 | 
			
		||||
        size_t i = 0;
 | 
			
		||||
        const size_t kMaxDigitPerIteration = 19;  // 2^64 = 18446744073709551616 > 10^19
 | 
			
		||||
        while (length >= kMaxDigitPerIteration) {
 | 
			
		||||
            AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
 | 
			
		||||
            length -= kMaxDigitPerIteration;
 | 
			
		||||
            i += kMaxDigitPerIteration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (length > 0)
 | 
			
		||||
            AppendDecimal64(decimals + i, decimals + i + length);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    BigInteger& operator=(const BigInteger &rhs)
 | 
			
		||||
    {
 | 
			
		||||
        if (this != &rhs) {
 | 
			
		||||
            count_ = rhs.count_;
 | 
			
		||||
            std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
 | 
			
		||||
        }
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    BigInteger& operator=(uint64_t u) {
 | 
			
		||||
        digits_[0] = u;            
 | 
			
		||||
        count_ = 1;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BigInteger& operator+=(uint64_t u) {
 | 
			
		||||
        Type backup = digits_[0];
 | 
			
		||||
        digits_[0] += u;
 | 
			
		||||
        for (size_t i = 0; i < count_ - 1; i++) {
 | 
			
		||||
            if (digits_[i] >= backup)
 | 
			
		||||
                return *this; // no carry
 | 
			
		||||
            backup = digits_[i + 1];
 | 
			
		||||
            digits_[i + 1] += 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Last carry
 | 
			
		||||
        if (digits_[count_ - 1] < backup)
 | 
			
		||||
            PushBack(1);
 | 
			
		||||
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BigInteger& operator*=(uint64_t u) {
 | 
			
		||||
        if (u == 0) return *this = 0;
 | 
			
		||||
        if (u == 1) return *this;
 | 
			
		||||
        if (*this == 1) return *this = u;
 | 
			
		||||
 | 
			
		||||
        uint64_t k = 0;
 | 
			
		||||
        for (size_t i = 0; i < count_; i++) {
 | 
			
		||||
            uint64_t hi;
 | 
			
		||||
            digits_[i] = MulAdd64(digits_[i], u, k, &hi);
 | 
			
		||||
            k = hi;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (k > 0)
 | 
			
		||||
            PushBack(k);
 | 
			
		||||
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BigInteger& operator*=(uint32_t u) {
 | 
			
		||||
        if (u == 0) return *this = 0;
 | 
			
		||||
        if (u == 1) return *this;
 | 
			
		||||
        if (*this == 1) return *this = u;
 | 
			
		||||
 | 
			
		||||
        uint64_t k = 0;
 | 
			
		||||
        for (size_t i = 0; i < count_; i++) {
 | 
			
		||||
            const uint64_t c = digits_[i] >> 32;
 | 
			
		||||
            const uint64_t d = digits_[i] & 0xFFFFFFFF;
 | 
			
		||||
            const uint64_t uc = u * c;
 | 
			
		||||
            const uint64_t ud = u * d;
 | 
			
		||||
            const uint64_t p0 = ud + k;
 | 
			
		||||
            const uint64_t p1 = uc + (p0 >> 32);
 | 
			
		||||
            digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
 | 
			
		||||
            k = p1 >> 32;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (k > 0)
 | 
			
		||||
            PushBack(k);
 | 
			
		||||
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BigInteger& operator<<=(size_t shift) {
 | 
			
		||||
        if (IsZero() || shift == 0) return *this;
 | 
			
		||||
 | 
			
		||||
        size_t offset = shift / kTypeBit;
 | 
			
		||||
        size_t interShift = shift % kTypeBit;
 | 
			
		||||
        RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
 | 
			
		||||
 | 
			
		||||
        if (interShift == 0) {
 | 
			
		||||
            std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
 | 
			
		||||
            count_ += offset;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            digits_[count_] = 0;
 | 
			
		||||
            for (size_t i = count_; i > 0; i--)
 | 
			
		||||
                digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
 | 
			
		||||
            digits_[offset] = digits_[0] << interShift;
 | 
			
		||||
            count_ += offset;
 | 
			
		||||
            if (digits_[count_])
 | 
			
		||||
                count_++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::memset(digits_, 0, offset * sizeof(Type));
 | 
			
		||||
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator==(const BigInteger& rhs) const {
 | 
			
		||||
        return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator==(const Type rhs) const {
 | 
			
		||||
        return count_ == 1 && digits_[0] == rhs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BigInteger& MultiplyPow5(unsigned exp) {
 | 
			
		||||
        static const uint32_t kPow5[12] = {
 | 
			
		||||
            5,
 | 
			
		||||
            5 * 5,
 | 
			
		||||
            5 * 5 * 5,
 | 
			
		||||
            5 * 5 * 5 * 5,
 | 
			
		||||
            5 * 5 * 5 * 5 * 5,
 | 
			
		||||
            5 * 5 * 5 * 5 * 5 * 5,
 | 
			
		||||
            5 * 5 * 5 * 5 * 5 * 5 * 5,
 | 
			
		||||
            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
 | 
			
		||||
            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
 | 
			
		||||
            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
 | 
			
		||||
            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
 | 
			
		||||
            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
 | 
			
		||||
        };
 | 
			
		||||
        if (exp == 0) return *this;
 | 
			
		||||
        for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
 | 
			
		||||
        for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
 | 
			
		||||
        if (exp > 0)                 *this *= kPow5[exp - 1];
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Compute absolute difference of this and rhs.
 | 
			
		||||
    // Assume this != rhs
 | 
			
		||||
    bool Difference(const BigInteger& rhs, BigInteger* out) const {
 | 
			
		||||
        int cmp = Compare(rhs);
 | 
			
		||||
        RAPIDJSON_ASSERT(cmp != 0);
 | 
			
		||||
        const BigInteger *a, *b;  // Makes a > b
 | 
			
		||||
        bool ret;
 | 
			
		||||
        if (cmp < 0) { a = &rhs; b = this; ret = true; }
 | 
			
		||||
        else         { a = this; b = &rhs; ret = false; }
 | 
			
		||||
 | 
			
		||||
        Type borrow = 0;
 | 
			
		||||
        for (size_t i = 0; i < a->count_; i++) {
 | 
			
		||||
            Type d = a->digits_[i] - borrow;
 | 
			
		||||
            if (i < b->count_)
 | 
			
		||||
                d -= b->digits_[i];
 | 
			
		||||
            borrow = (d > a->digits_[i]) ? 1 : 0;
 | 
			
		||||
            out->digits_[i] = d;
 | 
			
		||||
            if (d != 0)
 | 
			
		||||
                out->count_ = i + 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int Compare(const BigInteger& rhs) const {
 | 
			
		||||
        if (count_ != rhs.count_)
 | 
			
		||||
            return count_ < rhs.count_ ? -1 : 1;
 | 
			
		||||
 | 
			
		||||
        for (size_t i = count_; i-- > 0;)
 | 
			
		||||
            if (digits_[i] != rhs.digits_[i])
 | 
			
		||||
                return digits_[i] < rhs.digits_[i] ? -1 : 1;
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t GetCount() const { return count_; }
 | 
			
		||||
    Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
 | 
			
		||||
    bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void AppendDecimal64(const char* begin, const char* end) {
 | 
			
		||||
        uint64_t u = ParseUint64(begin, end);
 | 
			
		||||
        if (IsZero())
 | 
			
		||||
            *this = u;
 | 
			
		||||
        else {
 | 
			
		||||
            unsigned exp = static_cast<unsigned>(end - begin);
 | 
			
		||||
            (MultiplyPow5(exp) <<= exp) += u;   // *this = *this * 10^exp + u
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PushBack(Type digit) {
 | 
			
		||||
        RAPIDJSON_ASSERT(count_ < kCapacity);
 | 
			
		||||
        digits_[count_++] = digit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static uint64_t ParseUint64(const char* begin, const char* end) {
 | 
			
		||||
        uint64_t r = 0;
 | 
			
		||||
        for (const char* p = begin; p != end; ++p) {
 | 
			
		||||
            RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
 | 
			
		||||
            r = r * 10u + static_cast<unsigned>(*p - '0');
 | 
			
		||||
        }
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Assume a * b + k < 2^128
 | 
			
		||||
    static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
 | 
			
		||||
#if defined(_MSC_VER) && defined(_M_AMD64)
 | 
			
		||||
        uint64_t low = _umul128(a, b, outHigh) + k;
 | 
			
		||||
        if (low < k)
 | 
			
		||||
            (*outHigh)++;
 | 
			
		||||
        return low;
 | 
			
		||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
 | 
			
		||||
        __extension__ typedef unsigned __int128 uint128;
 | 
			
		||||
        uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
 | 
			
		||||
        p += k;
 | 
			
		||||
        *outHigh = static_cast<uint64_t>(p >> 64);
 | 
			
		||||
        return static_cast<uint64_t>(p);
 | 
			
		||||
#else
 | 
			
		||||
        const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
 | 
			
		||||
        uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
 | 
			
		||||
        x1 += (x0 >> 32); // can't give carry
 | 
			
		||||
        x1 += x2;
 | 
			
		||||
        if (x1 < x2)
 | 
			
		||||
            x3 += (static_cast<uint64_t>(1) << 32);
 | 
			
		||||
        uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
 | 
			
		||||
        uint64_t hi = x3 + (x1 >> 32);
 | 
			
		||||
 | 
			
		||||
        lo += k;
 | 
			
		||||
        if (lo < k)
 | 
			
		||||
            hi++;
 | 
			
		||||
        *outHigh = hi;
 | 
			
		||||
        return lo;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const size_t kBitCount = 3328;  // 64bit * 54 > 10^1000
 | 
			
		||||
    static const size_t kCapacity = kBitCount / sizeof(Type);
 | 
			
		||||
    static const size_t kTypeBit = sizeof(Type) * 8;
 | 
			
		||||
 | 
			
		||||
    Type digits_[kCapacity];
 | 
			
		||||
    size_t count_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_BIGINTEGER_H_
 | 
			
		||||
							
								
								
									
										71
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_clzll.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_clzll.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_CLZLL_H_
 | 
			
		||||
#define RAPIDJSON_CLZLL_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && !defined(UNDER_CE)
 | 
			
		||||
#include <intrin.h>
 | 
			
		||||
#if defined(_WIN64)
 | 
			
		||||
#pragma intrinsic(_BitScanReverse64)
 | 
			
		||||
#else
 | 
			
		||||
#pragma intrinsic(_BitScanReverse)
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
inline uint32_t clzll(uint64_t x) {
 | 
			
		||||
    // Passing 0 to __builtin_clzll is UB in GCC and results in an
 | 
			
		||||
    // infinite loop in the software implementation.
 | 
			
		||||
    RAPIDJSON_ASSERT(x != 0);
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && !defined(UNDER_CE)
 | 
			
		||||
    unsigned long r = 0;
 | 
			
		||||
#if defined(_WIN64)
 | 
			
		||||
    _BitScanReverse64(&r, x);
 | 
			
		||||
#else
 | 
			
		||||
    // Scan the high 32 bits.
 | 
			
		||||
    if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
 | 
			
		||||
        return 63 - (r + 32);
 | 
			
		||||
 | 
			
		||||
    // Scan the low 32 bits.
 | 
			
		||||
    _BitScanReverse(&r, static_cast<uint32_t>(x & 0xFFFFFFFF));
 | 
			
		||||
#endif // _WIN64
 | 
			
		||||
 | 
			
		||||
    return 63 - r;
 | 
			
		||||
#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll)
 | 
			
		||||
    // __builtin_clzll wrapper
 | 
			
		||||
    return static_cast<uint32_t>(__builtin_clzll(x));
 | 
			
		||||
#else
 | 
			
		||||
    // naive version
 | 
			
		||||
    uint32_t r = 0;
 | 
			
		||||
    while (!(x & (static_cast<uint64_t>(1) << 63))) {
 | 
			
		||||
        x <<= 1;
 | 
			
		||||
        ++r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return r;
 | 
			
		||||
#endif // _MSC_VER
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_CLZLL_H_
 | 
			
		||||
							
								
								
									
										257
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_diyfp.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_diyfp.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,257 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
 | 
			
		||||
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
 | 
			
		||||
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_DIYFP_H_
 | 
			
		||||
#define RAPIDJSON_DIYFP_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
#include "lottie_rapidjson_internal_clzll.h"
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
 | 
			
		||||
#include <intrin.h>
 | 
			
		||||
#pragma intrinsic(_umul128)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(effc++)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(padded)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct DiyFp {
 | 
			
		||||
    DiyFp() : f(), e() {}
 | 
			
		||||
 | 
			
		||||
    DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
 | 
			
		||||
 | 
			
		||||
    explicit DiyFp(double d) {
 | 
			
		||||
        union {
 | 
			
		||||
            double d;
 | 
			
		||||
            uint64_t u64;
 | 
			
		||||
        } u = { d };
 | 
			
		||||
 | 
			
		||||
        int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
 | 
			
		||||
        uint64_t significand = (u.u64 & kDpSignificandMask);
 | 
			
		||||
        if (biased_e != 0) {
 | 
			
		||||
            f = significand + kDpHiddenBit;
 | 
			
		||||
            e = biased_e - kDpExponentBias;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            f = significand;
 | 
			
		||||
            e = kDpMinExponent + 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DiyFp operator-(const DiyFp& rhs) const {
 | 
			
		||||
        return DiyFp(f - rhs.f, e);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DiyFp operator*(const DiyFp& rhs) const {
 | 
			
		||||
#if defined(_MSC_VER) && defined(_M_AMD64)
 | 
			
		||||
        uint64_t h;
 | 
			
		||||
        uint64_t l = _umul128(f, rhs.f, &h);
 | 
			
		||||
        if (l & (uint64_t(1) << 63)) // rounding
 | 
			
		||||
            h++;
 | 
			
		||||
        return DiyFp(h, e + rhs.e + 64);
 | 
			
		||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
 | 
			
		||||
        __extension__ typedef unsigned __int128 uint128;
 | 
			
		||||
        uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
 | 
			
		||||
        uint64_t h = static_cast<uint64_t>(p >> 64);
 | 
			
		||||
        uint64_t l = static_cast<uint64_t>(p);
 | 
			
		||||
        if (l & (uint64_t(1) << 63)) // rounding
 | 
			
		||||
            h++;
 | 
			
		||||
        return DiyFp(h, e + rhs.e + 64);
 | 
			
		||||
#else
 | 
			
		||||
        const uint64_t M32 = 0xFFFFFFFF;
 | 
			
		||||
        const uint64_t a = f >> 32;
 | 
			
		||||
        const uint64_t b = f & M32;
 | 
			
		||||
        const uint64_t c = rhs.f >> 32;
 | 
			
		||||
        const uint64_t d = rhs.f & M32;
 | 
			
		||||
        const uint64_t ac = a * c;
 | 
			
		||||
        const uint64_t bc = b * c;
 | 
			
		||||
        const uint64_t ad = a * d;
 | 
			
		||||
        const uint64_t bd = b * d;
 | 
			
		||||
        uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
 | 
			
		||||
        tmp += 1U << 31;  /// mult_round
 | 
			
		||||
        return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DiyFp Normalize() const {
 | 
			
		||||
        int s = static_cast<int>(clzll(f));
 | 
			
		||||
        return DiyFp(f << s, e - s);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DiyFp NormalizeBoundary() const {
 | 
			
		||||
        DiyFp res = *this;
 | 
			
		||||
        while (!(res.f & (kDpHiddenBit << 1))) {
 | 
			
		||||
            res.f <<= 1;
 | 
			
		||||
            res.e--;
 | 
			
		||||
        }
 | 
			
		||||
        res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
 | 
			
		||||
        res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
 | 
			
		||||
        DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
 | 
			
		||||
        DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
 | 
			
		||||
        mi.f <<= mi.e - pl.e;
 | 
			
		||||
        mi.e = pl.e;
 | 
			
		||||
        *plus = pl;
 | 
			
		||||
        *minus = mi;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    double ToDouble() const {
 | 
			
		||||
        union {
 | 
			
		||||
            double d;
 | 
			
		||||
            uint64_t u64;
 | 
			
		||||
        }u;
 | 
			
		||||
        RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
 | 
			
		||||
        if (e < kDpDenormalExponent) {
 | 
			
		||||
            // Underflow.
 | 
			
		||||
            return 0.0;
 | 
			
		||||
        }
 | 
			
		||||
        if (e >= kDpMaxExponent) {
 | 
			
		||||
            // Overflow.
 | 
			
		||||
            return std::numeric_limits<double>::infinity();
 | 
			
		||||
        }
 | 
			
		||||
        const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
 | 
			
		||||
            static_cast<uint64_t>(e + kDpExponentBias);
 | 
			
		||||
        u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
 | 
			
		||||
        return u.d;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const int kDiySignificandSize = 64;
 | 
			
		||||
    static const int kDpSignificandSize = 52;
 | 
			
		||||
    static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
 | 
			
		||||
    static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
 | 
			
		||||
    static const int kDpMinExponent = -kDpExponentBias;
 | 
			
		||||
    static const int kDpDenormalExponent = -kDpExponentBias + 1;
 | 
			
		||||
    static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
 | 
			
		||||
    static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
 | 
			
		||||
    static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
 | 
			
		||||
 | 
			
		||||
    uint64_t f;
 | 
			
		||||
    int e;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline DiyFp GetCachedPowerByIndex(size_t index) {
 | 
			
		||||
    // 10^-348, 10^-340, ..., 10^340
 | 
			
		||||
    static const uint64_t kCachedPowers_F[] = {
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
 | 
			
		||||
        RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
 | 
			
		||||
    };
 | 
			
		||||
    static const int16_t kCachedPowers_E[] = {
 | 
			
		||||
        -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007,  -980,
 | 
			
		||||
        -954,  -927,  -901,  -874,  -847,  -821,  -794,  -768,  -741,  -715,
 | 
			
		||||
        -688,  -661,  -635,  -608,  -582,  -555,  -529,  -502,  -475,  -449,
 | 
			
		||||
        -422,  -396,  -369,  -343,  -316,  -289,  -263,  -236,  -210,  -183,
 | 
			
		||||
        -157,  -130,  -103,   -77,   -50,   -24,     3,    30,    56,    83,
 | 
			
		||||
        109,   136,   162,   189,   216,   242,   269,   295,   322,   348,
 | 
			
		||||
        375,   402,   428,   455,   481,   508,   534,   561,   588,   614,
 | 
			
		||||
        641,   667,   694,   720,   747,   774,   800,   827,   853,   880,
 | 
			
		||||
        907,   933,   960,   986,  1013,  1039,  1066
 | 
			
		||||
    };
 | 
			
		||||
    RAPIDJSON_ASSERT(index < 87);
 | 
			
		||||
    return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline DiyFp GetCachedPower(int e, int* K) {
 | 
			
		||||
 | 
			
		||||
    //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
 | 
			
		||||
    double dk = (-61 - e) * 0.30102999566398114 + 347;  // dk must be positive, so can do ceiling in positive
 | 
			
		||||
    int k = static_cast<int>(dk);
 | 
			
		||||
    if (dk - k > 0.0)
 | 
			
		||||
        k++;
 | 
			
		||||
 | 
			
		||||
    unsigned index = static_cast<unsigned>((k >> 3) + 1);
 | 
			
		||||
    *K = -(-348 + static_cast<int>(index << 3));    // decimal exponent no need lookup table
 | 
			
		||||
 | 
			
		||||
    return GetCachedPowerByIndex(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline DiyFp GetCachedPower10(int exp, int *outExp) {
 | 
			
		||||
    RAPIDJSON_ASSERT(exp >= -348);
 | 
			
		||||
    unsigned index = static_cast<unsigned>(exp + 348) / 8u;
 | 
			
		||||
    *outExp = -348 + static_cast<int>(index) * 8;
 | 
			
		||||
    return GetCachedPowerByIndex(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
RAPIDJSON_DIAG_OFF(padded)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_DIYFP_H_
 | 
			
		||||
							
								
								
									
										245
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_dtoa.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_dtoa.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,245 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
 | 
			
		||||
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
 | 
			
		||||
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_DTOA_
 | 
			
		||||
#define RAPIDJSON_DTOA_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_internal_itoa.h"
 | 
			
		||||
#include "lottie_rapidjson_internal_diyfp.h"
 | 
			
		||||
#include "lottie_rapidjson_internal_ieee754.h"
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(effc++)
 | 
			
		||||
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
 | 
			
		||||
    while (rest < wp_w && delta - rest >= ten_kappa &&
 | 
			
		||||
           (rest + ten_kappa < wp_w ||  /// closer
 | 
			
		||||
            wp_w - rest > rest + ten_kappa - wp_w)) {
 | 
			
		||||
        buffer[len - 1]--;
 | 
			
		||||
        rest += ten_kappa;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int CountDecimalDigit32(uint32_t n) {
 | 
			
		||||
    // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
 | 
			
		||||
    if (n < 10) return 1;
 | 
			
		||||
    if (n < 100) return 2;
 | 
			
		||||
    if (n < 1000) return 3;
 | 
			
		||||
    if (n < 10000) return 4;
 | 
			
		||||
    if (n < 100000) return 5;
 | 
			
		||||
    if (n < 1000000) return 6;
 | 
			
		||||
    if (n < 10000000) return 7;
 | 
			
		||||
    if (n < 100000000) return 8;
 | 
			
		||||
    // Will not reach 10 digits in DigitGen()
 | 
			
		||||
    //if (n < 1000000000) return 9;
 | 
			
		||||
    //return 10;
 | 
			
		||||
    return 9;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
 | 
			
		||||
    static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
 | 
			
		||||
    const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
 | 
			
		||||
    const DiyFp wp_w = Mp - W;
 | 
			
		||||
    uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
 | 
			
		||||
    uint64_t p2 = Mp.f & (one.f - 1);
 | 
			
		||||
    int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
 | 
			
		||||
    *len = 0;
 | 
			
		||||
 | 
			
		||||
    while (kappa > 0) {
 | 
			
		||||
        uint32_t d = 0;
 | 
			
		||||
        switch (kappa) {
 | 
			
		||||
            case  9: d = p1 /  100000000; p1 %=  100000000; break;
 | 
			
		||||
            case  8: d = p1 /   10000000; p1 %=   10000000; break;
 | 
			
		||||
            case  7: d = p1 /    1000000; p1 %=    1000000; break;
 | 
			
		||||
            case  6: d = p1 /     100000; p1 %=     100000; break;
 | 
			
		||||
            case  5: d = p1 /      10000; p1 %=      10000; break;
 | 
			
		||||
            case  4: d = p1 /       1000; p1 %=       1000; break;
 | 
			
		||||
            case  3: d = p1 /        100; p1 %=        100; break;
 | 
			
		||||
            case  2: d = p1 /         10; p1 %=         10; break;
 | 
			
		||||
            case  1: d = p1;              p1 =           0; break;
 | 
			
		||||
            default:;
 | 
			
		||||
        }
 | 
			
		||||
        if (d || *len)
 | 
			
		||||
            buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
 | 
			
		||||
        kappa--;
 | 
			
		||||
        uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
 | 
			
		||||
        if (tmp <= delta) {
 | 
			
		||||
            *K += kappa;
 | 
			
		||||
            GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // kappa = 0
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        p2 *= 10;
 | 
			
		||||
        delta *= 10;
 | 
			
		||||
        char d = static_cast<char>(p2 >> -one.e);
 | 
			
		||||
        if (d || *len)
 | 
			
		||||
            buffer[(*len)++] = static_cast<char>('0' + d);
 | 
			
		||||
        p2 &= one.f - 1;
 | 
			
		||||
        kappa--;
 | 
			
		||||
        if (p2 < delta) {
 | 
			
		||||
            *K += kappa;
 | 
			
		||||
            int index = -kappa;
 | 
			
		||||
            GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Grisu2(double value, char* buffer, int* length, int* K) {
 | 
			
		||||
    const DiyFp v(value);
 | 
			
		||||
    DiyFp w_m, w_p;
 | 
			
		||||
    v.NormalizedBoundaries(&w_m, &w_p);
 | 
			
		||||
 | 
			
		||||
    const DiyFp c_mk = GetCachedPower(w_p.e, K);
 | 
			
		||||
    const DiyFp W = v.Normalize() * c_mk;
 | 
			
		||||
    DiyFp Wp = w_p * c_mk;
 | 
			
		||||
    DiyFp Wm = w_m * c_mk;
 | 
			
		||||
    Wm.f++;
 | 
			
		||||
    Wp.f--;
 | 
			
		||||
    DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline char* WriteExponent(int K, char* buffer) {
 | 
			
		||||
    if (K < 0) {
 | 
			
		||||
        *buffer++ = '-';
 | 
			
		||||
        K = -K;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (K >= 100) {
 | 
			
		||||
        *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
 | 
			
		||||
        K %= 100;
 | 
			
		||||
        const char* d = GetDigitsLut() + K * 2;
 | 
			
		||||
        *buffer++ = d[0];
 | 
			
		||||
        *buffer++ = d[1];
 | 
			
		||||
    }
 | 
			
		||||
    else if (K >= 10) {
 | 
			
		||||
        const char* d = GetDigitsLut() + K * 2;
 | 
			
		||||
        *buffer++ = d[0];
 | 
			
		||||
        *buffer++ = d[1];
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        *buffer++ = static_cast<char>('0' + static_cast<char>(K));
 | 
			
		||||
 | 
			
		||||
    return buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
 | 
			
		||||
    const int kk = length + k;  // 10^(kk-1) <= v < 10^kk
 | 
			
		||||
 | 
			
		||||
    if (0 <= k && kk <= 21) {
 | 
			
		||||
        // 1234e7 -> 12340000000
 | 
			
		||||
        for (int i = length; i < kk; i++)
 | 
			
		||||
            buffer[i] = '0';
 | 
			
		||||
        buffer[kk] = '.';
 | 
			
		||||
        buffer[kk + 1] = '0';
 | 
			
		||||
        return &buffer[kk + 2];
 | 
			
		||||
    }
 | 
			
		||||
    else if (0 < kk && kk <= 21) {
 | 
			
		||||
        // 1234e-2 -> 12.34
 | 
			
		||||
        std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
 | 
			
		||||
        buffer[kk] = '.';
 | 
			
		||||
        if (0 > k + maxDecimalPlaces) {
 | 
			
		||||
            // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
 | 
			
		||||
            // Remove extra trailing zeros (at least one) after truncation.
 | 
			
		||||
            for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
 | 
			
		||||
                if (buffer[i] != '0')
 | 
			
		||||
                    return &buffer[i + 1];
 | 
			
		||||
            return &buffer[kk + 2]; // Reserve one zero
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            return &buffer[length + 1];
 | 
			
		||||
    }
 | 
			
		||||
    else if (-6 < kk && kk <= 0) {
 | 
			
		||||
        // 1234e-6 -> 0.001234
 | 
			
		||||
        const int offset = 2 - kk;
 | 
			
		||||
        std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
 | 
			
		||||
        buffer[0] = '0';
 | 
			
		||||
        buffer[1] = '.';
 | 
			
		||||
        for (int i = 2; i < offset; i++)
 | 
			
		||||
            buffer[i] = '0';
 | 
			
		||||
        if (length - kk > maxDecimalPlaces) {
 | 
			
		||||
            // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
 | 
			
		||||
            // Remove extra trailing zeros (at least one) after truncation.
 | 
			
		||||
            for (int i = maxDecimalPlaces + 1; i > 2; i--)
 | 
			
		||||
                if (buffer[i] != '0')
 | 
			
		||||
                    return &buffer[i + 1];
 | 
			
		||||
            return &buffer[3]; // Reserve one zero
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            return &buffer[length + offset];
 | 
			
		||||
    }
 | 
			
		||||
    else if (kk < -maxDecimalPlaces) {
 | 
			
		||||
        // Truncate to zero
 | 
			
		||||
        buffer[0] = '0';
 | 
			
		||||
        buffer[1] = '.';
 | 
			
		||||
        buffer[2] = '0';
 | 
			
		||||
        return &buffer[3];
 | 
			
		||||
    }
 | 
			
		||||
    else if (length == 1) {
 | 
			
		||||
        // 1e30
 | 
			
		||||
        buffer[1] = 'e';
 | 
			
		||||
        return WriteExponent(kk - 1, &buffer[2]);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        // 1234e30 -> 1.234e33
 | 
			
		||||
        std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
 | 
			
		||||
        buffer[1] = '.';
 | 
			
		||||
        buffer[length + 1] = 'e';
 | 
			
		||||
        return WriteExponent(kk - 1, &buffer[0 + length + 2]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
 | 
			
		||||
    RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
 | 
			
		||||
    Double d(value);
 | 
			
		||||
    if (d.IsZero()) {
 | 
			
		||||
        if (d.Sign())
 | 
			
		||||
            *buffer++ = '-';     // -0.0, Issue #289
 | 
			
		||||
        buffer[0] = '0';
 | 
			
		||||
        buffer[1] = '.';
 | 
			
		||||
        buffer[2] = '0';
 | 
			
		||||
        return &buffer[3];
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        if (value < 0) {
 | 
			
		||||
            *buffer++ = '-';
 | 
			
		||||
            value = -value;
 | 
			
		||||
        }
 | 
			
		||||
        int length, K;
 | 
			
		||||
        Grisu2(value, buffer, &length, &K);
 | 
			
		||||
        return Prettify(buffer, length, K, maxDecimalPlaces);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_DTOA_
 | 
			
		||||
							
								
								
									
										78
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_ieee754.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_ieee754.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_IEEE754_
 | 
			
		||||
#define RAPIDJSON_IEEE754_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
class Double {
 | 
			
		||||
public:
 | 
			
		||||
    Double() {}
 | 
			
		||||
    Double(double d) : d_(d) {}
 | 
			
		||||
    Double(uint64_t u) : u_(u) {}
 | 
			
		||||
 | 
			
		||||
    double Value() const { return d_; }
 | 
			
		||||
    uint64_t Uint64Value() const { return u_; }
 | 
			
		||||
 | 
			
		||||
    double NextPositiveDouble() const {
 | 
			
		||||
        RAPIDJSON_ASSERT(!Sign());
 | 
			
		||||
        return Double(u_ + 1).Value();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Sign() const { return (u_ & kSignMask) != 0; }
 | 
			
		||||
    uint64_t Significand() const { return u_ & kSignificandMask; }
 | 
			
		||||
    int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
 | 
			
		||||
 | 
			
		||||
    bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
 | 
			
		||||
    bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
 | 
			
		||||
    bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
 | 
			
		||||
    bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
 | 
			
		||||
    bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
 | 
			
		||||
 | 
			
		||||
    uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
 | 
			
		||||
    int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
 | 
			
		||||
    uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
 | 
			
		||||
 | 
			
		||||
    static int EffectiveSignificandSize(int order) {
 | 
			
		||||
        if (order >= -1021)
 | 
			
		||||
            return 53;
 | 
			
		||||
        else if (order <= -1074)
 | 
			
		||||
            return 0;
 | 
			
		||||
        else
 | 
			
		||||
            return order + 1074;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static const int kSignificandSize = 52;
 | 
			
		||||
    static const int kExponentBias = 0x3FF;
 | 
			
		||||
    static const int kDenormalExponent = 1 - kExponentBias;
 | 
			
		||||
    static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
 | 
			
		||||
    static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
 | 
			
		||||
    static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
 | 
			
		||||
    static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
 | 
			
		||||
 | 
			
		||||
    union {
 | 
			
		||||
        double d_;
 | 
			
		||||
        uint64_t u_;
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_IEEE754_
 | 
			
		||||
							
								
								
									
										308
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_itoa.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_itoa.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,308 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_ITOA_
 | 
			
		||||
#define RAPIDJSON_ITOA_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
inline const char* GetDigitsLut() {
 | 
			
		||||
    static const char cDigitsLut[200] = {
 | 
			
		||||
        '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
 | 
			
		||||
        '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
 | 
			
		||||
        '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
 | 
			
		||||
        '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
 | 
			
		||||
        '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
 | 
			
		||||
        '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
 | 
			
		||||
        '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
 | 
			
		||||
        '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
 | 
			
		||||
        '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
 | 
			
		||||
        '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
 | 
			
		||||
    };
 | 
			
		||||
    return cDigitsLut;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline char* u32toa(uint32_t value, char* buffer) {
 | 
			
		||||
    RAPIDJSON_ASSERT(buffer != 0);
 | 
			
		||||
 | 
			
		||||
    const char* cDigitsLut = GetDigitsLut();
 | 
			
		||||
 | 
			
		||||
    if (value < 10000) {
 | 
			
		||||
        const uint32_t d1 = (value / 100) << 1;
 | 
			
		||||
        const uint32_t d2 = (value % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        if (value >= 1000)
 | 
			
		||||
            *buffer++ = cDigitsLut[d1];
 | 
			
		||||
        if (value >= 100)
 | 
			
		||||
            *buffer++ = cDigitsLut[d1 + 1];
 | 
			
		||||
        if (value >= 10)
 | 
			
		||||
            *buffer++ = cDigitsLut[d2];
 | 
			
		||||
        *buffer++ = cDigitsLut[d2 + 1];
 | 
			
		||||
    }
 | 
			
		||||
    else if (value < 100000000) {
 | 
			
		||||
        // value = bbbbcccc
 | 
			
		||||
        const uint32_t b = value / 10000;
 | 
			
		||||
        const uint32_t c = value % 10000;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d1 = (b / 100) << 1;
 | 
			
		||||
        const uint32_t d2 = (b % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d3 = (c / 100) << 1;
 | 
			
		||||
        const uint32_t d4 = (c % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        if (value >= 10000000)
 | 
			
		||||
            *buffer++ = cDigitsLut[d1];
 | 
			
		||||
        if (value >= 1000000)
 | 
			
		||||
            *buffer++ = cDigitsLut[d1 + 1];
 | 
			
		||||
        if (value >= 100000)
 | 
			
		||||
            *buffer++ = cDigitsLut[d2];
 | 
			
		||||
        *buffer++ = cDigitsLut[d2 + 1];
 | 
			
		||||
 | 
			
		||||
        *buffer++ = cDigitsLut[d3];
 | 
			
		||||
        *buffer++ = cDigitsLut[d3 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d4];
 | 
			
		||||
        *buffer++ = cDigitsLut[d4 + 1];
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        // value = aabbbbcccc in decimal
 | 
			
		||||
 | 
			
		||||
        const uint32_t a = value / 100000000; // 1 to 42
 | 
			
		||||
        value %= 100000000;
 | 
			
		||||
 | 
			
		||||
        if (a >= 10) {
 | 
			
		||||
            const unsigned i = a << 1;
 | 
			
		||||
            *buffer++ = cDigitsLut[i];
 | 
			
		||||
            *buffer++ = cDigitsLut[i + 1];
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            *buffer++ = static_cast<char>('0' + static_cast<char>(a));
 | 
			
		||||
 | 
			
		||||
        const uint32_t b = value / 10000; // 0 to 9999
 | 
			
		||||
        const uint32_t c = value % 10000; // 0 to 9999
 | 
			
		||||
 | 
			
		||||
        const uint32_t d1 = (b / 100) << 1;
 | 
			
		||||
        const uint32_t d2 = (b % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d3 = (c / 100) << 1;
 | 
			
		||||
        const uint32_t d4 = (c % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        *buffer++ = cDigitsLut[d1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d1 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d2];
 | 
			
		||||
        *buffer++ = cDigitsLut[d2 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d3];
 | 
			
		||||
        *buffer++ = cDigitsLut[d3 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d4];
 | 
			
		||||
        *buffer++ = cDigitsLut[d4 + 1];
 | 
			
		||||
    }
 | 
			
		||||
    return buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline char* i32toa(int32_t value, char* buffer) {
 | 
			
		||||
    RAPIDJSON_ASSERT(buffer != 0);
 | 
			
		||||
    uint32_t u = static_cast<uint32_t>(value);
 | 
			
		||||
    if (value < 0) {
 | 
			
		||||
        *buffer++ = '-';
 | 
			
		||||
        u = ~u + 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return u32toa(u, buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline char* u64toa(uint64_t value, char* buffer) {
 | 
			
		||||
    RAPIDJSON_ASSERT(buffer != 0);
 | 
			
		||||
    const char* cDigitsLut = GetDigitsLut();
 | 
			
		||||
    const uint64_t  kTen8 = 100000000;
 | 
			
		||||
    const uint64_t  kTen9 = kTen8 * 10;
 | 
			
		||||
    const uint64_t kTen10 = kTen8 * 100;
 | 
			
		||||
    const uint64_t kTen11 = kTen8 * 1000;
 | 
			
		||||
    const uint64_t kTen12 = kTen8 * 10000;
 | 
			
		||||
    const uint64_t kTen13 = kTen8 * 100000;
 | 
			
		||||
    const uint64_t kTen14 = kTen8 * 1000000;
 | 
			
		||||
    const uint64_t kTen15 = kTen8 * 10000000;
 | 
			
		||||
    const uint64_t kTen16 = kTen8 * kTen8;
 | 
			
		||||
 | 
			
		||||
    if (value < kTen8) {
 | 
			
		||||
        uint32_t v = static_cast<uint32_t>(value);
 | 
			
		||||
        if (v < 10000) {
 | 
			
		||||
            const uint32_t d1 = (v / 100) << 1;
 | 
			
		||||
            const uint32_t d2 = (v % 100) << 1;
 | 
			
		||||
 | 
			
		||||
            if (v >= 1000)
 | 
			
		||||
                *buffer++ = cDigitsLut[d1];
 | 
			
		||||
            if (v >= 100)
 | 
			
		||||
                *buffer++ = cDigitsLut[d1 + 1];
 | 
			
		||||
            if (v >= 10)
 | 
			
		||||
                *buffer++ = cDigitsLut[d2];
 | 
			
		||||
            *buffer++ = cDigitsLut[d2 + 1];
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            // value = bbbbcccc
 | 
			
		||||
            const uint32_t b = v / 10000;
 | 
			
		||||
            const uint32_t c = v % 10000;
 | 
			
		||||
 | 
			
		||||
            const uint32_t d1 = (b / 100) << 1;
 | 
			
		||||
            const uint32_t d2 = (b % 100) << 1;
 | 
			
		||||
 | 
			
		||||
            const uint32_t d3 = (c / 100) << 1;
 | 
			
		||||
            const uint32_t d4 = (c % 100) << 1;
 | 
			
		||||
 | 
			
		||||
            if (value >= 10000000)
 | 
			
		||||
                *buffer++ = cDigitsLut[d1];
 | 
			
		||||
            if (value >= 1000000)
 | 
			
		||||
                *buffer++ = cDigitsLut[d1 + 1];
 | 
			
		||||
            if (value >= 100000)
 | 
			
		||||
                *buffer++ = cDigitsLut[d2];
 | 
			
		||||
            *buffer++ = cDigitsLut[d2 + 1];
 | 
			
		||||
 | 
			
		||||
            *buffer++ = cDigitsLut[d3];
 | 
			
		||||
            *buffer++ = cDigitsLut[d3 + 1];
 | 
			
		||||
            *buffer++ = cDigitsLut[d4];
 | 
			
		||||
            *buffer++ = cDigitsLut[d4 + 1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (value < kTen16) {
 | 
			
		||||
        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
 | 
			
		||||
        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
 | 
			
		||||
 | 
			
		||||
        const uint32_t b0 = v0 / 10000;
 | 
			
		||||
        const uint32_t c0 = v0 % 10000;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d1 = (b0 / 100) << 1;
 | 
			
		||||
        const uint32_t d2 = (b0 % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d3 = (c0 / 100) << 1;
 | 
			
		||||
        const uint32_t d4 = (c0 % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        const uint32_t b1 = v1 / 10000;
 | 
			
		||||
        const uint32_t c1 = v1 % 10000;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d5 = (b1 / 100) << 1;
 | 
			
		||||
        const uint32_t d6 = (b1 % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d7 = (c1 / 100) << 1;
 | 
			
		||||
        const uint32_t d8 = (c1 % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        if (value >= kTen15)
 | 
			
		||||
            *buffer++ = cDigitsLut[d1];
 | 
			
		||||
        if (value >= kTen14)
 | 
			
		||||
            *buffer++ = cDigitsLut[d1 + 1];
 | 
			
		||||
        if (value >= kTen13)
 | 
			
		||||
            *buffer++ = cDigitsLut[d2];
 | 
			
		||||
        if (value >= kTen12)
 | 
			
		||||
            *buffer++ = cDigitsLut[d2 + 1];
 | 
			
		||||
        if (value >= kTen11)
 | 
			
		||||
            *buffer++ = cDigitsLut[d3];
 | 
			
		||||
        if (value >= kTen10)
 | 
			
		||||
            *buffer++ = cDigitsLut[d3 + 1];
 | 
			
		||||
        if (value >= kTen9)
 | 
			
		||||
            *buffer++ = cDigitsLut[d4];
 | 
			
		||||
 | 
			
		||||
        *buffer++ = cDigitsLut[d4 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d5];
 | 
			
		||||
        *buffer++ = cDigitsLut[d5 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d6];
 | 
			
		||||
        *buffer++ = cDigitsLut[d6 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d7];
 | 
			
		||||
        *buffer++ = cDigitsLut[d7 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d8];
 | 
			
		||||
        *buffer++ = cDigitsLut[d8 + 1];
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
 | 
			
		||||
        value %= kTen16;
 | 
			
		||||
 | 
			
		||||
        if (a < 10)
 | 
			
		||||
            *buffer++ = static_cast<char>('0' + static_cast<char>(a));
 | 
			
		||||
        else if (a < 100) {
 | 
			
		||||
            const uint32_t i = a << 1;
 | 
			
		||||
            *buffer++ = cDigitsLut[i];
 | 
			
		||||
            *buffer++ = cDigitsLut[i + 1];
 | 
			
		||||
        }
 | 
			
		||||
        else if (a < 1000) {
 | 
			
		||||
            *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
 | 
			
		||||
 | 
			
		||||
            const uint32_t i = (a % 100) << 1;
 | 
			
		||||
            *buffer++ = cDigitsLut[i];
 | 
			
		||||
            *buffer++ = cDigitsLut[i + 1];
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            const uint32_t i = (a / 100) << 1;
 | 
			
		||||
            const uint32_t j = (a % 100) << 1;
 | 
			
		||||
            *buffer++ = cDigitsLut[i];
 | 
			
		||||
            *buffer++ = cDigitsLut[i + 1];
 | 
			
		||||
            *buffer++ = cDigitsLut[j];
 | 
			
		||||
            *buffer++ = cDigitsLut[j + 1];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
 | 
			
		||||
        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
 | 
			
		||||
 | 
			
		||||
        const uint32_t b0 = v0 / 10000;
 | 
			
		||||
        const uint32_t c0 = v0 % 10000;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d1 = (b0 / 100) << 1;
 | 
			
		||||
        const uint32_t d2 = (b0 % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d3 = (c0 / 100) << 1;
 | 
			
		||||
        const uint32_t d4 = (c0 % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        const uint32_t b1 = v1 / 10000;
 | 
			
		||||
        const uint32_t c1 = v1 % 10000;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d5 = (b1 / 100) << 1;
 | 
			
		||||
        const uint32_t d6 = (b1 % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        const uint32_t d7 = (c1 / 100) << 1;
 | 
			
		||||
        const uint32_t d8 = (c1 % 100) << 1;
 | 
			
		||||
 | 
			
		||||
        *buffer++ = cDigitsLut[d1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d1 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d2];
 | 
			
		||||
        *buffer++ = cDigitsLut[d2 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d3];
 | 
			
		||||
        *buffer++ = cDigitsLut[d3 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d4];
 | 
			
		||||
        *buffer++ = cDigitsLut[d4 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d5];
 | 
			
		||||
        *buffer++ = cDigitsLut[d5 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d6];
 | 
			
		||||
        *buffer++ = cDigitsLut[d6 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d7];
 | 
			
		||||
        *buffer++ = cDigitsLut[d7 + 1];
 | 
			
		||||
        *buffer++ = cDigitsLut[d8];
 | 
			
		||||
        *buffer++ = cDigitsLut[d8 + 1];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline char* i64toa(int64_t value, char* buffer) {
 | 
			
		||||
    RAPIDJSON_ASSERT(buffer != 0);
 | 
			
		||||
    uint64_t u = static_cast<uint64_t>(value);
 | 
			
		||||
    if (value < 0) {
 | 
			
		||||
        *buffer++ = '-';
 | 
			
		||||
        u = ~u + 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return u64toa(u, buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_ITOA_
 | 
			
		||||
							
								
								
									
										186
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_meta.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_meta.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,186 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_INTERNAL_META_H_
 | 
			
		||||
#define RAPIDJSON_INTERNAL_META_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(effc++)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && !defined(__clang__)
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(6334)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//@cond RAPIDJSON_INTERNAL
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
 | 
			
		||||
template <typename T> struct Void { typedef void Type; };
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// BoolType, TrueType, FalseType
 | 
			
		||||
//
 | 
			
		||||
template <bool Cond> struct BoolType {
 | 
			
		||||
    static const bool Value = Cond;
 | 
			
		||||
    typedef BoolType Type;
 | 
			
		||||
};
 | 
			
		||||
typedef BoolType<true> TrueType;
 | 
			
		||||
typedef BoolType<false> FalseType;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
 | 
			
		||||
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
 | 
			
		||||
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
 | 
			
		||||
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
 | 
			
		||||
 | 
			
		||||
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
 | 
			
		||||
template <> struct AndExprCond<true, true> : TrueType {};
 | 
			
		||||
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
 | 
			
		||||
template <> struct OrExprCond<false, false> : FalseType {};
 | 
			
		||||
 | 
			
		||||
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
 | 
			
		||||
template <typename C> struct NotExpr  : SelectIf<C,FalseType,TrueType>::Type {};
 | 
			
		||||
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
 | 
			
		||||
template <typename C1, typename C2> struct OrExpr  : OrExprCond<C1::Value, C2::Value>::Type {};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// AddConst, MaybeAddConst, RemoveConst
 | 
			
		||||
template <typename T> struct AddConst { typedef const T Type; };
 | 
			
		||||
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
 | 
			
		||||
template <typename T> struct RemoveConst { typedef T Type; };
 | 
			
		||||
template <typename T> struct RemoveConst<const T> { typedef T Type; };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// IsSame, IsConst, IsMoreConst, IsPointer
 | 
			
		||||
//
 | 
			
		||||
template <typename T, typename U> struct IsSame : FalseType {};
 | 
			
		||||
template <typename T> struct IsSame<T, T> : TrueType {};
 | 
			
		||||
 | 
			
		||||
template <typename T> struct IsConst : FalseType {};
 | 
			
		||||
template <typename T> struct IsConst<const T> : TrueType {};
 | 
			
		||||
 | 
			
		||||
template <typename CT, typename T>
 | 
			
		||||
struct IsMoreConst
 | 
			
		||||
    : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
 | 
			
		||||
              BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
 | 
			
		||||
 | 
			
		||||
template <typename T> struct IsPointer : FalseType {};
 | 
			
		||||
template <typename T> struct IsPointer<T*> : TrueType {};
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// IsBaseOf
 | 
			
		||||
//
 | 
			
		||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
 | 
			
		||||
 | 
			
		||||
template <typename B, typename D> struct IsBaseOf
 | 
			
		||||
    : BoolType< ::std::is_base_of<B,D>::value> {};
 | 
			
		||||
 | 
			
		||||
#else // simplified version adopted from Boost
 | 
			
		||||
 | 
			
		||||
template<typename B, typename D> struct IsBaseOfImpl {
 | 
			
		||||
    RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
 | 
			
		||||
    RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
 | 
			
		||||
 | 
			
		||||
    typedef char (&Yes)[1];
 | 
			
		||||
    typedef char (&No) [2];
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    static Yes Check(const D*, T);
 | 
			
		||||
    static No  Check(const B*, int);
 | 
			
		||||
 | 
			
		||||
    struct Host {
 | 
			
		||||
        operator const B*() const;
 | 
			
		||||
        operator const D*();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename B, typename D> struct IsBaseOf
 | 
			
		||||
    : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// EnableIf / DisableIf
 | 
			
		||||
//
 | 
			
		||||
template <bool Condition, typename T = void> struct EnableIfCond  { typedef T Type; };
 | 
			
		||||
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
 | 
			
		||||
 | 
			
		||||
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
 | 
			
		||||
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
 | 
			
		||||
 | 
			
		||||
template <typename Condition, typename T = void>
 | 
			
		||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
 | 
			
		||||
 | 
			
		||||
template <typename Condition, typename T = void>
 | 
			
		||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
 | 
			
		||||
 | 
			
		||||
// SFINAE helpers
 | 
			
		||||
struct SfinaeTag {};
 | 
			
		||||
template <typename T> struct RemoveSfinaeTag;
 | 
			
		||||
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
 | 
			
		||||
 | 
			
		||||
#define RAPIDJSON_REMOVEFPTR_(type) \
 | 
			
		||||
    typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
 | 
			
		||||
        < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
 | 
			
		||||
 | 
			
		||||
#define RAPIDJSON_ENABLEIF(cond) \
 | 
			
		||||
    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
 | 
			
		||||
        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
 | 
			
		||||
 | 
			
		||||
#define RAPIDJSON_DISABLEIF(cond) \
 | 
			
		||||
    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
 | 
			
		||||
        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
 | 
			
		||||
 | 
			
		||||
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
 | 
			
		||||
    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
 | 
			
		||||
        <RAPIDJSON_REMOVEFPTR_(cond), \
 | 
			
		||||
         RAPIDJSON_REMOVEFPTR_(returntype)>::Type
 | 
			
		||||
 | 
			
		||||
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
 | 
			
		||||
    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
 | 
			
		||||
        <RAPIDJSON_REMOVEFPTR_(cond), \
 | 
			
		||||
         RAPIDJSON_REMOVEFPTR_(returntype)>::Type
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
//@endcond
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && !defined(__clang__)
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_INTERNAL_META_H_
 | 
			
		||||
							
								
								
									
										55
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_pow10.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_pow10.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_POW10_
 | 
			
		||||
#define RAPIDJSON_POW10_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
//! Computes integer powers of 10 in double (10.0^n).
 | 
			
		||||
/*! This function uses lookup table for fast and accurate results.
 | 
			
		||||
    \param n non-negative exponent. Must <= 308.
 | 
			
		||||
    \return 10.0^n
 | 
			
		||||
*/
 | 
			
		||||
inline double Pow10(int n) {
 | 
			
		||||
    static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
 | 
			
		||||
        1e+0,  
 | 
			
		||||
        1e+1,  1e+2,  1e+3,  1e+4,  1e+5,  1e+6,  1e+7,  1e+8,  1e+9,  1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 
 | 
			
		||||
        1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
 | 
			
		||||
        1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
 | 
			
		||||
        1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
 | 
			
		||||
        1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
 | 
			
		||||
        1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
 | 
			
		||||
        1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
 | 
			
		||||
        1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
 | 
			
		||||
        1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
 | 
			
		||||
        1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
 | 
			
		||||
        1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
 | 
			
		||||
        1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
 | 
			
		||||
        1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
 | 
			
		||||
        1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
 | 
			
		||||
        1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
 | 
			
		||||
        1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
 | 
			
		||||
    };
 | 
			
		||||
    RAPIDJSON_ASSERT(n >= 0 && n <= 308);
 | 
			
		||||
    return e[n];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_POW10_
 | 
			
		||||
							
								
								
									
										739
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_regex.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										739
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_regex.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,739 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_INTERNAL_REGEX_H_
 | 
			
		||||
#define RAPIDJSON_INTERNAL_REGEX_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_allocators.h"
 | 
			
		||||
#include "lottie_rapidjson_stream.h"
 | 
			
		||||
#include "lottie_rapidjson_internal_stack.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(padded)
 | 
			
		||||
RAPIDJSON_DIAG_OFF(switch-enum)
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(effc++)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_REGEX_VERBOSE
 | 
			
		||||
#define RAPIDJSON_REGEX_VERBOSE 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// DecodedStream
 | 
			
		||||
 | 
			
		||||
template <typename SourceStream, typename Encoding>
 | 
			
		||||
class DecodedStream {
 | 
			
		||||
public:
 | 
			
		||||
    DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
 | 
			
		||||
    unsigned Peek() { return codepoint_; }
 | 
			
		||||
    unsigned Take() {
 | 
			
		||||
        unsigned c = codepoint_;
 | 
			
		||||
        if (c) // No further decoding when '\0'
 | 
			
		||||
            Decode();
 | 
			
		||||
        return c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void Decode() {
 | 
			
		||||
        if (!Encoding::Decode(ss_, &codepoint_))
 | 
			
		||||
            codepoint_ = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SourceStream& ss_;
 | 
			
		||||
    unsigned codepoint_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// GenericRegex
 | 
			
		||||
 | 
			
		||||
static const SizeType kRegexInvalidState = ~SizeType(0);  //!< Represents an invalid index in GenericRegex::State::out, out1
 | 
			
		||||
static const SizeType kRegexInvalidRange = ~SizeType(0);
 | 
			
		||||
 | 
			
		||||
template <typename Encoding, typename Allocator>
 | 
			
		||||
class GenericRegexSearch;
 | 
			
		||||
 | 
			
		||||
//! Regular expression engine with subset of ECMAscript grammar.
 | 
			
		||||
/*!
 | 
			
		||||
    Supported regular expression syntax:
 | 
			
		||||
    - \c ab     Concatenation
 | 
			
		||||
    - \c a|b    Alternation
 | 
			
		||||
    - \c a?     Zero or one
 | 
			
		||||
    - \c a*     Zero or more
 | 
			
		||||
    - \c a+     One or more
 | 
			
		||||
    - \c a{3}   Exactly 3 times
 | 
			
		||||
    - \c a{3,}  At least 3 times
 | 
			
		||||
    - \c a{3,5} 3 to 5 times
 | 
			
		||||
    - \c (ab)   Grouping
 | 
			
		||||
    - \c ^a     At the beginning
 | 
			
		||||
    - \c a$     At the end
 | 
			
		||||
    - \c .      Any character
 | 
			
		||||
    - \c [abc]  Character classes
 | 
			
		||||
    - \c [a-c]  Character class range
 | 
			
		||||
    - \c [a-z0-9_] Character class combination
 | 
			
		||||
    - \c [^abc] Negated character classes
 | 
			
		||||
    - \c [^a-c] Negated character class range
 | 
			
		||||
    - \c [\b]   Backspace (U+0008)
 | 
			
		||||
    - \c \\| \\\\ ...  Escape characters
 | 
			
		||||
    - \c \\f Form feed (U+000C)
 | 
			
		||||
    - \c \\n Line feed (U+000A)
 | 
			
		||||
    - \c \\r Carriage return (U+000D)
 | 
			
		||||
    - \c \\t Tab (U+0009)
 | 
			
		||||
    - \c \\v Vertical tab (U+000B)
 | 
			
		||||
 | 
			
		||||
    \note This is a Thompson NFA engine, implemented with reference to 
 | 
			
		||||
        Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", 
 | 
			
		||||
        https://swtch.com/~rsc/regexp/regexp1.html 
 | 
			
		||||
*/
 | 
			
		||||
template <typename Encoding, typename Allocator = CrtAllocator>
 | 
			
		||||
class GenericRegex {
 | 
			
		||||
public:
 | 
			
		||||
    typedef Encoding EncodingType;
 | 
			
		||||
    typedef typename Encoding::Ch Ch;
 | 
			
		||||
    template <typename, typename> friend class GenericRegexSearch;
 | 
			
		||||
 | 
			
		||||
    GenericRegex(const Ch* source, Allocator* allocator = 0) : 
 | 
			
		||||
        ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_), 
 | 
			
		||||
        states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), 
 | 
			
		||||
        anchorBegin_(), anchorEnd_()
 | 
			
		||||
    {
 | 
			
		||||
        GenericStringStream<Encoding> ss(source);
 | 
			
		||||
        DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
 | 
			
		||||
        Parse(ds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~GenericRegex()
 | 
			
		||||
    {
 | 
			
		||||
        RAPIDJSON_DELETE(ownAllocator_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool IsValid() const {
 | 
			
		||||
        return root_ != kRegexInvalidState;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    enum Operator {
 | 
			
		||||
        kZeroOrOne,
 | 
			
		||||
        kZeroOrMore,
 | 
			
		||||
        kOneOrMore,
 | 
			
		||||
        kConcatenation,
 | 
			
		||||
        kAlternation,
 | 
			
		||||
        kLeftParenthesis
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static const unsigned kAnyCharacterClass = 0xFFFFFFFF;   //!< For '.'
 | 
			
		||||
    static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
 | 
			
		||||
    static const unsigned kRangeNegationFlag = 0x80000000;
 | 
			
		||||
 | 
			
		||||
    struct Range {
 | 
			
		||||
        unsigned start; // 
 | 
			
		||||
        unsigned end;
 | 
			
		||||
        SizeType next;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct State {
 | 
			
		||||
        SizeType out;     //!< Equals to kInvalid for matching state
 | 
			
		||||
        SizeType out1;    //!< Equals to non-kInvalid for split
 | 
			
		||||
        SizeType rangeStart;
 | 
			
		||||
        unsigned codepoint;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Frag {
 | 
			
		||||
        Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
 | 
			
		||||
        SizeType start;
 | 
			
		||||
        SizeType out; //!< link-list of all output states
 | 
			
		||||
        SizeType minIndex;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    State& GetState(SizeType index) {
 | 
			
		||||
        RAPIDJSON_ASSERT(index < stateCount_);
 | 
			
		||||
        return states_.template Bottom<State>()[index];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const State& GetState(SizeType index) const {
 | 
			
		||||
        RAPIDJSON_ASSERT(index < stateCount_);
 | 
			
		||||
        return states_.template Bottom<State>()[index];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Range& GetRange(SizeType index) {
 | 
			
		||||
        RAPIDJSON_ASSERT(index < rangeCount_);
 | 
			
		||||
        return ranges_.template Bottom<Range>()[index];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const Range& GetRange(SizeType index) const {
 | 
			
		||||
        RAPIDJSON_ASSERT(index < rangeCount_);
 | 
			
		||||
        return ranges_.template Bottom<Range>()[index];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    void Parse(DecodedStream<InputStream, Encoding>& ds) {
 | 
			
		||||
        Stack<Allocator> operandStack(allocator_, 256);    // Frag
 | 
			
		||||
        Stack<Allocator> operatorStack(allocator_, 256);   // Operator
 | 
			
		||||
        Stack<Allocator> atomCountStack(allocator_, 256);  // unsigned (Atom per parenthesis)
 | 
			
		||||
 | 
			
		||||
        *atomCountStack.template Push<unsigned>() = 0;
 | 
			
		||||
 | 
			
		||||
        unsigned codepoint;
 | 
			
		||||
        while (ds.Peek() != 0) {
 | 
			
		||||
            switch (codepoint = ds.Take()) {
 | 
			
		||||
                case '^':
 | 
			
		||||
                    anchorBegin_ = true;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case '$':
 | 
			
		||||
                    anchorEnd_ = true;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case '|':
 | 
			
		||||
                    while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
 | 
			
		||||
                        if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
 | 
			
		||||
                            return;
 | 
			
		||||
                    *operatorStack.template Push<Operator>() = kAlternation;
 | 
			
		||||
                    *atomCountStack.template Top<unsigned>() = 0;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case '(':
 | 
			
		||||
                    *operatorStack.template Push<Operator>() = kLeftParenthesis;
 | 
			
		||||
                    *atomCountStack.template Push<unsigned>() = 0;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case ')':
 | 
			
		||||
                    while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
 | 
			
		||||
                        if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
 | 
			
		||||
                            return;
 | 
			
		||||
                    if (operatorStack.Empty())
 | 
			
		||||
                        return;
 | 
			
		||||
                    operatorStack.template Pop<Operator>(1);
 | 
			
		||||
                    atomCountStack.template Pop<unsigned>(1);
 | 
			
		||||
                    ImplicitConcatenation(atomCountStack, operatorStack);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case '?':
 | 
			
		||||
                    if (!Eval(operandStack, kZeroOrOne))
 | 
			
		||||
                        return;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case '*':
 | 
			
		||||
                    if (!Eval(operandStack, kZeroOrMore))
 | 
			
		||||
                        return;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case '+':
 | 
			
		||||
                    if (!Eval(operandStack, kOneOrMore))
 | 
			
		||||
                        return;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case '{':
 | 
			
		||||
                    {
 | 
			
		||||
                        unsigned n, m;
 | 
			
		||||
                        if (!ParseUnsigned(ds, &n))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        if (ds.Peek() == ',') {
 | 
			
		||||
                            ds.Take();
 | 
			
		||||
                            if (ds.Peek() == '}')
 | 
			
		||||
                                m = kInfinityQuantifier;
 | 
			
		||||
                            else if (!ParseUnsigned(ds, &m) || m < n)
 | 
			
		||||
                                return;
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                            m = n;
 | 
			
		||||
 | 
			
		||||
                        if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
 | 
			
		||||
                            return;
 | 
			
		||||
                        ds.Take();
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case '.':
 | 
			
		||||
                    PushOperand(operandStack, kAnyCharacterClass);
 | 
			
		||||
                    ImplicitConcatenation(atomCountStack, operatorStack);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case '[':
 | 
			
		||||
                    {
 | 
			
		||||
                        SizeType range;
 | 
			
		||||
                        if (!ParseRange(ds, &range))
 | 
			
		||||
                            return;
 | 
			
		||||
                        SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
 | 
			
		||||
                        GetState(s).rangeStart = range;
 | 
			
		||||
                        *operandStack.template Push<Frag>() = Frag(s, s, s);
 | 
			
		||||
                    }
 | 
			
		||||
                    ImplicitConcatenation(atomCountStack, operatorStack);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case '\\': // Escape character
 | 
			
		||||
                    if (!CharacterEscape(ds, &codepoint))
 | 
			
		||||
                        return; // Unsupported escape character
 | 
			
		||||
                    // fall through to default
 | 
			
		||||
                    RAPIDJSON_DELIBERATE_FALLTHROUGH;
 | 
			
		||||
 | 
			
		||||
                default: // Pattern character
 | 
			
		||||
                    PushOperand(operandStack, codepoint);
 | 
			
		||||
                    ImplicitConcatenation(atomCountStack, operatorStack);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while (!operatorStack.Empty())
 | 
			
		||||
            if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
        // Link the operand to matching state.
 | 
			
		||||
        if (operandStack.GetSize() == sizeof(Frag)) {
 | 
			
		||||
            Frag* e = operandStack.template Pop<Frag>(1);
 | 
			
		||||
            Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
 | 
			
		||||
            root_ = e->start;
 | 
			
		||||
 | 
			
		||||
#if RAPIDJSON_REGEX_VERBOSE
 | 
			
		||||
            printf("root: %d\n", root_);
 | 
			
		||||
            for (SizeType i = 0; i < stateCount_ ; i++) {
 | 
			
		||||
                State& s = GetState(i);
 | 
			
		||||
                printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
 | 
			
		||||
            }
 | 
			
		||||
            printf("\n");
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
 | 
			
		||||
        State* s = states_.template Push<State>();
 | 
			
		||||
        s->out = out;
 | 
			
		||||
        s->out1 = out1;
 | 
			
		||||
        s->codepoint = codepoint;
 | 
			
		||||
        s->rangeStart = kRegexInvalidRange;
 | 
			
		||||
        return stateCount_++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
 | 
			
		||||
        SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
 | 
			
		||||
        *operandStack.template Push<Frag>() = Frag(s, s, s);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
 | 
			
		||||
        if (*atomCountStack.template Top<unsigned>())
 | 
			
		||||
            *operatorStack.template Push<Operator>() = kConcatenation;
 | 
			
		||||
        (*atomCountStack.template Top<unsigned>())++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SizeType Append(SizeType l1, SizeType l2) {
 | 
			
		||||
        SizeType old = l1;
 | 
			
		||||
        while (GetState(l1).out != kRegexInvalidState)
 | 
			
		||||
            l1 = GetState(l1).out;
 | 
			
		||||
        GetState(l1).out = l2;
 | 
			
		||||
        return old;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Patch(SizeType l, SizeType s) {
 | 
			
		||||
        for (SizeType next; l != kRegexInvalidState; l = next) {
 | 
			
		||||
            next = GetState(l).out;
 | 
			
		||||
            GetState(l).out = s;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Eval(Stack<Allocator>& operandStack, Operator op) {
 | 
			
		||||
        switch (op) {
 | 
			
		||||
            case kConcatenation:
 | 
			
		||||
                RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
 | 
			
		||||
                {
 | 
			
		||||
                    Frag e2 = *operandStack.template Pop<Frag>(1);
 | 
			
		||||
                    Frag e1 = *operandStack.template Pop<Frag>(1);
 | 
			
		||||
                    Patch(e1.out, e2.start);
 | 
			
		||||
                    *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
 | 
			
		||||
                }
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            case kAlternation:
 | 
			
		||||
                if (operandStack.GetSize() >= sizeof(Frag) * 2) {
 | 
			
		||||
                    Frag e2 = *operandStack.template Pop<Frag>(1);
 | 
			
		||||
                    Frag e1 = *operandStack.template Pop<Frag>(1);
 | 
			
		||||
                    SizeType s = NewState(e1.start, e2.start, 0);
 | 
			
		||||
                    *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            case kZeroOrOne:
 | 
			
		||||
                if (operandStack.GetSize() >= sizeof(Frag)) {
 | 
			
		||||
                    Frag e = *operandStack.template Pop<Frag>(1);
 | 
			
		||||
                    SizeType s = NewState(kRegexInvalidState, e.start, 0);
 | 
			
		||||
                    *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            case kZeroOrMore:
 | 
			
		||||
                if (operandStack.GetSize() >= sizeof(Frag)) {
 | 
			
		||||
                    Frag e = *operandStack.template Pop<Frag>(1);
 | 
			
		||||
                    SizeType s = NewState(kRegexInvalidState, e.start, 0);
 | 
			
		||||
                    Patch(e.out, s);
 | 
			
		||||
                    *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            case kOneOrMore:
 | 
			
		||||
                if (operandStack.GetSize() >= sizeof(Frag)) {
 | 
			
		||||
                    Frag e = *operandStack.template Pop<Frag>(1);
 | 
			
		||||
                    SizeType s = NewState(kRegexInvalidState, e.start, 0);
 | 
			
		||||
                    Patch(e.out, s);
 | 
			
		||||
                    *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            default: 
 | 
			
		||||
                // syntax error (e.g. unclosed kLeftParenthesis)
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
 | 
			
		||||
        RAPIDJSON_ASSERT(n <= m);
 | 
			
		||||
        RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
 | 
			
		||||
 | 
			
		||||
        if (n == 0) {
 | 
			
		||||
            if (m == 0)                             // a{0} not support
 | 
			
		||||
                return false;
 | 
			
		||||
            else if (m == kInfinityQuantifier)
 | 
			
		||||
                Eval(operandStack, kZeroOrMore);    // a{0,} -> a*
 | 
			
		||||
            else {
 | 
			
		||||
                Eval(operandStack, kZeroOrOne);         // a{0,5} -> a?
 | 
			
		||||
                for (unsigned i = 0; i < m - 1; i++)
 | 
			
		||||
                    CloneTopOperand(operandStack);      // a{0,5} -> a? a? a? a? a?
 | 
			
		||||
                for (unsigned i = 0; i < m - 1; i++)
 | 
			
		||||
                    Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (unsigned i = 0; i < n - 1; i++)        // a{3} -> a a a
 | 
			
		||||
            CloneTopOperand(operandStack);
 | 
			
		||||
 | 
			
		||||
        if (m == kInfinityQuantifier)
 | 
			
		||||
            Eval(operandStack, kOneOrMore);         // a{3,} -> a a a+
 | 
			
		||||
        else if (m > n) {
 | 
			
		||||
            CloneTopOperand(operandStack);          // a{3,5} -> a a a a
 | 
			
		||||
            Eval(operandStack, kZeroOrOne);         // a{3,5} -> a a a a?
 | 
			
		||||
            for (unsigned i = n; i < m - 1; i++)
 | 
			
		||||
                CloneTopOperand(operandStack);      // a{3,5} -> a a a a? a?
 | 
			
		||||
            for (unsigned i = n; i < m; i++)
 | 
			
		||||
                Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (unsigned i = 0; i < n - 1; i++)
 | 
			
		||||
            Eval(operandStack, kConcatenation);     // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
 | 
			
		||||
 | 
			
		||||
    void CloneTopOperand(Stack<Allocator>& operandStack) {
 | 
			
		||||
        const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
 | 
			
		||||
        SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
 | 
			
		||||
        State* s = states_.template Push<State>(count);
 | 
			
		||||
        memcpy(s, &GetState(src.minIndex), count * sizeof(State));
 | 
			
		||||
        for (SizeType j = 0; j < count; j++) {
 | 
			
		||||
            if (s[j].out != kRegexInvalidState)
 | 
			
		||||
                s[j].out += count;
 | 
			
		||||
            if (s[j].out1 != kRegexInvalidState)
 | 
			
		||||
                s[j].out1 += count;
 | 
			
		||||
        }
 | 
			
		||||
        *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
 | 
			
		||||
        stateCount_ += count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
 | 
			
		||||
        unsigned r = 0;
 | 
			
		||||
        if (ds.Peek() < '0' || ds.Peek() > '9')
 | 
			
		||||
            return false;
 | 
			
		||||
        while (ds.Peek() >= '0' && ds.Peek() <= '9') {
 | 
			
		||||
            if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
 | 
			
		||||
                return false; // overflow
 | 
			
		||||
            r = r * 10 + (ds.Take() - '0');
 | 
			
		||||
        }
 | 
			
		||||
        *u = r;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
 | 
			
		||||
        bool isBegin = true;
 | 
			
		||||
        bool negate = false;
 | 
			
		||||
        int step = 0;
 | 
			
		||||
        SizeType start = kRegexInvalidRange;
 | 
			
		||||
        SizeType current = kRegexInvalidRange;
 | 
			
		||||
        unsigned codepoint;
 | 
			
		||||
        while ((codepoint = ds.Take()) != 0) {
 | 
			
		||||
            if (isBegin) {
 | 
			
		||||
                isBegin = false;
 | 
			
		||||
                if (codepoint == '^') {
 | 
			
		||||
                    negate = true;
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            switch (codepoint) {
 | 
			
		||||
            case ']':
 | 
			
		||||
                if (start == kRegexInvalidRange)
 | 
			
		||||
                    return false;   // Error: nothing inside []
 | 
			
		||||
                if (step == 2) { // Add trailing '-'
 | 
			
		||||
                    SizeType r = NewRange('-');
 | 
			
		||||
                    RAPIDJSON_ASSERT(current != kRegexInvalidRange);
 | 
			
		||||
                    GetRange(current).next = r;
 | 
			
		||||
                }
 | 
			
		||||
                if (negate)
 | 
			
		||||
                    GetRange(start).start |= kRangeNegationFlag;
 | 
			
		||||
                *range = start;
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            case '\\':
 | 
			
		||||
                if (ds.Peek() == 'b') {
 | 
			
		||||
                    ds.Take();
 | 
			
		||||
                    codepoint = 0x0008; // Escape backspace character
 | 
			
		||||
                }
 | 
			
		||||
                else if (!CharacterEscape(ds, &codepoint))
 | 
			
		||||
                    return false;
 | 
			
		||||
                // fall through to default
 | 
			
		||||
                RAPIDJSON_DELIBERATE_FALLTHROUGH;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                switch (step) {
 | 
			
		||||
                case 1:
 | 
			
		||||
                    if (codepoint == '-') {
 | 
			
		||||
                        step++;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    // fall through to step 0 for other characters
 | 
			
		||||
                    RAPIDJSON_DELIBERATE_FALLTHROUGH;
 | 
			
		||||
 | 
			
		||||
                case 0:
 | 
			
		||||
                    {
 | 
			
		||||
                        SizeType r = NewRange(codepoint);
 | 
			
		||||
                        if (current != kRegexInvalidRange)
 | 
			
		||||
                            GetRange(current).next = r;
 | 
			
		||||
                        if (start == kRegexInvalidRange)
 | 
			
		||||
                            start = r;
 | 
			
		||||
                        current = r;
 | 
			
		||||
                    }
 | 
			
		||||
                    step = 1;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                    RAPIDJSON_ASSERT(step == 2);
 | 
			
		||||
                    GetRange(current).end = codepoint;
 | 
			
		||||
                    step = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    SizeType NewRange(unsigned codepoint) {
 | 
			
		||||
        Range* r = ranges_.template Push<Range>();
 | 
			
		||||
        r->start = r->end = codepoint;
 | 
			
		||||
        r->next = kRegexInvalidRange;
 | 
			
		||||
        return rangeCount_++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
 | 
			
		||||
        unsigned codepoint;
 | 
			
		||||
        switch (codepoint = ds.Take()) {
 | 
			
		||||
            case '^':
 | 
			
		||||
            case '$':
 | 
			
		||||
            case '|':
 | 
			
		||||
            case '(':
 | 
			
		||||
            case ')':
 | 
			
		||||
            case '?':
 | 
			
		||||
            case '*':
 | 
			
		||||
            case '+':
 | 
			
		||||
            case '.':
 | 
			
		||||
            case '[':
 | 
			
		||||
            case ']':
 | 
			
		||||
            case '{':
 | 
			
		||||
            case '}':
 | 
			
		||||
            case '\\':
 | 
			
		||||
                *escapedCodepoint = codepoint; return true;
 | 
			
		||||
            case 'f': *escapedCodepoint = 0x000C; return true;
 | 
			
		||||
            case 'n': *escapedCodepoint = 0x000A; return true;
 | 
			
		||||
            case 'r': *escapedCodepoint = 0x000D; return true;
 | 
			
		||||
            case 't': *escapedCodepoint = 0x0009; return true;
 | 
			
		||||
            case 'v': *escapedCodepoint = 0x000B; return true;
 | 
			
		||||
            default:
 | 
			
		||||
                return false; // Unsupported escape character
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Allocator* ownAllocator_;
 | 
			
		||||
    Allocator* allocator_;
 | 
			
		||||
    Stack<Allocator> states_;
 | 
			
		||||
    Stack<Allocator> ranges_;
 | 
			
		||||
    SizeType root_;
 | 
			
		||||
    SizeType stateCount_;
 | 
			
		||||
    SizeType rangeCount_;
 | 
			
		||||
 | 
			
		||||
    static const unsigned kInfinityQuantifier = ~0u;
 | 
			
		||||
 | 
			
		||||
    // For SearchWithAnchoring()
 | 
			
		||||
    bool anchorBegin_;
 | 
			
		||||
    bool anchorEnd_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename RegexType, typename Allocator = CrtAllocator>
 | 
			
		||||
class GenericRegexSearch {
 | 
			
		||||
public:
 | 
			
		||||
    typedef typename RegexType::EncodingType Encoding;
 | 
			
		||||
    typedef typename Encoding::Ch Ch;
 | 
			
		||||
 | 
			
		||||
    GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : 
 | 
			
		||||
        regex_(regex), allocator_(allocator), ownAllocator_(0),
 | 
			
		||||
        state0_(allocator, 0), state1_(allocator, 0), stateSet_()
 | 
			
		||||
    {
 | 
			
		||||
        RAPIDJSON_ASSERT(regex_.IsValid());
 | 
			
		||||
        if (!allocator_)
 | 
			
		||||
            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
 | 
			
		||||
        stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
 | 
			
		||||
        state0_.template Reserve<SizeType>(regex_.stateCount_);
 | 
			
		||||
        state1_.template Reserve<SizeType>(regex_.stateCount_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~GenericRegexSearch() {
 | 
			
		||||
        Allocator::Free(stateSet_);
 | 
			
		||||
        RAPIDJSON_DELETE(ownAllocator_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    bool Match(InputStream& is) {
 | 
			
		||||
        return SearchWithAnchoring(is, true, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Match(const Ch* s) {
 | 
			
		||||
        GenericStringStream<Encoding> is(s);
 | 
			
		||||
        return Match(is);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    bool Search(InputStream& is) {
 | 
			
		||||
        return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Search(const Ch* s) {
 | 
			
		||||
        GenericStringStream<Encoding> is(s);
 | 
			
		||||
        return Search(is);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    typedef typename RegexType::State State;
 | 
			
		||||
    typedef typename RegexType::Range Range;
 | 
			
		||||
 | 
			
		||||
    template <typename InputStream>
 | 
			
		||||
    bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
 | 
			
		||||
        DecodedStream<InputStream, Encoding> ds(is);
 | 
			
		||||
 | 
			
		||||
        state0_.Clear();
 | 
			
		||||
        Stack<Allocator> *current = &state0_, *next = &state1_;
 | 
			
		||||
        const size_t stateSetSize = GetStateSetSize();
 | 
			
		||||
        std::memset(stateSet_, 0, stateSetSize);
 | 
			
		||||
 | 
			
		||||
        bool matched = AddState(*current, regex_.root_);
 | 
			
		||||
        unsigned codepoint;
 | 
			
		||||
        while (!current->Empty() && (codepoint = ds.Take()) != 0) {
 | 
			
		||||
            std::memset(stateSet_, 0, stateSetSize);
 | 
			
		||||
            next->Clear();
 | 
			
		||||
            matched = false;
 | 
			
		||||
            for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
 | 
			
		||||
                const State& sr = regex_.GetState(*s);
 | 
			
		||||
                if (sr.codepoint == codepoint ||
 | 
			
		||||
                    sr.codepoint == RegexType::kAnyCharacterClass || 
 | 
			
		||||
                    (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
 | 
			
		||||
                {
 | 
			
		||||
                    matched = AddState(*next, sr.out) || matched;
 | 
			
		||||
                    if (!anchorEnd && matched)
 | 
			
		||||
                        return true;
 | 
			
		||||
                }
 | 
			
		||||
                if (!anchorBegin)
 | 
			
		||||
                    AddState(*next, regex_.root_);
 | 
			
		||||
            }
 | 
			
		||||
            internal::Swap(current, next);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return matched;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t GetStateSetSize() const {
 | 
			
		||||
        return (regex_.stateCount_ + 31) / 32 * 4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Return whether the added states is a match state
 | 
			
		||||
    bool AddState(Stack<Allocator>& l, SizeType index) {
 | 
			
		||||
        RAPIDJSON_ASSERT(index != kRegexInvalidState);
 | 
			
		||||
 | 
			
		||||
        const State& s = regex_.GetState(index);
 | 
			
		||||
        if (s.out1 != kRegexInvalidState) { // Split
 | 
			
		||||
            bool matched = AddState(l, s.out);
 | 
			
		||||
            return AddState(l, s.out1) || matched;
 | 
			
		||||
        }
 | 
			
		||||
        else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
 | 
			
		||||
            stateSet_[index >> 5] |= (1u << (index & 31));
 | 
			
		||||
            *l.template PushUnsafe<SizeType>() = index;
 | 
			
		||||
        }
 | 
			
		||||
        return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
 | 
			
		||||
        bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
 | 
			
		||||
        while (rangeIndex != kRegexInvalidRange) {
 | 
			
		||||
            const Range& r = regex_.GetRange(rangeIndex);
 | 
			
		||||
            if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
 | 
			
		||||
                return yes;
 | 
			
		||||
            rangeIndex = r.next;
 | 
			
		||||
        }
 | 
			
		||||
        return !yes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const RegexType& regex_;
 | 
			
		||||
    Allocator* allocator_;
 | 
			
		||||
    Allocator* ownAllocator_;
 | 
			
		||||
    Stack<Allocator> state0_;
 | 
			
		||||
    Stack<Allocator> state1_;
 | 
			
		||||
    uint32_t* stateSet_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef GenericRegex<UTF8<> > Regex;
 | 
			
		||||
typedef GenericRegexSearch<Regex> RegexSearch;
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__) || defined(_MSC_VER)
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_INTERNAL_REGEX_H_
 | 
			
		||||
							
								
								
									
										232
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_stack.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_stack.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,232 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_INTERNAL_STACK_H_
 | 
			
		||||
#define RAPIDJSON_INTERNAL_STACK_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_allocators.h"
 | 
			
		||||
#include "lottie_rapidjson_internal_swap.h"
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(c++98-compat)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Stack
 | 
			
		||||
 | 
			
		||||
//! A type-unsafe stack for storing different types of data.
 | 
			
		||||
/*! \tparam Allocator Allocator for allocating stack memory.
 | 
			
		||||
*/
 | 
			
		||||
template <typename Allocator>
 | 
			
		||||
class Stack {
 | 
			
		||||
public:
 | 
			
		||||
    // Optimization note: Do not allocate memory for stack_ in constructor.
 | 
			
		||||
    // Do it lazily when first Push() -> Expand() -> Resize().
 | 
			
		||||
    Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
 | 
			
		||||
    Stack(Stack&& rhs)
 | 
			
		||||
        : allocator_(rhs.allocator_),
 | 
			
		||||
          ownAllocator_(rhs.ownAllocator_),
 | 
			
		||||
          stack_(rhs.stack_),
 | 
			
		||||
          stackTop_(rhs.stackTop_),
 | 
			
		||||
          stackEnd_(rhs.stackEnd_),
 | 
			
		||||
          initialCapacity_(rhs.initialCapacity_)
 | 
			
		||||
    {
 | 
			
		||||
        rhs.allocator_ = 0;
 | 
			
		||||
        rhs.ownAllocator_ = 0;
 | 
			
		||||
        rhs.stack_ = 0;
 | 
			
		||||
        rhs.stackTop_ = 0;
 | 
			
		||||
        rhs.stackEnd_ = 0;
 | 
			
		||||
        rhs.initialCapacity_ = 0;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    ~Stack() {
 | 
			
		||||
        Destroy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
 | 
			
		||||
    Stack& operator=(Stack&& rhs) {
 | 
			
		||||
        if (&rhs != this)
 | 
			
		||||
        {
 | 
			
		||||
            Destroy();
 | 
			
		||||
 | 
			
		||||
            allocator_ = rhs.allocator_;
 | 
			
		||||
            ownAllocator_ = rhs.ownAllocator_;
 | 
			
		||||
            stack_ = rhs.stack_;
 | 
			
		||||
            stackTop_ = rhs.stackTop_;
 | 
			
		||||
            stackEnd_ = rhs.stackEnd_;
 | 
			
		||||
            initialCapacity_ = rhs.initialCapacity_;
 | 
			
		||||
 | 
			
		||||
            rhs.allocator_ = 0;
 | 
			
		||||
            rhs.ownAllocator_ = 0;
 | 
			
		||||
            rhs.stack_ = 0;
 | 
			
		||||
            rhs.stackTop_ = 0;
 | 
			
		||||
            rhs.stackEnd_ = 0;
 | 
			
		||||
            rhs.initialCapacity_ = 0;
 | 
			
		||||
        }
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
 | 
			
		||||
        internal::Swap(allocator_, rhs.allocator_);
 | 
			
		||||
        internal::Swap(ownAllocator_, rhs.ownAllocator_);
 | 
			
		||||
        internal::Swap(stack_, rhs.stack_);
 | 
			
		||||
        internal::Swap(stackTop_, rhs.stackTop_);
 | 
			
		||||
        internal::Swap(stackEnd_, rhs.stackEnd_);
 | 
			
		||||
        internal::Swap(initialCapacity_, rhs.initialCapacity_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Clear() { stackTop_ = stack_; }
 | 
			
		||||
 | 
			
		||||
    void ShrinkToFit() { 
 | 
			
		||||
        if (Empty()) {
 | 
			
		||||
            // If the stack is empty, completely deallocate the memory.
 | 
			
		||||
            Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
 | 
			
		||||
            stack_ = 0;
 | 
			
		||||
            stackTop_ = 0;
 | 
			
		||||
            stackEnd_ = 0;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            Resize(GetSize());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Optimization note: try to minimize the size of this function for force inline.
 | 
			
		||||
    // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
 | 
			
		||||
         // Expand the stack if needed
 | 
			
		||||
        if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
 | 
			
		||||
            Expand<T>(count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
 | 
			
		||||
        Reserve<T>(count);
 | 
			
		||||
        return PushUnsafe<T>(count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
 | 
			
		||||
        RAPIDJSON_ASSERT(stackTop_);
 | 
			
		||||
        RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
 | 
			
		||||
        T* ret = reinterpret_cast<T*>(stackTop_);
 | 
			
		||||
        stackTop_ += sizeof(T) * count;
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    T* Pop(size_t count) {
 | 
			
		||||
        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
 | 
			
		||||
        stackTop_ -= count * sizeof(T);
 | 
			
		||||
        return reinterpret_cast<T*>(stackTop_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    T* Top() { 
 | 
			
		||||
        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
 | 
			
		||||
        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    const T* Top() const {
 | 
			
		||||
        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
 | 
			
		||||
        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    T* End() { return reinterpret_cast<T*>(stackTop_); }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    const T* End() const { return reinterpret_cast<T*>(stackTop_); }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    T* Bottom() { return reinterpret_cast<T*>(stack_); }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
 | 
			
		||||
 | 
			
		||||
    bool HasAllocator() const {
 | 
			
		||||
        return allocator_ != 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Allocator& GetAllocator() {
 | 
			
		||||
        RAPIDJSON_ASSERT(allocator_);
 | 
			
		||||
        return *allocator_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Empty() const { return stackTop_ == stack_; }
 | 
			
		||||
    size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
 | 
			
		||||
    size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    void Expand(size_t count) {
 | 
			
		||||
        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
 | 
			
		||||
        size_t newCapacity;
 | 
			
		||||
        if (stack_ == 0) {
 | 
			
		||||
            if (!allocator_)
 | 
			
		||||
                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
 | 
			
		||||
            newCapacity = initialCapacity_;
 | 
			
		||||
        } else {
 | 
			
		||||
            newCapacity = GetCapacity();
 | 
			
		||||
            newCapacity += (newCapacity + 1) / 2;
 | 
			
		||||
        }
 | 
			
		||||
        size_t newSize = GetSize() + sizeof(T) * count;
 | 
			
		||||
        if (newCapacity < newSize)
 | 
			
		||||
            newCapacity = newSize;
 | 
			
		||||
 | 
			
		||||
        Resize(newCapacity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Resize(size_t newCapacity) {
 | 
			
		||||
        const size_t size = GetSize();  // Backup the current size
 | 
			
		||||
        stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
 | 
			
		||||
        stackTop_ = stack_ + size;
 | 
			
		||||
        stackEnd_ = stack_ + newCapacity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Destroy() {
 | 
			
		||||
        Allocator::Free(stack_);
 | 
			
		||||
        RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Prohibit copy constructor & assignment operator.
 | 
			
		||||
    Stack(const Stack&);
 | 
			
		||||
    Stack& operator=(const Stack&);
 | 
			
		||||
 | 
			
		||||
    Allocator* allocator_;
 | 
			
		||||
    Allocator* ownAllocator_;
 | 
			
		||||
    char *stack_;
 | 
			
		||||
    char *stackTop_;
 | 
			
		||||
    char *stackEnd_;
 | 
			
		||||
    size_t initialCapacity_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_STACK_H_
 | 
			
		||||
							
								
								
									
										69
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_strfunc.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_strfunc.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
 | 
			
		||||
#define RAPIDJSON_INTERNAL_STRFUNC_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_stream.h"
 | 
			
		||||
#include <cwchar>
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
//! Custom strlen() which works on different character types.
 | 
			
		||||
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
 | 
			
		||||
    \param s Null-terminated input string.
 | 
			
		||||
    \return Number of characters in the string. 
 | 
			
		||||
    \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
 | 
			
		||||
*/
 | 
			
		||||
template <typename Ch>
 | 
			
		||||
inline SizeType StrLen(const Ch* s) {
 | 
			
		||||
    RAPIDJSON_ASSERT(s != 0);
 | 
			
		||||
    const Ch* p = s;
 | 
			
		||||
    while (*p) ++p;
 | 
			
		||||
    return SizeType(p - s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
inline SizeType StrLen(const char* s) {
 | 
			
		||||
    return SizeType(std::strlen(s));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
inline SizeType StrLen(const wchar_t* s) {
 | 
			
		||||
    return SizeType(std::wcslen(s));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//! Returns number of code points in a encoded string.
 | 
			
		||||
template<typename Encoding>
 | 
			
		||||
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
 | 
			
		||||
    RAPIDJSON_ASSERT(s != 0);
 | 
			
		||||
    RAPIDJSON_ASSERT(outCount != 0);
 | 
			
		||||
    GenericStringStream<Encoding> is(s);
 | 
			
		||||
    const typename Encoding::Ch* end = s + length;
 | 
			
		||||
    SizeType count = 0;
 | 
			
		||||
    while (is.src_ < end) {
 | 
			
		||||
        unsigned codepoint;
 | 
			
		||||
        if (!Encoding::Decode(is, &codepoint))
 | 
			
		||||
            return false;
 | 
			
		||||
        count++;
 | 
			
		||||
    }
 | 
			
		||||
    *outCount = count;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
 | 
			
		||||
							
								
								
									
										290
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_strtod.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_strtod.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,290 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_STRTOD_
 | 
			
		||||
#define RAPIDJSON_STRTOD_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_internal_ieee754.h"
 | 
			
		||||
#include "lottie_rapidjson_internal_biginteger.h"
 | 
			
		||||
#include "lottie_rapidjson_internal_diyfp.h"
 | 
			
		||||
#include "lottie_rapidjson_internal_pow10.h"
 | 
			
		||||
#include <climits>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
inline double FastPath(double significand, int exp) {
 | 
			
		||||
    if (exp < -308)
 | 
			
		||||
        return 0.0;
 | 
			
		||||
    else if (exp >= 0)
 | 
			
		||||
        return significand * internal::Pow10(exp);
 | 
			
		||||
    else
 | 
			
		||||
        return significand / internal::Pow10(-exp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline double StrtodNormalPrecision(double d, int p) {
 | 
			
		||||
    if (p < -308) {
 | 
			
		||||
        // Prevent expSum < -308, making Pow10(p) = 0
 | 
			
		||||
        d = FastPath(d, -308);
 | 
			
		||||
        d = FastPath(d, p + 308);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        d = FastPath(d, p);
 | 
			
		||||
    return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
inline T Min3(T a, T b, T c) {
 | 
			
		||||
    T m = a;
 | 
			
		||||
    if (m > b) m = b;
 | 
			
		||||
    if (m > c) m = c;
 | 
			
		||||
    return m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
 | 
			
		||||
    const Double db(b);
 | 
			
		||||
    const uint64_t bInt = db.IntegerSignificand();
 | 
			
		||||
    const int bExp = db.IntegerExponent();
 | 
			
		||||
    const int hExp = bExp - 1;
 | 
			
		||||
 | 
			
		||||
    int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
 | 
			
		||||
 | 
			
		||||
    // Adjust for decimal exponent
 | 
			
		||||
    if (dExp >= 0) {
 | 
			
		||||
        dS_Exp2 += dExp;
 | 
			
		||||
        dS_Exp5 += dExp;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        bS_Exp2 -= dExp;
 | 
			
		||||
        bS_Exp5 -= dExp;
 | 
			
		||||
        hS_Exp2 -= dExp;
 | 
			
		||||
        hS_Exp5 -= dExp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Adjust for binary exponent
 | 
			
		||||
    if (bExp >= 0)
 | 
			
		||||
        bS_Exp2 += bExp;
 | 
			
		||||
    else {
 | 
			
		||||
        dS_Exp2 -= bExp;
 | 
			
		||||
        hS_Exp2 -= bExp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Adjust for half ulp exponent
 | 
			
		||||
    if (hExp >= 0)
 | 
			
		||||
        hS_Exp2 += hExp;
 | 
			
		||||
    else {
 | 
			
		||||
        dS_Exp2 -= hExp;
 | 
			
		||||
        bS_Exp2 -= hExp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Remove common power of two factor from all three scaled values
 | 
			
		||||
    int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
 | 
			
		||||
    dS_Exp2 -= common_Exp2;
 | 
			
		||||
    bS_Exp2 -= common_Exp2;
 | 
			
		||||
    hS_Exp2 -= common_Exp2;
 | 
			
		||||
 | 
			
		||||
    BigInteger dS = d;
 | 
			
		||||
    dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
 | 
			
		||||
 | 
			
		||||
    BigInteger bS(bInt);
 | 
			
		||||
    bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
 | 
			
		||||
 | 
			
		||||
    BigInteger hS(1);
 | 
			
		||||
    hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
 | 
			
		||||
 | 
			
		||||
    BigInteger delta(0);
 | 
			
		||||
    dS.Difference(bS, &delta);
 | 
			
		||||
 | 
			
		||||
    return delta.Compare(hS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool StrtodFast(double d, int p, double* result) {
 | 
			
		||||
    // Use fast path for string-to-double conversion if possible
 | 
			
		||||
    // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
 | 
			
		||||
    if (p > 22  && p < 22 + 16) {
 | 
			
		||||
        // Fast Path Cases In Disguise
 | 
			
		||||
        d *= internal::Pow10(p - 22);
 | 
			
		||||
        p = 22;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
 | 
			
		||||
        *result = FastPath(d, p);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Compute an approximation and see if it is within 1/2 ULP
 | 
			
		||||
inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
 | 
			
		||||
    uint64_t significand = 0;
 | 
			
		||||
    int i = 0;   // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999    
 | 
			
		||||
    for (; i < dLen; i++) {
 | 
			
		||||
        if (significand  >  RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
 | 
			
		||||
            (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
 | 
			
		||||
            break;
 | 
			
		||||
        significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (i < dLen && decimals[i] >= '5') // Rounding
 | 
			
		||||
        significand++;
 | 
			
		||||
 | 
			
		||||
    int remaining = dLen - i;
 | 
			
		||||
    const int kUlpShift = 3;
 | 
			
		||||
    const int kUlp = 1 << kUlpShift;
 | 
			
		||||
    int64_t error = (remaining == 0) ? 0 : kUlp / 2;
 | 
			
		||||
 | 
			
		||||
    DiyFp v(significand, 0);
 | 
			
		||||
    v = v.Normalize();
 | 
			
		||||
    error <<= -v.e;
 | 
			
		||||
 | 
			
		||||
    dExp += remaining;
 | 
			
		||||
 | 
			
		||||
    int actualExp;
 | 
			
		||||
    DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
 | 
			
		||||
    if (actualExp != dExp) {
 | 
			
		||||
        static const DiyFp kPow10[] = {
 | 
			
		||||
            DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60),  // 10^1
 | 
			
		||||
            DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57),  // 10^2
 | 
			
		||||
            DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54),  // 10^3
 | 
			
		||||
            DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50),  // 10^4
 | 
			
		||||
            DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47),  // 10^5
 | 
			
		||||
            DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44),  // 10^6
 | 
			
		||||
            DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40)   // 10^7
 | 
			
		||||
        };
 | 
			
		||||
        int adjustment = dExp - actualExp;
 | 
			
		||||
        RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
 | 
			
		||||
        v = v * kPow10[adjustment - 1];
 | 
			
		||||
        if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit
 | 
			
		||||
            error += kUlp / 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    v = v * cachedPower;
 | 
			
		||||
 | 
			
		||||
    error += kUlp + (error == 0 ? 0 : 1);
 | 
			
		||||
 | 
			
		||||
    const int oldExp = v.e;
 | 
			
		||||
    v = v.Normalize();
 | 
			
		||||
    error <<= oldExp - v.e;
 | 
			
		||||
 | 
			
		||||
    const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
 | 
			
		||||
    int precisionSize = 64 - effectiveSignificandSize;
 | 
			
		||||
    if (precisionSize + kUlpShift >= 64) {
 | 
			
		||||
        int scaleExp = (precisionSize + kUlpShift) - 63;
 | 
			
		||||
        v.f >>= scaleExp;
 | 
			
		||||
        v.e += scaleExp; 
 | 
			
		||||
        error = (error >> scaleExp) + 1 + kUlp;
 | 
			
		||||
        precisionSize -= scaleExp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
 | 
			
		||||
    const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
 | 
			
		||||
    const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
 | 
			
		||||
    if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
 | 
			
		||||
        rounded.f++;
 | 
			
		||||
        if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
 | 
			
		||||
            rounded.f >>= 1;
 | 
			
		||||
            rounded.e++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *result = rounded.ToDouble();
 | 
			
		||||
 | 
			
		||||
    return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
 | 
			
		||||
    RAPIDJSON_ASSERT(dLen >= 0);
 | 
			
		||||
    const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
 | 
			
		||||
    Double a(approx);
 | 
			
		||||
    int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
 | 
			
		||||
    if (cmp < 0)
 | 
			
		||||
        return a.Value();  // within half ULP
 | 
			
		||||
    else if (cmp == 0) {
 | 
			
		||||
        // Round towards even
 | 
			
		||||
        if (a.Significand() & 1)
 | 
			
		||||
            return a.NextPositiveDouble();
 | 
			
		||||
        else
 | 
			
		||||
            return a.Value();
 | 
			
		||||
    }
 | 
			
		||||
    else // adjustment
 | 
			
		||||
        return a.NextPositiveDouble();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
 | 
			
		||||
    RAPIDJSON_ASSERT(d >= 0.0);
 | 
			
		||||
    RAPIDJSON_ASSERT(length >= 1);
 | 
			
		||||
 | 
			
		||||
    double result = 0.0;
 | 
			
		||||
    if (StrtodFast(d, p, &result))
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    RAPIDJSON_ASSERT(length <= INT_MAX);
 | 
			
		||||
    int dLen = static_cast<int>(length);
 | 
			
		||||
 | 
			
		||||
    RAPIDJSON_ASSERT(length >= decimalPosition);
 | 
			
		||||
    RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
 | 
			
		||||
    int dExpAdjust = static_cast<int>(length - decimalPosition);
 | 
			
		||||
 | 
			
		||||
    RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
 | 
			
		||||
    int dExp = exp - dExpAdjust;
 | 
			
		||||
 | 
			
		||||
    // Make sure length+dExp does not overflow
 | 
			
		||||
    RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
 | 
			
		||||
 | 
			
		||||
    // Trim leading zeros
 | 
			
		||||
    while (dLen > 0 && *decimals == '0') {
 | 
			
		||||
        dLen--;
 | 
			
		||||
        decimals++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Trim trailing zeros
 | 
			
		||||
    while (dLen > 0 && decimals[dLen - 1] == '0') {
 | 
			
		||||
        dLen--;
 | 
			
		||||
        dExp++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dLen == 0) { // Buffer only contains zeros.
 | 
			
		||||
        return 0.0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Trim right-most digits
 | 
			
		||||
    const int kMaxDecimalDigit = 767 + 1;
 | 
			
		||||
    if (dLen > kMaxDecimalDigit) {
 | 
			
		||||
        dExp += dLen - kMaxDecimalDigit;
 | 
			
		||||
        dLen = kMaxDecimalDigit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If too small, underflow to zero.
 | 
			
		||||
    // Any x <= 10^-324 is interpreted as zero.
 | 
			
		||||
    if (dLen + dExp <= -324)
 | 
			
		||||
        return 0.0;
 | 
			
		||||
 | 
			
		||||
    // If too large, overflow to infinity.
 | 
			
		||||
    // Any x >= 10^309 is interpreted as +infinity.
 | 
			
		||||
    if (dLen + dExp > 309)
 | 
			
		||||
        return std::numeric_limits<double>::infinity();
 | 
			
		||||
 | 
			
		||||
    if (StrtodDiyFp(decimals, dLen, dExp, &result))
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
 | 
			
		||||
    return StrtodBigInteger(result, decimals, dLen, dExp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_STRTOD_
 | 
			
		||||
							
								
								
									
										46
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_swap.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_internal_swap.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
 | 
			
		||||
#define RAPIDJSON_INTERNAL_SWAP_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_rapidjson.h"
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(c++98-compat)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
namespace internal {
 | 
			
		||||
 | 
			
		||||
//! Custom swap() to avoid dependency on C++ <algorithm> header
 | 
			
		||||
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
 | 
			
		||||
    \note This has the same semantics as std::swap().
 | 
			
		||||
*/
 | 
			
		||||
template <typename T>
 | 
			
		||||
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
 | 
			
		||||
    T tmp = a;
 | 
			
		||||
        a = b;
 | 
			
		||||
        b = tmp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace internal
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_INTERNAL_SWAP_H_
 | 
			
		||||
							
								
								
									
										128
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_istreamwrapper.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_istreamwrapper.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
 | 
			
		||||
#define RAPIDJSON_ISTREAMWRAPPER_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_stream.h"
 | 
			
		||||
#include <iosfwd>
 | 
			
		||||
#include <ios>
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(padded)
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
 | 
			
		||||
/*!
 | 
			
		||||
    The classes can be wrapped including but not limited to:
 | 
			
		||||
 | 
			
		||||
    - \c std::istringstream
 | 
			
		||||
    - \c std::stringstream
 | 
			
		||||
    - \c std::wistringstream
 | 
			
		||||
    - \c std::wstringstream
 | 
			
		||||
    - \c std::ifstream
 | 
			
		||||
    - \c std::fstream
 | 
			
		||||
    - \c std::wifstream
 | 
			
		||||
    - \c std::wfstream
 | 
			
		||||
 | 
			
		||||
    \tparam StreamType Class derived from \c std::basic_istream.
 | 
			
		||||
*/
 | 
			
		||||
   
 | 
			
		||||
template <typename StreamType>
 | 
			
		||||
class BasicIStreamWrapper {
 | 
			
		||||
public:
 | 
			
		||||
    typedef typename StreamType::char_type Ch;
 | 
			
		||||
 | 
			
		||||
    //! Constructor.
 | 
			
		||||
    /*!
 | 
			
		||||
        \param stream stream opened for read.
 | 
			
		||||
    */
 | 
			
		||||
    BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 
 | 
			
		||||
        Read();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //! Constructor.
 | 
			
		||||
    /*!
 | 
			
		||||
        \param stream stream opened for read.
 | 
			
		||||
        \param buffer user-supplied buffer.
 | 
			
		||||
        \param bufferSize size of buffer in bytes. Must >=4 bytes.
 | 
			
		||||
    */
 | 
			
		||||
    BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 
 | 
			
		||||
        RAPIDJSON_ASSERT(bufferSize >= 4);
 | 
			
		||||
        Read();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ch Peek() const { return *current_; }
 | 
			
		||||
    Ch Take() { Ch c = *current_; Read(); return c; }
 | 
			
		||||
    size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
 | 
			
		||||
 | 
			
		||||
    // Not implemented
 | 
			
		||||
    void Put(Ch) { RAPIDJSON_ASSERT(false); }
 | 
			
		||||
    void Flush() { RAPIDJSON_ASSERT(false); } 
 | 
			
		||||
    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
 | 
			
		||||
    // For encoding detection only.
 | 
			
		||||
    const Ch* Peek4() const {
 | 
			
		||||
        return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    BasicIStreamWrapper();
 | 
			
		||||
    BasicIStreamWrapper(const BasicIStreamWrapper&);
 | 
			
		||||
    BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
 | 
			
		||||
 | 
			
		||||
    void Read() {
 | 
			
		||||
        if (current_ < bufferLast_)
 | 
			
		||||
            ++current_;
 | 
			
		||||
        else if (!eof_) {
 | 
			
		||||
            count_ += readCount_;
 | 
			
		||||
            readCount_ = bufferSize_;
 | 
			
		||||
            bufferLast_ = buffer_ + readCount_ - 1;
 | 
			
		||||
            current_ = buffer_;
 | 
			
		||||
 | 
			
		||||
            if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {
 | 
			
		||||
                readCount_ = static_cast<size_t>(stream_.gcount());
 | 
			
		||||
                *(bufferLast_ = buffer_ + readCount_) = '\0';
 | 
			
		||||
                eof_ = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    StreamType &stream_;
 | 
			
		||||
    Ch peekBuffer_[4], *buffer_;
 | 
			
		||||
    size_t bufferSize_;
 | 
			
		||||
    Ch *bufferLast_;
 | 
			
		||||
    Ch *current_;
 | 
			
		||||
    size_t readCount_;
 | 
			
		||||
    size_t count_;  //!< Number of characters read
 | 
			
		||||
    bool eof_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
 | 
			
		||||
typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__) || defined(_MSC_VER)
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_ISTREAMWRAPPER_H_
 | 
			
		||||
							
								
								
									
										70
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_memorybuffer.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_memorybuffer.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_MEMORYBUFFER_H_
 | 
			
		||||
#define RAPIDJSON_MEMORYBUFFER_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_stream.h"
 | 
			
		||||
#include "lottie_rapidjson_internal_stack.h"
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
//! Represents an in-memory output byte stream.
 | 
			
		||||
/*!
 | 
			
		||||
    This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
 | 
			
		||||
 | 
			
		||||
    It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
 | 
			
		||||
 | 
			
		||||
    Differences between MemoryBuffer and StringBuffer:
 | 
			
		||||
    1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 
 | 
			
		||||
    2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
 | 
			
		||||
 | 
			
		||||
    \tparam Allocator type for allocating memory buffer.
 | 
			
		||||
    \note implements Stream concept
 | 
			
		||||
*/
 | 
			
		||||
template <typename Allocator = CrtAllocator>
 | 
			
		||||
struct GenericMemoryBuffer {
 | 
			
		||||
    typedef char Ch; // byte
 | 
			
		||||
 | 
			
		||||
    GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
 | 
			
		||||
 | 
			
		||||
    void Put(Ch c) { *stack_.template Push<Ch>() = c; }
 | 
			
		||||
    void Flush() {}
 | 
			
		||||
 | 
			
		||||
    void Clear() { stack_.Clear(); }
 | 
			
		||||
    void ShrinkToFit() { stack_.ShrinkToFit(); }
 | 
			
		||||
    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
 | 
			
		||||
    void Pop(size_t count) { stack_.template Pop<Ch>(count); }
 | 
			
		||||
 | 
			
		||||
    const Ch* GetBuffer() const {
 | 
			
		||||
        return stack_.template Bottom<Ch>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t GetSize() const { return stack_.GetSize(); }
 | 
			
		||||
 | 
			
		||||
    static const size_t kDefaultCapacity = 256;
 | 
			
		||||
    mutable internal::Stack<Allocator> stack_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef GenericMemoryBuffer<> MemoryBuffer;
 | 
			
		||||
 | 
			
		||||
//! Implement specialized version of PutN() with memset() for better performance.
 | 
			
		||||
template<>
 | 
			
		||||
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
 | 
			
		||||
    std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_MEMORYBUFFER_H_
 | 
			
		||||
							
								
								
									
										71
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_memorystream.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_memorystream.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_MEMORYSTREAM_H_
 | 
			
		||||
#define RAPIDJSON_MEMORYSTREAM_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_stream.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(unreachable-code)
 | 
			
		||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
//! Represents an in-memory input byte stream.
 | 
			
		||||
/*!
 | 
			
		||||
    This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
 | 
			
		||||
 | 
			
		||||
    It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
 | 
			
		||||
 | 
			
		||||
    Differences between MemoryStream and StringStream:
 | 
			
		||||
    1. StringStream has encoding but MemoryStream is a byte stream.
 | 
			
		||||
    2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
 | 
			
		||||
    3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
 | 
			
		||||
    \note implements Stream concept
 | 
			
		||||
*/
 | 
			
		||||
struct MemoryStream {
 | 
			
		||||
    typedef char Ch; // byte
 | 
			
		||||
 | 
			
		||||
    MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
 | 
			
		||||
 | 
			
		||||
    Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
 | 
			
		||||
    Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
 | 
			
		||||
    size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
 | 
			
		||||
 | 
			
		||||
    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    void Put(Ch) { RAPIDJSON_ASSERT(false); }
 | 
			
		||||
    void Flush() { RAPIDJSON_ASSERT(false); }
 | 
			
		||||
    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
 | 
			
		||||
    // For encoding detection only.
 | 
			
		||||
    const Ch* Peek4() const {
 | 
			
		||||
        return Tell() + 4 <= size_ ? src_ : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const Ch* src_;     //!< Current read position.
 | 
			
		||||
    const Ch* begin_;   //!< Original head of the string.
 | 
			
		||||
    const Ch* end_;     //!< End of stream.
 | 
			
		||||
    size_t size_;       //!< Size of the stream.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_MEMORYBUFFER_H_
 | 
			
		||||
							
								
								
									
										316
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_msinttypes_inttypes.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_msinttypes_inttypes.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,316 @@
 | 
			
		||||
// ISO C9x  compliant inttypes.h for Microsoft Visual Studio
 | 
			
		||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
 | 
			
		||||
// 
 | 
			
		||||
//  Copyright (c) 2006-2013 Alexander Chemeris
 | 
			
		||||
// 
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without
 | 
			
		||||
// modification, are permitted provided that the following conditions are met:
 | 
			
		||||
// 
 | 
			
		||||
//   1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
//      this list of conditions and the following disclaimer.
 | 
			
		||||
// 
 | 
			
		||||
//   2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
//      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
//      documentation and/or other materials provided with the distribution.
 | 
			
		||||
// 
 | 
			
		||||
//   3. Neither the name of the product nor the names of its contributors may
 | 
			
		||||
//      be used to endorse or promote products derived from this software
 | 
			
		||||
//      without specific prior written permission.
 | 
			
		||||
// 
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
			
		||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 | 
			
		||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | 
			
		||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 | 
			
		||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | 
			
		||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
// 
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// The above software in this distribution may have been modified by 
 | 
			
		||||
// THL A29 Limited ("Tencent Modifications"). 
 | 
			
		||||
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
 | 
			
		||||
 | 
			
		||||
#ifndef _MSC_VER // [
 | 
			
		||||
#error "Use this header only with Microsoft Visual C++ compilers!"
 | 
			
		||||
#endif // _MSC_VER ]
 | 
			
		||||
 | 
			
		||||
#ifndef _MSC_INTTYPES_H_ // [
 | 
			
		||||
#define _MSC_INTTYPES_H_
 | 
			
		||||
 | 
			
		||||
#if _MSC_VER > 1000
 | 
			
		||||
#pragma once
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_msinttypes_stdint.h"
 | 
			
		||||
 | 
			
		||||
// miloyip: VC supports inttypes.h since VC2013
 | 
			
		||||
#if _MSC_VER >= 1800
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
// 7.8 Format conversion of integer types
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
   intmax_t quot;
 | 
			
		||||
   intmax_t rem;
 | 
			
		||||
} imaxdiv_t;
 | 
			
		||||
 | 
			
		||||
// 7.8.1 Macros for format specifiers
 | 
			
		||||
 | 
			
		||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198
 | 
			
		||||
 | 
			
		||||
// The fprintf macros for signed integers are:
 | 
			
		||||
#define PRId8       "d"
 | 
			
		||||
#define PRIi8       "i"
 | 
			
		||||
#define PRIdLEAST8  "d"
 | 
			
		||||
#define PRIiLEAST8  "i"
 | 
			
		||||
#define PRIdFAST8   "d"
 | 
			
		||||
#define PRIiFAST8   "i"
 | 
			
		||||
 | 
			
		||||
#define PRId16       "hd"
 | 
			
		||||
#define PRIi16       "hi"
 | 
			
		||||
#define PRIdLEAST16  "hd"
 | 
			
		||||
#define PRIiLEAST16  "hi"
 | 
			
		||||
#define PRIdFAST16   "hd"
 | 
			
		||||
#define PRIiFAST16   "hi"
 | 
			
		||||
 | 
			
		||||
#define PRId32       "I32d"
 | 
			
		||||
#define PRIi32       "I32i"
 | 
			
		||||
#define PRIdLEAST32  "I32d"
 | 
			
		||||
#define PRIiLEAST32  "I32i"
 | 
			
		||||
#define PRIdFAST32   "I32d"
 | 
			
		||||
#define PRIiFAST32   "I32i"
 | 
			
		||||
 | 
			
		||||
#define PRId64       "I64d"
 | 
			
		||||
#define PRIi64       "I64i"
 | 
			
		||||
#define PRIdLEAST64  "I64d"
 | 
			
		||||
#define PRIiLEAST64  "I64i"
 | 
			
		||||
#define PRIdFAST64   "I64d"
 | 
			
		||||
#define PRIiFAST64   "I64i"
 | 
			
		||||
 | 
			
		||||
#define PRIdMAX     "I64d"
 | 
			
		||||
#define PRIiMAX     "I64i"
 | 
			
		||||
 | 
			
		||||
#define PRIdPTR     "Id"
 | 
			
		||||
#define PRIiPTR     "Ii"
 | 
			
		||||
 | 
			
		||||
// The fprintf macros for unsigned integers are:
 | 
			
		||||
#define PRIo8       "o"
 | 
			
		||||
#define PRIu8       "u"
 | 
			
		||||
#define PRIx8       "x"
 | 
			
		||||
#define PRIX8       "X"
 | 
			
		||||
#define PRIoLEAST8  "o"
 | 
			
		||||
#define PRIuLEAST8  "u"
 | 
			
		||||
#define PRIxLEAST8  "x"
 | 
			
		||||
#define PRIXLEAST8  "X"
 | 
			
		||||
#define PRIoFAST8   "o"
 | 
			
		||||
#define PRIuFAST8   "u"
 | 
			
		||||
#define PRIxFAST8   "x"
 | 
			
		||||
#define PRIXFAST8   "X"
 | 
			
		||||
 | 
			
		||||
#define PRIo16       "ho"
 | 
			
		||||
#define PRIu16       "hu"
 | 
			
		||||
#define PRIx16       "hx"
 | 
			
		||||
#define PRIX16       "hX"
 | 
			
		||||
#define PRIoLEAST16  "ho"
 | 
			
		||||
#define PRIuLEAST16  "hu"
 | 
			
		||||
#define PRIxLEAST16  "hx"
 | 
			
		||||
#define PRIXLEAST16  "hX"
 | 
			
		||||
#define PRIoFAST16   "ho"
 | 
			
		||||
#define PRIuFAST16   "hu"
 | 
			
		||||
#define PRIxFAST16   "hx"
 | 
			
		||||
#define PRIXFAST16   "hX"
 | 
			
		||||
 | 
			
		||||
#define PRIo32       "I32o"
 | 
			
		||||
#define PRIu32       "I32u"
 | 
			
		||||
#define PRIx32       "I32x"
 | 
			
		||||
#define PRIX32       "I32X"
 | 
			
		||||
#define PRIoLEAST32  "I32o"
 | 
			
		||||
#define PRIuLEAST32  "I32u"
 | 
			
		||||
#define PRIxLEAST32  "I32x"
 | 
			
		||||
#define PRIXLEAST32  "I32X"
 | 
			
		||||
#define PRIoFAST32   "I32o"
 | 
			
		||||
#define PRIuFAST32   "I32u"
 | 
			
		||||
#define PRIxFAST32   "I32x"
 | 
			
		||||
#define PRIXFAST32   "I32X"
 | 
			
		||||
 | 
			
		||||
#define PRIo64       "I64o"
 | 
			
		||||
#define PRIu64       "I64u"
 | 
			
		||||
#define PRIx64       "I64x"
 | 
			
		||||
#define PRIX64       "I64X"
 | 
			
		||||
#define PRIoLEAST64  "I64o"
 | 
			
		||||
#define PRIuLEAST64  "I64u"
 | 
			
		||||
#define PRIxLEAST64  "I64x"
 | 
			
		||||
#define PRIXLEAST64  "I64X"
 | 
			
		||||
#define PRIoFAST64   "I64o"
 | 
			
		||||
#define PRIuFAST64   "I64u"
 | 
			
		||||
#define PRIxFAST64   "I64x"
 | 
			
		||||
#define PRIXFAST64   "I64X"
 | 
			
		||||
 | 
			
		||||
#define PRIoMAX     "I64o"
 | 
			
		||||
#define PRIuMAX     "I64u"
 | 
			
		||||
#define PRIxMAX     "I64x"
 | 
			
		||||
#define PRIXMAX     "I64X"
 | 
			
		||||
 | 
			
		||||
#define PRIoPTR     "Io"
 | 
			
		||||
#define PRIuPTR     "Iu"
 | 
			
		||||
#define PRIxPTR     "Ix"
 | 
			
		||||
#define PRIXPTR     "IX"
 | 
			
		||||
 | 
			
		||||
// The fscanf macros for signed integers are:
 | 
			
		||||
#define SCNd8       "d"
 | 
			
		||||
#define SCNi8       "i"
 | 
			
		||||
#define SCNdLEAST8  "d"
 | 
			
		||||
#define SCNiLEAST8  "i"
 | 
			
		||||
#define SCNdFAST8   "d"
 | 
			
		||||
#define SCNiFAST8   "i"
 | 
			
		||||
 | 
			
		||||
#define SCNd16       "hd"
 | 
			
		||||
#define SCNi16       "hi"
 | 
			
		||||
#define SCNdLEAST16  "hd"
 | 
			
		||||
#define SCNiLEAST16  "hi"
 | 
			
		||||
#define SCNdFAST16   "hd"
 | 
			
		||||
#define SCNiFAST16   "hi"
 | 
			
		||||
 | 
			
		||||
#define SCNd32       "ld"
 | 
			
		||||
#define SCNi32       "li"
 | 
			
		||||
#define SCNdLEAST32  "ld"
 | 
			
		||||
#define SCNiLEAST32  "li"
 | 
			
		||||
#define SCNdFAST32   "ld"
 | 
			
		||||
#define SCNiFAST32   "li"
 | 
			
		||||
 | 
			
		||||
#define SCNd64       "I64d"
 | 
			
		||||
#define SCNi64       "I64i"
 | 
			
		||||
#define SCNdLEAST64  "I64d"
 | 
			
		||||
#define SCNiLEAST64  "I64i"
 | 
			
		||||
#define SCNdFAST64   "I64d"
 | 
			
		||||
#define SCNiFAST64   "I64i"
 | 
			
		||||
 | 
			
		||||
#define SCNdMAX     "I64d"
 | 
			
		||||
#define SCNiMAX     "I64i"
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN64 // [
 | 
			
		||||
#  define SCNdPTR     "I64d"
 | 
			
		||||
#  define SCNiPTR     "I64i"
 | 
			
		||||
#else  // _WIN64 ][
 | 
			
		||||
#  define SCNdPTR     "ld"
 | 
			
		||||
#  define SCNiPTR     "li"
 | 
			
		||||
#endif  // _WIN64 ]
 | 
			
		||||
 | 
			
		||||
// The fscanf macros for unsigned integers are:
 | 
			
		||||
#define SCNo8       "o"
 | 
			
		||||
#define SCNu8       "u"
 | 
			
		||||
#define SCNx8       "x"
 | 
			
		||||
#define SCNX8       "X"
 | 
			
		||||
#define SCNoLEAST8  "o"
 | 
			
		||||
#define SCNuLEAST8  "u"
 | 
			
		||||
#define SCNxLEAST8  "x"
 | 
			
		||||
#define SCNXLEAST8  "X"
 | 
			
		||||
#define SCNoFAST8   "o"
 | 
			
		||||
#define SCNuFAST8   "u"
 | 
			
		||||
#define SCNxFAST8   "x"
 | 
			
		||||
#define SCNXFAST8   "X"
 | 
			
		||||
 | 
			
		||||
#define SCNo16       "ho"
 | 
			
		||||
#define SCNu16       "hu"
 | 
			
		||||
#define SCNx16       "hx"
 | 
			
		||||
#define SCNX16       "hX"
 | 
			
		||||
#define SCNoLEAST16  "ho"
 | 
			
		||||
#define SCNuLEAST16  "hu"
 | 
			
		||||
#define SCNxLEAST16  "hx"
 | 
			
		||||
#define SCNXLEAST16  "hX"
 | 
			
		||||
#define SCNoFAST16   "ho"
 | 
			
		||||
#define SCNuFAST16   "hu"
 | 
			
		||||
#define SCNxFAST16   "hx"
 | 
			
		||||
#define SCNXFAST16   "hX"
 | 
			
		||||
 | 
			
		||||
#define SCNo32       "lo"
 | 
			
		||||
#define SCNu32       "lu"
 | 
			
		||||
#define SCNx32       "lx"
 | 
			
		||||
#define SCNX32       "lX"
 | 
			
		||||
#define SCNoLEAST32  "lo"
 | 
			
		||||
#define SCNuLEAST32  "lu"
 | 
			
		||||
#define SCNxLEAST32  "lx"
 | 
			
		||||
#define SCNXLEAST32  "lX"
 | 
			
		||||
#define SCNoFAST32   "lo"
 | 
			
		||||
#define SCNuFAST32   "lu"
 | 
			
		||||
#define SCNxFAST32   "lx"
 | 
			
		||||
#define SCNXFAST32   "lX"
 | 
			
		||||
 | 
			
		||||
#define SCNo64       "I64o"
 | 
			
		||||
#define SCNu64       "I64u"
 | 
			
		||||
#define SCNx64       "I64x"
 | 
			
		||||
#define SCNX64       "I64X"
 | 
			
		||||
#define SCNoLEAST64  "I64o"
 | 
			
		||||
#define SCNuLEAST64  "I64u"
 | 
			
		||||
#define SCNxLEAST64  "I64x"
 | 
			
		||||
#define SCNXLEAST64  "I64X"
 | 
			
		||||
#define SCNoFAST64   "I64o"
 | 
			
		||||
#define SCNuFAST64   "I64u"
 | 
			
		||||
#define SCNxFAST64   "I64x"
 | 
			
		||||
#define SCNXFAST64   "I64X"
 | 
			
		||||
 | 
			
		||||
#define SCNoMAX     "I64o"
 | 
			
		||||
#define SCNuMAX     "I64u"
 | 
			
		||||
#define SCNxMAX     "I64x"
 | 
			
		||||
#define SCNXMAX     "I64X"
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN64 // [
 | 
			
		||||
#  define SCNoPTR     "I64o"
 | 
			
		||||
#  define SCNuPTR     "I64u"
 | 
			
		||||
#  define SCNxPTR     "I64x"
 | 
			
		||||
#  define SCNXPTR     "I64X"
 | 
			
		||||
#else  // _WIN64 ][
 | 
			
		||||
#  define SCNoPTR     "lo"
 | 
			
		||||
#  define SCNuPTR     "lu"
 | 
			
		||||
#  define SCNxPTR     "lx"
 | 
			
		||||
#  define SCNXPTR     "lX"
 | 
			
		||||
#endif  // _WIN64 ]
 | 
			
		||||
 | 
			
		||||
#endif // __STDC_FORMAT_MACROS ]
 | 
			
		||||
 | 
			
		||||
// 7.8.2 Functions for greatest-width integer types
 | 
			
		||||
 | 
			
		||||
// 7.8.2.1 The imaxabs function
 | 
			
		||||
#define imaxabs _abs64
 | 
			
		||||
 | 
			
		||||
// 7.8.2.2 The imaxdiv function
 | 
			
		||||
 | 
			
		||||
// This is modified version of div() function from Microsoft's div.c found
 | 
			
		||||
// in %MSVC.NET%\crt\src\div.c
 | 
			
		||||
#ifdef STATIC_IMAXDIV // [
 | 
			
		||||
static
 | 
			
		||||
#else // STATIC_IMAXDIV ][
 | 
			
		||||
_inline
 | 
			
		||||
#endif // STATIC_IMAXDIV ]
 | 
			
		||||
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
 | 
			
		||||
{
 | 
			
		||||
   imaxdiv_t result;
 | 
			
		||||
 | 
			
		||||
   result.quot = numer / denom;
 | 
			
		||||
   result.rem = numer % denom;
 | 
			
		||||
 | 
			
		||||
   if (numer < 0 && result.rem > 0) {
 | 
			
		||||
      // did division wrong; must fix up
 | 
			
		||||
      ++result.quot;
 | 
			
		||||
      result.rem -= denom;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 7.8.2.3 The strtoimax and strtoumax functions
 | 
			
		||||
#define strtoimax _strtoi64
 | 
			
		||||
#define strtoumax _strtoui64
 | 
			
		||||
 | 
			
		||||
// 7.8.2.4 The wcstoimax and wcstoumax functions
 | 
			
		||||
#define wcstoimax _wcstoi64
 | 
			
		||||
#define wcstoumax _wcstoui64
 | 
			
		||||
 | 
			
		||||
#endif // _MSC_VER >= 1800
 | 
			
		||||
 | 
			
		||||
#endif // _MSC_INTTYPES_H_ ]
 | 
			
		||||
							
								
								
									
										300
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_msinttypes_stdint.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_msinttypes_stdint.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,300 @@
 | 
			
		||||
// ISO C9x  compliant stdint.h for Microsoft Visual Studio
 | 
			
		||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
 | 
			
		||||
// 
 | 
			
		||||
//  Copyright (c) 2006-2013 Alexander Chemeris
 | 
			
		||||
// 
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without
 | 
			
		||||
// modification, are permitted provided that the following conditions are met:
 | 
			
		||||
// 
 | 
			
		||||
//   1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
//      this list of conditions and the following disclaimer.
 | 
			
		||||
// 
 | 
			
		||||
//   2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
//      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
//      documentation and/or other materials provided with the distribution.
 | 
			
		||||
// 
 | 
			
		||||
//   3. Neither the name of the product nor the names of its contributors may
 | 
			
		||||
//      be used to endorse or promote products derived from this software
 | 
			
		||||
//      without specific prior written permission.
 | 
			
		||||
// 
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
			
		||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 | 
			
		||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | 
			
		||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 | 
			
		||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | 
			
		||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
// 
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// The above software in this distribution may have been modified by 
 | 
			
		||||
// THL A29 Limited ("Tencent Modifications"). 
 | 
			
		||||
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
 | 
			
		||||
 | 
			
		||||
#ifndef _MSC_VER // [
 | 
			
		||||
#error "Use this header only with Microsoft Visual C++ compilers!"
 | 
			
		||||
#endif // _MSC_VER ]
 | 
			
		||||
 | 
			
		||||
#ifndef _MSC_STDINT_H_ // [
 | 
			
		||||
#define _MSC_STDINT_H_
 | 
			
		||||
 | 
			
		||||
#if _MSC_VER > 1000
 | 
			
		||||
#pragma once
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
 | 
			
		||||
#if _MSC_VER >= 1600 // [
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
 | 
			
		||||
 | 
			
		||||
#undef INT8_C
 | 
			
		||||
#undef INT16_C
 | 
			
		||||
#undef INT32_C
 | 
			
		||||
#undef INT64_C
 | 
			
		||||
#undef UINT8_C
 | 
			
		||||
#undef UINT16_C
 | 
			
		||||
#undef UINT32_C
 | 
			
		||||
#undef UINT64_C
 | 
			
		||||
 | 
			
		||||
// 7.18.4.1 Macros for minimum-width integer constants
 | 
			
		||||
 | 
			
		||||
#define INT8_C(val)  val##i8
 | 
			
		||||
#define INT16_C(val) val##i16
 | 
			
		||||
#define INT32_C(val) val##i32
 | 
			
		||||
#define INT64_C(val) val##i64
 | 
			
		||||
 | 
			
		||||
#define UINT8_C(val)  val##ui8
 | 
			
		||||
#define UINT16_C(val) val##ui16
 | 
			
		||||
#define UINT32_C(val) val##ui32
 | 
			
		||||
#define UINT64_C(val) val##ui64
 | 
			
		||||
 | 
			
		||||
// 7.18.4.2 Macros for greatest-width integer constants
 | 
			
		||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
 | 
			
		||||
// Check out Issue 9 for the details.
 | 
			
		||||
#ifndef INTMAX_C //   [
 | 
			
		||||
#  define INTMAX_C   INT64_C
 | 
			
		||||
#endif // INTMAX_C    ]
 | 
			
		||||
#ifndef UINTMAX_C //  [
 | 
			
		||||
#  define UINTMAX_C  UINT64_C
 | 
			
		||||
#endif // UINTMAX_C   ]
 | 
			
		||||
 | 
			
		||||
#endif // __STDC_CONSTANT_MACROS ]
 | 
			
		||||
 | 
			
		||||
#else // ] _MSC_VER >= 1700 [
 | 
			
		||||
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
 | 
			
		||||
// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
 | 
			
		||||
// or compiler would give many errors like this:
 | 
			
		||||
//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
 | 
			
		||||
#if defined(__cplusplus) && !defined(_M_ARM)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
#  include <wchar.h>
 | 
			
		||||
#if defined(__cplusplus) && !defined(_M_ARM)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Define _W64 macros to mark types changing their size, like intptr_t.
 | 
			
		||||
#ifndef _W64
 | 
			
		||||
#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
 | 
			
		||||
#     define _W64 __w64
 | 
			
		||||
#  else
 | 
			
		||||
#     define _W64
 | 
			
		||||
#  endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 7.18.1 Integer types
 | 
			
		||||
 | 
			
		||||
// 7.18.1.1 Exact-width integer types
 | 
			
		||||
 | 
			
		||||
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
 | 
			
		||||
// realize that, e.g. char has the same size as __int8
 | 
			
		||||
// so we give up on __intX for them.
 | 
			
		||||
#if (_MSC_VER < 1300)
 | 
			
		||||
   typedef signed char       int8_t;
 | 
			
		||||
   typedef signed short      int16_t;
 | 
			
		||||
   typedef signed int        int32_t;
 | 
			
		||||
   typedef unsigned char     uint8_t;
 | 
			
		||||
   typedef unsigned short    uint16_t;
 | 
			
		||||
   typedef unsigned int      uint32_t;
 | 
			
		||||
#else
 | 
			
		||||
   typedef signed __int8     int8_t;
 | 
			
		||||
   typedef signed __int16    int16_t;
 | 
			
		||||
   typedef signed __int32    int32_t;
 | 
			
		||||
   typedef unsigned __int8   uint8_t;
 | 
			
		||||
   typedef unsigned __int16  uint16_t;
 | 
			
		||||
   typedef unsigned __int32  uint32_t;
 | 
			
		||||
#endif
 | 
			
		||||
typedef signed __int64       int64_t;
 | 
			
		||||
typedef unsigned __int64     uint64_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 7.18.1.2 Minimum-width integer types
 | 
			
		||||
typedef int8_t    int_least8_t;
 | 
			
		||||
typedef int16_t   int_least16_t;
 | 
			
		||||
typedef int32_t   int_least32_t;
 | 
			
		||||
typedef int64_t   int_least64_t;
 | 
			
		||||
typedef uint8_t   uint_least8_t;
 | 
			
		||||
typedef uint16_t  uint_least16_t;
 | 
			
		||||
typedef uint32_t  uint_least32_t;
 | 
			
		||||
typedef uint64_t  uint_least64_t;
 | 
			
		||||
 | 
			
		||||
// 7.18.1.3 Fastest minimum-width integer types
 | 
			
		||||
typedef int8_t    int_fast8_t;
 | 
			
		||||
typedef int16_t   int_fast16_t;
 | 
			
		||||
typedef int32_t   int_fast32_t;
 | 
			
		||||
typedef int64_t   int_fast64_t;
 | 
			
		||||
typedef uint8_t   uint_fast8_t;
 | 
			
		||||
typedef uint16_t  uint_fast16_t;
 | 
			
		||||
typedef uint32_t  uint_fast32_t;
 | 
			
		||||
typedef uint64_t  uint_fast64_t;
 | 
			
		||||
 | 
			
		||||
// 7.18.1.4 Integer types capable of holding object pointers
 | 
			
		||||
#ifdef _WIN64 // [
 | 
			
		||||
   typedef signed __int64    intptr_t;
 | 
			
		||||
   typedef unsigned __int64  uintptr_t;
 | 
			
		||||
#else // _WIN64 ][
 | 
			
		||||
   typedef _W64 signed int   intptr_t;
 | 
			
		||||
   typedef _W64 unsigned int uintptr_t;
 | 
			
		||||
#endif // _WIN64 ]
 | 
			
		||||
 | 
			
		||||
// 7.18.1.5 Greatest-width integer types
 | 
			
		||||
typedef int64_t   intmax_t;
 | 
			
		||||
typedef uint64_t  uintmax_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 7.18.2 Limits of specified-width integer types
 | 
			
		||||
 | 
			
		||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259
 | 
			
		||||
 | 
			
		||||
// 7.18.2.1 Limits of exact-width integer types
 | 
			
		||||
#define INT8_MIN     ((int8_t)_I8_MIN)
 | 
			
		||||
#define INT8_MAX     _I8_MAX
 | 
			
		||||
#define INT16_MIN    ((int16_t)_I16_MIN)
 | 
			
		||||
#define INT16_MAX    _I16_MAX
 | 
			
		||||
#define INT32_MIN    ((int32_t)_I32_MIN)
 | 
			
		||||
#define INT32_MAX    _I32_MAX
 | 
			
		||||
#define INT64_MIN    ((int64_t)_I64_MIN)
 | 
			
		||||
#define INT64_MAX    _I64_MAX
 | 
			
		||||
#define UINT8_MAX    _UI8_MAX
 | 
			
		||||
#define UINT16_MAX   _UI16_MAX
 | 
			
		||||
#define UINT32_MAX   _UI32_MAX
 | 
			
		||||
#define UINT64_MAX   _UI64_MAX
 | 
			
		||||
 | 
			
		||||
// 7.18.2.2 Limits of minimum-width integer types
 | 
			
		||||
#define INT_LEAST8_MIN    INT8_MIN
 | 
			
		||||
#define INT_LEAST8_MAX    INT8_MAX
 | 
			
		||||
#define INT_LEAST16_MIN   INT16_MIN
 | 
			
		||||
#define INT_LEAST16_MAX   INT16_MAX
 | 
			
		||||
#define INT_LEAST32_MIN   INT32_MIN
 | 
			
		||||
#define INT_LEAST32_MAX   INT32_MAX
 | 
			
		||||
#define INT_LEAST64_MIN   INT64_MIN
 | 
			
		||||
#define INT_LEAST64_MAX   INT64_MAX
 | 
			
		||||
#define UINT_LEAST8_MAX   UINT8_MAX
 | 
			
		||||
#define UINT_LEAST16_MAX  UINT16_MAX
 | 
			
		||||
#define UINT_LEAST32_MAX  UINT32_MAX
 | 
			
		||||
#define UINT_LEAST64_MAX  UINT64_MAX
 | 
			
		||||
 | 
			
		||||
// 7.18.2.3 Limits of fastest minimum-width integer types
 | 
			
		||||
#define INT_FAST8_MIN    INT8_MIN
 | 
			
		||||
#define INT_FAST8_MAX    INT8_MAX
 | 
			
		||||
#define INT_FAST16_MIN   INT16_MIN
 | 
			
		||||
#define INT_FAST16_MAX   INT16_MAX
 | 
			
		||||
#define INT_FAST32_MIN   INT32_MIN
 | 
			
		||||
#define INT_FAST32_MAX   INT32_MAX
 | 
			
		||||
#define INT_FAST64_MIN   INT64_MIN
 | 
			
		||||
#define INT_FAST64_MAX   INT64_MAX
 | 
			
		||||
#define UINT_FAST8_MAX   UINT8_MAX
 | 
			
		||||
#define UINT_FAST16_MAX  UINT16_MAX
 | 
			
		||||
#define UINT_FAST32_MAX  UINT32_MAX
 | 
			
		||||
#define UINT_FAST64_MAX  UINT64_MAX
 | 
			
		||||
 | 
			
		||||
// 7.18.2.4 Limits of integer types capable of holding object pointers
 | 
			
		||||
#ifdef _WIN64 // [
 | 
			
		||||
#  define INTPTR_MIN   INT64_MIN
 | 
			
		||||
#  define INTPTR_MAX   INT64_MAX
 | 
			
		||||
#  define UINTPTR_MAX  UINT64_MAX
 | 
			
		||||
#else // _WIN64 ][
 | 
			
		||||
#  define INTPTR_MIN   INT32_MIN
 | 
			
		||||
#  define INTPTR_MAX   INT32_MAX
 | 
			
		||||
#  define UINTPTR_MAX  UINT32_MAX
 | 
			
		||||
#endif // _WIN64 ]
 | 
			
		||||
 | 
			
		||||
// 7.18.2.5 Limits of greatest-width integer types
 | 
			
		||||
#define INTMAX_MIN   INT64_MIN
 | 
			
		||||
#define INTMAX_MAX   INT64_MAX
 | 
			
		||||
#define UINTMAX_MAX  UINT64_MAX
 | 
			
		||||
 | 
			
		||||
// 7.18.3 Limits of other integer types
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN64 // [
 | 
			
		||||
#  define PTRDIFF_MIN  _I64_MIN
 | 
			
		||||
#  define PTRDIFF_MAX  _I64_MAX
 | 
			
		||||
#else  // _WIN64 ][
 | 
			
		||||
#  define PTRDIFF_MIN  _I32_MIN
 | 
			
		||||
#  define PTRDIFF_MAX  _I32_MAX
 | 
			
		||||
#endif  // _WIN64 ]
 | 
			
		||||
 | 
			
		||||
#define SIG_ATOMIC_MIN  INT_MIN
 | 
			
		||||
#define SIG_ATOMIC_MAX  INT_MAX
 | 
			
		||||
 | 
			
		||||
#ifndef SIZE_MAX // [
 | 
			
		||||
#  ifdef _WIN64 // [
 | 
			
		||||
#     define SIZE_MAX  _UI64_MAX
 | 
			
		||||
#  else // _WIN64 ][
 | 
			
		||||
#     define SIZE_MAX  _UI32_MAX
 | 
			
		||||
#  endif // _WIN64 ]
 | 
			
		||||
#endif // SIZE_MAX ]
 | 
			
		||||
 | 
			
		||||
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
 | 
			
		||||
#ifndef WCHAR_MIN // [
 | 
			
		||||
#  define WCHAR_MIN  0
 | 
			
		||||
#endif  // WCHAR_MIN ]
 | 
			
		||||
#ifndef WCHAR_MAX // [
 | 
			
		||||
#  define WCHAR_MAX  _UI16_MAX
 | 
			
		||||
#endif  // WCHAR_MAX ]
 | 
			
		||||
 | 
			
		||||
#define WINT_MIN  0
 | 
			
		||||
#define WINT_MAX  _UI16_MAX
 | 
			
		||||
 | 
			
		||||
#endif // __STDC_LIMIT_MACROS ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 7.18.4 Limits of other integer types
 | 
			
		||||
 | 
			
		||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
 | 
			
		||||
 | 
			
		||||
// 7.18.4.1 Macros for minimum-width integer constants
 | 
			
		||||
 | 
			
		||||
#define INT8_C(val)  val##i8
 | 
			
		||||
#define INT16_C(val) val##i16
 | 
			
		||||
#define INT32_C(val) val##i32
 | 
			
		||||
#define INT64_C(val) val##i64
 | 
			
		||||
 | 
			
		||||
#define UINT8_C(val)  val##ui8
 | 
			
		||||
#define UINT16_C(val) val##ui16
 | 
			
		||||
#define UINT32_C(val) val##ui32
 | 
			
		||||
#define UINT64_C(val) val##ui64
 | 
			
		||||
 | 
			
		||||
// 7.18.4.2 Macros for greatest-width integer constants
 | 
			
		||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
 | 
			
		||||
// Check out Issue 9 for the details.
 | 
			
		||||
#ifndef INTMAX_C //   [
 | 
			
		||||
#  define INTMAX_C   INT64_C
 | 
			
		||||
#endif // INTMAX_C    ]
 | 
			
		||||
#ifndef UINTMAX_C //  [
 | 
			
		||||
#  define UINTMAX_C  UINT64_C
 | 
			
		||||
#endif // UINTMAX_C   ]
 | 
			
		||||
 | 
			
		||||
#endif // __STDC_CONSTANT_MACROS ]
 | 
			
		||||
 | 
			
		||||
#endif // _MSC_VER >= 1600 ]
 | 
			
		||||
 | 
			
		||||
#endif // _MSC_STDINT_H_ ]
 | 
			
		||||
							
								
								
									
										81
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_ostreamwrapper.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_ostreamwrapper.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
// Tencent is pleased to support the open source community by making RapidJSON available.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the MIT License (the "License"); you may not use this file except
 | 
			
		||||
// in compliance with the License. You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://opensource.org/licenses/MIT
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software distributed 
 | 
			
		||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 | 
			
		||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 | 
			
		||||
// specific language governing permissions and limitations under the License.
 | 
			
		||||
 | 
			
		||||
#ifndef RAPIDJSON_OSTREAMWRAPPER_H_
 | 
			
		||||
#define RAPIDJSON_OSTREAMWRAPPER_H_
 | 
			
		||||
 | 
			
		||||
#include "lottie_rapidjson_stream.h"
 | 
			
		||||
#include <iosfwd>
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_PUSH
 | 
			
		||||
RAPIDJSON_DIAG_OFF(padded)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
 | 
			
		||||
/*!
 | 
			
		||||
    The classes can be wrapped including but not limited to:
 | 
			
		||||
 | 
			
		||||
    - \c std::ostringstream
 | 
			
		||||
    - \c std::stringstream
 | 
			
		||||
    - \c std::wpstringstream
 | 
			
		||||
    - \c std::wstringstream
 | 
			
		||||
    - \c std::ifstream
 | 
			
		||||
    - \c std::fstream
 | 
			
		||||
    - \c std::wofstream
 | 
			
		||||
    - \c std::wfstream
 | 
			
		||||
 | 
			
		||||
    \tparam StreamType Class derived from \c std::basic_ostream.
 | 
			
		||||
*/
 | 
			
		||||
   
 | 
			
		||||
template <typename StreamType>
 | 
			
		||||
class BasicOStreamWrapper {
 | 
			
		||||
public:
 | 
			
		||||
    typedef typename StreamType::char_type Ch;
 | 
			
		||||
    BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
 | 
			
		||||
 | 
			
		||||
    void Put(Ch c) {
 | 
			
		||||
        stream_.put(c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Flush() {
 | 
			
		||||
        stream_.flush();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Not implemented
 | 
			
		||||
    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    char Take() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    BasicOStreamWrapper(const BasicOStreamWrapper&);
 | 
			
		||||
    BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
 | 
			
		||||
 | 
			
		||||
    StreamType& stream_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
 | 
			
		||||
typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
RAPIDJSON_DIAG_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RAPIDJSON_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif // RAPIDJSON_OSTREAMWRAPPER_H_
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user