Compare commits
	
		
			89 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 52d4705a91 | ||
|   | 7288f71201 | ||
|   | 9c43eff753 | ||
|   | c8d7fdeedc | ||
|   | c211152e23 | ||
|   | ab75d5097e | ||
|   | c3644c8d3b | ||
|   | 6438a3dba3 | ||
|   | 4b226a6a63 | ||
|   | 4801850013 | ||
|   | 6a7412bf2b | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 5a1fd7dadd | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | ac06a26809 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 61d56f26f8 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 6aa05b3981 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | aad60c882e | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 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 | 
							
								
								
									
										22
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | # Docs: <https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/customizing-dependency-updates> | ||||||
|  |  | ||||||
|  | version: 2 | ||||||
|  |  | ||||||
|  | updates: | ||||||
|  |   - package-ecosystem: gomod | ||||||
|  |     directory: / | ||||||
|  |     schedule: {interval: weekly} | ||||||
|  |     reviewers: [42wim] | ||||||
|  |     assignees: [42wim] | ||||||
|  |  | ||||||
|  |   - package-ecosystem: github-actions | ||||||
|  |     directory: / | ||||||
|  |     schedule: {interval: weekly} | ||||||
|  |     reviewers: [42wim] | ||||||
|  |     assignees: [42wim] | ||||||
|  |  | ||||||
|  |   - package-ecosystem: docker | ||||||
|  |     directory: / | ||||||
|  |     schedule: {interval: weekly} | ||||||
|  |     reviewers: [42wim] | ||||||
|  |     assignees: [42wim] | ||||||
							
								
								
									
										16
									
								
								.github/workflows/development.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								.github/workflows/development.yml
									
									
									
									
										vendored
									
									
								
							| @@ -11,12 +11,12 @@ jobs: | |||||||
|       - name: Run golangci-lint |       - name: Run golangci-lint | ||||||
|         uses: golangci/golangci-lint-action@v2 |         uses: golangci/golangci-lint-action@v2 | ||||||
|         with: |         with: | ||||||
|           version: v1.29 |           version: latest | ||||||
|           args: "-v --new-from-rev HEAD~5" |           args: "-v --new-from-rev HEAD~5" | ||||||
|   test-build-upload: |   test-build-upload: | ||||||
|     strategy: |     strategy: | ||||||
|       matrix: |       matrix: | ||||||
|         go-version: [1.15.x, 1.16.x] |         go-version: [1.17.x] | ||||||
|         platform: [ubuntu-latest] |         platform: [ubuntu-latest] | ||||||
|     runs-on: ${{ matrix.platform }} |     runs-on: ${{ matrix.platform }} | ||||||
|     steps: |     steps: | ||||||
| @@ -35,23 +35,23 @@ jobs: | |||||||
|       run: | |       run: | | ||||||
|         mkdir -p output/{win,lin,arm,mac} |         mkdir -p output/{win,lin,arm,mac} | ||||||
|         VERSION=$(git describe --tags) |         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 |         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 | ||||||
|         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 |         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 | ||||||
|         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=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 |     - name: Upload linux 64-bit | ||||||
|       if: startsWith(matrix.go-version,'1.16') |       if: startsWith(matrix.go-version,'1.17') | ||||||
|       uses: actions/upload-artifact@v2 |       uses: actions/upload-artifact@v2 | ||||||
|       with: |       with: | ||||||
|         name: matterbridge-linux-64bit |         name: matterbridge-linux-64bit | ||||||
|         path: output/lin |         path: output/lin | ||||||
|     - name: Upload windows 64-bit |     - name: Upload windows 64-bit | ||||||
|       if: startsWith(matrix.go-version,'1.16') |       if: startsWith(matrix.go-version,'1.17') | ||||||
|       uses: actions/upload-artifact@v2 |       uses: actions/upload-artifact@v2 | ||||||
|       with: |       with: | ||||||
|         name: matterbridge-windows-64bit |         name: matterbridge-windows-64bit | ||||||
|         path: output/win |         path: output/win | ||||||
|     - name: Upload darwin 64-bit |     - name: Upload darwin 64-bit | ||||||
|       if: startsWith(matrix.go-version,'1.16') |       if: startsWith(matrix.go-version,'1.17') | ||||||
|       uses: actions/upload-artifact@v2 |       uses: actions/upload-artifact@v2 | ||||||
|       with: |       with: | ||||||
|         name: matterbridge-darwin-64bit |         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 | # Exclude configuration file | ||||||
| matterbridge.toml | matterbridge.toml | ||||||
|  |  | ||||||
|  | # Exclude IDE Files | ||||||
|  | .vscode | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ run: | |||||||
|   # concurrency: 4 |   # concurrency: 4 | ||||||
|  |  | ||||||
|   # timeout for analysis, e.g. 30s, 5m, default is 1m |   # 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 |   # exit code when at least one issue was found, default is 1 | ||||||
|   issues-exit-code: 1 |   issues-exit-code: 1 | ||||||
| @@ -182,7 +182,28 @@ linters: | |||||||
|     - interfacer |     - interfacer | ||||||
|     - goheader |     - goheader | ||||||
|     - noctx |     - 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 | # rules to deal with reported isues | ||||||
| issues: | issues: | ||||||
|   # List of regexps of issue texts to exclude, empty list by default. |   # List of regexps of issue texts to exclude, empty list by default. | ||||||
|   | |||||||
| @@ -18,8 +18,11 @@ builds: | |||||||
|     - arm |     - arm | ||||||
|     - arm64 |     - arm64 | ||||||
|     - 386 |     - 386 | ||||||
|  |   goarm: | ||||||
|  |     - 6 | ||||||
|  |     - 7 | ||||||
|   ldflags: |   ldflags: | ||||||
|     - -s -w -X main.githash={{.ShortCommit}} |     - -s -w -X github.com/42wim/matterbridge/version.GitHash={{.ShortCommit}} | ||||||
|  |  | ||||||
| archives: | archives: | ||||||
|   - |   - | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ FROM alpine AS builder | |||||||
| COPY . /go/src/matterbridge | COPY . /go/src/matterbridge | ||||||
| RUN apk --no-cache add go git \ | RUN apk --no-cache add go git \ | ||||||
|         && cd /go/src/matterbridge \ |         && 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 | FROM alpine | ||||||
| RUN apk --no-cache add ca-certificates mailcap | 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) |       - [Bridge slack (#general) - discord (general)](#bridge-slack-general---discord-general) | ||||||
|   - [Running](#running) |   - [Running](#running) | ||||||
|     - [Docker](#docker) |     - [Docker](#docker) | ||||||
|  |     - [Systemd](#systemd) | ||||||
|   - [Changelog](#changelog) |   - [Changelog](#changelog) | ||||||
|   - [FAQ](#faq) |   - [FAQ](#faq) | ||||||
|   - [Related projects](#related-projects) |   - [Related projects](#related-projects) | ||||||
| @@ -163,7 +164,7 @@ See <https://github.com/42wim/matterbridge/wiki> | |||||||
|  |  | ||||||
| ### Binaries | ### Binaries | ||||||
|  |  | ||||||
| - Latest stable release [v1.22.3](https://github.com/42wim/matterbridge/releases/latest) | - Latest stable release [v1.23.2](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. | - 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. | 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) | 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: | 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 | ```bash | ||||||
| go get github.com/42wim/matterbridge | go install github.com/42wim/matterbridge | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | To install the latest dev run: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | go install github.com/42wim/matterbridge@master | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| You should now have matterbridge binary in the ~/go/bin directory: | 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. | 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 | ## Changelog | ||||||
|  |  | ||||||
| See [changelog.md](https://github.com/42wim/matterbridge/blob/master/changelog.md) | 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://daniele.tech/2019/02/how-to-use-matterbridge-to-connect-2-different-slack-workspaces/> | ||||||
| - <https://userlinux.net/mattermost-and-matterbridge.html> | - <https://userlinux.net/mattermost-and-matterbridge.html> | ||||||
| - <https://nextcloud.com/blog/bridging-chat-services-in-talk/> | - <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) | - Youtube: [whatsapp - telegram bridging](https://www.youtube.com/watch?v=W-VXISoKtNc) | ||||||
|  |  | ||||||
| ## Thanks | ## Thanks | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ const ( | |||||||
| 	EventRejoinChannels    = "rejoin_channels" | 	EventRejoinChannels    = "rejoin_channels" | ||||||
| 	EventUserAction        = "user_action" | 	EventUserAction        = "user_action" | ||||||
| 	EventMsgDelete         = "msg_delete" | 	EventMsgDelete         = "msg_delete" | ||||||
|  | 	EventFileDelete        = "file_delete" | ||||||
| 	EventAPIConnected      = "api_connected" | 	EventAPIConnected      = "api_connected" | ||||||
| 	EventUserTyping        = "user_typing" | 	EventUserTyping        = "user_typing" | ||||||
| 	EventGetChannelMembers = "get_channel_members" | 	EventGetChannelMembers = "get_channel_members" | ||||||
| @@ -56,13 +57,14 @@ func (m Message) ParentValid() bool { | |||||||
| } | } | ||||||
|  |  | ||||||
| type FileInfo struct { | type FileInfo struct { | ||||||
| 	Name    string | 	Name     string | ||||||
| 	Data    *[]byte | 	Data     *[]byte | ||||||
| 	Comment string | 	Comment  string | ||||||
| 	URL     string | 	URL      string | ||||||
| 	Size    int64 | 	Size     int64 | ||||||
| 	Avatar  bool | 	Avatar   bool | ||||||
| 	SHA     string | 	SHA      string | ||||||
|  | 	NativeID string | ||||||
| } | } | ||||||
|  |  | ||||||
| type ChannelInfo struct { | type ChannelInfo struct { | ||||||
| @@ -138,6 +140,7 @@ type Protocol struct { | |||||||
| 	QuoteDisable           bool       // telegram | 	QuoteDisable           bool       // telegram | ||||||
| 	QuoteFormat            string     // telegram | 	QuoteFormat            string     // telegram | ||||||
| 	QuoteLengthLimit       int        // telegram | 	QuoteLengthLimit       int        // telegram | ||||||
|  | 	RealName               string     // IRC | ||||||
| 	RejoinDelay            int        // IRC | 	RejoinDelay            int        // IRC | ||||||
| 	ReplaceMessages        [][]string // all protocols | 	ReplaceMessages        [][]string // all protocols | ||||||
| 	ReplaceNicks           [][]string // all protocols | 	ReplaceNicks           [][]string // all protocols | ||||||
| @@ -167,8 +170,9 @@ type Protocol struct { | |||||||
| 	UseTLS                 bool       // IRC | 	UseTLS                 bool       // IRC | ||||||
| 	UseDiscriminator       bool       // discord | 	UseDiscriminator       bool       // discord | ||||||
| 	UseFirstName           bool       // telegram | 	UseFirstName           bool       // telegram | ||||||
| 	UseUserName            bool       // discord, matrix | 	UseUserName            bool       // discord, matrix, mattermost | ||||||
| 	UseInsecureURL         bool       // telegram | 	UseInsecureURL         bool       // telegram | ||||||
|  | 	UserName               string     // IRC | ||||||
| 	VerboseJoinPart        bool       // IRC | 	VerboseJoinPart        bool       // IRC | ||||||
| 	WebhookBindAddress     string     // mattermost, slack | 	WebhookBindAddress     string     // mattermost, slack | ||||||
| 	WebhookURL             string     // mattermost, slack | 	WebhookURL             string     // mattermost, slack | ||||||
|   | |||||||
| @@ -10,10 +10,14 @@ import ( | |||||||
| 	"github.com/42wim/matterbridge/bridge/config" | 	"github.com/42wim/matterbridge/bridge/config" | ||||||
| 	"github.com/42wim/matterbridge/bridge/discord/transmitter" | 	"github.com/42wim/matterbridge/bridge/discord/transmitter" | ||||||
| 	"github.com/42wim/matterbridge/bridge/helper" | 	"github.com/42wim/matterbridge/bridge/helper" | ||||||
|  | 	lru "github.com/hashicorp/golang-lru" | ||||||
| 	"github.com/matterbridge/discordgo" | 	"github.com/matterbridge/discordgo" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const MessageLength = 1950 | const ( | ||||||
|  | 	MessageLength = 1950 | ||||||
|  | 	cFileUpload   = "file_upload" | ||||||
|  | ) | ||||||
|  |  | ||||||
| type Bdiscord struct { | type Bdiscord struct { | ||||||
| 	*bridge.Config | 	*bridge.Config | ||||||
| @@ -35,10 +39,20 @@ type Bdiscord struct { | |||||||
| 	// Webhook specific logic | 	// Webhook specific logic | ||||||
| 	useAutoWebhooks bool | 	useAutoWebhooks bool | ||||||
| 	transmitter     *transmitter.Transmitter | 	transmitter     *transmitter.Transmitter | ||||||
|  | 	cache           *lru.Cache | ||||||
| } | } | ||||||
|  |  | ||||||
| func New(cfg *bridge.Config) bridge.Bridger { | 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.userMemberMap = make(map[string]*discordgo.Member) | ||||||
| 	b.nickMemberMap = make(map[string]*discordgo.Member) | 	b.nickMemberMap = make(map[string]*discordgo.Member) | ||||||
| 	b.channelInfoMap = make(map[string]*config.ChannelInfo) | 	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.messageDeleteBulk) | ||||||
| 	b.c.AddHandler(b.memberAdd) | 	b.c.AddHandler(b.memberAdd) | ||||||
| 	b.c.AddHandler(b.memberRemove) | 	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 | 	// Add privileged intent for guild member tracking. This is needed to track nicks | ||||||
| 	// for display names and @mention translation | 	// for display names and @mention translation | ||||||
| 	b.c.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAllWithoutPrivileged | | 	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") | 		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.Log.Debug("enabling even more discord debug") | ||||||
| 		b.c.Debug = true | 		b.c.Debug = true | ||||||
| 	} | 	} | ||||||
| @@ -280,6 +297,21 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st | |||||||
| 		return "", err | 		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 | 	// Upload a file if it exists | ||||||
| 	if msg.Extra != nil { | 	if msg.Extra != nil { | ||||||
| 		for _, rmsg := range helper.HandleExtra(msg, b.General) { | 		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 | // handleUploadFile handles native upload of files | ||||||
| func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (string, error) { | func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (string, error) { | ||||||
| 	var err error |  | ||||||
| 	for _, f := range msg.Extra["file"] { | 	for _, f := range msg.Extra["file"] { | ||||||
| 		fi := f.(config.FileInfo) | 		fi := f.(config.FileInfo) | ||||||
| 		file := discordgo.File{ | 		file := discordgo.File{ | ||||||
| @@ -340,10 +371,15 @@ func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (stri | |||||||
| 			Files:           []*discordgo.File{&file}, | 			Files:           []*discordgo.File{&file}, | ||||||
| 			AllowedMentions: b.getAllowedMentions(), | 			AllowedMentions: b.getAllowedMentions(), | ||||||
| 		} | 		} | ||||||
| 		_, err = b.c.ChannelMessageSendComplex(channelID, &m) | 		res, err := b.c.ChannelMessageSendComplex(channelID, &m) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return "", fmt.Errorf("file upload failed: %s", err) | 			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 | 	return "", nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ package bdiscord | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/42wim/matterbridge/bridge/config" | 	"github.com/42wim/matterbridge/bridge/config" | ||||||
|  | 	"github.com/davecgh/go-spew/spew" | ||||||
| 	"github.com/matterbridge/discordgo" | 	"github.com/matterbridge/discordgo" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -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) { | func (b *Bdiscord) messageTyping(s *discordgo.Session, m *discordgo.TypingStart) { | ||||||
| 	if !b.GetBool("ShowUserTyping") { | 	if !b.GetBool("ShowUserTyping") { | ||||||
| 		return | 		return | ||||||
| @@ -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} | 	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 != "" { | 	if m.Content != "" { | ||||||
| 		b.Log.Debugf("== Receiving event %#v", m.Message) |  | ||||||
| 		m.Message.Content = b.replaceChannelMentions(m.Message.Content) | 		m.Message.Content = b.replaceChannelMentions(m.Message.Content) | ||||||
| 		rmsg.Text, err = m.ContentWithMoreMentionsReplaced(b.c) | 		rmsg.Text, err = m.ContentWithMoreMentionsReplaced(b.c) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|   | |||||||
| @@ -82,10 +82,8 @@ func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordg | |||||||
| 				ContentType: "", | 				ContentType: "", | ||||||
| 				Reader:      bytes.NewReader(*fi.Data), | 				Reader:      bytes.NewReader(*fi.Data), | ||||||
| 			} | 			} | ||||||
| 			content := "" | 			content := fi.Comment | ||||||
| 			if msg.Text == "" { |  | ||||||
| 				content = fi.Comment |  | ||||||
| 			} |  | ||||||
| 			_, e2 := b.transmitter.Send( | 			_, e2 := b.transmitter.Send( | ||||||
| 				channelID, | 				channelID, | ||||||
| 				&discordgo.WebhookParams{ | 				&discordgo.WebhookParams{ | ||||||
|   | |||||||
							
								
								
									
										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" | 	"fmt" | ||||||
| 	"image/png" | 	"image/png" | ||||||
| 	"io" | 	"io" | ||||||
| 	"io/ioutil" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" |  | ||||||
| 	"os/exec" |  | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| @@ -83,10 +80,6 @@ func DownloadFileAuthRocket(url, token, userID string) (*[]byte, error) { | |||||||
| // word boundaries when splitting but this is hard to solve without potentially | // word boundaries when splitting but this is hard to solve without potentially | ||||||
| // breaking formatting and other stylistic effects. | // breaking formatting and other stylistic effects. | ||||||
| func GetSubLines(message string, maxLineLength int, clippingMessage string) []string { | func GetSubLines(message string, maxLineLength int, clippingMessage string) []string { | ||||||
| 	if clippingMessage == "" { |  | ||||||
| 		clippingMessage = " <clipped message>" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var lines []string | 	var lines []string | ||||||
| 	for _, line := range strings.Split(strings.TrimSpace(message), "\n") { | 	for _, line := range strings.Split(strings.TrimSpace(message), "\n") { | ||||||
| 		if maxLineLength == 0 || len([]byte(line)) <= maxLineLength { | 		if maxLineLength == 0 || len([]byte(line)) <= maxLineLength { | ||||||
| @@ -101,8 +94,8 @@ func GetSubLines(message string, maxLineLength int, clippingMessage string) []st | |||||||
| 		var splitStart int | 		var splitStart int | ||||||
| 		var startOfPreviousRune int | 		var startOfPreviousRune int | ||||||
| 		for i := range line { | 		for i := range line { | ||||||
| 			if i-splitStart > maxLineLength-len([]byte(clippingMessage)) { | 			if i-splitStart > maxLineLength { | ||||||
| 				lines = append(lines, line[splitStart:startOfPreviousRune]+clippingMessage) | 				lines = append(lines, line[splitStart:startOfPreviousRune]) | ||||||
| 				splitStart = startOfPreviousRune | 				splitStart = startOfPreviousRune | ||||||
| 			} | 			} | ||||||
| 			startOfPreviousRune = i | 			startOfPreviousRune = i | ||||||
| @@ -171,17 +164,23 @@ func HandleDownloadSize(logger *logrus.Entry, msg *config.Message, name string, | |||||||
|  |  | ||||||
| // HandleDownloadData adds the data for a remote file into a Matterbridge gateway message. | // 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) { | 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 | 	var avatar bool | ||||||
| 	logger.Debugf("Download OK %#v %#v", name, len(*data)) | 	logger.Debugf("Download OK %#v %#v", name, len(*data)) | ||||||
| 	if msg.Event == config.EventAvatarDownload { | 	if msg.Event == config.EventAvatarDownload { | ||||||
| 		avatar = true | 		avatar = true | ||||||
| 	} | 	} | ||||||
| 	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{ | 	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{ | ||||||
| 		Name:    name, | 		Name:     name, | ||||||
| 		Data:    data, | 		Data:     data, | ||||||
| 		URL:     url, | 		URL:      url, | ||||||
| 		Comment: comment, | 		Comment:  comment, | ||||||
| 		Avatar:  avatar, | 		Avatar:   avatar, | ||||||
|  | 		NativeID: id, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -239,66 +238,3 @@ func ConvertWebPToPNG(data *[]byte) error { | |||||||
| 	*data = w.Bytes() | 	*data = w.Bytes() | ||||||
| 	return nil | 	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" | ||||||
|  | } | ||||||
| @@ -2,6 +2,7 @@ package birc | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"crypto/tls" | 	"crypto/tls" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"hash/crc32" | 	"hash/crc32" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| @@ -24,7 +25,7 @@ import ( | |||||||
|  |  | ||||||
| type Birc struct { | type Birc struct { | ||||||
| 	i                                         *girc.Client | 	i                                         *girc.Client | ||||||
| 	Nick                                      string | 	Nick, MessageClipped                      string | ||||||
| 	names                                     map[string][]string | 	names                                     map[string][]string | ||||||
| 	connected                                 chan error | 	connected                                 chan error | ||||||
| 	Local                                     chan config.Message // local queue for flood control | 	Local                                     chan config.Message // local queue for flood control | ||||||
| @@ -72,6 +73,10 @@ func (b *Birc) Command(msg *config.Message) string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (b *Birc) Connect() error { | 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.Local = make(chan config.Message, b.MessageQueue+10) | ||||||
| 	b.Log.Infof("Connecting %s", b.GetString("Server")) | 	b.Log.Infof("Connecting %s", b.GetString("Server")) | ||||||
|  |  | ||||||
| @@ -167,10 +172,11 @@ func (b *Birc) Send(msg config.Message) (string, error) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if b.GetBool("MessageSplit") { | 	if b.GetBool("MessageSplit") { | ||||||
| 		msgLines = helper.GetSubLines(msg.Text, b.MessageLength, b.GetString("MessageClipped")) | 		msgLines = helper.GetSubLines(msg.Text, b.MessageLength, "") | ||||||
| 	} else { | 	} else { | ||||||
| 		msgLines = helper.GetSubLines(msg.Text, 0, b.GetString("MessageClipped")) | 		msgLines = []string{helper.GetSubLines(msg.Text, b.MessageLength, "")[0] + b.getMessageClipped()} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for i := range msgLines { | 	for i := range msgLines { | ||||||
| 		if len(b.Local) >= b.MessageQueue { | 		if len(b.Local) >= b.MessageQueue { | ||||||
| 			b.Log.Debugf("flooding, dropping message (queue at %d)", len(b.Local)) | 			b.Log.Debugf("flooding, dropping message (queue at %d)", len(b.Local)) | ||||||
| @@ -271,8 +277,11 @@ func (b *Birc) getClient() (*girc.Client, error) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 	user := b.GetString("UserName") | ||||||
|  | 	if user == "" { | ||||||
|  | 		user = b.GetString("Nick") | ||||||
|  | 	} | ||||||
| 	// fix strict user handling of girc | 	// fix strict user handling of girc | ||||||
| 	user := b.GetString("Nick") |  | ||||||
| 	for !girc.IsValidUser(user) { | 	for !girc.IsValidUser(user) { | ||||||
| 		if len(user) == 1 || len(user) == 0 { | 		if len(user) == 1 || len(user) == 0 { | ||||||
| 			user = "matterbridge" | 			user = "matterbridge" | ||||||
| @@ -280,6 +289,10 @@ func (b *Birc) getClient() (*girc.Client, error) { | |||||||
| 		} | 		} | ||||||
| 		user = user[1:] | 		user = user[1:] | ||||||
| 	} | 	} | ||||||
|  | 	realName := b.GetString("RealName") | ||||||
|  | 	if realName == "" { | ||||||
|  | 		realName = b.GetString("Nick") | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	debug := ioutil.Discard | 	debug := ioutil.Discard | ||||||
| 	if b.GetInt("DebugLevel") == 2 { | 	if b.GetInt("DebugLevel") == 2 { | ||||||
| @@ -293,15 +306,21 @@ func (b *Birc) getClient() (*girc.Client, error) { | |||||||
|  |  | ||||||
| 	b.Log.Debugf("setting pingdelay to %s", pingDelay) | 	b.Log.Debugf("setting pingdelay to %s", pingDelay) | ||||||
|  |  | ||||||
|  | 	tlsConfig, err := b.getTLSConfig() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	i := girc.New(girc.Config{ | 	i := girc.New(girc.Config{ | ||||||
| 		Server:     server, | 		Server:     server, | ||||||
| 		ServerPass: b.GetString("Password"), | 		ServerPass: b.GetString("Password"), | ||||||
| 		Port:       port, | 		Port:       port, | ||||||
| 		Nick:       b.GetString("Nick"), | 		Nick:       b.GetString("Nick"), | ||||||
| 		User:       user, | 		User:       user, | ||||||
| 		Name:       b.GetString("Nick"), | 		Name:       realName, | ||||||
| 		SSL:        b.GetBool("UseTLS"), | 		SSL:        b.GetBool("UseTLS"), | ||||||
| 		TLSConfig:  &tls.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), ServerName: server}, //nolint:gosec | 		Bind:       b.GetString("Bind"), | ||||||
|  | 		TLSConfig:  tlsConfig, | ||||||
| 		PingDelay:  pingDelay, | 		PingDelay:  pingDelay, | ||||||
| 		// skip gIRC internal rate limiting, since we have our own throttling | 		// skip gIRC internal rate limiting, since we have our own throttling | ||||||
| 		AllowFlood:    true, | 		AllowFlood:    true, | ||||||
| @@ -373,3 +392,31 @@ func (b *Birc) storeNames(client *girc.Client, event girc.Event) { | |||||||
| func (b *Birc) formatnicks(nicks []string) string { | func (b *Birc) formatnicks(nicks []string) string { | ||||||
| 	return strings.Join(nicks, ", ") + " currently on IRC" | 	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 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (b *Birc) getMessageClipped() string { | ||||||
|  | 	if b.GetString("MessageClipped") == "" { | ||||||
|  | 		return " <clipped message>" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return " " + b.GetString("MessageClipped") | ||||||
|  | } | ||||||
|   | |||||||
| @@ -48,8 +48,10 @@ type matrixUsername struct { | |||||||
|  |  | ||||||
| // SubTextMessage represents the new content of the message in edit messages. | // SubTextMessage represents the new content of the message in edit messages. | ||||||
| type SubTextMessage struct { | type SubTextMessage struct { | ||||||
| 	MsgType string `json:"msgtype"` | 	MsgType       string `json:"msgtype"` | ||||||
| 	Body    string `json:"body"` | 	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. | // MessageRelation explains how the current message relates to a previous message. | ||||||
| @@ -65,6 +67,19 @@ type EditedMessage struct { | |||||||
| 	matrix.TextMessage | 	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 { | func New(cfg *bridge.Config) bridge.Bridger { | ||||||
| 	b := &Bmatrix{Config: cfg} | 	b := &Bmatrix{Config: cfg} | ||||||
| 	b.RoomMap = make(map[string]string) | 	b.RoomMap = make(map[string]string) | ||||||
| @@ -138,7 +153,13 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) { | |||||||
| 		m := matrix.TextMessage{ | 		m := matrix.TextMessage{ | ||||||
| 			MsgType:       "m.emote", | 			MsgType:       "m.emote", | ||||||
| 			Body:          username.plain + msg.Text, | 			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 := "" | 		msgID := "" | ||||||
| @@ -201,20 +222,29 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) { | |||||||
|  |  | ||||||
| 	// Edit message if we have an ID | 	// Edit message if we have an ID | ||||||
| 	if msg.ID != "" { | 	if msg.ID != "" { | ||||||
| 		rmsg := EditedMessage{TextMessage: matrix.TextMessage{ | 		rmsg := EditedMessage{ | ||||||
| 			Body:    username.plain + msg.Text, | 			TextMessage: matrix.TextMessage{ | ||||||
| 			MsgType: "m.text", | 				Body:          username.plain + msg.Text, | ||||||
| 		}} | 				MsgType:       "m.text", | ||||||
| 		if b.GetBool("HTMLDisable") { | 				Format:        "org.matrix.custom.html", | ||||||
| 			rmsg.TextMessage.FormattedBody = username.formatted + "* " + msg.Text | 				FormattedBody: username.formatted + helper.ParseMarkdown(msg.Text), | ||||||
| 		} else { | 			}, | ||||||
| 			rmsg.Format = "org.matrix.custom.html" |  | ||||||
| 			rmsg.TextMessage.FormattedBody = username.formatted + "* " + helper.ParseMarkdown(msg.Text) |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		rmsg.NewContent = SubTextMessage{ | 		rmsg.NewContent = SubTextMessage{ | ||||||
| 			Body:    rmsg.TextMessage.Body, | 			Body:          rmsg.TextMessage.Body, | ||||||
| 			MsgType: "m.text", | 			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{ | 		rmsg.RelatedTo = MessageRelation{ | ||||||
| 			EventID: msg.ID, | 			EventID: msg.ID, | ||||||
| 			Type:    "m.replace", | 			Type:    "m.replace", | ||||||
| @@ -238,6 +268,50 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) { | |||||||
| 			MsgType:       "m.notice", | 			MsgType:       "m.notice", | ||||||
| 			Body:          username.plain + msg.Text, | 			Body:          username.plain + msg.Text, | ||||||
| 			FormattedBody: username.formatted + 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 ( | 		var ( | ||||||
| @@ -301,6 +375,9 @@ func (b *Bmatrix) handlematrix() { | |||||||
| 	syncer.OnEventType("m.room.member", b.handleMemberChange) | 	syncer.OnEventType("m.room.member", b.handleMemberChange) | ||||||
| 	go func() { | 	go func() { | ||||||
| 		for { | 		for { | ||||||
|  | 			if b == nil { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
| 			if err := b.mc.Sync(); err != nil { | 			if err := b.mc.Sync(); err != nil { | ||||||
| 				b.Log.Println("Sync() returned ", err) | 				b.Log.Println("Sync() returned ", err) | ||||||
| 			} | 			} | ||||||
| @@ -338,6 +415,35 @@ func (b *Bmatrix) handleEdit(ev *matrix.Event, rmsg config.Message) bool { | |||||||
| 	return true | 	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) { | 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 | 	// 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" { | 	if ev.Content["membership"] == "join" { | ||||||
| @@ -400,6 +506,11 @@ func (b *Bmatrix) handleEvent(ev *matrix.Event) { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		// Is it a reply? | ||||||
|  | 		if b.handleReply(ev, rmsg) { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		// Do we have attachments | 		// Do we have attachments | ||||||
| 		if b.containsAttachment(ev.Content) { | 		if b.containsAttachment(ev.Content) { | ||||||
| 			err := b.handleDownloadFile(&rmsg, ev.Content) | 			err := b.handleDownloadFile(&rmsg, ev.Content) | ||||||
|   | |||||||
| @@ -4,7 +4,9 @@ import ( | |||||||
| 	"github.com/42wim/matterbridge/bridge/config" | 	"github.com/42wim/matterbridge/bridge/config" | ||||||
| 	"github.com/42wim/matterbridge/bridge/helper" | 	"github.com/42wim/matterbridge/bridge/helper" | ||||||
| 	"github.com/42wim/matterbridge/matterclient" | 	"github.com/42wim/matterbridge/matterclient" | ||||||
|  | 	matterclient6 "github.com/matterbridge/matterclient" | ||||||
| 	"github.com/mattermost/mattermost-server/v5/model" | 	"github.com/mattermost/mattermost-server/v5/model" | ||||||
|  | 	model6 "github.com/mattermost/mattermost-server/v6/model" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // handleDownloadAvatar downloads the avatar of userid from channel | // 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{}), | 		Extra:    make(map[string][]interface{}), | ||||||
| 	} | 	} | ||||||
| 	if _, ok := b.avatarMap[userid]; !ok { | 	if _, ok := b.avatarMap[userid]; !ok { | ||||||
| 		data, resp := b.mc.Client.GetProfileImage(userid, "") | 		var ( | ||||||
| 		if resp.Error != nil { | 			data []byte | ||||||
| 			b.Log.Errorf("ProfileImage download failed for %#v %s", userid, resp.Error) | 			err  error | ||||||
| 			return | 			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 { | 		if err != nil { | ||||||
| 			b.Log.Error(err) | 			b.Log.Error(err) | ||||||
| 			return | 			return | ||||||
| @@ -38,6 +54,10 @@ func (b *Bmattermost) handleDownloadAvatar(userid string, channel string) { | |||||||
|  |  | ||||||
| // handleDownloadFile handles file download | // handleDownloadFile handles file download | ||||||
| func (b *Bmattermost) handleDownloadFile(rmsg *config.Message, id string) error { | 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) | 	url, _ := b.mc.Client.GetFileLink(id) | ||||||
| 	finfo, resp := b.mc.Client.GetFileInfo(id) | 	finfo, resp := b.mc.Client.GetFileInfo(id) | ||||||
| 	if resp.Error != nil { | 	if resp.Error != nil { | ||||||
| @@ -55,6 +75,25 @@ func (b *Bmattermost) handleDownloadFile(rmsg *config.Message, id string) error | |||||||
| 	return nil | 	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() { | func (b *Bmattermost) handleMatter() { | ||||||
| 	messages := make(chan *config.Message) | 	messages := make(chan *config.Message) | ||||||
| 	if b.GetString("WebhookBindAddress") != "" { | 	if b.GetString("WebhookBindAddress") != "" { | ||||||
| @@ -87,6 +126,12 @@ func (b *Bmattermost) handleMatter() { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (b *Bmattermost) handleMatterClient(messages chan *config.Message) { | 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 { | 	for message := range b.mc.MessageChan { | ||||||
| 		b.Log.Debugf("%#v", message.Raw.Data) | 		b.Log.Debugf("%#v", message.Raw.Data) | ||||||
|  |  | ||||||
| @@ -95,9 +140,14 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) { | |||||||
| 			continue | 			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) | 		// only download avatars if we have a place to upload them (configured mediaserver) | ||||||
| 		if b.General.MediaServerUpload != "" || b.General.MediaDownloadPath != "" { | 		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) | 		b.Log.Debugf("== Receiving event %#v", message) | ||||||
| @@ -105,7 +155,7 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) { | |||||||
| 		rmsg := &config.Message{ | 		rmsg := &config.Message{ | ||||||
| 			Username: message.Username, | 			Username: message.Username, | ||||||
| 			UserID:   message.UserID, | 			UserID:   message.UserID, | ||||||
| 			Channel:  message.Channel, | 			Channel:  channelName, | ||||||
| 			Text:     message.Text, | 			Text:     message.Text, | ||||||
| 			ID:       message.Post.Id, | 			ID:       message.Post.Id, | ||||||
| 			ParentID: message.Post.RootId, // ParentID is obsolete with mattermost | 			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 | 		// Use nickname instead of username if defined | ||||||
| 		if nick := b.mc.GetNickName(rmsg.UserID); nick != "" { | 		if !b.GetBool("useusername") { | ||||||
| 			rmsg.Username = nick | 			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 | 		messages <- rmsg | ||||||
| @@ -144,6 +258,7 @@ func (b *Bmattermost) handleMatterHook(messages chan *config.Message) { | |||||||
| 	for { | 	for { | ||||||
| 		message := b.mh.Receive() | 		message := b.mh.Receive() | ||||||
| 		b.Log.Debugf("Receiving from matterhook %#v", message) | 		b.Log.Debugf("Receiving from matterhook %#v", message) | ||||||
|  |  | ||||||
| 		messages <- &config.Message{ | 		messages <- &config.Message{ | ||||||
| 			UserID:   message.UserID, | 			UserID:   message.UserID, | ||||||
| 			Username: message.UserName, | 			Username: message.UserName, | ||||||
| @@ -155,9 +270,13 @@ func (b *Bmattermost) handleMatterHook(messages chan *config.Message) { | |||||||
|  |  | ||||||
| // handleUploadFile handles native upload of files | // handleUploadFile handles native upload of files | ||||||
| func (b *Bmattermost) handleUploadFile(msg *config.Message) (string, error) { | func (b *Bmattermost) handleUploadFile(msg *config.Message) (string, error) { | ||||||
|  | 	if b.mc6 != nil { | ||||||
|  | 		return b.handleUploadFile6(msg) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	var err error | 	var err error | ||||||
| 	var res, id string | 	var res, id string | ||||||
| 	channelID := b.mc.GetChannelId(msg.Channel, b.TeamID) | 	channelID := b.getChannelID(msg.Channel) | ||||||
| 	for _, f := range msg.Extra["file"] { | 	for _, f := range msg.Extra["file"] { | ||||||
| 		fi := f.(config.FileInfo) | 		fi := f.(config.FileInfo) | ||||||
| 		id, err = b.mc.UploadFile(*fi.Data, channelID, fi.Name) | 		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 | 	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) { | func (b *Bmattermost) handleProps(rmsg *config.Message, message *matterclient.Message) { | ||||||
| 	props := message.Post.Props | 	props := message.Post.Props | ||||||
| 	if props == nil { | 	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 | package bmattermost | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/42wim/matterbridge/bridge/config" | 	"github.com/42wim/matterbridge/bridge/config" | ||||||
| 	"github.com/42wim/matterbridge/bridge/helper" | 	"github.com/42wim/matterbridge/bridge/helper" | ||||||
| 	"github.com/42wim/matterbridge/matterclient" | 	"github.com/42wim/matterbridge/matterclient" | ||||||
| 	"github.com/42wim/matterbridge/matterhook" | 	"github.com/42wim/matterbridge/matterhook" | ||||||
|  | 	matterclient6 "github.com/matterbridge/matterclient" | ||||||
| 	"github.com/mattermost/mattermost-server/v5/model" | 	"github.com/mattermost/mattermost-server/v5/model" | ||||||
|  | 	model6 "github.com/mattermost/mattermost-server/v6/model" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func (b *Bmattermost) doConnectWebhookBind() error { | func (b *Bmattermost) doConnectWebhookBind() error { | ||||||
| @@ -15,25 +18,47 @@ func (b *Bmattermost) doConnectWebhookBind() error { | |||||||
| 	case b.GetString("WebhookURL") != "": | 	case b.GetString("WebhookURL") != "": | ||||||
| 		b.Log.Info("Connecting using webhookurl (sending) and webhookbindaddress (receiving)") | 		b.Log.Info("Connecting using webhookurl (sending) and webhookbindaddress (receiving)") | ||||||
| 		b.mh = matterhook.New(b.GetString("WebhookURL"), | 		b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||||
| 			matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | 			matterhook.Config{ | ||||||
| 				BindAddress: b.GetString("WebhookBindAddress")}) | 				InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||||
|  | 				BindAddress:        b.GetString("WebhookBindAddress"), | ||||||
|  | 			}) | ||||||
| 	case b.GetString("Token") != "": | 	case b.GetString("Token") != "": | ||||||
| 		b.Log.Info("Connecting using token (sending)") | 		b.Log.Info("Connecting using token (sending)") | ||||||
| 		err := b.apiLogin() | 		b.Log.Infof("Using mattermost v6 methods: %t", b.v6) | ||||||
| 		if err != nil { |  | ||||||
| 			return err | 		if b.v6 { | ||||||
|  | 			err := b.apiLogin6() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			err := b.apiLogin() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	case b.GetString("Login") != "": | 	case b.GetString("Login") != "": | ||||||
| 		b.Log.Info("Connecting using login/password (sending)") | 		b.Log.Info("Connecting using login/password (sending)") | ||||||
| 		err := b.apiLogin() | 		b.Log.Infof("Using mattermost v6 methods: %t", b.v6) | ||||||
| 		if err != nil { |  | ||||||
| 			return err | 		if b.v6 { | ||||||
|  | 			err := b.apiLogin6() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			err := b.apiLogin() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	default: | 	default: | ||||||
| 		b.Log.Info("Connecting using webhookbindaddress (receiving)") | 		b.Log.Info("Connecting using webhookbindaddress (receiving)") | ||||||
| 		b.mh = matterhook.New(b.GetString("WebhookURL"), | 		b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||||
| 			matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | 			matterhook.Config{ | ||||||
| 				BindAddress: b.GetString("WebhookBindAddress")}) | 				InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||||
|  | 				BindAddress:        b.GetString("WebhookBindAddress"), | ||||||
|  | 			}) | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| @@ -41,19 +66,39 @@ func (b *Bmattermost) doConnectWebhookBind() error { | |||||||
| func (b *Bmattermost) doConnectWebhookURL() error { | func (b *Bmattermost) doConnectWebhookURL() error { | ||||||
| 	b.Log.Info("Connecting using webhookurl (sending)") | 	b.Log.Info("Connecting using webhookurl (sending)") | ||||||
| 	b.mh = matterhook.New(b.GetString("WebhookURL"), | 	b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||||
| 		matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | 		matterhook.Config{ | ||||||
| 			DisableServer: true}) | 			InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||||
|  | 			DisableServer:      true, | ||||||
|  | 		}) | ||||||
| 	if b.GetString("Token") != "" { | 	if b.GetString("Token") != "" { | ||||||
| 		b.Log.Info("Connecting using token (receiving)") | 		b.Log.Info("Connecting using token (receiving)") | ||||||
| 		err := b.apiLogin() | 		b.Log.Infof("Using mattermost v6 methods: %t", b.v6) | ||||||
| 		if err != nil { |  | ||||||
| 			return err | 		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") != "" { | 	} else if b.GetString("Login") != "" { | ||||||
| 		b.Log.Info("Connecting using login/password (receiving)") | 		b.Log.Info("Connecting using login/password (receiving)") | ||||||
| 		err := b.apiLogin() | 		b.Log.Infof("Using mattermost v6 methods: %t", b.v6) | ||||||
| 		if err != nil { |  | ||||||
| 			return err | 		if b.v6 { | ||||||
|  | 			err := b.apiLogin6() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			err := b.apiLogin() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| @@ -84,6 +129,31 @@ func (b *Bmattermost) apiLogin() error { | |||||||
| 	return nil | 	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 | // replaceAction replace the message with the correct action (/me) code | ||||||
| func (b *Bmattermost) replaceAction(text string) (string, bool) { | func (b *Bmattermost) replaceAction(text string) (string, bool) { | ||||||
| 	if strings.HasPrefix(text, "*") && strings.HasSuffix(text, "*") { | 	if strings.HasPrefix(text, "*") && strings.HasSuffix(text, "*") { | ||||||
| @@ -171,11 +241,17 @@ func (b *Bmattermost) skipMessage(message *matterclient.Message) bool { | |||||||
| 		if b.GetBool("nosendjoinpart") { | 		if b.GetBool("nosendjoinpart") { | ||||||
| 			return true | 			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.Log.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account) | ||||||
| 		b.Remote <- config.Message{ | 		b.Remote <- config.Message{ | ||||||
| 			Username: "system", | 			Username: "system", | ||||||
| 			Text:     message.Text, | 			Text:     message.Text, | ||||||
| 			Channel:  message.Channel, | 			Channel:  channelName, | ||||||
| 			Account:  b.Account, | 			Account:  b.Account, | ||||||
| 			Event:    config.EventJoinLeave, | 			Event:    config.EventJoinLeave, | ||||||
| 		} | 		} | ||||||
| @@ -223,3 +299,119 @@ func (b *Bmattermost) skipMessage(message *matterclient.Message) bool { | |||||||
| 	} | 	} | ||||||
| 	return false | 	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 ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
| 	"github.com/42wim/matterbridge/bridge" | 	"github.com/42wim/matterbridge/bridge" | ||||||
| 	"github.com/42wim/matterbridge/bridge/config" | 	"github.com/42wim/matterbridge/bridge/config" | ||||||
| 	"github.com/42wim/matterbridge/bridge/helper" | 	"github.com/42wim/matterbridge/bridge/helper" | ||||||
| 	"github.com/42wim/matterbridge/matterclient" | 	"github.com/42wim/matterbridge/matterclient" | ||||||
| 	"github.com/42wim/matterbridge/matterhook" | 	"github.com/42wim/matterbridge/matterhook" | ||||||
|  | 	matterclient6 "github.com/matterbridge/matterclient" | ||||||
| 	"github.com/rs/xid" | 	"github.com/rs/xid" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Bmattermost struct { | type Bmattermost struct { | ||||||
| 	mh     *matterhook.Client | 	mh     *matterhook.Client | ||||||
| 	mc     *matterclient.MMClient | 	mc     *matterclient.MMClient | ||||||
|  | 	mc6    *matterclient6.Client | ||||||
|  | 	v6     bool | ||||||
| 	uuid   string | 	uuid   string | ||||||
| 	TeamID string | 	TeamID string | ||||||
| 	*bridge.Config | 	*bridge.Config | ||||||
| 	avatarMap map[string]string | 	avatarMap      map[string]string | ||||||
|  | 	channelsMutex  sync.RWMutex | ||||||
|  | 	channelInfoMap map[string]*config.ChannelInfo | ||||||
| } | } | ||||||
|  |  | ||||||
| const mattermostPlugin = "mattermost.plugin" | const mattermostPlugin = "mattermost.plugin" | ||||||
|  |  | ||||||
| func New(cfg *bridge.Config) bridge.Bridger { | 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() | 	b.uuid = xid.New().String() | ||||||
|  |  | ||||||
| 	return b | 	return b | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -37,6 +51,13 @@ func (b *Bmattermost) Connect() error { | |||||||
| 	if b.Account == mattermostPlugin { | 	if b.Account == mattermostPlugin { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if strings.HasPrefix(b.getVersion(), "6.") { | ||||||
|  | 		if !b.v6 { | ||||||
|  | 			b.v6 = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if b.GetString("WebhookBindAddress") != "" { | 	if b.GetString("WebhookBindAddress") != "" { | ||||||
| 		if err := b.doConnectWebhookBind(); err != nil { | 		if err := b.doConnectWebhookBind(); err != nil { | ||||||
| 			return err | 			return err | ||||||
| @@ -53,16 +74,34 @@ func (b *Bmattermost) Connect() error { | |||||||
| 		return nil | 		return nil | ||||||
| 	case b.GetString("Token") != "": | 	case b.GetString("Token") != "": | ||||||
| 		b.Log.Info("Connecting using token (sending and receiving)") | 		b.Log.Info("Connecting using token (sending and receiving)") | ||||||
| 		err := b.apiLogin() | 		b.Log.Infof("Using mattermost v6 methods: %t", b.v6) | ||||||
| 		if err != nil { |  | ||||||
| 			return err | 		if b.v6 { | ||||||
|  | 			err := b.apiLogin6() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			err := b.apiLogin() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		go b.handleMatter() | 		go b.handleMatter() | ||||||
| 	case b.GetString("Login") != "": | 	case b.GetString("Login") != "": | ||||||
| 		b.Log.Info("Connecting using login/password (sending and receiving)") | 		b.Log.Info("Connecting using login/password (sending and receiving)") | ||||||
| 		err := b.apiLogin() | 		b.Log.Infof("Using mattermost v6 methods: %t", b.v6) | ||||||
| 		if err != nil { |  | ||||||
| 			return err | 		if b.v6 { | ||||||
|  | 			err := b.apiLogin6() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			err := b.apiLogin() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		go b.handleMatter() | 		go b.handleMatter() | ||||||
| 	} | 	} | ||||||
| @@ -81,14 +120,25 @@ func (b *Bmattermost) JoinChannel(channel config.ChannelInfo) error { | |||||||
| 	if b.Account == mattermostPlugin { | 	if b.Account == mattermostPlugin { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	b.channelsMutex.Lock() | ||||||
|  | 	b.channelInfoMap[channel.ID] = &channel | ||||||
|  | 	b.channelsMutex.Unlock() | ||||||
|  |  | ||||||
| 	// we can only join channels using the API | 	// we can only join channels using the API | ||||||
| 	if b.GetString("WebhookURL") == "" && b.GetString("WebhookBindAddress") == "" { | 	if b.GetString("WebhookURL") == "" && b.GetString("WebhookBindAddress") == "" { | ||||||
| 		id := b.mc.GetChannelId(channel.Name, b.TeamID) | 		id := b.getChannelID(channel.Name) | ||||||
| 		if id == "" { | 		if id == "" { | ||||||
| 			return fmt.Errorf("Could not find channel ID for channel %s", channel.Name) | 			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 b.mc.JoinChannel(id) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -118,6 +168,10 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) { | |||||||
| 		if msg.ID == "" { | 		if msg.ID == "" { | ||||||
| 			return "", nil | 			return "", nil | ||||||
| 		} | 		} | ||||||
|  | 		if b.mc6 != nil { | ||||||
|  | 			return msg.ID, b.mc6.DeleteMessage(msg.ID) // nolint:wrapcheck | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return msg.ID, b.mc.DeleteMessage(msg.ID) | 		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) | 	// we only can reply to the root of the thread, not to a specific ID (like discord for example does) | ||||||
| 	if msg.ParentID != "" { | 	if msg.ParentID != "" { | ||||||
| 		post, res := b.mc.Client.GetPost(msg.ParentID, "") | 		if b.mc6 != nil { | ||||||
| 		if res.Error != nil { | 			post, _, err := b.mc6.Client.GetPost(msg.ParentID, "") | ||||||
| 			b.Log.Errorf("getting post %s failed: %s", msg.ParentID, res.Error.DetailedError) | 			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 | 	// Upload a file if it exists | ||||||
| 	if msg.Extra != nil { | 	if msg.Extra != nil { | ||||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | 		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 { | 			if b.mc6 != nil { | ||||||
| 				b.Log.Errorf("PostMessage failed: %s", err) | 				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 { | 		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 | 	// Edit message if we have an ID | ||||||
| 	if msg.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) | 		return b.mc.EditMessage(msg.ID, msg.Text) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Post normal message | 	// 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" | 	"golang.org/x/oauth2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var defaultScopes = []string{"openid", "profile", "offline_access", "Group.Read.All", "Group.ReadWrite.All"} | var ( | ||||||
| var attachRE = regexp.MustCompile(`<attachment id=.*?attachment>`) | 	defaultScopes = []string{"openid", "profile", "offline_access", "Group.Read.All", "Group.ReadWrite.All"} | ||||||
|  | 	attachRE      = regexp.MustCompile(`<attachment id=.*?attachment>`) | ||||||
|  | ) | ||||||
|  |  | ||||||
| type Bmsteams struct { | type Bmsteams struct { | ||||||
| 	gc    *msgraph.GraphServiceRequestBuilder | 	gc    *msgraph.GraphServiceRequestBuilder | ||||||
| @@ -50,7 +52,7 @@ func (b *Bmsteams) Connect() error { | |||||||
| 		b.Log.Errorf("Couldn't save sessionfile in %s: %s", tokenCachePath, err) | 		b.Log.Errorf("Couldn't save sessionfile in %s: %s", tokenCachePath, err) | ||||||
| 	} | 	} | ||||||
| 	// make file readable only for matterbridge user | 	// make file readable only for matterbridge user | ||||||
| 	err = os.Chmod(tokenCachePath, 0600) | 	err = os.Chmod(tokenCachePath, 0o600) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		b.Log.Errorf("Couldn't change permissions for %s: %s", tokenCachePath, err) | 		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. | 			// skip non-user message for now. | ||||||
| 			if msg.From.User == nil { | 			if msg.From == nil || msg.From.User == nil { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import ( | |||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net" | 	"net" | ||||||
| 	"strconv" | 	"strconv" | ||||||
|  | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"layeh.com/gumble/gumble" | 	"layeh.com/gumble/gumble" | ||||||
| @@ -252,8 +253,10 @@ func (b *Bmumble) processMessage(msg *config.Message) { | |||||||
| 	} else { | 	} else { | ||||||
| 		msgLines = helper.GetSubLines(msg.Text, 0, b.GetString("MessageClipped")) | 		msgLines = helper.GetSubLines(msg.Text, 0, b.GetString("MessageClipped")) | ||||||
| 	} | 	} | ||||||
| 	// Send the individual lindes | 	// Send the individual lines | ||||||
| 	for i := range msgLines { | 	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) | 		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 | 			// Ignore messages that are from the bot user | ||||||
| 			if msg.ActorID == b.user.User { | 			if msg.ActorID == b.user.User || msg.ActorType == "bridged" { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -123,7 +123,7 @@ func (b *Btalk) Send(msg config.Message) (string, error) { | |||||||
| 			return "", nil | 			return "", nil | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		sentMessage, err := r.room.SendMessage(msg.Username + msg.Text) | 		sentMessage, err := b.sendText(r, &msg, msg.Text) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			b.Log.Errorf("Could not send message to room %v from %v: %v", msg.Channel, msg.Username, err) | 			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 | 	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 { | func (b *Btalk) handleFiles(mmsg *config.Message, message *ocs.TalkRoomMessageData) error { | ||||||
| 	for _, parameter := range message.MessageParameters { | 	for _, parameter := range message.MessageParameters { | ||||||
| 		if parameter.Type == ocs.ROSTypeFile { | 		if parameter.Type == ocs.ROSTypeFile { | ||||||
| @@ -190,12 +201,12 @@ func (b *Btalk) handleSendingFile(msg *config.Message, r *Broom) error { | |||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		message := msg.Username | 		message := "" | ||||||
| 		if fi.Comment != "" { | 		if fi.Comment != "" { | ||||||
| 			message += fi.Comment + " " | 			message += fi.Comment + " " | ||||||
| 		} | 		} | ||||||
| 		message += fi.URL | 		message += fi.URL | ||||||
| 		_, err := r.room.SendMessage(message) | 		_, err := b.sendText(r, msg, message) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -27,7 +27,8 @@ func (b *Bslack) handleSlack() { | |||||||
| 	b.Log.Debug("Start listening for Slack messages") | 	b.Log.Debug("Start listening for Slack messages") | ||||||
| 	for message := range messages { | 	for message := range messages { | ||||||
| 		// don't do any action on deleted/typing 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) | 			b.Log.Debugf("<= Sending message from %s on %s to gateway", message.Username, b.Account) | ||||||
| 			// cleanup the message | 			// cleanup the message | ||||||
| 			message.Text = b.replaceMention(message.Text) | 			message.Text = b.replaceMention(message.Text) | ||||||
| @@ -76,6 +77,13 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) { | |||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			messages <- rmsg | 			messages <- rmsg | ||||||
|  | 		case *slack.FileDeletedEvent: | ||||||
|  | 			rmsg, err := b.handleFileDeletedEvent(ev) | ||||||
|  | 			if err != nil { | ||||||
|  | 				b.Log.Errorf("%#v", err) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			messages <- rmsg | ||||||
| 		case *slack.OutgoingErrorEvent: | 		case *slack.OutgoingErrorEvent: | ||||||
| 			b.Log.Debugf("%#v", ev.Error()) | 			b.Log.Debugf("%#v", ev.Error()) | ||||||
| 		case *slack.ChannelJoinedEvent: | 		case *slack.ChannelJoinedEvent: | ||||||
| @@ -95,6 +103,8 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) { | |||||||
| 			b.users.populateUser(ev.User) | 			b.users.populateUser(ev.User) | ||||||
| 		case *slack.HelloEvent, *slack.LatencyReport, *slack.ConnectingEvent: | 		case *slack.HelloEvent, *slack.LatencyReport, *slack.ConnectingEvent: | ||||||
| 			continue | 			continue | ||||||
|  | 		case *slack.UserChangeEvent: | ||||||
|  | 			b.users.invalidateUser(ev.User.ID) | ||||||
| 		default: | 		default: | ||||||
| 			b.Log.Debugf("Unhandled incoming event: %T", ev) | 			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 | 	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 { | func (b *Bslack) handleStatusEvent(ev *slack.MessageEvent, rmsg *config.Message) bool { | ||||||
| 	switch ev.SubType { | 	switch ev.SubType { | ||||||
| 	case sChannelJoined, sMemberJoined: | 	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. | 	// If we have files attached, download them (in memory) and put a pointer to it in msg.Extra. | ||||||
| 	for i := range ev.Files { | 	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 { | 		if err := b.handleDownloadFile(rmsg, &ev.Files[i], false); err != nil { | ||||||
| 			b.Log.Errorf("Could not download incoming file: %#v", err) | 			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. | 	// that the comment is not duplicated. | ||||||
| 	comment := rmsg.Text | 	comment := rmsg.Text | ||||||
| 	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 | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -36,24 +36,25 @@ type Bslack struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	sHello           = "hello" | 	sHello               = "hello" | ||||||
| 	sChannelJoin     = "channel_join" | 	sChannelJoin         = "channel_join" | ||||||
| 	sChannelLeave    = "channel_leave" | 	sChannelLeave        = "channel_leave" | ||||||
| 	sChannelJoined   = "channel_joined" | 	sChannelJoined       = "channel_joined" | ||||||
| 	sMemberJoined    = "member_joined_channel" | 	sMemberJoined        = "member_joined_channel" | ||||||
| 	sMessageChanged  = "message_changed" | 	sMessageChanged      = "message_changed" | ||||||
| 	sMessageDeleted  = "message_deleted" | 	sMessageDeleted      = "message_deleted" | ||||||
| 	sSlackAttachment = "slack_attachment" | 	sSlackAttachment     = "slack_attachment" | ||||||
| 	sPinnedItem      = "pinned_item" | 	sPinnedItem          = "pinned_item" | ||||||
| 	sUnpinnedItem    = "unpinned_item" | 	sUnpinnedItem        = "unpinned_item" | ||||||
| 	sChannelTopic    = "channel_topic" | 	sChannelTopic        = "channel_topic" | ||||||
| 	sChannelPurpose  = "channel_purpose" | 	sChannelPurpose      = "channel_purpose" | ||||||
| 	sFileComment     = "file_comment" | 	sFileComment         = "file_comment" | ||||||
| 	sMeMessage       = "me_message" | 	sMeMessage           = "me_message" | ||||||
| 	sUserTyping      = "user_typing" | 	sUserTyping          = "user_typing" | ||||||
| 	sLatencyReport   = "latency_report" | 	sLatencyReport       = "latency_report" | ||||||
| 	sSystemUser      = "system" | 	sSystemUser          = "system" | ||||||
| 	sSlackBotUser    = "slackbot" | 	sSlackBotUser        = "slackbot" | ||||||
|  | 	cfileDownloadChannel = "file_download_channel" | ||||||
|  |  | ||||||
| 	tokenConfig           = "Token" | 	tokenConfig           = "Token" | ||||||
| 	incomingWebhookConfig = "WebhookBindAddress" | 	incomingWebhookConfig = "WebhookBindAddress" | ||||||
| @@ -459,7 +460,7 @@ func (b *Bslack) uploadFile(msg *config.Message, channelID string) { | |||||||
| 		b.cache.Add("filename"+fi.Name, ts) | 		b.cache.Add("filename"+fi.Name, ts) | ||||||
| 		initialComment := fmt.Sprintf("File from %s", msg.Username) | 		initialComment := fmt.Sprintf("File from %s", msg.Username) | ||||||
| 		if fi.Comment != "" { | 		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{ | 		res, err := b.sc.UploadFile(slack.FileUploadParameters{ | ||||||
| 			Reader:          bytes.NewReader(*fi.Data), | 			Reader:          bytes.NewReader(*fi.Data), | ||||||
|   | |||||||
| @@ -113,6 +113,12 @@ func (b *users) populateUser(userID string) { | |||||||
| 	b.users[userID] = user | 	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) { | func (b *users) populateUsers(wait bool) { | ||||||
| 	b.refreshMutex.Lock() | 	b.refreshMutex.Lock() | ||||||
| 	if !wait && (time.Now().Before(b.earliestRefresh) || b.refreshInProgress) { | 	if !wait && (time.Now().Before(b.earliestRefresh) || b.refreshInProgress) { | ||||||
| @@ -285,6 +291,7 @@ func (b *channels) populateChannels(wait bool) { | |||||||
| 	queryParams := &slack.GetConversationsParameters{ | 	queryParams := &slack.GetConversationsParameters{ | ||||||
| 		ExcludeArchived: true, | 		ExcludeArchived: true, | ||||||
| 		Types:           []string{"public_channel,private_channel"}, | 		Types:           []string{"public_channel,private_channel"}, | ||||||
|  | 		Limit:           1000, | ||||||
| 	} | 	} | ||||||
| 	for { | 	for { | ||||||
| 		channels, nextCursor, err := b.sc.GetConversations(queryParams) | 		channels, nextCursor, err := b.sc.GetConversations(queryParams) | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package btelegram | package btelegram | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"html" | 	"html" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| @@ -9,14 +10,27 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/42wim/matterbridge/bridge/config" | 	"github.com/42wim/matterbridge/bridge/config" | ||||||
| 	"github.com/42wim/matterbridge/bridge/helper" | 	"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 { | func (b *Btelegram) handleUpdate(rmsg *config.Message, message, posted, edited *tgbotapi.Message) *tgbotapi.Message { | ||||||
| 	// handle channels | 	// handle channels | ||||||
| 	if posted != nil { | 	if posted != nil { | ||||||
| 		message = posted | 		if posted.Text == "/chatId" { | ||||||
| 		rmsg.Text = message.Text | 			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 | 	// edited channel message | ||||||
| @@ -94,7 +108,7 @@ func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Messag | |||||||
| // handleUsername handles the correct setting of the username | // handleUsername handles the correct setting of the username | ||||||
| func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Message) { | func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Message) { | ||||||
| 	if message.From != nil { | 	if message.From != nil { | ||||||
| 		rmsg.UserID = strconv.Itoa(message.From.ID) | 		rmsg.UserID = strconv.FormatInt(message.From.ID, 10) | ||||||
| 		if b.GetBool("UseFirstName") { | 		if b.GetBool("UseFirstName") { | ||||||
| 			rmsg.Username = message.From.FirstName | 			rmsg.Username = message.From.FirstName | ||||||
| 		} | 		} | ||||||
| @@ -110,6 +124,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 we really didn't find a username, set it to unknown | ||||||
| 	if rmsg.Username == "" { | 	if rmsg.Username == "" { | ||||||
| 		rmsg.Username = unknownUser | 		rmsg.Username = unknownUser | ||||||
| @@ -126,6 +159,10 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | |||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if b.GetInt("debuglevel") == 1 { | ||||||
|  | 			spew.Dump(update.Message) | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		var message *tgbotapi.Message | 		var message *tgbotapi.Message | ||||||
|  |  | ||||||
| 		rmsg := config.Message{Account: b.Account, Extra: make(map[string][]interface{})} | 		rmsg := config.Message{Account: b.Account, Extra: make(map[string][]interface{})} | ||||||
| @@ -167,7 +204,7 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | |||||||
| 			rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text) | 			rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text) | ||||||
| 			// channels don't have (always?) user information. see #410 | 			// channels don't have (always?) user information. see #410 | ||||||
| 			if message.From != nil { | 			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) | 			b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account) | ||||||
| @@ -180,60 +217,52 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | |||||||
| // handleDownloadAvatar downloads the avatar of userid from channel | // handleDownloadAvatar downloads the avatar of userid from channel | ||||||
| // sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful. | // sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful. | ||||||
| // logs an error message if it fails | // 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{ | 	rmsg := config.Message{ | ||||||
| 		Username: "system", | 		Username: "system", | ||||||
| 		Text:     "avatar", | 		Text:     "avatar", | ||||||
| 		Channel:  channel, | 		Channel:  channel, | ||||||
| 		Account:  b.Account, | 		Account:  b.Account, | ||||||
| 		UserID:   strconv.Itoa(userid), | 		UserID:   strconv.FormatInt(userid, 10), | ||||||
| 		Event:    config.EventAvatarDownload, | 		Event:    config.EventAvatarDownload, | ||||||
| 		Extra:    make(map[string][]interface{}), | 		Extra:    make(map[string][]interface{}), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if _, ok := b.avatarMap[strconv.Itoa(userid)]; !ok { | 	if _, ok := b.avatarMap[strconv.FormatInt(userid, 10)]; ok { | ||||||
| 		photos, err := b.c.GetUserProfilePhotos(tgbotapi.UserProfilePhotosConfig{UserID: userid, Limit: 1}) | 		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 { | 		if err != nil { | ||||||
| 			b.Log.Errorf("Userprofile download failed for %#v %s", userid, err) | 			b.Log.Error(err) | ||||||
|  | 			return | ||||||
| 		} | 		} | ||||||
|  | 		data, err := helper.DownloadFile(url) | ||||||
| 		if len(photos.Photos) > 0 { | 		if err != nil { | ||||||
| 			photo := photos.Photos[0][0] | 			b.Log.Errorf("download %s failed %#v", url, err) | ||||||
| 			url := b.getFileDirectURL(photo.FileID) | 			return | ||||||
| 			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 |  | ||||||
| 		} | 		} | ||||||
|  | 		helper.HandleDownloadData(b.Log, &rmsg, name, rmsg.Text, "", data, b.General) | ||||||
|  | 		b.Remote <- rmsg | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (b *Btelegram) maybeConvertTgs(name *string, data *[]byte) { | func (b *Btelegram) maybeConvertTgs(name *string, data *[]byte) { | ||||||
| 	var format string | 	format := b.GetString("MediaConvertTgs") | ||||||
| 	switch b.GetString("MediaConvertTgs") { | 	if helper.SupportsFormat(format) { | ||||||
| 	case FormatWebp: | 		b.Log.Debugf("Format supported by %s, converting %v", helper.LottieBackend(), name) | ||||||
| 		b.Log.Debugf("Tgs to WebP conversion enabled, converting %v", name) | 	} else { | ||||||
| 		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: |  | ||||||
| 		// Otherwise, no conversion was requested. Trying to run the usual webp | 		// Otherwise, no conversion was requested. Trying to run the usual webp | ||||||
| 		// converter would fail, because '.tgs.webp' is actually a gzipped JSON | 		// converter would fail, because '.tgs.webp' is actually a gzipped JSON | ||||||
| 		// file, and has nothing to do with WebP. | 		// file, and has nothing to do with WebP. | ||||||
| @@ -282,7 +311,7 @@ func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Messa | |||||||
| 		name = message.Document.FileName | 		name = message.Document.FileName | ||||||
| 		text = " " + message.Document.FileName + " : " + url | 		text = " " + message.Document.FileName + " : " + url | ||||||
| 	case message.Photo != nil: | 	case message.Photo != nil: | ||||||
| 		photos := *message.Photo | 		photos := message.Photo | ||||||
| 		size = photos[len(photos)-1].FileSize | 		size = photos[len(photos)-1].FileSize | ||||||
| 		text, name, url = b.getDownloadInfo(photos[len(photos)-1].FileID, "", true) | 		text, name, url = b.getDownloadInfo(photos[len(photos)-1].FileID, "", true) | ||||||
| 	} | 	} | ||||||
| @@ -341,11 +370,15 @@ func (b *Btelegram) handleDelete(msg *config.Message, chatid int64) (string, err | |||||||
| 	if msg.ID == "" { | 	if msg.ID == "" { | ||||||
| 		return "", nil | 		return "", nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	msgid, err := strconv.Atoi(msg.ID) | 	msgid, err := strconv.Atoi(msg.ID) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
| 	_, err = b.c.DeleteMessage(tgbotapi.DeleteMessageConfig{ChatID: chatid, MessageID: msgid}) |  | ||||||
|  | 	cfg := tgbotapi.NewDeleteMessage(chatid, msgid) | ||||||
|  | 	_, err = b.c.Send(cfg) | ||||||
|  |  | ||||||
| 	return "", err | 	return "", err | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -393,23 +426,23 @@ func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string { | |||||||
| 		} | 		} | ||||||
| 		switch filepath.Ext(fi.Name) { | 		switch filepath.Ext(fi.Name) { | ||||||
| 		case ".jpg", ".jpe", ".png": | 		case ".jpg", ".jpe", ".png": | ||||||
| 			pc := tgbotapi.NewPhotoUpload(chatid, file) | 			pc := tgbotapi.NewPhoto(chatid, file) | ||||||
| 			pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | 			pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | ||||||
| 			c = pc | 			c = pc | ||||||
| 		case ".mp4", ".m4v": | 		case ".mp4", ".m4v": | ||||||
| 			vc := tgbotapi.NewVideoUpload(chatid, file) | 			vc := tgbotapi.NewVideo(chatid, file) | ||||||
| 			vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | 			vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | ||||||
| 			c = vc | 			c = vc | ||||||
| 		case ".mp3", ".oga": | 		case ".mp3", ".oga": | ||||||
| 			ac := tgbotapi.NewAudioUpload(chatid, file) | 			ac := tgbotapi.NewAudio(chatid, file) | ||||||
| 			ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | 			ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | ||||||
| 			c = ac | 			c = ac | ||||||
| 		case ".ogg": | 		case ".ogg": | ||||||
| 			voc := tgbotapi.NewVoiceUpload(chatid, file) | 			voc := tgbotapi.NewVoice(chatid, file) | ||||||
| 			voc.Caption, voc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | 			voc.Caption, voc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | ||||||
| 			c = voc | 			c = voc | ||||||
| 		default: | 		default: | ||||||
| 			dc := tgbotapi.NewDocumentUpload(chatid, file) | 			dc := tgbotapi.NewDocument(chatid, file) | ||||||
| 			dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | 			dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | ||||||
| 			c = dc | 			c = dc | ||||||
| 		} | 		} | ||||||
| @@ -445,8 +478,11 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa | |||||||
| 	if message.Entities == nil { | 	if message.Entities == nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	indexMovedBy := 0 | ||||||
|  |  | ||||||
| 	// for now only do URL replacements | 	// for now only do URL replacements | ||||||
| 	for _, e := range *message.Entities { | 	for _, e := range message.Entities { | ||||||
| 		if e.Type == "text_link" { | 		if e.Type == "text_link" { | ||||||
| 			url, err := e.ParseURL() | 			url, err := e.ParseURL() | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| @@ -461,5 +497,17 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa | |||||||
| 			link := utf16.Decode(utfEncodedString[e.Offset : e.Offset+e.Length]) | 			link := utf16.Decode(utfEncodedString[e.Offset : e.Offset+e.Length]) | ||||||
| 			rmsg.Text = strings.Replace(rmsg.Text, string(link), url.String(), 1) | 			rmsg.Text = strings.Replace(rmsg.Text, string(link), url.String(), 1) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if e.Type == "code" { | ||||||
|  | 			offset := e.Offset + indexMovedBy | ||||||
|  | 			rmsg.Text = rmsg.Text[:offset] + "`" + rmsg.Text[offset:offset+e.Length] + "`" + rmsg.Text[offset+e.Length:] | ||||||
|  | 			indexMovedBy += 2 | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if e.Type == "pre" { | ||||||
|  | 			offset := e.Offset + indexMovedBy | ||||||
|  | 			rmsg.Text = rmsg.Text[:offset] + "```\n" + rmsg.Text[offset:offset+e.Length] + "\n```" + rmsg.Text[offset+e.Length:] | ||||||
|  | 			indexMovedBy += 8 | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import ( | |||||||
| 	"github.com/42wim/matterbridge/bridge" | 	"github.com/42wim/matterbridge/bridge" | ||||||
| 	"github.com/42wim/matterbridge/bridge/config" | 	"github.com/42wim/matterbridge/bridge/config" | ||||||
| 	"github.com/42wim/matterbridge/bridge/helper" | 	"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 ( | const ( | ||||||
| @@ -17,8 +17,6 @@ const ( | |||||||
| 	HTMLFormat  = "HTML" | 	HTMLFormat  = "HTML" | ||||||
| 	HTMLNick    = "htmlnick" | 	HTMLNick    = "htmlnick" | ||||||
| 	MarkdownV2  = "MarkdownV2" | 	MarkdownV2  = "MarkdownV2" | ||||||
| 	FormatPng   = "png" |  | ||||||
| 	FormatWebp  = "webp" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Btelegram struct { | type Btelegram struct { | ||||||
| @@ -32,10 +30,10 @@ func New(cfg *bridge.Config) bridge.Bridger { | |||||||
| 	if tgsConvertFormat != "" { | 	if tgsConvertFormat != "" { | ||||||
| 		err := helper.CanConvertTgsToX() | 		err := helper.CanConvertTgsToX() | ||||||
| 		if err != nil { | 		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 { | 		if !helper.SupportsFormat(tgsConvertFormat) { | ||||||
| 			log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but only '%s' and '%s' are supported.", FormatPng, FormatWebp, 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)} | 	return &Btelegram{Config: cfg, avatarMap: make(map[string]string)} | ||||||
| @@ -51,11 +49,7 @@ func (b *Btelegram) Connect() error { | |||||||
| 	} | 	} | ||||||
| 	u := tgbotapi.NewUpdate(0) | 	u := tgbotapi.NewUpdate(0) | ||||||
| 	u.Timeout = 60 | 	u.Timeout = 60 | ||||||
| 	updates, err := b.c.GetUpdatesChan(u) | 	updates := b.c.GetUpdatesChan(u) | ||||||
| 	if err != nil { |  | ||||||
| 		b.Log.Debugf("%#v", err) |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	b.Log.Info("Connection succeeded") | 	b.Log.Info("Connection succeeded") | ||||||
| 	go b.handleRecv(updates) | 	go b.handleRecv(updates) | ||||||
| 	return nil | 	return nil | ||||||
|   | |||||||
| @@ -34,6 +34,7 @@ type user struct { | |||||||
|  |  | ||||||
| type Bvk struct { | type Bvk struct { | ||||||
| 	c            *api.VK | 	c            *api.VK | ||||||
|  | 	lp           *longpoll.LongPoll | ||||||
| 	usernamesMap map[int]user // cache of user names and avatar URLs | 	usernamesMap map[int]user // cache of user names and avatar URLs | ||||||
| 	*bridge.Config | 	*bridge.Config | ||||||
| } | } | ||||||
| @@ -45,21 +46,23 @@ func New(cfg *bridge.Config) bridge.Bridger { | |||||||
| func (b *Bvk) Connect() error { | func (b *Bvk) Connect() error { | ||||||
| 	b.Log.Info("Connecting") | 	b.Log.Info("Connecting") | ||||||
| 	b.c = api.NewVK(b.GetString("Token")) | 	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 { | 	if err != nil { | ||||||
| 		b.Log.Debugf("%#v", err) | 		b.Log.Debugf("%#v", err) | ||||||
|  |  | ||||||
| 		return 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.handleMessage(obj.Message, false) | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	b.Log.Info("Connection succeeded") | 	b.Log.Info("Connection succeeded") | ||||||
|  |  | ||||||
| 	go func() { | 	go func() { | ||||||
| 		err := lp.Run() | 		err := b.lp.Run() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			b.Log.Fatal("Enable longpoll in group management") | 			b.Log.Fatal("Enable longpoll in group management") | ||||||
| 		} | 		} | ||||||
| @@ -69,6 +72,8 @@ func (b *Bvk) Connect() error { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (b *Bvk) Disconnect() error { | func (b *Bvk) Disconnect() error { | ||||||
|  | 	b.lp.Shutdown() | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -128,7 +128,6 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) { | |||||||
| 	var msgReplaceID string | 	var msgReplaceID string | ||||||
| 	msgID := xid.New().String() | 	msgID := xid.New().String() | ||||||
| 	if msg.ID != "" { | 	if msg.ID != "" { | ||||||
| 		msgID = msg.ID |  | ||||||
| 		msgReplaceID = msg.ID | 		msgReplaceID = msg.ID | ||||||
| 	} | 	} | ||||||
| 	b.Log.Debugf("=> Sending message %#v", msg) | 	b.Log.Debugf("=> Sending message %#v", msg) | ||||||
| @@ -169,11 +168,21 @@ func (b *Bxmpp) postSlackCompatibleWebhook(msg config.Message) error { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (b *Bxmpp) createXMPP() error { | func (b *Bxmpp) createXMPP() error { | ||||||
| 	if !strings.Contains(b.GetString("Jid"), "@") { | 	var serverName string | ||||||
| 		return fmt.Errorf("the Jid %s doesn't contain an @", b.GetString("Jid")) | 	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{ | 	tc := &tls.Config{ | ||||||
| 		ServerName:         strings.Split(b.GetString("Jid"), "@")[1], | 		ServerName:         serverName, | ||||||
| 		InsecureSkipVerify: b.GetBool("SkipTLSVerify"), // nolint: gosec | 		InsecureSkipVerify: b.GetBool("SkipTLSVerify"), // nolint: gosec | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -274,7 +283,13 @@ func (b *Bxmpp) handleXMPP() error { | |||||||
| 	for { | 	for { | ||||||
| 		m, err := b.xc.Recv() | 		m, err := b.xc.Recv() | ||||||
| 		if err != nil { | 		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) { | 		switch v := m.(type) { | ||||||
| @@ -385,7 +400,7 @@ func (b *Bxmpp) handleUploadFile(msg *config.Message) error { | |||||||
|  |  | ||||||
| func (b *Bxmpp) parseNick(remote string) string { | func (b *Bxmpp) parseNick(remote string) string { | ||||||
| 	s := strings.Split(remote, "@") | 	s := strings.Split(remote, "@") | ||||||
| 	if len(s) > 0 { | 	if len(s) > 1 { | ||||||
| 		s = strings.Split(s[1], "/") | 		s = strings.Split(s[1], "/") | ||||||
| 		if len(s) == 2 { | 		if len(s) == 2 { | ||||||
| 			return s[1] // nick | 			return s[1] // nick | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ package bzulip | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| @@ -11,6 +12,7 @@ import ( | |||||||
| 	"github.com/42wim/matterbridge/bridge" | 	"github.com/42wim/matterbridge/bridge" | ||||||
| 	"github.com/42wim/matterbridge/bridge/config" | 	"github.com/42wim/matterbridge/bridge/config" | ||||||
| 	"github.com/42wim/matterbridge/bridge/helper" | 	"github.com/42wim/matterbridge/bridge/helper" | ||||||
|  | 	"github.com/42wim/matterbridge/version" | ||||||
| 	gzb "github.com/matterbridge/gozulipbot" | 	gzb "github.com/matterbridge/gozulipbot" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -27,7 +29,7 @@ func New(cfg *bridge.Config) bridge.Bridger { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (b *Bzulip) Connect() error { | 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() | 	bot.Init() | ||||||
| 	q, err := bot.RegisterAll() | 	q, err := bot.RegisterAll() | ||||||
| 	b.q = q | 	b.q = q | ||||||
| @@ -125,6 +127,7 @@ func (b *Bzulip) handleQueue() error { | |||||||
| 			b.Log.Debug("heartbeat received.") | 			b.Log.Debug("heartbeat received.") | ||||||
| 		default: | 		default: | ||||||
| 			b.Log.Debugf("receiving error: %#v", err) | 			b.Log.Debugf("receiving error: %#v", err) | ||||||
|  | 			time.Sleep(time.Second * 10) | ||||||
| 		} | 		} | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			continue | 			continue | ||||||
|   | |||||||
							
								
								
									
										48
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,3 +1,51 @@ | |||||||
|  | # v1.23.2 | ||||||
|  |  | ||||||
|  | If you're running whatsapp you should update. | ||||||
|  |  | ||||||
|  | ## Bugfix | ||||||
|  |  | ||||||
|  | - whatsapp: Update go-whatsapp version (#1630) | ||||||
|  |  | ||||||
|  | # 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) | ||||||
|  |  | ||||||
|  | # 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 | # v1.22.3 | ||||||
|  |  | ||||||
| ## Bugfixes | ## Bugfixes | ||||||
|   | |||||||
| @@ -1,9 +1,10 @@ | |||||||
| FROM alpine:edge as certs | FROM alpine:edge as certs | ||||||
| RUN apk --update add ca-certificates | 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 | FROM scratch | ||||||
| ARG VERSION=1.12.3 |  | ||||||
| COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt | 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 | COPY --from=certs /bin/matterbridge /bin/matterbridge | ||||||
| RUN chmod +x /bin/matterbridge |  | ||||||
| ENTRYPOINT ["/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 { | func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string { | ||||||
| 	ID := protocol + " " + mID | 	ID := protocol + " " + mID | ||||||
| 	if gw.Messages.Contains(ID) { | 	if gw.Messages.Contains(ID) { | ||||||
| 		return mID | 		return ID | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// If not keyed, iterate through cache for downstream, and infer upstream. | 	// 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) | 		ids := v.([]*BrMsgID) | ||||||
| 		for _, downstreamMsgObj := range ids { | 		for _, downstreamMsgObj := range ids { | ||||||
| 			if ID == downstreamMsgObj.ID { | 			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.Avatar = gw.modifyAvatar(rmsg, dest) | ||||||
| 	msg.Username = gw.modifyUsername(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 | 	// for api we need originchannel as channel | ||||||
| 	if dest.Protocol == apiProtocol { | 	if dest.Protocol == apiProtocol { | ||||||
| 		msg.Channel = rmsg.Channel | 		msg.Channel = rmsg.Channel | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	msg.ParentID = gw.getDestMsgID(rmsg.Protocol+" "+canonicalParentMsgID, dest, channel) | 	msg.ParentID = gw.getDestMsgID(canonicalParentMsgID, dest, channel) | ||||||
| 	if msg.ParentID == "" { | 	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 | 	// 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 { | 	if r.BridgeValues().General.IgnoreFailureOnStart { | ||||||
| 		r.logger.Error(err) | 		r.logger.Error(err) | ||||||
| 		// setting this bridge empty | 		// setting this bridge empty | ||||||
| 		*br = bridge.Bridge{} | 		*br = bridge.Bridge{ | ||||||
|  | 			Log: br.Log, | ||||||
|  | 		} | ||||||
| 		return true | 		return true | ||||||
| 	} | 	} | ||||||
| 	return false | 	return false | ||||||
|   | |||||||
							
								
								
									
										137
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										137
									
								
								go.mod
									
									
									
									
									
								
							| @@ -3,37 +3,36 @@ module github.com/42wim/matterbridge | |||||||
| require ( | require ( | ||||||
| 	github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 | 	github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 | ||||||
| 	github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f | 	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/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560 | ||||||
| 	github.com/Rhymen/go-whatsapp v0.1.2-0.20210615184944-2b8a3e9b8aa2 | 	github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c | ||||||
| 	github.com/SevereCloud/vksdk/v2 v2.10.0 | 	github.com/SevereCloud/vksdk/v2 v2.13.0 | ||||||
| 	github.com/d5/tengo/v2 v2.7.0 | 	github.com/d5/tengo/v2 v2.10.0 | ||||||
| 	github.com/davecgh/go-spew v1.1.1 | 	github.com/davecgh/go-spew v1.1.1 | ||||||
| 	github.com/fsnotify/fsnotify v1.4.9 | 	github.com/fsnotify/fsnotify v1.5.1 | ||||||
| 	github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81 | 	github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 | ||||||
| 	github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7 | 	github.com/gomarkdown/markdown v0.0.0-20211207152620-5d6539fd8bfc | ||||||
| 	github.com/google/gops v0.3.18 | 	github.com/google/gops v0.3.22 | ||||||
| 	github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect |  | ||||||
| 	github.com/gorilla/schema v1.2.0 | 	github.com/gorilla/schema v1.2.0 | ||||||
| 	github.com/gorilla/websocket v1.4.2 | 	github.com/gorilla/websocket v1.4.2 | ||||||
|  | 	github.com/harmony-development/shibshib v0.0.0-20211127182844-512296f7c548 | ||||||
| 	github.com/hashicorp/golang-lru v0.5.4 | 	github.com/hashicorp/golang-lru v0.5.4 | ||||||
| 	github.com/jpillora/backoff v1.0.0 | 	github.com/jpillora/backoff v1.0.0 | ||||||
| 	github.com/keybase/go-keybase-chat-bot v0.0.0-20200505163032-5cacf52379da | 	github.com/keybase/go-keybase-chat-bot v0.0.0-20211201215354-ee4b23828b55 | ||||||
| 	github.com/kyokomi/emoji/v2 v2.2.8 | 	github.com/kyokomi/emoji/v2 v2.2.8 | ||||||
| 	github.com/labstack/echo/v4 v4.3.0 | 	github.com/labstack/echo/v4 v4.6.3 | ||||||
| 	github.com/lrstanley/girc v0.0.0-20210611213246-771323f1624b | 	github.com/lrstanley/girc v0.0.0-20211023233735-147f0ff77566 | ||||||
| 	github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 | 	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/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696 | ||||||
| 	github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7 | 	github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7 | ||||||
| 	github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050 | 	github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be | ||||||
| 	github.com/matterbridge/gozulipbot v0.0.0-20200820220548-be5824faa913 | 	github.com/matterbridge/gozulipbot v0.0.0-20211023205727-a19d6c1f3b75 | ||||||
| 	github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba | 	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.3.0 | ||||||
| 	github.com/mattn/godown v0.0.1 | 	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/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/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9 | ||||||
| 	github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c | 	github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c | ||||||
| 	github.com/rs/xid v1.3.0 | 	github.com/rs/xid v1.3.0 | ||||||
| @@ -41,20 +40,102 @@ require ( | |||||||
| 	github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca | 	github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca | ||||||
| 	github.com/shazow/ssh-chat v1.10.1 | 	github.com/shazow/ssh-chat v1.10.1 | ||||||
| 	github.com/sirupsen/logrus v1.8.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.10.0 | ||||||
| 	github.com/slack-go/slack v0.9.1 | 	github.com/spf13/viper v1.10.1 | ||||||
| 	github.com/spf13/viper v1.8.0 |  | ||||||
| 	github.com/stretchr/testify v1.7.0 | 	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/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/yaegashi/msgraph.go v0.1.4 | ||||||
| 	github.com/zfjagann/golang-ring v0.0.0-20210116075443-7c86fdb43134 | 	github.com/zfjagann/golang-ring v0.0.0-20210116075443-7c86fdb43134 | ||||||
| 	golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9 | 	golang.org/x/image v0.0.0-20211028202545-6944b10bf410 | ||||||
| 	golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1 | 	golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 | ||||||
| 	gomod.garykim.dev/nc-talk v0.2.2 | 	gomod.garykim.dev/nc-talk v0.3.0 | ||||||
| 	gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376 | 	gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376 | ||||||
| 	layeh.com/gumble v0.0.0-20200818122324-146f9205029b | 	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.1 // 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-20211123203042-d83791d6bcd9 // indirect | ||||||
|  | 	golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect | ||||||
|  | 	golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect | ||||||
|  | 	golang.org/x/text v0.3.7 // 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" | 	"log" | ||||||
| 	"net" | 	"net" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"regexp" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Message for rocketchat outgoing webhook. | // Message for rocketchat outgoing webhook. | ||||||
| @@ -68,7 +69,6 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||||||
| 	} | 	} | ||||||
| 	msg := Message{} | 	msg := Message{} | ||||||
| 	body, err := ioutil.ReadAll(r.Body) | 	body, err := ioutil.ReadAll(r.Body) | ||||||
| 	log.Println(string(body)) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Println(err) | 		log.Println(err) | ||||||
| 		http.NotFound(w, r) | 		http.NotFound(w, r) | ||||||
| @@ -89,7 +89,11 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||||||
| 	msg.ChannelName = "#" + msg.ChannelName | 	msg.ChannelName = "#" + msg.ChannelName | ||||||
| 	if c.Token != "" { | 	if c.Token != "" { | ||||||
| 		if msg.Token != 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) | 			http.NotFound(w, r) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -10,15 +10,13 @@ import ( | |||||||
| 	"github.com/42wim/matterbridge/bridge/config" | 	"github.com/42wim/matterbridge/bridge/config" | ||||||
| 	"github.com/42wim/matterbridge/gateway" | 	"github.com/42wim/matterbridge/gateway" | ||||||
| 	"github.com/42wim/matterbridge/gateway/bridgemap" | 	"github.com/42wim/matterbridge/gateway/bridgemap" | ||||||
|  | 	"github.com/42wim/matterbridge/version" | ||||||
| 	"github.com/google/gops/agent" | 	"github.com/google/gops/agent" | ||||||
| 	prefixed "github.com/matterbridge/logrus-prefixed-formatter" | 	prefixed "github.com/matterbridge/logrus-prefixed-formatter" | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	version = "1.22.3" |  | ||||||
| 	githash string |  | ||||||
|  |  | ||||||
| 	flagConfig  = flag.String("conf", "matterbridge.toml", "config file") | 	flagConfig  = flag.String("conf", "matterbridge.toml", "config file") | ||||||
| 	flagDebug   = flag.Bool("debug", false, "enable debug") | 	flagDebug   = flag.Bool("debug", false, "enable debug") | ||||||
| 	flagVersion = flag.Bool("version", false, "show version") | 	flagVersion = flag.Bool("version", false, "show version") | ||||||
| @@ -28,7 +26,7 @@ var ( | |||||||
| func main() { | func main() { | ||||||
| 	flag.Parse() | 	flag.Parse() | ||||||
| 	if *flagVersion { | 	if *flagVersion { | ||||||
| 		fmt.Printf("version: %s %s\n", version, githash) | 		fmt.Printf("version: %s %s\n", version.Release, version.GitHash) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -43,8 +41,8 @@ func main() { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	logger.Printf("Running version %s %s", version, githash) | 	logger.Printf("Running version %s %s", version.Release, version.GitHash) | ||||||
| 	if strings.Contains(version, "-dev") { | 	if strings.Contains(version.Release, "-dev") { | ||||||
| 		logger.Println("WARNING: THIS IS A DEVELOPMENT VERSION. Things may break.") | 		logger.Println("WARNING: THIS IS A DEVELOPMENT VERSION. Things may break.") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,6 +24,13 @@ Password="" | |||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| UseTLS=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) | #Enable SASL (PLAIN) authentication. (libera requires this from eg AWS hosts) | ||||||
| #It uses NickServNick and NickServPassword as login and password | #It uses NickServNick and NickServPassword as login and password | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| @@ -34,6 +41,11 @@ UseSASL=false | |||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| SkipTLSVerify=true | 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. | #If you know your charset, you can specify it manually. | ||||||
| #Otherwise it tries to detect this automatically. Select one below | #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", | # "iso-8859-2:1987", "iso-8859-9:1989", "866", "latin9", "iso-8859-10:1992", "iso-ir-109", "hebrew", | ||||||
| @@ -55,6 +67,14 @@ Charset="" | |||||||
| #REQUIRED | #REQUIRED | ||||||
| Nick="matterbot" | 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. | #If you registered your bot with a service like Nickserv on libera. | ||||||
| #Also being used when UseSASL=true | #Also being used when UseSASL=true | ||||||
| # | # | ||||||
| @@ -223,12 +243,16 @@ UseRelayMsg=false | |||||||
| #REQUIRED | #REQUIRED | ||||||
| Server="jabber.example.com:5222" | Server="jabber.example.com:5222" | ||||||
|  |  | ||||||
|  | #Use anonymous MUC login | ||||||
|  | #OPTIONAL (default false) | ||||||
|  | Anonymous=false | ||||||
|  |  | ||||||
| #Jid | #Jid | ||||||
| #REQUIRED | #REQUIRED if Anonymous=false | ||||||
| Jid="user@example.com" | Jid="user@example.com" | ||||||
|  |  | ||||||
| #Password | #Password | ||||||
| #REQUIRED | #REQUIRED if Anonymous=false | ||||||
| Password="yourpass" | Password="yourpass" | ||||||
|  |  | ||||||
| #MUC | #MUC | ||||||
| @@ -384,6 +408,10 @@ SkipTLSVerify=true | |||||||
| ## RELOADABLE SETTINGS | ## RELOADABLE SETTINGS | ||||||
| ## Settings below can be reloaded by editing the file | ## 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. | #how to format the list of IRC nicks when displayed in mattermost. | ||||||
| #Possible options are "table" and "plain" | #Possible options are "table" and "plain" | ||||||
| #OPTIONAL (default plain) | #OPTIONAL (default plain) | ||||||
| @@ -1284,13 +1312,6 @@ HTMLDisable=false | |||||||
| # UseUserName shows the username instead of the server nickname | # UseUserName shows the username instead of the server nickname | ||||||
| UseUserName=false | 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. | #Nicks you want to ignore. | ||||||
| #Regular expressions supported | #Regular expressions supported | ||||||
| #Messages from those users will not be sent to other bridges. | #Messages from those users will not be sent to other bridges. | ||||||
| @@ -1469,6 +1490,9 @@ Password = "talkuserpass" | |||||||
| # Suffix for Guest Users | # Suffix for Guest Users | ||||||
| GuestSuffix = " (Guest)" | GuestSuffix = " (Guest)" | ||||||
|  |  | ||||||
|  | # Separate display name (Note: needs to be configured from Nextcloud Talk to work) | ||||||
|  | SeparateDisplayName=false | ||||||
|  |  | ||||||
| ################################################################### | ################################################################### | ||||||
| # Mumble | # Mumble | ||||||
| ################################################################### | ################################################################### | ||||||
| @@ -1526,10 +1550,6 @@ MessageClipped="<clipped message>" | |||||||
| #See https://vk.com/dev/bots_docs | #See https://vk.com/dev/bots_docs | ||||||
| Token="Yourtokenhere" | Token="Yourtokenhere" | ||||||
|  |  | ||||||
| #Group ID |  | ||||||
| #For example in URL https://vk.com/public168963511 group ID is 168963511 |  | ||||||
| GroupID=123456789 |  | ||||||
|  |  | ||||||
| ################################################################### | ################################################################### | ||||||
| # WhatsApp | # WhatsApp | ||||||
| ################################################################### | ################################################################### | ||||||
| @@ -1647,6 +1667,18 @@ StripNick=false | |||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowTopicChange=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 | #API | ||||||
| ################################################################### | ################################################################### | ||||||
| @@ -1692,6 +1724,7 @@ RemoteNickFormat="{NICK}" | |||||||
|  |  | ||||||
| #RemoteNickFormat defines how remote users appear on this bridge | #RemoteNickFormat defines how remote users appear on this bridge | ||||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick. | #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 "{USERID}" (case sensitive) will be replaced by the user ID. | ||||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | #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 | #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: | #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 | #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) | #OPTIONAL (default empty) | ||||||
| MediaServerUpload="https://user:pass@yourserver.com/upload" | MediaServerUpload="https://user:pass@yourserver.com/upload" | ||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| @@ -1864,7 +1897,8 @@ enable=true | |||||||
|     # ------------------------------------------------------------------------------------------------------------------------------------- |     # ------------------------------------------------------------------------------------------------------------------------------------- | ||||||
|     #    irc     |      channel       |            #general           | The # symbol is required and should be lowercase! |     #    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 |     #   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 |     #  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 |     #  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. |     #            |    "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 |     #    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" |     account="zulip.streamchat" | ||||||
|     channel="general/topic:mytopic" |     channel="general/topic:mytopic" | ||||||
|  |  | ||||||
|  |     [[gateway.inout]] | ||||||
|  |     account="harmony.chat_harmonyapp_io" | ||||||
|  |     channel="channel id goes here" | ||||||
|  |  | ||||||
|     #API example |     #API example | ||||||
|     #[[gateway.inout]] |     #[[gateway.inout]] | ||||||
|     #account="api.local" |     #account="api.local" | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import ( | |||||||
| func (m *MMClient) parseActionPost(rmsg *Message) { | func (m *MMClient) parseActionPost(rmsg *Message) { | ||||||
| 	// add post to cache, if it already exists don't relay this again. | 	// add post to cache, if it already exists don't relay this again. | ||||||
| 	// this should fix reposts | 	// 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)) | 		m.logger.Debugf("message %#v in cache, not processing again", rmsg.Raw.Data["post"].(string)) | ||||||
| 		rmsg.Text = "" | 		rmsg.Text = "" | ||||||
| 		return | 		return | ||||||
| @@ -111,7 +111,7 @@ func (m *MMClient) GetFileLinks(filenames []string) []string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (m *MMClient) GetPosts(channelId string, limit int) *model.PostList { //nolint:golint | 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 { | 	if resp.Error != nil { | ||||||
| 		return 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 | 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 { | 	if resp.Error != nil { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ RUN apk add \ | |||||||
|     go \ |     go \ | ||||||
|     git \ |     git \ | ||||||
|   && cd /go/src/matterbridge \ |   && 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 | FROM alpine | ||||||
| RUN apk --no-cache add \ | 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_ | ||||||
							
								
								
									
										1415
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_pointer.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1415
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_pointer.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										277
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_prettywriter.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_prettywriter.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,277 @@ | |||||||
|  | // 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_PRETTYWRITER_H_ | ||||||
|  | #define RAPIDJSON_PRETTYWRITER_H_ | ||||||
|  |  | ||||||
|  | #include "lottie_rapidjson_writer.h" | ||||||
|  |  | ||||||
|  | #ifdef __GNUC__ | ||||||
|  | RAPIDJSON_DIAG_PUSH | ||||||
|  | RAPIDJSON_DIAG_OFF(effc++) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(__clang__) | ||||||
|  | RAPIDJSON_DIAG_PUSH | ||||||
|  | RAPIDJSON_DIAG_OFF(c++98-compat) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | RAPIDJSON_NAMESPACE_BEGIN | ||||||
|  |  | ||||||
|  | //! Combination of PrettyWriter format flags. | ||||||
|  | /*! \see PrettyWriter::SetFormatOptions | ||||||
|  |  */ | ||||||
|  | enum PrettyFormatOptions { | ||||||
|  |     kFormatDefault = 0,         //!< Default pretty formatting. | ||||||
|  |     kFormatSingleLineArray = 1  //!< Format arrays on a single line. | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //! Writer with indentation and spacing. | ||||||
|  | /*! | ||||||
|  |     \tparam OutputStream Type of output os. | ||||||
|  |     \tparam SourceEncoding Encoding of source string. | ||||||
|  |     \tparam TargetEncoding Encoding of output stream. | ||||||
|  |     \tparam StackAllocator Type of allocator for allocating memory of stack. | ||||||
|  | */ | ||||||
|  | template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> | ||||||
|  | class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> { | ||||||
|  | public: | ||||||
|  |     typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base; | ||||||
|  |     typedef typename Base::Ch Ch; | ||||||
|  |  | ||||||
|  |     //! Constructor | ||||||
|  |     /*! \param os Output stream. | ||||||
|  |         \param allocator User supplied allocator. If it is null, it will create a private one. | ||||||
|  |         \param levelDepth Initial capacity of stack. | ||||||
|  |     */ | ||||||
|  |     explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :  | ||||||
|  |         Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :  | ||||||
|  |         Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||||
|  |     PrettyWriter(PrettyWriter&& rhs) : | ||||||
|  |         Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     //! Set custom indentation. | ||||||
|  |     /*! \param indentChar       Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). | ||||||
|  |         \param indentCharCount  Number of indent characters for each indentation level. | ||||||
|  |         \note The default indentation is 4 spaces. | ||||||
|  |     */ | ||||||
|  |     PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { | ||||||
|  |         RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); | ||||||
|  |         indentChar_ = indentChar; | ||||||
|  |         indentCharCount_ = indentCharCount; | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //! Set pretty writer formatting options. | ||||||
|  |     /*! \param options Formatting options. | ||||||
|  |     */ | ||||||
|  |     PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { | ||||||
|  |         formatOptions_ = options; | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /*! @name Implementation of Handler | ||||||
|  |         \see Handler | ||||||
|  |     */ | ||||||
|  |     //@{ | ||||||
|  |  | ||||||
|  |     bool Null()                 { PrettyPrefix(kNullType);   return Base::EndValue(Base::WriteNull()); } | ||||||
|  |     bool Bool(bool b)           { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); } | ||||||
|  |     bool Int(int i)             { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); } | ||||||
|  |     bool Uint(unsigned u)       { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); } | ||||||
|  |     bool Int64(int64_t i64)     { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); } | ||||||
|  |     bool Uint64(uint64_t u64)   { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64));  } | ||||||
|  |     bool Double(double d)       { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); } | ||||||
|  |  | ||||||
|  |     bool RawNumber(const Ch* str, SizeType length, bool copy = false) { | ||||||
|  |         RAPIDJSON_ASSERT(str != 0); | ||||||
|  |         (void)copy; | ||||||
|  |         PrettyPrefix(kNumberType); | ||||||
|  |         return Base::EndValue(Base::WriteString(str, length)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool String(const Ch* str, SizeType length, bool copy = false) { | ||||||
|  |         RAPIDJSON_ASSERT(str != 0); | ||||||
|  |         (void)copy; | ||||||
|  |         PrettyPrefix(kStringType); | ||||||
|  |         return Base::EndValue(Base::WriteString(str, length)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  |     bool String(const std::basic_string<Ch>& str) { | ||||||
|  |         return String(str.data(), SizeType(str.size())); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     bool StartObject() { | ||||||
|  |         PrettyPrefix(kObjectType); | ||||||
|  |         new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false); | ||||||
|  |         return Base::WriteStartObject(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  |     bool Key(const std::basic_string<Ch>& str) { | ||||||
|  |         return Key(str.data(), SizeType(str.size())); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 	 | ||||||
|  |     bool EndObject(SizeType memberCount = 0) { | ||||||
|  |         (void)memberCount; | ||||||
|  |         RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object | ||||||
|  |         RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object | ||||||
|  |         RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value | ||||||
|  |         | ||||||
|  |         bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; | ||||||
|  |  | ||||||
|  |         if (!empty) { | ||||||
|  |             Base::os_->Put('\n'); | ||||||
|  |             WriteIndent(); | ||||||
|  |         } | ||||||
|  |         bool ret = Base::EndValue(Base::WriteEndObject()); | ||||||
|  |         (void)ret; | ||||||
|  |         RAPIDJSON_ASSERT(ret == true); | ||||||
|  |         if (Base::level_stack_.Empty()) // end of json text | ||||||
|  |             Base::Flush(); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool StartArray() { | ||||||
|  |         PrettyPrefix(kArrayType); | ||||||
|  |         new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true); | ||||||
|  |         return Base::WriteStartArray(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool EndArray(SizeType memberCount = 0) { | ||||||
|  |         (void)memberCount; | ||||||
|  |         RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); | ||||||
|  |         RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray); | ||||||
|  |         bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; | ||||||
|  |  | ||||||
|  |         if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { | ||||||
|  |             Base::os_->Put('\n'); | ||||||
|  |             WriteIndent(); | ||||||
|  |         } | ||||||
|  |         bool ret = Base::EndValue(Base::WriteEndArray()); | ||||||
|  |         (void)ret; | ||||||
|  |         RAPIDJSON_ASSERT(ret == true); | ||||||
|  |         if (Base::level_stack_.Empty()) // end of json text | ||||||
|  |             Base::Flush(); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //@} | ||||||
|  |  | ||||||
|  |     /*! @name Convenience extensions */ | ||||||
|  |     //@{ | ||||||
|  |  | ||||||
|  |     //! Simpler but slower overload. | ||||||
|  |     bool String(const Ch* str) { return String(str, internal::StrLen(str)); } | ||||||
|  |     bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } | ||||||
|  |  | ||||||
|  |     //@} | ||||||
|  |  | ||||||
|  |     //! Write a raw JSON value. | ||||||
|  |     /*! | ||||||
|  |         For user to write a stringified JSON as a value. | ||||||
|  |  | ||||||
|  |         \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. | ||||||
|  |         \param length Length of the json. | ||||||
|  |         \param type Type of the root of json. | ||||||
|  |         \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. | ||||||
|  |     */ | ||||||
|  |     bool RawValue(const Ch* json, size_t length, Type type) { | ||||||
|  |         RAPIDJSON_ASSERT(json != 0); | ||||||
|  |         PrettyPrefix(type); | ||||||
|  |         return Base::EndValue(Base::WriteRawValue(json, length)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     void PrettyPrefix(Type type) { | ||||||
|  |         (void)type; | ||||||
|  |         if (Base::level_stack_.GetSize() != 0) { // this value is not at root | ||||||
|  |             typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>(); | ||||||
|  |  | ||||||
|  |             if (level->inArray) { | ||||||
|  |                 if (level->valueCount > 0) { | ||||||
|  |                     Base::os_->Put(','); // add comma if it is not the first element in array | ||||||
|  |                     if (formatOptions_ & kFormatSingleLineArray) | ||||||
|  |                         Base::os_->Put(' '); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (!(formatOptions_ & kFormatSingleLineArray)) { | ||||||
|  |                     Base::os_->Put('\n'); | ||||||
|  |                     WriteIndent(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else {  // in object | ||||||
|  |                 if (level->valueCount > 0) { | ||||||
|  |                     if (level->valueCount % 2 == 0) { | ||||||
|  |                         Base::os_->Put(','); | ||||||
|  |                         Base::os_->Put('\n'); | ||||||
|  |                     } | ||||||
|  |                     else { | ||||||
|  |                         Base::os_->Put(':'); | ||||||
|  |                         Base::os_->Put(' '); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                     Base::os_->Put('\n'); | ||||||
|  |  | ||||||
|  |                 if (level->valueCount % 2 == 0) | ||||||
|  |                     WriteIndent(); | ||||||
|  |             } | ||||||
|  |             if (!level->inArray && level->valueCount % 2 == 0) | ||||||
|  |                 RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name | ||||||
|  |             level->valueCount++; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             RAPIDJSON_ASSERT(!Base::hasRoot_);  // Should only has one and only one root. | ||||||
|  |             Base::hasRoot_ = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void WriteIndent()  { | ||||||
|  |         size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; | ||||||
|  |         PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Ch indentChar_; | ||||||
|  |     unsigned indentCharCount_; | ||||||
|  |     PrettyFormatOptions formatOptions_; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     // Prohibit copy constructor & assignment operator. | ||||||
|  |     PrettyWriter(const PrettyWriter&); | ||||||
|  |     PrettyWriter& operator=(const PrettyWriter&); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | RAPIDJSON_NAMESPACE_END | ||||||
|  |  | ||||||
|  | #if defined(__clang__) | ||||||
|  | RAPIDJSON_DIAG_POP | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef __GNUC__ | ||||||
|  | RAPIDJSON_DIAG_POP | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif // RAPIDJSON_RAPIDJSON_H_ | ||||||
							
								
								
									
										692
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_rapidjson.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										692
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_rapidjson.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,692 @@ | |||||||
|  | // 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_RAPIDJSON_H_ | ||||||
|  | #define RAPIDJSON_RAPIDJSON_H_ | ||||||
|  |  | ||||||
|  | /*!\file rapidjson.h | ||||||
|  |     \brief common definitions and configuration | ||||||
|  |      | ||||||
|  |     \see RAPIDJSON_CONFIG | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration | ||||||
|  |     \brief Configuration macros for library features | ||||||
|  |  | ||||||
|  |     Some RapidJSON features are configurable to adapt the library to a wide | ||||||
|  |     variety of platforms, environments and usage scenarios.  Most of the | ||||||
|  |     features can be configured in terms of overridden or predefined | ||||||
|  |     preprocessor macros at compile-time. | ||||||
|  |  | ||||||
|  |     Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. | ||||||
|  |  | ||||||
|  |     \note These macros should be given on the compiler command-line | ||||||
|  |           (where applicable)  to avoid inconsistent values when compiling | ||||||
|  |           different translation units of a single application. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <cstdlib>  // malloc(), realloc(), free(), size_t | ||||||
|  | #include <cstring>  // memset(), memcpy(), memmove(), memcmp() | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_VERSION_STRING | ||||||
|  | // | ||||||
|  | // ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN | ||||||
|  | // token stringification | ||||||
|  | #define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) | ||||||
|  | #define RAPIDJSON_DO_STRINGIFY(x) #x | ||||||
|  |  | ||||||
|  | // token concatenation | ||||||
|  | #define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) | ||||||
|  | #define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) | ||||||
|  | #define RAPIDJSON_DO_JOIN2(X, Y) X##Y | ||||||
|  | //!@endcond | ||||||
|  |  | ||||||
|  | /*! \def RAPIDJSON_MAJOR_VERSION | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief Major version of RapidJSON in integer. | ||||||
|  | */ | ||||||
|  | /*! \def RAPIDJSON_MINOR_VERSION | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief Minor version of RapidJSON in integer. | ||||||
|  | */ | ||||||
|  | /*! \def RAPIDJSON_PATCH_VERSION | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief Patch version of RapidJSON in integer. | ||||||
|  | */ | ||||||
|  | /*! \def RAPIDJSON_VERSION_STRING | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief Version of RapidJSON in "<major>.<minor>.<patch>" string format. | ||||||
|  | */ | ||||||
|  | #define RAPIDJSON_MAJOR_VERSION 1 | ||||||
|  | #define RAPIDJSON_MINOR_VERSION 1 | ||||||
|  | #define RAPIDJSON_PATCH_VERSION 0 | ||||||
|  | #define RAPIDJSON_VERSION_STRING \ | ||||||
|  |     RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_NAMESPACE_(BEGIN|END) | ||||||
|  | /*! \def RAPIDJSON_NAMESPACE | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief   provide custom rapidjson namespace | ||||||
|  |  | ||||||
|  |     In order to avoid symbol clashes and/or "One Definition Rule" errors | ||||||
|  |     between multiple inclusions of (different versions of) RapidJSON in | ||||||
|  |     a single binary, users can customize the name of the main RapidJSON | ||||||
|  |     namespace. | ||||||
|  |  | ||||||
|  |     In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE | ||||||
|  |     to a custom name (e.g. \c MyRapidJSON) is sufficient.  If multiple | ||||||
|  |     levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref | ||||||
|  |     RAPIDJSON_NAMESPACE_END need to be defined as well: | ||||||
|  |  | ||||||
|  |     \code | ||||||
|  |     // in some .cpp file | ||||||
|  |     #define RAPIDJSON_NAMESPACE my::rapidjson | ||||||
|  |     #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { | ||||||
|  |     #define RAPIDJSON_NAMESPACE_END   } } | ||||||
|  |     #include "rapidjson/..." | ||||||
|  |     \endcode | ||||||
|  |  | ||||||
|  |     \see rapidjson | ||||||
|  |  */ | ||||||
|  | /*! \def RAPIDJSON_NAMESPACE_BEGIN | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief   provide custom rapidjson namespace (opening expression) | ||||||
|  |     \see RAPIDJSON_NAMESPACE | ||||||
|  | */ | ||||||
|  | /*! \def RAPIDJSON_NAMESPACE_END | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief   provide custom rapidjson namespace (closing expression) | ||||||
|  |     \see RAPIDJSON_NAMESPACE | ||||||
|  | */ | ||||||
|  | #ifndef RAPIDJSON_NAMESPACE | ||||||
|  | #define RAPIDJSON_NAMESPACE rapidjson | ||||||
|  | #endif | ||||||
|  | #ifndef RAPIDJSON_NAMESPACE_BEGIN | ||||||
|  | #define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { | ||||||
|  | #endif | ||||||
|  | #ifndef RAPIDJSON_NAMESPACE_END | ||||||
|  | #define RAPIDJSON_NAMESPACE_END } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_HAS_STDSTRING | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_HAS_STDSTRING | ||||||
|  | #ifdef RAPIDJSON_DOXYGEN_RUNNING | ||||||
|  | #define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default | ||||||
|  | #endif | ||||||
|  | /*! \def RAPIDJSON_HAS_STDSTRING | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief Enable RapidJSON support for \c std::string | ||||||
|  |  | ||||||
|  |     By defining this preprocessor symbol to \c 1, several convenience functions for using | ||||||
|  |     \ref rapidjson::GenericValue with \c std::string are enabled, especially | ||||||
|  |     for construction and comparison. | ||||||
|  |  | ||||||
|  |     \hideinitializer | ||||||
|  | */ | ||||||
|  | #endif // !defined(RAPIDJSON_HAS_STDSTRING) | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  | #include <string> | ||||||
|  | #endif // RAPIDJSON_HAS_STDSTRING | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_NO_INT64DEFINE | ||||||
|  |  | ||||||
|  | /*! \def RAPIDJSON_NO_INT64DEFINE | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief Use external 64-bit integer types. | ||||||
|  |  | ||||||
|  |     RapidJSON requires the 64-bit integer types \c int64_t and  \c uint64_t types | ||||||
|  |     to be available at global scope. | ||||||
|  |  | ||||||
|  |     If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to | ||||||
|  |     prevent RapidJSON from defining its own types. | ||||||
|  | */ | ||||||
|  | #ifndef RAPIDJSON_NO_INT64DEFINE | ||||||
|  | //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN | ||||||
|  | #if defined(_MSC_VER) && (_MSC_VER < 1800)	// Visual Studio 2013 | ||||||
|  | #include "lottie_rapidjson_msinttypes_stdint.h" | ||||||
|  | #include "lottie_rapidjson_msinttypes_inttypes.h" | ||||||
|  | #else | ||||||
|  | // Other compilers should have this. | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <inttypes.h> | ||||||
|  | #endif | ||||||
|  | //!@endcond | ||||||
|  | #ifdef RAPIDJSON_DOXYGEN_RUNNING | ||||||
|  | #define RAPIDJSON_NO_INT64DEFINE | ||||||
|  | #endif | ||||||
|  | #endif // RAPIDJSON_NO_INT64TYPEDEF | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_FORCEINLINE | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_FORCEINLINE | ||||||
|  | //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN | ||||||
|  | #if defined(_MSC_VER) && defined(NDEBUG) | ||||||
|  | #define RAPIDJSON_FORCEINLINE __forceinline | ||||||
|  | #elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) | ||||||
|  | #define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_FORCEINLINE | ||||||
|  | #endif | ||||||
|  | //!@endcond | ||||||
|  | #endif // RAPIDJSON_FORCEINLINE | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_ENDIAN | ||||||
|  | #define RAPIDJSON_LITTLEENDIAN  0   //!< Little endian machine | ||||||
|  | #define RAPIDJSON_BIGENDIAN     1   //!< Big endian machine | ||||||
|  |  | ||||||
|  | //! Endianness of the machine. | ||||||
|  | /*! | ||||||
|  |     \def RAPIDJSON_ENDIAN | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |  | ||||||
|  |     GCC 4.6 provided macro for detecting endianness of the target machine. But other | ||||||
|  |     compilers may not have this. User can define RAPIDJSON_ENDIAN to either | ||||||
|  |     \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. | ||||||
|  |  | ||||||
|  |     Default detection implemented with reference to | ||||||
|  |     \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html | ||||||
|  |     \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp | ||||||
|  | */ | ||||||
|  | #ifndef RAPIDJSON_ENDIAN | ||||||
|  | // Detect with GCC 4.6's macro | ||||||
|  | #  ifdef __BYTE_ORDER__ | ||||||
|  | #    if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | ||||||
|  | #      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN | ||||||
|  | #    elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | ||||||
|  | #      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN | ||||||
|  | #    else | ||||||
|  | #      error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. | ||||||
|  | #    endif // __BYTE_ORDER__ | ||||||
|  | // Detect with GLIBC's endian.h | ||||||
|  | #  elif defined(__GLIBC__) | ||||||
|  | #    include <endian.h> | ||||||
|  | #    if (__BYTE_ORDER == __LITTLE_ENDIAN) | ||||||
|  | #      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN | ||||||
|  | #    elif (__BYTE_ORDER == __BIG_ENDIAN) | ||||||
|  | #      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN | ||||||
|  | #    else | ||||||
|  | #      error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. | ||||||
|  | #   endif // __GLIBC__ | ||||||
|  | // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro | ||||||
|  | #  elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) | ||||||
|  | #    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN | ||||||
|  | #  elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) | ||||||
|  | #    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN | ||||||
|  | // Detect with architecture macros | ||||||
|  | #  elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) | ||||||
|  | #    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN | ||||||
|  | #  elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) | ||||||
|  | #    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN | ||||||
|  | #  elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) | ||||||
|  | #    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN | ||||||
|  | #  elif defined(RAPIDJSON_DOXYGEN_RUNNING) | ||||||
|  | #    define RAPIDJSON_ENDIAN | ||||||
|  | #  else | ||||||
|  | #    error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.    | ||||||
|  | #  endif | ||||||
|  | #endif // RAPIDJSON_ENDIAN | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_64BIT | ||||||
|  |  | ||||||
|  | //! Whether using 64-bit architecture | ||||||
|  | #ifndef RAPIDJSON_64BIT | ||||||
|  | #if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) | ||||||
|  | #define RAPIDJSON_64BIT 1 | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_64BIT 0 | ||||||
|  | #endif | ||||||
|  | #endif // RAPIDJSON_64BIT | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_ALIGN | ||||||
|  |  | ||||||
|  | //! Data alignment of the machine. | ||||||
|  | /*! \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \param x pointer to align | ||||||
|  |  | ||||||
|  |     Some machines require strict data alignment. The default is 8 bytes. | ||||||
|  |     User can customize by defining the RAPIDJSON_ALIGN function macro. | ||||||
|  | */ | ||||||
|  | #ifndef RAPIDJSON_ALIGN | ||||||
|  | #define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u)) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_UINT64_C2 | ||||||
|  |  | ||||||
|  | //! Construct a 64-bit literal by a pair of 32-bit integer. | ||||||
|  | /*! | ||||||
|  |     64-bit literal with or without ULL suffix is prone to compiler warnings. | ||||||
|  |     UINT64_C() is C macro which cause compilation problems. | ||||||
|  |     Use this macro to define 64-bit constants by a pair of 32-bit integer. | ||||||
|  | */ | ||||||
|  | #ifndef RAPIDJSON_UINT64_C2 | ||||||
|  | #define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32)) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_48BITPOINTER_OPTIMIZATION | ||||||
|  |  | ||||||
|  | //! Use only lower 48-bit address for some pointers. | ||||||
|  | /*! | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |  | ||||||
|  |     This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. | ||||||
|  |     The higher 16-bit can be used for storing other data. | ||||||
|  |     \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. | ||||||
|  | */ | ||||||
|  | #ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION | ||||||
|  | #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) | ||||||
|  | #define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 | ||||||
|  | #endif | ||||||
|  | #endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 | ||||||
|  | #if RAPIDJSON_64BIT != 1 | ||||||
|  | #error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 | ||||||
|  | #endif | ||||||
|  | #define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x)))) | ||||||
|  | #define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) | ||||||
|  | #define RAPIDJSON_GETPOINTER(type, p) (p) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD | ||||||
|  |  | ||||||
|  | /*! \def RAPIDJSON_SIMD | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief Enable SSE2/SSE4.2/Neon optimization. | ||||||
|  |  | ||||||
|  |     RapidJSON supports optimized implementations for some parsing operations | ||||||
|  |     based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel | ||||||
|  |     or ARM compatible processors. | ||||||
|  |  | ||||||
|  |     To enable these optimizations, three different symbols can be defined; | ||||||
|  |     \code | ||||||
|  |     // Enable SSE2 optimization. | ||||||
|  |     #define RAPIDJSON_SSE2 | ||||||
|  |  | ||||||
|  |     // Enable SSE4.2 optimization. | ||||||
|  |     #define RAPIDJSON_SSE42 | ||||||
|  |     \endcode | ||||||
|  |  | ||||||
|  |     // Enable ARM Neon optimization. | ||||||
|  |     #define RAPIDJSON_NEON | ||||||
|  |     \endcode | ||||||
|  |  | ||||||
|  |     \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. | ||||||
|  |  | ||||||
|  |     If any of these symbols is defined, RapidJSON defines the macro | ||||||
|  |     \c RAPIDJSON_SIMD to indicate the availability of the optimized code. | ||||||
|  | */ | ||||||
|  | #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ | ||||||
|  |     || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) | ||||||
|  | #define RAPIDJSON_SIMD | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_NO_SIZETYPEDEFINE | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_NO_SIZETYPEDEFINE | ||||||
|  | /*! \def RAPIDJSON_NO_SIZETYPEDEFINE | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief User-provided \c SizeType definition. | ||||||
|  |  | ||||||
|  |     In order to avoid using 32-bit size types for indexing strings and arrays, | ||||||
|  |     define this preprocessor symbol and provide the type rapidjson::SizeType | ||||||
|  |     before including RapidJSON: | ||||||
|  |     \code | ||||||
|  |     #define RAPIDJSON_NO_SIZETYPEDEFINE | ||||||
|  |     namespace rapidjson { typedef ::std::size_t SizeType; } | ||||||
|  |     #include "rapidjson/..." | ||||||
|  |     \endcode | ||||||
|  |  | ||||||
|  |     \see rapidjson::SizeType | ||||||
|  | */ | ||||||
|  | #ifdef RAPIDJSON_DOXYGEN_RUNNING | ||||||
|  | #define RAPIDJSON_NO_SIZETYPEDEFINE | ||||||
|  | #endif | ||||||
|  | RAPIDJSON_NAMESPACE_BEGIN | ||||||
|  | //! Size type (for string lengths, array sizes, etc.) | ||||||
|  | /*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, | ||||||
|  |     instead of using \c size_t. Users may override the SizeType by defining | ||||||
|  |     \ref RAPIDJSON_NO_SIZETYPEDEFINE. | ||||||
|  | */ | ||||||
|  | typedef unsigned SizeType; | ||||||
|  | RAPIDJSON_NAMESPACE_END | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // always import std::size_t to rapidjson namespace | ||||||
|  | RAPIDJSON_NAMESPACE_BEGIN | ||||||
|  | using std::size_t; | ||||||
|  | RAPIDJSON_NAMESPACE_END | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_ASSERT | ||||||
|  |  | ||||||
|  | //! Assertion. | ||||||
|  | /*! \ingroup RAPIDJSON_CONFIG | ||||||
|  |     By default, rapidjson uses C \c assert() for internal assertions. | ||||||
|  |     User can override it by defining RAPIDJSON_ASSERT(x) macro. | ||||||
|  |  | ||||||
|  |     \note Parsing errors are handled and can be customized by the | ||||||
|  |           \ref RAPIDJSON_ERRORS APIs. | ||||||
|  | */ | ||||||
|  | #ifndef RAPIDJSON_ASSERT | ||||||
|  | #include <cassert> | ||||||
|  | #define RAPIDJSON_ASSERT(x) assert(x) | ||||||
|  | #endif // RAPIDJSON_ASSERT | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_STATIC_ASSERT | ||||||
|  |  | ||||||
|  | // Prefer C++11 static_assert, if available | ||||||
|  | #ifndef RAPIDJSON_STATIC_ASSERT | ||||||
|  | #if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) | ||||||
|  | #define RAPIDJSON_STATIC_ASSERT(x) \ | ||||||
|  |    static_assert(x, RAPIDJSON_STRINGIFY(x)) | ||||||
|  | #endif // C++11 | ||||||
|  | #endif // RAPIDJSON_STATIC_ASSERT | ||||||
|  |  | ||||||
|  | // Adopt C++03 implementation from boost | ||||||
|  | #ifndef RAPIDJSON_STATIC_ASSERT | ||||||
|  | #ifndef __clang__ | ||||||
|  | //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN | ||||||
|  | #endif | ||||||
|  | RAPIDJSON_NAMESPACE_BEGIN | ||||||
|  | template <bool x> struct STATIC_ASSERTION_FAILURE; | ||||||
|  | template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; }; | ||||||
|  | template <size_t x> struct StaticAssertTest {}; | ||||||
|  | RAPIDJSON_NAMESPACE_END | ||||||
|  |  | ||||||
|  | #if defined(__GNUC__) || defined(__clang__) | ||||||
|  | #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE  | ||||||
|  | #endif | ||||||
|  | #ifndef __clang__ | ||||||
|  | //!@endcond | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /*! \def RAPIDJSON_STATIC_ASSERT | ||||||
|  |     \brief (Internal) macro to check for conditions at compile-time | ||||||
|  |     \param x compile-time condition | ||||||
|  |     \hideinitializer | ||||||
|  |  */ | ||||||
|  | #define RAPIDJSON_STATIC_ASSERT(x) \ | ||||||
|  |     typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ | ||||||
|  |       sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \ | ||||||
|  |     RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE | ||||||
|  | #endif // RAPIDJSON_STATIC_ASSERT | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY | ||||||
|  |  | ||||||
|  | //! Compiler branching hint for expression with high probability to be true. | ||||||
|  | /*! | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \param x Boolean expression likely to be true. | ||||||
|  | */ | ||||||
|  | #ifndef RAPIDJSON_LIKELY | ||||||
|  | #if defined(__GNUC__) || defined(__clang__) | ||||||
|  | #define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_LIKELY(x) (x) | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | //! Compiler branching hint for expression with low probability to be true. | ||||||
|  | /*! | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \param x Boolean expression unlikely to be true. | ||||||
|  | */ | ||||||
|  | #ifndef RAPIDJSON_UNLIKELY | ||||||
|  | #if defined(__GNUC__) || defined(__clang__) | ||||||
|  | #define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_UNLIKELY(x) (x) | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Helpers | ||||||
|  |  | ||||||
|  | //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN | ||||||
|  |  | ||||||
|  | #define RAPIDJSON_MULTILINEMACRO_BEGIN do {   | ||||||
|  | #define RAPIDJSON_MULTILINEMACRO_END \ | ||||||
|  | } while((void)0, 0) | ||||||
|  |  | ||||||
|  | // adopted from Boost | ||||||
|  | #define RAPIDJSON_VERSION_CODE(x,y,z) \ | ||||||
|  |   (((x)*100000) + ((y)*100) + (z)) | ||||||
|  |  | ||||||
|  | #if defined(__has_builtin) | ||||||
|  | #define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x) | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_HAS_BUILTIN(x) 0 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF | ||||||
|  |  | ||||||
|  | #if defined(__GNUC__) | ||||||
|  | #define RAPIDJSON_GNUC \ | ||||||
|  |     RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) | ||||||
|  |  | ||||||
|  | #define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) | ||||||
|  | #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) | ||||||
|  | #define RAPIDJSON_DIAG_OFF(x) \ | ||||||
|  |     RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) | ||||||
|  |  | ||||||
|  | // push/pop support in Clang and GCC>=4.6 | ||||||
|  | #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) | ||||||
|  | #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) | ||||||
|  | #define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop) | ||||||
|  | #else // GCC >= 4.2, < 4.6 | ||||||
|  | #define RAPIDJSON_DIAG_PUSH /* ignored */ | ||||||
|  | #define RAPIDJSON_DIAG_POP /* ignored */ | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #elif defined(_MSC_VER) | ||||||
|  |  | ||||||
|  | // pragma (MSVC specific) | ||||||
|  | #define RAPIDJSON_PRAGMA(x) __pragma(x) | ||||||
|  | #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) | ||||||
|  |  | ||||||
|  | #define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) | ||||||
|  | #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) | ||||||
|  | #define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop) | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | #define RAPIDJSON_DIAG_OFF(x) /* ignored */ | ||||||
|  | #define RAPIDJSON_DIAG_PUSH   /* ignored */ | ||||||
|  | #define RAPIDJSON_DIAG_POP    /* ignored */ | ||||||
|  |  | ||||||
|  | #endif // RAPIDJSON_DIAG_* | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // C++11 features | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||||
|  | #if defined(__clang__) | ||||||
|  | #if __has_feature(cxx_rvalue_references) && \ | ||||||
|  |     (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) | ||||||
|  | #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 | ||||||
|  | #endif | ||||||
|  | #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ | ||||||
|  |       (defined(_MSC_VER) && _MSC_VER >= 1600) || \ | ||||||
|  |       (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) | ||||||
|  |  | ||||||
|  | #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 | ||||||
|  | #endif | ||||||
|  | #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT | ||||||
|  | #if defined(__clang__) | ||||||
|  | #define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) | ||||||
|  | #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ | ||||||
|  |     (defined(_MSC_VER) && _MSC_VER >= 1900) || \ | ||||||
|  |     (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) | ||||||
|  | #define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  | #if RAPIDJSON_HAS_CXX11_NOEXCEPT | ||||||
|  | #define RAPIDJSON_NOEXCEPT noexcept | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_NOEXCEPT /* noexcept */ | ||||||
|  | #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT | ||||||
|  |  | ||||||
|  | // no automatic detection, yet | ||||||
|  | #ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS | ||||||
|  | #if (defined(_MSC_VER) && _MSC_VER >= 1700) | ||||||
|  | #define RAPIDJSON_HAS_CXX11_TYPETRAITS 1 | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR | ||||||
|  | #if defined(__clang__) | ||||||
|  | #define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) | ||||||
|  | #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ | ||||||
|  |       (defined(_MSC_VER) && _MSC_VER >= 1700) || \ | ||||||
|  |       (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) | ||||||
|  | #define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 | ||||||
|  | #endif | ||||||
|  | #endif // RAPIDJSON_HAS_CXX11_RANGE_FOR | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // C++17 features | ||||||
|  |  | ||||||
|  | #if defined(__has_cpp_attribute) | ||||||
|  | # if __has_cpp_attribute(fallthrough) | ||||||
|  | #  define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] | ||||||
|  | # else | ||||||
|  | #  define RAPIDJSON_DELIBERATE_FALLTHROUGH | ||||||
|  | # endif | ||||||
|  | #else | ||||||
|  | # define RAPIDJSON_DELIBERATE_FALLTHROUGH | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | //!@endcond | ||||||
|  |  | ||||||
|  | //! Assertion (in non-throwing contexts). | ||||||
|  |  /*! \ingroup RAPIDJSON_CONFIG | ||||||
|  |     Some functions provide a \c noexcept guarantee, if the compiler supports it. | ||||||
|  |     In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to | ||||||
|  |     throw an exception.  This macro adds a separate customization point for | ||||||
|  |     such cases. | ||||||
|  |  | ||||||
|  |     Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is | ||||||
|  |     supported, and to \ref RAPIDJSON_ASSERT otherwise. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // RAPIDJSON_NOEXCEPT_ASSERT | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_NOEXCEPT_ASSERT | ||||||
|  | #ifdef RAPIDJSON_ASSERT_THROWS | ||||||
|  | #if RAPIDJSON_HAS_CXX11_NOEXCEPT | ||||||
|  | #define RAPIDJSON_NOEXCEPT_ASSERT(x) | ||||||
|  | #else | ||||||
|  | #include <cassert> | ||||||
|  | #define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) | ||||||
|  | #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) | ||||||
|  | #endif // RAPIDJSON_ASSERT_THROWS | ||||||
|  | #endif // RAPIDJSON_NOEXCEPT_ASSERT | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // malloc/realloc/free | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_MALLOC | ||||||
|  | ///! customization point for global \c malloc | ||||||
|  | #define RAPIDJSON_MALLOC(size) std::malloc(size) | ||||||
|  | #endif | ||||||
|  | #ifndef RAPIDJSON_REALLOC | ||||||
|  | ///! customization point for global \c realloc | ||||||
|  | #define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size) | ||||||
|  | #endif | ||||||
|  | #ifndef RAPIDJSON_FREE | ||||||
|  | ///! customization point for global \c free | ||||||
|  | #define RAPIDJSON_FREE(ptr) std::free(ptr) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // new/delete | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_NEW | ||||||
|  | ///! customization point for global \c new | ||||||
|  | #define RAPIDJSON_NEW(TypeName) new TypeName | ||||||
|  | #endif | ||||||
|  | #ifndef RAPIDJSON_DELETE | ||||||
|  | ///! customization point for global \c delete | ||||||
|  | #define RAPIDJSON_DELETE(x) delete x | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Type | ||||||
|  |  | ||||||
|  | /*! \namespace rapidjson | ||||||
|  |     \brief main RapidJSON namespace | ||||||
|  |     \see RAPIDJSON_NAMESPACE | ||||||
|  | */ | ||||||
|  | RAPIDJSON_NAMESPACE_BEGIN | ||||||
|  |  | ||||||
|  | //! Type of JSON value | ||||||
|  | enum Type { | ||||||
|  |     kNullType = 0,      //!< null | ||||||
|  |     kFalseType = 1,     //!< false | ||||||
|  |     kTrueType = 2,      //!< true | ||||||
|  |     kObjectType = 3,    //!< object | ||||||
|  |     kArrayType = 4,     //!< array  | ||||||
|  |     kStringType = 5,    //!< string | ||||||
|  |     kNumberType = 6     //!< number | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | RAPIDJSON_NAMESPACE_END | ||||||
|  |  | ||||||
|  | #endif // RAPIDJSON_RAPIDJSON_H_ | ||||||
							
								
								
									
										2244
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_reader.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2244
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_reader.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2496
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_schema.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2496
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_schema.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										223
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_stream.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_stream.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,223 @@ | |||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | #include "lottie_rapidjson_rapidjson.h" | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_STREAM_H_ | ||||||
|  | #define RAPIDJSON_STREAM_H_ | ||||||
|  |  | ||||||
|  | #include "lottie_rapidjson_encodings.h" | ||||||
|  |  | ||||||
|  | RAPIDJSON_NAMESPACE_BEGIN | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | //  Stream | ||||||
|  |  | ||||||
|  | /*! \class rapidjson::Stream | ||||||
|  |     \brief Concept for reading and writing characters. | ||||||
|  |  | ||||||
|  |     For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). | ||||||
|  |  | ||||||
|  |     For write-only stream, only need to implement Put() and Flush(). | ||||||
|  |  | ||||||
|  | \code | ||||||
|  | concept Stream { | ||||||
|  |     typename Ch;    //!< Character type of the stream. | ||||||
|  |  | ||||||
|  |     //! Read the current character from stream without moving the read cursor. | ||||||
|  |     Ch Peek() const; | ||||||
|  |  | ||||||
|  |     //! Read the current character from stream and moving the read cursor to next character. | ||||||
|  |     Ch Take(); | ||||||
|  |  | ||||||
|  |     //! Get the current read cursor. | ||||||
|  |     //! \return Number of characters read from start. | ||||||
|  |     size_t Tell(); | ||||||
|  |  | ||||||
|  |     //! Begin writing operation at the current read pointer. | ||||||
|  |     //! \return The begin writer pointer. | ||||||
|  |     Ch* PutBegin(); | ||||||
|  |  | ||||||
|  |     //! Write a character. | ||||||
|  |     void Put(Ch c); | ||||||
|  |  | ||||||
|  |     //! Flush the buffer. | ||||||
|  |     void Flush(); | ||||||
|  |  | ||||||
|  |     //! End the writing operation. | ||||||
|  |     //! \param begin The begin write pointer returned by PutBegin(). | ||||||
|  |     //! \return Number of characters written. | ||||||
|  |     size_t PutEnd(Ch* begin); | ||||||
|  | } | ||||||
|  | \endcode | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | //! Provides additional information for stream. | ||||||
|  | /*! | ||||||
|  |     By using traits pattern, this type provides a default configuration for stream. | ||||||
|  |     For custom stream, this type can be specialized for other configuration. | ||||||
|  |     See TEST(Reader, CustomStringStream) in readertest.cpp for example. | ||||||
|  | */ | ||||||
|  | template<typename Stream> | ||||||
|  | struct StreamTraits { | ||||||
|  |     //! Whether to make local copy of stream for optimization during parsing. | ||||||
|  |     /*! | ||||||
|  |         By default, for safety, streams do not use local copy optimization. | ||||||
|  |         Stream that can be copied fast should specialize this, like StreamTraits<StringStream>. | ||||||
|  |     */ | ||||||
|  |     enum { copyOptimization = 0 }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //! Reserve n characters for writing to a stream. | ||||||
|  | template<typename Stream> | ||||||
|  | inline void PutReserve(Stream& stream, size_t count) { | ||||||
|  |     (void)stream; | ||||||
|  |     (void)count; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //! Write character to a stream, presuming buffer is reserved. | ||||||
|  | template<typename Stream> | ||||||
|  | inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { | ||||||
|  |     stream.Put(c); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //! Put N copies of a character to a stream. | ||||||
|  | template<typename Stream, typename Ch> | ||||||
|  | inline void PutN(Stream& stream, Ch c, size_t n) { | ||||||
|  |     PutReserve(stream, n); | ||||||
|  |     for (size_t i = 0; i < n; i++) | ||||||
|  |         PutUnsafe(stream, c); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // GenericStreamWrapper | ||||||
|  |  | ||||||
|  | //! A Stream Wrapper | ||||||
|  | /*! \tThis string stream is a wrapper for any stream by just forwarding any | ||||||
|  |     \treceived message to the origin stream. | ||||||
|  |     \note implements Stream concept | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #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 | ||||||
|  |  | ||||||
|  | template <typename InputStream, typename Encoding = UTF8<> > | ||||||
|  | class GenericStreamWrapper { | ||||||
|  | public: | ||||||
|  |     typedef typename Encoding::Ch Ch; | ||||||
|  |     GenericStreamWrapper(InputStream& is): is_(is) {} | ||||||
|  |  | ||||||
|  |     Ch Peek() const { return is_.Peek(); } | ||||||
|  |     Ch Take() { return is_.Take(); } | ||||||
|  |     size_t Tell() { return is_.Tell(); } | ||||||
|  |     Ch* PutBegin() { return is_.PutBegin(); } | ||||||
|  |     void Put(Ch ch) { is_.Put(ch); } | ||||||
|  |     void Flush() { is_.Flush(); } | ||||||
|  |     size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } | ||||||
|  |  | ||||||
|  |     // wrapper for MemoryStream | ||||||
|  |     const Ch* Peek4() const { return is_.Peek4(); } | ||||||
|  |  | ||||||
|  |     // wrapper for AutoUTFInputStream | ||||||
|  |     UTFType GetType() const { return is_.GetType(); } | ||||||
|  |     bool HasBOM() const { return is_.HasBOM(); } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     InputStream& is_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #if defined(_MSC_VER) && _MSC_VER <= 1800 | ||||||
|  | RAPIDJSON_DIAG_POP | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // StringStream | ||||||
|  |  | ||||||
|  | //! Read-only string stream. | ||||||
|  | /*! \note implements Stream concept | ||||||
|  | */ | ||||||
|  | template <typename Encoding> | ||||||
|  | struct GenericStringStream { | ||||||
|  |     typedef typename Encoding::Ch Ch; | ||||||
|  |  | ||||||
|  |     GenericStringStream(const Ch *src) : src_(src), head_(src) {} | ||||||
|  |  | ||||||
|  |     Ch Peek() const { return *src_; } | ||||||
|  |     Ch Take() { return *src_++; } | ||||||
|  |     size_t Tell() const { return static_cast<size_t>(src_ - head_); } | ||||||
|  |  | ||||||
|  |     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; } | ||||||
|  |  | ||||||
|  |     const Ch* src_;     //!< Current read position. | ||||||
|  |     const Ch* head_;    //!< Original head of the string. | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename Encoding> | ||||||
|  | struct StreamTraits<GenericStringStream<Encoding> > { | ||||||
|  |     enum { copyOptimization = 1 }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //! String stream with UTF8 encoding. | ||||||
|  | typedef GenericStringStream<UTF8<> > StringStream; | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // InsituStringStream | ||||||
|  |  | ||||||
|  | //! A read-write string stream. | ||||||
|  | /*! This string stream is particularly designed for in-situ parsing. | ||||||
|  |     \note implements Stream concept | ||||||
|  | */ | ||||||
|  | template <typename Encoding> | ||||||
|  | struct GenericInsituStringStream { | ||||||
|  |     typedef typename Encoding::Ch Ch; | ||||||
|  |  | ||||||
|  |     GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} | ||||||
|  |  | ||||||
|  |     // Read | ||||||
|  |     Ch Peek() { return *src_; } | ||||||
|  |     Ch Take() { return *src_++; } | ||||||
|  |     size_t Tell() { return static_cast<size_t>(src_ - head_); } | ||||||
|  |  | ||||||
|  |     // Write | ||||||
|  |     void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } | ||||||
|  |  | ||||||
|  |     Ch* PutBegin() { return dst_ = src_; } | ||||||
|  |     size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); } | ||||||
|  |     void Flush() {} | ||||||
|  |  | ||||||
|  |     Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } | ||||||
|  |     void Pop(size_t count) { dst_ -= count; } | ||||||
|  |  | ||||||
|  |     Ch* src_; | ||||||
|  |     Ch* dst_; | ||||||
|  |     Ch* head_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename Encoding> | ||||||
|  | struct StreamTraits<GenericInsituStringStream<Encoding> > { | ||||||
|  |     enum { copyOptimization = 1 }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //! Insitu string stream with UTF8 encoding. | ||||||
|  | typedef GenericInsituStringStream<UTF8<> > InsituStringStream; | ||||||
|  |  | ||||||
|  | RAPIDJSON_NAMESPACE_END | ||||||
|  |  | ||||||
|  | #endif // RAPIDJSON_STREAM_H_ | ||||||
							
								
								
									
										121
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_stringbuffer.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_stringbuffer.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | |||||||
|  | // 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_STRINGBUFFER_H_ | ||||||
|  | #define RAPIDJSON_STRINGBUFFER_H_ | ||||||
|  |  | ||||||
|  | #include "lottie_rapidjson_stream.h" | ||||||
|  | #include "lottie_rapidjson_internal_stack.h" | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||||
|  | #include <utility> // std::move | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "lottie_rapidjson_internal_stack.h" | ||||||
|  |  | ||||||
|  | #if defined(__clang__) | ||||||
|  | RAPIDJSON_DIAG_PUSH | ||||||
|  | RAPIDJSON_DIAG_OFF(c++98-compat) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | RAPIDJSON_NAMESPACE_BEGIN | ||||||
|  |  | ||||||
|  | //! Represents an in-memory output stream. | ||||||
|  | /*! | ||||||
|  |     \tparam Encoding Encoding of the stream. | ||||||
|  |     \tparam Allocator type for allocating memory buffer. | ||||||
|  |     \note implements Stream concept | ||||||
|  | */ | ||||||
|  | template <typename Encoding, typename Allocator = CrtAllocator> | ||||||
|  | class GenericStringBuffer { | ||||||
|  | public: | ||||||
|  |     typedef typename Encoding::Ch Ch; | ||||||
|  |  | ||||||
|  |     GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||||
|  |     GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} | ||||||
|  |     GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { | ||||||
|  |         if (&rhs != this) | ||||||
|  |             stack_ = std::move(rhs.stack_); | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     void Put(Ch c) { *stack_.template Push<Ch>() = c; } | ||||||
|  |     void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; } | ||||||
|  |     void Flush() {} | ||||||
|  |  | ||||||
|  |     void Clear() { stack_.Clear(); } | ||||||
|  |     void ShrinkToFit() { | ||||||
|  |         // Push and pop a null terminator. This is safe. | ||||||
|  |         *stack_.template Push<Ch>() = '\0'; | ||||||
|  |         stack_.ShrinkToFit(); | ||||||
|  |         stack_.template Pop<Ch>(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Reserve(size_t count) { stack_.template Reserve<Ch>(count); } | ||||||
|  |     Ch* Push(size_t count) { return stack_.template Push<Ch>(count); } | ||||||
|  |     Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); } | ||||||
|  |     void Pop(size_t count) { stack_.template Pop<Ch>(count); } | ||||||
|  |  | ||||||
|  |     const Ch* GetString() const { | ||||||
|  |         // Push and pop a null terminator. This is safe. | ||||||
|  |         *stack_.template Push<Ch>() = '\0'; | ||||||
|  |         stack_.template Pop<Ch>(1); | ||||||
|  |  | ||||||
|  |         return stack_.template Bottom<Ch>(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //! Get the size of string in bytes in the string buffer. | ||||||
|  |     size_t GetSize() const { return stack_.GetSize(); } | ||||||
|  |  | ||||||
|  |     //! Get the length of string in Ch in the string buffer. | ||||||
|  |     size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } | ||||||
|  |  | ||||||
|  |     static const size_t kDefaultCapacity = 256; | ||||||
|  |     mutable internal::Stack<Allocator> stack_; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     // Prohibit copy constructor & assignment operator. | ||||||
|  |     GenericStringBuffer(const GenericStringBuffer&); | ||||||
|  |     GenericStringBuffer& operator=(const GenericStringBuffer&); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //! String buffer with UTF8 encoding | ||||||
|  | typedef GenericStringBuffer<UTF8<> > StringBuffer; | ||||||
|  |  | ||||||
|  | template<typename Encoding, typename Allocator> | ||||||
|  | inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) { | ||||||
|  |     stream.Reserve(count); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename Encoding, typename Allocator> | ||||||
|  | inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) { | ||||||
|  |     stream.PutUnsafe(c); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //! Implement specialized version of PutN() with memset() for better performance. | ||||||
|  | template<> | ||||||
|  | inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) { | ||||||
|  |     std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | RAPIDJSON_NAMESPACE_END | ||||||
|  |  | ||||||
|  | #if defined(__clang__) | ||||||
|  | RAPIDJSON_DIAG_POP | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif // RAPIDJSON_STRINGBUFFER_H_ | ||||||
							
								
								
									
										710
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_writer.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										710
									
								
								vendor/github.com/Benau/go_rlottie/lottie_rapidjson_writer.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,710 @@ | |||||||
|  | // 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_WRITER_H_ | ||||||
|  | #define RAPIDJSON_WRITER_H_ | ||||||
|  |  | ||||||
|  | #include "lottie_rapidjson_stream.h" | ||||||
|  | #include "lottie_rapidjson_internal_clzll.h" | ||||||
|  | #include "lottie_rapidjson_internal_meta.h" | ||||||
|  | #include "lottie_rapidjson_internal_stack.h" | ||||||
|  | #include "lottie_rapidjson_internal_strfunc.h" | ||||||
|  | #include "lottie_rapidjson_internal_dtoa.h" | ||||||
|  | #include "lottie_rapidjson_internal_itoa.h" | ||||||
|  | #include "lottie_rapidjson_stringbuffer.h" | ||||||
|  | #include <new>      // placement new | ||||||
|  |  | ||||||
|  | #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) | ||||||
|  | #include <intrin.h> | ||||||
|  | #pragma intrinsic(_BitScanForward) | ||||||
|  | #endif | ||||||
|  | #ifdef RAPIDJSON_SSE42 | ||||||
|  | #include <nmmintrin.h> | ||||||
|  | #elif defined(RAPIDJSON_SSE2) | ||||||
|  | #include <emmintrin.h> | ||||||
|  | #elif defined(RAPIDJSON_NEON) | ||||||
|  | #include <arm_neon.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef __clang__ | ||||||
|  | RAPIDJSON_DIAG_PUSH | ||||||
|  | RAPIDJSON_DIAG_OFF(padded) | ||||||
|  | RAPIDJSON_DIAG_OFF(unreachable-code) | ||||||
|  | RAPIDJSON_DIAG_OFF(c++98-compat) | ||||||
|  | #elif defined(_MSC_VER) | ||||||
|  | RAPIDJSON_DIAG_PUSH | ||||||
|  | RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | RAPIDJSON_NAMESPACE_BEGIN | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // WriteFlag | ||||||
|  |  | ||||||
|  | /*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS  | ||||||
|  |     \ingroup RAPIDJSON_CONFIG | ||||||
|  |     \brief User-defined kWriteDefaultFlags definition. | ||||||
|  |  | ||||||
|  |     User can define this as any \c WriteFlag combinations. | ||||||
|  | */ | ||||||
|  | #ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS | ||||||
|  | #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | //! Combination of writeFlags | ||||||
|  | enum WriteFlag { | ||||||
|  |     kWriteNoFlags = 0,              //!< No flags are set. | ||||||
|  |     kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. | ||||||
|  |     kWriteNanAndInfFlag = 2,        //!< Allow writing of Infinity, -Infinity and NaN. | ||||||
|  |     kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS  //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //! JSON writer | ||||||
|  | /*! Writer implements the concept Handler. | ||||||
|  |     It generates JSON text by events to an output os. | ||||||
|  |  | ||||||
|  |     User may programmatically calls the functions of a writer to generate JSON text. | ||||||
|  |  | ||||||
|  |     On the other side, a writer can also be passed to objects that generates events,  | ||||||
|  |  | ||||||
|  |     for example Reader::Parse() and Document::Accept(). | ||||||
|  |  | ||||||
|  |     \tparam OutputStream Type of output stream. | ||||||
|  |     \tparam SourceEncoding Encoding of source string. | ||||||
|  |     \tparam TargetEncoding Encoding of output stream. | ||||||
|  |     \tparam StackAllocator Type of allocator for allocating memory of stack. | ||||||
|  |     \note implements Handler concept | ||||||
|  | */ | ||||||
|  | template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> | ||||||
|  | class Writer { | ||||||
|  | public: | ||||||
|  |     typedef typename SourceEncoding::Ch Ch; | ||||||
|  |  | ||||||
|  |     static const int kDefaultMaxDecimalPlaces = 324; | ||||||
|  |  | ||||||
|  |     //! Constructor | ||||||
|  |     /*! \param os Output stream. | ||||||
|  |         \param stackAllocator User supplied allocator. If it is null, it will create a private one. | ||||||
|  |         \param levelDepth Initial capacity of stack. | ||||||
|  |     */ | ||||||
|  |     explicit | ||||||
|  |     Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :  | ||||||
|  |         os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} | ||||||
|  |  | ||||||
|  |     explicit | ||||||
|  |     Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : | ||||||
|  |         os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||||
|  |     Writer(Writer&& rhs) : | ||||||
|  |         os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) { | ||||||
|  |         rhs.os_ = 0; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     //! Reset the writer with a new stream. | ||||||
|  |     /*! | ||||||
|  |         This function reset the writer with a new stream and default settings, | ||||||
|  |         in order to make a Writer object reusable for output multiple JSONs. | ||||||
|  |  | ||||||
|  |         \param os New output stream. | ||||||
|  |         \code | ||||||
|  |         Writer<OutputStream> writer(os1); | ||||||
|  |         writer.StartObject(); | ||||||
|  |         // ... | ||||||
|  |         writer.EndObject(); | ||||||
|  |  | ||||||
|  |         writer.Reset(os2); | ||||||
|  |         writer.StartObject(); | ||||||
|  |         // ... | ||||||
|  |         writer.EndObject(); | ||||||
|  |         \endcode | ||||||
|  |     */ | ||||||
|  |     void Reset(OutputStream& os) { | ||||||
|  |         os_ = &os; | ||||||
|  |         hasRoot_ = false; | ||||||
|  |         level_stack_.Clear(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //! Checks whether the output is a complete JSON. | ||||||
|  |     /*! | ||||||
|  |         A complete JSON has a complete root object or array. | ||||||
|  |     */ | ||||||
|  |     bool IsComplete() const { | ||||||
|  |         return hasRoot_ && level_stack_.Empty(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int GetMaxDecimalPlaces() const { | ||||||
|  |         return maxDecimalPlaces_; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //! Sets the maximum number of decimal places for double output. | ||||||
|  |     /*! | ||||||
|  |         This setting truncates the output with specified number of decimal places. | ||||||
|  |  | ||||||
|  |         For example,  | ||||||
|  |  | ||||||
|  |         \code | ||||||
|  |         writer.SetMaxDecimalPlaces(3); | ||||||
|  |         writer.StartArray(); | ||||||
|  |         writer.Double(0.12345);                 // "0.123" | ||||||
|  |         writer.Double(0.0001);                  // "0.0" | ||||||
|  |         writer.Double(1.234567890123456e30);    // "1.234567890123456e30" (do not truncate significand for positive exponent) | ||||||
|  |         writer.Double(1.23e-4);                 // "0.0"                  (do truncate significand for negative exponent) | ||||||
|  |         writer.EndArray(); | ||||||
|  |         \endcode | ||||||
|  |  | ||||||
|  |         The default setting does not truncate any decimal places. You can restore to this setting by calling | ||||||
|  |         \code | ||||||
|  |         writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); | ||||||
|  |         \endcode | ||||||
|  |     */ | ||||||
|  |     void SetMaxDecimalPlaces(int maxDecimalPlaces) { | ||||||
|  |         maxDecimalPlaces_ = maxDecimalPlaces; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /*!@name Implementation of Handler | ||||||
|  |         \see Handler | ||||||
|  |     */ | ||||||
|  |     //@{ | ||||||
|  |  | ||||||
|  |     bool Null()                 { Prefix(kNullType);   return EndValue(WriteNull()); } | ||||||
|  |     bool Bool(bool b)           { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } | ||||||
|  |     bool Int(int i)             { Prefix(kNumberType); return EndValue(WriteInt(i)); } | ||||||
|  |     bool Uint(unsigned u)       { Prefix(kNumberType); return EndValue(WriteUint(u)); } | ||||||
|  |     bool Int64(int64_t i64)     { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } | ||||||
|  |     bool Uint64(uint64_t u64)   { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } | ||||||
|  |  | ||||||
|  |     //! Writes the given \c double value to the stream | ||||||
|  |     /*! | ||||||
|  |         \param d The value to be written. | ||||||
|  |         \return Whether it is succeed. | ||||||
|  |     */ | ||||||
|  |     bool Double(double d)       { Prefix(kNumberType); return EndValue(WriteDouble(d)); } | ||||||
|  |  | ||||||
|  |     bool RawNumber(const Ch* str, SizeType length, bool copy = false) { | ||||||
|  |         RAPIDJSON_ASSERT(str != 0); | ||||||
|  |         (void)copy; | ||||||
|  |         Prefix(kNumberType); | ||||||
|  |         return EndValue(WriteString(str, length)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool String(const Ch* str, SizeType length, bool copy = false) { | ||||||
|  |         RAPIDJSON_ASSERT(str != 0); | ||||||
|  |         (void)copy; | ||||||
|  |         Prefix(kStringType); | ||||||
|  |         return EndValue(WriteString(str, length)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  |     bool String(const std::basic_string<Ch>& str) { | ||||||
|  |         return String(str.data(), SizeType(str.size())); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     bool StartObject() { | ||||||
|  |         Prefix(kObjectType); | ||||||
|  |         new (level_stack_.template Push<Level>()) Level(false); | ||||||
|  |         return WriteStartObject(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  |     bool Key(const std::basic_string<Ch>& str) | ||||||
|  |     { | ||||||
|  |       return Key(str.data(), SizeType(str.size())); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     bool EndObject(SizeType memberCount = 0) { | ||||||
|  |         (void)memberCount; | ||||||
|  |         RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object | ||||||
|  |         RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object | ||||||
|  |         RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value | ||||||
|  |         level_stack_.template Pop<Level>(1); | ||||||
|  |         return EndValue(WriteEndObject()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool StartArray() { | ||||||
|  |         Prefix(kArrayType); | ||||||
|  |         new (level_stack_.template Push<Level>()) Level(true); | ||||||
|  |         return WriteStartArray(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool EndArray(SizeType elementCount = 0) { | ||||||
|  |         (void)elementCount; | ||||||
|  |         RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); | ||||||
|  |         RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray); | ||||||
|  |         level_stack_.template Pop<Level>(1); | ||||||
|  |         return EndValue(WriteEndArray()); | ||||||
|  |     } | ||||||
|  |     //@} | ||||||
|  |  | ||||||
|  |     /*! @name Convenience extensions */ | ||||||
|  |     //@{ | ||||||
|  |  | ||||||
|  |     //! Simpler but slower overload. | ||||||
|  |     bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } | ||||||
|  |     bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } | ||||||
|  |      | ||||||
|  |     //@} | ||||||
|  |  | ||||||
|  |     //! Write a raw JSON value. | ||||||
|  |     /*! | ||||||
|  |         For user to write a stringified JSON as a value. | ||||||
|  |  | ||||||
|  |         \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. | ||||||
|  |         \param length Length of the json. | ||||||
|  |         \param type Type of the root of json. | ||||||
|  |     */ | ||||||
|  |     bool RawValue(const Ch* json, size_t length, Type type) { | ||||||
|  |         RAPIDJSON_ASSERT(json != 0); | ||||||
|  |         Prefix(type); | ||||||
|  |         return EndValue(WriteRawValue(json, length)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //! Flush the output stream. | ||||||
|  |     /*! | ||||||
|  |         Allows the user to flush the output stream immediately. | ||||||
|  |      */ | ||||||
|  |     void Flush() { | ||||||
|  |         os_->Flush(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static const size_t kDefaultLevelDepth = 32; | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     //! Information for each nested level | ||||||
|  |     struct Level { | ||||||
|  |         Level(bool inArray_) : valueCount(0), inArray(inArray_) {} | ||||||
|  |         size_t valueCount;  //!< number of values in this level | ||||||
|  |         bool inArray;       //!< true if in array, otherwise in object | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     bool WriteNull()  { | ||||||
|  |         PutReserve(*os_, 4); | ||||||
|  |         PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool WriteBool(bool b)  { | ||||||
|  |         if (b) { | ||||||
|  |             PutReserve(*os_, 4); | ||||||
|  |             PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             PutReserve(*os_, 5); | ||||||
|  |             PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool WriteInt(int i) { | ||||||
|  |         char buffer[11]; | ||||||
|  |         const char* end = internal::i32toa(i, buffer); | ||||||
|  |         PutReserve(*os_, static_cast<size_t>(end - buffer)); | ||||||
|  |         for (const char* p = buffer; p != end; ++p) | ||||||
|  |             PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p)); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool WriteUint(unsigned u) { | ||||||
|  |         char buffer[10]; | ||||||
|  |         const char* end = internal::u32toa(u, buffer); | ||||||
|  |         PutReserve(*os_, static_cast<size_t>(end - buffer)); | ||||||
|  |         for (const char* p = buffer; p != end; ++p) | ||||||
|  |             PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p)); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool WriteInt64(int64_t i64) { | ||||||
|  |         char buffer[21]; | ||||||
|  |         const char* end = internal::i64toa(i64, buffer); | ||||||
|  |         PutReserve(*os_, static_cast<size_t>(end - buffer)); | ||||||
|  |         for (const char* p = buffer; p != end; ++p) | ||||||
|  |             PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p)); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool WriteUint64(uint64_t u64) { | ||||||
|  |         char buffer[20]; | ||||||
|  |         char* end = internal::u64toa(u64, buffer); | ||||||
|  |         PutReserve(*os_, static_cast<size_t>(end - buffer)); | ||||||
|  |         for (char* p = buffer; p != end; ++p) | ||||||
|  |             PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p)); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool WriteDouble(double d) { | ||||||
|  |         if (internal::Double(d).IsNanOrInf()) { | ||||||
|  |             if (!(writeFlags & kWriteNanAndInfFlag)) | ||||||
|  |                 return false; | ||||||
|  |             if (internal::Double(d).IsNan()) { | ||||||
|  |                 PutReserve(*os_, 3); | ||||||
|  |                 PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             if (internal::Double(d).Sign()) { | ||||||
|  |                 PutReserve(*os_, 9); | ||||||
|  |                 PutUnsafe(*os_, '-'); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |                 PutReserve(*os_, 8); | ||||||
|  |             PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); | ||||||
|  |             PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         char buffer[25]; | ||||||
|  |         char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); | ||||||
|  |         PutReserve(*os_, static_cast<size_t>(end - buffer)); | ||||||
|  |         for (char* p = buffer; p != end; ++p) | ||||||
|  |             PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p)); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool WriteString(const Ch* str, SizeType length)  { | ||||||
|  |         static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; | ||||||
|  |         static const char escape[256] = { | ||||||
|  | #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | ||||||
|  |             //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F | ||||||
|  |             'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 | ||||||
|  |             'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 | ||||||
|  |               0,   0, '"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20 | ||||||
|  |             Z16, Z16,                                                                       // 30~4F | ||||||
|  |               0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\',   0,   0,   0, // 50 | ||||||
|  |             Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                                // 60~FF | ||||||
|  | #undef Z16 | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         if (TargetEncoding::supportUnicode) | ||||||
|  |             PutReserve(*os_, 2 + length * 6); // "\uxxxx..." | ||||||
|  |         else | ||||||
|  |             PutReserve(*os_, 2 + length * 12);  // "\uxxxx\uyyyy..." | ||||||
|  |  | ||||||
|  |         PutUnsafe(*os_, '\"'); | ||||||
|  |         GenericStringStream<SourceEncoding> is(str); | ||||||
|  |         while (ScanWriteUnescapedString(is, length)) { | ||||||
|  |             const Ch c = is.Peek(); | ||||||
|  |             if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) { | ||||||
|  |                 // Unicode escaping | ||||||
|  |                 unsigned codepoint; | ||||||
|  |                 if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) | ||||||
|  |                     return false; | ||||||
|  |                 PutUnsafe(*os_, '\\'); | ||||||
|  |                 PutUnsafe(*os_, 'u'); | ||||||
|  |                 if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(codepoint >>  8) & 15]); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(codepoint >>  4) & 15]); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(codepoint      ) & 15]); | ||||||
|  |                 } | ||||||
|  |                 else { | ||||||
|  |                     RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); | ||||||
|  |                     // Surrogate pair | ||||||
|  |                     unsigned s = codepoint - 0x010000; | ||||||
|  |                     unsigned lead = (s >> 10) + 0xD800; | ||||||
|  |                     unsigned trail = (s & 0x3FF) + 0xDC00; | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(lead >>  8) & 15]); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(lead >>  4) & 15]); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(lead      ) & 15]); | ||||||
|  |                     PutUnsafe(*os_, '\\'); | ||||||
|  |                     PutUnsafe(*os_, 'u'); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(trail >>  8) & 15]); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(trail >>  4) & 15]); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[(trail      ) & 15]);                     | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)]))  { | ||||||
|  |                 is.Take(); | ||||||
|  |                 PutUnsafe(*os_, '\\'); | ||||||
|  |                 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)])); | ||||||
|  |                 if (escape[static_cast<unsigned char>(c)] == 'u') { | ||||||
|  |                     PutUnsafe(*os_, '0'); | ||||||
|  |                     PutUnsafe(*os_, '0'); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]); | ||||||
|  |                     PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?  | ||||||
|  |                 Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) : | ||||||
|  |                 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_)))) | ||||||
|  |                 return false; | ||||||
|  |         } | ||||||
|  |         PutUnsafe(*os_, '\"'); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) { | ||||||
|  |         return RAPIDJSON_LIKELY(is.Tell() < length); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool WriteStartObject() { os_->Put('{'); return true; } | ||||||
|  |     bool WriteEndObject()   { os_->Put('}'); return true; } | ||||||
|  |     bool WriteStartArray()  { os_->Put('['); return true; } | ||||||
|  |     bool WriteEndArray()    { os_->Put(']'); return true; } | ||||||
|  |  | ||||||
|  |     bool WriteRawValue(const Ch* json, size_t length) { | ||||||
|  |         PutReserve(*os_, length); | ||||||
|  |         GenericStringStream<SourceEncoding> is(json); | ||||||
|  |         while (RAPIDJSON_LIKELY(is.Tell() < length)) { | ||||||
|  |             RAPIDJSON_ASSERT(is.Peek() != '\0'); | ||||||
|  |             if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?  | ||||||
|  |                 Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) : | ||||||
|  |                 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_)))) | ||||||
|  |                 return false; | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Prefix(Type type) { | ||||||
|  |         (void)type; | ||||||
|  |         if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root | ||||||
|  |             Level* level = level_stack_.template Top<Level>(); | ||||||
|  |             if (level->valueCount > 0) { | ||||||
|  |                 if (level->inArray)  | ||||||
|  |                     os_->Put(','); // add comma if it is not the first element in array | ||||||
|  |                 else  // in object | ||||||
|  |                     os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); | ||||||
|  |             } | ||||||
|  |             if (!level->inArray && level->valueCount % 2 == 0) | ||||||
|  |                 RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name | ||||||
|  |             level->valueCount++; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root. | ||||||
|  |             hasRoot_ = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Flush the value if it is the top level one. | ||||||
|  |     bool EndValue(bool ret) { | ||||||
|  |         if (RAPIDJSON_UNLIKELY(level_stack_.Empty()))   // end of json text | ||||||
|  |             Flush(); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     OutputStream* os_; | ||||||
|  |     internal::Stack<StackAllocator> level_stack_; | ||||||
|  |     int maxDecimalPlaces_; | ||||||
|  |     bool hasRoot_; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     // Prohibit copy constructor & assignment operator. | ||||||
|  |     Writer(const Writer&); | ||||||
|  |     Writer& operator=(const Writer&); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Full specialization for StringStream to prevent memory copying | ||||||
|  |  | ||||||
|  | template<> | ||||||
|  | inline bool Writer<StringBuffer>::WriteInt(int i) { | ||||||
|  |     char *buffer = os_->Push(11); | ||||||
|  |     const char* end = internal::i32toa(i, buffer); | ||||||
|  |     os_->Pop(static_cast<size_t>(11 - (end - buffer))); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<> | ||||||
|  | inline bool Writer<StringBuffer>::WriteUint(unsigned u) { | ||||||
|  |     char *buffer = os_->Push(10); | ||||||
|  |     const char* end = internal::u32toa(u, buffer); | ||||||
|  |     os_->Pop(static_cast<size_t>(10 - (end - buffer))); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<> | ||||||
|  | inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) { | ||||||
|  |     char *buffer = os_->Push(21); | ||||||
|  |     const char* end = internal::i64toa(i64, buffer); | ||||||
|  |     os_->Pop(static_cast<size_t>(21 - (end - buffer))); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<> | ||||||
|  | inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) { | ||||||
|  |     char *buffer = os_->Push(20); | ||||||
|  |     const char* end = internal::u64toa(u, buffer); | ||||||
|  |     os_->Pop(static_cast<size_t>(20 - (end - buffer))); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<> | ||||||
|  | inline bool Writer<StringBuffer>::WriteDouble(double d) { | ||||||
|  |     if (internal::Double(d).IsNanOrInf()) { | ||||||
|  |         // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). | ||||||
|  |         if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) | ||||||
|  |             return false; | ||||||
|  |         if (internal::Double(d).IsNan()) { | ||||||
|  |             PutReserve(*os_, 3); | ||||||
|  |             PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (internal::Double(d).Sign()) { | ||||||
|  |             PutReserve(*os_, 9); | ||||||
|  |             PutUnsafe(*os_, '-'); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |             PutReserve(*os_, 8); | ||||||
|  |         PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); | ||||||
|  |         PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     char *buffer = os_->Push(25); | ||||||
|  |     char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); | ||||||
|  |     os_->Pop(static_cast<size_t>(25 - (end - buffer))); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) | ||||||
|  | template<> | ||||||
|  | inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) { | ||||||
|  |     if (length < 16) | ||||||
|  |         return RAPIDJSON_LIKELY(is.Tell() < length); | ||||||
|  |  | ||||||
|  |     if (!RAPIDJSON_LIKELY(is.Tell() < length)) | ||||||
|  |         return false; | ||||||
|  |  | ||||||
|  |     const char* p = is.src_; | ||||||
|  |     const char* end = is.head_ + length; | ||||||
|  |     const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); | ||||||
|  |     const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15)); | ||||||
|  |     if (nextAligned > end) | ||||||
|  |         return true; | ||||||
|  |  | ||||||
|  |     while (p != nextAligned) | ||||||
|  |         if (*p < 0x20 || *p == '\"' || *p == '\\') { | ||||||
|  |             is.src_ = p; | ||||||
|  |             return RAPIDJSON_LIKELY(is.Tell() < length); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |             os_->PutUnsafe(*p++); | ||||||
|  |  | ||||||
|  |     // The rest of string using SIMD | ||||||
|  |     static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; | ||||||
|  |     static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; | ||||||
|  |     static const char space[16]  = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; | ||||||
|  |     const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0])); | ||||||
|  |     const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0])); | ||||||
|  |     const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0])); | ||||||
|  |  | ||||||
|  |     for (; p != endAligned; p += 16) { | ||||||
|  |         const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p)); | ||||||
|  |         const __m128i t1 = _mm_cmpeq_epi8(s, dq); | ||||||
|  |         const __m128i t2 = _mm_cmpeq_epi8(s, bs); | ||||||
|  |         const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F | ||||||
|  |         const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); | ||||||
|  |         unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x)); | ||||||
|  |         if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped | ||||||
|  |             SizeType len; | ||||||
|  | #ifdef _MSC_VER         // Find the index of first escaped | ||||||
|  |             unsigned long offset; | ||||||
|  |             _BitScanForward(&offset, r); | ||||||
|  |             len = offset; | ||||||
|  | #else | ||||||
|  |             len = static_cast<SizeType>(__builtin_ffs(r) - 1); | ||||||
|  | #endif | ||||||
|  |             char* q = reinterpret_cast<char*>(os_->PushUnsafe(len)); | ||||||
|  |             for (size_t i = 0; i < len; i++) | ||||||
|  |                 q[i] = p[i]; | ||||||
|  |  | ||||||
|  |             p += len; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     is.src_ = p; | ||||||
|  |     return RAPIDJSON_LIKELY(is.Tell() < length); | ||||||
|  | } | ||||||
|  | #elif defined(RAPIDJSON_NEON) | ||||||
|  | template<> | ||||||
|  | inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) { | ||||||
|  |     if (length < 16) | ||||||
|  |         return RAPIDJSON_LIKELY(is.Tell() < length); | ||||||
|  |  | ||||||
|  |     if (!RAPIDJSON_LIKELY(is.Tell() < length)) | ||||||
|  |         return false; | ||||||
|  |  | ||||||
|  |     const char* p = is.src_; | ||||||
|  |     const char* end = is.head_ + length; | ||||||
|  |     const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); | ||||||
|  |     const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15)); | ||||||
|  |     if (nextAligned > end) | ||||||
|  |         return true; | ||||||
|  |  | ||||||
|  |     while (p != nextAligned) | ||||||
|  |         if (*p < 0x20 || *p == '\"' || *p == '\\') { | ||||||
|  |             is.src_ = p; | ||||||
|  |             return RAPIDJSON_LIKELY(is.Tell() < length); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |             os_->PutUnsafe(*p++); | ||||||
|  |  | ||||||
|  |     // The rest of string using SIMD | ||||||
|  |     const uint8x16_t s0 = vmovq_n_u8('"'); | ||||||
|  |     const uint8x16_t s1 = vmovq_n_u8('\\'); | ||||||
|  |     const uint8x16_t s2 = vmovq_n_u8('\b'); | ||||||
|  |     const uint8x16_t s3 = vmovq_n_u8(32); | ||||||
|  |  | ||||||
|  |     for (; p != endAligned; p += 16) { | ||||||
|  |         const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p)); | ||||||
|  |         uint8x16_t x = vceqq_u8(s, s0); | ||||||
|  |         x = vorrq_u8(x, vceqq_u8(s, s1)); | ||||||
|  |         x = vorrq_u8(x, vceqq_u8(s, s2)); | ||||||
|  |         x = vorrq_u8(x, vcltq_u8(s, s3)); | ||||||
|  |  | ||||||
|  |         x = vrev64q_u8(x);                     // Rev in 64 | ||||||
|  |         uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0);   // extract | ||||||
|  |         uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1);  // extract | ||||||
|  |  | ||||||
|  |         SizeType len = 0; | ||||||
|  |         bool escaped = false; | ||||||
|  |         if (low == 0) { | ||||||
|  |             if (high != 0) { | ||||||
|  |                 uint32_t lz = internal::clzll(high); | ||||||
|  |                 len = 8 + (lz >> 3); | ||||||
|  |                 escaped = true; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             uint32_t lz = internal::clzll(low); | ||||||
|  |             len = lz >> 3; | ||||||
|  |             escaped = true; | ||||||
|  |         } | ||||||
|  |         if (RAPIDJSON_UNLIKELY(escaped)) {   // some of characters is escaped | ||||||
|  |             char* q = reinterpret_cast<char*>(os_->PushUnsafe(len)); | ||||||
|  |             for (size_t i = 0; i < len; i++) | ||||||
|  |                 q[i] = p[i]; | ||||||
|  |  | ||||||
|  |             p += len; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     is.src_ = p; | ||||||
|  |     return RAPIDJSON_LIKELY(is.Tell() < length); | ||||||
|  | } | ||||||
|  | #endif // RAPIDJSON_NEON | ||||||
|  |  | ||||||
|  | RAPIDJSON_NAMESPACE_END | ||||||
|  |  | ||||||
|  | #if defined(_MSC_VER) || defined(__clang__) | ||||||
|  | RAPIDJSON_DIAG_POP | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif // RAPIDJSON_RAPIDJSON_H_ | ||||||
							
								
								
									
										525
									
								
								vendor/github.com/Benau/go_rlottie/rlottie.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										525
									
								
								vendor/github.com/Benau/go_rlottie/rlottie.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,525 @@ | |||||||
|  | /* | ||||||
|  |  * 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 _RLOTTIE_H_ | ||||||
|  | #define _RLOTTIE_H_ | ||||||
|  |  | ||||||
|  | #include <future> | ||||||
|  | #include <vector> | ||||||
|  | #include <memory> | ||||||
|  |  | ||||||
|  | #if defined _WIN32 || defined __CYGWIN__ | ||||||
|  |   #ifdef RLOTTIE_BUILD | ||||||
|  |     #define RLOTTIE_API __declspec(dllexport) | ||||||
|  |   #else | ||||||
|  |     #define RLOTTIE_API __declspec(dllimport) | ||||||
|  |   #endif | ||||||
|  | #else | ||||||
|  |   #ifdef RLOTTIE_BUILD | ||||||
|  |       #define RLOTTIE_API __attribute__ ((visibility ("default"))) | ||||||
|  |   #else | ||||||
|  |       #define RLOTTIE_API | ||||||
|  |   #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | class AnimationImpl; | ||||||
|  | struct LOTNode; | ||||||
|  | struct LOTLayerNode; | ||||||
|  |  | ||||||
|  | namespace rlottie { | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  *  @brief Configures rlottie model cache policy. | ||||||
|  |  * | ||||||
|  |  *  Provides Library level control to configure model cache | ||||||
|  |  *  policy. Setting it to 0 will disable | ||||||
|  |  *  the cache as well as flush all the previously cached content. | ||||||
|  |  * | ||||||
|  |  *  @param[in] cacheSize  Maximum Model Cache size. | ||||||
|  |  * | ||||||
|  |  *  @note to disable Caching configure with 0 size. | ||||||
|  |  *  @note to flush the current Cache content configure it with 0 and | ||||||
|  |  *        then reconfigure with the new size. | ||||||
|  |  * | ||||||
|  |  *  @internal | ||||||
|  |  */ | ||||||
|  | RLOTTIE_API void configureModelCacheSize(size_t cacheSize); | ||||||
|  |  | ||||||
|  | struct Color { | ||||||
|  |     Color() = default; | ||||||
|  |     Color(float r, float g , float b):_r(r), _g(g), _b(b){} | ||||||
|  |     float r() const {return _r;} | ||||||
|  |     float g() const {return _g;} | ||||||
|  |     float b() const {return _b;} | ||||||
|  | private: | ||||||
|  |     float _r{0}; | ||||||
|  |     float _g{0}; | ||||||
|  |     float _b{0}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct Size { | ||||||
|  |     Size() = default; | ||||||
|  |     Size(float w, float h):_w(w), _h(h){} | ||||||
|  |     float w() const {return _w;} | ||||||
|  |     float h() const {return _h;} | ||||||
|  | private: | ||||||
|  |     float _w{0}; | ||||||
|  |     float _h{0}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct Point { | ||||||
|  |     Point() = default; | ||||||
|  |     Point(float x, float y):_x(x), _y(y){} | ||||||
|  |     float x() const {return _x;} | ||||||
|  |     float y() const {return _y;} | ||||||
|  | private: | ||||||
|  |     float _x{0}; | ||||||
|  |     float _y{0}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct FrameInfo { | ||||||
|  |     explicit FrameInfo(uint32_t frame): _frameNo(frame){} | ||||||
|  |     uint32_t curFrame() const {return _frameNo;} | ||||||
|  | private: | ||||||
|  |     uint32_t _frameNo; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum class Property { | ||||||
|  |     FillColor,     /*!< Color property of Fill object , value type is rlottie::Color */ | ||||||
|  |     FillOpacity,   /*!< Opacity property of Fill object , value type is float [ 0 .. 100] */ | ||||||
|  |     StrokeColor,   /*!< Color property of Stroke object , value type is rlottie::Color */ | ||||||
|  |     StrokeOpacity, /*!< Opacity property of Stroke object , value type is float [ 0 .. 100] */ | ||||||
|  |     StrokeWidth,   /*!< stroke width property of Stroke object , value type is float */ | ||||||
|  |     TrAnchor,      /*!< Transform Anchor property of Layer and Group object , value type is rlottie::Point */ | ||||||
|  |     TrPosition,    /*!< Transform Position property of Layer and Group object , value type is rlottie::Point */ | ||||||
|  |     TrScale,       /*!< Transform Scale property of Layer and Group object , value type is rlottie::Size. range[0 ..100] */ | ||||||
|  |     TrRotation,    /*!< Transform Rotation property of Layer and Group object , value type is float. range[0 .. 360] in degrees*/ | ||||||
|  |     TrOpacity      /*!< Transform Opacity property of Layer and Group object , value type is float [ 0 .. 100] */ | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct Color_Type{}; | ||||||
|  | struct Point_Type{}; | ||||||
|  | struct Size_Type{}; | ||||||
|  | struct Float_Type{}; | ||||||
|  | template <typename T> struct MapType; | ||||||
|  |  | ||||||
|  | class RLOTTIE_API Surface { | ||||||
|  | public: | ||||||
|  |     /** | ||||||
|  |      *  @brief Surface object constructor. | ||||||
|  |      * | ||||||
|  |      *  @param[in] buffer surface buffer. | ||||||
|  |      *  @param[in] width  surface width. | ||||||
|  |      *  @param[in] height  surface height. | ||||||
|  |      *  @param[in] bytesPerLine  number of bytes in a surface scanline. | ||||||
|  |      * | ||||||
|  |      *  @note Default surface format is ARGB32_Premultiplied. | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     Surface(uint32_t *buffer, size_t width, size_t height, size_t bytesPerLine); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Sets the Draw Area available on the Surface. | ||||||
|  |      * | ||||||
|  |      *  Lottie will use the draw region size to generate frame image | ||||||
|  |      *  and will update only the draw rgion of the surface. | ||||||
|  |      * | ||||||
|  |      *  @param[in] x      region area x position. | ||||||
|  |      *  @param[in] y      region area y position. | ||||||
|  |      *  @param[in] width  region area width. | ||||||
|  |      *  @param[in] height region area height. | ||||||
|  |      * | ||||||
|  |      *  @note Default surface format is ARGB32_Premultiplied. | ||||||
|  |      *  @note Default draw region area is [ 0 , 0, surface width , surface height] | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     void setDrawRegion(size_t x, size_t y, size_t width, size_t height); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns width of the surface. | ||||||
|  |      * | ||||||
|  |      *  @return surface width | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |     size_t width() const {return mWidth;} | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns height of the surface. | ||||||
|  |      * | ||||||
|  |      *  @return surface height | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     size_t height() const {return mHeight;} | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns number of bytes in the surface scanline. | ||||||
|  |      * | ||||||
|  |      *  @return number of bytes in scanline. | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     size_t  bytesPerLine() const {return mBytesPerLine;} | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns buffer attached tp the surface. | ||||||
|  |      * | ||||||
|  |      *  @return buffer attaced to the Surface. | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     uint32_t *buffer() const {return mBuffer;} | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns drawable area width of the surface. | ||||||
|  |      * | ||||||
|  |      *  @return drawable area width | ||||||
|  |      * | ||||||
|  |      *  @note Default value is width() of the surface | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |     size_t drawRegionWidth() const {return mDrawArea.w;} | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns drawable area height of the surface. | ||||||
|  |      * | ||||||
|  |      *  @return drawable area height | ||||||
|  |      * | ||||||
|  |      *  @note Default value is height() of the surface | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     size_t drawRegionHeight() const {return mDrawArea.h;} | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns drawable area's x position of the surface. | ||||||
|  |      * | ||||||
|  |      *  @return drawable area's x potition. | ||||||
|  |      * | ||||||
|  |      *  @note Default value is 0 | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     size_t drawRegionPosX() const {return mDrawArea.x;} | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns drawable area's y position of the surface. | ||||||
|  |      * | ||||||
|  |      *  @return drawable area's y potition. | ||||||
|  |      * | ||||||
|  |      *  @note Default value is 0 | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     size_t drawRegionPosY() const {return mDrawArea.y;} | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Default constructor. | ||||||
|  |      */ | ||||||
|  |     Surface() = default; | ||||||
|  | private: | ||||||
|  |     uint32_t    *mBuffer{nullptr}; | ||||||
|  |     size_t       mWidth{0}; | ||||||
|  |     size_t       mHeight{0}; | ||||||
|  |     size_t       mBytesPerLine{0}; | ||||||
|  |     struct { | ||||||
|  |         size_t   x{0}; | ||||||
|  |         size_t   y{0}; | ||||||
|  |         size_t   w{0}; | ||||||
|  |         size_t   h{0}; | ||||||
|  |     }mDrawArea; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | using MarkerList = std::vector<std::tuple<std::string, int , int>>; | ||||||
|  | /** | ||||||
|  |  *  @brief https://helpx.adobe.com/after-effects/using/layer-markers-composition-markers.html | ||||||
|  |  *  Markers exported form AE are used to describe a segmnet of an animation {comment/tag , startFrame, endFrame} | ||||||
|  |  *  Marker can be use to devide a resource in to separate animations by tagging the segment with comment string , | ||||||
|  |  *  start frame and duration of that segment. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | using LayerInfoList = std::vector<std::tuple<std::string, int , int>>; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | using ColorFilter = std::function<void(float &r , float &g, float &b)>; | ||||||
|  |  | ||||||
|  | class RLOTTIE_API Animation { | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Constructs an animation object from file path. | ||||||
|  |      * | ||||||
|  |      *  @param[in] path Lottie resource file path | ||||||
|  |      *  @param[in] cachePolicy whether to cache or not the model data. | ||||||
|  |      *             use only when need to explicit disabl caching for a | ||||||
|  |      *             particular resource. To disable caching at library level | ||||||
|  |      *             use @see configureModelCacheSize() instead. | ||||||
|  |      * | ||||||
|  |      *  @return Animation object that can render the contents of the | ||||||
|  |      *          Lottie resource represented by file path. | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     static std::unique_ptr<Animation> | ||||||
|  |     loadFromFile(const std::string &path, bool cachePolicy=true); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Constructs an animation object from JSON string data. | ||||||
|  |      * | ||||||
|  |      *  @param[in] jsonData The JSON string data. | ||||||
|  |      *  @param[in] key the string that will be used to cache the JSON string data. | ||||||
|  |      *  @param[in] resourcePath the path will be used to search for external resource. | ||||||
|  |      *  @param[in] cachePolicy whether to cache or not the model data. | ||||||
|  |      *             use only when need to explicit disabl caching for a | ||||||
|  |      *             particular resource. To disable caching at library level | ||||||
|  |      *             use @see configureModelCacheSize() instead. | ||||||
|  |      * | ||||||
|  |      *  @return Animation object that can render the contents of the | ||||||
|  |      *          Lottie resource represented by JSON string data. | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     static std::unique_ptr<Animation> | ||||||
|  |     loadFromData(std::string jsonData, const std::string &key, | ||||||
|  |                  const std::string &resourcePath="", bool cachePolicy=true); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Constructs an animation object from JSON string data and update. | ||||||
|  |      *  the color properties using ColorFilter. | ||||||
|  |  | ||||||
|  |      *  @param[in] jsonData The JSON string data. | ||||||
|  |      *  @param[in] resourcePath the path will be used to search for external resource. | ||||||
|  |      *  @param[in] filter The color filter that will be applied for each color property | ||||||
|  |      *             found during parsing. | ||||||
|  |  | ||||||
|  |      *  @return Animation object that can render the contents of the | ||||||
|  |      *          Lottie resource represented by JSON string data. | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     static std::unique_ptr<Animation> | ||||||
|  |     loadFromData(std::string jsonData, std::string resourcePath, ColorFilter filter); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns default framerate of the Lottie resource. | ||||||
|  |      * | ||||||
|  |      *  @return framerate of the Lottie resource | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |     double frameRate() const; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns total number of frames present in the Lottie resource. | ||||||
|  |      * | ||||||
|  |      *  @return frame count of the Lottie resource. | ||||||
|  |      * | ||||||
|  |      *  @note frame number starts with 0. | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     size_t totalFrame() const; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns default viewport size of the Lottie resource. | ||||||
|  |      * | ||||||
|  |      *  @param[out] width  default width of the viewport. | ||||||
|  |      *  @param[out] height default height of the viewport. | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |     void   size(size_t &width, size_t &height) const; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns total animation duration of Lottie resource in second. | ||||||
|  |      *         it uses totalFrame() and frameRate() to calculate the duration. | ||||||
|  |      *         duration = totalFrame() / frameRate(). | ||||||
|  |      * | ||||||
|  |      *  @return total animation duration in second. | ||||||
|  |      *  @retval 0 if the Lottie resource has no animation. | ||||||
|  |      * | ||||||
|  |      *  @see totalFrame() | ||||||
|  |      *  @see frameRate() | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     double duration() const; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns frame number for a given position. | ||||||
|  |      *         this function helps to map the position value retuned | ||||||
|  |      *         by the animator to a frame number in side the Lottie resource. | ||||||
|  |      *         frame_number = lerp(start_frame, endframe, pos); | ||||||
|  |      * | ||||||
|  |      *  @param[in] pos normalized position value [0 ... 1] | ||||||
|  |      * | ||||||
|  |      *  @return frame numer maps to the position value [startFrame .... endFrame] | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     size_t frameAtPos(double pos); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Renders the content to surface Asynchronously. | ||||||
|  |      *         it gives a future in return to get the result of the | ||||||
|  |      *         rendering at a future point. | ||||||
|  |      *         To get best performance user has to start rendering as soon as | ||||||
|  |      *         it finds that content at {frameNo} has to be rendered and get the | ||||||
|  |      *         result from the future at the last moment when the surface is needed | ||||||
|  |      *         to draw into the screen. | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      *  @param[in] frameNo Content corresponds to the @p frameNo needs to be drawn | ||||||
|  |      *  @param[in] surface Surface in which content will be drawn | ||||||
|  |      *  @param[in] keepAspectRatio whether to keep the aspect ratio while scaling the content. | ||||||
|  |      * | ||||||
|  |      *  @return future that will hold the result when rendering finished. | ||||||
|  |      * | ||||||
|  |      *  for Synchronus rendering @see renderSync | ||||||
|  |      * | ||||||
|  |      *  @see Surface | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     std::future<Surface> render(size_t frameNo, Surface surface, bool keepAspectRatio=true); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Renders the content to surface synchronously. | ||||||
|  |      *         for performance use the async rendering @see render | ||||||
|  |      * | ||||||
|  |      *  @param[in] frameNo Content corresponds to the @p frameNo needs to be drawn | ||||||
|  |      *  @param[in] surface Surface in which content will be drawn | ||||||
|  |      *  @param[in] keepAspectRatio whether to keep the aspect ratio while scaling the content. | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     void              renderSync(size_t frameNo, Surface surface, bool keepAspectRatio=true); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns root layer of the composition updated with | ||||||
|  |      *         content of the Lottie resource at frame number @p frameNo. | ||||||
|  |      * | ||||||
|  |      *  @param[in] frameNo Content corresponds to the @p frameNo needs to be extracted. | ||||||
|  |      *  @param[in] width   content viewbox width | ||||||
|  |      *  @param[in] height  content viewbox height | ||||||
|  |      * | ||||||
|  |      *  @return Root layer node. | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     const LOTLayerNode * renderTree(size_t frameNo, size_t width, size_t height) const; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns Composition Markers. | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      *  @return returns MarkerList of the Composition. | ||||||
|  |      * | ||||||
|  |      *  @see MarkerList | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     const MarkerList& markers() const; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Returns Layer information{name, inFrame, outFrame} of all the child layers  of the composition. | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      *  @return List of Layer Information of the Composition. | ||||||
|  |      * | ||||||
|  |      *  @see LayerInfoList | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     const LayerInfoList& layers() const; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief Sets property value for the specified {@link KeyPath}. This {@link KeyPath} can resolve | ||||||
|  |      *  to multiple contents. In that case, the callback's value will apply to all of them. | ||||||
|  |      * | ||||||
|  |      *  Keypath should conatin object names separated by (.) and can handle globe(**) or wildchar(*). | ||||||
|  |      * | ||||||
|  |      *  @usage | ||||||
|  |      *  To change fillcolor property of fill1 object in the layer1->group1->fill1 hirarchy to RED color | ||||||
|  |      * | ||||||
|  |      *     player->setValue<rlottie::Property::FillColor>("layer1.group1.fill1", rlottie::Color(1, 0, 0); | ||||||
|  |      * | ||||||
|  |      *  if all the color property inside group1 needs to be changed to GREEN color | ||||||
|  |      * | ||||||
|  |      *     player->setValue<rlottie::Property::FillColor>("**.group1.**", rlottie::Color(0, 1, 0); | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     template<Property prop, typename AnyValue> | ||||||
|  |     void setValue(const std::string &keypath, AnyValue value) | ||||||
|  |     { | ||||||
|  |         setValue(MapType<std::integral_constant<Property, prop>>{}, prop, keypath, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  @brief default destructor | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     ~Animation(); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     void setValue(Color_Type, Property, const std::string &, Color); | ||||||
|  |     void setValue(Float_Type, Property, const std::string &, float); | ||||||
|  |     void setValue(Size_Type, Property, const std::string &, Size); | ||||||
|  |     void setValue(Point_Type, Property, const std::string &, Point); | ||||||
|  |  | ||||||
|  |     void setValue(Color_Type, Property, const std::string &, std::function<Color(const FrameInfo &)> &&); | ||||||
|  |     void setValue(Float_Type, Property, const std::string &, std::function<float(const FrameInfo &)> &&); | ||||||
|  |     void setValue(Size_Type, Property, const std::string &, std::function<Size(const FrameInfo &)> &&); | ||||||
|  |     void setValue(Point_Type, Property, const std::string &, std::function<Point(const FrameInfo &)> &&); | ||||||
|  |     /** | ||||||
|  |      *  @brief default constructor | ||||||
|  |      * | ||||||
|  |      *  @internal | ||||||
|  |      */ | ||||||
|  |     Animation(); | ||||||
|  |  | ||||||
|  |     std::unique_ptr<AnimationImpl> d; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //Map Property to Value type | ||||||
|  | template<> struct MapType<std::integral_constant<Property, Property::FillColor>>: Color_Type{}; | ||||||
|  | template<> struct MapType<std::integral_constant<Property, Property::StrokeColor>>: Color_Type{}; | ||||||
|  | template<> struct MapType<std::integral_constant<Property, Property::FillOpacity>>: Float_Type{}; | ||||||
|  | template<> struct MapType<std::integral_constant<Property, Property::StrokeOpacity>>: Float_Type{}; | ||||||
|  | template<> struct MapType<std::integral_constant<Property, Property::StrokeWidth>>: Float_Type{}; | ||||||
|  | template<> struct MapType<std::integral_constant<Property, Property::TrRotation>>: Float_Type{}; | ||||||
|  | template<> struct MapType<std::integral_constant<Property, Property::TrOpacity>>: Float_Type{}; | ||||||
|  | template<> struct MapType<std::integral_constant<Property, Property::TrAnchor>>: Point_Type{}; | ||||||
|  | template<> struct MapType<std::integral_constant<Property, Property::TrPosition>>: Point_Type{}; | ||||||
|  | template<> struct MapType<std::integral_constant<Property, Property::TrScale>>: Size_Type{}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | }  // namespace lotplayer | ||||||
|  |  | ||||||
|  | #endif  // _RLOTTIE_H_ | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user