mirror of
https://github.com/bitwarden/mobile
synced 2026-01-13 22:13:38 +00:00
Compare commits
9 Commits
fix-beta
...
a798ae0761
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a798ae0761 | ||
|
|
7f8b19a0a7 | ||
|
|
e50175abe1 | ||
|
|
8f435b2f26 | ||
|
|
cdbdec8943 | ||
|
|
3d42da2a29 | ||
|
|
16303e581b | ||
|
|
bc4b03b994 | ||
|
|
484eb03eca |
1
.github/renovate.json
vendored
1
.github/renovate.json
vendored
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"enabled": false,
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base",
|
||||
|
||||
18
.github/workflows/build-beta.yml
vendored
18
.github/workflows/build-beta.yml
vendored
@@ -47,9 +47,9 @@ jobs:
|
||||
runs-on: macos-14
|
||||
needs: setup
|
||||
env:
|
||||
ios_folder_path: src/App/Platforms/iOS
|
||||
app_output_name: App
|
||||
app_ci_output_filename: App_x64_Debug
|
||||
_IOS_FOLDER_PATH: src/App/Platforms/iOS
|
||||
_APP_OUTPUT_NAME: App
|
||||
_APP_CI_OUTPUT_FILENAME: App_x64_Debug
|
||||
steps:
|
||||
- name: Set XCode version
|
||||
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
|
||||
echo "### CFBundleVersion $BUILD_NUMBER" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./${{ env.ios_folder_path }}/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./${{ env._IOS_FOLDER_PATH }}/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Extension/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Autofill/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.ShareExtension/Info.plist
|
||||
@@ -145,7 +145,7 @@ jobs:
|
||||
- name: Update Entitlements
|
||||
run: |
|
||||
echo "##### Updating Entitlements"
|
||||
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>beta<\/string>/' ./${{ env.ios_folder_path }}/Entitlements.plist
|
||||
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>beta<\/string>/' ./${{ env._IOS_FOLDER_PATH }}/Entitlements.plist
|
||||
|
||||
- name: Get certificates
|
||||
run: |
|
||||
@@ -245,8 +245,8 @@ jobs:
|
||||
ARCHIVE_PATH: ./${{ env.main_app_folder_path }}/bin/Debug/${{ env.target-net-version }}-ios/iossimulator-x64
|
||||
EXPORT_PATH: ./bitwarden-export
|
||||
run: |
|
||||
zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH
|
||||
mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH
|
||||
zip -r -q ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip $ARCHIVE_PATH
|
||||
mv ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip $EXPORT_PATH
|
||||
|
||||
- name: Show Bitwarden Export
|
||||
shell: bash
|
||||
@@ -276,8 +276,8 @@ jobs:
|
||||
- name: Upload .app file for Automation CI
|
||||
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
|
||||
with:
|
||||
name: ${{ env.app_ci_output_filename }}.app.zip
|
||||
path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip
|
||||
name: ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip
|
||||
path: ./bitwarden-export/${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Install AppCenter CLI
|
||||
|
||||
54
.github/workflows/build.yml
vendored
54
.github/workflows/build.yml
vendored
@@ -1,12 +1,6 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- "l10n_master"
|
||||
- "gh-pages"
|
||||
paths-ignore:
|
||||
- ".github/workflows/**"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
@@ -70,8 +64,8 @@ jobs:
|
||||
matrix:
|
||||
variant: ["prod", "qa"]
|
||||
env:
|
||||
android_folder_path: src\App\Platforms\Android
|
||||
android_folder_path_bash: src/App/Platforms/Android
|
||||
_ANDROID_FOLDER_PATH: src\App\Platforms\Android
|
||||
_ANDROID_FOLDER_PATH_BASH: src/App/Platforms/Android
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
@@ -126,9 +120,9 @@ jobs:
|
||||
mkdir -p $HOME/secrets
|
||||
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
--name app_play-keystore.jks --file ./${{ env.android_folder_path_bash }}/app_play-keystore.jks --output none
|
||||
--name app_play-keystore.jks --file ./${{ env._ANDROID_FOLDER_PATH_BASH }}/app_play-keystore.jks --output none
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
--name app_upload-keystore.jks --file ./${{ env.android_folder_path_bash }}/app_upload-keystore.jks --output none
|
||||
--name app_upload-keystore.jks --file ./${{ env._ANDROID_FOLDER_PATH_BASH }}/app_upload-keystore.jks --output none
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
--name play_creds.json --file $HOME/secrets/play_creds.json --output none
|
||||
shell: bash
|
||||
@@ -140,7 +134,7 @@ jobs:
|
||||
CONTAINER_NAME: mobile
|
||||
run: |
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
--name google-services.json --file ./${{ env.android_folder_path_bash }}/google-services.json --output none
|
||||
--name google-services.json --file ./${{ env._ANDROID_FOLDER_PATH_BASH }}/google-services.json --output none
|
||||
shell: bash
|
||||
|
||||
- name: Increment version
|
||||
@@ -149,7 +143,7 @@ jobs:
|
||||
echo "##### Setting Android Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
|
||||
|
||||
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
|
||||
./${{ env.android_folder_path_bash }}/AndroidManifest.xml
|
||||
./${{ env._ANDROID_FOLDER_PATH_BASH }}/AndroidManifest.xml
|
||||
shell: bash
|
||||
|
||||
- name: Restore packages
|
||||
@@ -193,7 +187,7 @@ jobs:
|
||||
}
|
||||
Write-Output "##### Sign Google Play Bundle Release Configuration"
|
||||
|
||||
$signingUploadKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_upload-keystore.jks"
|
||||
$signingUploadKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env._ANDROID_FOLDER_PATH }}\app_upload-keystore.jks"
|
||||
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android `
|
||||
/p:AndroidPackageFormats=aab `
|
||||
/p:AndroidKeyStore=true `
|
||||
@@ -210,7 +204,7 @@ jobs:
|
||||
|
||||
Write-Output "##### Sign APK Release Configuration"
|
||||
|
||||
$signingPlayKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_play-keystore.jks"
|
||||
$signingPlayKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env._ANDROID_FOLDER_PATH }}\app_play-keystore.jks"
|
||||
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android `
|
||||
/p:AndroidKeyStore=true `
|
||||
/p:AndroidSigningKeyStore=$signingPlayKeyStore `
|
||||
@@ -295,9 +289,9 @@ jobs:
|
||||
name: F-Droid Build
|
||||
runs-on: windows-2022
|
||||
env:
|
||||
android_folder_path: src\App\Platforms\Android
|
||||
android_folder_path_bash: src/App/Platforms/Android
|
||||
android_manifest_path: src/App/Platforms/Android/AndroidManifest.xml
|
||||
_ANDROID_FOLDER_PATH: src\App\Platforms\Android
|
||||
_ANDROID_FOLDER_PATH_BASH: src/App/Platforms/Android
|
||||
_ANDROID_MANIFEST_PATH: src/App/Platforms/Android/AndroidManifest.xml
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
@@ -350,7 +344,7 @@ jobs:
|
||||
FILE: app_fdroid-keystore.jks
|
||||
run: |
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
|
||||
--file ${{ env.android_folder_path_bash }}/$FILE --output none
|
||||
--file ${{ env._ANDROID_FOLDER_PATH_BASH }}/$FILE --output none
|
||||
shell: bash
|
||||
|
||||
- name: Increment version
|
||||
@@ -359,14 +353,14 @@ jobs:
|
||||
echo "##### Setting F-Droid Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
|
||||
|
||||
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
|
||||
./${{ env.android_manifest_path }}
|
||||
./${{ env._ANDROID_MANIFEST_PATH }}
|
||||
shell: bash
|
||||
|
||||
- name: Clean for F-Droid
|
||||
run: |
|
||||
$directoryBuildProps = $($env:GITHUB_WORKSPACE + "/Directory.Build.props");
|
||||
|
||||
$androidManifest = $($env:GITHUB_WORKSPACE + "/${{ env.android_manifest_path }}");
|
||||
$androidManifest = $($env:GITHUB_WORKSPACE + "/${{ env._ANDROID_MANIFEST_PATH }}");
|
||||
|
||||
Write-Output "##### Back up project files"
|
||||
|
||||
@@ -399,7 +393,7 @@ jobs:
|
||||
|
||||
Write-Output "##### Sign FDroid"
|
||||
|
||||
$signingFdroidKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_fdroid-keystore.jks"
|
||||
$signingFdroidKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env._ANDROID_FOLDER_PATH }}\app_fdroid-keystore.jks"
|
||||
dotnet build $projToBuild -c Release -f ${{ env.target-net-version }}-android `
|
||||
/p:AndroidKeyStore=true `
|
||||
/p:AndroidSigningKeyStore=$signingFdroidKeyStore `
|
||||
@@ -439,9 +433,9 @@ jobs:
|
||||
runs-on: macos-14
|
||||
needs: setup
|
||||
env:
|
||||
ios_folder_path: src/App/Platforms/iOS
|
||||
app_output_name: App
|
||||
app_ci_output_filename: App_x64_Debug
|
||||
_IOS_FOLDER_PATH: src/App/Platforms/iOS
|
||||
_APP_OUTPUT_NAME: App
|
||||
_APP_CI_OUTPUT_FILENAME: App_x64_Debug
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
@@ -521,7 +515,7 @@ jobs:
|
||||
BUILD_NUMBER=$((8000 + $GITHUB_RUN_NUMBER))
|
||||
echo "##### Setting iOS CFBundleVersion to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
|
||||
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./${{ env.ios_folder_path }}/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./${{ env._IOS_FOLDER_PATH }}/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Extension/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Autofill/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.ShareExtension/Info.plist
|
||||
@@ -531,7 +525,7 @@ jobs:
|
||||
- name: Update Entitlements
|
||||
run: |
|
||||
echo "##### Updating Entitlements"
|
||||
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>production<\/string>/' ./${{ env.ios_folder_path }}/Entitlements.plist
|
||||
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>production<\/string>/' ./${{ env._IOS_FOLDER_PATH }}/Entitlements.plist
|
||||
|
||||
- name: Get certificates
|
||||
run: |
|
||||
@@ -615,8 +609,8 @@ jobs:
|
||||
ARCHIVE_PATH: ./${{ env.main_app_folder_path }}/bin/Debug/${{ env.target-net-version }}-ios/iossimulator-x64
|
||||
EXPORT_PATH: ./bitwarden-export
|
||||
run: |
|
||||
zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH
|
||||
mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH
|
||||
zip -r -q ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip $ARCHIVE_PATH
|
||||
mv ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip $EXPORT_PATH
|
||||
|
||||
- name: Copy all dSYMs files to upload
|
||||
env:
|
||||
@@ -641,8 +635,8 @@ jobs:
|
||||
- name: Upload .app file for Automation CI
|
||||
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
|
||||
with:
|
||||
name: ${{ env.app_ci_output_filename }}.app.zip
|
||||
path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip
|
||||
name: ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip
|
||||
path: ./bitwarden-export/${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Install AppCenter CLI
|
||||
|
||||
17
.github/workflows/crowdin-pull.yml
vendored
17
.github/workflows/crowdin-pull.yml
vendored
@@ -3,18 +3,25 @@ name: Crowdin Sync
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs: {}
|
||||
schedule:
|
||||
- cron: '0 0 * * 5'
|
||||
|
||||
jobs:
|
||||
crowdin-sync:
|
||||
name: Autosync
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
_CROWDIN_PROJECT_ID: "269690"
|
||||
steps:
|
||||
- name: Generate GH App token
|
||||
uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1.11.1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.BW_GHAPP_ID }}
|
||||
private-key: ${{ secrets.BW_GHAPP_KEY }}
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
@@ -31,7 +38,7 @@ jobs:
|
||||
- name: Download translations
|
||||
uses: crowdin/github-action@61ac8b980551f674046220c3e104bddae2916ac5 # v2.0.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
||||
with:
|
||||
config: crowdin.yml
|
||||
|
||||
3
.github/workflows/pr-labeler.yml
vendored
3
.github/workflows/pr-labeler.yml
vendored
@@ -11,6 +11,7 @@ jobs:
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
|
||||
- name: Label PR
|
||||
uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
|
||||
with:
|
||||
sync-labels: true
|
||||
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -296,17 +296,11 @@ iOSInjectionProject/
|
||||
timeline.xctimeline
|
||||
playground.xcworkspace
|
||||
|
||||
# Swift Package Manager
|
||||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
||||
# Packages/
|
||||
# Package.pins
|
||||
# Package.resolved
|
||||
# *.xcodeproj
|
||||
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
|
||||
# hence it is not needed unless you have added a package configuration file to your project
|
||||
# .swiftpm
|
||||
|
||||
.build/
|
||||
# xcode / swift package manager - used by the MessagePack lib
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
.swiftpm
|
||||
|
||||
# CocoaPods
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "lib/MessagePack"]
|
||||
path = lib/MessagePack
|
||||
url = https://github.com/bitwarden/MessagePack.git
|
||||
Submodule lib/MessagePack deleted from 1ecb15e311
19
lib/MessagePack/LICENSE.md
Normal file
19
lib/MessagePack/LICENSE.md
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright 2018 Read Evaluate Press, LLC
|
||||
|
||||
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.
|
||||
32
lib/MessagePack/MessagePack-FlightSchool.podspec
Normal file
32
lib/MessagePack/MessagePack-FlightSchool.podspec
Normal file
@@ -0,0 +1,32 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'MessagePack-FlightSchool'
|
||||
s.module_name = 'MessagePack'
|
||||
s.version = '1.2.4'
|
||||
s.summary = 'A MessagePack encoder and decoder for Codable types.'
|
||||
|
||||
s.description = <<-DESC
|
||||
This functionality is discussed in Chapter 7 of
|
||||
Flight School Guide to Swift Codable.
|
||||
DESC
|
||||
|
||||
s.homepage = 'https://flight.school/books/codable/'
|
||||
|
||||
s.license = { type: 'MIT', file: 'LICENSE.md' }
|
||||
|
||||
s.author = { 'Mattt' => 'mattt@flight.school' }
|
||||
|
||||
s.social_media_url = 'https://twitter.com/mattt'
|
||||
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.osx.deployment_target = '10.10'
|
||||
s.watchos.deployment_target = '2.0'
|
||||
s.tvos.deployment_target = '9.0'
|
||||
|
||||
s.source = { git: 'https://github.com/Flight-School/MessagePack.git',
|
||||
tag: s.version.to_s }
|
||||
|
||||
s.source_files = 'Sources/**/*.swift'
|
||||
|
||||
s.swift_version = '4.2'
|
||||
s.static_framework = true
|
||||
end
|
||||
13
lib/MessagePack/MessagePack.playground/Contents.swift
Normal file
13
lib/MessagePack/MessagePack.playground/Contents.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
import MessagePack
|
||||
|
||||
let encoder = MessagePackEncoder()
|
||||
|
||||
let value: String = "hello"
|
||||
let encodedData = try encoder.encode(value)
|
||||
|
||||
print("Bytes: ", encodedData.map{ String($0, radix: 16, uppercase: true) })
|
||||
|
||||
let decoder = MessagePackDecoder()
|
||||
let decodedValue = try decoder.decode(String.self, from: encodedData)
|
||||
|
||||
decodedValue == value
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='5.0' target-platform='macos' executeOnSourceChanges='false'>
|
||||
<timeline fileName='timeline.xctimeline'/>
|
||||
</playground>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
25
lib/MessagePack/MessagePack.xcodeproj/MessagePack_Info.plist
Normal file
25
lib/MessagePack/MessagePack.xcodeproj/MessagePack_Info.plist
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
543
lib/MessagePack/MessagePack.xcodeproj/project.pbxproj
Normal file
543
lib/MessagePack/MessagePack.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,543 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXAggregateTarget section */
|
||||
"MessagePack::MessagePackPackageTests::ProductTarget" /* MessagePackPackageTests */ = {
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = OBJ_57 /* Build configuration list for PBXAggregateTarget "MessagePackPackageTests" */;
|
||||
buildPhases = (
|
||||
);
|
||||
dependencies = (
|
||||
OBJ_60 /* PBXTargetDependency */,
|
||||
);
|
||||
name = MessagePackPackageTests;
|
||||
productName = MessagePackPackageTests;
|
||||
};
|
||||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1BC312FF2992DE9C00177F2A /* DataSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BC312FE2992DE9C00177F2A /* DataSpec.swift */; };
|
||||
OBJ_38 /* AnyCodingKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* AnyCodingKey.swift */; };
|
||||
OBJ_39 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* Box.swift */; };
|
||||
OBJ_40 /* KeyedDecodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* KeyedDecodingContainer.swift */; };
|
||||
OBJ_41 /* MessagePackDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* MessagePackDecoder.swift */; };
|
||||
OBJ_42 /* SingleValueDecodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* SingleValueDecodingContainer.swift */; };
|
||||
OBJ_43 /* UnkeyedDecodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* UnkeyedDecodingContainer.swift */; };
|
||||
OBJ_44 /* KeyedEncodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* KeyedEncodingContainer.swift */; };
|
||||
OBJ_45 /* MessagePackEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* MessagePackEncoder.swift */; };
|
||||
OBJ_46 /* SingleValueEncodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* SingleValueEncodingContainer.swift */; };
|
||||
OBJ_47 /* UnkeyedEncodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* UnkeyedEncodingContainer.swift */; };
|
||||
OBJ_48 /* FixedWidthInteger+Bytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* FixedWidthInteger+Bytes.swift */; };
|
||||
OBJ_55 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; };
|
||||
OBJ_66 /* Airport.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* Airport.swift */; };
|
||||
OBJ_67 /* MessagePackDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* MessagePackDecodingTests.swift */; };
|
||||
OBJ_68 /* MessagePackEncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* MessagePackEncodingTests.swift */; };
|
||||
OBJ_69 /* MessagePackPerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_27 /* MessagePackPerformanceTests.swift */; };
|
||||
OBJ_70 /* MessagePackRoundTripTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_28 /* MessagePackRoundTripTests.swift */; };
|
||||
OBJ_72 /* MessagePack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "MessagePack::MessagePack::Product" /* MessagePack.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
1BC312FC2989A1AD00177F2A /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = OBJ_1 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = "MessagePack::MessagePack";
|
||||
remoteInfo = MessagePack;
|
||||
};
|
||||
1BC312FD2989A1B200177F2A /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = OBJ_1 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = "MessagePack::MessagePackTests";
|
||||
remoteInfo = MessagePackTests;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1BC312FE2992DE9C00177F2A /* DataSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSpec.swift; sourceTree = "<group>"; };
|
||||
"MessagePack::MessagePack::Product" /* MessagePack.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MessagePack.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
"MessagePack::MessagePackTests::Product" /* MessagePackTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = MessagePackTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
OBJ_10 /* Box.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = "<group>"; };
|
||||
OBJ_12 /* KeyedDecodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyedDecodingContainer.swift; sourceTree = "<group>"; };
|
||||
OBJ_13 /* MessagePackDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackDecoder.swift; sourceTree = "<group>"; };
|
||||
OBJ_14 /* SingleValueDecodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleValueDecodingContainer.swift; sourceTree = "<group>"; };
|
||||
OBJ_15 /* UnkeyedDecodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnkeyedDecodingContainer.swift; sourceTree = "<group>"; };
|
||||
OBJ_17 /* KeyedEncodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyedEncodingContainer.swift; sourceTree = "<group>"; };
|
||||
OBJ_18 /* MessagePackEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackEncoder.swift; sourceTree = "<group>"; };
|
||||
OBJ_19 /* SingleValueEncodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleValueEncodingContainer.swift; sourceTree = "<group>"; };
|
||||
OBJ_20 /* UnkeyedEncodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnkeyedEncodingContainer.swift; sourceTree = "<group>"; };
|
||||
OBJ_21 /* FixedWidthInteger+Bytes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FixedWidthInteger+Bytes.swift"; sourceTree = "<group>"; };
|
||||
OBJ_24 /* Airport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Airport.swift; sourceTree = "<group>"; };
|
||||
OBJ_25 /* MessagePackDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackDecodingTests.swift; sourceTree = "<group>"; };
|
||||
OBJ_26 /* MessagePackEncodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackEncodingTests.swift; sourceTree = "<group>"; };
|
||||
OBJ_27 /* MessagePackPerformanceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackPerformanceTests.swift; sourceTree = "<group>"; };
|
||||
OBJ_28 /* MessagePackRoundTripTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackRoundTripTests.swift; sourceTree = "<group>"; };
|
||||
OBJ_29 /* MessagePack.xcworkspace */ = {isa = PBXFileReference; lastKnownFileType = wrapper.workspace; path = MessagePack.xcworkspace; sourceTree = SOURCE_ROOT; };
|
||||
OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
|
||||
OBJ_9 /* AnyCodingKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyCodingKey.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
OBJ_49 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
OBJ_71 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 0;
|
||||
files = (
|
||||
OBJ_72 /* MessagePack.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
OBJ_11 /* Decoder */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
OBJ_12 /* KeyedDecodingContainer.swift */,
|
||||
OBJ_13 /* MessagePackDecoder.swift */,
|
||||
OBJ_14 /* SingleValueDecodingContainer.swift */,
|
||||
OBJ_15 /* UnkeyedDecodingContainer.swift */,
|
||||
);
|
||||
path = Decoder;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
OBJ_16 /* Encoder */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
OBJ_17 /* KeyedEncodingContainer.swift */,
|
||||
OBJ_18 /* MessagePackEncoder.swift */,
|
||||
OBJ_19 /* SingleValueEncodingContainer.swift */,
|
||||
OBJ_20 /* UnkeyedEncodingContainer.swift */,
|
||||
);
|
||||
path = Encoder;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
OBJ_22 /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
OBJ_23 /* MessagePackTests */,
|
||||
);
|
||||
name = Tests;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
OBJ_23 /* MessagePackTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
OBJ_24 /* Airport.swift */,
|
||||
OBJ_25 /* MessagePackDecodingTests.swift */,
|
||||
OBJ_26 /* MessagePackEncodingTests.swift */,
|
||||
OBJ_27 /* MessagePackPerformanceTests.swift */,
|
||||
OBJ_28 /* MessagePackRoundTripTests.swift */,
|
||||
);
|
||||
name = MessagePackTests;
|
||||
path = Tests/MessagePackTests;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
OBJ_30 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
"MessagePack::MessagePackTests::Product" /* MessagePackTests.xctest */,
|
||||
"MessagePack::MessagePack::Product" /* MessagePack.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
OBJ_5 /* */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
OBJ_6 /* Package.swift */,
|
||||
OBJ_7 /* Sources */,
|
||||
OBJ_22 /* Tests */,
|
||||
OBJ_29 /* MessagePack.xcworkspace */,
|
||||
OBJ_30 /* Products */,
|
||||
);
|
||||
name = "";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
OBJ_7 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
OBJ_8 /* MessagePack */,
|
||||
);
|
||||
name = Sources;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
OBJ_8 /* MessagePack */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
OBJ_9 /* AnyCodingKey.swift */,
|
||||
OBJ_10 /* Box.swift */,
|
||||
OBJ_11 /* Decoder */,
|
||||
OBJ_16 /* Encoder */,
|
||||
OBJ_21 /* FixedWidthInteger+Bytes.swift */,
|
||||
1BC312FE2992DE9C00177F2A /* DataSpec.swift */,
|
||||
);
|
||||
name = MessagePack;
|
||||
path = Sources/MessagePack;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
"MessagePack::MessagePack" /* MessagePack */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = OBJ_34 /* Build configuration list for PBXNativeTarget "MessagePack" */;
|
||||
buildPhases = (
|
||||
OBJ_37 /* Sources */,
|
||||
OBJ_49 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = MessagePack;
|
||||
productName = MessagePack;
|
||||
productReference = "MessagePack::MessagePack::Product" /* MessagePack.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
"MessagePack::MessagePackTests" /* MessagePackTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = OBJ_62 /* Build configuration list for PBXNativeTarget "MessagePackTests" */;
|
||||
buildPhases = (
|
||||
OBJ_65 /* Sources */,
|
||||
OBJ_71 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
OBJ_73 /* PBXTargetDependency */,
|
||||
);
|
||||
name = MessagePackTests;
|
||||
productName = MessagePackTests;
|
||||
productReference = "MessagePack::MessagePackTests::Product" /* MessagePackTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
"MessagePack::SwiftPMPackageDescription" /* MessagePackPackageDescription */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = OBJ_51 /* Build configuration list for PBXNativeTarget "MessagePackPackageDescription" */;
|
||||
buildPhases = (
|
||||
OBJ_54 /* Sources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = MessagePackPackageDescription;
|
||||
productName = MessagePackPackageDescription;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
OBJ_1 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 9999;
|
||||
};
|
||||
buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "MessagePack" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
);
|
||||
mainGroup = OBJ_5 /* */;
|
||||
productRefGroup = OBJ_30 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
"MessagePack::MessagePack" /* MessagePack */,
|
||||
"MessagePack::SwiftPMPackageDescription" /* MessagePackPackageDescription */,
|
||||
"MessagePack::MessagePackPackageTests::ProductTarget" /* MessagePackPackageTests */,
|
||||
"MessagePack::MessagePackTests" /* MessagePackTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
OBJ_37 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 0;
|
||||
files = (
|
||||
OBJ_38 /* AnyCodingKey.swift in Sources */,
|
||||
OBJ_39 /* Box.swift in Sources */,
|
||||
OBJ_40 /* KeyedDecodingContainer.swift in Sources */,
|
||||
OBJ_41 /* MessagePackDecoder.swift in Sources */,
|
||||
OBJ_42 /* SingleValueDecodingContainer.swift in Sources */,
|
||||
OBJ_43 /* UnkeyedDecodingContainer.swift in Sources */,
|
||||
OBJ_44 /* KeyedEncodingContainer.swift in Sources */,
|
||||
OBJ_45 /* MessagePackEncoder.swift in Sources */,
|
||||
OBJ_46 /* SingleValueEncodingContainer.swift in Sources */,
|
||||
OBJ_47 /* UnkeyedEncodingContainer.swift in Sources */,
|
||||
1BC312FF2992DE9C00177F2A /* DataSpec.swift in Sources */,
|
||||
OBJ_48 /* FixedWidthInteger+Bytes.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
OBJ_54 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 0;
|
||||
files = (
|
||||
OBJ_55 /* Package.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
OBJ_65 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 0;
|
||||
files = (
|
||||
OBJ_66 /* Airport.swift in Sources */,
|
||||
OBJ_67 /* MessagePackDecodingTests.swift in Sources */,
|
||||
OBJ_68 /* MessagePackEncodingTests.swift in Sources */,
|
||||
OBJ_69 /* MessagePackPerformanceTests.swift in Sources */,
|
||||
OBJ_70 /* MessagePackRoundTripTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
OBJ_60 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = "MessagePack::MessagePackTests" /* MessagePackTests */;
|
||||
targetProxy = 1BC312FD2989A1B200177F2A /* PBXContainerItemProxy */;
|
||||
};
|
||||
OBJ_73 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = "MessagePack::MessagePack" /* MessagePack */;
|
||||
targetProxy = 1BC312FC2989A1AD00177F2A /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
OBJ_3 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_NS_ASSERTIONS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_SWIFT_FLAGS = "-DXcode";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "SWIFT_PACKAGE DEBUG";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
USE_HEADERMAP = NO;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
OBJ_35 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ENABLE_TESTABILITY = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = MessagePack.xcodeproj/MessagePack_Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = MessagePack;
|
||||
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGET_NAME = MessagePack;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
OBJ_36 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ENABLE_TESTABILITY = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = MessagePack.xcodeproj/MessagePack_Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = MessagePack;
|
||||
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGET_NAME = MessagePack;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
OBJ_4 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
OTHER_SWIFT_FLAGS = "-DXcode";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
USE_HEADERMAP = NO;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
OBJ_52 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
LD = /usr/bin/true;
|
||||
OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
OBJ_53 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
LD = /usr/bin/true;
|
||||
OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
OBJ_58 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
OBJ_59 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
OBJ_63 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = MessagePack.xcodeproj/MessagePackTests_Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks";
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGET_NAME = MessagePackTests;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
OBJ_64 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = MessagePack.xcodeproj/MessagePackTests_Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks";
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGET_NAME = MessagePackTests;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
OBJ_2 /* Build configuration list for PBXProject "MessagePack" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
OBJ_3 /* Debug */,
|
||||
OBJ_4 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
OBJ_34 /* Build configuration list for PBXNativeTarget "MessagePack" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
OBJ_35 /* Debug */,
|
||||
OBJ_36 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
OBJ_51 /* Build configuration list for PBXNativeTarget "MessagePackPackageDescription" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
OBJ_52 /* Debug */,
|
||||
OBJ_53 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
OBJ_57 /* Build configuration list for PBXAggregateTarget "MessagePackPackageTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
OBJ_58 /* Debug */,
|
||||
OBJ_59 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
OBJ_62 /* Build configuration list for PBXNativeTarget "MessagePackTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
OBJ_63 /* Debug */,
|
||||
OBJ_64 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = OBJ_1 /* Project object */;
|
||||
}
|
||||
7
lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1010"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "MessagePack::MessagePack"
|
||||
BuildableName = "MessagePack.framework"
|
||||
BlueprintName = "MessagePack"
|
||||
ReferencedContainer = "container:MessagePack.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "MessagePack::MessagePackTests"
|
||||
BuildableName = "MessagePackTests.xctest"
|
||||
BlueprintName = "MessagePackTests"
|
||||
ReferencedContainer = "container:MessagePack.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "MessagePack::MessagePack"
|
||||
BuildableName = "MessagePack.framework"
|
||||
BlueprintName = "MessagePack"
|
||||
ReferencedContainer = "container:MessagePack.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "MessagePack::MessagePack"
|
||||
BuildableName = "MessagePack.framework"
|
||||
BlueprintName = "MessagePack"
|
||||
ReferencedContainer = "container:MessagePack.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "MessagePack::MessagePack"
|
||||
BuildableName = "MessagePack.framework"
|
||||
BlueprintName = "MessagePack"
|
||||
ReferencedContainer = "container:MessagePack.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
10
lib/MessagePack/MessagePack.xcworkspace/contents.xcworkspacedata
generated
Normal file
10
lib/MessagePack/MessagePack.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:MessagePack.playground">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:MessagePack.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
28
lib/MessagePack/Package.swift
Normal file
28
lib/MessagePack/Package.swift
Normal file
@@ -0,0 +1,28 @@
|
||||
// swift-tools-version:4.0
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "MessagePack",
|
||||
products: [
|
||||
// Products define the executables and libraries produced by a package, and make them visible to other packages.
|
||||
.library(
|
||||
name: "MessagePack",
|
||||
targets: ["MessagePack"]),
|
||||
],
|
||||
dependencies: [
|
||||
// Dependencies declare other packages that this package depends on.
|
||||
// .package(url: /* package url */, from: "1.0.0"),
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
|
||||
.target(
|
||||
name: "MessagePack",
|
||||
dependencies: []),
|
||||
.testTarget(
|
||||
name: "MessagePackTests",
|
||||
dependencies: ["MessagePack"]),
|
||||
]
|
||||
)
|
||||
87
lib/MessagePack/README.md
Normal file
87
lib/MessagePack/README.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# MessagePack
|
||||
|
||||
[![Build Status][build status badge]][build status]
|
||||
|
||||
A [MessagePack](https://msgpack.org/) encoder and decoder for `Codable` types.
|
||||
|
||||
This functionality is discussed in Chapter 7 of
|
||||
[Flight School Guide to Swift Codable](https://flight.school/books/codable).
|
||||
|
||||
## Requirements
|
||||
|
||||
- Swift 4.2+
|
||||
|
||||
## Usage
|
||||
|
||||
### Encoding Messages
|
||||
|
||||
```swift
|
||||
import MessagePack
|
||||
|
||||
let encoder = MessagePackEncoder()
|
||||
let value = try! encoder.encode(["a": 1, "b": 2, "c": 3])
|
||||
// [0x83, 0xA1, 0x62, 0x02, 0xA1, 0x61, 0x01, 0xA1, 0x63, 0x03]
|
||||
```
|
||||
|
||||
### Decoding Messages
|
||||
|
||||
```swift
|
||||
import MessagePack
|
||||
|
||||
let decoder = MessagePackDecoder()
|
||||
let data = Data(bytes: [0xCB, 0x40, 0x09, 0x21, 0xF9, 0xF0, 0x1B, 0x86, 0x6E])
|
||||
let value = try! decoder.decode(Double.self, from: data)
|
||||
// 3.14159
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
### Swift Package Manager
|
||||
|
||||
Add the MessagePack package to your target dependencies in `Package.swift`:
|
||||
|
||||
```swift
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "YourProject",
|
||||
dependencies: [
|
||||
.package(
|
||||
url: "https://github.com/Flight-School/MessagePack",
|
||||
from: "1.2.3"
|
||||
),
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
Then run the `swift build` command to build your project.
|
||||
|
||||
### CocoaPods
|
||||
|
||||
You can install `MessagePack` via CocoaPods,
|
||||
by adding the following line to your `Podfile`:
|
||||
|
||||
```ruby
|
||||
pod 'MessagePack-FlightSchool', '~> 1.2.4'
|
||||
```
|
||||
|
||||
Run the `pod install` command to download the library
|
||||
and integrate it into your Xcode project.
|
||||
|
||||
> **Note**
|
||||
> The module name for this library is "MessagePack" ---
|
||||
> that is, to use it, you add `import MessagePack` to the top of your Swift code
|
||||
> just as you would by any other installation method.
|
||||
> The pod is called "MessagePack-FlightSchool"
|
||||
> because there's an existing pod with the name "MessagePack".
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Contact
|
||||
|
||||
Mattt ([@mattt](https://twitter.com/mattt))
|
||||
|
||||
[build status]: https://github.com/Flight-School/MessagePack/actions?query=workflow%3ACI
|
||||
[build status badge]: https://github.com/Flight-School/MessagePack/workflows/CI/badge.svg
|
||||
28
lib/MessagePack/Sources/MessagePack/AnyCodingKey.swift
Normal file
28
lib/MessagePack/Sources/MessagePack/AnyCodingKey.swift
Normal file
@@ -0,0 +1,28 @@
|
||||
struct AnyCodingKey: CodingKey, Equatable {
|
||||
var stringValue: String
|
||||
var intValue: Int?
|
||||
|
||||
init?(stringValue: String) {
|
||||
self.stringValue = stringValue
|
||||
self.intValue = nil
|
||||
}
|
||||
|
||||
init?(intValue: Int) {
|
||||
self.stringValue = "\(intValue)"
|
||||
self.intValue = intValue
|
||||
}
|
||||
|
||||
init<Key>(_ base: Key) where Key : CodingKey {
|
||||
if let intValue = base.intValue {
|
||||
self.init(intValue: intValue)!
|
||||
} else {
|
||||
self.init(stringValue: base.stringValue)!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension AnyCodingKey: Hashable {
|
||||
var hashValue: Int {
|
||||
return self.intValue?.hashValue ?? self.stringValue.hashValue
|
||||
}
|
||||
}
|
||||
44
lib/MessagePack/Sources/MessagePack/Box.swift
Normal file
44
lib/MessagePack/Sources/MessagePack/Box.swift
Normal file
@@ -0,0 +1,44 @@
|
||||
import Foundation
|
||||
|
||||
struct Box<Value> {
|
||||
let value: Value
|
||||
init(_ value: Value) {
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
extension Box: Encodable where Value: Encodable {
|
||||
func encode(to encoder: Encoder) throws {
|
||||
try self.value.encode(to: encoder)
|
||||
}
|
||||
}
|
||||
|
||||
extension Box: Decodable where Value: Decodable {
|
||||
init(from decoder: Decoder) throws {
|
||||
self.init(try Value(from: decoder))
|
||||
}
|
||||
}
|
||||
|
||||
extension Box where Value == Data {
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
self.init(try container.decode(Value.self))
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(self.value)
|
||||
}
|
||||
}
|
||||
|
||||
extension Box where Value == Date {
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
self.init(try container.decode(Value.self))
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(self.value)
|
||||
}
|
||||
}
|
||||
60
lib/MessagePack/Sources/MessagePack/DataSpec.swift
Normal file
60
lib/MessagePack/Sources/MessagePack/DataSpec.swift
Normal file
@@ -0,0 +1,60 @@
|
||||
import Foundation
|
||||
|
||||
public struct DataSpec {
|
||||
let name: String
|
||||
let isObj: Bool
|
||||
let isArray: Bool
|
||||
let dataSpecBuilder: DataSpecBuilder?
|
||||
|
||||
init(_ name: String, _ isObj: Bool, _ isArray: Bool, _ dataSpecBuilder: DataSpecBuilder?) {
|
||||
self.name = name
|
||||
self.isObj = isObj
|
||||
self.isArray = isArray
|
||||
self.dataSpecBuilder = dataSpecBuilder
|
||||
}
|
||||
}
|
||||
|
||||
public class DataSpecBuilder : NSCopying {
|
||||
var specs: [DataSpec] = []
|
||||
var specsIterator: IndexingIterator<[DataSpec]>
|
||||
|
||||
init() {
|
||||
specsIterator = IndexingIterator(_elements: [])
|
||||
}
|
||||
|
||||
func append(_ name: String) -> DataSpecBuilder {
|
||||
return append(DataSpec(name, false, false, nil))
|
||||
}
|
||||
|
||||
func appendObj(_ name: String, _ dataSpecBuilder: DataSpecBuilder) -> DataSpecBuilder {
|
||||
return append(DataSpec(name, true, false, dataSpecBuilder))
|
||||
}
|
||||
|
||||
func appendArray(_ name: String) -> DataSpecBuilder {
|
||||
return append(DataSpec(name, false, true, nil))
|
||||
}
|
||||
|
||||
func appendArray(_ name: String, _ dataSpecBuilder: DataSpecBuilder) -> DataSpecBuilder {
|
||||
return append(DataSpec(name, false, true, dataSpecBuilder))
|
||||
}
|
||||
|
||||
func append(_ spec: DataSpec) -> DataSpecBuilder {
|
||||
specs.append(spec)
|
||||
return self
|
||||
}
|
||||
|
||||
func build() -> DataSpecBuilder {
|
||||
specsIterator = specs.makeIterator()
|
||||
return self
|
||||
}
|
||||
|
||||
func next() -> DataSpec {
|
||||
return specsIterator.next()!
|
||||
}
|
||||
|
||||
public func copy(with zone: NSZone? = nil) -> Any {
|
||||
let b = DataSpecBuilder()
|
||||
b.specs = specs
|
||||
return b.build()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
import Foundation
|
||||
|
||||
extension _MessagePackDecoder {
|
||||
final class KeyedContainer<Key> where Key: CodingKey {
|
||||
lazy var nestedContainers: [String: MessagePackDecodingContainer] = {
|
||||
guard let count = self.count else {
|
||||
return [:]
|
||||
}
|
||||
|
||||
var nestedContainers: [String: MessagePackDecodingContainer] = [:]
|
||||
|
||||
let unkeyedContainer = UnkeyedContainer(data: self.data.suffix(from: self.index), codingPath: self.codingPath, userInfo: self.userInfo)
|
||||
if currentSpec != nil && currentSpec!.isObj {
|
||||
unkeyedContainer.count = count
|
||||
} else {
|
||||
unkeyedContainer.count = count * 2
|
||||
}
|
||||
|
||||
do {
|
||||
var iterator = unkeyedContainer.nestedContainers.makeIterator()
|
||||
|
||||
for _ in 0..<count {
|
||||
var key: String = ""
|
||||
if currentSpec == nil || !currentSpec!.isObj {
|
||||
guard let keyContainer = iterator.next() as? _MessagePackDecoder.SingleValueContainer else {
|
||||
fatalError() // FIXME
|
||||
}
|
||||
|
||||
key = try keyContainer.decode(String.self)
|
||||
}
|
||||
|
||||
guard let container = iterator.next() else {
|
||||
fatalError() // FIXME
|
||||
}
|
||||
|
||||
|
||||
if currentSpec != nil && currentSpec!.isObj {
|
||||
key = container.currentSpec!.name
|
||||
}
|
||||
|
||||
container.codingPath += [AnyCodingKey(stringValue: key)!]
|
||||
nestedContainers[key] = container
|
||||
}
|
||||
} catch {
|
||||
fatalError("\(error)") // FIXME
|
||||
}
|
||||
|
||||
self.index = unkeyedContainer.index
|
||||
|
||||
return nestedContainers
|
||||
}()
|
||||
|
||||
lazy var count: Int? = {
|
||||
do {
|
||||
let format = try self.readByte()
|
||||
|
||||
if currentSpec != nil && currentSpec!.isObj && 0x90...0x9f ~= format {
|
||||
return Int(format & 0x0F)
|
||||
}
|
||||
|
||||
switch format {
|
||||
case 0x80...0x8f:
|
||||
return Int(format & 0x0F)
|
||||
case 0xde:
|
||||
return Int(try read(UInt16.self))
|
||||
case 0xdf:
|
||||
return Int(try read(UInt32.self))
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
|
||||
var data: Data
|
||||
var index: Data.Index
|
||||
var codingPath: [CodingKey]
|
||||
var userInfo: [CodingUserInfoKey: Any]
|
||||
var currentSpec: DataSpec?
|
||||
|
||||
func nestedCodingPath(forKey key: CodingKey) -> [CodingKey] {
|
||||
return self.codingPath + [key]
|
||||
}
|
||||
|
||||
init(data: Data, codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) {
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
self.data = data
|
||||
self.index = self.data.startIndex
|
||||
}
|
||||
|
||||
func checkCanDecodeValue(forKey key: Key) throws {
|
||||
guard self.contains(key) else {
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "key not found: \(key)")
|
||||
throw DecodingError.keyNotFound(key, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackDecoder.KeyedContainer: KeyedDecodingContainerProtocol {
|
||||
var allKeys: [Key] {
|
||||
return self.nestedContainers.keys.map{ Key(stringValue: $0)! }
|
||||
}
|
||||
|
||||
func contains(_ key: Key) -> Bool {
|
||||
return self.nestedContainers.keys.contains(key.stringValue)
|
||||
}
|
||||
|
||||
func decodeNil(forKey key: Key) throws -> Bool {
|
||||
try checkCanDecodeValue(forKey: key)
|
||||
|
||||
let nestedContainer = self.nestedContainers[key.stringValue]
|
||||
|
||||
switch nestedContainer {
|
||||
case let singleValueContainer as _MessagePackDecoder.SingleValueContainer:
|
||||
return singleValueContainer.decodeNil()
|
||||
case is _MessagePackDecoder.UnkeyedContainer,
|
||||
is _MessagePackDecoder.KeyedContainer<AnyCodingKey>:
|
||||
return false
|
||||
default:
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "cannot decode nil for key: \(key)")
|
||||
throw DecodingError.typeMismatch(Any?.self, context)
|
||||
}
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable {
|
||||
try checkCanDecodeValue(forKey: key)
|
||||
|
||||
let container = self.nestedContainers[key.stringValue]!
|
||||
let decoder = MessagePackDecoder()
|
||||
|
||||
if userInfo.keys.contains(MessagePackDecoder.dataSpecKey) {
|
||||
decoder.userInfo[MessagePackDecoder.dataSpecKey] = container.currentSpec!.dataSpecBuilder?.copy() as? DataSpecBuilder
|
||||
if container.currentSpec!.isArray {
|
||||
decoder.userInfo[MessagePackDecoder.isArrayDataSpecKey] = true
|
||||
}
|
||||
}
|
||||
|
||||
let value = try decoder.decode(T.self, from: container.data)
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
|
||||
try checkCanDecodeValue(forKey: key)
|
||||
|
||||
guard let unkeyedContainer = self.nestedContainers[key.stringValue] as? _MessagePackDecoder.UnkeyedContainer else {
|
||||
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "cannot decode nested container for key: \(key)")
|
||||
}
|
||||
|
||||
return unkeyedContainer
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
|
||||
try checkCanDecodeValue(forKey: key)
|
||||
|
||||
guard let keyedContainer = self.nestedContainers[key.stringValue] as? _MessagePackDecoder.KeyedContainer<NestedKey> else {
|
||||
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "cannot decode nested container for key: \(key)")
|
||||
}
|
||||
|
||||
return KeyedDecodingContainer(keyedContainer)
|
||||
}
|
||||
|
||||
func superDecoder() throws -> Decoder {
|
||||
return _MessagePackDecoder(data: self.data)
|
||||
}
|
||||
|
||||
func superDecoder(forKey key: Key) throws -> Decoder {
|
||||
let decoder = _MessagePackDecoder(data: self.data)
|
||||
decoder.codingPath = [key]
|
||||
|
||||
return decoder
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackDecoder.KeyedContainer: MessagePackDecodingContainer {}
|
||||
@@ -0,0 +1,168 @@
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
An object that decodes instances of a data type from MessagePack objects.
|
||||
*/
|
||||
final public class MessagePackDecoder {
|
||||
public init() {}
|
||||
|
||||
/**
|
||||
A dictionary you use to customize the decoding process
|
||||
by providing contextual information.
|
||||
*/
|
||||
public var userInfo: [CodingUserInfoKey : Any] = [:]
|
||||
|
||||
/**
|
||||
Returns a value of the type you specify,
|
||||
decoded from a MessagePack object.
|
||||
|
||||
- Parameters:
|
||||
- type: The type of the value to decode
|
||||
from the supplied MessagePack object.
|
||||
- data: The MessagePack object to decode.
|
||||
- Throws: `DecodingError.dataCorrupted(_:)`
|
||||
if the data is not valid MessagePack.
|
||||
*/
|
||||
public func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable {
|
||||
let decoder = _MessagePackDecoder(data: data)
|
||||
decoder.userInfo = self.userInfo
|
||||
decoder.userInfo[MessagePackDecoder.nonMatchingFloatDecodingStrategyKey] = nonMatchingFloatDecodingStrategy
|
||||
|
||||
switch type {
|
||||
case is Data.Type:
|
||||
let box = try Box<Data>(from: decoder)
|
||||
return box.value as! T
|
||||
case is Date.Type:
|
||||
let box = try Box<Date>(from: decoder)
|
||||
return box.value as! T
|
||||
default:
|
||||
return try T(from: decoder)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The strategy used by a decoder when it encounters format mismatches for floating point values.
|
||||
*/
|
||||
public var nonMatchingFloatDecodingStrategy: NonMatchingFloatDecodingStrategy = .strict
|
||||
|
||||
/**
|
||||
The strategies for decoding floating point values when their format doesn't match.
|
||||
*/
|
||||
public enum NonMatchingFloatDecodingStrategy {
|
||||
|
||||
/// Throws a DecodingError.typeMismatch
|
||||
case strict
|
||||
|
||||
/// Performs a cast
|
||||
case cast
|
||||
}
|
||||
|
||||
internal static var nonMatchingFloatDecodingStrategyKey: CodingUserInfoKey {
|
||||
return CodingUserInfoKey(rawValue: "nonMatchingFloatDecodingStrategyKey")!
|
||||
}
|
||||
|
||||
static var dataSpecKey : CodingUserInfoKey {
|
||||
return CodingUserInfoKey(rawValue: "dataSpecKey")!
|
||||
}
|
||||
|
||||
static var isArrayDataSpecKey : CodingUserInfoKey {
|
||||
return CodingUserInfoKey(rawValue: "isArrayDataSpecKey")!
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - TopLevelDecoder
|
||||
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
|
||||
extension MessagePackDecoder: TopLevelDecoder {
|
||||
public typealias Input = Data
|
||||
}
|
||||
#endif
|
||||
|
||||
// MARK: -
|
||||
|
||||
final class _MessagePackDecoder {
|
||||
var codingPath: [CodingKey] = []
|
||||
|
||||
var userInfo: [CodingUserInfoKey : Any] = [:]
|
||||
|
||||
var container: MessagePackDecodingContainer?
|
||||
fileprivate var data: Data
|
||||
|
||||
init(data: Data) {
|
||||
self.data = data
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackDecoder: Decoder {
|
||||
fileprivate func assertCanCreateContainer() {
|
||||
precondition(self.container == nil)
|
||||
}
|
||||
|
||||
func container<Key>(keyedBy type: Key.Type) -> KeyedDecodingContainer<Key> where Key : CodingKey {
|
||||
assertCanCreateContainer()
|
||||
|
||||
let container = KeyedContainer<Key>(data: self.data, codingPath: self.codingPath, userInfo: self.userInfo)
|
||||
|
||||
if userInfo.keys.contains(MessagePackDecoder.dataSpecKey) {
|
||||
container.currentSpec = DataSpec("", true, false, nil)
|
||||
}
|
||||
|
||||
self.container = container
|
||||
|
||||
return KeyedDecodingContainer(container)
|
||||
}
|
||||
|
||||
func unkeyedContainer() -> UnkeyedDecodingContainer {
|
||||
assertCanCreateContainer()
|
||||
|
||||
let container = UnkeyedContainer(data: self.data, codingPath: self.codingPath, userInfo: self.userInfo)
|
||||
self.container = container
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
func singleValueContainer() -> SingleValueDecodingContainer {
|
||||
assertCanCreateContainer()
|
||||
|
||||
let container = SingleValueContainer(data: self.data, codingPath: self.codingPath, userInfo: self.userInfo)
|
||||
self.container = container
|
||||
|
||||
return container
|
||||
}
|
||||
}
|
||||
|
||||
protocol MessagePackDecodingContainer: class {
|
||||
var codingPath: [CodingKey] { get set }
|
||||
|
||||
var userInfo: [CodingUserInfoKey : Any] { get }
|
||||
|
||||
var data: Data { get set }
|
||||
var index: Data.Index { get set }
|
||||
|
||||
var currentSpec: DataSpec? { get set }
|
||||
}
|
||||
|
||||
extension MessagePackDecodingContainer {
|
||||
func readByte() throws -> UInt8 {
|
||||
return try read(1).first!
|
||||
}
|
||||
|
||||
func read(_ length: Int) throws -> Data {
|
||||
let nextIndex = self.index.advanced(by: length)
|
||||
guard nextIndex <= self.data.endIndex else {
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Unexpected end of data")
|
||||
throw DecodingError.dataCorrupted(context)
|
||||
}
|
||||
defer { self.index = nextIndex }
|
||||
|
||||
return self.data.subdata(in: self.index..<nextIndex)
|
||||
}
|
||||
|
||||
func read<T>(_ type: T.Type) throws -> T where T : FixedWidthInteger {
|
||||
let stride = MemoryLayout<T>.stride
|
||||
let bytes = [UInt8](try read(stride))
|
||||
return T(bytes: bytes)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
import Foundation
|
||||
|
||||
#if os(Linux)
|
||||
let NSEC_PER_SEC: UInt64 = 1000000000
|
||||
#endif
|
||||
|
||||
extension _MessagePackDecoder {
|
||||
final class SingleValueContainer {
|
||||
var codingPath: [CodingKey]
|
||||
var userInfo: [CodingUserInfoKey: Any]
|
||||
var data: Data
|
||||
var index: Data.Index
|
||||
var currentSpec: DataSpec?
|
||||
|
||||
init(data: Data, codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) {
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
self.data = data
|
||||
self.index = self.data.startIndex
|
||||
}
|
||||
|
||||
func checkCanDecode<T>(_ type: T.Type, format: UInt8) throws {
|
||||
guard self.index <= self.data.endIndex else {
|
||||
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Unexpected end of data")
|
||||
}
|
||||
|
||||
guard self.data[self.index] == format else {
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)")
|
||||
throw DecodingError.typeMismatch(type, context)
|
||||
}
|
||||
}
|
||||
|
||||
var nonMatchingFloatDecodingStrategy: MessagePackDecoder.NonMatchingFloatDecodingStrategy {
|
||||
return userInfo[MessagePackDecoder.nonMatchingFloatDecodingStrategyKey] as? MessagePackDecoder.NonMatchingFloatDecodingStrategy ?? .strict
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackDecoder.SingleValueContainer: SingleValueDecodingContainer {
|
||||
func decodeNil() -> Bool {
|
||||
let format = try? readByte()
|
||||
return format == 0xc0
|
||||
}
|
||||
|
||||
func decode(_ type: Bool.Type) throws -> Bool {
|
||||
let format = try readByte()
|
||||
switch format {
|
||||
case 0xc2: return false
|
||||
case 0xc3: return true
|
||||
default:
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)")
|
||||
throw DecodingError.typeMismatch(Bool.self, context)
|
||||
}
|
||||
}
|
||||
|
||||
func decode(_ type: String.Type) throws -> String {
|
||||
let length: Int
|
||||
let format = try readByte()
|
||||
switch format {
|
||||
case 0xa0...0xbf:
|
||||
length = Int(format - 0xa0)
|
||||
case 0xd9:
|
||||
length = Int(try read(UInt8.self))
|
||||
case 0xda:
|
||||
length = Int(try read(UInt16.self))
|
||||
case 0xdb:
|
||||
length = Int(try read(UInt32.self))
|
||||
default:
|
||||
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Invalid format for String length: \(format)")
|
||||
}
|
||||
|
||||
let data = try read(length)
|
||||
guard let string = String(data: data, encoding: .utf8) else {
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Couldn't decode string with UTF-8 encoding")
|
||||
throw DecodingError.dataCorrupted(context)
|
||||
}
|
||||
|
||||
return string
|
||||
}
|
||||
|
||||
func decode(_ type: Double.Type) throws -> Double {
|
||||
let format = try readByte()
|
||||
switch format {
|
||||
case 0xca:
|
||||
switch nonMatchingFloatDecodingStrategy {
|
||||
case .strict:
|
||||
break
|
||||
case .cast:
|
||||
let bitPattern = try read(UInt32.self)
|
||||
return Double(Float(bitPattern: bitPattern))
|
||||
}
|
||||
case 0xcb:
|
||||
let bitPattern = try read(UInt64.self)
|
||||
return Double(bitPattern: bitPattern)
|
||||
default:
|
||||
break
|
||||
}
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)")
|
||||
throw DecodingError.typeMismatch(Double.self, context)
|
||||
}
|
||||
|
||||
func decode(_ type: Float.Type) throws -> Float {
|
||||
let format = try readByte()
|
||||
switch format {
|
||||
case 0xca:
|
||||
let bitPattern = try read(UInt32.self)
|
||||
return Float(bitPattern: bitPattern)
|
||||
case 0xcb:
|
||||
switch nonMatchingFloatDecodingStrategy {
|
||||
case .strict:
|
||||
break
|
||||
case .cast:
|
||||
let bitPattern = try read(UInt64.self)
|
||||
return Float(Double(bitPattern: bitPattern))
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)")
|
||||
throw DecodingError.typeMismatch(Float.self, context)
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type) throws -> T where T : BinaryInteger & Decodable {
|
||||
let format = try readByte()
|
||||
var t: T?
|
||||
|
||||
switch format {
|
||||
case 0x00...0x7f:
|
||||
t = T(format)
|
||||
case 0xcc:
|
||||
t = T(exactly: try read(UInt8.self))
|
||||
case 0xcd:
|
||||
t = T(exactly: try read(UInt16.self))
|
||||
case 0xce:
|
||||
t = T(exactly: try read(UInt32.self))
|
||||
case 0xcf:
|
||||
t = T(exactly: try read(UInt64.self))
|
||||
case 0xd0:
|
||||
t = T(exactly: try read(Int8.self))
|
||||
case 0xd1:
|
||||
t = T(exactly: try read(Int16.self))
|
||||
case 0xd2:
|
||||
t = T(exactly: try read(Int32.self))
|
||||
case 0xd3:
|
||||
t = T(exactly: try read(Int64.self))
|
||||
case 0xe0...0xff:
|
||||
t = T(exactly: Int8(bitPattern: format))
|
||||
default:
|
||||
t = nil
|
||||
}
|
||||
|
||||
guard let value = t else {
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)")
|
||||
throw DecodingError.typeMismatch(T.self, context)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func decode(_ type: Date.Type) throws -> Date {
|
||||
let format = try readByte()
|
||||
|
||||
var seconds: TimeInterval
|
||||
var nanoseconds: TimeInterval
|
||||
|
||||
switch format {
|
||||
case 0xd6:
|
||||
_ = try read(Int8.self) // -1
|
||||
nanoseconds = 0
|
||||
seconds = TimeInterval(try read(UInt32.self))
|
||||
case 0xd7:
|
||||
_ = try read(Int8.self) // -1
|
||||
let bitPattern = try read(UInt64.self)
|
||||
nanoseconds = TimeInterval(UInt32(bitPattern >> 34))
|
||||
seconds = TimeInterval(UInt32(bitPattern & 0x03_FF_FF_FF_FF))
|
||||
case 0xc7:
|
||||
_ = try read(Int8.self) // 12
|
||||
_ = try read(Int8.self) // -1
|
||||
nanoseconds = TimeInterval(try read(UInt32.self))
|
||||
seconds = TimeInterval(try read(Int64.self))
|
||||
default:
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)")
|
||||
throw DecodingError.typeMismatch(Date.self, context)
|
||||
}
|
||||
|
||||
let timeInterval = TimeInterval(seconds) + nanoseconds / Double(NSEC_PER_SEC)
|
||||
|
||||
return Date(timeIntervalSince1970: timeInterval)
|
||||
}
|
||||
|
||||
func decode(_ type: Data.Type) throws -> Data {
|
||||
let length: Int
|
||||
let format = try readByte()
|
||||
switch format {
|
||||
case 0xc4:
|
||||
length = Int(try read(UInt8.self))
|
||||
case 0xc5:
|
||||
length = Int(try read(UInt16.self))
|
||||
case 0xc6:
|
||||
length = Int(try read(UInt32.self))
|
||||
default:
|
||||
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Invalid format for Data length: \(format)")
|
||||
}
|
||||
|
||||
return self.data.subdata(in: self.index..<self.index.advanced(by: length))
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
|
||||
switch type {
|
||||
case is Data.Type:
|
||||
return try decode(Data.self) as! T
|
||||
case is Date.Type:
|
||||
return try decode(Date.self) as! T
|
||||
default:
|
||||
let decoder = _MessagePackDecoder(data: self.data)
|
||||
let value = try T(from: decoder)
|
||||
if let nextIndex = decoder.container?.index {
|
||||
self.index = nextIndex
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackDecoder.SingleValueContainer: MessagePackDecodingContainer {}
|
||||
@@ -0,0 +1,235 @@
|
||||
import Foundation
|
||||
|
||||
extension _MessagePackDecoder {
|
||||
final class UnkeyedContainer {
|
||||
var codingPath: [CodingKey]
|
||||
|
||||
var nestedCodingPath: [CodingKey] {
|
||||
return self.codingPath + [AnyCodingKey(intValue: self.count ?? 0)!]
|
||||
}
|
||||
|
||||
var userInfo: [CodingUserInfoKey: Any]
|
||||
|
||||
var data: Data
|
||||
var index: Data.Index
|
||||
var currentSpec: DataSpec?
|
||||
|
||||
lazy var count: Int? = {
|
||||
do {
|
||||
let format = try self.readByte()
|
||||
switch format {
|
||||
case 0x90...0x9f:
|
||||
return Int(format & 0x0F)
|
||||
case 0xdc:
|
||||
return Int(try read(UInt16.self))
|
||||
case 0xdd:
|
||||
return Int(try read(UInt32.self))
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
|
||||
var currentIndex: Int = 0
|
||||
|
||||
lazy var nestedContainers: [MessagePackDecodingContainer] = {
|
||||
guard let count = self.count else {
|
||||
return []
|
||||
}
|
||||
|
||||
var nestedContainers: [MessagePackDecodingContainer] = []
|
||||
|
||||
do {
|
||||
for _ in 0..<count {
|
||||
let container = try self.decodeContainer()
|
||||
nestedContainers.append(container)
|
||||
}
|
||||
} catch {
|
||||
fatalError("\(error)") // FIXME
|
||||
}
|
||||
|
||||
self.currentIndex = 0
|
||||
|
||||
return nestedContainers
|
||||
}()
|
||||
|
||||
init(data: Data, codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) {
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
self.data = data
|
||||
self.index = self.data.startIndex
|
||||
}
|
||||
|
||||
var isAtEnd: Bool {
|
||||
guard let count = self.count else {
|
||||
return true
|
||||
}
|
||||
|
||||
return currentIndex >= count
|
||||
}
|
||||
|
||||
func checkCanDecodeValue() throws {
|
||||
guard !self.isAtEnd else {
|
||||
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Unexpected end of data")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackDecoder.UnkeyedContainer: UnkeyedDecodingContainer {
|
||||
func decodeNil() throws -> Bool {
|
||||
try checkCanDecodeValue()
|
||||
defer { self.currentIndex += 1 }
|
||||
|
||||
let nestedContainer = self.nestedContainers[self.currentIndex]
|
||||
|
||||
switch nestedContainer {
|
||||
case let singleValueContainer as _MessagePackDecoder.SingleValueContainer:
|
||||
return singleValueContainer.decodeNil()
|
||||
case is _MessagePackDecoder.UnkeyedContainer,
|
||||
is _MessagePackDecoder.KeyedContainer<AnyCodingKey>:
|
||||
return false
|
||||
default:
|
||||
let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "cannot decode nil for index: \(self.currentIndex)")
|
||||
throw DecodingError.typeMismatch(Any?.self, context)
|
||||
}
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
|
||||
try checkCanDecodeValue()
|
||||
defer { self.currentIndex += 1 }
|
||||
|
||||
if userInfo.keys.contains(MessagePackDecoder.isArrayDataSpecKey) {
|
||||
currentSpec = DataSpec("", false, true, (userInfo[MessagePackDecoder.dataSpecKey] as? DataSpecBuilder)?.copy() as? DataSpecBuilder)
|
||||
}
|
||||
|
||||
let container = self.nestedContainers[self.currentIndex]
|
||||
let decoder = MessagePackDecoder()
|
||||
|
||||
if userInfo.keys.contains(MessagePackDecoder.dataSpecKey) {
|
||||
decoder.userInfo[MessagePackDecoder.dataSpecKey] = (userInfo[MessagePackDecoder.dataSpecKey] as? DataSpecBuilder)?.copy() as? DataSpecBuilder
|
||||
}
|
||||
|
||||
let value = try decoder.decode(T.self, from: container.data)
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
|
||||
try checkCanDecodeValue()
|
||||
defer { self.currentIndex += 1 }
|
||||
|
||||
let container = self.nestedContainers[self.currentIndex] as! _MessagePackDecoder.UnkeyedContainer
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
|
||||
try checkCanDecodeValue()
|
||||
defer { self.currentIndex += 1 }
|
||||
|
||||
let container = self.nestedContainers[self.currentIndex] as! _MessagePackDecoder.KeyedContainer<NestedKey>
|
||||
|
||||
return KeyedDecodingContainer(container)
|
||||
}
|
||||
|
||||
func superDecoder() throws -> Decoder {
|
||||
return _MessagePackDecoder(data: self.data)
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackDecoder.UnkeyedContainer {
|
||||
func decodeContainer() throws -> MessagePackDecodingContainer {
|
||||
try checkCanDecodeValue()
|
||||
defer { self.currentIndex += 1 }
|
||||
|
||||
let startIndex = self.index
|
||||
|
||||
var currDataSpec: DataSpec? = nil
|
||||
if currentSpec != nil && currentSpec!.isArray && currentSpec!.dataSpecBuilder != nil {
|
||||
currDataSpec = DataSpec("", true, false, currentSpec!.dataSpecBuilder!.copy() as? DataSpecBuilder)
|
||||
} else {
|
||||
let dataSpec = self.userInfo[MessagePackDecoder.dataSpecKey] as? DataSpecBuilder
|
||||
if let currDS = dataSpec?.next() {
|
||||
currDataSpec = DataSpec(currDS.name, currDS.isObj, currDS.isArray, currDS.dataSpecBuilder?.copy() as? DataSpecBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
let length: Int
|
||||
let format = try self.readByte()
|
||||
switch format {
|
||||
case 0x00...0x7f,
|
||||
0xc0, 0xc2, 0xc3,
|
||||
0xe0...0xff:
|
||||
length = 0
|
||||
case 0xcc, 0xd0, 0xd4:
|
||||
length = 1
|
||||
case 0xcd, 0xd1, 0xd5:
|
||||
length = 2
|
||||
case 0xca, 0xce, 0xd2:
|
||||
length = 4
|
||||
case 0xcb, 0xcf, 0xd3:
|
||||
length = 8
|
||||
case 0xd6:
|
||||
length = 5
|
||||
case 0xd7:
|
||||
length = 9
|
||||
case 0xd8:
|
||||
length = 16
|
||||
case 0xa0...0xbf:
|
||||
length = Int(format - 0xa0)
|
||||
case 0xc4, 0xc7, 0xd9:
|
||||
length = Int(try read(UInt8.self))
|
||||
case 0xc5, 0xc8, 0xda:
|
||||
length = Int(try read(UInt16.self))
|
||||
case 0xc6, 0xc9, 0xdb:
|
||||
length = Int(try read(UInt32.self))
|
||||
case 0x80...0x8f, 0xde, 0xdf:
|
||||
let container = _MessagePackDecoder.KeyedContainer<AnyCodingKey>(data: self.data.suffix(from: startIndex), codingPath: self.nestedCodingPath, userInfo: self.userInfo)
|
||||
container.currentSpec = currDataSpec
|
||||
_ = container.nestedContainers // FIXME
|
||||
self.index = container.index
|
||||
|
||||
return container
|
||||
case 0x90...0x9f, 0xdc, 0xdd:
|
||||
if currDataSpec != nil && currDataSpec!.isObj {
|
||||
var objUserInfo = self.userInfo
|
||||
objUserInfo[MessagePackDecoder.dataSpecKey] = currDataSpec!.dataSpecBuilder!
|
||||
|
||||
let container = _MessagePackDecoder.KeyedContainer<AnyCodingKey>(data: self.data.suffix(from: startIndex), codingPath: self.nestedCodingPath, userInfo: objUserInfo)
|
||||
container.currentSpec = currDataSpec
|
||||
_ = container.nestedContainers // FIXME
|
||||
self.index = container.index
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
var arrUserInfo = self.userInfo
|
||||
if currDataSpec != nil && currDataSpec!.isArray {
|
||||
arrUserInfo[MessagePackDecoder.dataSpecKey] = currDataSpec!.dataSpecBuilder!
|
||||
}
|
||||
|
||||
let container = _MessagePackDecoder.UnkeyedContainer(data: self.data.suffix(from: startIndex), codingPath: self.nestedCodingPath, userInfo: arrUserInfo)
|
||||
container.currentSpec = currDataSpec
|
||||
_ = container.nestedContainers // FIXME
|
||||
|
||||
self.index = container.index
|
||||
|
||||
return container
|
||||
default:
|
||||
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Invalid format: \(format)")
|
||||
}
|
||||
|
||||
let range: Range<Data.Index> = startIndex..<self.index.advanced(by: length)
|
||||
self.index = range.upperBound
|
||||
|
||||
let container = _MessagePackDecoder.SingleValueContainer(data: self.data.subdata(in: range), codingPath: self.codingPath, userInfo: self.userInfo)
|
||||
container.currentSpec = currDataSpec
|
||||
|
||||
return container
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackDecoder.UnkeyedContainer: MessagePackDecodingContainer {}
|
||||
@@ -0,0 +1,90 @@
|
||||
import Foundation
|
||||
|
||||
extension _MessagePackEncoder {
|
||||
final class KeyedContainer<Key> where Key: CodingKey {
|
||||
private var storage: [AnyCodingKey: _MessagePackEncodingContainer] = [:]
|
||||
|
||||
var codingPath: [CodingKey]
|
||||
var userInfo: [CodingUserInfoKey: Any]
|
||||
|
||||
func nestedCodingPath(forKey key: CodingKey) -> [CodingKey] {
|
||||
return self.codingPath + [key]
|
||||
}
|
||||
|
||||
init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) {
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackEncoder.KeyedContainer: KeyedEncodingContainerProtocol {
|
||||
func encodeNil(forKey key: Key) throws {
|
||||
var container = self.nestedSingleValueContainer(forKey: key)
|
||||
try container.encodeNil()
|
||||
}
|
||||
|
||||
func encode<T>(_ value: T, forKey key: Key) throws where T : Encodable {
|
||||
var container = self.nestedSingleValueContainer(forKey: key)
|
||||
try container.encode(value)
|
||||
}
|
||||
|
||||
private func nestedSingleValueContainer(forKey key: Key) -> SingleValueEncodingContainer {
|
||||
let container = _MessagePackEncoder.SingleValueContainer(codingPath: self.nestedCodingPath(forKey: key), userInfo: self.userInfo)
|
||||
self.storage[AnyCodingKey(key)] = container
|
||||
return container
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
|
||||
let container = _MessagePackEncoder.UnkeyedContainer(codingPath: self.nestedCodingPath(forKey: key), userInfo: self.userInfo)
|
||||
self.storage[AnyCodingKey(key)] = container
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> where NestedKey : CodingKey {
|
||||
let container = _MessagePackEncoder.KeyedContainer<NestedKey>(codingPath: self.nestedCodingPath(forKey: key), userInfo: self.userInfo)
|
||||
self.storage[AnyCodingKey(key)] = container
|
||||
|
||||
return KeyedEncodingContainer(container)
|
||||
}
|
||||
|
||||
func superEncoder() -> Encoder {
|
||||
fatalError("Unimplemented") // FIXME
|
||||
}
|
||||
|
||||
func superEncoder(forKey key: Key) -> Encoder {
|
||||
fatalError("Unimplemented") // FIXME
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackEncoder.KeyedContainer: _MessagePackEncodingContainer {
|
||||
var data: Data {
|
||||
var data = Data()
|
||||
|
||||
let length = storage.count
|
||||
if let uint16 = UInt16(exactly: length) {
|
||||
if length <= 15 {
|
||||
data.append(0x80 + UInt8(length))
|
||||
} else {
|
||||
data.append(0xde)
|
||||
data.append(contentsOf: uint16.bytes)
|
||||
}
|
||||
} else if let uint32 = UInt32(exactly: length) {
|
||||
data.append(0xdf)
|
||||
data.append(contentsOf: uint32.bytes)
|
||||
} else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
for (key, container) in self.storage {
|
||||
let keyContainer = _MessagePackEncoder.SingleValueContainer(codingPath: self.codingPath, userInfo: self.userInfo)
|
||||
try! keyContainer.encode(key.stringValue)
|
||||
data.append(keyContainer.data)
|
||||
|
||||
data.append(container.data)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
An object that encodes instances of a data type as MessagePack objects.
|
||||
*/
|
||||
final public class MessagePackEncoder {
|
||||
public init() {}
|
||||
|
||||
/**
|
||||
A dictionary you use to customize the encoding process
|
||||
by providing contextual information.
|
||||
*/
|
||||
public var userInfo: [CodingUserInfoKey : Any] = [:]
|
||||
|
||||
/**
|
||||
Returns a MessagePack-encoded representation of the value you supply.
|
||||
|
||||
- Parameters:
|
||||
- value: The value to encode as MessagePack.
|
||||
- Throws: `EncodingError.invalidValue(_:_:)`
|
||||
if the value can't be encoded as a MessagePack object.
|
||||
*/
|
||||
public func encode<T>(_ value: T) throws -> Data where T : Encodable {
|
||||
let encoder = _MessagePackEncoder()
|
||||
encoder.userInfo = self.userInfo
|
||||
|
||||
switch value {
|
||||
case let data as Data:
|
||||
try Box<Data>(data).encode(to: encoder)
|
||||
case let date as Date:
|
||||
try Box<Date>(date).encode(to: encoder)
|
||||
default:
|
||||
try value.encode(to: encoder)
|
||||
}
|
||||
|
||||
return encoder.data
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - TopLevelEncoder
|
||||
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
|
||||
extension MessagePackEncoder: TopLevelEncoder {
|
||||
public typealias Input = Data
|
||||
}
|
||||
#endif
|
||||
|
||||
// MARK: -
|
||||
|
||||
protocol _MessagePackEncodingContainer {
|
||||
var data: Data { get }
|
||||
}
|
||||
|
||||
class _MessagePackEncoder {
|
||||
var codingPath: [CodingKey] = []
|
||||
|
||||
var userInfo: [CodingUserInfoKey : Any] = [:]
|
||||
|
||||
fileprivate var container: _MessagePackEncodingContainer?
|
||||
|
||||
var data: Data {
|
||||
return container?.data ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackEncoder: Encoder {
|
||||
fileprivate func assertCanCreateContainer() {
|
||||
precondition(self.container == nil)
|
||||
}
|
||||
|
||||
func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key : CodingKey {
|
||||
assertCanCreateContainer()
|
||||
|
||||
let container = KeyedContainer<Key>(codingPath: self.codingPath, userInfo: self.userInfo)
|
||||
self.container = container
|
||||
|
||||
return KeyedEncodingContainer(container)
|
||||
}
|
||||
|
||||
func unkeyedContainer() -> UnkeyedEncodingContainer {
|
||||
assertCanCreateContainer()
|
||||
|
||||
let container = UnkeyedContainer(codingPath: self.codingPath, userInfo: self.userInfo)
|
||||
self.container = container
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
func singleValueContainer() -> SingleValueEncodingContainer {
|
||||
assertCanCreateContainer()
|
||||
|
||||
let container = SingleValueContainer(codingPath: self.codingPath, userInfo: self.userInfo)
|
||||
self.container = container
|
||||
|
||||
return container
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
import Foundation
|
||||
|
||||
extension _MessagePackEncoder {
|
||||
final class SingleValueContainer {
|
||||
private var storage: Data = Data()
|
||||
|
||||
fileprivate var canEncodeNewValue = true
|
||||
fileprivate func checkCanEncode(value: Any?) throws {
|
||||
guard self.canEncodeNewValue else {
|
||||
let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Attempt to encode value through single value container when previously value already encoded.")
|
||||
throw EncodingError.invalidValue(value as Any, context)
|
||||
}
|
||||
}
|
||||
|
||||
var codingPath: [CodingKey]
|
||||
var userInfo: [CodingUserInfoKey: Any]
|
||||
|
||||
init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) {
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackEncoder.SingleValueContainer: SingleValueEncodingContainer {
|
||||
func encodeNil() throws {
|
||||
try checkCanEncode(value: nil)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
self.storage.append(0xc0)
|
||||
}
|
||||
|
||||
func encode(_ value: Bool) throws {
|
||||
try checkCanEncode(value: nil)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
switch value {
|
||||
case false:
|
||||
self.storage.append(0xc2)
|
||||
case true:
|
||||
self.storage.append(0xc3)
|
||||
}
|
||||
}
|
||||
|
||||
func encode(_ value: String) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
guard let data = value.data(using: .utf8) else {
|
||||
let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Cannot encode string using UTF-8 encoding.")
|
||||
throw EncodingError.invalidValue(value, context)
|
||||
}
|
||||
|
||||
let length = data.count
|
||||
if let uint8 = UInt8(exactly: length) {
|
||||
if (uint8 <= 31) {
|
||||
self.storage.append(0xa0 + uint8)
|
||||
} else {
|
||||
self.storage.append(0xd9)
|
||||
self.storage.append(contentsOf: uint8.bytes)
|
||||
}
|
||||
} else if let uint16 = UInt16(exactly: length) {
|
||||
self.storage.append(0xda)
|
||||
self.storage.append(contentsOf: uint16.bytes)
|
||||
} else if let uint32 = UInt32(exactly: length) {
|
||||
self.storage.append(0xdb)
|
||||
self.storage.append(contentsOf: uint32.bytes)
|
||||
} else {
|
||||
let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Cannot encode string with length \(length).")
|
||||
throw EncodingError.invalidValue(value, context)
|
||||
}
|
||||
|
||||
self.storage.append(data)
|
||||
}
|
||||
|
||||
func encode(_ value: Double) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
self.storage.append(0xcb)
|
||||
self.storage.append(contentsOf: value.bitPattern.bytes)
|
||||
}
|
||||
|
||||
func encode(_ value: Float) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
self.storage.append(0xca)
|
||||
self.storage.append(contentsOf: value.bitPattern.bytes)
|
||||
}
|
||||
|
||||
func encode<T>(_ value: T) throws where T : BinaryInteger & Encodable {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
if value < 0 {
|
||||
if let int8 = Int8(exactly: value) {
|
||||
return try encode(int8)
|
||||
} else if let int16 = Int16(exactly: value) {
|
||||
return try encode(int16)
|
||||
} else if let int32 = Int32(exactly: value) {
|
||||
return try encode(int32)
|
||||
} else if let int64 = Int64(exactly: value) {
|
||||
return try encode(int64)
|
||||
}
|
||||
} else {
|
||||
if let uint8 = UInt8(exactly: value) {
|
||||
return try encode(uint8)
|
||||
} else if let uint16 = UInt16(exactly: value) {
|
||||
return try encode(uint16)
|
||||
} else if let uint32 = UInt32(exactly: value) {
|
||||
return try encode(uint32)
|
||||
} else if let uint64 = UInt64(exactly: value) {
|
||||
return try encode(uint64)
|
||||
}
|
||||
}
|
||||
|
||||
let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Cannot encode integer \(value).")
|
||||
throw EncodingError.invalidValue(value, context)
|
||||
}
|
||||
|
||||
func encode(_ value: Int8) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
if (value >= 0 && value <= 127) {
|
||||
self.storage.append(UInt8(value))
|
||||
} else if (value < 0 && value >= -31) {
|
||||
self.storage.append(0xe0 + (0x1f & UInt8(truncatingIfNeeded: value)))
|
||||
} else {
|
||||
self.storage.append(0xd0)
|
||||
self.storage.append(contentsOf: value.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
func encode(_ value: Int16) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
self.storage.append(0xd1)
|
||||
self.storage.append(contentsOf: value.bytes)
|
||||
}
|
||||
|
||||
func encode(_ value: Int32) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
self.storage.append(0xd2)
|
||||
self.storage.append(contentsOf: value.bytes)
|
||||
}
|
||||
|
||||
func encode(_ value: Int64) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
self.storage.append(0xd3)
|
||||
self.storage.append(contentsOf: value.bytes)
|
||||
}
|
||||
|
||||
func encode(_ value: UInt8) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
if (value <= 127) {
|
||||
self.storage.append(value)
|
||||
} else {
|
||||
self.storage.append(0xcc)
|
||||
self.storage.append(contentsOf: value.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
func encode(_ value: UInt16) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
self.storage.append(0xcd)
|
||||
self.storage.append(contentsOf: value.bytes)
|
||||
}
|
||||
|
||||
func encode(_ value: UInt32) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
self.storage.append(0xce)
|
||||
self.storage.append(contentsOf: value.bytes)
|
||||
}
|
||||
|
||||
func encode(_ value: UInt64) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
self.storage.append(0xcf)
|
||||
self.storage.append(contentsOf: value.bytes)
|
||||
}
|
||||
|
||||
func encode(_ value: Date) throws {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
let timeInterval = value.timeIntervalSince1970
|
||||
let (integral, fractional) = modf(timeInterval)
|
||||
|
||||
let seconds = Int64(integral)
|
||||
let nanoseconds = UInt32(fractional * Double(NSEC_PER_SEC))
|
||||
|
||||
if seconds < 0 || seconds > UInt32.max {
|
||||
self.storage.append(0xc7)
|
||||
self.storage.append(0x0C)
|
||||
self.storage.append(0xFF)
|
||||
self.storage.append(contentsOf: nanoseconds.bytes)
|
||||
self.storage.append(contentsOf: seconds.bytes)
|
||||
} else if nanoseconds > 0 {
|
||||
self.storage.append(0xd7)
|
||||
self.storage.append(0xFF)
|
||||
self.storage.append(contentsOf: ((UInt64(nanoseconds) << 34) + UInt64(seconds)).bytes)
|
||||
} else {
|
||||
self.storage.append(0xd6)
|
||||
self.storage.append(0xFF)
|
||||
self.storage.append(contentsOf: UInt32(seconds).bytes)
|
||||
}
|
||||
}
|
||||
|
||||
func encode(_ value: Data) throws {
|
||||
let length = value.count
|
||||
if let uint8 = UInt8(exactly: length) {
|
||||
self.storage.append(0xc4)
|
||||
self.storage.append(uint8)
|
||||
self.storage.append(value)
|
||||
} else if let uint16 = UInt16(exactly: length) {
|
||||
self.storage.append(0xc5)
|
||||
self.storage.append(contentsOf: uint16.bytes)
|
||||
self.storage.append(value)
|
||||
} else if let uint32 = UInt32(exactly: length) {
|
||||
self.storage.append(0xc6)
|
||||
self.storage.append(contentsOf: uint32.bytes)
|
||||
self.storage.append(value)
|
||||
} else {
|
||||
let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Cannot encode data of length \(value.count).")
|
||||
throw EncodingError.invalidValue(value, context)
|
||||
}
|
||||
}
|
||||
|
||||
func encode<T>(_ value: T) throws where T : Encodable {
|
||||
try checkCanEncode(value: value)
|
||||
defer { self.canEncodeNewValue = false }
|
||||
|
||||
switch value {
|
||||
case let data as Data:
|
||||
try self.encode(data)
|
||||
case let date as Date:
|
||||
try self.encode(date)
|
||||
default:
|
||||
let encoder = _MessagePackEncoder()
|
||||
try value.encode(to: encoder)
|
||||
self.storage.append(encoder.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackEncoder.SingleValueContainer: _MessagePackEncodingContainer {
|
||||
var data: Data {
|
||||
return storage
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import Foundation
|
||||
|
||||
extension _MessagePackEncoder {
|
||||
final class UnkeyedContainer {
|
||||
private var storage: [_MessagePackEncodingContainer] = []
|
||||
|
||||
var count: Int {
|
||||
return storage.count
|
||||
}
|
||||
|
||||
var codingPath: [CodingKey]
|
||||
|
||||
var nestedCodingPath: [CodingKey] {
|
||||
return self.codingPath + [AnyCodingKey(intValue: self.count)!]
|
||||
}
|
||||
|
||||
var userInfo: [CodingUserInfoKey: Any]
|
||||
|
||||
init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) {
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackEncoder.UnkeyedContainer: UnkeyedEncodingContainer {
|
||||
func encodeNil() throws {
|
||||
var container = self.nestedSingleValueContainer()
|
||||
try container.encodeNil()
|
||||
}
|
||||
|
||||
func encode<T>(_ value: T) throws where T : Encodable {
|
||||
var container = self.nestedSingleValueContainer()
|
||||
try container.encode(value)
|
||||
}
|
||||
|
||||
private func nestedSingleValueContainer() -> SingleValueEncodingContainer {
|
||||
let container = _MessagePackEncoder.SingleValueContainer(codingPath: self.nestedCodingPath, userInfo: self.userInfo)
|
||||
self.storage.append(container)
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> where NestedKey : CodingKey {
|
||||
let container = _MessagePackEncoder.KeyedContainer<NestedKey>(codingPath: self.nestedCodingPath, userInfo: self.userInfo)
|
||||
self.storage.append(container)
|
||||
|
||||
return KeyedEncodingContainer(container)
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
|
||||
let container = _MessagePackEncoder.UnkeyedContainer(codingPath: self.nestedCodingPath, userInfo: self.userInfo)
|
||||
self.storage.append(container)
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
func superEncoder() -> Encoder {
|
||||
fatalError("Unimplemented") // FIXME
|
||||
}
|
||||
}
|
||||
|
||||
extension _MessagePackEncoder.UnkeyedContainer: _MessagePackEncodingContainer {
|
||||
var data: Data {
|
||||
var data = Data()
|
||||
|
||||
let length = storage.count
|
||||
if let uint16 = UInt16(exactly: length) {
|
||||
if uint16 <= 15 {
|
||||
data.append(UInt8(0x90 + uint16))
|
||||
} else {
|
||||
data.append(0xdc)
|
||||
data.append(contentsOf: uint16.bytes)
|
||||
}
|
||||
} else if let uint32 = UInt32(exactly: length) {
|
||||
data.append(0xdd)
|
||||
data.append(contentsOf: uint32.bytes)
|
||||
} else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
for container in storage {
|
||||
data.append(container.data)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
extension FixedWidthInteger {
|
||||
init(bytes: [UInt8]) {
|
||||
self = bytes.withUnsafeBufferPointer {
|
||||
$0.baseAddress!.withMemoryRebound(to: Self.self, capacity: 1) {
|
||||
$0.pointee
|
||||
}
|
||||
}.bigEndian
|
||||
}
|
||||
|
||||
var bytes: [UInt8] {
|
||||
let capacity = MemoryLayout<Self>.size
|
||||
var mutableValue = self.bigEndian
|
||||
return withUnsafePointer(to: &mutableValue) {
|
||||
return $0.withMemoryRebound(to: UInt8.self, capacity: capacity) {
|
||||
return Array(UnsafeBufferPointer(start: $0, count: capacity))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
lib/MessagePack/Tests/LinuxMain.swift
Normal file
8
lib/MessagePack/Tests/LinuxMain.swift
Normal file
@@ -0,0 +1,8 @@
|
||||
import XCTest
|
||||
@testable import MessagePackTests
|
||||
|
||||
XCTMain([
|
||||
testCase(MessagePackDecodingTests.allTests),
|
||||
testCase(MessagePackEncodingTests.allTests),
|
||||
testCase(MessagePackRoundTripTests.allTests),
|
||||
])
|
||||
63
lib/MessagePack/Tests/MessagePackTests/Airport.swift
Normal file
63
lib/MessagePack/Tests/MessagePackTests/Airport.swift
Normal file
@@ -0,0 +1,63 @@
|
||||
struct Airport: Codable, Equatable {
|
||||
let name: String
|
||||
let iata: String
|
||||
let icao: String
|
||||
let coordinates: [Double]
|
||||
|
||||
struct Runway: Codable, Equatable {
|
||||
enum Surface: String, Codable, Equatable {
|
||||
case rigid, flexible, gravel, sealed, unpaved, other
|
||||
}
|
||||
|
||||
let direction: String
|
||||
let distance: Int
|
||||
let surface: Surface
|
||||
}
|
||||
|
||||
let runways: [Runway]
|
||||
|
||||
let instrumentApproachProcedures: [String]
|
||||
|
||||
static var example: Airport {
|
||||
return Airport(
|
||||
name: "Portland International Airport",
|
||||
iata: "PDX",
|
||||
icao: "KPDX",
|
||||
coordinates: [-122.5975,
|
||||
45.5886111111111],
|
||||
runways: [
|
||||
Airport.Runway(
|
||||
direction: "3/21",
|
||||
distance: 1829,
|
||||
surface: .flexible
|
||||
)
|
||||
],
|
||||
instrumentApproachProcedures: [
|
||||
"HI-ILS OR LOC RWY 28",
|
||||
"HI-ILS OR LOC/DME RWY 10",
|
||||
"ILS OR LOC RWY 10L",
|
||||
"ILS OR LOC RWY 10R",
|
||||
"ILS OR LOC RWY 28L",
|
||||
"ILS OR LOC RWY 28R",
|
||||
"ILS RWY 10R (SA CAT I)",
|
||||
"ILS RWY 10R (CAT II - III)",
|
||||
"RNAV (RNP) Y RWY 28L",
|
||||
"RNAV (RNP) Y RWY 28R",
|
||||
"RNAV (RNP) Z RWY 10L",
|
||||
"RNAV (RNP) Z RWY 10R",
|
||||
"RNAV (RNP) Z RWY 28L",
|
||||
"RNAV (RNP) Z RWY 28R",
|
||||
"RNAV (GPS) X RWY 28L",
|
||||
"RNAV (GPS) X RWY 28R",
|
||||
"RNAV (GPS) Y RWY 10L",
|
||||
"RNAV (GPS) Y RWY 10R",
|
||||
"LOC/DME RWY 21",
|
||||
"VOR-A",
|
||||
"HI-TACAN RWY 10",
|
||||
"TACAN RWY 28",
|
||||
"COLUMBIA VISUAL RWY 10L/",
|
||||
"MILL VISUAL RWY 28L/R"
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
import XCTest
|
||||
@testable import MessagePack
|
||||
|
||||
class MessagePackDecodingTests: XCTestCase {
|
||||
var decoder: MessagePackDecoder!
|
||||
|
||||
override func setUp() {
|
||||
self.decoder = MessagePackDecoder()
|
||||
}
|
||||
|
||||
func assertTypeMismatch<T>(_ expression: @autoclosure () throws -> T,
|
||||
_ message: @autoclosure () -> String = "",
|
||||
file: StaticString = #file,
|
||||
line: UInt = #line) -> Any.Type? {
|
||||
var error: Error?
|
||||
XCTAssertThrowsError(expression, message,
|
||||
file: file, line: line) {
|
||||
error = $0
|
||||
}
|
||||
guard case .typeMismatch(let type, _) = error as? DecodingError else {
|
||||
XCTFail(file: file, line: line)
|
||||
return nil
|
||||
}
|
||||
return type
|
||||
}
|
||||
|
||||
func testDecodeNil() {
|
||||
let data = Data(bytes: [0xC0])
|
||||
let value = try! decoder.decode(Int?.self, from: data)
|
||||
XCTAssertNil(value)
|
||||
}
|
||||
|
||||
func testDecodeFalse() {
|
||||
let data = Data(bytes: [0xc2])
|
||||
let value = try! decoder.decode(Bool.self, from: data)
|
||||
XCTAssertEqual(value, false)
|
||||
}
|
||||
|
||||
func testDecodeTrue() {
|
||||
let data = Data(bytes: [0xc3])
|
||||
let value = try! decoder.decode(Bool.self, from: data)
|
||||
XCTAssertEqual(value, true)
|
||||
}
|
||||
|
||||
func testDecodeInt() {
|
||||
let data = Data(bytes: [0x2A])
|
||||
let value = try! decoder.decode(Int.self, from: data)
|
||||
XCTAssertEqual(value, 42)
|
||||
}
|
||||
|
||||
func testDecodeNegativeInt() {
|
||||
let data = Data(bytes: [0xFF])
|
||||
let value = try! decoder.decode(Int.self, from: data)
|
||||
XCTAssertEqual(value, -1)
|
||||
}
|
||||
|
||||
func testDecodeUInt() {
|
||||
let data = Data(bytes: [0xCC, 0x80])
|
||||
let value = try! decoder.decode(Int.self, from: data)
|
||||
XCTAssertEqual(value, 128)
|
||||
}
|
||||
|
||||
func testDecodeFloat() {
|
||||
let data = Data(bytes: [0xCA, 0x40, 0x48, 0xF5, 0xC3])
|
||||
let value = try! decoder.decode(Float.self, from: data)
|
||||
XCTAssertEqual(value, 3.14)
|
||||
}
|
||||
|
||||
func testDecodeFloatToDouble() {
|
||||
let data = Data(bytes: [0xCA, 0x40, 0x48, 0xF5, 0xC3])
|
||||
let type = assertTypeMismatch(try decoder.decode(Double.self, from: data))
|
||||
XCTAssertTrue(type is Double.Type)
|
||||
decoder.nonMatchingFloatDecodingStrategy = .cast
|
||||
let value = try! decoder.decode(Double.self, from: data)
|
||||
XCTAssertEqual(value, 3.14, accuracy: 1e-6)
|
||||
}
|
||||
|
||||
func testDecodeDouble() {
|
||||
let data = Data(bytes: [0xCB, 0x40, 0x09, 0x21, 0xF9, 0xF0, 0x1B, 0x86, 0x6E])
|
||||
let value = try! decoder.decode(Double.self, from: data)
|
||||
XCTAssertEqual(value, 3.14159)
|
||||
}
|
||||
|
||||
func testDecodeDoubleToFloat() {
|
||||
let data = Data(bytes: [0xCB, 0x40, 0x09, 0x21, 0xF9, 0xF0, 0x1B, 0x86, 0x6E])
|
||||
let type = assertTypeMismatch(try decoder.decode(Float.self, from: data))
|
||||
XCTAssertTrue(type is Float.Type)
|
||||
decoder.nonMatchingFloatDecodingStrategy = .cast
|
||||
let value = try! decoder.decode(Float.self, from: data)
|
||||
XCTAssertEqual(value, 3.14159)
|
||||
}
|
||||
|
||||
func testDecodeFixedArray() {
|
||||
let data = Data(bytes: [0x93, 0x01, 0x02, 0x03])
|
||||
let value = try! decoder.decode([Int].self, from: data)
|
||||
XCTAssertEqual(value, [1, 2, 3])
|
||||
}
|
||||
|
||||
func testDecodeVariableArray() {
|
||||
let data = Data(bytes: [0xdc] + [0x00, 0x10] + Array(0x01...0x10))
|
||||
let value = try! decoder.decode([Int].self, from: data)
|
||||
XCTAssertEqual(value, Array(1...16))
|
||||
}
|
||||
|
||||
func testDecodeFixedDictionary() {
|
||||
let data = Data(bytes: [0x83, 0xA1, 0x62, 0x02, 0xA1, 0x61, 0x01, 0xA1, 0x63, 0x03])
|
||||
let value = try! decoder.decode([String: Int].self, from: data)
|
||||
XCTAssertEqual(value, ["a": 1, "b": 2, "c": 3])
|
||||
}
|
||||
|
||||
func testDecodeData() {
|
||||
let data = Data(bytes: [0xC4, 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F])
|
||||
let value = try! decoder.decode(Data.self, from: data)
|
||||
XCTAssertEqual(value, "hello".data(using: .utf8))
|
||||
}
|
||||
|
||||
func testDecodeDate() {
|
||||
let data = Data(bytes: [0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01])
|
||||
let date = Date(timeIntervalSince1970: 1)
|
||||
let value = try! decoder.decode(Date.self, from: data)
|
||||
XCTAssertEqual(value, date)
|
||||
}
|
||||
|
||||
func testDecodeDistantPast() {
|
||||
let data = Data(bytes: [0xC7, 0x0C, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF1, 0x88, 0x6B, 0x66, 0x00])
|
||||
let date = Date.distantPast
|
||||
let value = try! decoder.decode(Date.self, from: data)
|
||||
XCTAssertEqual(value, date)
|
||||
}
|
||||
|
||||
func testDecodeDistantFuture() {
|
||||
let data = Data(bytes: [0xC7, 0x0C, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xEC, 0x31, 0x88, 0x00])
|
||||
let date = Date.distantFuture
|
||||
let value = try! decoder.decode(Date.self, from: data)
|
||||
XCTAssertEqual(value, date)
|
||||
}
|
||||
|
||||
func testDecodeArrayWithDate() {
|
||||
let data = Data(bytes: [0x91, 0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01])
|
||||
let date = Date(timeIntervalSince1970: 1)
|
||||
let value = try! decoder.decode([Date].self, from: data)
|
||||
XCTAssertEqual(value, [date])
|
||||
}
|
||||
|
||||
func testDecodeDictionaryWithDate() {
|
||||
let data = Data(bytes: [0x81, 0xA1, 0x31, 0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01])
|
||||
let date = Date(timeIntervalSince1970: 1)
|
||||
let value = try! decoder.decode([String: Date].self, from: data)
|
||||
XCTAssertEqual(value, ["1": date])
|
||||
}
|
||||
|
||||
func testDecodeBv() {
|
||||
let b64 = "lK50ZXN0aW5nIHN0cmluZyeSpnF3ZXF3ZagxMjNpY29uc5OU2SRlMTZkYTYwMi0zMjE1LTRiZDYtYjY5MC00Y2Q4NmEwZmU3NjSoQ2lwaGVyIDEBk61jaXBodXNlcm5hbWUxrWFkZmFmZHcyMzQxMzGSkblodHRwczovL3d3dy5nb29nbGUuY29tLmFykbVodHRwczovL3d3dy5hcHBsZS5jb22U2SRhNjExMWU2Ny1hMTMwLTRiM2ItODM5NS0xZjIzMDFjNjk3ZjeoQ2lwaGVyIDIBk6g0MzEzMjEzMatqbGpsbHl1bHVpecCU2SRiOGIwODM3MC0xNGU0LTQzZmUtYjBkOS04ZjJlMDlmODJkYzWoQ2lwaGVyIDMBk6twaW9waW9waXBpb6x6eGN6eHZ6eHZ4enaSkbdodHRwczovL3d3dy52aXNhLmNvbS5hcpG1aHR0cHM6Ly93d3cuZG9ja3MuY29t" // array mode with envData and ciphers
|
||||
|
||||
// let b64 = "hKFirnRlc3Rpbmcgc3RyaW5noWMnp2VudkRhdGGCpGJhc2WmcXdlcXdlpWljb25zqDEyM2ljb25zp2NpcGhlcnOThKJpZNkkMDA4YmE0NDctZjU0Mi00OWVjLWJjYTktMDMzZTQ2OTU0YTBipG5hbWWoQ2lwaGVyIDGkdHlwZQGlbG9naW6DqHVzZXJuYW1lrWNpcGh1c2VybmFtZTGkdG90cK1hZGZhZmR3MjM0MTMxpHVyaXOSgaN1cmm5aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS5hcoGjdXJptWh0dHBzOi8vd3d3LmFwcGxlLmNvbYSiaWTZJDQ1ZTBhODJiLTgyZGQtNDJiZi05ODhhLTAyYTkyNGM4Yzg5M6RuYW1lqENpcGhlciAypHR5cGUBpWxvZ2lug6h1c2VybmFtZag0MzEzMjEzMaR0b3Rwq2psamxseXVsdWl5pHVyaXPAhKJpZNkkZTBjZWU5NDEtZDI1Ni00MjdiLWJkNWUtNDMxMmMwN2U1NDI5pG5hbWWoQ2lwaGVyIDOkdHlwZQGlbG9naW6DqHVzZXJuYW1lq3Bpb3Bpb3BpcGlvpHRvdHCsenhjenh2enh2eHp2pHVyaXOSgaN1cmm3aHR0cHM6Ly93d3cudmlzYS5jb20uYXKBo3VyabVodHRwczovL3d3dy5kb2Nrcy5jb20=" // dict mode with envData and ciphers
|
||||
|
||||
do {
|
||||
if let d = Data(base64Encoded: b64) {
|
||||
let decoder = MessagePackDecoder()
|
||||
decoder.userInfo[MessagePackDecoder.dataSpecKey] = DataSpecBuilder()
|
||||
.append("b")
|
||||
.append("c")
|
||||
.appendObj("envData", DataSpecBuilder()
|
||||
.append("base")
|
||||
.append("icons")
|
||||
.build())
|
||||
.appendArray("ciphers", DataSpecBuilder()
|
||||
.append("id")
|
||||
.append("name")
|
||||
.append("type")
|
||||
.appendObj("login", DataSpecBuilder()
|
||||
.append("username")
|
||||
.append("totp")
|
||||
.appendArray("uris", DataSpecBuilder()
|
||||
.append("uri")
|
||||
.build())
|
||||
.build())
|
||||
.build())
|
||||
.build()
|
||||
|
||||
let codTest = try decoder.decode(CodableTest.self, from: d)
|
||||
|
||||
XCTAssertEqual(codTest.b, "testing string")
|
||||
XCTAssertEqual(codTest.envData.base, "qweqwe")
|
||||
XCTAssertEqual(codTest.envData.icons, "123icons")
|
||||
XCTAssertTrue(codTest.ciphers!.count > 1)
|
||||
} else {
|
||||
XCTAssertEqual(1, 0)
|
||||
}
|
||||
} catch let error {
|
||||
XCTFail("E: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
("testDecodeNil", testDecodeNil),
|
||||
("testDecodeFalse", testDecodeFalse),
|
||||
("testDecodeTrue", testDecodeTrue),
|
||||
("testDecodeInt", testDecodeInt),
|
||||
("testDecodeUInt", testDecodeUInt),
|
||||
("testDecodeFloat", testDecodeFloat),
|
||||
("testDecodeFloatToDouble", testDecodeFloatToDouble),
|
||||
("testDecodeDouble", testDecodeDouble),
|
||||
("testDecodeDoubleToFloat", testDecodeDoubleToFloat),
|
||||
("testDecodeFixedArray", testDecodeFixedArray),
|
||||
("testDecodeFixedDictionary", testDecodeFixedDictionary),
|
||||
("testDecodeData", testDecodeData),
|
||||
("testDecodeDistantPast", testDecodeDistantPast),
|
||||
("testDecodeDistantFuture", testDecodeDistantFuture),
|
||||
("testDecodeArrayWithDate", testDecodeArrayWithDate),
|
||||
("testDecodeDictionaryWithDate", testDecodeDictionaryWithDate),
|
||||
("testDecodeBv", testDecodeBv)
|
||||
]
|
||||
}
|
||||
|
||||
struct CodableTest : Codable {
|
||||
enum CodingKeys: Int, CodingKey {
|
||||
case b
|
||||
case c
|
||||
case envData
|
||||
case ciphers
|
||||
}
|
||||
|
||||
var b: String
|
||||
var c: Int
|
||||
var envData: EnvironmentUrlDataDto
|
||||
var ciphers: [Cipher]?
|
||||
|
||||
func printt() {
|
||||
print("B: \(b)")
|
||||
print("C: \(c)")
|
||||
print("ENVDATA")
|
||||
envData.printt()
|
||||
|
||||
if let cs = ciphers {
|
||||
print("CIPHERS")
|
||||
for c in cs {
|
||||
c.printt()
|
||||
print("----------------------------")
|
||||
}
|
||||
}
|
||||
|
||||
print("###########################")
|
||||
}
|
||||
}
|
||||
|
||||
struct EnvironmentUrlDataDto : Codable {
|
||||
var base: String?
|
||||
var icons: String?
|
||||
|
||||
func printt() {
|
||||
print("Base: \(base ?? "")")
|
||||
print("Icons: \(icons ?? "")")
|
||||
}
|
||||
}
|
||||
|
||||
struct Cipher:Identifiable,Codable{
|
||||
enum CodingKeys: Int, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case login
|
||||
}
|
||||
|
||||
var id:String
|
||||
var name:String?
|
||||
var userId:String?
|
||||
var login:Login
|
||||
|
||||
func printt() {
|
||||
print("id: \(id)")
|
||||
print("name: \(name ?? "")")
|
||||
print("LOGIN")
|
||||
login.printt()
|
||||
}
|
||||
}
|
||||
|
||||
struct Login:Codable{
|
||||
var username:String?
|
||||
var totp:String?
|
||||
var uris:[LoginUri]?
|
||||
|
||||
func printt() {
|
||||
print("username: \(username ?? "")")
|
||||
print("totp: \(totp ?? "")")
|
||||
print("URIS")
|
||||
if let us = uris {
|
||||
for u in us {
|
||||
u.printt()
|
||||
print("----------------------------")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LoginUri:Codable{
|
||||
var uri:String?
|
||||
|
||||
func printt() {
|
||||
print("Uri: \(uri ?? "")")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
import XCTest
|
||||
@testable import MessagePack
|
||||
|
||||
class MessagePackEncodingTests: XCTestCase {
|
||||
var encoder: MessagePackEncoder!
|
||||
|
||||
override func setUp() {
|
||||
self.encoder = MessagePackEncoder()
|
||||
}
|
||||
|
||||
func testEncodeNil() {
|
||||
let value = try! encoder.encode(nil as Int?)
|
||||
XCTAssertEqual(value, Data(bytes: [0xc0]))
|
||||
}
|
||||
|
||||
func testEncodeFalse() {
|
||||
let value = try! encoder.encode(false)
|
||||
XCTAssertEqual(value, Data(bytes: [0xc2]))
|
||||
}
|
||||
|
||||
func testEncodeTrue() {
|
||||
let value = try! encoder.encode(true)
|
||||
XCTAssertEqual(value, Data(bytes: [0xc3]))
|
||||
}
|
||||
|
||||
func testEncodeInt() {
|
||||
let value = try! encoder.encode(42 as Int)
|
||||
XCTAssertEqual(value, Data(bytes: [0x2A]))
|
||||
}
|
||||
|
||||
func testEncodeUInt() {
|
||||
let value = try! encoder.encode(128 as UInt)
|
||||
XCTAssertEqual(value, Data(bytes: [0xCC, 0x80]))
|
||||
}
|
||||
|
||||
func testEncodeFloat() {
|
||||
let value = try! encoder.encode(3.14 as Float)
|
||||
XCTAssertEqual(value, Data(bytes: [0xCA, 0x40, 0x48, 0xF5, 0xC3]))
|
||||
}
|
||||
|
||||
func testEncodeDouble() {
|
||||
let value = try! encoder.encode(3.14159 as Double)
|
||||
XCTAssertEqual(value, Data(bytes: [0xCB, 0x40, 0x09, 0x21, 0xF9, 0xF0, 0x1B, 0x86, 0x6E]))
|
||||
}
|
||||
|
||||
func testEncodeString() {
|
||||
let value = try! encoder.encode("hello")
|
||||
XCTAssertEqual(value, Data(bytes: [0xA5, 0x68, 0x65, 0x6C, 0x6C, 0x6F]))
|
||||
}
|
||||
|
||||
func testEncodeFixedArray() {
|
||||
let value = try! encoder.encode([1, 2, 3])
|
||||
XCTAssertEqual(value, Data(bytes: [0x93, 0x01, 0x02, 0x03]))
|
||||
}
|
||||
|
||||
func testEncodeVariableArray() {
|
||||
let value = try! encoder.encode(Array(1...16))
|
||||
XCTAssertEqual(value, Data(bytes: [0xdc] + [0x00, 0x10] + Array(0x01...0x10)))
|
||||
}
|
||||
|
||||
func testEncodeFixedDictionary() {
|
||||
let value = try! encoder.encode(["a": 1])
|
||||
XCTAssertEqual(value, Data(bytes: [0x81, 0xA1, 0x61, 0x01]))
|
||||
}
|
||||
|
||||
func testEncodeVariableDictionary() {
|
||||
let letters = "abcdefghijklmnopqrstuvwxyz".unicodeScalars
|
||||
let dictionary = Dictionary(uniqueKeysWithValues: zip(letters.map { String($0) }, 1...26))
|
||||
let value = try! encoder.encode(dictionary)
|
||||
XCTAssertEqual(value.count, 81)
|
||||
XCTAssert(value.starts(with: [0xde] + [0x00, 0x1A]))
|
||||
}
|
||||
|
||||
func testEncodeData() {
|
||||
let data = "hello".data(using: .utf8)
|
||||
let value = try! encoder.encode(data)
|
||||
XCTAssertEqual(value, Data(bytes: [0xC4, 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F]))
|
||||
}
|
||||
|
||||
func testEncodeDate() {
|
||||
let date = Date(timeIntervalSince1970: 1)
|
||||
let value = try! encoder.encode(date)
|
||||
XCTAssertEqual(value, Data(bytes: [0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01]))
|
||||
}
|
||||
|
||||
func testEncodeDistantPast() {
|
||||
let date = Date.distantPast
|
||||
let value = try! encoder.encode(date)
|
||||
XCTAssertEqual(value, Data(bytes: [0xC7, 0x0C, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF1, 0x88, 0x6B, 0x66, 0x00]))
|
||||
}
|
||||
|
||||
func testEncodeDistantFuture() {
|
||||
let date = Date.distantFuture
|
||||
let value = try! encoder.encode(date)
|
||||
XCTAssertEqual(value, Data(bytes: [0xC7, 0x0C, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xEC, 0x31, 0x88, 0x00]))
|
||||
}
|
||||
|
||||
func testEncodeArrayWithDate() {
|
||||
let date = Date(timeIntervalSince1970: 1)
|
||||
let value = try! encoder.encode([date])
|
||||
XCTAssertEqual(value, Data(bytes: [0x91, 0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01]))
|
||||
}
|
||||
|
||||
func testEncodeDictionaryWithDate() {
|
||||
let date = Date(timeIntervalSince1970: 1)
|
||||
let value = try! encoder.encode(["1": date])
|
||||
XCTAssertEqual(value, Data(bytes: [0x81, 0xA1, 0x31, 0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01]))
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
("testEncodeFalse", testEncodeFalse),
|
||||
("testEncodeTrue", testEncodeTrue),
|
||||
("testEncodeInt", testEncodeInt),
|
||||
("testEncodeUInt", testEncodeUInt),
|
||||
("testEncodeFloat", testEncodeFloat),
|
||||
("testEncodeDouble", testEncodeDouble),
|
||||
("testEncodeFixedArray", testEncodeFixedArray),
|
||||
("testEncodeVariableArray", testEncodeVariableArray),
|
||||
("testEncodeFixedDictionary", testEncodeFixedDictionary),
|
||||
("testEncodeVariableDictionary", testEncodeVariableDictionary),
|
||||
("testEncodeDate", testEncodeDate),
|
||||
("testEncodeDistantPast", testEncodeDistantPast),
|
||||
("testEncodeDistantFuture", testEncodeDistantFuture),
|
||||
("testEncodeArrayWithDate", testEncodeArrayWithDate),
|
||||
("testEncodeDictionaryWithDate", testEncodeDictionaryWithDate)
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import XCTest
|
||||
@testable import MessagePack
|
||||
|
||||
class MessagePackPerformanceTests: XCTestCase {
|
||||
var encoder: MessagePackEncoder!
|
||||
var decoder: MessagePackDecoder!
|
||||
|
||||
override func setUp() {
|
||||
self.encoder = MessagePackEncoder()
|
||||
self.decoder = MessagePackDecoder()
|
||||
}
|
||||
|
||||
func testPerformance() {
|
||||
let count = 100
|
||||
let values = [Airport](repeating: .example, count: count)
|
||||
|
||||
self.measure {
|
||||
let encoded = try! encoder.encode(values)
|
||||
let decoded = try! decoder.decode([Airport].self, from: encoded)
|
||||
XCTAssertEqual(decoded.count, count)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import XCTest
|
||||
@testable import MessagePack
|
||||
|
||||
class MessagePackRoundTripTests: XCTestCase {
|
||||
var encoder: MessagePackEncoder!
|
||||
var decoder: MessagePackDecoder!
|
||||
|
||||
override func setUp() {
|
||||
self.encoder = MessagePackEncoder()
|
||||
self.decoder = MessagePackDecoder()
|
||||
}
|
||||
|
||||
func testRoundTripAirport() {
|
||||
let value = Airport.example
|
||||
let encoded = try! encoder.encode(value)
|
||||
let decoded = try! decoder.decode(Airport.self, from: encoded)
|
||||
|
||||
XCTAssertEqual(value.name, decoded.name)
|
||||
XCTAssertEqual(value.iata, decoded.iata)
|
||||
XCTAssertEqual(value.icao, decoded.icao)
|
||||
XCTAssertEqual(value.coordinates[0], decoded.coordinates[0], accuracy: 0.01)
|
||||
XCTAssertEqual(value.coordinates[1], decoded.coordinates[1], accuracy: 0.01)
|
||||
XCTAssertEqual(value.runways[0].direction, decoded.runways[0].direction)
|
||||
XCTAssertEqual(value.runways[0].distance, decoded.runways[0].distance)
|
||||
XCTAssertEqual(value.runways[0].surface, decoded.runways[0].surface)
|
||||
}
|
||||
|
||||
func testRoundTripParachutePack() {
|
||||
struct Parachute: Codable, Equatable {
|
||||
enum Canopy: String, Codable, Equatable {
|
||||
case round, cruciform, rogalloWing, annular, ramAir
|
||||
}
|
||||
|
||||
let canpoy: Canopy
|
||||
let surfaceArea: Double
|
||||
}
|
||||
|
||||
struct ParachutePack: Codable, Equatable {
|
||||
let main: Parachute?
|
||||
let reserve: Parachute?
|
||||
}
|
||||
|
||||
let value = ParachutePack(main: Parachute(canpoy: .ramAir, surfaceArea: 200), reserve: nil)
|
||||
let encoded = try! encoder.encode(value)
|
||||
let decoded = try! decoder.decode(ParachutePack.self, from: encoded)
|
||||
|
||||
XCTAssertEqual(value, decoded)
|
||||
}
|
||||
|
||||
func testRoundTripArray() {
|
||||
let count: UInt8 = 100
|
||||
var bytes: [UInt8] = [0xdc, 0x00, count]
|
||||
var encoded: [Int] = []
|
||||
for n in 1...count {
|
||||
bytes.append(n)
|
||||
encoded.append(Int(n))
|
||||
}
|
||||
|
||||
let data = Data(bytes: bytes)
|
||||
let decoded = try! decoder.decode([Int].self, from: data)
|
||||
XCTAssertEqual(encoded, decoded)
|
||||
}
|
||||
|
||||
func testRoundTripDictionary() {
|
||||
let (a, z): (UInt8, UInt8) = (0x61, 0x7a)
|
||||
var bytes: [UInt8] = [0xde, 0x00, 0x1A]
|
||||
var encoded: [String: Int] = [:]
|
||||
for n in a...z {
|
||||
bytes.append(contentsOf: [0xA1, n, n])
|
||||
encoded[String(Unicode.Scalar(n))] = Int(n)
|
||||
}
|
||||
|
||||
let data = Data(bytes: bytes)
|
||||
let decoded = try! decoder.decode([String: Int].self, from: data)
|
||||
XCTAssertEqual(encoded, decoded)
|
||||
}
|
||||
|
||||
func testRoundTripDate() {
|
||||
var bytes: [UInt8] = [0xD6, 0xFF]
|
||||
|
||||
let dateComponents = DateComponents(year: 2018, month: 4, day: 20)
|
||||
let encoded = Calendar.current.date(from: dateComponents)!
|
||||
|
||||
let secondsSince1970 = UInt32(encoded.timeIntervalSince1970)
|
||||
bytes.append(contentsOf: secondsSince1970.bytes)
|
||||
|
||||
let data = Data(bytes: bytes)
|
||||
let decoded = try! decoder.decode(Date.self, from: data)
|
||||
XCTAssertEqual(encoded, decoded)
|
||||
}
|
||||
|
||||
func testRoundTripDateWithNanoseconds() {
|
||||
let encoded = Date()
|
||||
let data = try! self.encoder.encode(encoded)
|
||||
let decoded = try! self.decoder.decode(Date.self, from: data)
|
||||
XCTAssertEqual(encoded.timeIntervalSinceReferenceDate, decoded.timeIntervalSinceReferenceDate, accuracy: 0.0001)
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
("testRoundTripAirport", testRoundTripAirport),
|
||||
("testRoundTripArray", testRoundTripArray),
|
||||
("testRoundTripDictionary", testRoundTripDictionary),
|
||||
("testRoundTripDate", testRoundTripDate),
|
||||
("testRoundTripDateWithNanoseconds", testRoundTripDateWithNanoseconds)
|
||||
]
|
||||
}
|
||||
@@ -446,7 +446,7 @@
|
||||
<value>تغيير البريد الإلكتروني</value>
|
||||
</data>
|
||||
<data name="ChangeEmailConfirmation" xml:space="preserve">
|
||||
<value>يمكنك تغيير عنوان بريدك الإلكتروني من خزنة الويب على bitwarden.com. هل تريد زيارة الموقع الآن؟</value>
|
||||
<value>يمكنك تغيير عنوان بريدك الإلكتروني من خزانة الويب على bitwarden.com. هل تريد زيارة الموقع الآن؟</value>
|
||||
</data>
|
||||
<data name="ChangeMasterPassword" xml:space="preserve">
|
||||
<value>تغيير كلمة المرور الرئيسية</value>
|
||||
@@ -550,20 +550,20 @@
|
||||
<value>فورًا</value>
|
||||
</data>
|
||||
<data name="VaultTimeout" xml:space="preserve">
|
||||
<value>مهلة الخزنة</value>
|
||||
<value>مهلة الخزانة</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutAction" xml:space="preserve">
|
||||
<value>إجراء مهلة الخزنة</value>
|
||||
<value>إجراء مهلة الخزانة</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutLogOutConfirmation" xml:space="preserve">
|
||||
<value>سيؤدي تسجيل الخروج إلى إزالة جميع الوصول إلى الخزنة الخاصة بك ويتطلب المصادقة عبر الإنترنت بعد انتهاء المهلة. هل أنت متأكد من أنك تريد استخدام هذا الإعداد؟</value>
|
||||
<value>سيؤدي تسجيل الخروج إلى إزالة جميع الوصول إلى الخزانة الخاصة بك ويتطلب المصادقة عبر الإنترنت بعد انتهاء المهلة. هل أنت متأكد من أنك تريد استخدام هذا الإعداد؟</value>
|
||||
</data>
|
||||
<data name="LoggingIn" xml:space="preserve">
|
||||
<value>جارِ تسجيل الدخول...</value>
|
||||
<comment>Message shown when interacting with the server</comment>
|
||||
</data>
|
||||
<data name="LoginOrCreateNewAccount" xml:space="preserve">
|
||||
<value>قم بتسجيل الدخول أو إنشاء حساب جديد للوصول إلى خزنتك الآمنة.</value>
|
||||
<value>قم بتسجيل الدخول أو إنشاء حساب جديد للوصول إلى خزانتك الآمنة.</value>
|
||||
</data>
|
||||
<data name="Manage" xml:space="preserve">
|
||||
<value>إدارة</value>
|
||||
@@ -572,7 +572,7 @@
|
||||
<value>تأكيد كلمة المرور غير صحيح.</value>
|
||||
</data>
|
||||
<data name="MasterPasswordDescription" xml:space="preserve">
|
||||
<value>كلمة المرور الرئيسية هي كلمة المرور المستخدمة للوصول إلى الخزنة الخاصة بك. من المهم جدا ً ألا تنسى ذلك. لا توجد طريقة للعثور عليها إذا نسيت.</value>
|
||||
<value>كلمة المرور الرئيسية هي كلمة المرور المستخدمة للوصول إلى الخزانة الخاصة بك. من المهم جدا ً ألا تنسى ذلك. لا توجد طريقة للعثور عليها إذا نسيت.</value>
|
||||
</data>
|
||||
<data name="MasterPasswordHint" xml:space="preserve">
|
||||
<value>فهرس كلمة المرور الرئيسية (اختياري)</value>
|
||||
@@ -604,13 +604,13 @@
|
||||
<value>تم إنشاء عنصر جديد.</value>
|
||||
</data>
|
||||
<data name="NoFavorites" xml:space="preserve">
|
||||
<value>لا توجد عناصر مفضلة في خزنتك.</value>
|
||||
<value>لا توجد عناصر مفضلة في خزانتك.</value>
|
||||
</data>
|
||||
<data name="NoItems" xml:space="preserve">
|
||||
<value>لا توجد عناصر في خزنتك.</value>
|
||||
<value>لا توجد عناصر في خزانتك.</value>
|
||||
</data>
|
||||
<data name="NoItemsTap" xml:space="preserve">
|
||||
<value>لا توجد في خزنتك عناصر لهذا الموقع/التطبيق. انقر لإضافة واحد.</value>
|
||||
<value>لا توجد في خزانتك عناصر لهذا الموقع/التطبيق. انقر لإضافة واحد.</value>
|
||||
</data>
|
||||
<data name="NoUsernamePasswordConfigured" xml:space="preserve">
|
||||
<value>لا يحتوي هذا المعرّف على اسم مستخدم أو كلمة مرور تم تكوينها.</value>
|
||||
@@ -644,7 +644,7 @@
|
||||
<value>هل أنت متأكد من أنك تريد سحق كلمة المرور الموجودة؟</value>
|
||||
</data>
|
||||
<data name="PushNotificationAlert" xml:space="preserve">
|
||||
<value>bitwarden تلقائيا يحافظ على خزنتك في المزامنة باستخدام دفع الإخطارات. للحصول على أفضل تجربة ممكنة، يرجى اختيار "موافق" على مربع الحوار التالي (تفعيل دفع الإخطارات ).</value>
|
||||
<value>Bitwarden يحافظ تلقائيا على خزانتك في المزامنة باستخدام دفع الإخطارات. للحصول على أفضل تجربة ممكنة، يرجى اختيار "سماح" على مربع الحوار التالي عند طلب السماح بدفع الإشعارات.</value>
|
||||
<comment>Push notifications for apple products</comment>
|
||||
</data>
|
||||
<data name="RateTheApp" xml:space="preserve">
|
||||
@@ -660,7 +660,7 @@
|
||||
<value>إعادة إدخال كلمة المرور الرئيسية</value>
|
||||
</data>
|
||||
<data name="SearchVault" xml:space="preserve">
|
||||
<value>البحث في الخزنة</value>
|
||||
<value>البحث في الخزانة</value>
|
||||
</data>
|
||||
<data name="Security" xml:space="preserve">
|
||||
<value>الأمان</value>
|
||||
@@ -695,7 +695,7 @@
|
||||
<value>فشل المزامنة.</value>
|
||||
</data>
|
||||
<data name="SyncVaultNow" xml:space="preserve">
|
||||
<value>مزامنة الخزنة الآن</value>
|
||||
<value>مزامنة الخزانة الآن</value>
|
||||
</data>
|
||||
<data name="TouchID" xml:space="preserve">
|
||||
<value>Touch ID معرف اتصال البصمة</value>
|
||||
@@ -721,7 +721,7 @@
|
||||
<value>عرض العنصر</value>
|
||||
</data>
|
||||
<data name="WebVault" xml:space="preserve">
|
||||
<value>خزنة الويب Bitwarden</value>
|
||||
<value>خزانة الويب Bitwarden</value>
|
||||
</data>
|
||||
<data name="Lost2FAApp" xml:space="preserve">
|
||||
<value>هل تم فقدان تطبيق المصادقة؟</value>
|
||||
@@ -744,14 +744,14 @@
|
||||
<comment>This is used for the autofill service. ex. "Logins for twitter.com"</comment>
|
||||
</data>
|
||||
<data name="NoItemsForUri" xml:space="preserve">
|
||||
<value>لا توجد عناصر في خزنتك لـ {0}.</value>
|
||||
<value>لا توجد عناصر في خزانتك لـ {0}.</value>
|
||||
<comment>This is used for the autofill service. ex. "There are no items in your vault for twitter.com".</comment>
|
||||
</data>
|
||||
<data name="BitwardenAutofillServiceOverlay" xml:space="preserve">
|
||||
<value>عند تحديد حقل الإدخال ومشاهدة تراكب الملء التلقائي لـ Bitwarden ، يمكنك النقر عليه لتشغيل خدمة الملء التلقائي.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillServiceNotificationContent" xml:space="preserve">
|
||||
<value>اضغط على هذا الإشعار لملء معلومات تسجيل الدخول تلقائيًا من خزنتك.</value>
|
||||
<value>اضغط على هذا الإشعار لملء معلومات تسجيل الدخول تلقائيًا من خزانتك.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillServiceOpenAccessibilitySettings" xml:space="preserve">
|
||||
<value>فتح إعدادات إمكانية الوصول</value>
|
||||
@@ -778,7 +778,7 @@
|
||||
<value>الحالة</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillServiceAlert2" xml:space="preserve">
|
||||
<value>أسهل طريقة لإضافة تسجيلات دخول جديدة إلى خزنتك هي من خدمة التعبئة التلقائية Bitwarden تعرف على المزيد حول استخدام خدمة الملء التلقائي لـ Bitwarden عن طريق الانتقال إلى شاشة "إعدادات".</value>
|
||||
<value>أسهل طريقة لإضافة تسجيلات دخول جديدة إلى خزانتك هي من خدمة التعبئة التلقائية Bitwarden تعرف على المزيد حول استخدام خدمة الملء التلقائي لـ Bitwarden عن طريق الانتقال إلى شاشة "إعدادات".</value>
|
||||
</data>
|
||||
<data name="Autofill" xml:space="preserve">
|
||||
<value>التعبئة التلقائية</value>
|
||||
@@ -949,7 +949,7 @@
|
||||
<value>لا يمكنك استخدام هذه الميزة حتى تقوم بتحديث مفتاح التشفير الخاص بك.</value>
|
||||
</data>
|
||||
<data name="EncryptionKeyMigrationRequiredDescriptionLong" xml:space="preserve">
|
||||
<value>مطلوب ترحيل مفتاح التشفير. الرجاء تسجيل الدخول بواسطة مخزن الويب لتحديث مفتاح التشفير الخاص بك.</value>
|
||||
<value>مطلوب ترحيل مفتاح التشفير. الرجاء تسجيل الدخول بواسطة خزانة الويب لتحديث مفتاح التشفير الخاص بك.</value>
|
||||
</data>
|
||||
<data name="LearnMore" xml:space="preserve">
|
||||
<value>اعرف المزيد</value>
|
||||
@@ -984,10 +984,10 @@
|
||||
<value>رابط الخادم</value>
|
||||
</data>
|
||||
<data name="WebVaultUrl" xml:space="preserve">
|
||||
<value>رابط خادم مخزن الويب</value>
|
||||
<value>رابط خادم خزانة الويب</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
|
||||
<value>اضغط على هذا الإشعار لعرض العناصر من الخزنة الخاصة بك.</value>
|
||||
<value>اضغط على هذا الإشعار لعرض العناصر من الخزانة الخاصة بك.</value>
|
||||
</data>
|
||||
<data name="CustomFields" xml:space="preserve">
|
||||
<value>حقول مخصصة</value>
|
||||
@@ -1149,10 +1149,10 @@
|
||||
<value>ملء تلقائي باستخدام Bitwarden</value>
|
||||
</data>
|
||||
<data name="VaultIsLocked" xml:space="preserve">
|
||||
<value>الخزنة مقفلة</value>
|
||||
<value>الخزانة مقفلة</value>
|
||||
</data>
|
||||
<data name="GoToMyVault" xml:space="preserve">
|
||||
<value>اذهب لخزنتي</value>
|
||||
<value>اذهب لخزانتي</value>
|
||||
</data>
|
||||
<data name="Collections" xml:space="preserve">
|
||||
<value>المختارات</value>
|
||||
@@ -1301,7 +1301,7 @@
|
||||
<value>نوصي بتعطيل أي تطبيقات أخرى من تطبيقات التعبئة التلقائية تحت الإعدادات إذا كنت لا تخطط لاستخدامها.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillDescription" xml:space="preserve">
|
||||
<value>الوصول إلى الخزن, الخاص, بك مباشرة من لوحة المفاتيح الخاصة بك لملء كلمات المرور تلقائياً بسرعة.</value>
|
||||
<value>الوصول إلى الخزانة الخاصة بك مباشرة من لوحة المفاتيح الخاصة بك لملء كلمات المرور تلقائياً بسرعة.</value>
|
||||
</data>
|
||||
<data name="AutofillTurnOn" xml:space="preserve">
|
||||
<value>لتمكين التعبئة التلقائية لكلمة المرور على جهازك، اتبع هذه التعليمات:</value>
|
||||
@@ -1325,7 +1325,7 @@
|
||||
<value>تعبئة تلقائية لكلمة المرور</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillAlert2" xml:space="preserve">
|
||||
<value>أسهل طريقة لإضافة تسجيلات دخول جديدة إلى خزنتك هي من خدمة التعبئة التلقائية Bitwarden. تعرف على المزيد حول استخدام خدمة الملء التلقائي لـ Bitwarden عن طريق الانتقال إلى شاشة "إعدادات".</value>
|
||||
<value>أسهل طريقة لإضافة تسجيلات دخول جديدة إلى خزانتك هي من خدمة التعبئة التلقائية Bitwarden. تعرف على المزيد حول استخدام خدمة الملء التلقائي لـ Bitwarden عن طريق الانتقال إلى شاشة "إعدادات".</value>
|
||||
</data>
|
||||
<data name="InvalidEmail" xml:space="preserve">
|
||||
<value>عنوان البريد الإلكتروني غير صالح.</value>
|
||||
@@ -1468,10 +1468,10 @@
|
||||
<comment>A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing.</comment>
|
||||
</data>
|
||||
<data name="LearnOrgConfirmation" xml:space="preserve">
|
||||
<value>يسمح لك Bitwarden بمشاركة عناصر خزنتك مع الآخرين باستخدام حساب المؤسسة. هل ترغب في زيارة موقع bitwarden.com لمعرفة المزيد؟</value>
|
||||
<value>يسمح لك Bitwarden بمشاركة عناصر خزانتك مع الآخرين باستخدام حساب المؤسسة. هل ترغب في زيارة موقع bitwarden.com لمعرفة المزيد؟</value>
|
||||
</data>
|
||||
<data name="ExportVault" xml:space="preserve">
|
||||
<value>تصدير الخزنة</value>
|
||||
<value>تصدير الخزانة</value>
|
||||
</data>
|
||||
<data name="LockNow" xml:space="preserve">
|
||||
<value>إقفل الآن</value>
|
||||
@@ -1496,13 +1496,13 @@
|
||||
<comment>ex: Logged in as user@example.com on bitwarden.com.</comment>
|
||||
</data>
|
||||
<data name="VaultLockedMasterPassword" xml:space="preserve">
|
||||
<value>خزنتك مقفلة. تحقق من كلمة المرور الرئيسية للمتابعة.</value>
|
||||
<value>خزانتك مقفلة. تحقق من كلمة المرور الرئيسية للمتابعة.</value>
|
||||
</data>
|
||||
<data name="VaultLockedPIN" xml:space="preserve">
|
||||
<value>خزنتك مقفلة. تحقق من رمز PIN الخاص بك للمتابعة.</value>
|
||||
<value>خزانتك مقفلة. تحقق من رمز PIN الخاص بك للمتابعة.</value>
|
||||
</data>
|
||||
<data name="VaultLockedIdentity" xml:space="preserve">
|
||||
<value>خزنتك مقفلة. تحقق من هويتك للمتابعة.</value>
|
||||
<value>خزانتك مقفلة. تحقق من هويتك للمتابعة.</value>
|
||||
</data>
|
||||
<data name="Dark" xml:space="preserve">
|
||||
<value>داكن</value>
|
||||
@@ -1586,13 +1586,13 @@
|
||||
<value>اطلب إضافة تسجيل الدخول</value>
|
||||
</data>
|
||||
<data name="AskToAddLoginDescription" xml:space="preserve">
|
||||
<value>اطلب إضافة عنصر إذا لم يتم العثور عليه في خزنتك.</value>
|
||||
<value>اطلب إضافة عنصر إذا لم يتم العثور عليه في خزانتك.</value>
|
||||
</data>
|
||||
<data name="OnRestart" xml:space="preserve">
|
||||
<value>عند إعادة تشغيل التطبيق</value>
|
||||
</data>
|
||||
<data name="AutofillServiceNotEnabled" xml:space="preserve">
|
||||
<value>التعبئة التلقائية تجعل من السهل الوصول بشكل آمن إلى خزنة Bitwarden الخاصة بك من مواقع الويب والتطبيقات الأخرى. يبدو أنك لم تقم بتمكين خدمة التعبئة التلقائية لـ Bitwarden. تمكين التعبئة التلقائية لـ Bitwarden من شاشة "الإعدادات".</value>
|
||||
<value>التعبئة التلقائية تجعل من السهل الوصول بشكل آمن إلى خزانة Bitwarden الخاصة بك من مواقع الويب والتطبيقات الأخرى. يبدو أنك لم تقم بتمكين خدمة التعبئة التلقائية لـ Bitwarden. تمكين التعبئة التلقائية لـ Bitwarden من شاشة "الإعدادات".</value>
|
||||
</data>
|
||||
<data name="ThemeAppliedOnRestart" xml:space="preserve">
|
||||
<value>سيتم تطبيق تغييرات السمة الخاصة بك عند إعادة تشغيل التطبيق.</value>
|
||||
@@ -1650,7 +1650,7 @@
|
||||
<value>صيغة الملف</value>
|
||||
</data>
|
||||
<data name="ExportVaultMasterPasswordDescription" xml:space="preserve">
|
||||
<value>أدخل كلمة المرور الرئيسية لتصدير بيانات خزنتك.</value>
|
||||
<value>أدخل كلمة المرور الرئيسية لتصدير بيانات خزانتك.</value>
|
||||
</data>
|
||||
<data name="SendVerificationCodeToEmail" xml:space="preserve">
|
||||
<value>إرسال رمز التحقق إلى بريدك الإلكتروني</value>
|
||||
@@ -1662,7 +1662,7 @@
|
||||
<value>قم بتأكيد هويتك للمتابعة.</value>
|
||||
</data>
|
||||
<data name="ExportVaultWarning" xml:space="preserve">
|
||||
<value>يحتوي هذا التصدير على بيانات خزنتك بتنسيق غير مشفر. لا يجب عليك تخزين أو إرسال الملف الذي تم تصديره عبر قنوات غير آمنة (مثل البريد الإلكتروني). احذفه مباشرة بعد انتهائك من استخدامه.</value>
|
||||
<value>يحتوي هذا التصدير على بيانات خزانتك بتنسيق غير مشفر. لا يجب عليك تخزين أو إرسال الملف الذي تم تصديره عبر قنوات غير آمنة (مثل البريد الإلكتروني). احذفه مباشرة بعد انتهائك من استخدامه.</value>
|
||||
</data>
|
||||
<data name="EncExportKeyWarning" xml:space="preserve">
|
||||
<value>يقوم هذا التصدير بتشفير بياناتك باستخدام مفتاح تشفير حسابك. إذا قمت بتدوير مفتاح تشفير حسابك يجب عليك التصدير مرة أخرى لأنك لن تتمكن من فك تشفير ملف التصدير هذا.</value>
|
||||
@@ -1671,17 +1671,17 @@
|
||||
<value>مفاتيح تشفير الحساب فريدة من نوعها لكل حساب مستخدم Bitwarden، لذلك لا يمكنك استيراد تصدير مشفر إلى حساب آخر.</value>
|
||||
</data>
|
||||
<data name="ExportVaultConfirmationTitle" xml:space="preserve">
|
||||
<value>تأكيد تصدير الخزنة</value>
|
||||
<value>تأكيد تصدير الخزانة</value>
|
||||
<comment>Title for the alert to confirm vault exports.</comment>
|
||||
</data>
|
||||
<data name="Warning" xml:space="preserve">
|
||||
<value>تحذير</value>
|
||||
</data>
|
||||
<data name="ExportVaultFailure" xml:space="preserve">
|
||||
<value>كانت هناك مشكلة في تصدير خزنتك. إذا استمرت المشكلة، ستحتاج إلى التصدير من خزانة الويب.</value>
|
||||
<value>كانت هناك مشكلة في تصدير خزانتك. إذا استمرت المشكلة، ستحتاج إلى التصدير من خزانة الويب.</value>
|
||||
</data>
|
||||
<data name="ExportVaultSuccess" xml:space="preserve">
|
||||
<value>تم تصدير الخزنة بنجاح</value>
|
||||
<value>تم تصدير الخزانة بنجاح</value>
|
||||
</data>
|
||||
<data name="Clone" xml:space="preserve">
|
||||
<value>استنساخ</value>
|
||||
@@ -1695,7 +1695,7 @@
|
||||
<comment>Button text for an open operation (verb).</comment>
|
||||
</data>
|
||||
<data name="UnableToSaveAttachment" xml:space="preserve">
|
||||
<value>كانت هناك مشكلة في حفظ هذا المرفق. إذا استمرت المشكلة ، يمكنك حفظها من خزنة الويب.</value>
|
||||
<value>كانت هناك مشكلة في حفظ هذا المرفق. إذا استمرت المشكلة ، يمكنك حفظها من خزانة الويب.</value>
|
||||
</data>
|
||||
<data name="SaveAttachmentSuccess" xml:space="preserve">
|
||||
<value>تم حفظ المرفق بنجاح</value>
|
||||
@@ -1756,7 +1756,7 @@
|
||||
<value>تمكين المزامنة عند التحديث</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefreshDescription" xml:space="preserve">
|
||||
<value>مزامنة الخزنة مع إيماءة السحب لأسفل.</value>
|
||||
<value>مزامنة الخزانة مع إيماءة السحب لأسفل.</value>
|
||||
</data>
|
||||
<data name="LogInSso" xml:space="preserve">
|
||||
<value>تسجيل الدخول الفردي للمؤسسة</value>
|
||||
@@ -1774,7 +1774,7 @@
|
||||
<value>تعيين كلمة المرور الرئيسية</value>
|
||||
</data>
|
||||
<data name="SetMasterPasswordSummary" xml:space="preserve">
|
||||
<value>من أجل إكمال تسجيل الدخول باستخدام SSO، يرجى تعيين كلمة مرور رئيسية للوصول وحماية خزنتك.</value>
|
||||
<value>من أجل إكمال تسجيل الدخول باستخدام SSO، يرجى تعيين كلمة مرور رئيسية للوصول وحماية خزانتك.</value>
|
||||
</data>
|
||||
<data name="MasterPasswordPolicyInEffect" xml:space="preserve">
|
||||
<value>1 - تتطلب سياسة واحدة أو أكثر من سياسات المؤسسة كلمة مرورك الرئيسية لتلبية المتطلبات التالية:</value>
|
||||
@@ -2138,16 +2138,16 @@
|
||||
<value>هذه المؤسسة لديها سياسة الشركة التي ستقوم تلقائياً بتسجيلك في إعادة تعيين كلمة المرور. التسجيل سيسمح لمسؤولي المؤسسة بتغيير كلمة المرور الرئيسية الخاصة بك.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>سياسات مؤسستك تؤثر على مهلة الخزنة الخاص بك. الحد الأقصى المسموح به لمهلة الخزنة هو {0} ساعة و {1} دقيقة</value>
|
||||
<value>سياسات مؤسستك تؤثر على مهلة الخزانة الخاص بك. الحد الأقصى المسموح به لمهلة الخزانة هو {0} ساعة و {1} دقيقة.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>سياسات مؤسستك تؤثر على مهلة خزنتك. الحد الأقصى المسموح به لمهلة الخزنة هو {0} ساعة(ساعات) و {1} دقيقة(دقائق). يتم تعيين إجراء مهلة المخزن الخاص بك إلى {2}.</value>
|
||||
<value>سياسات مؤسستك تؤثر على مهلة خزانتك. الحد الأقصى المسموح به لمهلة الخزنة هو {0} ساعة(ساعات) و {1} دقيقة(دقائق). يتم تعيين إجراء مهلة المخزن الخاص بك إلى {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>سياسات مؤسستك قامت بتعيين إجراء مهلة خزنتك إلى {0}.</value>
|
||||
<value>سياسات مؤسستك قامت بتعيين إجراء مهلة خزانتك إلى {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>مهلة خزنتك تتجاوز القيود التي تضعها مؤسستك.</value>
|
||||
<value>مهلة خزانتك تتجاوز القيود التي تضعها مؤسستك.</value>
|
||||
</data>
|
||||
<data name="DisablePersonalVaultExportPolicyInEffect" xml:space="preserve">
|
||||
<value>واحدة أو أكثر من سياسات المؤسسة تمنعك من تصدير خزانتك الشخصية.</value>
|
||||
@@ -2258,16 +2258,16 @@
|
||||
<value>كلمة المرور مخفية، انقر للإظهار.</value>
|
||||
</data>
|
||||
<data name="FilterByVault" xml:space="preserve">
|
||||
<value>تصفية العناصر حسب الخزنات</value>
|
||||
<value>تصفية العناصر حسب الخزانات</value>
|
||||
</data>
|
||||
<data name="AllVaults" xml:space="preserve">
|
||||
<value>جميع الخزنات</value>
|
||||
<value>جميع الخزانات</value>
|
||||
</data>
|
||||
<data name="Vaults" xml:space="preserve">
|
||||
<value>الخزنات</value>
|
||||
<value>الخزانات</value>
|
||||
</data>
|
||||
<data name="VaultFilterDescription" xml:space="preserve">
|
||||
<value>الخزنة: {0}</value>
|
||||
<value>الخزانة: {0}</value>
|
||||
</data>
|
||||
<data name="All" xml:space="preserve">
|
||||
<value>الكل</value>
|
||||
@@ -2307,7 +2307,7 @@
|
||||
حدد إضافة TOTP لتخزين المفتاح بأمان</value>
|
||||
</data>
|
||||
<data name="NeverLockWarning" xml:space="preserve">
|
||||
<value>تعيين خيارات قفل الخاص بك إلى "مطلقا" يبقي خزنتك متاحةً لأي شخص لديه حق الوصول إلى جهازك. إذا كنت تستخدم هذا الخيار، يجب أن تتأكد من الحفاظ على حماية جهازك بشكل صحيح.</value>
|
||||
<value>تعيين خيارات قفل الخاص بك إلى "مطلقا" يبقي خزانتك متاحةً لأي شخص لديه حق الوصول إلى جهازك. إذا كنت تستخدم هذا الخيار، يجب أن تتأكد من الحفاظ على حماية جهازك بشكل صحيح.</value>
|
||||
</data>
|
||||
<data name="EnvironmentPageUrlsError" xml:space="preserve">
|
||||
<value>واحد أو أكثر من عناوين URL التي تم إدخالها غير صالحة. الرجاء مراجعتها ومحاولة الحفظ مرة أخرى.</value>
|
||||
@@ -2516,7 +2516,7 @@
|
||||
<value>تم إرسال إشعار إلى جهازك.</value>
|
||||
</data>
|
||||
<data name="PleaseMakeSureYourVaultIsUnlockedAndTheFingerprintPhraseMatchesOnTheOtherDevice" xml:space="preserve">
|
||||
<value>الرجاء التأكد من أن الخزنة الخاصة بك غير مقفلة وأن عبارة بصمة الإصبع تتطابق على الجهاز الآخر.</value>
|
||||
<value>الرجاء التأكد من أن الخزانة الخاصة بك غير مقفلة وأن عبارة بصمة الإصبع تتطابق على الجهاز الآخر.</value>
|
||||
</data>
|
||||
<data name="ResendNotification" xml:space="preserve">
|
||||
<value>إعادة إرسال الإشعار</value>
|
||||
@@ -2627,7 +2627,7 @@
|
||||
<value>المنطقة</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>كلمة المرور الرئيسية الخاصة بك لا تفي بواحدة أو أكثر من سياسات مؤسستك. من أجل الوصول إلى الخزنة، يجب عليك تحديث كلمة المرور الرئيسية الآن. سيتم تسجيل خروجك من الجلسة الحالية، مما يتطلب منك تسجيل الدخول مرة أخرى. وقد تظل الجلسات النشطة على أجهزة أخرى نشطة لمدة تصل إلى ساعة واحدة.</value>
|
||||
<value>كلمة المرور الرئيسية الخاصة بك لا تفي بواحدة أو أكثر من سياسات مؤسستك. من أجل الوصول إلى الخزانة، يجب عليك تحديث كلمة المرور الرئيسية الآن. سيتم تسجيل خروجك من الجلسة الحالية، مما يتطلب منك تسجيل الدخول مرة أخرى. وقد تظل الجلسات النشطة على أجهزة أخرى نشطة لمدة تصل إلى ساعة واحدة.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>كلمة المرور الرئيسية الحالية</value>
|
||||
@@ -2702,7 +2702,7 @@
|
||||
<value>تسجيل الدخول كـ {0}</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionChangedToLogOut" xml:space="preserve">
|
||||
<value>تَغيير إجراء مهلة المخزن لتسجيل الخروج</value>
|
||||
<value>تَغيير إجراء مهلة خزانتك لتسجيل الخروج</value>
|
||||
</data>
|
||||
<data name="BlockAutoFill" xml:space="preserve">
|
||||
<value>حظر التعبئة التلقائية</value>
|
||||
@@ -2760,7 +2760,7 @@
|
||||
<value>جارٍ تسجيل الدخول</value>
|
||||
</data>
|
||||
<data name="Vault" xml:space="preserve">
|
||||
<value>الخزنة</value>
|
||||
<value>الخزانة</value>
|
||||
</data>
|
||||
<data name="Appearance" xml:space="preserve">
|
||||
<value>المظهر</value>
|
||||
@@ -2809,7 +2809,7 @@
|
||||
<value>{0} ساعات</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>استخدم Bitwarden لحفظ مفاتيح المرور الجديدة وتسجيل الدخول باستخدام مفاتيح المرور المخزنة في المخزن الخاص بك.</value>
|
||||
<value>استخدم Bitwarden لحفظ مفاتيح المرور الجديدة وتسجيل الدخول باستخدام مفاتيح المرور المخزنة في خزانتك.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>يتم استخدام إطار التعبئة التلقائية لأندرويد للمساعدة في ملء معلومات تسجيل الدخول في تطبيقات أخرى على جهازك.</value>
|
||||
@@ -2865,7 +2865,7 @@
|
||||
<value>استكشف المزيد من الميزات لحساب Bitwarden الخاص بك على تطبيق الويب.</value>
|
||||
</data>
|
||||
<data name="LearnAboutOrganizationsDescriptionLong" xml:space="preserve">
|
||||
<value>يتيح لك Bitwarden مشاركة عناصر خزنتك مع الآخرين باستخدام حساب المؤسسة. تعرف على المزيد على موقع bitwarden.com على شبكة الإنترنت.</value>
|
||||
<value>يتيح لك Bitwarden مشاركة عناصر خزانتك مع الآخرين باستخدام حساب المؤسسة. تعرف على المزيد على موقع bitwarden.com على شبكة الإنترنت.</value>
|
||||
</data>
|
||||
<data name="RateAppDescriptionLong" xml:space="preserve">
|
||||
<value>ساعد الآخرين في معرفة ما إذا كان Bitwarden مناسبا لهم. قم بزيارة متجر التطبيقات وترك التقييم الآن.</value>
|
||||
|
||||
@@ -364,7 +364,7 @@
|
||||
<comment>Label for a uri/url.</comment>
|
||||
</data>
|
||||
<data name="UseFingerprintToUnlock" xml:space="preserve">
|
||||
<value>Kilidi barmaq izi ilə açın</value>
|
||||
<value>Kilidi açmaq üçün barmaq izi istifadə et</value>
|
||||
</data>
|
||||
<data name="Username" xml:space="preserve">
|
||||
<value>İstifadəçi adı</value>
|
||||
@@ -468,7 +468,7 @@
|
||||
<value>Elementə düzəliş et</value>
|
||||
</data>
|
||||
<data name="EnableAutomaticSyncing" xml:space="preserve">
|
||||
<value>Avto-sinxr icazə ver</value>
|
||||
<value>Avto-sinxrn icazə ver</value>
|
||||
</data>
|
||||
<data name="EnterEmailForHint" xml:space="preserve">
|
||||
<value>Ana parol məsləhətini alacağınız hesabınızın e-poçt ünvanını daxil edin.</value>
|
||||
@@ -705,10 +705,10 @@
|
||||
<value>İki mərhələli giriş</value>
|
||||
</data>
|
||||
<data name="UnlockWith" xml:space="preserve">
|
||||
<value>{0} ilə kilidi açın</value>
|
||||
<value>Kilidi {0} ilə aç</value>
|
||||
</data>
|
||||
<data name="UnlockWithPIN" xml:space="preserve">
|
||||
<value>PIN kod ilə kilidi açın</value>
|
||||
<value>Kilidi PIN kodla aç</value>
|
||||
</data>
|
||||
<data name="Validating" xml:space="preserve">
|
||||
<value>Doğrulanır</value>
|
||||
@@ -1170,7 +1170,7 @@ Skan prosesi avtomatik baş tutacaq.</value>
|
||||
<value>Avto-doldurma əlçatımlılıq xidməti</value>
|
||||
</data>
|
||||
<data name="AutofillServiceDescription" xml:space="preserve">
|
||||
<value>Bitwarden avto-doldurma xidməti, giriş məlumatlarının cihazınızdakı digər tətbiqlərdə doldurmasına kömək etməsi üçün Android Avto-doldurma Çərçivəsini istifadə edir.</value>
|
||||
<value>Bitwarden avto-doldurma xidməti, cihazınızdakı digər tətbiqlərə giriş məlumatlarını doldurmağa kömək edən Android Avto-doldurma Çərçivəsini istifadə edir.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillServiceDescription" xml:space="preserve">
|
||||
<value>Giriş məlumatlarını digər tətbiqlərdə doldurmaq üçün Bitwarden avto-doldurma xidmətini istifadə edin.</value>
|
||||
@@ -1623,7 +1623,7 @@ Skan prosesi avtomatik baş tutacaq.</value>
|
||||
<value>Biometrik</value>
|
||||
</data>
|
||||
<data name="UseBiometricsToUnlock" xml:space="preserve">
|
||||
<value>Kilidi biometriklə aç</value>
|
||||
<value>Kilidi açmaq üçün biometrik istifadə et</value>
|
||||
</data>
|
||||
<data name="AccessibilityOverlayPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden diqqətinizi tələb edir - Bitwarden ayarlarında "Avto-doldurma əlçatımlılıq xidməti"nə baxın</value>
|
||||
@@ -1753,16 +1753,16 @@ Skan prosesi avtomatik baş tutacaq.</value>
|
||||
<value>Ana parolun doğrulanması gözlənildiyi üçün bu hesab üzrə avto-doldurma biometrik kilid açma sıradan çıxarıldı.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Təzələmə zamanı sinxr icazə ver</value>
|
||||
<value>Təzələmə zamanı sinxrn icazə ver</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefreshDescription" xml:space="preserve">
|
||||
<value>Barmağınızla aşağı çəkdikdə seyfi sinxronlaşdır.</value>
|
||||
</data>
|
||||
<data name="LogInSso" xml:space="preserve">
|
||||
<value>Müəssisə üçün tək daxil olma</value>
|
||||
<value>Müəssisə üçün vahid daxil olma</value>
|
||||
</data>
|
||||
<data name="LogInSsoSummary" xml:space="preserve">
|
||||
<value>Təşkilatınızın tək daxil olma portalını istifadə edərək daha tez giriş edə bilərsiniz. Başlatmaq üçün lütfən təşkilatınızın identifikatorunu daxil edin.</value>
|
||||
<value>Təşkilatınızın vahid daxil olma portalını istifadə edərək cəld giriş edin. Başlatmaq üçün lütfən təşkilatınızın identifikatorunu daxil edin.</value>
|
||||
</data>
|
||||
<data name="OrgIdentifier" xml:space="preserve">
|
||||
<value>Təşkilat identifikatoru</value>
|
||||
@@ -1822,16 +1822,16 @@ Skan prosesi avtomatik baş tutacaq.</value>
|
||||
<value>Bitwarden diqqətinizi tələb edir - Bitwarden Ayarlarında "Avto-doldurma xidməti"ndə "Üzərindən göstər"i işə salın</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Keçid açarının idarə edilməsi</value>
|
||||
<value>Keçid açarını idarəetmə</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Avto-doldurma xidmətləri</value>
|
||||
</data>
|
||||
<data name="InlineAutofill" xml:space="preserve">
|
||||
<value>Sətir daxili avto-doldurmanı istifadə edin</value>
|
||||
<value>Sətirdaxili avto-doldurmanı istifadə et</value>
|
||||
</data>
|
||||
<data name="InlineAutofillDescription" xml:space="preserve">
|
||||
<value>Seçdiyiniz IME (klaviatura) dəstəkləyirsə sətir daxili avto-doldurmanı istifadə edə bilərsiniz. Əgər konfiqurasiyanız dəstəkləmirsə (və ya bu seçim sıradan çıxarılıbsa) ilkin Avto-doldurma qutusu istifadə ediləcəkdir.</value>
|
||||
<value>Seçdiyiniz IME (klaviatura) dəstəkləyirsə sətirdaxili avto-doldurmanı istifadə edin. Əgər konfiqurasiyanız dəstəkləmirsə (və ya bu seçim söndürülübsə) ilkin Avto-doldurma örtüyü istifadə ediləcəkdir.</value>
|
||||
</data>
|
||||
<data name="Accessibility" xml:space="preserve">
|
||||
<value>Əlçatımlılığı istifadə et</value>
|
||||
@@ -1843,10 +1843,10 @@ Skan prosesi avtomatik baş tutacaq.</value>
|
||||
<value>Saytda və vebdə giriş məlumatlarınızı avto-doldurmaq üçün Bitwarden Əlçatımlılıq Xidmətini istifadə edin. ("Üzərində göstər" seçimi açıq olmalıdır)</value>
|
||||
</data>
|
||||
<data name="AccessibilityDescription3" xml:space="preserve">
|
||||
<value>Avto-doldurma cəld əməliyyat qutusunu istifadə etmək üçün Bitwarden əlçatımlılıq xidmətini istifadə edin və/və ya "Üzərində göstər"i (əgər fəaldırsa) istifadə edərək açılan bir pəncərə göstərə bilərsiniz.</value>
|
||||
<value>Avto-doldurma Cəld Əməliyyat Xanasını istifadə etmək üçün Bitwarden Əlçatımlılıq Xidmətini istifadə edin və/və ya "Üzərində göstər"i (əgər açıqdırsa) istifadə edərək açılan bir pəncərədə göstərin.</value>
|
||||
</data>
|
||||
<data name="AccessibilityDescription4" xml:space="preserve">
|
||||
<value>Avto-doldurma cəld əməliyyat qutusunu istifadə etmək və ya "Üzərində göstər"i (əgər fəaldırsa) istifadə edərək Avto-doldurma xidmətini təqlid etmək tələb olunur.</value>
|
||||
<value>Avto-doldurma Cəld Əməliyyat Xanasını istifadə etmək və ya "Üzərində göstər"i (əgər açıqdırsa) istifadə edərək Avto-doldurma xidmətini təqlid etmək üçün tələb olunur.</value>
|
||||
</data>
|
||||
<data name="DrawOver" xml:space="preserve">
|
||||
<value>"Üzərində göstər"i istifadə edin</value>
|
||||
@@ -2529,7 +2529,7 @@ Bu hesaba keçmək istəyirsiniz?</value>
|
||||
<value>Bu tələb artıq yararsızdır</value>
|
||||
</data>
|
||||
<data name="PendingLogInRequests" xml:space="preserve">
|
||||
<value>Giriş tələbləri gözlənilir</value>
|
||||
<value>Gözlənilən giriş tələbləri</value>
|
||||
</data>
|
||||
<data name="DeclineAllRequests" xml:space="preserve">
|
||||
<value>Bütün tələbləri rədd et</value>
|
||||
@@ -2810,10 +2810,10 @@ Bu hesaba keçmək istəyirsiniz?</value>
|
||||
<value>Yeni keçid açarlarını saxlamaq və seyfinizdəki keçid açarları ilə giriş etmək üçün Bitwarden-i istifadə edin.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>Android Avto-doldurma Çərçivəsi, giriş məlumatlarını cihazınızdakı digər tətbiqlərə doldurmağa kömək etmək üçün istifadə olunur.</value>
|
||||
<value>Android Avto-doldurma Çərçivəsi, cihazınızdakı digər tətbiqlərə giriş məlumatlarının doldurulmasına kömək etmək üçün istifadə olunur.</value>
|
||||
</data>
|
||||
<data name="UseInlineAutofillExplanationLong" xml:space="preserve">
|
||||
<value>Seçdiyiniz klaviatura dəstəkləyirsə sətir daxili avto-doldurmanı istifadə edin. Əks halda, ilkin örtük istifadə edin.</value>
|
||||
<value>Seçdiyiniz klaviatura dəstəkləyirsə sətirdaxili avto-doldurmanı istifadə edin. Əks halda, ilkin örtük istifadə edin.</value>
|
||||
</data>
|
||||
<data name="AdditionalOptions" xml:space="preserve">
|
||||
<value>Əlavə seçimlər</value>
|
||||
|
||||
@@ -910,7 +910,7 @@ Das Scannen erfolgt automatisch.</value>
|
||||
<value>TOTP kopieren</value>
|
||||
</data>
|
||||
<data name="CopyTotpAutomaticallyDescription" xml:space="preserve">
|
||||
<value>Ist ein Authentifizierungsschlüssel mit deinen Zugangsdaten verknüpft, wird der TOTP Verifizierungscode in die Zwischenablage kopiert, wenn du die Zugangsdaten automatisch einfügen lässt.</value>
|
||||
<value>Ist ein Authentifizierungsschlüssel mit deinen Zugangsdaten verknüpft, wird der TOTP-Verifizierungscode in deine Zwischenablage kopiert, wenn du die Zugangsdaten automatisch ausfüllen lässt.</value>
|
||||
</data>
|
||||
<data name="CopyTotpAutomatically" xml:space="preserve">
|
||||
<value>TOTP automatisch kopieren</value>
|
||||
|
||||
@@ -1134,7 +1134,7 @@ Koodi skannataan automaattisesti.</value>
|
||||
<value>Osoite</value>
|
||||
</data>
|
||||
<data name="Expiration" xml:space="preserve">
|
||||
<value>Erääntymisaika</value>
|
||||
<value>Voimassaolo päättyy</value>
|
||||
</data>
|
||||
<data name="ShowWebsiteIcons" xml:space="preserve">
|
||||
<value>Näytä sivustokuvakkeet</value>
|
||||
@@ -1931,7 +1931,7 @@ Koodi skannataan automaattisesti.</value>
|
||||
<value>Erääntymispäivä</value>
|
||||
</data>
|
||||
<data name="ExpirationTime" xml:space="preserve">
|
||||
<value>Erääntymisaika</value>
|
||||
<value>Voimassaolo päättyy</value>
|
||||
</data>
|
||||
<data name="ExpirationDateInfo" xml:space="preserve">
|
||||
<value>Send erääntyy määritettynä ajankohtana.</value>
|
||||
@@ -2935,11 +2935,11 @@ Haluatko vaihtaa tähän tiliin?</value>
|
||||
<value>Virhe luettaessa pääsyavainta</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Virhe luotaessa pääsyavainta osoitteelle {0}. Yritä myöhemmin uudelleen.</value>
|
||||
<value>Virhe luotaessa pääsyavainta kohteeseen {0}. Yritä myöhemmin uudelleen.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Virhe luettaessa osoitteen {0} pääsyavainta. Yritä myöhemmin uudelleen.</value>
|
||||
<value>Virhe luettaessa kohteen {0} pääsyavainta. Yritä myöhemmin uudelleen.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
|
||||
@@ -296,67 +296,67 @@
|
||||
<comment>Text to define that there are more options things to see.</comment>
|
||||
</data>
|
||||
<data name="MyVault" xml:space="preserve">
|
||||
<value>My vault</value>
|
||||
<value>A miña caixa forte</value>
|
||||
<comment>The title for the vault page.</comment>
|
||||
</data>
|
||||
<data name="Authenticator" xml:space="preserve">
|
||||
<value>Authenticator</value>
|
||||
<value>Autenticador</value>
|
||||
<comment>Authenticator TOTP feature</comment>
|
||||
</data>
|
||||
<data name="Name" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
<value>Nome</value>
|
||||
<comment>Label for an entity name.</comment>
|
||||
</data>
|
||||
<data name="No" xml:space="preserve">
|
||||
<value>No</value>
|
||||
<value>Non</value>
|
||||
</data>
|
||||
<data name="Notes" xml:space="preserve">
|
||||
<value>Notes</value>
|
||||
<value>Notas</value>
|
||||
<comment>Label for notes.</comment>
|
||||
</data>
|
||||
<data name="Ok" xml:space="preserve">
|
||||
<value>Ok</value>
|
||||
<value>Aceptar</value>
|
||||
<comment>Acknowledgement.</comment>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
<value>Contrasinal</value>
|
||||
<comment>Label for a password.</comment>
|
||||
</data>
|
||||
<data name="Save" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
<value>Gardar</value>
|
||||
<comment>Button text for a save operation (verb).</comment>
|
||||
</data>
|
||||
<data name="Move" xml:space="preserve">
|
||||
<value>Move</value>
|
||||
<value>Mover</value>
|
||||
</data>
|
||||
<data name="Saving" xml:space="preserve">
|
||||
<value>Saving...</value>
|
||||
<value>Gardando...</value>
|
||||
<comment>Message shown when interacting with the server</comment>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
<value>Axustes</value>
|
||||
<comment>The title for the settings page.</comment>
|
||||
</data>
|
||||
<data name="Show" xml:space="preserve">
|
||||
<value>Show</value>
|
||||
<value>Amosar</value>
|
||||
<comment>Reveal a hidden value (password).</comment>
|
||||
</data>
|
||||
<data name="ItemDeleted" xml:space="preserve">
|
||||
<value>Item deleted</value>
|
||||
<value>Elemento eliminado</value>
|
||||
<comment>Confirmation message after successfully deleting a login.</comment>
|
||||
</data>
|
||||
<data name="Submit" xml:space="preserve">
|
||||
<value>Submit</value>
|
||||
<value>Enviar</value>
|
||||
</data>
|
||||
<data name="Sync" xml:space="preserve">
|
||||
<value>Sync</value>
|
||||
<value>Sincronizar</value>
|
||||
<comment>The title for the sync page.</comment>
|
||||
</data>
|
||||
<data name="ThankYou" xml:space="preserve">
|
||||
<value>Thank you</value>
|
||||
<value>Grazas</value>
|
||||
</data>
|
||||
<data name="Tools" xml:space="preserve">
|
||||
<value>Tools</value>
|
||||
<value>Ferramentas</value>
|
||||
<comment>The title for the tools page.</comment>
|
||||
</data>
|
||||
<data name="URI" xml:space="preserve">
|
||||
@@ -364,53 +364,53 @@
|
||||
<comment>Label for a uri/url.</comment>
|
||||
</data>
|
||||
<data name="UseFingerprintToUnlock" xml:space="preserve">
|
||||
<value>Use fingerprint to unlock</value>
|
||||
<value>Engade unha pegada dactilar para desbloquear</value>
|
||||
</data>
|
||||
<data name="Username" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
<value>Nome de usuario</value>
|
||||
<comment>Label for a username.</comment>
|
||||
</data>
|
||||
<data name="ValidationFieldRequired" xml:space="preserve">
|
||||
<value>The {0} field is required.</value>
|
||||
<value>O campo {0} é obrigatorio.</value>
|
||||
<comment>Validation message for when a form field is left blank and is required to be entered.</comment>
|
||||
</data>
|
||||
<data name="ValueHasBeenCopied" xml:space="preserve">
|
||||
<value>{0} copied</value>
|
||||
<value>{0} copiados</value>
|
||||
<comment>Confirmation message after successfully copying a value to the clipboard.</comment>
|
||||
</data>
|
||||
<data name="VerifyFingerprint" xml:space="preserve">
|
||||
<value>Verify fingerprint</value>
|
||||
<value>Verifica a pegada dixital</value>
|
||||
</data>
|
||||
<data name="VerifyMasterPassword" xml:space="preserve">
|
||||
<value>Verify master password</value>
|
||||
<value>Verifica o contrasinal mestre</value>
|
||||
</data>
|
||||
<data name="VerifyPIN" xml:space="preserve">
|
||||
<value>Verify PIN</value>
|
||||
<value>Verifica o PIN</value>
|
||||
</data>
|
||||
<data name="Version" xml:space="preserve">
|
||||
<value>Version</value>
|
||||
<value>Versión</value>
|
||||
</data>
|
||||
<data name="View" xml:space="preserve">
|
||||
<value>View</value>
|
||||
<value>Vista</value>
|
||||
</data>
|
||||
<data name="VisitOurWebsite" xml:space="preserve">
|
||||
<value>Visit our website</value>
|
||||
<value>Visita o noso sitio web</value>
|
||||
</data>
|
||||
<data name="Website" xml:space="preserve">
|
||||
<value>Website</value>
|
||||
<value>Sitio web</value>
|
||||
<comment>Label for a website.</comment>
|
||||
</data>
|
||||
<data name="Yes" xml:space="preserve">
|
||||
<value>Yes</value>
|
||||
<value>Si</value>
|
||||
</data>
|
||||
<data name="Account" xml:space="preserve">
|
||||
<value>Account</value>
|
||||
<value>Conta</value>
|
||||
</data>
|
||||
<data name="AccountCreated" xml:space="preserve">
|
||||
<value>Your new account has been created! You may now log in.</value>
|
||||
<value>A túa nova conta foi creada! Podes iniciar sesión agora.</value>
|
||||
</data>
|
||||
<data name="AddAnItem" xml:space="preserve">
|
||||
<value>Add an Item</value>
|
||||
<value>Engadir un elemento</value>
|
||||
</data>
|
||||
<data name="AppExtension" xml:space="preserve">
|
||||
<value>App extension</value>
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
<value>Segnala un bug</value>
|
||||
</data>
|
||||
<data name="FileBugReportDescription" xml:space="preserve">
|
||||
<value>Segnala un problema nella nostra repository su GitHub.</value>
|
||||
<value>Segnala un problema nel nostro repository su GitHub.</value>
|
||||
</data>
|
||||
<data name="FingerprintDirection" xml:space="preserve">
|
||||
<value>Usa la tua impronta digitale per verificare.</value>
|
||||
@@ -285,7 +285,7 @@
|
||||
<value>Account già aggiunto</value>
|
||||
</data>
|
||||
<data name="SwitchToAlreadyAddedAccountConfirmation" xml:space="preserve">
|
||||
<value>Vuoi passarci adesso?</value>
|
||||
<value>Vuoi cambiarlo ora?</value>
|
||||
</data>
|
||||
<data name="MasterPassword" xml:space="preserve">
|
||||
<value>Password principale</value>
|
||||
@@ -375,7 +375,7 @@
|
||||
<comment>Validation message for when a form field is left blank and is required to be entered.</comment>
|
||||
</data>
|
||||
<data name="ValueHasBeenCopied" xml:space="preserve">
|
||||
<value>{0} copiata.</value>
|
||||
<value>{0} copiato</value>
|
||||
<comment>Confirmation message after successfully copying a value to the clipboard.</comment>
|
||||
</data>
|
||||
<data name="VerifyFingerprint" xml:space="preserve">
|
||||
@@ -407,7 +407,7 @@
|
||||
<value>Account</value>
|
||||
</data>
|
||||
<data name="AccountCreated" xml:space="preserve">
|
||||
<value>Il tuo nuovo account è stato creato! Ora puoi fare il login.</value>
|
||||
<value>Il tuo nuovo account è stato creato! Ora puoi effettuare il log in.</value>
|
||||
</data>
|
||||
<data name="AddAnItem" xml:space="preserve">
|
||||
<value>Aggiungi un elemento</value>
|
||||
@@ -523,7 +523,7 @@
|
||||
<value>Puoi importare in massa i tuoi login dalla cassaforte online di bitwarden.com. Vuoi visitare ora il sito?</value>
|
||||
</data>
|
||||
<data name="ImportItemsDescription" xml:space="preserve">
|
||||
<value>Importa rapidamente i tuoi elementi in massa da altri gestori di password.</value>
|
||||
<value>Importa rapidamente in massa i tuoi elementi da altri password manager.</value>
|
||||
</data>
|
||||
<data name="LastSync" xml:space="preserve">
|
||||
<value>Ultima sincronizzazione:</value>
|
||||
@@ -563,7 +563,7 @@
|
||||
<comment>Message shown when interacting with the server</comment>
|
||||
</data>
|
||||
<data name="LoginOrCreateNewAccount" xml:space="preserve">
|
||||
<value>Accedi o crea un nuovo account per aprire la tua cassaforte.</value>
|
||||
<value>Entra o crea un nuovo account per accedere alla tua cassaforte.</value>
|
||||
</data>
|
||||
<data name="Manage" xml:space="preserve">
|
||||
<value>Gestisci</value>
|
||||
@@ -638,7 +638,7 @@
|
||||
<value>Suggerimento password</value>
|
||||
</data>
|
||||
<data name="PasswordHintAlert" xml:space="preserve">
|
||||
<value>Ti abbiamo inviato un'email con il suggerimento per la password principale.</value>
|
||||
<value>Ti abbiamo inviato un'email con il tuo suggerimento per la password principale.</value>
|
||||
</data>
|
||||
<data name="PasswordOverrideAlert" xml:space="preserve">
|
||||
<value>Sei sicuro di voler sovrascrivere la password corrente?</value>
|
||||
@@ -695,7 +695,7 @@
|
||||
<value>Sincronizzazione fallita</value>
|
||||
</data>
|
||||
<data name="SyncVaultNow" xml:space="preserve">
|
||||
<value>Sincronizza cassaforte ora</value>
|
||||
<value>Sincronizza cassaforte</value>
|
||||
</data>
|
||||
<data name="TouchID" xml:space="preserve">
|
||||
<value>Touch ID</value>
|
||||
@@ -711,7 +711,7 @@
|
||||
<value>Sblocca con codice PIN</value>
|
||||
</data>
|
||||
<data name="Validating" xml:space="preserve">
|
||||
<value>Convalida</value>
|
||||
<value>Verifica in corso...</value>
|
||||
<comment>Message shown when interacting with the server</comment>
|
||||
</data>
|
||||
<data name="VerificationCode" xml:space="preserve">
|
||||
@@ -763,10 +763,10 @@
|
||||
<value>2. Attiva l'interruttore e clicca Consenti per accettare.</value>
|
||||
</data>
|
||||
<data name="Disabled" xml:space="preserve">
|
||||
<value>Disabilitato</value>
|
||||
<value>Disattivato</value>
|
||||
</data>
|
||||
<data name="Enabled" xml:space="preserve">
|
||||
<value>Attivo</value>
|
||||
<value>Attivato</value>
|
||||
</data>
|
||||
<data name="Off" xml:space="preserve">
|
||||
<value>No</value>
|
||||
@@ -817,7 +817,7 @@
|
||||
<comment>For 2FA</comment>
|
||||
</data>
|
||||
<data name="EnterVerificationCodeEmail" xml:space="preserve">
|
||||
<value>Digita il codice di verifica a 6 cifre ricevuto per email su {0}.</value>
|
||||
<value>Inserisci il codice di verifica a 6 cifre ricevuto inviato a {0}.</value>
|
||||
<comment>For 2FA</comment>
|
||||
</data>
|
||||
<data name="LoginUnavailable" xml:space="preserve">
|
||||
@@ -836,7 +836,7 @@
|
||||
<comment>Remember my two-step login</comment>
|
||||
</data>
|
||||
<data name="SendVerificationCodeAgain" xml:space="preserve">
|
||||
<value>Invia email con codice di verifica di nuovo</value>
|
||||
<value>Invia di nuovo l'email con codice di verifica</value>
|
||||
<comment>For 2FA</comment>
|
||||
</data>
|
||||
<data name="TwoStepLoginOptions" xml:space="preserve">
|
||||
@@ -877,7 +877,7 @@
|
||||
<comment>Message shown when downloading a file</comment>
|
||||
</data>
|
||||
<data name="AttachmentLargeWarning" xml:space="preserve">
|
||||
<value>Questo allegato ha dimensione {0}. Sei sicuro di volerlo scaricare sul tuo dispositivo?</value>
|
||||
<value>Questo allegato ha una dimensione di {0}. Sei sicuro di volerlo scaricare sul tuo dispositivo?</value>
|
||||
<comment>The placeholder will show the file size of the attachment. Ex "25 MB"</comment>
|
||||
</data>
|
||||
<data name="AuthenticatorKey" xml:space="preserve">
|
||||
@@ -1049,7 +1049,7 @@
|
||||
<value>Dicembre</value>
|
||||
</data>
|
||||
<data name="Dr" xml:space="preserve">
|
||||
<value>Dott</value>
|
||||
<value>Dr</value>
|
||||
</data>
|
||||
<data name="ExpirationMonth" xml:space="preserve">
|
||||
<value>Mese di scadenza</value>
|
||||
@@ -1154,7 +1154,7 @@
|
||||
<value>Vai alla mia cassaforte</value>
|
||||
</data>
|
||||
<data name="Collections" xml:space="preserve">
|
||||
<value>Raccolte</value>
|
||||
<value>Collezioni</value>
|
||||
</data>
|
||||
<data name="NoItemsCollection" xml:space="preserve">
|
||||
<value>Non ci sono elementi in questa raccolta.</value>
|
||||
@@ -1197,7 +1197,7 @@
|
||||
<value>Non siamo riusciti ad aprire automaticamente il menu delle impostazioni del fornitore di credenziali di Android per te. Puoi raggiungere il menu delle impostazioni del fornitore di credenziali manualmente da Impostazioni Android > Sistema > Password e account > Password, passkey, e servizi dati.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>Non siamo riusciti ad aprire le impostazioni del riempimento automatico di Android per te. Puoi navigare manualmente nelle impostazioni di riempimento automatico dalle Impostazioni di Android > Cerca Impostazioni > Cerca "Password e autofill"</value>
|
||||
<value>Non siamo riusciti ad aprire le impostazioni del riempimento automatico di Android per te. Puoi navigare manualmente nelle impostazioni di riempimento automatico dalle Impostazioni di Android > Cerca Impostazioni > Cerca "Password" > Seleziona "Compilazione automatica e password".</value>
|
||||
</data>
|
||||
<data name="CustomFieldName" xml:space="preserve">
|
||||
<value>Nome campo personalizzato</value>
|
||||
@@ -1779,7 +1779,7 @@
|
||||
<value>Una o più politiche dell'organizzazione richiedono che la tua password principale soddisfi questi requisiti:</value>
|
||||
</data>
|
||||
<data name="PolicyInEffectMinComplexity" xml:space="preserve">
|
||||
<value>Punteggio minimo di complessità {0}</value>
|
||||
<value>Punteggio di complessità minimo di {0}</value>
|
||||
</data>
|
||||
<data name="PolicyInEffectMinLength" xml:space="preserve">
|
||||
<value>Lunghezza minima di {0}</value>
|
||||
@@ -2563,7 +2563,7 @@ Vuoi passare a questo account?</value>
|
||||
<value>Importante</value>
|
||||
</data>
|
||||
<data name="YourMasterPasswordCannotBeRecoveredIfYouForgetItXCharactersMinimum" xml:space="preserve">
|
||||
<value>La tua password principale non può essere recuperata se la dimentichi! {0} caratteri minimi.</value>
|
||||
<value>La tua password principale non può essere recuperata se la dimentichi! Minimo {0} caratteri.</value>
|
||||
</data>
|
||||
<data name="WeakMasterPassword" xml:space="preserve">
|
||||
<value>Password principale debole</value>
|
||||
@@ -2593,7 +2593,7 @@ Vuoi passare a questo account?</value>
|
||||
<value>Password principale debole e violata</value>
|
||||
</data>
|
||||
<data name="WeakPasswordIdentifiedAndFoundInADataBreachAlertDescription" xml:space="preserve">
|
||||
<value>Password debole e trovata una violazione dei dati. Usa una password forte e unica per proteggere il tuo account. Sei sicuro di voler usare questa password?</value>
|
||||
<value>Password debole e trovata in una violazione dei dati. Usa una password forte e unica per proteggere il tuo account. Sei sicuro di voler usare questa password?</value>
|
||||
</data>
|
||||
<data name="OrganizationSsoIdentifierRequired" xml:space="preserve">
|
||||
<value>Identificatore SSO dell'organizzazione obbligatorio.</value>
|
||||
|
||||
@@ -2626,7 +2626,7 @@
|
||||
<value>지역</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour.</value>
|
||||
<value>마스터 비밀번호가 조직 정책에 맞지 않습니다. 보관함에 액세스하려면 지금 마스터 비밀번호를 업데이트해야 합니다. 계속하면 현재 세션에서 로그아웃되며 다시 로그인해야 합니다. 다른 장치의 활성 세션은 최대 1시간 동안 계속 활성 상태로 유지될 수 있습니다.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>현재 마스터 비밀번호</value>
|
||||
@@ -2759,7 +2759,7 @@
|
||||
<value>Logging in on</value>
|
||||
</data>
|
||||
<data name="Vault" xml:space="preserve">
|
||||
<value>Vault</value>
|
||||
<value>보관함</value>
|
||||
</data>
|
||||
<data name="Appearance" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
@@ -2783,13 +2783,13 @@
|
||||
<value>Unlock options</value>
|
||||
</data>
|
||||
<data name="SessionTimeout" xml:space="preserve">
|
||||
<value>Session timeout</value>
|
||||
<value>세션 만료</value>
|
||||
</data>
|
||||
<data name="SessionTimeoutAction" xml:space="preserve">
|
||||
<value>Session timeout action</value>
|
||||
<value>세션 만료 시 동작</value>
|
||||
</data>
|
||||
<data name="AccountFingerprintPhrase" xml:space="preserve">
|
||||
<value>Account fingerprint phrase</value>
|
||||
<value>계정 지문 구절</value>
|
||||
<comment>A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing.</comment>
|
||||
</data>
|
||||
<data name="OneHourAndOneMinute" xml:space="preserve">
|
||||
|
||||
@@ -2463,7 +2463,7 @@ jāizvēlas "Pievienot TOTP", lai droši glabātu atslēgu.</value>
|
||||
<value>Izmantot uzstādīto domēna visu tverošo iesūtni.</value>
|
||||
</data>
|
||||
<data name="ForwardedEmailDescription" xml:space="preserve">
|
||||
<value>Izveidot e-pastu aizstājvārdu ar ārēju pārvirzīšanas pakalpojumu.</value>
|
||||
<value>Izveidot e-pasta aizstājadresi ar ārēju pārvirzīšanas pakalpojumu.</value>
|
||||
</data>
|
||||
<data name="Random" xml:space="preserve">
|
||||
<value>Nejauši</value>
|
||||
|
||||
@@ -2632,7 +2632,7 @@
|
||||
<value>Текущий мастер-пароль</value>
|
||||
</data>
|
||||
<data name="LoggedIn" xml:space="preserve">
|
||||
<value>Вход выполнен!</value>
|
||||
<value>Выполнен вход!</value>
|
||||
</data>
|
||||
<data name="ApproveWithMyOtherDevice" xml:space="preserve">
|
||||
<value>Одобрить с другим устройством</value>
|
||||
|
||||
@@ -229,7 +229,7 @@
|
||||
<value>Priečinky</value>
|
||||
</data>
|
||||
<data name="FolderUpdated" xml:space="preserve">
|
||||
<value>Priečinok aktualizovaný.</value>
|
||||
<value>Priečinok bol uložený</value>
|
||||
</data>
|
||||
<data name="GoToWebsite" xml:space="preserve">
|
||||
<value>Prejsť na stránku</value>
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
<value>Bitwarden треба пажњу - Омогућите „Преко“ у „Сервиси Ауто-пуњења“ из подешавања Bitwarden-а</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Управљање приступачног кључа</value>
|
||||
<value>Управљање приступног кључа</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Сервиси Ауто-пуњења</value>
|
||||
@@ -2652,22 +2652,22 @@
|
||||
<value>Запамти овај уређај</value>
|
||||
</data>
|
||||
<data name="Passkey" xml:space="preserve">
|
||||
<value>Приступачни кључ</value>
|
||||
<value>Приступни кључ</value>
|
||||
</data>
|
||||
<data name="Passkeys" xml:space="preserve">
|
||||
<value>Приступачни кључеви</value>
|
||||
<value>Приступни кључеви</value>
|
||||
</data>
|
||||
<data name="Application" xml:space="preserve">
|
||||
<value>Апликација</value>
|
||||
</data>
|
||||
<data name="YouCannotEditPasskeyApplicationBecauseItWouldInvalidateThePasskey" xml:space="preserve">
|
||||
<value>Не може да се уреди апликација кључева јер би то поништило приступачни кључ</value>
|
||||
<value>Не може да се уреди апликација кључева јер би то поништило приступни кључ</value>
|
||||
</data>
|
||||
<data name="PasskeyWillNotBeCopied" xml:space="preserve">
|
||||
<value>Приступачни кључ неће бити копиран</value>
|
||||
<value>Приступни кључ неће бити копиран</value>
|
||||
</data>
|
||||
<data name="ThePasskeyWillNotBeCopiedToTheClonedItemDoYouWantToContinueCloningThisItem" xml:space="preserve">
|
||||
<value>Приступачни кључ неће бити копиран на клонирану ставку. Да ли желите да наставите са клонирањем ставке?</value>
|
||||
<value>Приступни кључ неће бити копиран на клонирану ставку. Да ли желите да наставите са клонирањем ставке?</value>
|
||||
</data>
|
||||
<data name="CopyApplication" xml:space="preserve">
|
||||
<value>Копирај апликацију</value>
|
||||
@@ -2930,10 +2930,10 @@
|
||||
<value>За ову радњу је потребна верификација. Подесите метод откључавања у Bitwarden да би наставили.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Грешка у креацији приступачног кључа</value>
|
||||
<value>Грешка у креацији приступног кључа</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Грешка у читању приступачног кључа</value>
|
||||
<value>Грешка у читању приступног кључа</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Дошло је до проблема при креирању приступачког кључа за {0}. Покушајте поново касније.</value>
|
||||
@@ -2956,7 +2956,7 @@
|
||||
<value>Подесити ауто-пуњење</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Имајте инстантни приступ Вашим лозинкама и приступачним кључевима!</value>
|
||||
<value>Имајте инстантни приступ Вашим лозинкама и приступним кључевима!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>Да бисте подесили ауто-пуњење лозинки и управљање приступним кључевима, подесите Bitwarden као ваш омиљени провајдер у подешавањима iOS-а.</value>
|
||||
|
||||
@@ -2008,7 +2008,7 @@ Skanningen sker automatiskt.</value>
|
||||
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
|
||||
</data>
|
||||
<data name="AddSend" xml:space="preserve">
|
||||
<value>Skapa ny Send</value>
|
||||
<value>Ny Send</value>
|
||||
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
|
||||
</data>
|
||||
<data name="AreYouSureDeleteSend" xml:space="preserve">
|
||||
|
||||
@@ -422,7 +422,7 @@
|
||||
<value>தன்னிரப்பி சேவை</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Set Bitwarden as your passkey provider in device settings.</value>
|
||||
<value>Bitwarden-ஐ உமது கடவுவிசை வழங்குநராகச் சாதன அமைவுகளில் அமை.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>தெளிவற்ற எழுத்துக்களைத் தவிர்</value>
|
||||
@@ -1823,7 +1823,7 @@
|
||||
<value>Bitwardenக்கு கவனம் தேவை - Bitwarden அமைப்புகளிலிருந்து "தன்னிரப்பி சேவைகள்"-இல் "மேலே-வரைதல்"-ஐ இயக்குக</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Passkey management</value>
|
||||
<value>கடவுவிசை நிர்வகிப்பு</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>தன்னிரப்பி சேவைகள்</value>
|
||||
|
||||
@@ -422,7 +422,7 @@
|
||||
<value>自动填充服务</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>在设备的设置中将 Bitwarden 设置为您的通行密钥提供程序。</value>
|
||||
<value>在设备的「设置」中将 Bitwarden 设置为您的通行密钥提供程序。</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>避免易混淆的字符</value>
|
||||
@@ -2257,7 +2257,7 @@
|
||||
<value>密码不可见,点击以显示。</value>
|
||||
</data>
|
||||
<data name="FilterByVault" xml:space="preserve">
|
||||
<value>按密码库过滤项目</value>
|
||||
<value>按密码库筛选项目</value>
|
||||
</data>
|
||||
<data name="AllVaults" xml:space="preserve">
|
||||
<value>所有密码库</value>
|
||||
|
||||
@@ -2808,7 +2808,7 @@
|
||||
<value>{0} 小時</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Use Bitwarden to save new passkeys and log in with passkeys stored in your vault.</value>
|
||||
<value>使用 Bitwarden 來保存新的通行密鑰(passkey) 和 使用儲存在密碼庫中的通行密鑰(passkey) 來登入。</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>Android 自動填入框架能協助在裝置上的其他應用程式當中,填入登入資訊。</value>
|
||||
@@ -2833,13 +2833,13 @@
|
||||
<value>接下來聯絡支援嗎?</value>
|
||||
</data>
|
||||
<data name="ContinueToPrivacyPolicy" xml:space="preserve">
|
||||
<value>Continue to privacy policy?</value>
|
||||
<value>繼續前往隱私權政策?</value>
|
||||
</data>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>接下來前往 App Store 嗎?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Continue to device Settings?</value>
|
||||
<value>繼續前往裝置設定?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>在 Bitwarden Web 應用程式中設定兩步驟登入,讓您的帳戶更加安全。</value>
|
||||
@@ -2858,7 +2858,7 @@
|
||||
<value>找不到您想要的資訊?請在 bitwarden.com 上聯絡 Bitwarden 技術支援。</value>
|
||||
</data>
|
||||
<data name="PrivacyPolicyDescriptionLong" xml:space="preserve">
|
||||
<value>Check out our privacy policy on bitwarden.com.</value>
|
||||
<value>在 bitwarden.com 上查看我們的隱私權政策。</value>
|
||||
</data>
|
||||
<data name="ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp" xml:space="preserve">
|
||||
<value>在 Web 應用程式上探索 Bitwarden 帳戶的更多功能。</value>
|
||||
@@ -2892,7 +2892,7 @@
|
||||
<value>設定解鎖選項,變更您密碼庫的逾時動作。</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Choose a login to save this passkey to</value>
|
||||
<value>選擇登入項目以保存這個通行密鑰(passkey) </value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Save passkey as new login</value>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"Add2FactorAutenticationToAnItemToViewVerificationCodes" = "Doğrulama kodlarına baxmaq üçün bir elementə 2 faktorlu kimlik doğrulama əlavə edin";
|
||||
"LogInToBitwardenOnYourIPhoneToViewVerificationCodes" = "Doğrulama kodlarına baxmaq üçün iPhone-nunuzda Bitwarden-ə giriş edin";
|
||||
"SyncingItemsContainingVerificationCodes" = "Doğrulama kodlarını ehtiva edən elementlər sinxronlaşdırılır";
|
||||
"UnlockBitwardenOnYourIPhoneToViewVerificationCodes" = "Doğrulama kodlarına baxmaq üçün iPhone-nunuzda Bitwarden-in kilidini açın";
|
||||
"UnlockBitwardenOnYourIPhoneToViewVerificationCodes" = "Doğrulama kodlarına baxmaq üçün Bitwarden-in kilidini iPhone-nunuzda açın";
|
||||
"SetUpBitwardenToViewItemsContainingVerificationCodes" = "Doğrulama kodlarını ehtiva edən elementlərə baxmaq üçün Bitwarden-i quraşdırın";
|
||||
"Search" = "Axtar";
|
||||
"NoItemsFound" = "Heç bir element tapılmadı";
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
"SetUpBitwardenToViewItemsContainingVerificationCodes" = "Jāuzstāda Bitwarden, lai apskatītu vienumus, kas satur apliecinājuma kodus";
|
||||
"Search" = "Meklēt";
|
||||
"NoItemsFound" = "Netika atrasti vienumi";
|
||||
"SetUpAppleWatchPasscodeInOrderToUseBitwarden" = "Jāuzstāda Apple Watch paroles vārdkopa, lai varētu izmantot Bitwarden";
|
||||
"SetUpAppleWatchPasscodeInOrderToUseBitwarden" = "Jāiestata Apple Watch piekļuves kods, lai varētu izmantot Bitwarden";
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
يتوفر Bitwarden بأكثر من 40 لغة، وتتنامى الترجمات بفضل مجتمعنا العالمي.
|
||||
|
||||
تطبيقات متعددة المنصات
|
||||
قم بحماية ومشاركة بياناتك الحساسة عبر خزنة Bitwarden من أي متصفح ويب، أو هاتف ذكي، أو جهاز كمبيوتر، وغيرها.
|
||||
قم بحماية ومشاركة بياناتك الحساسة عبر خزانة Bitwarden من أي متصفح ويب، أو هاتف ذكي، أو جهاز كمبيوتر، وغيرها.
|
||||
</value>
|
||||
<comment>Max 4000 characters</comment>
|
||||
</data>
|
||||
@@ -156,18 +156,18 @@
|
||||
<comment>Max 100 characters</comment>
|
||||
</data>
|
||||
<data name="Screenshot1" xml:space="preserve">
|
||||
<value>إدارة جميع تسجيلات الدخول وكلمات المرور الخاصة بك من خزنة آمنة</value>
|
||||
<value>إدارة جميع تسجيلات الدخول وكلمات المرور الخاصة بك من خزانة آمنة</value>
|
||||
</data>
|
||||
<data name="Screenshot2" xml:space="preserve">
|
||||
<value>إنشاء كلمات مرور قوية وعشوائية وآمنة تلقائيًا</value>
|
||||
</data>
|
||||
<data name="Screenshot3" xml:space="preserve">
|
||||
<value>حماية خزنتك باستخدام Touch ID أو رمز تعريف شخصي أو كلمة مرور رئيسية</value>
|
||||
<value>حماية خزانتك باستخدام Touch ID أو رمز تعريف شخصي أو كلمة مرور رئيسية</value>
|
||||
</data>
|
||||
<data name="Screenshot4" xml:space="preserve">
|
||||
<value>التعبئة التلقائية للمعرفات من سفاري، كروم، ومئات التطبيقات الأخرى</value>
|
||||
</data>
|
||||
<data name="Screenshot5" xml:space="preserve">
|
||||
<value>مزامنة خزنتك والوصول إليها من أجهزة متعددة</value>
|
||||
<value>مزامنة خزانتك والوصول إليها من أجهزة متعددة</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
يتوفر Bitwarden بأكثر من 40 لغة، وتتنامى الترجمات بفضل مجتمعنا العالمي.
|
||||
|
||||
تطبيقات متعددة المنصات
|
||||
قم بحماية ومشاركة بياناتك الحساسة عبر خزنة Bitwarden من أي متصفح ويب، أو هاتف ذكي، أو جهاز كمبيوتر، وغيرها.
|
||||
قم بحماية ومشاركة بياناتك الحساسة عبر خزانة Bitwarden من أي متصفح ويب، أو هاتف ذكي، أو جهاز كمبيوتر، وغيرها.
|
||||
</value>
|
||||
<comment>Max 4000 characters</comment>
|
||||
</data>
|
||||
@@ -165,13 +165,13 @@
|
||||
<value>إنشاء كلمات مرور قوية وعشوائية وآمنة تلقائيًا</value>
|
||||
</data>
|
||||
<data name="Screenshot3" xml:space="preserve">
|
||||
<value>حماية خزنتك باستخدام بصمة الإصبع أو رقم التعريف الشخصي أو كلمة المرور الرئيسية</value>
|
||||
<value>حماية خزانتك باستخدام بصمة الإصبع أو رقم التعريف الشخصي أو كلمة المرور الرئيسية</value>
|
||||
</data>
|
||||
<data name="Screenshot4" xml:space="preserve">
|
||||
<value>معرفات سريعة متكاملة ذاتيًا من متصفح الويب والتطبيقات الأخرى</value>
|
||||
</data>
|
||||
<data name="Screenshot5" xml:space="preserve">
|
||||
<value>مزامنة ووصول آمن لخزنتك من الأجهزة المختلفة
|
||||
<value>مزامنة ووصول آمن لخزانتك من الأجهزة المختلفة
|
||||
|
||||
- هاتف
|
||||
- جهاز لوحي
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
<comment>Max 30 characters</comment>
|
||||
</data>
|
||||
<data name="ShortDescription" xml:space="preserve">
|
||||
<value>Bitwarden è un gestore di login e password che ti aiuta a restare al sicuro online.</value>
|
||||
<value>Bitwarden è un gestore di password che ti aiuta a rimanere al sicuro online.</value>
|
||||
<comment>Max 80 characters</comment>
|
||||
</data>
|
||||
<data name="FullDesciption" xml:space="preserve">
|
||||
|
||||
Reference in New Issue
Block a user