# All files / api blob.ts

93.75% Statements 45/48
50% Branches 3/6
100% Functions 12/12
93.62% Lines 44/47

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143

    2x
    2x
    2x
    2x

    2x

    37x

    336x

    2x

    43x
    43x

    2x
    14x
    14x
    14x
    14x
    14x
    13x

    1x

    2x
    30x
    30x
    30x

    30x

    71x

    30x

    2x
    279x
    279x
    279x

    2x
    7x
    7x
    7x
    7x
    20x

    7x

    2x
    270x

    2x
    14x

    2x
    171x

    2x

    2x

     /**
     * Copyright 2017 Google Inc.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *   http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */

    import { PlatformSupport } from '../platform/platform';
    import { makeConstructorPrivate } from '../util/api';
    import { Code, FirestoreError } from '../util/error';
    import {
      invalidClassError,
      validateArgType,
      validateExactNumberOfArgs
    } from '../util/input_validation';
    import { primitiveComparator } from '../util/misc';

    /** Helper function to assert Uint8Array is available at runtime. */
    function assertUint8ArrayAvailable() {
      Iif (typeof Uint8Array === 'undefined') {
        throw new FirestoreError(
          Code.UNIMPLEMENTED,
          'Uint8Arrays are not available in this environment.'
        );
      }
    }

    /** Helper function to assert Base64 functions are available at runtime. */
    function assertBase64Available() {
      Iif (!PlatformSupport.getPlatform().base64Available) {
        throw new FirestoreError(
          Code.UNIMPLEMENTED,
          'Blobs are unavailable in Firestore in this environment.'
        );
      }
    }

    /**
     * Immutable class holding a blob (binary data).
     * This class is directly exposed in the public API.
     *
     * Note that while you can't hide the constructor in JavaScript code, we are
     * using the hack above to make sure no-one outside this module can call it.
     */
    export class Blob {
      // Prefix with underscore to signal this is a private variable in JS and
      // prevent it showing up for autocompletion.
      // A binary string is a string with each char as Unicode code point in the
      // range of [0, 255], essentially simulating a byte array.
      private _binaryString: string;

      private constructor(binaryString: string) {
        assertBase64Available();
        this._binaryString = binaryString;
      }

      static fromBase64String(base64: string): Blob {
        validateExactNumberOfArgs('Blob.fromBase64String', arguments, 1);
        validateArgType('Blob.fromBase64String', 'string', 1, base64);
        assertBase64Available();
        try {
          const binaryString = PlatformSupport.getPlatform().atob(base64);
          return new Blob(binaryString);
        } catch (e) {
          throw new FirestoreError(
            Code.INVALID_ARGUMENT,
            'Failed to construct Blob from Base64 string: ' + e
          );
        }
      }

      static fromUint8Array(array: Uint8Array): Blob {
        validateExactNumberOfArgs('Blob.fromUint8Array', arguments, 1);
        assertUint8ArrayAvailable();
        Iif (!(array instanceof Uint8Array)) {
          throw invalidClassError('Blob.fromUint8Array', 'Uint8Array', 1, array);
        }
        // We can't call array.map directly because it expects the return type to
        // be a Uint8Array, whereas we can convert it to a regular array by invoking
        // map on the Array prototype.
        const binaryString = Array.prototype.map
          .call(array, (char: number) => {
            return String.fromCharCode(char);
          })
          .join('');
        return new Blob(binaryString);
      }

      toBase64(): string {
        validateExactNumberOfArgs('Blob.toBase64', arguments, 0);
        assertBase64Available();
        return PlatformSupport.getPlatform().btoa(this._binaryString);
      }

      toUint8Array(): Uint8Array {
        validateExactNumberOfArgs('Blob.toUint8Array', arguments, 0);
        assertUint8ArrayAvailable();
        const buffer = new Uint8Array(this._binaryString.length);
        for (let i = 0; i < this._binaryString.length; i++) {
          buffer[i] = this._binaryString.charCodeAt(i);
        }
        return buffer;
      }

      toString(): string {
        return 'Blob(base64: ' + this.toBase64() + ')';
      }

      isEqual(other: Blob): boolean {
        return this._binaryString === other._binaryString;
      }

      /**
       * Actually private to JS consumers of our API, so this function is prefixed
       * with an underscore.
       */
      _compareTo(other: Blob): number {
        return primitiveComparator(this._binaryString, other._binaryString);
      }
    }

    // Public instance that disallows construction at runtime. This constructor is
    // used when exporting Blob on firebase.firestore.Blob and will be called Blob
    // publicly. Internally we still use Blob which has a type checked private
    // constructor. Note that Blob and PublicBlob can be used interchangeably in
    // instanceof checks.
    // For our internal TypeScript code PublicBlob doesn't exist as a type, and so
    // we need to use Blob as type and export it too.
    // tslint:disable-next-line:variable-name We're treating this as a class name.
    export let PublicBlob = makeConstructorPrivate(
      Blob,
      'Use Blob.fromUint8Array() or Blob.fromBase64String() instead.'
    );