/**
 * Copyright(c) Live2D Inc. All rights reserved.
 *
 * Use of this source code is governed by the Live2D Open Software license
 * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
 */ import { strtod } from '../live2dcubismframework' ; import { csmMap , iterator as csmMap_iterator } from '../type/csmmap' ; import { csmString } from '../type/csmstring' ; import { csmVector , iterator as csmVector_iterator } from '../type/csmvector' ; import { CubismLogInfo } from './cubismdebug' ; const CSM_JSON_ERROR_TYPE_MISMATCH = 'Error: type mismatch' ; const CSM_JSON_ERROR_INDEX_OF_BOUNDS = 'Error: index out of bounds' ; /**
 * パースしたJSONエレメントの要素の基底クラス。
 */ export abstract class Value { /**
     * コンストラクタ
     */ public constructor ( ) { } /**
     * 要素を文字列型で返す(csmString型)
     */ public abstract getString ( defaultValue ? , indent ? ) ; /**
     * 要素を文字列型で返す(string)
     */ public getRawString ( defaultValue ? , indent ? ) { return this . getString ( defaultValue , indent ) ; } /**
     * 要素を数値型で返す(number)
     */ public toInt ( defaultValue = 0 ) { return defaultValue ; } /**
     * 要素を数値型で返す(number)
     */ public toFloat ( defaultValue = 0 ) { return defaultValue ; } /**
     * 要素を真偽値で返す(boolean)
     */ public toBoolean ( defaultValue = false ) { return defaultValue ; } /**
     * サイズを返す
     */ public getSize ( ) { return 0 ; } /**
     * 要素を配列で返す(Value[])
     */ public getArray ( defaultValue = null ) { return defaultValue ; } /**
     * 要素をコンテナで返す(array)
     */ public getVector ( defaultValue = new csmVector < Value > ( ) ) { return defaultValue ; } /**
     * 要素をマップで返す(csmMap<csmString, Value>)
     */ public getMap ( defaultValue ? ) { return defaultValue ; } /**
     * 添字演算子[index]
     */ public getValueByIndex ( index ) { return Value . errorValue . setErrorNotForClientCall ( CSM_JSON_ERROR_TYPE_MISMATCH ) ; } /**
     * 添字演算子[string | csmString]
     */ public getValueByString ( s ) { return Value . nullValue . setErrorNotForClientCall ( CSM_JSON_ERROR_TYPE_MISMATCH ) ; } return public getKeys ( ) { return Value . s_dummyKeys ; } /**
     * Valueの種類がエラー値ならtrue
     */ public isError ( ) { return false ; } /**
     * Valueの種類がnullならtrue
     */ public isNull ( ) { return false ; } /**
     * Valueの種類が真偽値ならtrue
     */ public isBool ( ) { return false ; } /**
     * Valueの種類が数値型ならtrue
     */ public isFloat ( ) { return false ; } /**
     * Valueの種類が文字列ならtrue
     */ public isString ( ) { return false ; } /**
     * Valueの種類が配列ならtrue
     */ public isArray ( ) { return false ; } /**
     * Valueの種類がマップ型ならtrue
     */ public isMap ( ) { return false ; } /**
     * 引数の値と等しければtrue
     */ public equals ( value ) ; public equals ( value ) ; public equals ( value ) ; public equals ( value ) ; public equals ( value ) { return false ; } /**
     * Valueの値が静的ならtrue、静的なら解放しない
     */ public isStatic ( ) { return false ; } /**
     * Valueにエラー値をセットする
     */ public setErrorNotForClientCall ( errorStr ) { return JsonError . errorValue ; } /**
     * 初期化用メソッド
     */ public static staticInitializeNotForClientCall ( ) { JsonBoolean . trueValue = new JsonBoolean ( true ) ; JsonBoolean . falseValue = new JsonBoolean ( false ) ; Value . errorValue = new JsonError ( 'ERROR' , true ) ; Value . nullValue = new JsonNullvalue ( ) ; Value . s_dummyKeys = new csmVector < string > ( ) ; } /**
     * リリース用メソッド
     */ public static staticReleaseNotForClientCall ( ) { JsonBoolean . trueValue = null ; JsonBoolean . falseValue = null ; Value . errorValue = null ; Value . nullValue = null ; Value . s_dummyKeys = null ; } protected _stringBuffer : string ; private static s_dummyKeys : csmVector < string > ; public static errorValue : Value ; public static nullValue : Value ; } /**
 * Ascii文字のみ対応した最小限の軽量JSONパーサ。
 * 仕様はJSONのサブセットとなる。
 * 設定ファイル(model3.json)などのロード用
 *
 * [未対応項目]
 * ・日本語などの非ASCII文字
 * ・eによる指数表現
 */ export class CubismJson { /**
     * コンストラクタ
     */ public constructor ( buffer ? , length ? ) { this . _error = null ; this . _lineCount = 0 ; this . _root = null ; if ( buffer != undefined ) { this . parseBytes ( buffer , length ) ; } } param buffer param size return public static create ( buffer , size ) { const json = new CubismJson ( ) ; const succeeded = json . parseBytes ( buffer , size ) ; if ( ! succeeded ) { CubismJson . delete ( json ) ; return null ; } else { return json ; } } param instance public static delete ( instance ) { instance = null ; } /**
     * パースしたJSONのルート要素を返す
     */ public getRoot ( ) { return this . _root ; } param buffer return public arrayBufferToString ( buffer ) { const uint8Array = new Uint8Array ( buffer ) ; let str = '' ; for ( let i = 0 , len = uint8Array . length ; i < len ; ++ i ) { str += '%' + this . pad ( uint8Array [ i ] . toString ( 16 ) ) ; } str = decodeURIComponent ( str ) ; return str ; } /**
     * エンコード、パディング
     */ private pad ( n ) { return n . length < 2 ? '0' + n : n ; } param buffer param size public parseBytes ( buffer , size ) { const endPos = new Array ( 1 ) ; const decodeBuffer = this . arrayBufferToString ( buffer ) ; this . _root = this . parseValue ( decodeBuffer , size , 0 , endPos ) ; if ( this . _error ) { let strbuf = '\0' ; strbuf = 'Json parse error : @line ' + ( this . _lineCount + 1 ) + '\n' ; this . _root = new JsonString ( strbuf ) ; CubismLogInfo ( '{0}' , this . _root . getRawString ( ) ) ; return false ; } else if ( this . _root == null ) { this . _root = new JsonError ( new csmString ( this . _error ) , false ) ; return false ; } return true ; } /**
     * パース時のエラー値を返す
     */ public getParseError ( ) { return this . _error ; } /**
     * ルート要素の次の要素がファイルの終端だったらtrueを返す
     */ public checkEndOfFile ( ) { return this . _root . getArray ( ) [ 1 ] . equals ( 'EOF' ) ; } param buffer param length param begin param outEndPos return protected parseValue ( buffer , length , begin , outEndPos ) { if ( this . _error ) return null ; let o = null ; let i = begin ; let f ; for ( ; i < length ; i ++ ) { const c = buffer [ i ] ; switch ( c ) { case '-' : case '.' : case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : { const afterString = new Array ( 1 ) ; f = strtod ( buffer . slice ( i ) , afterString ) ; outEndPos [ 0 ] = buffer . indexOf ( afterString [ 0 ] ) ; return new JsonFloat ( f ) ; } case '"' : return new JsonString ( this . parseString ( buffer , length , i + 1 , outEndPos ) ) ; case '[' : o = this . parseArray ( buffer , length , i + 1 , outEndPos ) ; return o ; case '{' : o = this . parseObject ( buffer , length , i + 1 , outEndPos ) ; return o ; case 'n' : if ( i + 3 < length ) { o = new JsonNullvalue ( ) ; outEndPos [ 0 ] = i + 4 ; } else { this . _error = 'parse null' ; } return o ; case 't' : if ( i + 3 < length ) { o = JsonBoolean . trueValue ; outEndPos [ 0 ] = i + 4 ; } else { this . _error = 'parse true' ; } return o ; case 'f' : if ( i + 4 < length ) { o = JsonBoolean . falseValue ; outEndPos [ 0 ] = i + 5 ; } else { this . _error = "illegal ',' position" ; } return o ; case ',' : this . _error = "illegal ',' position" ; return null ; case ']' : outEndPos [ 0 ] = i ; return null ; case '\n' : this . _lineCount ++ ; case ' ' : case '\t' : case '\r' : default : break ; } } this . _error = 'illegal end of value' ; return null ; } param string param length param begin param outEndPos return protected parseString ( string , length , begin , outEndPos ) { if ( this . _error ) return null ; let i = begin ; let c , c2 ; const ret = new csmString ( '' ) ; let bufStart = begin ; for ( ; i < length ; i ++ ) { c = string [ i ] ; switch ( c ) { case '"' : { outEndPos [ 0 ] = i + 1 ; ret . append ( string . slice ( bufStart ) , i - bufStart ) ; return ret . s ; } case '//' : { i ++ ; if ( i - 1 > bufStart ) { ret . append ( string . slice ( bufStart ) , i - bufStart ) ; } bufStart = i + 1 ; if ( i < length ) { c2 = string [ i ] ; switch ( c2 ) { case '\\' : ret . expansion ( 1 , '\\' ) ; break ; case '"' : ret . expansion ( 1 , '"' ) ; break ; case '/' : ret . expansion ( 1 , '/' ) ; break ; case 'b' : ret . expansion ( 1 , '\b' ) ; break ; case 'f' : ret . expansion ( 1 , '\f' ) ; break ; case 'n' : ret . expansion ( 1 , '\n' ) ; break ; case 'r' : ret . expansion ( 1 , '\r' ) ; break ; case 't' : ret . expansion ( 1 , '\t' ) ; break ; case 'u' : this . _error = 'parse string/unicord escape not supported' ; break ; default : break ; } } else { this . _error = 'parse string/escape error' ; } } default : { break ; } } } this . _error = 'parse string/illegal end' ; return null ; } param buffer param length param begin param outEndPos return protected parseObject ( buffer , length , begin , outEndPos ) { if ( this . _error ) return null ; const ret = new JsonMap ( ) ; let key = '' ; let i = begin ; let c = '' ; const localRetEndPos2 = Array ( 1 ) ; let ok = false ; for ( ; i < length ; i ++ ) { FOR_LOOP : for ( ; i < length ; i ++ ) { c = buffer [ i ] ; switch ( c ) { case '"' : key = this . parseString ( buffer , length , i + 1 , localRetEndPos2 ) ; if ( this . _error ) { return null ; } i = localRetEndPos2 [ 0 ] ; ok = true ; break FOR_LOOP ; case '}' : outEndPos [ 0 ] = i + 1 ; return ret ; case ':' : this . _error = "illegal ':' position" ; break ; case '\n' : this . _lineCount ++ ; default : break ; } } if ( ! ok ) { this . _error = 'key not found' ; return null ; } ok = false ; FOR_LOOP2 : for ( ; i < length ; i ++ ) { c = buffer [ i ] ; switch ( c ) { case ':' : ok = true ; i ++ ; break FOR_LOOP2 ; case '}' : this . _error = "illegal '}' position" ; break ; case '\n' : this . _lineCount ++ ; default : break ; } } if ( ! ok ) { this . _error = "':' not found" ; return null ; } const value = this . parseValue ( buffer , length , i , localRetEndPos2 ) ; if ( this . _error ) { return null ; } i = localRetEndPos2 [ 0 ] ; ret . put ( key , value ) ; FOR_LOOP3 : for ( ; i < length ; i ++ ) { c = buffer [ i ] ; switch ( c ) { case ',' : break FOR_LOOP3 ; case '}' : outEndPos [ 0 ] = i + 1 ; return ret ; case '\n' : this . _lineCount ++ ; default : break ; } } } this . _error = 'illegal end of perseObject' ; return null ; } param buffer param length param begin param outEndPos return protected parseArray ( buffer , length , begin , outEndPos ) { if ( this . _error ) return null ; let ret = new JsonArray ( ) ; let i = begin ; let c ; const localRetEndpos2 = new Array ( 1 ) ; for ( ; i < length ; i ++ ) { const value = this . parseValue ( buffer , length , i , localRetEndpos2 ) ; if ( this . _error ) { return null ; } i = localRetEndpos2 [ 0 ] ; if ( value ) { ret . add ( value ) ; } FOR_LOOP : for ( ; i < length ; i ++ ) { c = buffer [ i ] ; switch ( c ) { case ',' : break FOR_LOOP ; case ']' : outEndPos [ 0 ] = i + 1 ; return ret ; case '\n' : ++ this . _lineCount ; default : break ; } } } ret = void 0 ; this . _error = 'illegal end of parseObject' ; return null ; } _error : string ; _lineCount : number ; _root : Value ; } /**
 * パースしたJSONの要素をfloat値として扱う
 */ export class JsonFloat extends Value { /**
     * コンストラクタ
     */ constructor ( v ) { super ( ) ; this . _value = v ; } /**
     * Valueの種類が数値型ならtrue
     */ public isFloat ( ) { return true ; } /**
     * 要素を文字列で返す(csmString型)
     */ public getString ( defaultValue , indent ) { const strbuf = '\0' ; this . _value = parseFloat ( strbuf ) ; this . _stringBuffer = strbuf ; return this . _stringBuffer ; } /**
     * 要素を数値型で返す(number)
     */ public toInt ( defaultValue = 0 ) { return parseInt ( this . _value . toString ( ) ) ; } /**
     * 要素を数値型で返す(number)
     */ public toFloat ( defaultValue = 0.0 ) { return this . _value ; } /**
     * 引数の値と等しければtrue
     */ public equals ( value ) ; public equals ( value ) ; public equals ( value ) ; public equals ( value ) ; public equals ( value ) { if ( 'number' === typeof value ) { if ( Math . round ( value ) ) { return false ; } else { return value == this . _value ; } } return false ; } private _value : number ; } /**
 * パースしたJSONの要素を真偽値として扱う
 */ export class JsonBoolean extends Value { /**
     * Valueの種類が真偽値ならtrue
     */ public isBool ( ) { return true ; } /**
     * 要素を真偽値で返す(boolean)
     */ public toBoolean ( defaultValue = false ) { return this . _boolValue ; } /**
     * 要素を文字列で返す(csmString型)
     */ public getString ( defaultValue , indent ) { this . _stringBuffer = this . _boolValue ? 'true' : 'false' ; return this . _stringBuffer ; } /**
     * 引数の値と等しければtrue
     */ public equals ( value ) ; public equals ( value ) ; public equals ( value ) ; public equals ( value ) ; public equals ( value ) { if ( 'boolean' === typeof value ) { return value == this . _boolValue ; } return false ; } /**
     * Valueの値が静的ならtrue, 静的なら解放しない
     */ public isStatic ( ) { return true ; } /**
     * 引数付きコンストラクタ
     */ public constructor ( v ) { super ( ) ; this . _boolValue = v ; } static trueValue : JsonBoolean ; static falseValue : JsonBoolean ; private _boolValue : boolean ; } /**
 * パースしたJSONの要素を文字列として扱う
 */ export class JsonString extends Value { /**
     * 引数付きコンストラクタ
     */ public constructor ( s ) ; public constructor ( s ) ; public constructor ( s ) { super ( ) ; if ( 'string' === typeof s ) { this . _stringBuffer = s ; } if ( s instanceof csmString ) { this . _stringBuffer = s . s ; } } /**
     * Valueの種類が文字列ならtrue
     */ public isString ( ) { return true ; } /**
     * 要素を文字列で返す(csmString型)
     */ public getString ( defaultValue , indent ) { return this . _stringBuffer ; } /**
     * 引数の値と等しければtrue
     */ public equals ( value ) ; public equals ( value ) ; public equals ( value ) ; public equals ( value ) ; public equals ( value ) { if ( 'string' === typeof value ) { return this . _stringBuffer == value ; } if ( value instanceof csmString ) { return this . _stringBuffer == value . s ; } return false ; } } /**
 * JSONパース時のエラー結果。文字列型のようにふるまう
 */ export class JsonError extends JsonString { /**
     * Valueの値が静的ならtrue、静的なら解放しない
     */ public isStatic ( ) { return this . _isStatic ; } /**
     * エラー情報をセットする
     */ public setErrorNotForClientCall ( s ) { this . _stringBuffer = s ; return this ; } /**
     * 引数付きコンストラクタ
     */ public constructor ( s , isStatic ) { if ( 'string' === typeof s ) { super ( s ) ; } else { super ( s ) ; } this . _isStatic = isStatic ; } /**
     * Valueの種類がエラー値ならtrue
     */ public isError ( ) { return true ; } protected _isStatic : boolean ; } /**
 * パースしたJSONの要素をNULL値として持つ
 */ export class JsonNullvalue extends Value { /**
     * Valueの種類がNULL値ならtrue
     */ public isNull ( ) { return true ; } /**
     * 要素を文字列で返す(csmString型)
     */ public getString ( defaultValue , indent ) { return this . _stringBuffer ; } /**
     * Valueの値が静的ならtrue, 静的なら解放しない
     */ public isStatic ( ) { return true ; } /**
     * Valueにエラー値をセットする
     */ public setErrorNotForClientCall ( s ) { this . _stringBuffer = s ; return JsonError . nullValue ; } /**
     * コンストラクタ
     */ public constructor ( ) { super ( ) ; this . _stringBuffer = 'NullValue' ; } } /**
 * パースしたJSONの要素を配列として持つ
 */ export class JsonArray extends Value { /**
     * コンストラクタ
     */ public constructor ( ) { super ( ) ; this . _array = new csmVector < Value > ( ) ; } /**
     * デストラクタ相当の処理
     */ public release ( ) { for ( let ite = this . _array . begin ( ) ; ite . notEqual ( this . _array . end ( ) ) ; ite . preIncrement ( ) ) { let v = ite . ptr ( ) ; if ( v && ! v . isStatic ( ) ) { v = void 0 ; v = null ; } } } /**
     * Valueの種類が配列ならtrue
     */ public isArray ( ) { return true ; } /**
     * 添字演算子[index]
     */ public getValueByIndex ( index ) { if ( index < 0 || this . _array . getSize ( ) <= index ) { return Value . errorValue . setErrorNotForClientCall ( CSM_JSON_ERROR_INDEX_OF_BOUNDS ) ; } const v = this . _array . at ( index ) ; if ( v == null ) { return Value . nullValue ; } return v ; } /**
     * 添字演算子[string | csmString]
     */ public getValueByString ( s ) { return Value . errorValue . setErrorNotForClientCall ( CSM_JSON_ERROR_TYPE_MISMATCH ) ; } /**
     * 要素を文字列で返す(csmString型)
     */ public getString ( defaultValue , indent ) { const stringBuffer = indent + '[\n' ; for ( let ite = this . _array . begin ( ) ; ite . notEqual ( this . _array . end ( ) ) ; ite . increment ( ) ) { const v = ite . ptr ( ) ; this . _stringBuffer += indent + '' + v . getString ( indent + ' ' ) + '\n' ; } this . _stringBuffer = stringBuffer + indent + ']\n' ; return this . _stringBuffer ; } param v public add ( v ) { this . _array . pushBack ( v ) ; } /**
     * 要素をコンテナで返す(csmVector<Value>)
     */ public getVector ( defaultValue = null ) { return this . _array ; } /**
     * 要素の数を返す
     */ public getSize ( ) { return this . _array . getSize ( ) ; } private _array : csmVector < Value > ; } /**
 * パースしたJSONの要素をマップとして持つ
 */ export class JsonMap extends Value { /**
     * コンストラクタ
     */ public constructor ( ) { super ( ) ; this . _map = new csmMap < string , Value > ( ) ; } /**
     * デストラクタ相当の処理
     */ public release ( ) { const ite = this . _map . begin ( ) ; while ( ite . notEqual ( this . _map . end ( ) ) ) { let v = ite . ptr ( ) . second ; if ( v && ! v . isStatic ( ) ) { v = void 0 ; v = null ; } ite . preIncrement ( ) ; } } /**
     * Valueの値がMap型ならtrue
     */ public isMap ( ) { return true ; } /**
     * 添字演算子[string | csmString]
     */ public getValueByString ( s ) { if ( s instanceof csmString ) { const ret = this . _map . getValue ( s . s ) ; if ( ret == null ) { return Value . nullValue ; } return ret ; } for ( let iter = this . _map . begin ( ) ; iter . notEqual ( this . _map . end ( ) ) ; iter . preIncrement ( ) ) { if ( iter . ptr ( ) . first == s ) { if ( iter . ptr ( ) . second == null ) { return Value . nullValue ; } return iter . ptr ( ) . second ; } } return Value . nullValue ; } /**
     * 添字演算子[index]
     */ public getValueByIndex ( index ) { return Value . errorValue . setErrorNotForClientCall ( CSM_JSON_ERROR_TYPE_MISMATCH ) ; } /**
     * 要素を文字列で返す(csmString型)
     */ public getString ( defaultValue , indent ) { this . _stringBuffer = indent + '{\n' ; const ite = this . _map . begin ( ) ; while ( ite . notEqual ( this . _map . end ( ) ) ) { const key = ite . ptr ( ) . first ; const v = ite . ptr ( ) . second ; this . _stringBuffer += indent + ' ' + key + ' : ' + v . getString ( indent + '   ' ) + ' \n' ; ite . preIncrement ( ) ; } this . _stringBuffer += indent + '}\n' ; return this . _stringBuffer ; } /**
     * 要素をMap型で返す
     */ public getMap ( defaultValue ? ) { return this . _map ; } /**
     * Mapに要素を追加する
     */ public put ( key , v ) { this . _map . setValue ( key , v ) ; } /**
     * Mapからキーのリストを取得する
     */ public getKeys ( ) { if ( ! this . _keys ) { this . _keys = new csmVector < string > ( ) ; const ite = this . _map . begin ( ) ; while ( ite . notEqual ( this . _map . end ( ) ) ) { const key = ite . ptr ( ) . first ; this . _keys . pushBack ( key ) ; ite . preIncrement ( ) ; } } return this . _keys ; } /**
     * Mapの要素数を取得する
     */ public getSize ( ) { return this . _keys . getSize ( ) ; } private _map : csmMap < string , Value > ; private _keys : csmVector < string > ; } import * as $ from './cubismjson' ; export namespace Live2DCubismFramework { export const CubismJson = $ . CubismJson ; export type CubismJson = $ . CubismJson ; export const JsonArray = $ . JsonArray ; export type JsonArray = $ . JsonArray ; export const JsonBoolean = $ . JsonBoolean ; export type JsonBoolean = $ . JsonBoolean ; export const JsonError = $ . JsonError ; export type JsonError = $ . JsonError ; export const JsonFloat = $ . JsonFloat ; export type JsonFloat = $ . JsonFloat ; export const JsonMap = $ . JsonMap ; export type JsonMap = $ . JsonMap ; export const JsonNullvalue = $ . JsonNullvalue ; export type JsonNullvalue = $ . JsonNullvalue ; export const JsonString = $ . JsonString ; export type JsonString = $ . JsonString ; export const Value = $ . Value ; export type Value = $ . Value ; }