Full Code of node-modules/hessian.js for AI

master 45c7694b8ade cached
52 files
313.1 KB
97.4k tokens
12 symbols
1 requests
Download .txt
Showing preview only (329K chars total). Download the full file or copy to clipboard to get everything.
Repository: node-modules/hessian.js
Branch: master
Commit: 45c7694b8ade
Files: 52
Total size: 313.1 KB

Directory structure:
gitextract_u4wdc7d8/

├── .github/
│   └── workflows/
│       ├── codeql.yml
│       ├── nodejs.yml
│       └── release.yml
├── .gitignore
├── .jshintignore
├── .jshintrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── benchmark/
│   ├── README.md
│   ├── buf.txt
│   ├── cache.js
│   ├── decode.js
│   ├── encode.js
│   ├── reg.js
│   └── string.js
├── index.js
├── lib/
│   ├── convert/
│   │   ├── index.js
│   │   └── java.util.locale.js
│   ├── custom_handler.js
│   ├── object.js
│   ├── utils.js
│   ├── v1/
│   │   ├── decoder.js
│   │   └── encoder.js
│   ├── v2/
│   │   ├── decoder.js
│   │   └── encoder.js
│   └── v2_optimize/
│       ├── decoder.js
│       └── encoder.js
├── package.json
└── test/
    ├── array.test.js
    ├── binary.test.js
    ├── boolean.test.js
    ├── convert.test.js
    ├── custom_handler.test.js
    ├── date.test.js
    ├── decode.circular.test.js
    ├── double.test.js
    ├── exception.test.js
    ├── fixtures/
    │   └── 4k.txt
    ├── int.test.js
    ├── list.test.js
    ├── long.test.js
    ├── map.test.js
    ├── null.test.js
    ├── object.test.js
    ├── string.test.js
    ├── utils.js
    ├── utils.test.js
    ├── v1.test.js
    ├── v2.decode.cache.test.js
    ├── v2.list.encode.test.js
    └── v2.optimize.endecode.test.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/codeql.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
  push:
    branches: [ "master" ]
  pull_request:
    # The branches below must be a subset of the branches above
    branches: [ "master" ]
  schedule:
    - cron: '45 14 * * 3'

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: [ 'javascript' ]
        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
        # Use only 'java' to analyze code written in Java, Kotlin or both
        # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
        # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support

    steps:
    - name: Checkout repository
      uses: actions/checkout@v3

    # Initializes the CodeQL tools for scanning.
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v2
      with:
        languages: ${{ matrix.language }}
        # If you wish to specify custom queries, you can do so here or in a config file.
        # By default, queries listed here will override any specified in a config file.
        # Prefix the list here with "+" to use these queries and those in the config file.

        # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
        # queries: security-extended,security-and-quality


    # Autobuild attempts to build any compiled languages  (C/C++, C#, Go, or Java).
    # If this step fails, then you should remove it and run the build manually (see below)
    - name: Autobuild
      uses: github/codeql-action/autobuild@v2

    # ℹ️ Command-line programs to run using the OS shell.
    # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun

    #   If the Autobuild fails above, remove it and uncomment the following three lines.
    #   modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.

    # - run: |
    #   echo "Run, Build Application using script"
    #   ./location_of_script_within_repo/buildscript.sh

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v2
      with:
        category: "/language:${{matrix.language}}"


================================================
FILE: .github/workflows/nodejs.yml
================================================
name: CI

on:
  push:
    branches: [ master, 1.x ]

  pull_request:
    branches: [ master, 1.x ]

  workflow_dispatch: {}

jobs:
  Job:
    name: Node.js
    uses: artusjs/github-actions/.github/workflows/node-test.yml@v1
    with:
      os: 'ubuntu-latest'
      version: '14, 16, 18'


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  push:
    branches: [ master ]

  workflow_dispatch: {}

jobs:
  release:
    name: Node.js
    uses: artusjs/github-actions/.github/workflows/node-release.yml@v1
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
    with:
      checkTest: false


================================================
FILE: .gitignore
================================================
lib-cov
*.seed
*.log
*.csv
*.out
*.pid
*.gz

pids
logs
results

npm-debug.log
node_modules

.DS_Store
coverage.html
coverage/
.idea/

================================================
FILE: .jshintignore
================================================
node_modules/
coverage/
.tmp/
.git/


================================================
FILE: .jshintrc
================================================
{
    // JSHint Default Configuration File (as on JSHint website)
    // See http://jshint.com/docs/ for more details

    "maxerr"        : 50,       // {int} Maximum error before stopping

    // Enforcing
    "bitwise"       : false,    // true: Prohibit bitwise operators (&, |, ^, etc.)
    "camelcase"     : false,    // true: Identifiers must be in camelCase
    "curly"         : true,     // true: Require {} for every new block or scope
    "eqeqeq"        : true,     // true: Require triple equals (===) for comparison
    "forin"         : false,    // true: Require filtering for..in loops with obj.hasOwnProperty()
    "immed"         : false,    // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
    "indent"        : false,    // {int} Number of spaces to use for indentation
    "latedef"       : false,    // true: Require variables/functions to be defined before being used
    "newcap"        : false,    // true: Require capitalization of all constructor functions e.g. `new F()`
    "noarg"         : true,     // true: Prohibit use of `arguments.caller` and `arguments.callee`
    "noempty"       : true,     // true: Prohibit use of empty blocks
    "nonew"         : false,    // true: Prohibit use of constructors for side-effects (without assignment)
    "plusplus"      : false,    // true: Prohibit use of `++` & `--`
    "quotmark"      : false,    // Quotation mark consistency:
                                //   false    : do nothing (default)
                                //   true     : ensure whatever is used is consistent
                                //   "single" : require single quotes
                                //   "double" : require double quotes
    "undef"         : true,     // true: Require all non-global variables to be declared (prevents global leaks)
    "unused"        : false,    // true: Require all defined variables be used
    "strict"        : "global",     // true: Requires all functions run in ES5 Strict Mode
    "trailing"      : false,    // true: Prohibit trailing whitespaces
    "maxparams"     : false,    // {int} Max number of formal params allowed per function
    "maxdepth"      : false,    // {int} Max depth of nested blocks (within functions)
    "maxstatements" : false,    // {int} Max number statements per function
    "maxcomplexity" : false,    // {int} Max cyclomatic complexity per function
    "maxlen"        : false,    // {int} Max number of characters per line

    // Relaxing
    "asi"           : false,     // true: Tolerate Automatic Semicolon Insertion (no semicolons)
    "boss"          : true,      // true: Tolerate assignments where comparisons would be expected
    "debug"         : false,     // true: Allow debugger statements e.g. browser breakpoints.
    "eqnull"        : false,     // true: Tolerate use of `== null`
    "es5"           : false,     // true: Allow ES5 syntax (ex: getters and setters)
    "esnext"        : true,      // true: Allow ES.next (ES6) syntax (ex: `const`)
    "moz"           : false,     // true: Allow Mozilla specific syntax (extends and overrides esnext features)
                                 // (ex: `for each`, multiple try/catch, function expression…)
    "evil"          : false,     // true: Tolerate use of `eval` and `new Function()`
    "expr"          : true,      // true: Tolerate `ExpressionStatement` as Programs
    "funcscope"     : false,     // true: Tolerate defining variables inside control statements"
    "iterator"      : false,     // true: Tolerate using the `__iterator__` property
    "lastsemic"     : false,     // true: Tolerate omitting a semicolon for the last statement of a 1-line block
    "laxbreak"      : true,      // true: Tolerate possibly unsafe line breakings
    "laxcomma"      : false,     // true: Tolerate comma-first style coding
    "loopfunc"      : true,     // true: Tolerate functions being defined in loops
    "multistr"      : true,      // true: Tolerate multi-line strings
    "proto"         : false,     // true: Tolerate using the `__proto__` property
    "scripturl"     : false,     // true: Tolerate script-targeted URLs
    "smarttabs"     : false,     // true: Tolerate mixed tabs/spaces when used for alignment
    "shadow"        : true,      // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
    "sub"           : false,     // true: Tolerate using `[]` notation when it can still be expressed in dot notation
    "supernew"      : false,     // true: Tolerate `new function () { ... };` and `new Object;`
    "validthis"     : true,      // true: Tolerate using this in a non-constructor function

    // Environments
    "browser"       : true,     // Web Browser (window, document, etc)
    "couch"         : false,    // CouchDB
    "devel"         : true,     // Development/debugging (alert, confirm, etc)
    "dojo"          : false,    // Dojo Toolkit
    "jquery"        : false,    // jQuery
    "mootools"      : false,    // MooTools
    "node"          : true,     // Node.js
    "nonstandard"   : false,    // Widely adopted globals (escape, unescape, etc)
    "prototypejs"   : false,    // Prototype and Scriptaculous
    "rhino"         : false,    // Rhino
    "worker"        : false,    // Web Workers
    "wsh"           : false,    // Windows Scripting Host
    "yui"           : false,    // Yahoo User Interface
    "noyield"       : true,     // allow generators without a yield

    // Legacy
    "nomen"         : false,    // true: Prohibit dangling `_` in variables
    "onevar"        : false,    // true: Allow only one `var` statement per function
    "passfail"      : false,    // true: Stop on first error
    "white"         : false,    // true: Check against strict whitespace and indentation rules

    // Custom Globals
    "globals"       : {         // additional predefined global variables
      // mocha
      "describe": true,
      "it": true,
      "before": true,
      "afterEach": true,
      "beforeEach": true,
      "after": true
    }
}


================================================
FILE: CHANGELOG.md
================================================
# Changelog

## [2.11.0](https://github.com/node-modules/hessian.js/compare/v2.10.1...v2.11.0) (2023-04-16)


### Features

* remove debug and use byte@2 ([#137](https://github.com/node-modules/hessian.js/issues/137)) ([1eb3b3e](https://github.com/node-modules/hessian.js/commit/1eb3b3ed5193deaa176231322d03daab99e49aff))


---


2.10.1 / 2021-11-15
==================

**fixes**
  * [[`543b2bc`](https://github.com/node-modules/hessian.js.git/commit/543b2bc482828ae5e6cb804cf958c9f22dfb24d6)] - fix: 🐛 ref should use custom handler (#126) (Hongcai Deng <<admin@dhchouse.com>>)

**others**
  * [[`33dcabf`](https://github.com/node-modules/hessian.js.git/commit/33dcabf7a585705c6e88b9f49782120bf5e29475)] - test: github action only test on macOS and Linux (#129) (fengmk2 <<fengmk2@gmail.com>>)
  * [[`895fa83`](https://github.com/node-modules/hessian.js.git/commit/895fa8367c428cb6b2a42dd6ded311ed9eb1b475)] - test: 💍 fix ref should use custom handler circular bug (#128) (Hongcai Deng <<admin@dhchouse.com>>)
  * [[`5c633be`](https://github.com/node-modules/hessian.js.git/commit/5c633be4ae130d55f263133b6607ce1238273b52)] - test: run test on github action (#127) (fengmk2 <<fengmk2@gmail.com>>)
  * [[`0b14874`](https://github.com/node-modules/hessian.js.git/commit/0b148740d78e312d2ec6da4e37b0ade35a3c15ae)] - chore: add contributors (#117) (fengmk2 <<fengmk2@gmail.com>>)
  * [[`9012536`](https://github.com/node-modules/hessian.js.git/commit/9012536fc49fe7d57eeafb390ab11fcff027d12a)] - chore: add node 12 & 14 into travis list (#125) (Jackson Tian <<shyvo1987@gmail.com>>)

2.10.0 / 2020-05-15
==================

**features**
  * [[`461a715`](http://github.com/node-modules/hessian.js/commit/461a71551503d6f6430f9b078ffd2be4f7624de4)] - feat: support encode & decode custom map type (#122) (zōng yǔ <<gxcsoccer@users.noreply.github.com>>)

2.9.0 / 2019-05-15
==================

**features**
  * [[`ee57e93`](http://github.com/node-modules/hessian.js/commit/ee57e93e580dd4a595cf1098a4f35febfbc6a990)] - feat: support custom decode handler (#119) (zōng yǔ <<gxcsoccer@users.noreply.github.com>>)

**fixes**
  * [[`3f0b392`](http://github.com/node-modules/hessian.js/commit/3f0b392c58a9b5e65915eca55bc209439ba1e3db)] - fix: should reset _classRefFields (#87) (fengmk2 <<fengmk2@gmail.com>>)

**others**
  * [[`f71da69`](http://github.com/node-modules/hessian.js/commit/f71da690266f1fb65e6a569ee417996001ded8f1)] - test: fix throws test on node 10 (#110) (fengmk2 <<fengmk2@gmail.com>>)

2.8.1 / 2018-01-18
==================

**fixes**
  * [[`b231db0`](http://github.com/dead-horse/hessian.js/commit/b231db01af9379936bd810762a1a0bb1f37cd59c)] - fix: compose cache key with class and fields length (#102) (Yiyu He <<dead_horse@qq.com>>)

2.8.0 / 2018-01-10
==================

**features**
  * [[`ce5a7f8`](http://github.com/node-modules/hessian.js/commit/ce5a7f81fb65285f04619d3131872b2325dd92b0)] - feat: support convert java.util.Locale to com.caucho.hessian.io.LocaleHandle (#99) (zōng yǔ <<gxcsoccer@users.noreply.github.com>>)

2.7.0 / 2017-12-26
==================

**features**
  * [[`ceaef7b`](http://github.com/dead-horse/hessian.js/commit/ceaef7b169772ad8edb07a5839d830c4789eee1e)] - feat: hessian2 optimize codec (#97) (Hongcai Deng <<admin@dhchouse.com>>)

2.6.0 / 2017-11-16
==================

**features**
  * [[`1403a44`](http://github.com/dead-horse/hessian.js/commit/1403a445db7982f35c2b557f13411a9ced4b83e1)] - feat: use byte.getRawStringByStringLength to read utf8 string (#94) (Yiyu He <<dead_horse@qq.com>>)

**fixes**
  * [[`a7a3f92`](http://github.com/dead-horse/hessian.js/commit/a7a3f9276bc2d5f2bd48006850694b494285c3a4)] - fix: support writeLong parameter is a Long object (#96) (zōng yǔ <<gxcsoccer@users.noreply.github.com>>)

2.5.0 / 2017-11-01
==================

**features**
  * [[`4d3b48e`](http://github.com/dead-horse/hessian.js/commit/4d3b48e6e5ed06dca54f2c1dffeb092628b80fbd)] - feat: support cache class for v2/decode (#90) (Yiyu He <<dead_horse@qq.com>>)

2.4.0 / 2017-08-02
==================

**features**
  * [[`ab45730`](http://github.com/node-modules/hessian.js/commit/ab457306e0ab6ac28eaa0e93b3478bcb1fbf5108)] - feat: upgrade is-type-of to 1.1.0 (#81) (fengmk2 <<fengmk2@gmail.com>>)

2.3.1 / 2017-07-25
==================

  * fix: skip regExp & Function property (#77)

2.3.0 / 2017-07-25
==================

  * feat: map key is object should try to use `name` propery (#78)

2.2.2 / 2017-07-13
==================

  * fix: package.json to reduce vulnerabilities (#75)

2.2.1 / 2016-08-25
==================

  * fix: downward compatibility (#71)

2.2.0 / 2016-08-24
==================

  * feat: support java.util.HashMap to es6 Map (#70)

2.1.9 / 2016-08-24
==================

  * fix(writeDate): overflow 32-bit signed integer issue

2.1.8 / 2016-04-03
==================

  * deps: upgrade all deps

2.1.7 / 2016-04-01
==================

  * fix: remove es6
  * chore: add examples for test
  * fix: v2 list encode

2.1.6 / 2016-03-10
==================

  * lint: remove deprecated rule "globastrict", replace with rule "strict:global"
  * fix: donnot use the api of module long introduced in new version, module byte depends on the old version.
  * fix: output Number.MAX_SAFE_INTEGER as string rather than number. fix #56

2.1.5 / 2016-02-03
==================

  * fix: fix encode/decode date bug

2.1.4 / 2015-10-12
==================

  * fix: HashMap & Map is same type

2.1.3 / 2015-10-01
==================

 * test: use npm scripts instead of Makefile
 * test: add undefined test
 * fix: array encode can be null

2.1.2 / 2015-09-10
==================

 * fix: skip innerClass ref field like this$\d

2.1.1 / 2015-09-06
==================

  * fix(writeLong) hessian2.0 write long bug

2.1.0 / 2015-08-27
==================

 * test(testcase) fix testcase
 * chore(README) modify README
 * feat(generic) support generic map

2.0.0 / 2015-07-05
==================

 * feat(hessian 2.0) implement hessian 2.0

1.0.4 / 2015-04-09
==================

 * test: add more node version on travis ci
 * test: add encode {$class: "java.lang.Long", $: null} => null test case
 * fix(encode) fix object property null issue

1.0.3 / 2015-03-11
==================

  * fix(decode): toString is not stable.
  * chore(test): skip large string with v0.11.15
  * fix(writeObject): should assertType obj.$ when writeObject and add more messge
  * ignore 0xd800 and 0xdbff char test cases

1.0.2 / 2015-01-29
==================

 * feat(null): writeNull when obj.$ is null

1.0.1 / 2014-08-27
==================

  * Merge pull request #30 from node-modules/java.lang.Error
  * support decode java.lang.*Error as js Error

1.0.0 / 2014-08-27
==================

  * bump byte

0.5.2 / 2014-08-20
==================

  * Merge pull request #29 from node-modules/exception-bug-fix
  * only test on node 0.10.28
  * change badge and add travis coverage
  * fix exception convert bug
  * support `java.util.concurrent.atomic.AtomicLong` fix #27

0.5.1 / 2014-06-25
==================

  * default list and map withType

0.5.0 / 2014-06-25
==================

  * Merge pull request #26 from node-modules/full-with-type
  * withType return all type info for v1
  * add bencmark result link

0.4.2 / 2014-05-15
==================

  * Merge pull request #24 from node-modules/support-Long
  * support encode Long instance

0.4.1 / 2014-05-15
==================

  * Merge pull request #23 from node-modules/cache-class-name
  * cache class name

0.4.0 / 2014-05-13
==================

 * reuse encoder and add base benchmark
 * fix read object missing with type

0.3.1 / 2014-05-08
==================

 * handle xxxx.HSFException
 * Decode java exception object to js Error object. close #18
 * hessian 2.0 should read hessian 1.0 date format
 * add utf8 test cases

0.3.0 / 2014-04-28
==================

 * hessian 2.0 can decode hessian 1.0 list
 * hessian 2.0 can read hessian 1.0 hashmap
 * hessian 2.0 can decode hessian 1.0 int format
 * hessian 2.0 can decode hessian 1.0 long format
 * fix hessian 2.0 long decode and encode
 * add hessian 1.0 enum, list, map bin test
 * encode string as java hessian 1.0 impl
 * add number bin test

0.2.1 / 2014-04-24
==================

 * fix writeObject 2.0, now Enum as a normal java Object
 * improve enum write in hessian 2.0

0.2.0 / 2014-04-23
==================

 * hessian 2.0 refator
 * refactor readArray
 * encode and decode enum
 * refactor writeObject, writeRef, writeDate
 * refactor hessian writeObject with real java codes

0.1.11 / 2014-04-22
==================

  * bump byte

0.1.10 / 2014-04-22
==================

  * fix write array error

0.1.9 / 2014-04-22
==================

  * fix btypebuffer

0.1.8 / 2014-04-22
==================

  * support java.lang.Object

0.1.7 / 2014-04-06
==================

  * support response with int key

0.1.6 / 2014-04-04
==================

  * fix type?

0.1.5 / 2014-04-04
==================

  * fix encode array bug

0.1.4 / 2014-04-03
==================

  * fix no length read array in v1
  * use is-type-of

0.1.3 / 2014-04-01
==================

  * fix test in 0.11

0.1.2 / 2014-03-20
==================

  * remove exports.java, just let people use js-to-java module

0.1.1 / 2014-03-13
==================

  * Merge pull request #11 from dead-horse/use-is-type-of
  * use is-type-of to do type check
  * use badge replace install code

0.1.0 / 2014-02-14
==================

  * Merge pull request #9 from fengmk2/hessian-v2
  * encode hessian 2.0 list
  * encode hessian 2.0 map
  * add readRefId() to share code logic between v1.0 and v2.0
  * change decoder switch and if else to hash map code detect
  * add hessian 2.0 decoder
  * Support hessian 2.0 encoder.
  * Support hessian 2.0 decode. #8
  * fix test

0.0.3 / 2014-02-12
==================

  * add decoder.position method
  * update dependencies
  * fix encode long, read end of buffer
  * add npm badge

0.0.2 / 2014-01-30
==================

  * update readme
  * Merge pull request #6 from fengmk2/compact-types
  * fix hasOwnProperty was override: `{hasOwnProperty: 1}`
  * add type list examples: int[] = {0, 1, 2}
  * Support decode sparse array, @see http://hessian.caucho.com/doc/hessian-1.0-spec.xtp#map fixed #5
  * support anonymous variable-length list = {0, "foobar"}
  * add binary, date, double, int, list, long, string test cases on hessian 1.0.2
  * add java base types and each type mapping one test file.
  * update readme
  * Merge pull request #1 from fengmk2/more-tests
  * add readArray error test case
  * Add more tests and remove assert use TypeError instead.
  * change name to hessian.js
  * remove utility
  * fix typo
  * add AUTHORS

0.0.1 / 2014-01-27
==================

  * update readme
  * add npmignore
  * complete all the unit test
  * use get instead of read in readString
  * add todo
  * add mocha-lcov-reporter
  * add fixture.dat
  * add fixture.dat
  * add travis
  * add test
  * add test for simple type
  * update readme
  * add v1 decoder
  * add readme
  * fully support simple and complex js object to hessian
  * v1 encoder simple type done
  * update byte
  * use byte to handle the buffer things
  * Initial commit


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) node-modules and other contributors.

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.


================================================
FILE: README.md
================================================
hessian.js
=========

[![NPM version][npm-image]][npm-url]
[![build status][github-action-image]][github-action-url]
[![Test coverage][codecov-image]][codecov-url]
[![npm download][download-image]][download-url]

[npm-image]: https://img.shields.io/npm/v/hessian.js.svg?style=flat-square
[npm-url]: https://npmx.dev/package/hessian.js
[github-action-image]: https://github.com/node-modules/hessian.js/actions/workflows/nodejs.yml/badge.svg
[github-action-url]: https://github.com/node-modules/hessian.js/actions/workflows/nodejs.yml
[codecov-image]: https://codecov.io/github/node-modules/hessian.js/coverage.svg?branch=master
[codecov-url]: https://codecov.io/github/node-modules/hessian.js?branch=master
[download-image]: https://img.shields.io/npm/dm/hessian.js.svg?style=flat-square
[download-url]: https://npmx.dev/package/hessian.js

Hessian Serialization [1.0](http://hessian.caucho.com/doc/hessian-1.0-spec.xtp) and
[2.0](http://hessian.caucho.com/doc/hessian-serialization.html) (base on version [4.0.7](http://mvnrepository.com/artifact/com.caucho/hessian/4.0.7)) written by pure JavaScript.
Support all kind of types in Java, with [high performance](benchmark/README.md).

## Install

```bash
$ npm install hessian.js
```

## Support Types

8 primitive types:

1. raw binary data
2. boolean
3. 64-bit millisecond date
4. 64-bit double
5. 32-bit int
6. 64-bit long
7. null
8. UTF8-encoded string

3 recursive types:

1. `list` for lists and arrays
2. `map` for maps and dictionaries
3. `object` for objects

one special contruct:

1. ref for shared and circular object references

Hessian 2.0 has 3 internal reference maps:

* An object/list reference map.
* An class definition reference map.
* A type (class name) reference map.

## Encoder

Tips: you can use with [js-to-java](https://github.com/node-modules/js-to-java) to help you write java class in js.

### Simple javascript type

```js
var hessian = require('hessian.js');
var java = require('js-to-java');
var encoder = new hessian.Encoder();

encoder.write(1); // int
encoder.write(1.1); // double
encoder.write(1e100); // double
encoder.write(Math.pow(2, 18)); // long
encoder.write(true); // boolean
encoder.write(null); // null
encoder.write('test'); // string

// java base types
encoder.write(java.long(3001010320)); // 3001010320L
encoder.write(java.double(100)); // double
encoder.write(java.array.int([0, 1, 2])); // int[] = {0, 1, 2}

var object = {};
object.prop1 = [1, 2, 3];
object.prop2 = 'string';
object.prop3 = {key: 'value'};
object.prop4 = object;  // circular
encoder.write(object); // object
```

### Complex java type

```js
var hessian = require('hessian.js');
var encoder = new hessian.Encoder();

var long = {
  $class: 'java.lang.Long',
  $: 1
}
encoder.write(long); // long type

var testObject = {
  $class: 'com.hessian.TestObject',
  $: {
    a: 1,
    b: 'test',
    c: {$class: 'java.lang.Long', $: 123}
  }
};
encoder.write(testObject);
```

### Java Generic Map

```js
// java code:
// Map<Long, Integer> map = new HashMap<Long, Integer>();
// map.put(123L, 123456);
// map.put(123456L, 123);

var hessian = require('hessian.js');
var encoder = new hessian.Encoder();

// using es6 Map
var map = new Map();
map.set({ '$class': 'java.lang.Long', '$': 123 }, 123456);
map.set({ '$class': 'java.lang.Long', '$': 123456 }, 123);

encoder.write(map); // or encoder.write({ '$class': 'java.util.HashMap', '$': map })
```

### Consistent Java type

If a type of Class contains a plurality of data, you must ensure that the number of attributes, and each instance of the order is the same!

```
// Wrong

[
  {$class: 'com.X', $: {a: 1, b: 2}},
  {$class: 'com.X', $: {b: 22, a: 11}},
  {$class: 'com.X', $: {a: 1, b: 2, c: 3}}]

// Right

[
  {$class: 'com.X', $: {a: 1, b: 2, c: 0}},
  {$class: 'com.X', $: {a: 11, b: 22, c: 0}},
  {$class: 'com.X', $: {a: 1, b: 2, c: 3}},
]

```


## Decoder

```js
var hessian = require('hessian.js');
var decoder = new hessian.Decoder(buf);

decoder.read(); //return what it is
decoder.readNull();
decoder.readBool();
decoder.readInt();
decoder.readLong();
decoder.readDouble();
decoder.readDate();
decoder.readObect();
decoder.readMap();
decoder.readArray();
decoder.readList();
decoder.readRef();
```

## Simple Usage

hessian 1.0:

```js
var hessian = require('hessian.js');

var testObject = {
  a: 1,
  b: 'string',
  c: true,
  d: 1.1,
  e: Math.pow(2, 40),
  f: [1, 2, 3, '4', true, 5],
  g: {a: 1, b: true, c: 'string'}
};

var buf;
try {
  buf = hessian.encode(testObject);
} catch (err) {
  console.log('encode error: ', err.message);
  process.exit(1);
}

try {
  var res = hessian.decode(buf);
  // res.should.eql(testObject);
} catch (err) {
  console.log('decode error: ', err.message);
}
```

hessian 2.0:

```js
var hessian = require('hessian.js');

var testObject = {
  a: 1,
  b: 'string',
  c: true,
  d: 1.1,
  e: Math.pow(2, 40),
  f: [1, 2, 3, '4', true, 5],
  g: {a: 1, b: true, c: 'string'}
};

var buf;
try {
  buf = hessian.encode(testObject, '2.0');
} catch (err) {
  console.log('encode error: ', err.message);
  process.exit(1);
}

try {
  var res = hessian.decode(buf, '2.0');
  // res.should.eql(testObject);
} catch (err) {
  console.log('decode error: ', err.message);
}
```

## TODO

1. more unit test, include test with other language.
2. benchmark test.
3. ~~hessian 2.0 decode~~
3. ~~hessian 2.0 encode~~

## What's different between hassian 1.0 and 2.0?

* `R` meaning `ref` on 1.0, but `x52 ('R')` represents any non-final string chunk on 2.0

## Hessian 2.0 Serialization Grammar

```
           # starting production
top        ::= value

           # 8-bit binary data split into 64k chunks
binary     ::= x41 b1 b0 <binary-data> binary # non-final chunk
           ::= 'B' b1 b0 <binary-data>        # final chunk
           ::= [x20-x2f] <binary-data>        # binary data of
                                                 #  length 0-15
           ::= [x34-x37] <binary-data>        # binary data of
                                                 #  length 0-1023

           # boolean true/false
boolean    ::= 'T'
           ::= 'F'

           # definition for an object (compact map)
class-def  ::= 'C' string int string*

           # time in UTC encoded as 64-bit long milliseconds since
           #  epoch
date       ::= x4a b7 b6 b5 b4 b3 b2 b1 b0
           ::= x4b b3 b2 b1 b0       # minutes since epoch

           # 64-bit IEEE double
double     ::= 'D' b7 b6 b5 b4 b3 b2 b1 b0
           ::= x5b                   # 0.0
           ::= x5c                   # 1.0
           ::= x5d b0                # byte cast to double
                                     #  (-128.0 to 127.0)
           ::= x5e b1 b0             # short cast to double
           ::= x5f b3 b2 b1 b0       # 32-bit float cast to double

           # 32-bit signed integer
int        ::= 'I' b3 b2 b1 b0
           ::= [x80-xbf]             # -x10 to x3f
           ::= [xc0-xcf] b0          # -x800 to x7ff
           ::= [xd0-xd7] b1 b0       # -x40000 to x3ffff

           # list/vector
list       ::= x55 type value* 'Z'   # variable-length list
           ::= 'V' type int value*   # fixed-length list
           ::= x57 value* 'Z'        # variable-length untyped list
           ::= x58 int value*        # fixed-length untyped list
           ::= [x70-77] type value*  # fixed-length typed list
           ::= [x78-7f] value*       # fixed-length untyped list

           # 64-bit signed long integer
long       ::= 'L' b7 b6 b5 b4 b3 b2 b1 b0
           ::= [xd8-xef]             # -x08 to x0f
           ::= [xf0-xff] b0          # -x800 to x7ff
           ::= [x38-x3f] b1 b0       # -x40000 to x3ffff
           ::= x59 b3 b2 b1 b0       # 32-bit integer cast to long

           # map/object
map        ::= 'M' type (value value)* 'Z'  # key, value map pairs
           ::= 'H' (value value)* 'Z'       # untyped key, value

           # null value
null       ::= 'N'

           # Object instance
object     ::= 'O' int value*
           ::= [x60-x6f] value*

           # value reference (e.g. circular trees and graphs)
ref        ::= x51 int            # reference to nth map/list/object

           # UTF-8 encoded character string split into 64k chunks
string     ::= x52 b1 b0 <utf8-data> string  # non-final chunk
           ::= 'S' b1 b0 <utf8-data>         # string of length
                                             #  0-65535
           ::= [x00-x1f] <utf8-data>         # string of length
                                             #  0-31
           ::= [x30-x34] <utf8-data>         # string of length
                                             #  0-1023

           # map/list types for OO languages
type       ::= string                        # type name
           ::= int                           # type reference

           # main production
value      ::= null
           ::= binary
           ::= boolean
           ::= class-def value
           ::= date
           ::= double
           ::= int
           ::= list
           ::= long
           ::= map
           ::= object
           ::= ref
           ::= string
```

## Hessian 2.0 Bytecode map

Hessian 2.0 is organized as a bytecode protocol.
A Hessian reader is essentially a switch statement on the initial octet.

```
x00 - x1f    # utf-8 string length 0-32
x20 - x2f    # binary data length 0-16
x30 - x33    # utf-8 string length 0-1023
x34 - x37    # binary data length 0-1023
x38 - x3f    # three-octet compact long (-x40000 to x3ffff)
x40          # reserved (expansion/escape)
x41          # 8-bit binary data non-final chunk ('A')
x42          # 8-bit binary data final chunk ('B')
x43          # object type definition ('C')
x44          # 64-bit IEEE encoded double ('D')
x45          # reserved
x46          # boolean false ('F')
x47          # reserved
x48          # untyped map ('H')
x49          # 32-bit signed integer ('I')
x4a          # 64-bit UTC millisecond date
x4b          # 32-bit UTC minute date
x4c          # 64-bit signed long integer ('L')
x4d          # map with type ('M')
x4e          # null ('N')
x4f          # object instance ('O')
x50          # reserved
x51          # reference to map/list/object - integer ('Q')
x52          # utf-8 string non-final chunk ('R')
x53          # utf-8 string final chunk ('S')
x54          # boolean true ('T')
x55          # variable-length list/vector ('U')
x56          # fixed-length list/vector ('V')
x57          # variable-length untyped list/vector ('W')
x58          # fixed-length untyped list/vector ('X')
x59          # long encoded as 32-bit int ('Y')
x5a          # list/map terminator ('Z')
x5b          # double 0.0
x5c          # double 1.0
x5d          # double represented as byte (-128.0 to 127.0)
x5e          # double represented as short (-32768.0 to 327676.0)
x5f          # double represented as float
x60 - x6f    # object with direct type (` ... n, o)
x70 - x77    # fixed list with direct length (p, q, r, s, t, u, v, w)
x78 - x7f    # fixed untyped list with direct length (x, y, z, {, |, }, ~, .....)
x80 - xbf    # one-octet compact int (-x10 to x3f, x90 is 0)
xc0 - xcf    # two-octet compact int (-x800 to x7ff)
xd0 - xd7    # three-octet compact int (-x40000 to x3ffff)
xd8 - xef    # one-octet compact long (-x8 to xf, xe0 is 0)
xf0 - xff    # two-octet compact long (-x800 to x7ff, xf8 is 0)
```

## About Hessian 2.0 Optimized Decoder
Hessian 2.0 introduced [ref](http://hessian.caucho.com/doc/hessian-serialization.html##ref) to avoid sending duplicated class definition in the same context. Actully, the `context` can promote to `connection` level in some RPC framework. For example, [EADS](https://www.aliyun.com/product/edas), Requests using the same connection will not change their class definition.

## Licences

[MIT](LICENSE)
<!-- GITCONTRIBUTOR_START -->

## Contributors

|[<img src="https://avatars.githubusercontent.com/u/985607?v=4" width="100px;"/><br/><sub><b>dead-horse</b></sub>](https://github.com/dead-horse)<br/>|[<img src="https://avatars.githubusercontent.com/u/156269?v=4" width="100px;"/><br/><sub><b>fengmk2</b></sub>](https://github.com/fengmk2)<br/>|[<img src="https://avatars.githubusercontent.com/u/1207064?v=4" width="100px;"/><br/><sub><b>gxcsoccer</b></sub>](https://github.com/gxcsoccer)<br/>|[<img src="https://avatars.githubusercontent.com/u/1433247?v=4" width="100px;"/><br/><sub><b>denghongcai</b></sub>](https://github.com/denghongcai)<br/>|[<img src="https://avatars.githubusercontent.com/u/340282?v=4" width="100px;"/><br/><sub><b>fool2fish</b></sub>](https://github.com/fool2fish)<br/>|[<img src="https://avatars.githubusercontent.com/u/1400114?v=4" width="100px;"/><br/><sub><b>coolme200</b></sub>](https://github.com/coolme200)<br/>|
| :---: | :---: | :---: | :---: | :---: | :---: |
[<img src="https://avatars.githubusercontent.com/u/327019?v=4" width="100px;"/><br/><sub><b>JacksonTian</b></sub>](https://github.com/JacksonTian)<br/>|[<img src="https://avatars.githubusercontent.com/u/1681459?v=4" width="100px;"/><br/><sub><b>xusiyuan841028</b></sub>](https://github.com/xusiyuan841028)<br/>|[<img src="https://avatars.githubusercontent.com/u/19733683?v=4" width="100px;"/><br/><sub><b>snyk-bot</b></sub>](https://github.com/snyk-bot)<br/>

This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Sun Apr 16 2023 15:34:56 GMT+0800`.

<!-- GITCONTRIBUTOR_END -->


================================================
FILE: benchmark/README.md
================================================
benchmark result
----------

```
node benchmark/encode.js

  Hessian Encode Benchmark
  node version: v0.11.12, date: Tue May 27 2014 11:30:03 GMT+0800 (CST)
  Starting...
  16 tests completed.

  hessian1 encode: number         x 1,669,884 ops/sec ±1.38% (93 runs sampled)
  hessian2 encode: number         x 1,893,674 ops/sec ±0.74% (96 runs sampled)
  hessian1 encode: date           x   834,286 ops/sec ±1.40% (91 runs sampled)
  hessian2 encode: date           x   789,740 ops/sec ±1.06% (95 runs sampled)
  hessian1 encode: long           x   646,034 ops/sec ±0.89% (95 runs sampled)
  hessian2 encode: long           x   643,354 ops/sec ±1.60% (88 runs sampled)
  hessian1 encode: string         x   955,180 ops/sec ±1.19% (96 runs sampled)
  hessian2 encode: string         x 1,006,919 ops/sec ±1.22% (93 runs sampled)
  hessian1 encode: [1, 2, 3]      x   536,860 ops/sec ±0.85% (94 runs sampled)
  hessian2 encode: [1, 2, 3]      x   615,294 ops/sec ±0.93% (95 runs sampled)
  hessian1 encode array           x   377,167 ops/sec ±0.85% (95 runs sampled)
  hessian2 encode array           x   403,383 ops/sec ±0.94% (91 runs sampled)
  hessian1 encode: simple object  x   146,367 ops/sec ±1.67% (93 runs sampled)
  hessian2 encode: simple object  x   147,188 ops/sec ±1.81% (94 runs sampled)
  hessian1 encode: complex object x    95,309 ops/sec ±1.40% (91 runs sampled)
  hessian2 encode: complex object x    95,851 ops/sec ±1.20% (96 runs sampled)


  Hessian Decode Benchmark
  node version: v0.11.12, date: Tue May 27 2014 11:31:30 GMT+0800 (CST)
  Starting...
  16 tests completed.

  hessian1 decode: number         x 5,915,496 ops/sec ±0.73% (98 runs sampled)
  hessian2 decode: number         x 5,838,371 ops/sec ±2.66% (90 runs sampled)
  hessian1 decode: date           x 2,958,136 ops/sec ±1.87% (91 runs sampled)
  hessian2 decode: date           x 2,721,653 ops/sec ±0.81% (97 runs sampled)
  hessian1 decode: long           x 4,076,127 ops/sec ±0.83% (93 runs sampled)
  hessian2 decode: long           x 5,400,659 ops/sec ±1.26% (93 runs sampled)
  hessian1 decode: string         x 1,067,996 ops/sec ±2.20% (91 runs sampled)
  hessian2 decode: string         x 1,133,082 ops/sec ±1.04% (93 runs sampled)
  hessian1 decode: [1, 2, 3]      x 1,201,908 ops/sec ±1.26% (91 runs sampled)
  hessian2 decode: [1, 2, 3]      x 1,915,498 ops/sec ±1.66% (95 runs sampled)
  hessian1 decode array           x   505,896 ops/sec ±1.13% (93 runs sampled)
  hessian2 decode array           x   616,792 ops/sec ±0.79% (98 runs sampled)
  hessian1 decode: simple object  x   194,474 ops/sec ±0.87% (97 runs sampled)
  hessian2 decode: simple object  x   177,599 ops/sec ±0.97% (96 runs sampled)
  hessian1 decode: complex object x   139,387 ops/sec ±0.83% (97 runs sampled)
  hessian2 decode: complex object x   139,213 ops/sec ±0.58% (99 runs sampled)
  ```


================================================
FILE: benchmark/cache.js
================================================
'use strict';

var Benchmark = require('benchmark');
var benchmarks = require('beautify-benchmark');
var path = require('path');
var fs = require('fs');
var assert = require('assert');
var hessian = require('../');


var buf = fs.readFileSync(path.join(__dirname, 'buf.txt'));
var cache = new Map();

assert.deepEqual(hessian.decode(buf, '2.0', { classCache: cache }), hessian.decode(buf, '2.0'));
assert.deepEqual(hessian.decode(buf, '2.0', { classCache: cache }), hessian.decode(buf, '2.0'));
var suite = new Benchmark.Suite();

suite

.add('with cache', function() {
  hessian.decode(buf, '2.0', { classCache: cache });
})
.add('without cache', function() {
  hessian.decode(buf, '2.0');
})

.on('cycle', function(event) {
  benchmarks.add(event.target);
})
.on('start', function(event) {
  console.log('\n  Cache Benchmark\n  node version: %s, date: %s\n  Starting...',
    process.version, Date());
})
.on('complete', function done() {
  benchmarks.log();
})
.run({ 'async': false });

// Cache Benchmark
// node version: v8.9.0, date: Thu Nov 16 2017 13:30:47 GMT+0800 (CST)
// Starting...
// 2 tests completed.
//
// with cache    x 19,947 ops/sec ±3.81% (80 runs sampled)
// without cache x  8,360 ops/sec ±1.38% (87 runs sampled)


================================================
FILE: benchmark/decode.js
================================================
'use strict';

var ByteBuffer = require('byte');
var Benchmark = require('benchmark');
var benchmarks = require('beautify-benchmark');
var java = require('js-to-java');
var hessian = require('../');

var suite = new Benchmark.Suite();

var simpleObject = {
  $class: 'com.hessiantest.org.MockRequest',
  $: {
    id: 123,
    name: 'getData',
    args: [1, "name", "xxx1231231231231xxx123"]
  }
};

var simpleObjectBuf1 = hessian.encode(simpleObject, '1.0');
var simpleObjectBuf2 = hessian.encode(simpleObject, '2.0');

var complexObject = {
  $class: 'com.hessiantest.org.MockRequest',
  $: {
    id: 123,
    name: 'getData',
    args: [1, "name", "xxx1231231231231xxx123"],
    conn: {
      $class: 'com.hessiantest.org.MockRequestConnection',
      $: {
        ctx: java.long(1024)
      }
    }
  }
};

var complexObjectBuf1 = hessian.encode(complexObject, '1.0');
var complexObjectBuf2 = hessian.encode(complexObject, '2.0');

var number1Buf1 = hessian.encode(1, '1.0');
var number1Buf2 = hessian.encode(1, '2.0');

var dateBuf1 = hessian.encode(new Date(), '1.0');
var dateBuf2 = hessian.encode(new Date(), '2.0');

var longBuf1 = hessian.encode(java.long(300), '1.0');
var longBuf2 = hessian.encode(java.long(300), '2.0');

var stringBuf1 = hessian.encode('xxx1231231231231xxx123', '1.0');
var stringBuf2 = hessian.encode('xxx1231231231231xxx123', '2.0');

var arrBuf1 = hessian.encode([1, 2, 3], '1.0');
var arrBuf2 = hessian.encode([1, 2, 3], '2.0');

var arrObjectBuf1 = hessian.encode([1, "name", "xxx1231231231231xxx123"], '1.0');
var arrObjectBuf2 = hessian.encode([1, "name", "xxx1231231231231xxx123"], '2.0');

suite

.add('hessian1 decode: number', function() {
  hessian.decode(number1Buf1, '1.0');
})
.add('hessian2 decode: number', function() {
  hessian.decode(number1Buf2, '2.0');
})

.add('hessian1 decode: date', function() {
  hessian.decode(dateBuf1, '1.0');
})
.add('hessian2 decode: date', function() {
  hessian.decode(dateBuf2, '2.0');
})

.add('hessian1 decode: long', function() {
  hessian.decode(longBuf1, '1.0');
})
.add('hessian2 decode: long', function() {
  hessian.decode(longBuf2, '2.0');
})

.add('hessian1 decode: string', function() {
  hessian.decode(stringBuf1, '1.0');
})
.add('hessian2 decode: string', function() {
  hessian.decode(stringBuf2, '2.0');
})

.add('hessian1 decode: [1, 2, 3]', function() {
  hessian.decode(arrBuf1, '1.0');
})
.add('hessian2 decode: [1, 2, 3]', function() {
  hessian.decode(arrBuf2, '2.0');
})
.add('hessian1 decode array', function() {
  hessian.decode(arrObjectBuf1, '1.0');
})
.add('hessian2 decode array', function() {
  hessian.decode(arrObjectBuf2, '2.0');
})

.add('hessian1 decode: simple object', function() {
  hessian.decode(simpleObjectBuf1, '1.0');
})
.add('hessian2 decode: simple object', function() {
  hessian.decode(simpleObjectBuf2, '2.0');
})

.add('hessian1 decode: complex object', function() {
  hessian.decode(complexObjectBuf1, '1.0');
})
.add('hessian2 decode: complex object', function() {
  hessian.decode(complexObjectBuf2, '2.0');
})
.add('hessian1 decode with type: number', function() {
  hessian.decode(number1Buf1, '1.0', true);
})
.add('hessian2 decode with type: number', function() {
  hessian.decode(number1Buf2, '2.0', true);
})

.add('hessian1 decode with type: date', function() {
  hessian.decode(dateBuf1, '1.0', true);
})
.add('hessian2 decode with type: date', function() {
  hessian.decode(dateBuf2, '2.0', true);
})

.add('hessian1 decode with type: long', function() {
  hessian.decode(longBuf1, '1.0', true);
})
.add('hessian2 decode with type: long', function() {
  hessian.decode(longBuf2, '2.0', true);
})

.add('hessian1 decode with type: string', function() {
  hessian.decode(stringBuf1, '1.0', true);
})
.add('hessian2 decode with type: string', function() {
  hessian.decode(stringBuf2, '2.0', true);
})

.add('hessian1 decode with type: [1, 2, 3]', function() {
  hessian.decode(arrBuf1, '1.0', true);
})
.add('hessian2 decode with type: [1, 2, 3]', function() {
  hessian.decode(arrBuf2, '2.0', true);
})
.add('hessian1 decode with type array', function() {
  hessian.decode(arrObjectBuf1, '1.0', true);
})
.add('hessian2 decode with type array', function() {
  hessian.decode(arrObjectBuf2, '2.0', true);
})

.add('hessian1 decode with type: simple object', function() {
  hessian.decode(simpleObjectBuf1, '1.0', true);
})
.add('hessian2 decode with type: simple object', function() {
  hessian.decode(simpleObjectBuf2, '2.0', true);
})

.add('hessian1 decode with type: complex object', function() {
  hessian.decode(complexObjectBuf1, '1.0', true);
})
.add('hessian2 decode with type: complex object', function() {
  hessian.decode(complexObjectBuf2, '2.0', true);
})

.on('cycle', function(event) {
  benchmarks.add(event.target);
})
.on('start', function(event) {
  console.log('\n  Hessian Decode Benchmark\n  node version: %s, date: %s\n  Starting...',
    process.version, Date());
})
.on('complete', function done() {
  benchmarks.log();
})
.run({ 'async': false });

// Hessian Decode Benchmark
// node version: v8.9.0, date: Thu Nov 16 2017 13:31:15 GMT+0800 (CST)
// Starting...
// 32 tests completed.
//
// hessian1 decode: number                   x 6,546,954 ops/sec ±1.41% (87 runs sampled)
// hessian2 decode: number                   x 6,247,164 ops/sec ±2.10% (84 runs sampled)
// hessian1 decode: date                     x 2,378,658 ops/sec ±2.29% (86 runs sampled)
// hessian2 decode: date                     x 2,378,814 ops/sec ±1.71% (84 runs sampled)
// hessian1 decode: long                     x 3,669,483 ops/sec ±1.88% (85 runs sampled)
// hessian2 decode: long                     x 6,125,751 ops/sec ±1.13% (81 runs sampled)
// hessian1 decode: string                   x 2,123,485 ops/sec ±1.26% (88 runs sampled)
// hessian2 decode: string                   x 1,968,578 ops/sec ±1.53% (86 runs sampled)
// hessian1 decode: [1, 2, 3]                x 1,292,327 ops/sec ±3.02% (83 runs sampled)
// hessian2 decode: [1, 2, 3]                x 1,463,036 ops/sec ±2.95% (82 runs sampled)
// hessian1 decode array                     x   764,305 ops/sec ±1.10% (85 runs sampled)
// hessian2 decode array                     x   819,871 ops/sec ±4.13% (85 runs sampled)
// hessian1 decode: simple object            x   225,427 ops/sec ±1.02% (87 runs sampled)
// hessian2 decode: simple object            x   206,072 ops/sec ±1.41% (85 runs sampled)
// hessian1 decode: complex object           x   139,136 ops/sec ±2.46% (86 runs sampled)
// hessian2 decode: complex object           x   132,702 ops/sec ±3.12% (80 runs sampled)
// hessian1 decode with type: number         x 4,971,071 ops/sec ±1.97% (83 runs sampled)
// hessian2 decode with type: number         x 6,165,893 ops/sec ±1.59% (86 runs sampled)
// hessian1 decode with type: date           x 2,205,802 ops/sec ±1.86% (85 runs sampled)
// hessian2 decode with type: date           x 2,290,528 ops/sec ±2.34% (86 runs sampled)
// hessian1 decode with type: long           x 3,340,413 ops/sec ±1.27% (86 runs sampled)
// hessian2 decode with type: long           x 6,072,529 ops/sec ±0.94% (89 runs sampled)
// hessian1 decode with type: string         x 1,986,114 ops/sec ±1.30% (86 runs sampled)
// hessian2 decode with type: string         x 2,074,055 ops/sec ±0.97% (88 runs sampled)
// hessian1 decode with type: [1, 2, 3]      x 1,026,832 ops/sec ±1.26% (86 runs sampled)
// hessian2 decode with type: [1, 2, 3]      x 1,565,525 ops/sec ±1.06% (87 runs sampled)
// hessian1 decode with type array           x   632,280 ops/sec ±4.27% (80 runs sampled)
// hessian2 decode with type array           x   876,049 ops/sec ±2.26% (86 runs sampled)
// hessian1 decode with type: simple object  x   189,740 ops/sec ±3.36% (82 runs sampled)
// hessian2 decode with type: simple object  x   238,079 ops/sec ±1.85% (84 runs sampled)
// hessian1 decode with type: complex object x   130,701 ops/sec ±2.27% (87 runs sampled)
// hessian2 decode with type: complex object x   160,600 ops/sec ±1.63% (87 runs sampled)


================================================
FILE: benchmark/encode.js
================================================
'use strict';

var ByteBuffer = require('byte');
var Benchmark = require('benchmark');
var benchmarks = require('beautify-benchmark');
var java = require('js-to-java');
var hessian = require('../');

var suite = new Benchmark.Suite();

var simpleObject = {
  $class: 'com.hessiantest.org.MockRequest',
  $: {
    id: 123,
    name: 'getData',
    args: [1, "name", "xxx1231231231231xxx123"]
  }
};

var complexObject = {
  $class: 'com.hessiantest.org.MockRequest',
  $: {
    id: 123,
    name: 'getData',
    args: [1, "name", "xxx1231231231231xxx123"],
    conn: {
      $class: 'com.hessiantest.org.MockRequestConnection',
      $: {
        ctx: java.long(1024)
      }
    }
  }
};

suite

.add('hessian1 encode: number', function() {
  hessian.encode(1, '1.0');
})
.add('hessian2 encode: number', function() {
  hessian.encode(1, '2.0');
})

.add('hessian1 encode: date', function() {
  hessian.encode(new Date(), '1.0');
})
.add('hessian2 encode: date', function() {
  hessian.encode(new Date(), '2.0');
})

.add('hessian1 encode: long', function() {
  hessian.encode(java.long(300), '1.0');
})
.add('hessian2 encode: long', function() {
  hessian.encode(java.long(300), '2.0');
})

.add('hessian1 encode: string', function() {
  hessian.encode('xxx1231231231231xxx123', '1.0');
})
.add('hessian2 encode: string', function() {
  hessian.encode('xxx1231231231231xxx123', '2.0');
})

.add('hessian1 encode: [1, 2, 3]', function() {
  hessian.encode([1, 2, 3], '1.0');
})
.add('hessian2 encode: [1, 2, 3]', function() {
  hessian.encode([1, 2, 3], '2.0');
})
.add('hessian1 encode array', function() {
  hessian.encode([1, "name", "xxx1231231231231xxx123"], '1.0');
})
.add('hessian2 encode array', function() {
  hessian.encode([1, "name", "xxx1231231231231xxx123"], '2.0');
})

.add('hessian1 encode: simple object', function() {
  hessian.encode(simpleObject, '1.0');
})
.add('hessian2 encode: simple object', function() {
  hessian.encode(simpleObject, '2.0');
})

.add('hessian1 encode: complex object', function() {
  hessian.encode(complexObject, '1.0');
})
.add('hessian2 encode: complex object', function() {
  hessian.encode(complexObject, '2.0');
})

.on('cycle', function(event) {
  benchmarks.add(event.target);
})
.on('start', function(event) {
  console.log('\n  Hessian Encode Benchmark\n  node version: %s, date: %s\n  Starting...',
    process.version, Date());
})
.on('complete', function done() {
  benchmarks.log();
})
.run({ 'async': false });

// node version: v0.11.12, date: Tue May 13 2014 10:30:18 GMT+0800 (CST)
// Starting...
// 16 tests completed.
//
// hessian1 encode: number         x 1,262,878 ops/sec ±10.80% (74 runs sampled)
// hessian2 encode: number         x 1,816,722 ops/sec ±2.34% (92 runs sampled)
// hessian1 encode: date           x   766,202 ops/sec ±3.90% (90 runs sampled)
// hessian2 encode: date           x   673,284 ops/sec ±4.78% (83 runs sampled)
// hessian1 encode: long           x   650,132 ops/sec ±1.48% (96 runs sampled)
// hessian2 encode: long           x   636,692 ops/sec ±3.49% (88 runs sampled)
// hessian1 encode: string         x   804,401 ops/sec ±6.48% (79 runs sampled)
// hessian2 encode: string         x   967,111 ops/sec ±3.15% (88 runs sampled)
// hessian1 encode: [1, 2, 3]      x   525,540 ops/sec ±2.36% (92 runs sampled)
// hessian2 encode: [1, 2, 3]      x   623,072 ops/sec ±2.27% (97 runs sampled)
// hessian1 encode array           x   318,811 ops/sec ±8.70% (82 runs sampled)
// hessian2 encode array           x   396,659 ops/sec ±3.12% (92 runs sampled)
// hessian1 encode: simple object  x   101,458 ops/sec ±9.30% (67 runs sampled)
// hessian2 encode: simple object  x   132,938 ops/sec ±3.23% (89 runs sampled)
// hessian1 encode: complex object x    90,243 ops/sec ±2.08% (93 runs sampled)
// hessian2 encode: complex object x    80,702 ops/sec ±5.94% (86 runs sampled)

// node version: v0.11.12, date: Wed May 14 2014 18:47:59 GMT+0800 (CST)
// Starting...
// 16 tests completed.
//
// hessian1 encode: number         x 1,601,925 ops/sec ±2.57% (89 runs sampled)
// hessian2 encode: number         x 1,800,237 ops/sec ±1.90% (93 runs sampled)
// hessian1 encode: date           x   773,461 ops/sec ±2.22% (88 runs sampled)
// hessian2 encode: date           x   703,063 ops/sec ±4.90% (86 runs sampled)
// hessian1 encode: long           x   555,507 ops/sec ±4.36% (87 runs sampled)
// hessian2 encode: long           x   598,983 ops/sec ±3.26% (86 runs sampled)
// hessian1 encode: string         x   911,037 ops/sec ±2.50% (95 runs sampled)
// hessian2 encode: string         x 1,013,393 ops/sec ±1.75% (92 runs sampled)
// hessian1 encode: [1, 2, 3]      x   520,715 ops/sec ±1.55% (91 runs sampled)
// hessian2 encode: [1, 2, 3]      x   552,279 ops/sec ±3.97% (86 runs sampled)
// hessian1 encode array           x   377,503 ops/sec ±1.40% (94 runs sampled)
// hessian2 encode array           x   403,264 ops/sec ±3.10% (93 runs sampled)
// hessian1 encode: simple object  x   132,363 ops/sec ±5.80% (83 runs sampled)
// hessian2 encode: simple object  x   138,711 ops/sec ±3.52% (89 runs sampled)
// hessian1 encode: complex object x    94,401 ops/sec ±1.15% (90 runs sampled)
// hessian2 encode: complex object x    90,484 ops/sec ±1.33% (97 runs sampled)

// node version: v0.11.12, date: Thu May 15 2014 18:13:05 GMT+0800 (CST)
// Starting...
// 16 tests completed.
//
// hessian1 encode: number         x 1,553,553 ops/sec ±3.58% (92 runs sampled)
// hessian2 encode: number         x 1,895,587 ops/sec ±0.63% (97 runs sampled)
// hessian1 encode: date           x   599,048 ops/sec ±0.58% (98 runs sampled)
// hessian2 encode: date           x   562,479 ops/sec ±1.76% (93 runs sampled)
// hessian1 encode: long           x   498,383 ops/sec ±0.69% (98 runs sampled)
// hessian2 encode: long           x   672,058 ops/sec ±1.20% (96 runs sampled)
// hessian1 encode: string         x   980,671 ops/sec ±2.19% (97 runs sampled)
// hessian2 encode: string         x 1,041,627 ops/sec ±0.70% (93 runs sampled)
// hessian1 encode: [1, 2, 3]      x   538,953 ops/sec ±2.54% (92 runs sampled)
// hessian2 encode: [1, 2, 3]      x   631,285 ops/sec ±0.36% (99 runs sampled)
// hessian1 encode array           x   389,785 ops/sec ±0.51% (98 runs sampled)
// hessian2 encode array           x   408,655 ops/sec ±2.37% (97 runs sampled)
// hessian1 encode: simple object  x   161,088 ops/sec ±0.84% (97 runs sampled)
// hessian2 encode: simple object  x   155,580 ops/sec ±0.82% (98 runs sampled)
// hessian1 encode: complex object x   103,974 ops/sec ±1.34% (96 runs sampled)
// hessian2 encode: complex object x   100,160 ops/sec ±1.18% (101 runs sampled)


================================================
FILE: benchmark/reg.js
================================================
'use strict';

var Benchmark = require('benchmark');
var benchmarks = require('beautify-benchmark');

var suite = new Benchmark.Suite();


var INNER_CLASS_PROPERTY_REG = /^this\$\d+$/;
var INNER_CLASS_LABEL = '$$ignore_inner_property$$';

var name1 = 'foobar';
var name2 = 'this$123';
var name3 = INNER_CLASS_LABEL;

suite

.add('dynamic', function() {
  /^this\$\d+/.test(name1);
  /^this\$\d+/.test(name2);
})
.add('static', function() {
  INNER_CLASS_PROPERTY_REG.test(name1);
  INNER_CLASS_PROPERTY_REG.test(name2);
})
.add('equal', function() {
  name1 === INNER_CLASS_LABEL;
  name3 === INNER_CLASS_LABEL;
})

.on('cycle', function(event) {
  benchmarks.add(event.target);
})
.on('start', function(event) {
  console.log('\n  Reg Benchmark\n  node version: %s, date: %s\n  Starting...',
    process.version, Date());
})
.on('complete', function done() {
  benchmarks.log();
})
.run({ 'async': false });

// node version: v8.5.0, date: Sat Oct 21 2017 08:00:33 GMT+0800 (CST)
// Starting...
// 3 tests completed.
//
// dynamic x   8,355,274 ops/sec ±1.00% (85 runs sampled)
// static  x  10,547,340 ops/sec ±0.90% (89 runs sampled)
// equal   x 488,054,083 ops/sec ±0.67% (88 runs sampled)


================================================
FILE: benchmark/string.js
================================================
'use strict';

const Benchmark = require('benchmark');
const benchmarks = require('beautify-benchmark');
const assert = require('assert');

const ByteBuffer = require('byte');
const io = ByteBuffer.allocate(1024 * 1024);

const str = '1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234';
io.putRawString(str);
const buf = io.array();

// io.position(0);
// console.log(io.getRawStringByStringLength(1024));
// console.log(buf.toString());

io.position(0);
assert(io.getRawStringByStringLength(1024) === buf.toString());

function getUTF(buf) {
  const data = [];
  const length = buf.length;
  for (let i = 0; i < length; i++) {
    const ch = buf[i];
    if (ch < 0x80) {
      data.push(ch);
    } else if ((ch & 0xe0) === 0xc0) {
      const ch1 = buf[++i];
      const v = ((ch & 0x1f) << 6) + (ch1 & 0x3f);
      data.push(v);
    } else if ((ch & 0xf0) === 0xe0) {
      const ch1 = buf[++i];
      const ch2 = buf[++i];
      const v = ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6) + (ch2 & 0x3f);
      data.push(v);
    } else {
      throw new Error('string is not valid UTF-8 encode');
    }
  }
  return String.fromCharCode.apply(String, data);
}

assert(getUTF(buf) === buf.toString());


function getUTF2(buf) {
  const length = buf.length;
  const data = [];
  let start = 0;
  const numInts = length >> 2;
  for (let i = 0; i < numInts; i++) {
    const num = buf.readInt32BE(i * 4);
    if ((num & 0x80808080) !== 0) {
      throw new Error();
    }
  }
  const offset = start + length;
  return buf.toString('utf8', 0, offset);

  // while (i < length) {
  //   const num = buf.readInt32BE(i);
  //   if ((num & 0x80808080) === 0) {
  //     data.push(buf[i]);
  //     data.push(buf[i + 1]);
  //     data.push(buf[i + 2]);
  //     data.push(buf[i + 3]);
  //     i += 4;
  //   } else {
  //     assert(false);
  //   }
  // }
  // return String.fromCharCode.apply(String, data);
}

assert(getUTF2(buf) === buf.toString());
io.position(0);
assert(io.getRawStringFast(1024) === buf.toString());

const suite = new Benchmark.Suite();
suite
  .add('io.getRawStringByStringLength', function() {
    io._offset = 0;
    io.getRawStringByStringLength(1024);
  })
  .add('io.getRawStringFast', function() {
    io._offset = 0;
    io.getRawStringFast(1024);
  })
  .add('buf.toString', function() {
    buf.toString();
  })
  .add('getUTF', function() {
    getUTF(buf);
  })
  .add('getUTF2', function() {
    getUTF2(buf);
  })
  .on('cycle', function(event) {
    benchmarks.add(event.target);
  })
  .on('start', function(event) {
    console.log('\n  Cache Benchmark\n  node version: %s, date: %s\n  Starting...',
      process.version, Date());
  })
  .on('complete', function done() {
    benchmarks.log();
  })
  .run({ 'async': false });

// Cache Benchmark
// node version: v8.9.0, date: Thu Nov 16 2017 13:26:18 GMT+0800 (CST)
// Starting...
// 2 tests completed.
//
// with cache    x 21,724 ops/sec ±2.01% (82 runs sampled)
// without cache x  8,523 ops/sec ±1.17% (89 runs sampled)


================================================
FILE: index.js
================================================
'use strict';

var EncoderV1 = exports.EncoderV1 = exports.Encoder = require('./lib/v1/encoder');
var DecoderV1 = exports.DecoderV1 = exports.Decoder = require('./lib/v1/decoder');

var EncoderV2 = exports.EncoderV2 = require('./lib/v2/encoder');
var DecoderV2 = exports.DecoderV2 = require('./lib/v2/decoder');

exports.encoderV1 = new EncoderV1({size: 1024 * 1024});
exports.encoderV2 = new EncoderV2({size: 1024 * 1024});

exports.decode = function decode(buf, version, options) {
  var classCache;
  var withType;

  if (version && typeof version !== 'string') {
    // buf, withType, version
    var t = version;
    version = options;
    options = t;
  }

  if (typeof options === 'boolean') {
    withType = options;
  }
  if (typeof options === 'object') {
    withType = options.withType;
    classCache = options.classCache;
  }
  withType = !!withType;

  if (version === '2.0') {
    return new DecoderV2(buf, classCache).read(withType);
  }
  return new DecoderV1(buf, classCache).read(withType);
};

exports.encode = function encode(obj, version) {
  var encoder;
  if (version === '2.0') {
    encoder = exports.encoderV2;
  } else {
    encoder = exports.encoderV1;
  }

  encoder.reset();
  return encoder.write(obj).get();
};

var custom = require('./lib/custom_handler');

exports.registerDecodeHandler = custom.registerDecodeHandler;
exports.deregisterDecodeHandler= custom.deregisterDecodeHandler;


================================================
FILE: lib/convert/index.js
================================================
'use strict';

module.exports = {
  'java.util.Locale': require('./java.util.locale'),
};


================================================
FILE: lib/convert/java.util.locale.js
================================================
'use strict';

module.exports = function(obj) {
  return {
    $class: 'com.caucho.hessian.io.LocaleHandle',
    $: { value: obj.$ },
  };
};


================================================
FILE: lib/custom_handler.js
================================================
'use strict';

var assert = require('assert');

var handlers = {};

function deregisterDecodeHandler(className) {
	delete handlers[className];
}

function registerDecodeHandler(className, handler) {
  assert(typeof handler === 'function', 'handler should be a function');
  handlers[className] = handler;
}

function handle(result, withType) {
  var className = result.$class;
  var handler = handlers[className];

  if (handler) {
    result = handler(result);
  }
  return withType ? result : result.$;
}

exports.handle = handle;
exports.registerDecodeHandler = registerDecodeHandler;
exports.deregisterDecodeHandler = deregisterDecodeHandler;


================================================
FILE: lib/object.js
================================================
'use strict';

var util = require('util');

exports.DEFAULT_CLASSNAME = {
  boolean: 'boolean',
  int: 'int',
  long: 'long',
  double: 'double',
  date: 'java.util.Date',
  string: 'java.lang.String',
  byteArray: '[B',
  list: 'java.util.ArrayList',
  // iList: 'java.util.List',
  map: 'java.util.HashMap',
  iMap: 'java.util.Map',
  exception: 'java.lang.RuntimeException'
};

exports.Object = 'java.lang.Object';

var SERIALIZER_MAP = exports.SERIALIZER_MAP = {};

[
  'boolean',
  'java.lang.Boolean',
  'bool',
].forEach(function (t) {
  SERIALIZER_MAP[t] = 'Bool';
});

[
  'double',
  'java.lang.Double',
  'float',
  'java.lang.Float',
].forEach(function (t) {
  SERIALIZER_MAP[t] = 'Double';
});

[
  'java.lang.Long',
  'long',
].forEach(function (t) {
  SERIALIZER_MAP[t] = 'Long';
});

[
  'short',
  'java.lang.Short',
  'int',
  'java.lang.Integer',
  'byte',
  'java.lang.Byte',
].forEach(function (t) {
  SERIALIZER_MAP[t] = 'Int';
});

[
  'java.lang.String',
  'String',
  'string',
  'char',
  'char[]',
  'java.lang.Character',
].forEach(function (t) {
  SERIALIZER_MAP[t] = 'String';
});

[
  'java.util.Date'
].forEach(function (t) {
  SERIALIZER_MAP[t] = 'Date';
});

// http://www.devthought.com/2011/12/22/a-string-is-not-an-error/
function JavaExceptionError(obj, withType) {
  Error.call(this);
  Error.captureStackTrace(this, JavaExceptionError);

  // $: { detailMessage: 'this is a java IOException instance',
  // cause: [Circular],
  // stackTrace:
  //  [ { declaringClass: 'hessian.Main',
  //      methodName: 'main',
  //      fileName: 'Main.java',
  //      lineNumber: 1282 } ] }
  var undeclaredThrowable = obj.$.undeclaredThrowable;
  if (undeclaredThrowable && withType) {
    undeclaredThrowable = undeclaredThrowable.$;
  }
  var detailMessage = obj.$.detailMessage;
  if (detailMessage && withType) {
    detailMessage = detailMessage.$;
  }

  var cause = obj.$.cause;
  if (cause && cause.$ && withType) {
    cause = cause.$;
  }

  if (undeclaredThrowable && undeclaredThrowable instanceof Error) {
    if (!obj.$.detailMessage) {
      return undeclaredThrowable;
    }
    this.name = undeclaredThrowable.name;
    if (withType) {
      this.message = obj.$.detailMessage.$ + '; ' + undeclaredThrowable.message;
    } else {
      this.message = obj.$.detailMessage + '; ' + undeclaredThrowable.message;
    }
  } else if (!detailMessage && cause && cause !== obj.$) {
    return cause;
  } else {
    if (withType) {
      this.message = obj.$.detailMessage && obj.$.detailMessage.$ || obj.$class;
      if (obj.$.reasonAndSolution) {
        this.message += '; reasonAndSolution: ' + obj.$.reasonAndSolution.$;
      }
    } else {
      this.message = obj.$.detailMessage || obj.$class;
      if (obj.$.reasonAndSolution) {
        this.message += '; reasonAndSolution: ' + obj.$.reasonAndSolution;
      }
    }
    this.name = obj.$class;
  }

  this.cause = obj.$.cause;

  var stack = this.name + ': ' + this.message;
  if (withType) {
    var stackTraces = obj.$.stackTrace && obj.$.stackTrace.$ || [];
    for (var i = 0; i < stackTraces.length; i++) {
      var trace = stackTraces[i].$;
      stack += '\n    at ' + (trace.declaringClass && trace.declaringClass.$)
        + '.' + (trace.methodName && trace.methodName.$)
        + ' (' + (trace.fileName && trace.fileName.$)
        + ':' + (trace.lineNumber && trace.lineNumber.$) + ')';
    }
  } else {
    var stackTraces = obj.$.stackTrace || [];
    for (var i = 0; i < stackTraces.length; i++) {
      var trace = stackTraces[i];
      stack += '\n    at ' + trace.declaringClass + '.' + trace.methodName
        + ' (' + trace.fileName + ':' + trace.lineNumber + ')';
    }
  }

  this.stack = stack;
}

util.inherits(JavaExceptionError, Error);

exports.JavaExceptionError = JavaExceptionError;


================================================
FILE: lib/utils.js
================================================
'use strict';

var debug = require('util').debuglog('hessian.js:utils');
var Long = require('long');
var object = require('./object');

var MAX_SAFE_INT = Long.fromNumber(Math.pow(2, 53) - 1);
var MIN_SAFE_INT = Long.fromNumber(1 - Math.pow(2, 53));

var MAX_BYTE_TRUNK_SIZE = exports.MAX_BYTE_TRUNK_SIZE = 0x8000;
var MAX_CHAR_TRUNK_SIZE = exports.MAX_CHAR_TRUNK_SIZE = 0x8000;

// Map feature detect
exports.supportES6Map = typeof Map === 'function' && typeof Map.prototype.forEach === 'function';

exports.getSerializer = function (type) {
  // get from SERIALIZER_MAP
  if (object.SERIALIZER_MAP[type]) {
    return 'write' + object.SERIALIZER_MAP[type];
  }
  // array: [int
  if (type[0] === '[') {
    return 'writeArray';
  }
  // object
  return 'writeObject';
};

exports.isJavaObject = function (type) {
  return type === object.Object;
};

exports.handleLong = function (val) {
  if (val.greaterThan(MAX_SAFE_INT) || val.lessThan(MIN_SAFE_INT)) {
    val = val.toString();
    debug('[hessian.js Warning] Read a not safe long(%s), translate it to string', val);
    return val;
  }
  return val.toNumber();
};

var _hasOwnProperty = Object.prototype.hasOwnProperty;
/* jshint -W001 */
exports.hasOwnProperty = function hasOwnProperty(obj, property) {
  return _hasOwnProperty.call(obj, property);
};

exports.addByteCodes = function addByteCodes(map, codes, method) {
  for (var i = 0; i < codes.length; i++) {
    var code = codes[i];
    if (Array.isArray(code)) {
      var startCode = code[0];
      var endCode = code[1];
      for (var c = startCode; c <= endCode; c++) {
        map[c] = method;
      }
    } else {
      map[code] = method;
    }
  }
};


================================================
FILE: lib/v1/decoder.js
================================================
'use strict';

var debug = require('util').debuglog('hessian:v1:decoder');
var ByteBuffer = require('byte');
var is = require('is-type-of');
var utils = require('../utils');
var object = require('../object');
var handle = require('../custom_handler').handle;
var JavaExceptionError = object.JavaExceptionError;
var supportES6Map = require('../utils').supportES6Map;

var BYTE_CODES = {};

function Decoder(buf) {
  this.byteBuffer = buf ? ByteBuffer.wrap(buf) : null;
  this.refMap = {};
  this.refId = 0;
  this.BYTE_CODES = BYTE_CODES;
}

/**
 * prototype of Decoder
 */

var proto = Decoder.prototype;

proto.throwError = function (method, code) {
  throw new TypeError('hessian ' + method + ' error, unexpect code: 0x' + code.toString(16));
};

proto._addRef = function (obj) {
  this.refMap[this.refId++] = obj;
};

/**
 * init from a buffer
 * @param {Buffer} buf
 * @api public
 */
proto.init = function (buf) {
  this.byteBuffer = ByteBuffer.wrap(buf);
  return this;
};

/**
 * clean the decoder
 * @api public
 */
proto.clean = function () {
  this.byteBuffer = new ByteBuffer();
  this.refMap = {};
  this.refId = 0;
  return this;
};

/**
 * check if the label match the method
 * @api private
 */
proto._checkLabel = function (method, label) {
  var l = this.byteBuffer.getChar();
  var labelIsOk = l === label || label.indexOf(l) >= 0;
  if (!labelIsOk) {
    throw new TypeError('hessian ' + method + ' only accept label `' + label +
      '` but got unexpect label `' + l + '`');
  }
  return l;
};

proto.handleType = function(type, val, withType) {
  return withType ? {$class: object.DEFAULT_CLASSNAME[type], $: val} : val;
};

/**
 * read a null from buffer
 *
 * v1.0
 * ```
 * null ::= N(x4e)
 * ```
 *
 * @return {Null}
 * @api public
 */
proto.readNull = function () {
  this._checkLabel('readNull', 'N');
  return null;
};

utils.addByteCodes(BYTE_CODES, [
  0x4e,
], 'readNull');

/**
 * read a boolean from buffer
 *
 * v1.0
 * ```
 * boolean ::= T(x54)
 *         ::= F(x46)
 * ```
 *
 * @return {Boolean}
 * @api public
 */
proto.readBool = function (withType) {
  var label = this._checkLabel('readBool', ['T', 'F']);
  var val = label === 'T';
  return this.handleType('boolean', val, withType);
};

utils.addByteCodes(BYTE_CODES, [
  0x54,
  0x46,
], 'readBool');

/**
 * read a int from buffer
 *
 * v1.0
 * ```
 * int ::= I(x49) b32 b24 b16 b8
 * ```
 *
 * @return {Number}
 * @api public
 */
proto.readInt = function (withType) {
  this._checkLabel('readInt', 'I');
  var val = this.byteBuffer.getInt();
  return this.handleType('int', val, withType);
};

utils.addByteCodes(BYTE_CODES, [
  0x49
], 'readInt');

/**
 * read a long from buffer
 *
 * v1.0
 * ```
 * long ::= L(x4c) b64 b56 b48 b40 b32 b24 b16 b8
 * ```
 *
 * @return {Number}
 * @api public
 */
proto.readLong = function (withType) {
  this._checkLabel('readLong', 'L');
  var val = utils.handleLong(this.byteBuffer.getLong());
  return this.handleType('long', val, withType);
};

utils.addByteCodes(BYTE_CODES, [
  0x4c
], 'readLong');

/**
 * read a double from buffer
 *
 * v1.0
 * ```
 * double ::= D(x44) b64 b56 b48 b40 b32 b24 b16 b8
 * ```
 *
 * @return {Number}
 * @api public
 */
proto.readDouble = function (withType) {
  this._checkLabel('readDouble', 'D');
  var val = this.byteBuffer.getDouble();
  return this.handleType('double', val, withType);
};

utils.addByteCodes(BYTE_CODES, [
  0x44
], 'readDouble');

/**
 * read a date from buffer
 *
 * v1.0
 * ```
 * date ::= d(x64) b64 b56 b48 b40 b32 b24 b16 b8
 * ```
 * Date represented by a 64-bit long of milliseconds since Jan 1 1970 00:00H, UTC.
 *
 * @return {Date}
 * @api public
 */
proto.readDate = function (withType) {
  this._checkLabel('readDate', 'd');
  var date = utils.handleLong(this.byteBuffer.getLong());
  debug('read a date with milliEpoch: %d', date);
  var val = new Date(date);
  return this.handleType('date', val, withType);
};

utils.addByteCodes(BYTE_CODES, [
  0x64
], 'readDate');

/**
 * read bytes from buffer
 *
 * v1.0
 * ```
 * binary ::= (b(x62) b16 b8 binary-data)* B(x42) b16 b8 binary-data
 * ```
 * Binary data is encoded in chunks.
 * 'B' represents the final chunk and
 * 'b' represents any initial chunk. Each chunk has a 16-bit length value.
 *
 * @return {Buffer}
 * @api public
 */
proto.readBytes = function () {
  var label = this._checkLabel('readBytes', ['b', 'B']);
  var bufs = [];
  var length = 0;
  // get all trunk start with 'b'
  while (label === 'b') {
    length = this.byteBuffer.getUInt16();
    bufs.push(this.byteBuffer.read(length));
    label = this._checkLabel('readBytes', ['b', 'B']);
  }
  // get the last trunk start with 'B'
  length = this.byteBuffer.getUInt16();
  bufs.push(this.byteBuffer.read(length));

  return Buffer.concat(bufs);
};

utils.addByteCodes(BYTE_CODES, [
  0x62,
  0x42
], 'readBytes');

proto._readUTF8String = function (len) {
  if (!is.number(len)) {
    len = this.byteBuffer.getUInt16();
  }
  if (len === 0) {
    return '';
  }
  return this.byteBuffer.getRawStringByStringLength(len);
};

/**
 * read a string from buffer
 *
 * The length is the number of characters, which may be different than the number of bytes.
 *
 * v1.0
 * ```
 * string ::= (s(x73) b16 b8 utf-8-data)* S(x53) b16 b8 utf-8-data
 * ```
 *
 * @return {String}
 * @api public
 */
proto.readString = function (withType) {
  var str = '';
  var code = this.byteBuffer.get();
  // get all trunk start with 's'
  while (code === 0x73) {
    str += this._readUTF8String();
    code = this.byteBuffer.get();
  }

  if (code === 0x53) {
    // x53 ('S') represents the final chunk
    debug('read last trunk of string');
    str += this._readUTF8String();
  } else {
    // error format
    throw new TypeError('hessian readString error, unexpect string code: 0x' + code.toString(16));
  }
  return this.handleType('string', str, withType);
};

utils.addByteCodes(BYTE_CODES, [
  0x73,
  0x53
], 'readString');

/**
 * v1.0
 * ```
 * t(x74) b16 b8 type-string
 * ```
 *
 * @param {Boolean} skip skip type, if true, will return empty string
 * @return {String} type string
 */
proto.readType = function (skip) {
  this._checkLabel('readType', 't');
  var typeLength = this.byteBuffer.getUInt16();
  if (skip) {
    this.byteBuffer.skip(typeLength);
    debug('ignore type, skip %d bytes', typeLength);
    return '';
  } else {
    var type = this.byteBuffer.readRawString(typeLength);
    debug('get type: %s', type);
    return type;
  }
};

utils.addByteCodes(BYTE_CODES, [
  0x74,
], 'readType');

proto.readLength = function () {
  this._checkLabel('readLength', 'l'); // x6c
  var len = this.byteBuffer.getUInt();
  debug('read length: %s', len);
  return len;
};

utils.addByteCodes(BYTE_CODES, [
  0x6c,
], 'readLength');

/**
 * A sparse array, hessian v1.0
 * http://hessian.caucho.com/doc/hessian-1.0-spec.xtp#map
 */
proto._readSparseObject = function (withType) {
  var obj = {};
  var label = this.byteBuffer.getChar(this.byteBuffer.position());
  while (label !== 'z') {
    debug('sparse array label: %s', label);
    var key = this.read(withType);
    var val = this.read(withType);
    obj[key] = val;
    label = this.byteBuffer.getChar(this.byteBuffer.position());
  }
  // skip 'z' char
  this.byteBuffer.position(this.byteBuffer.position() + 1);

  // default type info
  if (withType) {
    return {
      $class: object.DEFAULT_CLASSNAME.map,
      $: obj
    };
  }

  return obj;
};

/**
 * read an object from buffer
 *
 * v1.0
 * ```
 * map ::= M(x4d) t b16 b8 type-string (object, object)* z
 * ```
 *
 * @param {Boolean} withType if need retain the type info
 * @return {Object}
 * @api public
 */
proto.readObject = function (withType) {
  this._checkLabel('readObject', 'M');
  debug('start read an object');
  var typeLabel = this.byteBuffer.getChar(this.byteBuffer.position());
  if (typeLabel !== 't') {
    debug('read sparse object, start label: %s', typeLabel);
    return this._readSparseObject(withType);
  }

  var type = this.readType(false) || object.DEFAULT_CLASSNAME.map;
  // if object is 'java.util.HashMap', type will be ''

  var result = {
    $class: type,
    $: {}
  };
  var isMap = (type.indexOf(object.DEFAULT_CLASSNAME.map) === 0 ||
    type.indexOf(object.DEFAULT_CLASSNAME.iMap) === 0) && supportES6Map;

  if (isMap) {
    Object.defineProperty(result.$, '$map', {
      value: new Map(),
      enumerable: false,
    });
  }

  this._addRef(result);

  // get
  var label = this.byteBuffer.getChar();
  var key;

  while (label !== 'z') {
    this.byteBuffer.position(this.byteBuffer.position() - 1);
    key = this.read();

    var value = this.read(withType);
    label = this.byteBuffer.getChar();
    // property name will auto transfer to a String type.
    debug('read object prop: %j with type: %s', key, withType);
    if (!/^this\$\d+$/.test(key)) {
      var k = is.object(key) && key.name ? key.name : key;
      result.$[k] = value;
    }
    if (isMap) {
      result.$.$map.set(key, value);
    }
  }
  debug('read object finish');

  // java.lang.NoClassDefFoundError
  if (/Exception$/.test(type) || /^java\.lang\.\w+Error$/.test(type)) {
    result.$ = new JavaExceptionError(result, withType);
  }

  return handle(result, withType);
};

utils.addByteCodes(BYTE_CODES, [
  0x4d,
], 'readObject');

/**
 * read an map from buffer
 *
 * v1.0
 * ```
 * map ::= M t b16 b8 type-string (object, object)* z
 * ```
 *
 * @param {Boolean} withType if need retain the type info
 * @return {Object}
 * @api public
 */
proto.readMap = proto.readObject;

/**
 * anonymous variable-length list = {0, "foobar"}
 * http://hessian.caucho.com/doc/hessian-1.0-spec.xtp#list
 */
proto._readNoLengthArray = function (withType, type) {
  var arr = [];
  var label = this.byteBuffer.getChar(this.byteBuffer.position());
  while (label !== 'z') {
    debug('no length array item#%d label: %s', arr.length, label);
    arr.push(this.read(withType));
    label = this.byteBuffer.getChar(this.byteBuffer.position());
  }
  // skip 'z' char
  this.byteBuffer.position(this.byteBuffer.position() + 1);

  arr = withType
  ? { $class: type, $: arr }
  : arr;
  return arr;
};

/**
 * read an array from buffer
 *
 * v1.0
 * ```
 * list ::= V(x56) type? length? object* z
 * ```
 *
 * @param {Boolean} withType if need retain the type info
 * @return {Array}
 * @api public
 */
proto.readArray = function (withType) {
  debug('start read an array');
  this._checkLabel('readArray', 'V');
  var type = '';

  var typeLabel = this.byteBuffer.getChar(this.byteBuffer.position());
  if (typeLabel === 't') {
    type = this.readType(!withType);
  }
  type = type || object.DEFAULT_CLASSNAME.list;

  var lengthLabel = this.byteBuffer.getChar(this.byteBuffer.position());
  if (lengthLabel !== 'l') {
    debug('read no length array, start label: %s', typeLabel);
    return this._readNoLengthArray(withType, type);
  }

  // if object is 'java.util.ArrayList', type will be ''

  var realResult = [];
  var result = realResult;

  if (withType) {
    result = {
      $class: type,
      $: realResult
    };
  }

  this._addRef(result);

  var len = this.readLength();
  while (len--) {
    realResult.push(this.read(withType));
  }
  var endLabel = this.byteBuffer.getChar();
  if (endLabel !== 'z') {
    throw new TypeError('hessian readArray error, unexpect end label: ' + endLabel);
  }
  debug('read array finished with a length of %d', realResult.length);
  return result;
};

utils.addByteCodes(BYTE_CODES, [
  0x56,
], 'readArray');

proto.readList = proto.readArray;

/**
 * Get a object by ref id
 *
 * @return {Object}
 */
proto.readRef = function (withType) {
  var rid = this.readRefId();
  var obj = this.refMap[rid];
  if (!withType && obj && utils.hasOwnProperty(obj, '$')) {
    return handle(obj, withType);
  }
  return obj;
};

/**
 * v1.0
 * ```
 * ref ::= R(x52) b32 b24 b16 b8
 * ```
 *
 * @return {Number}
 */
proto.readRefId = function (withType) {
  this._checkLabel('readRef', 'R');
  return this.byteBuffer.getInt();
};

utils.addByteCodes(BYTE_CODES, [
  0x52,
], 'readRef');

/**
 * read any thing
 *
 * @param {Boolean} withType if need retain the type info
 * @api public
 */
proto.read = function (withType) {
  var pos = this.byteBuffer.position();
  var code = this.byteBuffer.get(pos);
  var method = this.BYTE_CODES[code];
  if (debug.enabled) {
    debug('read position: %s, code: 0x%s, method: %s', pos, code.toString(16), method);
  }

  if (!method) {
    throw new Error('hessian read got an unexpect code: 0x' + code.toString(16));
  }

  return this[method](withType);
};

/**
 * set or get decoder byteBuffer position
 */
proto.position = function (num) {
  if (is.number(num)) {
    this.byteBuffer.position(num);
    return this;
  }

  return this.byteBuffer.position();
};

module.exports = Decoder;


================================================
FILE: lib/v1/encoder.js
================================================
'use strict';

var debug = require('util').debuglog('hessian:v1:encoder');
var utility = require('utility');
var ByteBuffer = require('byte');
var utils = require('../utils');
var javaObject = require('../object');
var is = require('is-type-of');
var converts = require('../convert');
var supportES6Map = require('../utils').supportES6Map;

function Encoder(options) {
  options = options || {};
  //array of buffer
  this.byteBuffer = new ByteBuffer({
    size: options.size
  });
  this.objects = [];
  this.mapTypes = utility.assign({
    'java.util.HashMap': true,
    'java.util.Map': true,
    'com.alibaba.fastjson.JSONObject': true,
  }, options.mapTypes);
}

var proto = Encoder.prototype;

proto.isMap = function (type) {
  return utility.has(this.mapTypes, type) && this.mapTypes[type];
};

proto._assertType = function (method, expectType, val, desc) {
  var valType = typeof val;
  if (!is[expectType](val)) {
    var msg = 'hessian ' + method +
      ' expect input type is `' + expectType + '`, but got `' + valType + '`' + ' : ' + JSON.stringify(val) + ' ' + (desc || '');
    throw new TypeError(msg);
  }
};

/**
 * get the encode buffer
 * @return {Buffer}
 */
proto.get = function () {
  return this.byteBuffer.array();
};

/**
 * clean the buf
 */
proto.reset = proto.clean = function () {
  this.byteBuffer.reset();
  this.objects = [];
  return this;
};

/**
 * encode null
 * : N
 */
proto.writeNull = function () {
  this.byteBuffer.putChar('N');
  return this;
};

/**
 * encode bool
 * : T
 * : F
 */
proto.writeBool = function (val) {
  this.byteBuffer.putChar(val ? 'T' : 'F');
  return this;
};

/**
 * encode int
 * : I 0x00 0x00 0x00 0x10
 */
proto.writeInt = function (val) {
  this._assertType('writeInt', 'int32', val);
  this.byteBuffer
    .putChar('I')
    .putInt(val);
  return this;
};

/**
 * encode long
 * warning: we won't check if the long value is out of bound, be careful!
 * : L 0x00 0x00 0x00 0x00 0x10 0x32 0x33 0x12
 */
proto.writeLong = function (val) {
  this.byteBuffer
    .putChar('L')
    .putLong(val);
  return this;
};

/**
 * encode double
 * : D 0x00 0x00 0x00 0x00 0x10 0x32 0x33 0x12
 */
proto.writeDouble = function (val) {
  this._assertType('writeDouble', 'number', val);
  this.byteBuffer
    .putChar('D')
    .putDouble(val);
  return this;
};

/**
 * encode date
 * 1.0: http://hessian.caucho.com/doc/hessian-1.0-spec.xtp#date
 * : d 0x00 0x00 0x00 0x00 0x10 0x32 0x33 0x12
 */
proto.writeDate = function (milliEpoch) {
  if (milliEpoch instanceof Date) {
    milliEpoch = milliEpoch.getTime();
  }
  this._assertType('writeDate', 'number', milliEpoch);

  this.byteBuffer
    .putChar('d')
    .putLong(milliEpoch);
  return this;
};

/**
 * encode buffer
 * : b 0x80 0x00 [...]
 *   B 0x00 0x03 [0x01 0x02 0x03]
 */
proto.writeBytes = function (buf) {
  this._assertType('writeBytes', 'buffer', buf);
  var offset = 0;
  while (buf.length - offset > utils.MAX_BYTE_TRUNK_SIZE) {
    this.byteBuffer
      .putChar('b')
      .putUInt16(utils.MAX_BYTE_TRUNK_SIZE)
      .put(buf.slice(offset, offset + utils.MAX_BYTE_TRUNK_SIZE));

    offset += utils.MAX_BYTE_TRUNK_SIZE;
  }

  this.byteBuffer
    .putChar('B')
    .putUInt16(buf.length - offset)
    .put(buf.slice(offset));
  return this;
};

/**
 * encode string
 * : s 0x80 0x00 [...]
 *   S 0x00 0x03 [0x01 0x02 0x03]
 */
proto.writeString = function (str) {
  this._assertType('writeString', 'string', str);
  var offset = 0;

  var length = str.length;
  var strOffset = 0;
  while (length > 0x8000) {
    var sublen = 0x8000;
    // chunk can't end in high surrogate
    var tail = str.charCodeAt(strOffset + sublen - 1);

    if (0xd800 <= tail && tail <= 0xdbff) {
      debug('writeString got tail: 0x%s', tail.toString(16));
      sublen--;
    }

    this.byteBuffer
      .put(0x73) // 's'
      .putUInt16(sublen)
      .putRawString(str.slice(strOffset, strOffset + sublen));

    length -= sublen;
    strOffset += sublen;
    debug('writeString strOffset: %s, length: %s, sublen: %s', strOffset, length, sublen);
  }

  debug('writeString left length: %s', length);
  this.byteBuffer
    .put(0x53) // 'S'
    .putUInt16(length)
    .putRawString(str.slice(strOffset));

  return this;
};

var _typecache = {};

/**
 * encode type
 * v1.0
 * ```
 * type ::= 0x74(t) type-string-length(putUInt16) type-string(putRawString)
 * ```
 */
proto.writeType = function (type) {
  type = type || '';
  if (_typecache[type]) {
    this.byteBuffer.put(_typecache[type]);
    return this;
  }

  var start = this.byteBuffer.position();

  this.byteBuffer
    .put(0x74)
    .putUInt16(type.length)
    .putRawString(type);

  var end = this.byteBuffer.position();
  _typecache[type] = this.byteBuffer.copy(start, end);

  return this;
};

/**
 * encode ref
 * v1.0
 * ```
 * ref ::= R(0x52) int(putInt)
 * ```
 */
proto.writeRef = function (refId) {
  this.byteBuffer
    .putChar('R')
    .putInt(refId);

  return this;
};

proto._checkRef = function (obj) {
  var refIndex = this.objects.indexOf(obj);
  if (refIndex >= 0) {
    // already have this object
    // just write ref
    debug('writeObject with a refIndex: %d', refIndex);
    this.writeRef(refIndex);
    return true;
  }
  // a new comming object
  this.objects.push(obj);
  return false;
};

/**
 * A sparse array
 *
 * @param {Object} obj simple obj
 * @return {this}
 */
proto._writeHashMap = function (obj, type) {
  debug('_writeHashMap() %j, fields: %j', obj);

  // Real code in java impl:
  // http://grepcode.com/file/repo1.maven.org/maven2/com.caucho/hessian/3.1.3/com/caucho/hessian/io/Hessian2Output.java#Hessian2Output.writeMapBegin%28java.lang.String%29
  // M(0x4d) type(writeType) (<key> <value>) z(0x7a)
  this.byteBuffer.put(0x4d);
  // hashmap's type is null
  this.writeType(type);

  if (supportES6Map && obj instanceof Map) {
    obj.forEach(function (value, key) {
      this.write(key);
      this.write(value);
    }, this);
  } else {
    // hash map must sort keys
    var keys = Object.keys(obj).sort();
    for (var i = 0; i < keys.length; i++) {
      var k = keys[i];
      this.writeString(k);
      this.write(obj[k]);
    }
  }
  this.byteBuffer.put(0x7a);
  return this;
};

// M(0x4d) type(writeType) (<key> <value>) z(0x7a)
proto._writeObject = function (obj) {
  this._assertType('writeObject / writeMap', 'object', obj.$, obj.$class);
  this.byteBuffer.put(0x4d);
  this.writeType(obj.$class);

  var val = obj.$;
  var keys = Object.keys(val);
  for (var i = 0, len = keys.length; i < len; i++) {
    var key = keys[i];
    this.writeString(key);
    this.write(val[key]);
  }
  this.byteBuffer.put(0x7a);
  return this;
};

/**
 * encode object
 *   support circular
 *   support all kind of java object
 * : {a: 1}
 * : {$class: 'java.lang.Map', $: {a: 1}}
 */
proto.writeObject = function (obj) {
  if (is.nullOrUndefined(obj) ||
    // : { a: { '$class': 'xxx', '$': null } }
    (is.string(obj.$class) && is.nullOrUndefined(obj.$))) {
    debug('writeObject with a null');
    return this.writeNull();
  }
  this._assertType('writeObject / writeMap', 'object', obj);

  if (this._checkRef(obj)) {
    // if is ref, will write by _checkRef
    return this;
  }

  var className = '';
  var realObj;
  if (!obj.$class || !obj.$) {
    // : {a: 1}
    realObj = obj;
  } else {
    // : {$class: 'java.util.HashMap', $: {a: 1}}
    className = obj.$class === javaObject.DEFAULT_CLASSNAME.map || obj.$class === javaObject.DEFAULT_CLASSNAME.iMap ? '' : obj.$class;
    realObj = obj.$;
  }

  if (!className || this.isMap(className)) {
    return this._writeHashMap(realObj, className);
  }

  debug('writeObject with complex object, className: %s', className);
  var convertor = converts[obj.$class];
  obj = convertor ? convertor(obj) : obj;
  return this._writeObject(obj);
};

proto.writeMap = proto.writeObject;

proto._writeListBegin = function (length, type) {
  this.byteBuffer.putChar('V');

  if (type) {
    this.writeType(type);
  }

  this.byteBuffer.put(0x6c); // 'l'
  this.byteBuffer.putInt(length);
  return true;
};

/**
 * encode array
 *
 * v1.0
 * ```
 * list ::= V(x56) [type(writeType)] l(0x6c) long-length(putInt) values 'z'
 * ```
 *
 * v2.0
 * ```
 * list ::= V(x56) type(writeType) n(0x6e) short-length(put) values 'z'
 *      ::= V(x56) type(writeType) l(0x6c) long-length(putInt) values 'z'
 *      ::= v(x76) ref(writeInt) fix-length(writeInt) values
 * ```
 *
 * An ordered list, like an array.
 * The two list productions are a fixed-length list and a variable length list.
 * Both lists have a type.
 * The type string may be an arbitrary UTF-8 string understood by the service.
 *
 * fixed length list:
 * Hessian 2.0 allows a compact form of the list for successive lists of
 * the same type where the length is known beforehand.
 * The type and length are encoded by integers,
 * where the type is a reference to an earlier specified type.
 *
 * @param {Array} arr
 * @return {this}
 */

proto.writeArray = function (arr) {
  if (this._checkRef(arr)) {
    // if is ref, will write by _checkRef
    return this;
  }

  var isSimpleArray = is.array(arr);
  var className = ''; // empty string meaning: `javaObject.DEFAULT_CLASSNAME.list`
  var realArray = arr;
  if (!isSimpleArray) {
    if (is.object(arr) && is.nullOrUndefined(arr.$)) {
      return this.writeNull();
    }
    var isComplexArray = is.object(arr) &&
      is.string(arr.$class) && is.array(arr.$);
    if (!isComplexArray) {
      throw new TypeError('hessian writeArray input type invalid');
    }

    debug('write array with a complex array with className: %s', className);

    className = arr.$class === javaObject.DEFAULT_CLASSNAME.list ? '' : arr.$class;
    realArray = arr.$;
  }

  var hasEnd = this._writeListBegin(realArray.length, className);

  for (var i = 0; i < realArray.length; i++) {
    this.write(realArray[i]);
  }

  if (hasEnd) {
    this.byteBuffer.putChar('z');
  }
  return this;
};

proto.writeList = proto.writeArray;

/**
 * write any type
 * @param {Object|Number|String|Boolean|Array} val
 * : 1 => int
 * : 1.1 => double
 * :
 */
proto.write = function (val) {
  var type = typeof val;
  if (is.nullOrUndefined(val) || is.NaN(val) || is.function(val) || is.regExp(val)) {
    return this.writeNull();
  }
  switch (type) {
  case 'string':
    return this.writeString(val);
  case 'boolean':
    return this.writeBool(val);
  case 'number':
    // must check long value first
    if (is.long(val)) {
      debug('write number %d as long', val);
      return this.writeLong(val);
    }

    if (is.int(val)) {
      debug('write number %d as int', val);
      return this.writeInt(val);
    }

    // double
    debug('write number %d as double', val);
    return this.writeDouble(val);
  }

  if (is.long(val) || is.Long(val)) {
    debug('write long: high: %s, low: %s', val.high, val.low);
    return this.writeLong(val);
  }

  if (is.date(val)) {
    debug('write Date: %s', val);
    return this.writeDate(val);
  }

  if (is.buffer(val)) {
    debug('write Buffer with a length of %d', val.length);
    return this.writeBytes(val);
  }

  if (is.array(val)) {
    debug('write simple array with a length of %d', val.length);
    return this.writeArray(val);
  }

  // Object
  // {a: 1, b: 'test'}
  // {a: 0, b: null}
  if (!is.string(val.$class) || !utils.hasOwnProperty(val, '$')) {
    debug('write simple object');
    return this.writeObject(val);
  }

  if (is.array(val.$)) {
    debug('detect val.$ is array');
    return this.writeArray(val);
  }

  var method = utils.getSerializer(val.$class);
  debug('write detect %s use serializer %s', val.$class, method);

  // {$class: 'long', $: 123}
  if (method !== 'writeObject' && method !== 'writeArray') {
    if (is.nullOrUndefined(val.$)) {
      return this.writeNull();
    }
    return this[method](val.$);
  }

  // java.lang.Object
  if (utils.isJavaObject(val.$class)) {
    if (is.date(val.$) || !is.object(val.$)) {
      return this.write(val.$);
    }
  }

  // {$class: 'java.util.Map', $: {a: 1}}
  return this[method](val);
};

module.exports = Encoder;


================================================
FILE: lib/v2/decoder.js
================================================
'use strict';

var debug = require('util').debuglog('hessian:v2:decoder');
var util = require('util');
var is = require('is-type-of');
var DecoderV1 = require('../v1/decoder');
var utils = require('../utils');
var handle = require('../custom_handler').handle;
var JavaExceptionError = require('../object').JavaExceptionError;
var supportES6Map = require('../utils').supportES6Map;

var BYTE_CODES = {};

function Decoder(buf, classCache) {
  DecoderV1.call(this, buf);
  this.BYTE_CODES = BYTE_CODES;
  this.classes = []; // {name: classname, fields: []}
  this.types = [];

  this._isLastChunk = false;
  this.classCache = classCache;
}

util.inherits(Decoder, DecoderV1);

var proto = Decoder.prototype;

proto.clean = function () {
  DecoderV1.prototype.clean.call(this);
  this.types = [];
  this.classes = [];
  return this;
};

// readBool()
utils.addByteCodes(BYTE_CODES, [
  0x46,
  0x54,
], 'readBool');

// readNull()
utils.addByteCodes(BYTE_CODES, [
  0x4e,
], 'readNull');

/**
 * read a int from buffer
 *
 * v2.0
 * ```
 * int ::= I(x49) b3 b2 b1 b0
 *     ::= [x80-xbf]
 *     ::= [xc0-xcf] b0
 *     ::= [xd0-xd7] b1 b0
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##int
 * ```
 *
 * A 32-bit signed integer. An integer is represented by the octet x49 ('I')
 * followed by the 4 octets of the integer in big-endian order.
 * ```
 * value = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
 * ```
 *
 * single octet integers:
 * Integers between -16 and 47 can be encoded by a single octet in the range x80 to xbf.
 * ```
 * value = code - 0x90
 * ```
 *
 * two octet integers:
 * Integers between -2048 and 2047 can be encoded in two octets with the leading byte in the range xc0 to xcf.
 * ```
 * value = ((code - 0xc8) << 8) + b0;
 * ```
 *
 * three octet integers:
 * Integers between -262144 and 262143 can be encoded in three bytes with the leading byte in the range xd0 to xd7.
 * ```
 * value = ((code - 0xd4) << 16) + (b1 << 8) + b0;
 * ```
 *
 * @return {Number}
 * @api public
 */
proto.readInt = function () {
  var code = this.byteBuffer.get();
  // Compact int
  if (code >= 0x80 && code <= 0xbf) {
    // Integers between -16 and 47 can be encoded by a single octet in the range x80 to xbf.
    // value = code - 0x90
    return code - 0x90;
  }
  if (code >= 0xc0 && code <= 0xcf) {
    // Integers between -2048 and 2047 can be encoded in two octets with the leading byte in the range xc0 to xcf.
    // value = ((code - 0xc8) << 8) + b0;
    return ((code - 0xc8) << 8) + this.byteBuffer.get();
  }
  if (code >= 0xd0 && code <= 0xd7) {
    // Integers between -262144 and 262143 can be encoded in three bytes with the leading byte in the range xd0 to xd7.
    // value = ((code - 0xd4) << 16) + (b1 << 8) + b0;
    var b1 = this.byteBuffer.get();
    var b0 = this.byteBuffer.get();
    return ((code - 0xd4) << 16) + (b1 << 8) + b0;
  }
  if (code === 0x49) {
    return this.byteBuffer.getInt();
  }

  this.throwError('readInt', code);
};

utils.addByteCodes(BYTE_CODES, [
  [0x80, 0xbf],
  [0xc0, 0xcf],
  [0xd0, 0xd7],
  0x49
], 'readInt');

/**
 * read a long from buffer
 *
 * v2.0
 * ```
 * long ::= L(x4c) b7 b6 b5 b4 b3 b2 b1 b0
 *      ::= [xd8-xef]
 *      ::= [xf0-xff] b0
 *      ::= [x38-x3f] b1 b0
 *      ::= x4c b3 b2 b1 b0
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##long
 * ```
 * A 64-bit signed integer. An long is represented by the octet x4c ('L' )
 * followed by the 8-bytes of the integer in big-endian order.
 *
 * single octet longs:
 * Longs between -8 and 15 are represented by a single octet in the range xd8 to xef.
 * ```
 * value = (code - 0xe0)
 * ```
 *
 * two octet longs:
 * Longs between -2048 and 2047 are encoded in two octets with the leading byte in the range xf0 to xff.
 * ```
 * value = ((code - 0xf8) << 8) + b0
 * ```
 *
 * three octet longs:
 * Longs between -262144 and 262143 are encoded in three octets with the leading byte in the range x38 to x3f.
 * ```
 * value = ((code - 0x3c) << 16) + (b1 << 8) + b0
 * ```
 *
 * four octet longs:
 * Longs between which fit into 32-bits are encoded in five octets with the leading byte x59.
 * ```
 * value = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0
 * ```
 *
 * @return {Number}
 * @api public
 */
proto.readLong = function () {
  var code = this.byteBuffer.get();
  // Compact long
  if (code >= 0xd8 && code <= 0xef) {
    // Longs between -8 and 15 are represented by a single octet in the range xd8 to xef.
    // value = (code - 0xe0)
    return code - 0xe0;
  }
  if (code >= 0xf0 && code <= 0xff) {
    // Longs between -2048 and 2047 are encoded in two octets with the leading byte in the range xf0 to xff.
    // value = ((code - 0xf8) << 8) + b0
    return ((code - 0xf8) << 8) + this.byteBuffer.get();
  }
  if (code >= 0x38 && code <= 0x3f) {
    // Longs between -262144 and 262143 are encoded in three octets with the leading byte in the range x38 to x3f.
    // value = ((code - 0x3c) << 16) + (b1 << 8) + b0
    var b1 = this.byteBuffer.get();
    var b0 = this.byteBuffer.get();
    return ((code - 0x3c) << 16) + (b1 << 8) + b0;
  }
  if (code === 0x59) {
    // 32-bit integer cast to long
    return this.byteBuffer.getInt32();
  }
  if (code === 0x4c) {
    return utils.handleLong(this.byteBuffer.getLong());
  }

  this.throwError('readLong', code);
};

utils.addByteCodes(BYTE_CODES, [
  [0xd8, 0xef],
  [0xf0, 0xff],
  [0x38, 0x3f],
  0x59,
  0x4c
], 'readLong');

/**
 * read a double from buffer
 *
 * v2.0
 * ```
 * double ::= D(x44) b7 b6 b5 b4 b3 b2 b1 b0
 *        ::= x5b
 *        ::= x5c
 *        ::= x5d(byte) b0
 *        ::= x5e(short) b1 b0
 *        ::= x5f(float) b3 b2 b1 b0
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##double
 * ```
 * The double 0.0 can be represented by the octet x5b
 * The double 1.0 can be represented by the octet x5c
 *
 * double octet:
 * Doubles between -128.0 and 127.0 with no fractional component
 * can be represented in two octets by casting the byte value to a double.
 * ```
 * value = (double) b0
 * ```
 *
 * double short:
 * Doubles between -32768.0 (-0x8000) and 32767.0(0x8000 - 1) with no fractional component
 * can be represented in three octets by casting the short value to a double.
 * ```
 * value = (double) (256 * b1 + b0)
 * ```
 *
 * double float:
 * Doubles which are equivalent to their 32-bit float representation
 * can be represented as the 4-octet float and then cast to double.
 *
 * @return {Number}
 * @api public
 */
proto.readDouble = function () {
  var code = this.byteBuffer.get();
  if (code === 0x44) {
    return this.byteBuffer.getDouble();
  }

  // Compact double
  if (code === 0x5b) {
    return 0.0;
  }
  if (code === 0x5c) {
    return 1.0;
  }
  if (code === 0x5d) {
    return this.byteBuffer.getInt8();
  }
  if (code === 0x5e) {
    return this.byteBuffer.getInt16();
  }
  if (code === 0x5f) {
    return this.byteBuffer.getInt32() * 0.001;
  }
  this.throwError('readDouble', code);
};

utils.addByteCodes(BYTE_CODES, [
  0x44,
  0x5b,
  0x5c,
  0x5d,
  0x5e,
  0x5f
], 'readDouble');

/**
 * read a date from buffer,
 *
 * v2.0
 * ```
 * date ::= x4a(J) b7 b6 b5 b4 b3 b2 b1 b0 // Date represented by a 64-bit long of milliseconds since Jan 1 1970 00:00H, UTC.
 *      ::= x4b(K) b4 b3 b2 b1 b0          // The second form contains a 32-bit int of minutes since Jan 1 1970 00:00H, UTC.
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##date
 * ```
 *
 * @return {Date}
 * @api public
 */
proto.readDate = function () {
  var code = this.byteBuffer.get();
  if (code === 0x4a) {
    return new Date(utils.handleLong(this.byteBuffer.getLong()));
  }
  if (code === 0x4b) {
    return new Date(this.byteBuffer.getInt32() * 60000);
  }

  this.throwError('readDate', code);
};

utils.addByteCodes(BYTE_CODES, [
  0x4a,
  0x4b,
], 'readDate');

/**
 * read bytes from buffer
 *
 * v2.0
 * ```
 * binary ::= x41(A) b1 b0 <binary-data> binary
 *        ::= x42(B) b1 b0 <binary-data>
 *        ::= [x20-x2f] <binary-data>
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##binary
 * ```
 * The octet x42 ('B') encodes the final chunk and
 * x41 ('A') represents any non-final chunk.
 * Each chunk has a 16-bit length value.
 *
 * len = 256 * b1 + b0
 *
 * Binary data with length less than 15 may be encoded by a single octet length [x20-x2f].
 *
 * len = code - 0x20
 *
 * @return {Buffer}
 * @api public
 */
proto.readBytes = function () {
  var code = this.byteBuffer.get();
  if (code >= 0x20 && code <= 0x2f) {
    // short binary
    var len = code - 0x20;
    return this.byteBuffer.read(len);
  }

  var bufs = [];
  var length = 0;
  // get non-final trunk start with 'A'
  while (code === 0x41) {
    length = this.byteBuffer.getUInt16();
    bufs.push(this.byteBuffer.read(length));
    code = this.byteBuffer.get();
  }

  if (code === 0x42) {
    // get the last trunk start with 'B'
    length = this.byteBuffer.getUInt16();
    bufs.push(this.byteBuffer.read(length));
  } else if (code >= 0x20 && code <= 0x2f) {
    length = code - 0x20;
    bufs.push(this.byteBuffer.read(length));
  } else if (code >= 0x34 && code <= 0x37) {
    length = (code - 0x34) * 256 + this.byteBuffer.get();
    bufs.push(this.byteBuffer.read(length));
  } else {
    this.throwError('readBytes', code);
  }

  return Buffer.concat(bufs);
};

utils.addByteCodes(BYTE_CODES, [
  0x41,
  0x42,
  [0x34, 0x37],
  [0x20, 0x2f],
], 'readBytes');

/**
 * read a string from buffer
 *
 * The length is the number of characters, which may be different than the number of bytes.
 *
 * v2.0
 * ```
 * string ::= R(x52) b1 b0 <utf8-data> string  # non-final chunk
 *        ::= S(x53) b1 b0 <utf8-data>         # string of length 0-65535
 *        ::= [x00-x1f] <utf8-data>            # string of length 0-31
 *        ::= [x30-x33] b0 <utf8-data>         # string of length 0-1023
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##string
 * ```
 * A 16-bit unicode character string encoded in UTF-8. Strings are encoded in chunks.
 * x53 ('S') represents the final chunk and x52 ('R') represents any non-final chunk.
 * Each chunk has a 16-bit unsigned integer length value.
 *
 * The length is the number of 16-bit characters, which may be different than the number of bytes.
 * String chunks may not split surrogate pairs.
 *
 * short strings:
 * Strings with length less than 32 may be encoded with a single octet length [x00-x1f].
 * ```
 * [x00-x1f] <utf8-data>
 * ```
 *
 * @return {String}
 * @api public
 */
proto.readString = function () {
  var str = '';
  var code = this.byteBuffer.get();
  debug('readString() code: %s', code);

  var length;
  switch(code) {
    // 0-byte string
    case 0x00: case 0x01: case 0x02: case 0x03:
    case 0x04: case 0x05: case 0x06: case 0x07:
    case 0x08: case 0x09: case 0x0a: case 0x0b:
    case 0x0c: case 0x0d: case 0x0e: case 0x0f:

    case 0x10: case 0x11: case 0x12: case 0x13:
    case 0x14: case 0x15: case 0x16: case 0x17:
    case 0x18: case 0x19: case 0x1a: case 0x1b:
    case 0x1c: case 0x1d: case 0x1e: case 0x1f:
      this._isLastChunk = true;
      length = code - 0x00;
      debug('read short strings');
      str += this._readUTF8String(length);
      break;

    case 0x30: case 0x31: case 0x32: case 0x33:
      this._isLastChunk = true;
      length = (code - 0x30) * 256 + this.byteBuffer.get();
      str += this._readUTF8String(length);
      break;

    case 0x53:
      this._isLastChunk = true;
      // x53 ('S') represents the final chunk
      debug('read last trunk of string');
      str += this._readUTF8String();
      break;

    case 0x52:
      this._isLastChunk = false;
      // x52 ('R') represents any non-final chunk.
      str += this._readUTF8String();

      while (!this._isLastChunk) {
        str += this.readString();
      }
      break;

    default:
      this.throwError('readString', code);
      break;
  }
  return str;
};

utils.addByteCodes(BYTE_CODES, [
  0x52,
  0x53,
  [0x00, 0x1f],
  [0x30, 0x33],
], 'readString');

/**
 * @return {String} type string
 *
 * v2.0
 * ```
 * ref ::= (0x51) int(putInt)
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##ref
 * ```
 */
proto.readType = function () {
  var pos = this.byteBuffer.position();
  var code = this.byteBuffer.get(pos);

  var type = '';
  switch (code) {
    case 0x00: case 0x01: case 0x02: case 0x03:
    case 0x04: case 0x05: case 0x06: case 0x07:
    case 0x08: case 0x09: case 0x0a: case 0x0b:
    case 0x0c: case 0x0d: case 0x0e: case 0x0f:

    case 0x10: case 0x11: case 0x12: case 0x13:
    case 0x14: case 0x15: case 0x16: case 0x17:
    case 0x18: case 0x19: case 0x1a: case 0x1b:
    case 0x1c: case 0x1d: case 0x1e: case 0x1f:

    case 0x30: case 0x31: case 0x32: case 0x33:
    case 0x52: case 0x53:
      type = this.readString();
      this.types.push(type);
      debug('got type#%d: %s', this.types.length, type);
      break;

    default:
      var ref = this.readInt();
      type = this.types[ref];
      debug('got ref:%d type#%d: %s', ref, this.types.length, type);
      break;
  }
  return type;
};

// properties match with this$\d+ means inner properties
// it is useless for node and is circular structure
var INNER_CLASS_PROPERTY_REG = /^this\$\d+$/;
var INNER_CLASS_LABEL = '$$ignore_inner_property$$';

proto._readObjectDefinition = function () {
  var classname = this.readString();
  var fieldsLength = this.readInt();
  // compose cache key with class name and fields length
  // more safely
  var cachekey = classname + '##' + fieldsLength;

  // get class definition from cache
  var cacheClz = this.classCache && this.classCache.get(cachekey);
  if (cacheClz) {
    this.byteBuffer.skip(cacheClz.length);
    this.classes.push(cacheClz);
    return cacheClz;
  }

  var pos = this.byteBuffer.position();
  var fields = [];
  for (var i = 0; i < fieldsLength; i++) {
    var name = this.readString();
    if (INNER_CLASS_PROPERTY_REG.test(name)) {
      name = INNER_CLASS_LABEL;
    }
    fields.push(name);
  }
  debug('_readObjectDefinition got %s fields: %j', classname, fields);
  var clz = {
    name: classname,
    fields: fields,
    length: this.byteBuffer.position() - pos,
  };

  this.classes.push(clz);
  // set class definition into cache
  if (this.classCache) {
    this.classCache.set(cachekey, clz);
  }
  return clz;
};

/**
 * Read an object from buffer
 *
 * v2.0
 * ```
 * class-def  ::= 'C(x43)' string int string*
 *
 * object     ::= 'O(x4f)' int value*
 *            ::= [x60-x6f] value*
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##object
 * ```
 *
 * class definition:
 * Hessian 2.0 has a compact object form where the field names are only serialized once.
 * Following objects only need to serialize their values.
 *
 * The object definition includes a mandatory type string,
 * the number of fields, and the field names.
 * The object definition is stored in the object definition map
 * and will be referenced by object instances with an integer reference.
 *
 * object instantiation:
 * Hessian 2.0 has a compact object form where the field names are only serialized once.
 * Following objects only need to serialize their values.
 *
 * The object instantiation creates a new object based on a previous definition.
 * The integer value refers to the object definition.
 *
 * @param {Boolean} withType if need retain the type info
 * @return {Object}
 * @api public
 */
proto.readObject = function (withType) {
  var code = this.byteBuffer.get();
  var ref;
  if (code === 0x43) {
    // C(x43) type fields-length(writeInt) fields-names(writeString) o ref fields-values(write)
    this._readObjectDefinition();
    return this.readObject(withType);
  } else if (code === 0x4f) {
    ref = this.readInt();
  } else if (code >= 0x60 && code <= 0x6f) {
    ref = code - 0x60;
  } else {
    this.throwError('readObject', code);
  }

  var cls = this.classes[ref];
  debug('readObject %s, ref: %s', cls.name, ref);

  var result = {
    $class: cls.name,
    $: {}
  };
  this._addRef(result);

  var fields = cls.fields;
  for (var i = 0; i < fields.length; i++) {
    var name = fields[i];
    var value = this.read(withType);
    if (name !== INNER_CLASS_LABEL) {
      result.$[name] = value;
    }
  }

  if (/Exception$/.test(cls.name)) {
    result.$ = new JavaExceptionError(result, withType);
  }

  return handle(result, withType);
};

utils.addByteCodes(BYTE_CODES, [
  0x43,
  0x4f,
  [0x60, 0x6f],
], 'readObject');

/**
 * v2.0
 * ```
 * ref ::= Q(x51) int
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##ref
 * ```
 *
 * Each map or list is stored into an array as it is parsed.
 * ref selects one of the stored objects. The first object is numbered '0'.
 *
 * @return {Number}
 */
proto.readRefId = function (withType) {
  var code = this.byteBuffer.get();
  if (code === 0x51) {
    return this.readInt();
  }

  this.throwError('readRef', code);
};

utils.addByteCodes(BYTE_CODES, [
  0x51,
], 'readRef');

proto._readFixedLengthItems = function (len, list, withType) {
  for (var i = 0; i < len; i++) {
    list.push(this.read(withType));
  }
};

/**
 * read an array from buffer
 *
 * v2.0
 * ```
 * list ::= x55 type value* 'Z'   # variable-length list
 *      ::= 'V(x56)' type int value*   # fixed-length list
 *      ::= x57 value* 'Z'        # variable-length untyped list
 *      ::= x58 int value*        # fixed-length untyped list
 *      ::= [x70-77] type value*  # fixed-length typed list
 *      ::= [x78-7f] value*       # fixed-length untyped list
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##list
 * ```
 * An ordered list, like an array.
 * The two list productions are a fixed-length list and a variable length list.
 * Both lists have a type.
 * The type string may be an arbitrary UTF-8 string understood by the service.
 *
 * fixed length list:
 * Hessian 2.0 allows a compact form of the list for successive lists of
 * the same type where the length is known beforehand.
 * The type and length are encoded by integers,
 * where the type is a reference to an earlier specified type.
 *
 * @param {Boolean} withType if need retain the type info
 * @return {Array}
 * @api public
 */
proto.readArray = function (withType) {
  var code = this.byteBuffer.get();
  var type;
  var result;
  var list = [];
  var length = null;

  if (code === 0x56) {
    type = this.readType();
    length = this.readInt();
  } else if (code === 0x58) {
    length = this.readInt();
  } else if (code >= 0x78 && code <= 0x7f) {
    length = code - 0x78;
  } else if (code >= 0x70 && code <= 0x77) {
    type = this.readType();
    length = code - 0x70;
  }

  debug('readArray() type: %s, code: %s', type, code);

  if (type) {
    result = {
      $class: type,
      $: list
    };
  } else {
    result = list;
  }

  this._addRef(result);
  this._readFixedLengthItems(length, list, withType);

  if (!withType) {
    return list;
  }

  return result;
};

utils.addByteCodes(BYTE_CODES, [
  0x56,
  0x58,
  [0x70, 0x77],
  [0x78, 0x7f],
], 'readArray');

proto._readMap = function (map, withType) {
  var code = this.byteBuffer.get(this.byteBuffer.position());
  map = map || {};

  if (supportES6Map) {
    Object.defineProperty(map, '$map', {
      value: new Map(),
      enumerable: false,
    });
  }

  var k;
  var v;
  // Z(0x5a) list/map terminator
  while (code !== 0x5a) {
    k = this.read(withType);
    v = this.read(withType);
    var key = is.object(k) && k.name ? k.name : k;
    map[key] = v;
    if (supportES6Map) {
      map.$map.set(k, v);
    }

    code = this.byteBuffer.get(this.byteBuffer.position());
  }

  // got [Z], move forward 1 byte
  this.byteBuffer.skip(1);
  return map;
};

/**
 * A sparse array, untyped map (HashMap for Java)
 * hessian 2.0
 * @see http://hessian.caucho.com/doc/hessian-serialization.html#anchor27
 *
 * @return {Object}
 */
proto.readHashMap = function (withType) {
  // H: x48
  var code = this.byteBuffer.get();
  if (code !== 0x48) {
    this.throwError('readHashMap', code);
  }

  var result = {};
  this._addRef(result);
  this._readMap(result, withType);
  return handle({ $class: 'java.util.HashMap', $: result }, withType);
};

utils.addByteCodes(BYTE_CODES, [
  0x48
], 'readHashMap');

/**
 * read an map from buffer
 *
 * v2.0
 * ```
 * map        ::= M(x4d) [type] (value value)* Z
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##map
 * ```
 * Represents serialized maps and can represent objects.
 * The type element describes the type of the map.
 * The type may be empty, i.e. a zero length.
 * The parser is responsible for choosing a type if one is not specified.
 * For objects, unrecognized keys will be ignored.
 *
 * Each map is added to the reference list. Any time the parser expects a map,
 * it must also be able to support a null or a ref.
 *
 * The type is chosen by the service.
 *
 * @param {Boolean} withType if need retain the type info
 * @return {Object}
 * @api public
 */
proto.readMap = function (withType) {
  var code = this.byteBuffer.get();
  if (code !== 0x4d) {
    this.throwError('readMap', code);
  }

  var type = this.readType();
  debug('readMap() got type: %j, withType: %s', type, withType);
  if (!type) {
    var map = {};
    this._addRef(map);
    this._readMap(map);
    return handle({ $class: 'java.util.HashMap', $: map }, withType);
  }

  var result = {
    $class: type,
    $: {}
  };

  // obj maybe refers to itself
  this._addRef(result);
  this._readMap(result.$, withType);

  if (/Exception$/.test(type)) {
    result.$ = new JavaExceptionError(result);
  }

  return handle(result, withType);
};

utils.addByteCodes(BYTE_CODES, [
  0x4d
], 'readMap');

module.exports = Decoder;


================================================
FILE: lib/v2/encoder.js
================================================
'use strict';

var debug = require('util').debuglog('hessian:v2:encoder');
var is = require('is-type-of');
var util = require('util');
var Long = require('long');
var utility = require('utility');
var javaObject = require('../object');
var EncoderV1 = require('../v1/encoder');
var supportES6Map = require('../utils').supportES6Map;

function Encoder(options) {
  EncoderV1.call(this, options);

  this._classRefs = [];
  this._classRefFields = {};
  this._typeRefs = [];
}

util.inherits(Encoder, EncoderV1);

var proto = Encoder.prototype;

/**
 * clean the buf
 */
proto.reset = proto.clean = function () {
  EncoderV1.prototype.clean.call(this);
  this._classRefs = [];
  this._classRefFields = {};
  this._typeRefs = [];
  return this;
};

var INT_DIRECT_MIN = -0x10; // -16
var INT_DIRECT_MAX = 0x2f;  // 47
var INT_ZERO = 0x90;        // 144

var INT_BYTE_MIN = -0x800;  // -2048
var INT_BYTE_MAX = 0x7ff;   // 2047
var INT_BYTE_ZERO = 0xc8;   // 200

var INT_SHORT_MIN = -0x40000; // -262144
var INT_SHORT_MAX = 0x3ffff;  // 262143
var INT_SHORT_ZERO = 0xd4;    // 212

/**
 * encode int
 *
 * v1.0
 * ```
 * int ::= I(x49) b3 b2 b1 b0
 * ```
 *
 * v2.0
 * ```
 * int ::= I(x49) b3 b2 b1 b0
 *     ::= [x80-xbf]
 *     ::= [xc0-xcf] b0
 *     ::= [xd0-xd7] b1 b0
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##int
 * ```
 */
proto.writeInt = function (val) {
  this._assertType('writeInt', 'int32', val);
  if (INT_DIRECT_MIN <= val && val <= INT_DIRECT_MAX) {
    this.byteBuffer.put(val + INT_ZERO);
  } else if (INT_BYTE_MIN <= val && val <= INT_BYTE_MAX) {
    var b0 = val & 0xff;
    var code = (val >> 8) + INT_BYTE_ZERO;
    this.byteBuffer.put(code).put(b0);
  } else if (INT_SHORT_MIN <= val && val <= INT_SHORT_MAX) {
    var b1b0 = val & 0xffff;
    var code = (val >> 16) + INT_SHORT_ZERO;
    this.byteBuffer.put(code).putUInt16(b1b0);
  } else {
    this.byteBuffer
      .put(0x49)
      .putInt(val);
  }
  return this;
};

/**
 * encode long
 *
 * warning: we won't check if the long value is out of bound, be careful!
 *
 * v1.0
 * ```
 * long ::= L(x4c) b7 b6 b5 b4 b3 b2 b1 b0
 * ```
 *
 * v2.0
 * ```
 * long ::= L(x4c) b7 b6 b5 b4 b3 b2 b1 b0
 *      ::= [xd8-xef]
 *      ::= [xf0-xff] b0
 *      ::= [x38-x3f] b1 b0
 *      ::= x4c b3 b2 b1 b0
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##long
 * ```
 * A 64-bit signed integer. An long is represented by the octet x4c ('L' )
 * followed by the 8-bytes of the integer in big-endian order.
 *
 * single octet longs:
 * Longs between -8 and 15 are represented by a single octet in the range xd8 to xef.
 * ```
 * value = (code - 0xe0)
 * ```
 *
 * two octet longs:
 * Longs between -2048 and 2047 are encoded in two octets with the leading byte in the range xf0 to xff.
 * ```
 * value = ((code - 0xf8) << 8) + b0
 * ```
 *
 * three octet longs:
 * Longs between -262144 and 262143 are encoded in three octets with the leading byte in the range x38 to x3f.
 * ```
 * value = ((code - 0x3c) << 16) + (b1 << 8) + b0
 * ```
 *
 * four octet longs:
 * Longs between which fit into 32-bits are encoded in five octets with the leading byte x59.
 * ```
 * value = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0
 * ```
 */
proto.writeLong = function (val) {
  if (typeof val === 'string') {
    if (!utility.isSafeNumberString(val)) {
      val = Long.fromString(val);
    } else {
      val = Number(val);
    }
  } else if (Long.isLong(val) && (val.high === 0 || val.high === -1)) {
    val = val.toNumber();
  }

  if (typeof val === 'number') {
    if (val >= -8 && val <= 15) {
      this.byteBuffer.put(val + 0xe0);
    } else if (val >= -2048 && val <= 2047) {
      var b0 = val & 0xff;
      var code = (val >> 8) + 0xf8;
      this.byteBuffer.put(code).put(b0);
    } else if (val >= -262144 && val <= 262143) {
      var b1b0 = val & 0xffff;
      var code = (val >> 16) + 0x3c;
      this.byteBuffer.put(code).putUInt16(b1b0);
    } else if (val >= -0x80000000 && val <= 0x7fffffff) {
      // 32-bit integer cast to long
      this.byteBuffer.put(0x59).putInt32(val);
    } else {
      this.byteBuffer
        .put(0x4c) // 'L'
        .putLong(val);
    }
  } else {
    this.byteBuffer
      .put(0x4c) // 'L'
      .putLong(val);
  }
  return this;
};

/**
 * encode double
 *
 * v1.0
 * ```
 * double ::= D(x44) b7 b6 b5 b4 b3 b2 b1 b0
 * ```
 *
 * v2.0
 * ```
 * double ::= D(x44) b7 b6 b5 b4 b3 b2 b1 b0
 *        ::= x5b
 *        ::= x5c
 *        ::= x5d(byte) b0
 *        ::= x5e(short) b1 b0
 *        ::= x5f(float) b3 b2 b1 b0
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##double
 * ```
 * The double 0.0 can be represented by the octet x5b
 * The double 1.0 can be represented by the octet x5c
 *
 * double octet:
 * Doubles between -128.0 and 127.0 with no fractional component
 * can be represented in two octets by casting the byte value to a double.
 * ```
 * value = (double) b0
 * ```
 *
 * double short:
 * Doubles between -32768.0 (-0x8000) and 32767.0(0x8000 - 1) with no fractional component
 * can be represented in three octets by casting the short value to a double.
 * ```
 * value = (double) (256 * b1 + b0)
 * ```
 *
 * double float:
 * Doubles which are equivalent to their 32-bit float representation
 * can be represented as the 4-octet float and then cast to double.
 */
proto.writeDouble = function (val) {
  var intValue = parseInt(val);
  if (intValue === val) {
    if (val === 0) {
      this.byteBuffer.put(0x5b);
      return this;
    } else if (val === 1) {
      this.byteBuffer.put(0x5c);
      return this;
    } else if (-0x80 <= intValue && intValue < 0x80) {
      this.byteBuffer.put(0x5d).put(intValue);
      return this;
    } else if (-0x8000 <= intValue && intValue < 0x8000) {
      this.byteBuffer.put(0x5e).putInt16(intValue);
      return this;
    }
  }

  var mills = parseInt(val * 1000, 10);
  if (is.int32(mills) && mills * 0.001 === val) {
    // // 32-bit integer cast to double
    this.byteBuffer.put(0x5f).putInt32(mills);
    return this;
  }

  this.byteBuffer.put(0x44).putDouble(val);
  return this;
};

/**
 * Writes a date to the stream.
 *
 * date ::= x4a b7 b6 b5 b4 b3 b2 b1 b0
 *      ::= x4b b4 b3 b2 b1 b0
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##date
 *
 * @param time the date in milliseconds from the epoch in UTC
 */
proto.writeDate = function (milliEpoch) {
  if (milliEpoch instanceof Date) {
    milliEpoch = milliEpoch.getTime();
  }

  this._assertType('writeDate', 'number', milliEpoch);

  if ((milliEpoch % 60000) === 0) {
    // compact date
    var minutes = milliEpoch / 60000;
    if (minutes >= -0x80000000 && minutes <= 0x7fffffff) {
      this.byteBuffer
        .put(0x4b)
        .putInt32(minutes);
      return this;
    }
  }

  this.byteBuffer
    .putChar(0x4a)
    .putLong(milliEpoch);
  return this;
};

/**
 * encode buffer
 *
 * v1.0
 * ```
 * binary ::= [x62(b)] b1 b0 <binary-data> binary  # non-final chunk
 *        ::= x42(B) b1 b0 <binary-data>           # final chunk
 * ```
 *
 * v2.0
 * ```
 * binary ::= x41(A) b1 b0 <binary-data> binary    # non-final chunk
 *        ::= x42(B) b1 b0 <binary-data>           # final chunk
 *        ::= [x20-x2f] <binary-data>              # binary data of length 0-15
 *        ::= [x34-x37] b0 <binary-data>           # binary data of length 0-1023
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##binary
 * ```
 * The octet x42 ('B') encodes the final chunk and
 * x62 ('b') represents any non-final chunk.
 * Each chunk has a 16-bit length value.
 *
 * len = 256 * b1 + b0 # max length 32768(0x8000)
 *
 * Binary data with length less than 15 may be encoded by a single octet length [x20-x2f].
 *
 * len = code - 0x20
 */
proto.writeBytes = function (buf) {
  this._assertType('writeBytes', 'buffer', buf);
  if (buf.length <= 15) {
    this.byteBuffer.put(buf.length + 0x20).put(buf);
    return this;
  }

  var offset = 0;
  var left = buf.length - offset;
  while (left > 4093) {
    this.byteBuffer
      .put(0x41) // 'A'
      .putUInt16(4093)
      .put(buf.slice(offset, offset + 4093));

    offset += 4093;
    left = buf.length - offset;
  }

  if (left <= 15) {
    this.byteBuffer
      .put(left + 0x20)
      .put(buf.slice(offset));
  } else if (left <= 1023) {
    this.byteBuffer
      .put((left >> 8) + 0x34)
      .put(left)
      .put(buf.slice(offset));
  } else {
    this.byteBuffer
      .put(0x42) // 'B'
      .putUInt16(left)
      .put(buf.slice(offset));
  }
  return this;
};

/**
 * encode string
 *
 * v1.0
 * ```
 * string ::= s(x73) b1 b0 <utf8-data> string  # non-final chunk
 *        ::= S(x53) b1 b0 <utf8-data>         # string of length 0-65535
 * ```
 *
 * v2.0
 * ```
 * string ::= R(x52) b1 b0 <utf8-data> string  # non-final chunk
 *        ::= S(x53) b1 b0 <utf8-data>         # string of length 0-65535
 *        ::= [x00-x1f] <utf8-data>            # string of length 0-31
 *        ::= [x30-x33] b0 <utf8-data>         # string of length 0-1023
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##string
 * ```
 * A 16-bit unicode character string encoded in UTF-8. Strings are encoded in chunks.
 * x53 ('S') represents the final chunk and x52 ('R') represents any non-final chunk.
 * Each chunk has a 16-bit unsigned integer length value.
 *
 * The length is the number of 16-bit (0x8000) characters, which may be different than the number of bytes.
 * String chunks may not split surrogate pairs.
 *
 * short strings:
 * Strings with length less than 32 may be encoded with a single octet length [x00-x1f].
 * ```
 * [x00-x1f] <utf8-data>
 * ```
 */
proto.writeString = function (str) {
  this._assertType('writeString', 'string', str);

  var length = str.length;
  var strOffset = 0;
  var sublen;
  while (length > 0x8000) {
    sublen = 0x8000;
    // chunk can't end in high surrogate
    var tail = str.charCodeAt(strOffset + sublen - 1);
    if (0xd800 <= tail && tail <= 0xdbff) {
      debug('writeString got tail: 0x%s', tail.toString(16));
      sublen--;
    }

    this.byteBuffer
      .put(0x52)
      .putUInt16(sublen)
      .putRawString(str.slice(strOffset, strOffset + sublen));

    length -= sublen;
    strOffset += sublen;
    debug('writeString strOffset: %s, length: %s, sublen: %s', strOffset, length, sublen);
  }

  debug('writeString left length: %s', length);
  if (length <= 31) {
    // short strings
    this.byteBuffer.put(length);
  } else if (length <= 1023) {
    this.byteBuffer
      .put(48 + (length >> 8))
      .put(length);
  } else {
    this.byteBuffer
      .putChar('S')
      .put(length >> 8)
      .put(length);
  }

  this.byteBuffer.putRawString(str.slice(strOffset));
  return this;
};

var _typecache = {};

/**
 * encode type
 *
 * v1.0
 * ```
 * type ::= 0x74(t) type-string-length(putUInt16) type-string(putRawString)
 * ```
 *
 * v2.0
 * ```
 * type ::= type-string(putRawString)
 *      ::= type-ref(writeInt)
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##type
 * ```
 *
 * A map or list includes a type attribute indicating the type name of the map or
 * list for object-oriented languages.
 *
 * Each type is added to the type map for future reference.
 *
 * type references:
 * Repeated type strings MAY use the type map to refer to a previously used type.
 * The type reference is zero-based over all the types encountered during parsing.
 */
proto.writeType = function (type) {
  type = type || '';
  if (!type) {
    return;
  }

  var ref = this._typeRefs.indexOf(type);
  if (ref >= 0) {
    this.writeInt(ref);
  } else {
    this._typeRefs.push(type);
    if (_typecache[type]) {
      this.byteBuffer.put(_typecache[type]);
    } else {
      var start = this.byteBuffer.position();
      this.writeString(type);
      var end = this.byteBuffer.position();
      _typecache[type] = this.byteBuffer.copy(start, end);
    }
  }
  return this;
};

/**
 * encode ref
 *
 * v1.0
 * ```
 * ref ::= R(0x52) int(putInt)
 * ```
 *
 * v2.0
 * ```
 * ref ::= (0x51) int(putInt)
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##ref
 * ```
 *
 * Each map or list is stored into an array as it is parsed.
 * ref selects one of the stored objects. The first object is numbered '0'.
 */
proto.writeRef = function (value) {
  this.byteBuffer.put(0x51);
  this.writeInt(value);
  return this;
};

var _classcache = {};

/**
 *
 * v2.0
 * ```
 * class-def  ::= 'C' string int string*
 * object     ::= 'O' int value*
 *            ::= [x60-x6f] value*
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##object
 * ```
 */
proto._writeObjectBegin = function (type, fields) {
  debug('_writeObjectBegin() type: %s', type);
  var ref = this._classRefs.indexOf(type);
  if (ref >= 0) {
    if (ref <= 15) {
      this.byteBuffer.put(0x60 + ref);
    } else {
      // O(x4f) type-string-length(writeInt) type-string(putRawString)
      this.byteBuffer.putChar('O');
      this.writeInt(ref);
    }
    return ref;
  } else {
    // class definition
    this.byteBuffer.putChar('C');
    this._classRefs.push(type);
    this._classRefFields[type] = fields;
    if (_classcache[type]) {
      this.byteBuffer.put(_classcache[type]);
    } else {
      var start = this.byteBuffer.position();
      this.writeString(type);
      var end = this.byteBuffer.position();
      _classcache[type] = this.byteBuffer.copy(start, end);
    }
    return -1;
  }
};

// class definition:
//
// The object definition includes a mandatory type string, the number of fields,
// and the field names. The object definition is stored in the object definition
// map and will be referenced by object instances with an integer reference.
//
// object instantiation:
//
// The object instantiation creates a new object based on a previous definition.
// The integer value refers to the object definition.
//
// type format: length(writeInt) stringbytes(putRawString)
proto._writeObject = function (obj) {
  var className = obj.$class;
  var realObj = obj.$;
  // hessian 2.0
  // field defined sort must same as java Class defined
  var keys = Object.keys(realObj);
  var ref = this._writeObjectBegin(className, keys);
  if (ref === -1) {
    // writeDefinition20
    // out.writeClassFieldLength(_fields.length);
    this.writeInt(keys.length);
    // write field names
    for (var i = 0; i < keys.length; i++) {
      var key = keys[i];
      this.writeString(key);
    }
    this._writeObjectBegin(className);
  }
  keys = this._classRefFields[className];
  // writeInstance
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    this.write(realObj[key]);
  }

  return this;
};

/**
 * A sparse array
 *
 * ```
 * untyped map    ::= 'H' (value value)* 'Z'
 *
 * @see http://hessian.caucho.com/doc/hessian-serialization.html##map
 * ```
 *
 * @param {Object} obj simple obj
 * @return {this}
 */
proto._writeHashMap = function (obj, type) {
  debug('_writeHashMap() %j, fields: %j', obj);

  if (type) {
    this.byteBuffer.put(0x4d);
    this.writeType(type);
  } else {
    this.byteBuffer.put(0x48); // H
  }

  if (supportES6Map && obj instanceof Map) {
    obj.forEach(function (value, key) {
      this.write(key);
      this.write(value);
    }, this);
  } else {
    // hash map must sort keys
    var keys = Object.keys(obj).sort();
    for (var i = 0; i < keys.length; i++) {
      var k = keys[i];
      this.writeString(k);
      this.write(obj[k]);
    }
  }
  this.byteBuffer.putChar('Z');
  return this;
};

// Writes the list header to the stream.
//
// list ::= x55 type value* 'Z'   # variable-length list
//      ::= 'V' type int value*   # fixed-length list
//      ::= x57 value* 'Z'        # variable-length untyped list
//      ::= x58 int value*        # fixed-length untyped list
//      ::= [x70-77] type value*  # fixed-length typed list
//      ::= [x78-7f] value*       # fixed-length untyped list
//
// @see http://hessian.caucho.com/doc/hessian-serialization.html##list
proto._writeListBegin = function (length, type) {
  if (length < 0) {
    if (!type) {
      this.byteBuffer.put(0x57);
    } else {
      this.byteBuffer.put(0x55);
      this.writeType(type);
    }
    return true;
  } else if (length <= 7) {
    if (!type) {
      this.byteBuffer.put(120 + length);
    } else {
      this.byteBuffer.put(112 + length);
      this.writeType(type);
    }
    return false;
  } else {
    if (!type) {
      this.byteBuffer.put(0x58);
    } else {
      this.byteBuffer.put(0x56);
      this.writeType(type);
    }
    this.writeInt(length);
    return false;
  }
};

module.exports = Encoder;


================================================
FILE: lib/v2_optimize/decoder.js
================================================
'use strict';

var util = require('util');
var DecoderV2 = require('../v2/decoder');
var DecoderV1 = require('../v1/decoder');

function Decoder(buf, classRefs) {
  DecoderV2.call(this, buf);
  this.classes = classRefs; // using passed in ref array
}

util.inherits(Decoder, DecoderV2);

var proto = Decoder.prototype;

proto.clean = function () {
  DecoderV1.prototype.clean.call(this); // can not clean `this.classes`
  this.types = [];
  return this;
};

module.exports = Decoder;


================================================
FILE: lib/v2_optimize/encoder.js
================================================
'use strict';

var util = require('util');
var EncoderV2 = require('../v2/encoder');
var EncoderV1 = require('../v1/encoder');

function Encoder(options) {
  EncoderV2.call(this, options);

  this._classRefs = options.classRefs;
  this._classRefFields = options.classRefFields;
  this._typeRefs = [];
}

util.inherits(Encoder, EncoderV2);

var proto = Encoder.prototype;

/**
 * clean the buf
 */
proto.reset = proto.clean = function () {
  EncoderV1.prototype.clean.call(this);
  this._typeRefs = [];
  return this;
};

module.exports = Encoder;


================================================
FILE: package.json
================================================
{
  "name": "hessian.js",
  "version": "2.11.0",
  "description": "Hessian Serialization written by pure JavaScript, support all kind of types in Java.",
  "main": "index.js",
  "files": [
    "index.js",
    "lib"
  ],
  "scripts": {
    "test": "egg-bin test",
    "test-cov": "egg-bin cov",
    "lint": "jshint .",
    "ci": "npm run lint && npm run test-cov",
    "benchmark": "node benchmark/encode.js && node benchmark/decode.js",
    "contributor": "git-contributor"
  },
  "repository": {
    "type": "git",
    "url": "git://github.com/node-modules/hessian.js.git"
  },
  "keywords": [
    "hessian",
    "protocol",
    "java",
    "rpc",
    "serialization"
  ],
  "author": "dead_horse <dead_horse@qq.com>",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/node-modules/hessian.js/issues",
    "email": "dead_horse@qq.com"
  },
  "homepage": "https://github.com/node-modules/hessian.js",
  "dependencies": {
    "byte": "^2.0.0",
    "is-type-of": "^1.2.1",
    "long": "^4.0.0",
    "utility": "^1.16.1"
  },
  "devDependencies": {
    "beautify-benchmark": "^0.2.4",
    "benchmark": "^2.1.4",
    "egg-bin": "^6.3.0",
    "git-contributor": "^2.0.0",
    "js-to-java": "^2.6.1",
    "jshint": "^2.10.2"
  },
  "engines": {
    "node": ">= 0.12.0"
  }
}


================================================
FILE: test/array.test.js
================================================
'use strict';

const assert = require('assert');
const hessian = require('..');

describe('array.test.js', function () {
  it('should write null v1', function () {
    var b = hessian.encode([
      {
        $class: '[java.lang.Integer',
        $: null
      },
      {
        $class: '[java.lang.Integer',
        $: [1]
      }
    ]);
    var a = hessian.decode(b);
    assert.deepEqual(a, [null, [1]]);
  });

  it('should write undefined v1', function () {
    var b = hessian.encode([
      {
        $class: '[java.lang.Integer',
        $: undefined
      },
      {
        $class: '[java.lang.Integer',
        $: [1]
      }
    ]);
    var a = hessian.decode(b);
    assert.deepEqual(a, [null, [1]]);
  });

  it('should write null v2', function () {
    var b = hessian.encode([
      {
        $class: '[java.lang.Integer',
        $: null
      },
      {
        $class: '[java.lang.Integer',
        $: [1]
      }
    ], '2.0');
    var a = hessian.decode(b, '2.0');
    assert.deepEqual(a, [null, [1]]);
  });

  it('should write undefined v2', function () {
    var b = hessian.encode([
      {
        $class: '[java.lang.Integer',
        $: undefined
      },
      {
        $class: '[java.lang.Integer',
        $: [1]
      }
    ], '2.0');
    var a = hessian.decode(b, '2.0');
    assert.deepEqual(a, [null, [1]]);
  });
});


================================================
FILE: test/binary.test.js
================================================
'use strict';

const assert = require('assert');
const hessian = require('..');
const utils = require('./utils');

describe('binary.test.js', function () {
  it('should read "foo" binary', function () {
    hessian.decode(Buffer.concat([new Buffer(['B'.charCodeAt(0), 0x00, 0x03]), new Buffer('foo')]));
  });

  it('should write "foo"', function () {
    assert.deepEqual(
      hessian.encode(new Buffer('foo')),
      Buffer.concat([new Buffer(['B'.charCodeAt(0), 0x00, 0x03]), new Buffer('foo')])
    );
  });

  it('should read and write empty binary', function () {
    var empty = hessian.decode(new Buffer(['B'.charCodeAt(0), 0x00, 0x00]));
    assert(Buffer.isBuffer(empty));
    assert(empty.length === 0);

    assert.deepEqual(
      hessian.encode(new Buffer('')),
      new Buffer(['B'.charCodeAt(0), 0x00, 0x00])
    );
  });

  it('should write and read as java impl', function () {
    var bytes = new Buffer(65535);
    bytes.fill(0x41);
    var buf = hessian.encode(bytes, '1.0');
    assert(buf.length === utils.bytes('v1/bytes/65535').length);
    assert.deepEqual(buf, utils.bytes('v1/bytes/65535'));
    assert.deepEqual(hessian.decode(utils.bytes('v1/bytes/65535'), '1.0'), bytes);

    var bytes = new Buffer(32768);
    bytes.fill(0x41);
    var buf = hessian.encode(bytes, '1.0');
    assert(buf.length === utils.bytes('v1/bytes/32768').length);
    assert.deepEqual(buf, utils.bytes('v1/bytes/32768'));
    assert.deepEqual(hessian.decode(utils.bytes('v1/bytes/32768'), '1.0'), bytes);

    var bytes = new Buffer(32769);
    bytes.fill(0x41);
    var buf = hessian.encode(bytes, '1.0');
    assert(buf.length === utils.bytes('v1/bytes/32769').length);
    assert.deepEqual(buf, utils.bytes('v1/bytes/32769'));
    assert.deepEqual(hessian.decode(utils.bytes('v1/bytes/32769'), '1.0'), bytes);

    var bytes = new Buffer(32767);
    bytes.fill(0x41);
    var buf = hessian.encode(bytes, '1.0');
    assert(buf.length === utils.bytes('v1/bytes/32767').length);
    assert.deepEqual(buf, utils.bytes('v1/bytes/32767'));
    assert.deepEqual(hessian.decode(utils.bytes('v1/bytes/32767'), '1.0'), bytes);

    var bytes = new Buffer(32769);
    bytes.fill(0x41);
    var buf = hessian.encode(bytes, '1.0');
    assert(buf.length === utils.bytes('v1/bytes/32769').length);
    assert.deepEqual(buf, utils.bytes('v1/bytes/32769'));
    assert.deepEqual(hessian.decode(utils.bytes('v1/bytes/32769'), '1.0'), bytes);

    var bytes = new Buffer(42769);
    bytes.fill(0x41);
    var buf = hessian.encode(bytes, '1.0');
    assert(buf.length === utils.bytes('v1/bytes/42769').length);
    assert.deepEqual(buf, utils.bytes('v1/bytes/42769'));
    assert.deepEqual(hessian.decode(utils.bytes('v1/bytes/42769'), '1.0'), bytes);

    var bytes = new Buffer(82769);
    bytes.fill(0x41);
    var buf = hessian.encode(bytes, '1.0');
    assert(buf.length === utils.bytes('v1/bytes/82769').length);
    assert.deepEqual(buf, utils.bytes('v1/bytes/82769'));
    assert.deepEqual(hessian.decode(utils.bytes('v1/bytes/82769'), '1.0'), bytes);
  });

  describe('v2.0', function () {
    it('should read zero length binary data', function () {
      var buf = hessian.decode(new Buffer([0x20]), '2.0');
      assert(buf.length === 0);
      assert.deepEqual(buf, new Buffer(0));
    });

    it('should read short datas', function () {
      var decoder = new hessian.DecoderV2(new Buffer([0x20, 0x23, 0x23, 0x02, 0x03, 0x20]));
      var buf = decoder.read();
      assert(buf.length === 0);
      assert.deepEqual(buf, new Buffer(0));

      buf = decoder.read();
      assert(buf.length === 3);
      assert.deepEqual(buf, new Buffer([0x23, 2, 3]));

      buf = decoder.read();
      assert(buf.length === 0);
      assert.deepEqual(buf, new Buffer(0));
      decoder.clean();
    });

    it('should read max length short datas', function () {
      var input = new Buffer(16);
      input.fill(0x2f);
      input[0] = 0x2f;
      var buf = hessian.decode(input, '2.0');
      assert(buf.length === 15);
      var output = new Buffer(15);
      output.fill(0x2f);
      assert.deepEqual(buf, output);

      var buf15 = new Buffer(15);
      buf15.fill(0x41);
      assert.deepEqual(hessian.encode(buf15, '2.0'), utils.bytes('v2/bytes/15'));
      assert.deepEqual(hessian.decode(utils.bytes('v2/bytes/15'), '2.0'), buf15);

      var buf16 = new Buffer(16);
      buf16.fill(0x41);
      assert.deepEqual(hessian.encode(buf16, '2.0'), utils.bytes('v2/bytes/16'));
      assert.deepEqual(hessian.decode(utils.bytes('v2/bytes/16'), '2.0'), buf16);
    });

    it('should read long binary', function () {
      var buf = hessian.encode(new Buffer(65535), '2.0');
      assert(buf[0] === 0x41);
      hessian.decode(buf, '2.0');

      buf = hessian.encode(new Buffer(65536), '2.0');
      hessian.decode(buf, '2.0');

      buf = hessian.encode(new Buffer(65535 * 2 - 10), '2.0');
      hessian.decode(buf, '2.0');
    });

    it('should write short binary', function () {
      assert.deepEqual(hessian.encode(new Buffer(''), '2.0'), new Buffer([0x20]));
    });

    it('should write and read as java impl', function () {
      var bytes = new Buffer(65535);
      bytes.fill(0x41);
      var buf = hessian.encode(bytes, '2.0');
      assert(buf.length === utils.bytes('v2/bytes/65535').length);
      assert.deepEqual(buf, utils.bytes('v2/bytes/65535'));
      assert.deepEqual(hessian.decode(utils.bytes('v2/bytes/65535'), '2.0'), bytes);

      var bytes = new Buffer(32768);
      bytes.fill(0x41);
      var buf = hessian.encode(bytes, '2.0');
      assert(buf.length === utils.bytes('v2/bytes/32768').length);
      assert.deepEqual(buf, utils.bytes('v2/bytes/32768'));
      assert.deepEqual(hessian.decode(utils.bytes('v2/bytes/32768'), '2.0'), bytes);

      var bytes = new Buffer(32769);
      bytes.fill(0x41);
      var buf = hessian.encode(bytes, '2.0');
      assert(buf.length === utils.bytes('v2/bytes/32769').length);
      assert.deepEqual(buf, utils.bytes('v2/bytes/32769'));
      assert.deepEqual(hessian.decode(utils.bytes('v2/bytes/32769'), '2.0'), bytes);

      var bytes = new Buffer(32767);
      bytes.fill(0x41);
      var buf = hessian.encode(bytes, '2.0');
      assert(buf.length === utils.bytes('v2/bytes/32767').length);
      assert.deepEqual(buf, utils.bytes('v2/bytes/32767'));
      assert.deepEqual(hessian.decode(utils.bytes('v2/bytes/32767'), '2.0'), bytes);

      var bytes = new Buffer(32769);
      bytes.fill(0x41);
      var buf = hessian.encode(bytes, '2.0');
      assert(buf.length === utils.bytes('v2/bytes/32769').length);
      assert.deepEqual(buf, utils.bytes('v2/bytes/32769'));
      assert.deepEqual(hessian.decode(utils.bytes('v2/bytes/32769'), '2.0'), bytes);

      var bytes = new Buffer(42769);
      bytes.fill(0x41);
      var buf = hessian.encode(bytes, '2.0');
      assert(buf.length === utils.bytes('v2/bytes/42769').length);
      assert.deepEqual(buf, utils.bytes('v2/bytes/42769'));
      assert.deepEqual(hessian.decode(utils.bytes('v2/bytes/42769'), '2.0'), bytes);

      var bytes = new Buffer(82769);
      bytes.fill(0x41);
      var buf = hessian.encode(bytes, '2.0');
      assert(buf.length === utils.bytes('v2/bytes/82769').length);
      assert.deepEqual(buf, utils.bytes('v2/bytes/82769'));
      assert.deepEqual(hessian.decode(utils.bytes('v2/bytes/82769'), '2.0'), bytes);
    });
  });
});


================================================
FILE: test/boolean.test.js
================================================
'use strict';

const assert = require('assert');
const hessian = require('..');

describe('boolean.test.js', function () {
  it('should read true and false', function () {
    assert(hessian.decode(new Buffer('T')) === true);
    assert(hessian.decode(new Buffer('F')) === false);
  });

  it('should write true and false', function () {
    assert.deepEqual(hessian.encode(true), new Buffer('T'));
    assert.deepEqual(hessian.encode(false), new Buffer('F'));
  });

  describe('v2.0', function () {
    it('should read write as 1.0', function () {
      assert.deepEqual(hessian.encode(true, '2.0'), new Buffer('T'));
      assert.deepEqual(hessian.encode(false, '2.0'), new Buffer('F'));
      assert(hessian.decode(new Buffer('T'), '2.0') === true);
      assert(hessian.decode(new Buffer('F'), '2.0') === false);
    });
  });
});


================================================
FILE: test/convert.test.js
================================================
'use strict';

const assert = require('assert');
const java = require('js-to-java');
const hessian = require('..');

describe('test/convert.test.js', function() {
  [
    '1.0', '2.0'
  ].forEach(function(version) {
    describe(version, function() {
      it('should convert java.util.Locale to com.caucho.hessian.io.LocaleHandle', function() {
        var buf1 = hessian.encode(java.Locale('zh_CN'), version);
        var buf2 = hessian.encode({
          $class: 'java.util.Locale',
          $: 'zh_CN',
        }, version);
        assert.deepEqual(buf1, buf2);
      });
    });
  });
});


================================================
FILE: test/custom_handler.test.js
================================================
'use strict';

const assert = require('assert');
const hessian = require('..');
const supportES6Map = require('../lib/utils').supportES6Map;

describe('utils.test.js', function () {
  describe('v1.0', function () {
  	it('should decode with custom handler', function () {
  		hessian.registerDecodeHandler('java.math.BigDecimal', function (result) {
        return {
          $class: result.$class,
          $: result.$.value,
        };
  		});
      var o = { $class: 'java.math.BigDecimal', $: { value: '100.06' } };
      var buf = hessian.encode(o, '1.0');
      var output = hessian.decode(buf, '1.0');
      assert(output === '100.06');
      hessian.deregisterDecodeHandler('java.math.BigDecimal');
      output = hessian.decode(buf, '1.0');
      assert.deepEqual(output, { value: '100.06' });
  	});

  	if (!supportES6Map) {
  		return;
  	}

  	it('should decode map with custom handler', function () {
  		hessian.registerDecodeHandler('java.util.HashMap', function (result) {
        return {
          $class: result.$class,
          $: result.$.$map,
        };
  		});
      var map = new Map();
      map.set(1, 'fee');
      map.set(2, 'fie');
      map.set(3, 'foe');
      var buf = hessian.encode({
        $class: 'java.util.HashMap',
        $: map
      }, '1.0');
      var output = hessian.decode(buf, '1.0');
      assert(output instanceof Map);
      assert(output.get(1) === 'fee');
      assert(output.get(2) === 'fie');
      assert(output.get(3) === 'foe');
      hessian.deregisterDecodeHandler('java.util.HashMap');
  	});
  });

  describe('v2.0', function () {
  	it('should decode with custom handler', function () {
  		hessian.registerDecodeHandler('java.math.BigDecimal', function (result) {
        return {
          $class: result.$class,
          $: result.$.value,
        };
  		});
      var o = { $class: 'java.math.BigDecimal', $: { value: '100.06' } };
      var buf = hessian.encode(o, '2.0');
      var output = hessian.decode(buf, '2.0');
      assert(output === '100.06');
      hessian.deregisterDecodeHandler('java.math.BigDecimal');
      output = hessian.decode(buf, '2.0');
      assert.deepEqual(output, { value: '100.06' });
  	});

    it('should decode with custom handler if has ref', function () {
  		hessian.registerDecodeHandler('java.math.BigDecimal', function (result) {
        return {
          $class: result.$class,
          $: result.$.value,
        };
  		});
      var o = { $class: 'java.math.BigDecimal', $: { value: '100.06' } };
      var map = new Map();
      map.set(1, o);
      map.set(2, o);
      var buf = hessian.encode({
        $class: 'java.util.HashMap',
        $: map
      }, '2.0');
      var output = hessian.decode(buf, '2.0');
      /**
       * fix problem like ref object reuse
       */
      assert(output[1] === '100.06');
      assert(output[2] === '100.06');
      hessian.deregisterDecodeHandler('java.math.BigDecimal');
      output = hessian.decode(buf, '2.0');
      assert.deepEqual(output, {'1': { value: '100.06'}, '2': { value: '100.06' }});
  	});

    it('should decode with custom handler if has ref and has circular ref', function () {
      var circularObj = { value: '100.06' };
      circularObj.ref = circularObj;
  		hessian.registerDecodeHandler('java.test.circular', function (result) {
        // must modify result in place to avoid circular problem
        return {
          $class: result.$class,
          $: result.$,
        };
  		});
      var o = { $class: 'java.test.circular', $: circularObj };
      var map = new Map();
      map.set(1, o);
      map.set(2, o);
      var buf = hessian.encode({
        $class: 'java.util.HashMap',
        $: map
      }, '2.0');
      var output = hessian.decode(buf, '2.0');
      /**
       * fix problem like ref object reuse
       */
      assert(output[1].value === '100.06');
      assert(output[2].value === '100.06');
      assert(output[1].ref.ref.ref.ref.value === '100.06');
      hessian.deregisterDecodeHandler('java.test.circular');
  	});

  	if (!supportES6Map) {
  		return;
  	}

  	it('should decode map with custom handler', function () {
  		hessian.registerDecodeHandler('java.util.HashMap', function (result) {
        return {
          $class: result.$class,
          $: result.$.$map,
        };
  		});
      var map = new Map();
      map.set(1, 'fee');
      map.set(2, 'fie');
      map.set(3, 'foe');
      var buf = hessian.encode({
        $class: 'java.util.HashMap',
        $: map
      }, '2.0');
      var output = hessian.decode(buf, '2.0');
      assert(output instanceof Map);
      assert(output.get(1) === 'fee');
      assert(output.get(2) === 'fie');
      assert(output.get(3) === 'foe');
      hessian.deregisterDecodeHandler('java.util.HashMap');
  	});
  });
});


================================================
FILE: test/date.test.js
================================================
'use strict';

const assert = require('assert');
const hessian = require('..');
const utils = require('./utils');

describe('date.test.js', function () {
  var dateBuffer = new Buffer(['d'.charCodeAt(0), 0x00, 0x00, 0x00, 0xd0, 0x4b, 0x92, 0x84, 0xb8]);

  it('should read date 2:51:31 May 8, 1998', function () {
    var d = hessian.decode(dateBuffer);
    assert(Object.prototype.toString.call(d) === '[object Date]');
    assert(d.getFullYear() === 1998);
    assert(d.getTime() === 894621091000);
    assert(d.toUTCString() === 'Fri, 08 May 1998 09:51:31 GMT');
    assert(d.toISOString() === '1998-05-08T09:51:31.000Z');
  });

  it('should write date 2:51:31 May 8, 1998', function () {
    assert.deepEqual(hessian.encode(new Date(894621091000)), dateBuffer);
  });

  it('should write date 0 and read', function () {
    assert.deepEqual(
      hessian.encode(new Date(0)),
      new Buffer(['d'.charCodeAt(0), 0, 0, 0, 0, 0, 0, 0, 0])
    );
  });

  it('should read date 09:51:31 May 8, 1998 UTC', function () {
    var d = hessian.decode(utils.bytes('v1/date/894621091000'), '1.0');
    assert(Object.prototype.toString.call(d) === '[object Date]');
    assert(d.getFullYear() === 1998);
    assert(d.getTime() === 894621091000);
    assert(d.toUTCString() === 'Fri, 08 May 1998 09:51:31 GMT');
    assert(d.toISOString() === '1998-05-08T09:51:31.000Z');
  });

  it('should read date 09:51:00 May 8, 1998 UTC', function () {
    var d = hessian.decode(utils.bytes('v1/date/894621060000'), '1.0');
    assert(Object.prototype.toString.call(d) === '[object Date]');
    assert(d.getFullYear() === 1998);
    assert(d.getTime() === 894621060000);
    assert(d.toUTCString() === 'Fri, 08 May 1998 09:51:00 GMT');
    assert(d.toISOString() === '1998-05-08T09:51:00.000Z');
  });

  it('should write date', function () {
    var now = new Date(1398280514000);
    assert.deepEqual(hessian.encode(now, '1.0'), utils.bytes('v1/date/now'));
    // read it
    assert.deepEqual(hessian.decode(utils.bytes('v1/date/now'), '1.0'), now);
  });

  describe('hessian 2.0', function () {
    it('should read date 09:51:31 May 8, 1998 UTC', function () {
      var d = hessian.decode(utils.bytes('v2/date/894621091000'), '2.0');
      assert(Object.prototype.toString.call(d) === '[object Date]');
      assert(d.getFullYear() === 1998);
      assert(d.getTime() === 894621091000);
      assert(d.toUTCString() === 'Fri, 08 May 1998 09:51:31 GMT');
      assert(d.toISOString() === '1998-05-08T09:51:31.000Z');
    });

    it('should read Compact: date in minutes, 09:51:00 May 8, 1998 UTC', function () {
      var d = hessian.decode(utils.bytes('v2/date/894621060000'), '2.0');
      assert(Object.prototype.toString.call(d) === '[object Date]');
      assert(d.getFullYear() === 1998);
      assert(d.getTime() === 894621060000);
      assert(d.toUTCString() === 'Fri, 08 May 1998 09:51:00 GMT');
      assert(d.toISOString() === '1998-05-08T09:51:00.000Z');
    });

    it('should write and read date, Thu, 23 Jan 6053 02:08:00 GMT', function () {
      // Maximum of 32-bit integer
      var overflow32BitInt = Math.pow(2, 31);
      var milliseconds = overflow32BitInt * 60000;
      var date = new Date();
      date.setTime(milliseconds);

      var bytes = utils.bytes('v2/date/' + milliseconds.toString());

      assert.deepEqual(hessian.encode(date, '2.0'), bytes);
      assert.deepEqual(hessian.decode(bytes, '2.0'), date);
    });

    it('should write and read date, Wed, 08 Dec -2114 21:53:00 GMT (2115 B.C.)', function () {
      // Minimum of 32-bit integer
      var overflow32BitInt = -1 * (Math.pow(2, 31) + 1);
      var milliseconds = overflow32BitInt * 60000;
      var date = new Date();
      date.setTime(milliseconds);

      var bytes = utils.bytes('v2/date/' + milliseconds.toString());

      assert.deepEqual(hessian.encode(date, '2.0'), bytes);
      assert.deepEqual(hessian.decode(bytes, '2.0'), date);
    });


    it('should write and read date', function () {
      var now = new Date(1398280514000);
      assert.deepEqual(hessian.encode(now, '2.0'), utils.bytes('v2/date/now'));
      // read it
      assert.deepEqual(hessian.decode(utils.bytes('v2/date/now'), '2.0'), now);
    });

    it('should write and read Wed Jan 04 1950 00:00:00 GMT+0800 (CST)', function () {
      var date = new Date('Wed Jan 04 1950 00:00:00 GMT+0800 (CST)');
      var bin = new Buffer('4bff5f8c60', 'hex');
      assert.deepEqual(hessian.encode(date, '2.0'), bin);
      assert.deepEqual(hessian.decode(bin, '2.0'), date);
    });

    // it('should read 1.0 format', function () {
    //   hessian.decode(utils.bytes('v1/date/894621091000'), '2.0').getTime()
    //     .should.equal(894621091000);
    //   hessian.decode(utils.bytes('v1/date/894621060000'), '2.0').getTime()
    //     .should.equal(894621060000);
    //   hessian.decode(utils.bytes('v1/date/now'), '2.0').getTime()
    //     .should.equal(1398280514000);
    // });
  });
});


================================================
FILE: test/decode.circular.test.js
================================================
'use strict';

const assert = require('assert');
const hessian = require('..');
const utils = require('./utils');

describe('test/decode.circular.test.js', function () {

  it('v1 decode()', function () {
    var data = new Buffer([77, 116, 0, 49, 99, 111, 109, 46, 97, 108, 105, 112, 97, 121, 46, 99, 111, 110, 102, 105, 103, 115, 101, 114, 118, 101, 114, 46, 99, 111, 110, 102, 114, 101, 103, 95, 116, 101, 115, 116, 46, 79, 110, 108, 105, 110, 101, 77, 111, 100, 117, 108, 101, 83, 0, 6, 109, 111, 100, 117, 108, 101, 83, 0, 1, 97, 83, 0, 4, 100, 101, 115, 99, 83, 0, 1, 98, 83, 0, 8, 118, 101, 114, 115, 105, 111, 110, 115, 86, 108, 0, 0, 0, 1, 77, 116, 0, 57, 99, 111, 109, 46, 97, 108, 105, 112, 97, 121, 46, 99, 111, 110, 102, 105, 103, 115, 101, 114, 118, 101, 114, 46, 99, 111, 110, 102, 114, 101, 103, 95, 116, 101, 115, 116, 46, 79, 110, 108, 105, 110, 101, 77, 111, 100, 117, 108, 101, 36, 86, 101, 114, 115, 105, 111, 110, 83, 0, 7, 118, 101, 114, 115, 105, 111, 110, 83, 0, 1, 99, 83, 0, 6, 97, 115, 115, 101, 116, 115, 86, 108, 0, 0, 0, 1, 83, 0, 1, 105, 122, 83, 0, 6, 116, 104, 105, 115, 36, 48, 82, 0, 0, 0, 0, 122, 122, 122]);
    var rs = hessian.decode(data);
    assert(
      JSON.stringify(rs) === '{"module":"a","desc":"b","versions":[{"version":"c","assets":["i"]}]}'
    );
  });


  it('v2 decode()', function () {
    var javabuf = utils.bytes('v2/object/ConnectionRequest');
    var connreq1 = hessian.decode(javabuf, '2.0');
    assert(connreq1.ctx && connreq1.ctx.id);
    assert(JSON.stringify(connreq1) === '{"ctx":{"id":101}}');
  });

});


================================================
FILE: test/double.test.js
================================================
'use strict';

const assert = require('assert');
const java = require('js-to-java');
const hessian = require('..');
const utils = require('./utils');

describe('double.test.js', function () {
  var doubleBuffer = new Buffer(['D'.charCodeAt(0),
    0x40, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00]);

  it('should read double 12.25', function () {
    assert(hessian.decode(doubleBuffer) === 12.25);
  });

  it('should write double 12.25', function () {
    assert.deepEqual(hessian.encode(12.25), doubleBuffer);
    assert.deepEqual(hessian.encode(java.double(12.25)), doubleBuffer);
    assert.deepEqual(hessian.encode({
      $class: 'double',
      $: 12.25
    }), doubleBuffer);
  });

  it('should write double 100', function () {
    assert.deepEqual(
      hessian.encode(java.double(100)),
      new Buffer(['D'.charCodeAt(0), 0x40, 0x59, 0, 0, 0, 0, 0, 0])
    );
  });

  it('should write double 0', function () {
    assert.deepEqual(
      hessian.encode(java.double(0)),
      new Buffer(['D'.charCodeAt(0), 0, 0, 0, 0, 0, 0, 0, 0])
    );
  });

  it('should write as java impl', function () {
    assert.deepEqual(hessian.encode(java.double(0), '1.0'), utils.bytes('v1/double/0'));
    assert.deepEqual(hessian.encode(java.double(0.0), '1.0'), utils.bytes('v1/double/0'));
    assert.deepEqual(hessian.encode(java.double(1), '1.0'), utils.bytes('v1/double/1'));
    assert.deepEqual(hessian.encode(java.double(1.0), '1.0'), utils.bytes('v1/double/1'));
    assert.deepEqual(hessian.encode(java.double(10), '1.0'), utils.bytes('v1/double/10'));
    assert.deepEqual(
      hessian.encode(java.double(10.123), '1.0'),
      utils.bytes('v1/double/10.123')
    );
    assert.deepEqual(hessian.encode(java.double(10.1), '1.0'), utils.bytes('v1/double/10.1'));
    assert.deepEqual(hessian.encode(java.double(-128), '1.0'), utils.bytes('v1/double/-128'));
    assert.deepEqual(
      hessian.encode(java.double(-127.9999), '1.0'),
      utils.bytes('v1/double/-127.9999')
    );
    assert.deepEqual(hessian.encode(java.double(127), '1.0'), utils.bytes('v1/double/127'));
    assert.deepEqual(
      hessian.encode(java.double(126.9989), '1.0'),
      utils.bytes('v1/double/126.9989')
    );
    assert.deepEqual(
      hessian.encode(java.double(-32768), '1.0'),
      utils.bytes('v1/double/-32768')
    );
    assert.deepEqual(
      hessian.encode(java.double(-32767.999), '1.0'),
      utils.bytes('v1/double/-32767.999')
    );
    assert.deepEqual(hessian.encode(java.double(32767), '1.0'), utils.bytes('v1/double/32767'));
    assert.deepEqual(
      hessian.encode(java.double(32766.99999), '1.0'),
      utils.bytes('v1/double/32766.99999')
    );
    assert.deepEqual(hessian.encode(java.double(32768), '1.0'), utils.bytes('v1/double/32768'));
    assert.deepEqual(
      hessian.encode(java.double(32767.99999), '1.0'),
      utils.bytes('v1/double/32767.99999')
    );

    // float byte
    assert.deepEqual(
      hessian.encode(java.double(-2147483649), '1.0'),
      utils.bytes('v1/double/-2147483649')
    );
    assert.deepEqual(
      hessian.encode(java.double(-2147483648), '1.0'),
      utils.bytes('v1/double/-2147483648')
    );
    assert.deepEqual(
      hessian.encode(java.double(-2147483647), '1.0'),
      utils.bytes('v1/double/-2147483647')
    );
    assert.deepEqual(
      hessian.encode(java.double(-2147483610.123), '1.0'),
      utils.bytes('v1/double/-2147483610.123')
    );
    assert.deepEqual(
      hessian.encode(java.double(2147483648), '1.0'),
      utils.bytes('v1/double/2147483648')
    );
    assert.deepEqual(
      hessian.encode(java.double(2147483647), '1.0'),
      utils.bytes('v1/double/2147483647')
    );
    assert.deepEqual(
      hessian.encode(java.double(2147483646), '1.0'),
      utils.bytes('v1/double/2147483646')
    );
    assert.deepEqual(
      hessian.encode(java.double(2147483646.456), '1.0'),
      utils.bytes('v1/double/2147483646.456')
    );
  });

  it('should read java bin format', function () {
    assert(hessian.decode(utils.bytes('v1/double/0'), '1.0') === 0);
    assert(hessian.decode(utils.bytes('v1/double/1'), '1.0') === 1);
    assert(hessian.decode(utils.bytes('v1/double/10'), '1.0') === 10);
    assert(hessian.decode(utils.bytes('v1/double/10.123'), '1.0') === 10.123);
    assert(hessian.decode(utils.bytes('v1/double/10.1'), '1.0') === 10.1);
    assert(hessian.decode(utils.bytes('v1/double/-128'), '1.0') === -128);
    assert(hessian.decode(utils.bytes('v1/double/-127.9999'), '1.0') === -127.9999);
    assert(hessian.decode(utils.bytes('v1/double/127'), '1.0') === 127);
    assert(hessian.decode(utils.bytes('v1/double/126.9989'), '1.0') === 126.9989);
    assert(hessian.decode(utils.bytes('v1/double/-32768'), '1.0') === -32768);
    assert(hessian.decode(utils.bytes('v1/double/-32767.999'), '1.0') === -32767.999);
    assert(hessian.decode(utils.bytes('v1/double/32767'), '1.0') === 32767);
    assert(
      hessian.decode(utils.bytes('v1/double/32766.99999'), '1.0') === 32766.99999
    );
    assert(hessian.decode(utils.bytes('v1/double/32768'), '1.0') === 32768);
    assert(
      hessian.decode(utils.bytes('v1/double/32767.99999'), '1.0') === 32767.99999
    );
    assert(
      hessian.decode(utils.bytes('v1/double/-2147483649'), '1.0') === -2147483649
    );
    assert(
      hessian.decode(utils.bytes('v1/double/-2147483648'), '1.0') === -2147483648
    );
    assert(
      hessian.decode(utils.bytes('v1/double/-2147483647'), '1.0') === -2147483647
    );
    assert(
      hessian.decode(utils.bytes('v1/double/-2147483610.123'), '1.0') === -2147483610.123
    );
    assert(hessian.decode(utils.bytes('v1/double/2147483648'), '1.0') === 2147483648);
    assert(hessian.decode(utils.bytes('v1/double/2147483647'), '1.0') === 2147483647);
    assert(hessian.decode(utils.bytes('v1/double/2147483646'), '1.0') === 2147483646);
    assert(
      hessian.decode(utils.bytes('v1/double/2147483646.456'), '1.0') === 2147483646.456
    );
  });

  describe('v2.0', function () {
    it('should read 0.0 and 1.0', function () {
      assert(hessian.decode(new Buffer([0x5b]), '2.0') === 0.0);
      assert(hessian.decode(new Buffer([0x5c]), '2.0') === 1.0);
    });

    it('should read 8 bits double', function () {
      assert(hessian.decode(new Buffer([0x5d, 0x00]), '2.0') === 0.0);
      assert(hessian.decode(new Buffer([0x5d, 0x01]), '2.0') === 1.0);
      assert(hessian.decode(new Buffer([0x5d, 0x80]), '2.0') === -128.0);
      assert(hessian.decode(new Buffer([0x5d, 0x7f]), '2.0') === 127.0);
    });

    it('should read 16 bits double', function () {
      assert(hessian.decode(new Buffer([0x5e, 0x00, 0x00]), '2.0') === 0.0);
      assert(hessian.decode(new Buffer([0x5e, 0x00, 0x01]), '2.0') === 1.0);
      assert(hessian.decode(new Buffer([0x5e, 0x00, 0x80]), '2.0') === 128.0);
      assert(hessian.decode(new Buffer([0x5e, 0x00, 0x7f]), '2.0') === 127.0);
      assert(hessian.decode(new Buffer([0x5e, 0x80, 0x00]), '2.0') === -32768.0);
      assert(hessian.decode(new Buffer([0x5e, 0x7f, 0xff]), '2.0') === 32767.0);
    });

    it('should read 32 bits float double', function () {
      assert(hessian.decode(new Buffer([0x5f, 0x00, 0x00, 0x00, 0x00]), '2.0') === 0.0);
      assert(hessian.decode(new Buffer([0x5f, 0x00, 0x00, 0x2f, 0xda]), '2.0') === 12.25);
    });

    it('should read normal double', function () {
      assert(
        hessian.decode(new Buffer([0x44, 0x40, 0x24, 0, 0, 0, 0, 0, 0]), '2.0') === 10.0
      );
    });

    it('should write 0.0 and 1.0', function () {
      assert.deepEqual(hessian.encode(java.double(0), '2.0'), new Buffer([0x5b]));
      assert.deepEqual(hessian.encode(java.double(0.0), '2.0'), new Buffer([0x5b]));

      assert.deepEqual(hessian.encode(java.double(1), '2.0'), new Buffer([0x5c]));
      assert.deepEqual(hessian.encode(java.double(1.0), '2.0'), new Buffer([0x5c]));
    });

    it('should write as java impl', function () {
      assert.deepEqual(hessian.encode(java.double(0), '2.0'), utils.bytes('v2/double/0'));
      assert.deepEqual(hessian.encode(java.double(0.0), '2.0'), utils.bytes('v2/double/0'));
      assert.deepEqual(hessian.encode(java.double(1), '2.0'), utils.bytes('v2/double/1'));
      assert.deepEqual(hessian.encode(java.double(1.0), '2.0'), utils.bytes('v2/double/1'));
      assert.deepEqual(hessian.encode(java.double(10), '2.0'), utils.bytes('v2/double/10'));
      assert.deepEqual(
        hessian.encode(java.double(10.123), '2.0'),
        utils.bytes('v2/double/10.123')
      );
      assert.deepEqual(hessian.encode(java.double(10.1), '2.0'), utils.bytes('v2/double/10.1'));
      assert.deepEqual(hessian.encode(java.double(-128), '2.0'), utils.bytes('v2/double/-128'));
      assert.deepEqual(
        hessian.encode(java.double(-127.9999), '2.0'),
        utils.bytes('v2/double/-127.9999')
      );
      assert.deepEqual(hessian.encode(java.double(127), '2.0'), utils.bytes('v2/double/127'));
      assert.deepEqual(
        hessian.encode(java.double(126.9989), '2.0'),
        utils.bytes('v2/double/126.9989')
      );
      assert.deepEqual(
        hessian.encode(java.double(-32768), '2.0'),
        utils.bytes('v2/double/-32768')
      );
      assert.deepEqual(
        hessian.encode(java.double(-32767.999), '2.0'),
        utils.bytes('v2/double/-32767.999')
      );
      assert.deepEqual(hessian.encode(java.double(32767), '2.0'), utils.bytes('v2/double/32767'));
      assert.deepEqual(
        hessian.encode(java.double(32766.99999), '2.0'),
        utils.bytes('v2/double/32766.99999')
      );
      assert.deepEqual(hessian.encode(java.double(32768), '2.0'), utils.bytes('v2/double/32768'));
      assert.deepEqual(
        hessian.encode(java.double(32767.99999), '2.0'),
        utils.bytes('v2/double/32767.99999')
      );

      // float byte
      assert(hessian.encode(java.double(-0x800000), '2.0').length === 9);
      assert.deepEqual(hessian.encode(java.double(-0x800000), '2.0'), utils.bytes('v2/double/-0x800000'));
      assert(hessian.encode(java.double(-0x80000000), '2.0').length === 9);
      assert.deepEqual(hessian.encode(java.double(-0x80000000), '2.0'), utils.bytes('v2/double/-0x80000000'));
      assert.deepEqual(hessian.encode(java.double(-2147483649), '2.0'), utils.bytes('v2/double/-2147483649'));
      assert.deepEqual(hessian.encode(java.double(-2147483648), '2.0'), utils.bytes('v2/double/-2147483648'));
      // hessian.encode(java.double(-2147483647), '2.0').should.eql(utils.bytes('v2/double/-2147483647'));
      assert.deepEqual(
        hessian.encode(java.double(-2147483610.123), '2.0'),
        utils.bytes('v2/double/-2147483610.123')
      );
      // hessian.encode(java.double(2147483648), '2.0').should.eql(utils.bytes('v2/double/2147483648'));
      // hessian.encode(java.double(2147483647), '2.0').should.eql(utils.bytes('v2/double/2147483647'));
      // hessian.encode(java.double(2147483646), '2.0').should.eql(utils.bytes('v2/double/2147483646'));
      assert.deepEqual(
        hessian.encode(java.double(2147483646.456), '2.0'),
        utils.bytes('v2/double/2147483646.456')
      );
    });

    it('should read java bin format', function () {
      assert(hessian.decode(utils.bytes('v2/double/0'), '2.0') === 0);
      assert(hessian.decode(utils.bytes('v2/double/1'), '2.0') === 1);
      assert(hessian.decode(utils.bytes('v2/double/10'), '2.0') === 10);
      assert(hessian.decode(utils.bytes('v2/double/10.123'), '2.0') === 10.123);
      assert(hessian.decode(utils.bytes('v2/double/10.1'), '2.0') === 10.1);
      assert(hessian.decode(utils.bytes('v2/double/-128'), '2.0') === -128);
      assert(hessian.decode(utils.bytes('v2/double/-127.9999'), '2.0') === -127.9999);
      assert(hessian.decode(utils.bytes('v2/double/127'), '2.0') === 127);
      assert(hessian.decode(utils.bytes('v2/double/126.9989'), '2.0') === 126.9989);
      assert(hessian.decode(utils.bytes('v2/double/-32768'), '2.0') === -32768);
      assert(hessian.decode(utils.bytes('v2/double/-32767.999'), '2.0') === -32767.999);
      assert(hessian.decode(utils.bytes('v2/double/32767'), '2.0') === 32767);
      assert(
        hessian.decode(utils.bytes('v2/double/32766.99999'), '2.0') === 32766.99999
      );
      assert(hessian.decode(utils.bytes('v2/double/32768'), '2.0') === 32768);
      assert(
        hessian.decode(utils.bytes('v2/double/32767.99999'), '2.0') === 32767.99999
      );

      // float byte
      assert(hessian.decode(utils.bytes('v2/double/-0x800000'), '2.0') === -0x800000);
      assert(
        hessian.decode(utils.bytes('v2/double/-0x80000000'), '2.0') === -0x80000000
      );
      assert(
        hessian.decode(utils.bytes('v2/double/-2147483649'), '2.0') === -2147483649
      );
      assert(
        hessian.decode(utils.bytes('v2/double/-2147483648'), '2.0') === -2147483648
      );
      assert(
        hessian.decode(utils.bytes('v2/double/-2147483647'), '2.0') === -2147483647
      );
      assert(
        hessian.decode(utils.bytes('v2/double/-2147483610.123'), '2.0') === -2147483610.123
      );
      assert(hessian.decode(utils.bytes('v2/double/2147483648'), '2.0') === 2147483648);
      assert(hessian.decode(utils.bytes('v2/double/2147483647'), '2.0') === 2147483647);
      assert(hessian.decode(utils.bytes('v2/double/2147483646'), '2.0') === 2147483646);
      assert(
        hessian.decode(utils.bytes('v2/double/2147483646.456'), '2.0') === 2147483646.456
      );
    });

    it('should read java hessian 1.0 bin format', function () {
      assert(hessian.decode(utils.bytes('v1/double/0'), '2.0') === 0);
      assert(hessian.decode(utils.bytes('v1/double/1'), '2.0') === 1);
      assert(hessian.decode(utils.bytes('v1/double/10'), '2.0') === 10);
      assert(hessian.decode(utils.bytes('v1/double/10.123'), '2.0') === 10.123);
      assert(hessian.decode(utils.bytes('v1/double/10.1'), '2.0') === 10.1);
      assert(hessian.decode(utils.bytes('v1/double/-128'), '2.0') === -128);
      assert(hessian.decode(utils.bytes('v1/double/-127.9999'), '2.0') === -127.9999);
      assert(hessian.decode(utils.bytes('v1/double/127'), '2.0') === 127);
      assert(hessian.decode(utils.bytes('v1/double/126.9989'), '2.0') === 126.9989);
      assert(hessian.decode(utils.bytes('v1/double/-32768'), '2.0') === -32768);
      assert(hessian.decode(utils.bytes('v1/double/-32767.999'), '2.0') === -32767.999);
      assert(hessian.decode(utils.bytes('v1/double/32767'), '2.0') === 32767);
      assert(
        hessian.decode(utils.bytes('v1/double/32766.99999'), '2.0') === 32766.99999
      );
      assert(hessian.decode(utils.bytes('v1/double/32768'), '2.0') === 32768);
      assert(
        hessian.decode(utils.bytes('v1/double/32767.99999'), '2.0') === 32767.99999
      );
      assert(
        hessian.decode(utils.bytes('v1/double/-2147483649'), '2.0') === -2147483649
      );
      assert(
        hessian.decode(utils.bytes('v1/double/-2147483648'), '2.0') === -2147483648
      );
      assert(
        hessian.decode(utils.bytes('v1/double/-2147483647'), '2.0') === -2147483647
      );
      assert(
        hessian.decode(utils.bytes('v1/double/-2147483610.123'), '2.0') === -2147483610.123
      );
      assert(hessian.decode(utils.bytes('v1/double/2147483648'), '2.0') === 2147483648);
      assert(hessian.decode(utils.bytes('v1/double/2147483647'), '2.0') === 2147483647);
      assert(hessian.decode(utils.bytes('v1/double/2147483646'), '2.0') === 2147483646);
      assert(
        hessian.decode(utils.bytes('v1/double/2147483646.456'), '2.0') === 2147483646.456
      );
    });
  });
});


================================================
FILE: test/exception.test.js
================================================
'use strict';

const assert = require('assert');
const hessian = require('..');
const utils = require('./utils');

describe('exception.test.js', function () {
  describe('v1.0', function () {
    it('should read java exception as js error', function () {
      var ioe = hessian.decode(utils.bytes('v1/exception/IOException'));
      assert(ioe instanceof Error);
      assert(ioe.name === 'java.io.IOException');
      assert(ioe.message === 'this is a java IOException instance');
      assert(
        ioe.stack === 'java.io.IOException: this is a java IOException instance\n    at hessian.Main.main (Main.java:1283)'
      );

      var ioe = hessian.decode(utils.bytes('v1/exception/IOException'), true);
      assert(ioe.$ instanceof Error);
      assert(ioe.$.name === 'java.io.IOException');
      assert(ioe.$.message === 'this is a java IOException instance');
      assert(
        ioe.$.stack === 'java.io.IOException: this is a java IOException instance\n    at hessian.Main.main (Main.java:1283)'
      );

      var e = hessian.decode(utils.bytes('v1/exception/UndeclaredThrowableException'));
      assert(e instanceof Error);
      assert((e instanceof Error) === true);
      assert(e.name === 'java.io.IOException');
      assert(e.message === 'this is a java IOException instance');
      assert(
        e.stack === 'java.io.IOException: this is a java IOException instance\n    at hessian.Main.main (Main.java:1283)'
      );
      assert(e.cause);
      assert(e.cause.detailMessage === 'this is a java IOException instance');

      var e = hessian.decode(utils.bytes('v1/exception/UndeclaredThrowableException'), true);
      assert(e.$ instanceof Error);
      assert(e.$.name === 'java.io.IOException');
      assert(e.$.message === 'this is a java IOException instance');
      assert(
        e.$.stack === 'java.io.IOException: this is a java IOException instance\n    at hessian.Main.main (Main.java:1283)'
      );
      assert(e.$.cause);
      assert(e.$.cause.$class === 'java.io.IOException');
      assert(e.$.cause.$ instanceof Error);
      assert(e.$.cause.$.name === 'java.io.IOException');

      var e = hessian.decode(utils.bytes('v1/exception/UndeclaredThrowableException2'));
      assert(e instanceof Error);
      assert((e instanceof Error) === true);
      assert(e.name === 'java.io.IOException');
      assert(e.message === '模拟测试异常; this is a java IOException instance');
      assert(
        e.stack === 'java.io.IOException: 模拟测试异常; this is a java IOException instance\n    at hessian.Main.main (Main.java:1303)'
      );

      var e = hessian.decode(utils.bytes('v1/exception/UndeclaredThrowableException2'), true);
      assert(e.$ instanceof Error);
      assert(e.$.name === 'java.io.IOException');
      assert(e.$.message === '模拟测试异常; this is a java IOException instance');
      assert(
        e.$.stack === 'java.io.IOException: 模拟测试异常; this is a java IOException instance\n    at hessian.Main.main (Main.java:1303)'
      );
    });
  });

  describe('v2.0', function () {
    it('should read java exception as js error', function () {
      var ioe = hessian.decode(utils.bytes('v2/exception/IOException'), '2.0');
      assert(ioe instanceof Error);
      assert((ioe instanceof Error) === true);
      assert(ioe.name === 'java.io.IOException');
      assert(ioe.message === 'this is a java IOException instance');
      assert(
        ioe.stack === 'java.io.IOException: this is a java IOException instance\n    at hessian.Main.main (Main.java:1283)'
      );

      var e = hessian.decode(utils.bytes('v2/exception/UndeclaredThrowableException'), '2.0');
      assert(e instanceof Error);
      assert(e.name === 'java.io.IOException');
      assert(e.message === 'this is a java IOException instance');
      assert(
        e.stack === 'java.io.IOException: this is a java IOException instance\n    at hessian.Main.main (Main.java:1283)'
      );

      var e = hessian.decode(utils.bytes('v2/exception/UndeclaredThrowableException2'), '2.0');
      assert(e instanceof Error);
      assert(e.name === 'java.io.IOException');
      assert(e.message === '模拟测试异常; this is a java IOException instance');
      assert(e.stack === 'java.io.IOException: 模拟测试异常; this is a java IOException instance\n    at hessian.Main.main (Main.java:1303)');

      var e = hessian.decode(utils.bytes('v2/exception/UndeclaredThrowableException3'), '2.0');
      assert(e instanceof Error);
      assert(e.name === 'com.taobao.hsf.exception.HSFServiceAddressNotFoundException');
      assert(e.message === 'HSFServiceAddressNotFoundException-');
      assert(e.cause.stackTrace.length === 56);
    });

    // it('should read hessian 1.0 exception', function () {
    //   var ioe = hessian.decode(utils.bytes('v1/exception/IOException'), '2.0');
    //   ioe.should.be.an.Error;
    //   should.ok((ioe instanceof Error) === true);
    //   ioe.name.should.equal('java.io.IOException');
    //   ioe.message.should.equal('this is a java IOException instance');
    //   ioe.stack.should.equal('java.io.IOException: this is a java IOException instance\n    at hessian.Main.main (Main.java:1283)');

    //   var e = hessian.decode(utils.bytes('v1/exception/UndeclaredThrowableException'), '2.0');
    //   e.should.be.an.Error;
    //   should.ok((e instanceof Error) === true);
    //   e.name.should.equal('java.io.IOException');
    //   e.message.should.equal('this is a java IOException instance');
    //   e.stack.should.equal('java.io.IOException: this is a java IOException instance\n    at hessian.Main.main (Main.java:1283)');

    //   var e = hessian.decode(utils.bytes('v1/exception/UndeclaredThrowableException2'), '2.0');
    //   e.should.be.an.Error;
    //   should.ok((e instanceof Error) === true);
    //   e.name.should.equal('java.io.IOException');
    //   e.message.should.equal('模拟测试异常; this is a java IOException instance');
    //   e.stack.should.equal('java.io.IOException: 模拟测试异常; this is a java IOException instance\n    at hessian.Main.main (Main.java:1303)');
    // });
  });
});


================================================
FILE: test/fixtures/4k.txt
================================================
/*!
 * hessian.js - test/double.test.js
 *
 * Copyright(c) 2014
 * MIT Licensed
 *
 * Authors:
 *   fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)
 */

"use strict";

/**
 * Module dependencies.
 */

var should = require('should');
var java = require('js-to-java');
var hessian = require('../');

describe('double.test.js', function () {
  var doubleBuffer = new Buffer(['D'.charCodeAt(0),
    0x40, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00]);

  it('should read double 12.25', function () {
    hessian.decode(doubleBuffer).should.equal(12.25);
  });

  it('should write double 12.25', function () {
    hessian.encode(12.25).should.eql(doubleBuffer);
    hessian.encode(java.double(12.25)).should.eql(doubleBuffer);
    hessian.encode({
      $class: 'double',
      $: 12.25
    }).should.eql(doubleBuffer);
  });

  it('should write double 100', function () {
    hessian.encode(java.double(100)).should.eql(
      new Buffer(['D'.charCodeAt(0), 0x40, 0x59, 0, 0, 0, 0, 0, 0]));
  });

  it('should write double 0', function () {
    hessian.encode(java.double(0)).should.eql(
      new Buffer(['D'.charCodeAt(0), 0, 0, 0, 0, 0, 0, 0, 0]));
  });

  describe('v2.0', function () {
    it('should read 0.0 and 1.0', function () {
      hessian.decode(new Buffer([0x5b]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5c]), '2.0').should.equal(1.0);
    });

    it('should read 8 bits double', function () {
      hessian.decode(new Buffer([0x5d, 0x00]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5d, 0x01]), '2.0').should.equal(1.0);
      hessian.decode(new Buffer([0x5d, 0x80]), '2.0').should.equal(-128.0);
      hessian.decode(new Buffer([0x5d, 0x7f]), '2.0').should.equal(127.0);
    });

    it('should read 16 bits double', function () {
      hessian.decode(new Buffer([0x5e, 0x00, 0x00]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5e, 0x00, 0x01]), '2.0').should.equal(1.0);
      hessian.decode(new Buffer([0x5e, 0x00, 0x80]), '2.0').should.equal(128.0);
      hessian.decode(new Buffer([0x5e, 0x00, 0x7f]), '2.0').should.equal(127.0);
      hessian.decode(new Buffer([0x5e, 0x80, 0x00]), '2.0').should.equal(-32768.0);
      hessian.decode(new Buffer([0x5e, 0x7f, 0xff]), '2.0').should.equal(32767.0);
    });

    it('should read 32 bits float double', function () {
      hessian.decode(new Buffer([0x5f, 0x00, 0x00, 0x00, 0x00]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5f, 0x41, 0x44, 0x00, 0x00]), '2.0').should.equal(12.25);
    });

    it('should read normal double', function () {
      hessian.decode(new Buffer([0x44, 0x40, 0x24, 0, 0, 0, 0, 0, 0]), '2.0').should.equal(10.0);
    });

    it('should write 0.0 and 1.0', function () {
      hessian.encode(java.double(0), '2.0').should.eql(new Buffer([0x5b]));
      hessian.encode(java.double(0.0), '2.0').should.eql(new Buffer([0x5b]));

      hessian.encode(java.double(1), '2.0').should.eql(new Buffer([0x5c]));
      hessian.encode(java.double(1.0), '2.0').should.eql(new Buffer([0x5c]));
    });

    it('should write big double', function () {
      hessian.encode(java.double(10), '2.0')
        .should.eql(new Buffer([0x44, 0x40, 0x24, 0, 0, 0, 0, 0, 0]));
    });
  });
});
/*!
 * hessian.js - test/double.test.js
 *
 * Copyright(c) 2014
 * MIT Licensed
 *
 * Authors:
 *   fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)
 */

"use strict";

/**
 * Module dependencies.
 */

var should = require('should');
var java = require('js-to-java');
var hessian = require('../');

describe('double.test.js', function () {
  var doubleBuffer = new Buffer(['D'.charCodeAt(0),
    0x40, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00]);

  it('should read double 12.25', function () {
    hessian.decode(doubleBuffer).should.equal(12.25);
  });

  it('should write double 12.25', function () {
    hessian.encode(12.25).should.eql(doubleBuffer);
    hessian.encode(java.double(12.25)).should.eql(doubleBuffer);
    hessian.encode({
      $class: 'double',
      $: 12.25
    }).should.eql(doubleBuffer);
  });

  it('should write double 100', function () {
    hessian.encode(java.double(100)).should.eql(
      new Buffer(['D'.charCodeAt(0), 0x40, 0x59, 0, 0, 0, 0, 0, 0]));
  });

  it('should write double 0', function () {
    hessian.encode(java.double(0)).should.eql(
      new Buffer(['D'.charCodeAt(0), 0, 0, 0, 0, 0, 0, 0, 0]));
  });

  describe('v2.0', function () {
    it('should read 0.0 and 1.0', function () {
      hessian.decode(new Buffer([0x5b]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5c]), '2.0').should.equal(1.0);
    });

    it('should read 8 bits double', function () {
      hessian.decode(new Buffer([0x5d, 0x00]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5d, 0x01]), '2.0').should.equal(1.0);
      hessian.decode(new Buffer([0x5d, 0x80]), '2.0').should.equal(-128.0);
      hessian.decode(new Buffer([0x5d, 0x7f]), '2.0').should.equal(127.0);
    });

    it('should read 16 bits double', function () {
      hessian.decode(new Buffer([0x5e, 0x00, 0x00]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5e, 0x00, 0x01]), '2.0').should.equal(1.0);
      hessian.decode(new Buffer([0x5e, 0x00, 0x80]), '2.0').should.equal(128.0);
      hessian.decode(new Buffer([0x5e, 0x00, 0x7f]), '2.0').should.equal(127.0);
      hessian.decode(new Buffer([0x5e, 0x80, 0x00]), '2.0').should.equal(-32768.0);
      hessian.decode(new Buffer([0x5e, 0x7f, 0xff]), '2.0').should.equal(32767.0);
    });

    it('should read 32 bits float double', function () {
      hessian.decode(new Buffer([0x5f, 0x00, 0x00, 0x00, 0x00]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5f, 0x41, 0x44, 0x00, 0x00]), '2.0').should.equal(12.25);
    });

    it('should read normal double', function () {
      hessian.decode(new Buffer([0x44, 0x40, 0x24, 0, 0, 0, 0, 0, 0]), '2.0').should.equal(10.0);
    });

    it('should write 0.0 and 1.0', function () {
      hessian.encode(java.double(0), '2.0').should.eql(new Buffer([0x5b]));
      hessian.encode(java.double(0.0), '2.0').should.eql(new Buffer([0x5b]));

      hessian.encode(java.double(1), '2.0').should.eql(new Buffer([0x5c]));
      hessian.encode(java.double(1.0), '2.0').should.eql(new Buffer([0x5c]));
    });

    it('should write big double', function () {
      hessian.encode(java.double(10), '2.0')
        .should.eql(new Buffer([0x44, 0x40, 0x24, 0, 0, 0, 0, 0, 0]));
    });
  });
});
/*!
 * hessian.js - test/double.test.js
 *
 * Copyright(c) 2014
 * MIT Licensed
 *
 * Authors:
 *   fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)
 */

"use strict";

/**
 * Module dependencies.
 */

var should = require('should');
var java = require('js-to-java');
var hessian = require('../');

describe('double.test.js', function () {
  var doubleBuffer = new Buffer(['D'.charCodeAt(0),
    0x40, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00]);

  it('should read double 12.25', function () {
    hessian.decode(doubleBuffer).should.equal(12.25);
  });

  it('should write double 12.25', function () {
    hessian.encode(12.25).should.eql(doubleBuffer);
    hessian.encode(java.double(12.25)).should.eql(doubleBuffer);
    hessian.encode({
      $class: 'double',
      $: 12.25
    }).should.eql(doubleBuffer);
  });

  it('should write double 100', function () {
    hessian.encode(java.double(100)).should.eql(
      new Buffer(['D'.charCodeAt(0), 0x40, 0x59, 0, 0, 0, 0, 0, 0]));
  });

  it('should write double 0', function () {
    hessian.encode(java.double(0)).should.eql(
      new Buffer(['D'.charCodeAt(0), 0, 0, 0, 0, 0, 0, 0, 0]));
  });

  describe('v2.0', function () {
    it('should read 0.0 and 1.0', function () {
      hessian.decode(new Buffer([0x5b]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5c]), '2.0').should.equal(1.0);
    });

    it('should read 8 bits double', function () {
      hessian.decode(new Buffer([0x5d, 0x00]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5d, 0x01]), '2.0').should.equal(1.0);
      hessian.decode(new Buffer([0x5d, 0x80]), '2.0').should.equal(-128.0);
      hessian.decode(new Buffer([0x5d, 0x7f]), '2.0').should.equal(127.0);
    });

    it('should read 16 bits double', function () {
      hessian.decode(new Buffer([0x5e, 0x00, 0x00]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5e, 0x00, 0x01]), '2.0').should.equal(1.0);
      hessian.decode(new Buffer([0x5e, 0x00, 0x80]), '2.0').should.equal(128.0);
      hessian.decode(new Buffer([0x5e, 0x00, 0x7f]), '2.0').should.equal(127.0);
      hessian.decode(new Buffer([0x5e, 0x80, 0x00]), '2.0').should.equal(-32768.0);
      hessian.decode(new Buffer([0x5e, 0x7f, 0xff]), '2.0').should.equal(32767.0);
    });

    it('should read 32 bits float double', function () {
      hessian.decode(new Buffer([0x5f, 0x00, 0x00, 0x00, 0x00]), '2.0').should.equal(0.0);
      hessian.decode(new Buffer([0x5f, 0x41, 0x44, 0x00, 0x00]), '2.0').should.equal(12.25);
    });

    it('should read normal double', function () {
      hessian.decode(new Buffer([0x44, 0x40, 0x24, 0, 0, 0, 0, 0, 0]), '2.0').should.equal(10.0);
    });

    it('should write 0.0 and 1.0', function () {
      hessian.encode(java.double(0), '2.0').should.eql(new Buffer([0x5b]));
      hessian.encode(java.double(0.0), '2.0').should.eql(new Buffer([0x5b]));

      hessian.encode(java.double(1), '2.0').should.eql(new Buffer([0x5c]));
      hessian.encode(java.double(1.0), '2.0').should.eql(new Buffer([0x5c]));
    });

    it('should write big double', function () {
      hessian.encode(java.double(10), '2.0')
        .should.eql(new Buffer([0x44, 0x40, 0x24, 0, 0, 0, 0, 0, 0]));
    });
  });
});


================================================
FILE: test/int.test.js
================================================
'use strict';

const assert = require('assert');
const hessian = require('..');
const utils = require('./utils');

describe('int.test.js', function () {
  it('should read integer 300', function () {
    assert(
      hessian.decode(new Buffer(['I'.charCodeAt(0), 0x00, 0x00, 0x01, 0x2c])) === 300
    );
  });

  it('should write integer 300', function () {
    assert.deepEqual(
      hessian.encode(300),
      new Buffer(['I'.charCodeAt(0), 0x00, 0x00, 0x01, 0x2c])
    );
  });

  it('should write integer 0', function () {
    assert.deepEqual(hessian.encode(0), new Buffer(['I'.charCodeAt(0), 0, 0, 0, 0]));
  });

  it('should write number as java write', function () {
    assert.deepEqual(hessian.encode(0, '1.0'), utils.bytes('v1/number/0'));
    assert.deepEqual(hessian.encode(1), utils.bytes('v1/number/1'));
    assert.deepEqual(hessian.encode(10), utils.bytes('v1/number/10'));
    assert.deepEqual(hessian.encode(16), utils.bytes('v1/number/16'));
    assert.deepEqual(hessian.encode(2047), utils.bytes('v1/number/2047'));
    assert.deepEqual(hessian.encode(255, '1.0'), utils.bytes('v1/number/255'));
    assert.deepEqual(hessian.encode(256, '1.0'), utils.bytes('v1/number/256'));
    assert.deepEqual(hessian.encode(262143, '1.0'), utils.bytes('v1/number/262143'));
    assert.deepEqual(hessian.encode(262144, '1.0'), utils.bytes('v1/number/262144'));
    assert.deepEqual(hessian.encode(46, '1.0'), utils.bytes('v1/number/46'));
    assert.deepEqual(hessian.encode(47, '1.0'), utils.bytes('v1/number/47'));

    assert.deepEqual(hessian.encode(-16, '1.0'), utils.bytes('v1/number/-16'));
    assert.deepEqual(hessian.encode(-2048, '1.0'), utils.bytes('v1/number/-2048'));
    assert.deepEqual(hessian.encode(-256), utils.bytes('v1/number/-256'));
    assert.deepEqual(hessian.encode(-262144, '1.0'), utils.bytes('v1/number/-262144'));
    assert.deepEqual(hessian.encode(-262145, '1.0'), utils.bytes('v1/number/-262145'));
  });

  it('should read java number bin', function () {
    assert(hessian.decode(utils.bytes('v1/number/0'), '1.0') === 0);
    assert(hessian.decode(utils.bytes('v1/number/1'), '1.0') === 1);
    assert(hessian.decode(utils.bytes('v1/number/10'), '1.0') === 10);
    assert(hessian.decode(utils.bytes('v1/number/16'), '1.0') === 16);
    assert(hessian.decode(utils.bytes('v1/number/2047'), '1.0') === 2047);
    assert(hessian.decode(utils.bytes('v1/number/255'), '1.0') === 255);
    assert(hessian.decode(utils.bytes('v1/number/256'), '1.0') === 256);
    assert(hessian.decode(utils.bytes('v1/number/262143'), '1.0') === 262143);
    assert(hessian.decode(utils.bytes('v1/number/262144'), '1.0') === 262144);
    assert(hessian.decode(utils.bytes('v1/number/46'), '1.0') === 46);
    assert(hessian.decode(utils.bytes('v1/number/47'), '1.0') === 47);
    assert(hessian.decode(utils.bytes('v1/number/-16'), '1.0') === -16);
    assert(hessian.decode(utils.bytes('v1/number/-2048'), '1.0') === -2048);
    assert(hessian.decode(utils.bytes('v1/number/-256'), '1.0') === -256);
    assert(hessian.decode(utils.bytes('v1/number/-262144'), '1.0') === -262144);
    assert(hessian.decode(utils.bytes('v1/number/-262145'), '1.0') === -262145);
  });

  describe('v2.0', function () {
    it('should read compact integers', function () {
      assert(hessian.decode(new Buffer([0x90]), '2.0') === 0);
      assert(hessian.decode(new Buffer([0x80]), '2.0') === -16);
      assert(hessian.decode(new Buffer([0xbf]), '2.0') === 47);

      assert(hessian.decode(new Buffer([0xc8, 0x00]), '2.0') === 0);
      assert(hessian.decode(new Buffer([0xc0, 0x00]), '2.0') === -2048);
      assert(hessian.decode(new Buffer([0xc7, 0x00]), '2.0') === -256);
      assert(hessian.decode(new Buffer([0xcf, 0xff]), '2.0') === 2047);

      assert(hessian.decode(new Buffer([0xd4, 0x00, 0x00]), '2.0') === 0);
      assert(hessian.decode(new Buffer([0xd0, 0x00, 0x00]), '2.0') === -262144);
      assert(hessian.decode(new Buffer([0xd7, 0xff, 0xff]), '2.0') === 262143);

      assert(
        hessian.decode(new Buffer(['I'.charCodeAt(0), 0x00, 0x00, 0x00, 0x00]), '2.0') === 0
      );
      assert(
        hessian.decode(new Buffer(['I'.charCodeAt(0), 0x00, 0x00, 0x01, 0x2c]), '2.0') === 300
      );
    });

    it('should write number as java write', function () {
      assert.deepEqual(hessian.encode(0, '2.0'), utils.bytes('v2/number/0'));
      assert.deepEqual(hessian.encode(1, '2.0'), utils.bytes('v2/number/1'));
      assert.deepEqual(hessian.encode(10, '2.0'), utils.bytes('v2/number/10'));
      assert.deepEqual(hessian.encode(16, '2.0'), utils.bytes('v2/number/16'));
      assert.deepEqual(hessian.encode(2047, '2.0'), utils.bytes('v2/number/2047'));
      assert.deepEqual(hessian.encode(255, '2.0'), utils.bytes('v2/number/255'));
      assert.deepEqual(hessian.encode(256, '2.0'), utils.bytes('v2/number/256'));
      assert.deepEqual(hessian.encode(262143, '2.0'), utils.bytes('v2/number/262143'));
      assert.deepEqual(hessian.encode(262144, '2.0'), utils.bytes('v2/number/262144'));
      assert.deepEqual(hessian.encode(46, '2.0'), utils.bytes('v2/number/46'));
      assert.deepEqual(hessian.encode(47, '2.0'), utils.bytes('v2/number/47'));
      assert.deepEqual(hessian.encode(-16, '2.0'), utils.bytes('v2/number/-16'));
      assert.deepEqual(hessian.encode(-2048, '2.0'), utils.bytes('v2/number/-2048'));
      assert.deepEqual(hessian.encode(-256, '2.0'), utils.bytes('v2/number/-256'));
      assert.deepEqual(hessian.encode(-262144, '2.0'), utils.bytes('v2/number/-262144'));
      assert.deepEqual(hessian.encode(-262145, '2.0'), utils.bytes('v2/number/-262145'));
    });

    it('should read java number bin', function () {
      assert(hessian.decode(utils.bytes('v2/number/0'), '2.0') === 0);
      assert(hessian.decode(utils.bytes('v2/number/1'), '2.0') === 1);
      assert(hessian.decode(utils.bytes('v2/number/10'), '2.0') === 10);
      assert(hessian.decode(utils.bytes('v2/number/16'), '2.0') === 16);
      assert(hessian.decode(utils.bytes('v2/number/2047'), '2.0') === 2047);
      assert(hessian.decode(utils.bytes('v2/number/255'), '2.0') === 255);
      assert(hessian.decode(utils.bytes('v2/number/256'), '2.0') === 256);
      assert(hessian.decode(utils.bytes('v2/number/262143'), '2.0') === 262143);
      assert(hessian.decode(utils.bytes('v2/number/262144'), '2.0') === 262144);
      assert(hessian.decode(utils.bytes('v2/number/46'), '2.0') === 46);
      assert(hessian.decode(utils.bytes('v2/number/47'), '2.0') === 47);
      assert(hessian.decode(utils.bytes('v2/number/-16'), '2.0') === -16);
      assert(hessian.decode(utils.bytes('v2/number/-2048'), '2.0') === -2048);
      assert(hessian.decode(utils.bytes('v2/number/-256'), '2.0') === -256);
      assert(hessian.decode(utils.bytes('v2/number/-262144'), '2.0') === -262144);
      assert(hessian.decode(utils.bytes('v2/number/-262145'), '2.0') === -262145);
    });

    it('should read hessian 1.0 number bin', function () {
      assert(hessian.decode(utils.bytes('v1/number/0'), '2.0') === 0);
      assert(hessian.decode(utils.bytes('v1/number/1'), '2.0') === 1);
      assert(hessian.decode(utils.bytes('v1/number/10'), '2.0') === 10);
      assert(hessian.decode(utils.bytes('v1/number/16'), '2.0') === 16);
      assert(hessian.decode(utils.bytes('v1/number/2047'), '2.0') === 2047);
      assert(hessian.decode(utils.bytes('v1/number/255'), '2.0') === 255);
      assert(hessian.decode(utils.bytes('v1/number/256'), '2.0') === 256);
      assert(hessian.decode(utils.bytes('v1/number/262143'), '2.0') === 262143);
      assert(hessian.decode(utils.bytes('v1/number/262144'), '2.0') === 262144);
      assert(hessian.decode(utils.bytes('v1/number/46'), '2.0') === 46);
      assert(hessian.decode(utils.bytes('v1/number/47'), '2.0') === 47);
      assert(hessian.decode(utils.bytes('v1/number/-16'), '2.0') === -16);
      assert(hessian.decode(utils.bytes('v1/number/-2048'), '2.0') === -2048);
      assert(hessian.decode(utils.bytes('v1/number/-256'), '2.0') === -256);
      assert(hessian.decode(utils.bytes('v1/number/-262144'), '2.0') === -262144);
      assert(hessian.decode(utils.bytes('v1/number/-262145'), '2.0') === -262145);
    });

    it('should write compact integers', function () {
      // -16 ~ 47
      var buf = hessian.encode(0, '2.0');
      assert(buf.length === 1);
      assert(buf[0] === 0x90);
      assert.deepEqual(buf, new Buffer([0x90]));

      buf = hessian.encode(1, '2.0');
      assert(buf.length === 1);
      assert(buf[0] === 0x91);
      assert.deepEqual(buf, new Buffer([0x91]));

      buf = hessian.encode(-16, '2.0');
      assert(buf.length === 1);
      assert(buf[0] === 0x80);
      assert.deepEqual(buf, new Buffer([0x80]));

      buf = hessian.encode(46, '2.0');
      assert(buf.length === 1);
      assert(buf[0] === 0xbe);
      assert.deepEqual(buf, new Buffer([0xbe]));

      buf = hessian.encode(47, '2.0');
      assert(buf.length === 1);
      assert(buf[0] === 0xbf);
      assert.deepEqual(buf, new Buffer([0xbf]));

      // -2048 ~ 2047
      buf = hessian.encode(-2048, '2.0');
      assert(
Download .txt
gitextract_u4wdc7d8/

├── .github/
│   └── workflows/
│       ├── codeql.yml
│       ├── nodejs.yml
│       └── release.yml
├── .gitignore
├── .jshintignore
├── .jshintrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── benchmark/
│   ├── README.md
│   ├── buf.txt
│   ├── cache.js
│   ├── decode.js
│   ├── encode.js
│   ├── reg.js
│   └── string.js
├── index.js
├── lib/
│   ├── convert/
│   │   ├── index.js
│   │   └── java.util.locale.js
│   ├── custom_handler.js
│   ├── object.js
│   ├── utils.js
│   ├── v1/
│   │   ├── decoder.js
│   │   └── encoder.js
│   ├── v2/
│   │   ├── decoder.js
│   │   └── encoder.js
│   └── v2_optimize/
│       ├── decoder.js
│       └── encoder.js
├── package.json
└── test/
    ├── array.test.js
    ├── binary.test.js
    ├── boolean.test.js
    ├── convert.test.js
    ├── custom_handler.test.js
    ├── date.test.js
    ├── decode.circular.test.js
    ├── double.test.js
    ├── exception.test.js
    ├── fixtures/
    │   └── 4k.txt
    ├── int.test.js
    ├── list.test.js
    ├── long.test.js
    ├── map.test.js
    ├── null.test.js
    ├── object.test.js
    ├── string.test.js
    ├── utils.js
    ├── utils.test.js
    ├── v1.test.js
    ├── v2.decode.cache.test.js
    ├── v2.list.encode.test.js
    └── v2.optimize.endecode.test.js
Download .txt
SYMBOL INDEX (12 symbols across 9 files)

FILE: benchmark/string.js
  function getUTF (line 21) | function getUTF(buf) {
  function getUTF2 (line 47) | function getUTF2(buf) {

FILE: lib/custom_handler.js
  function deregisterDecodeHandler (line 7) | function deregisterDecodeHandler(className) {
  function registerDecodeHandler (line 11) | function registerDecodeHandler(className, handler) {
  function handle (line 16) | function handle(result, withType) {

FILE: lib/object.js
  function JavaExceptionError (line 77) | function JavaExceptionError(obj, withType) {

FILE: lib/v1/decoder.js
  function Decoder (line 14) | function Decoder(buf) {

FILE: lib/v1/encoder.js
  function Encoder (line 12) | function Encoder(options) {

FILE: lib/v2/decoder.js
  function Decoder (line 14) | function Decoder(buf, classCache) {

FILE: lib/v2/encoder.js
  function Encoder (line 12) | function Encoder(options) {

FILE: lib/v2_optimize/decoder.js
  function Decoder (line 7) | function Decoder(buf, classRefs) {

FILE: lib/v2_optimize/encoder.js
  function Encoder (line 7) | function Encoder(options) {
Condensed preview — 52 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (334K chars).
[
  {
    "path": ".github/workflows/codeql.yml",
    "chars": 2943,
    "preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
  },
  {
    "path": ".github/workflows/nodejs.yml",
    "chars": 288,
    "preview": "name: CI\n\non:\n  push:\n    branches: [ master, 1.x ]\n\n  pull_request:\n    branches: [ master, 1.x ]\n\n  workflow_dispatch:"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 314,
    "preview": "name: Release\n\non:\n  push:\n    branches: [ master ]\n\n  workflow_dispatch: {}\n\njobs:\n  release:\n    name: Node.js\n    use"
  },
  {
    "path": ".gitignore",
    "chars": 132,
    "preview": "lib-cov\n*.seed\n*.log\n*.csv\n*.out\n*.pid\n*.gz\n\npids\nlogs\nresults\n\nnpm-debug.log\nnode_modules\n\n.DS_Store\ncoverage.html\ncove"
  },
  {
    "path": ".jshintignore",
    "chars": 36,
    "preview": "node_modules/\ncoverage/\n.tmp/\n.git/\n"
  },
  {
    "path": ".jshintrc",
    "chars": 6087,
    "preview": "{\n    // JSHint Default Configuration File (as on JSHint website)\n    // See http://jshint.com/docs/ for more details\n\n "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 11199,
    "preview": "# Changelog\n\n## [2.11.0](https://github.com/node-modules/hessian.js/compare/v2.10.1...v2.11.0) (2023-04-16)\n\n\n### Featur"
  },
  {
    "path": "LICENSE",
    "chars": 1098,
    "preview": "The MIT License (MIT)\n\nCopyright (c) node-modules and other contributors.\n\nPermission is hereby granted, free of charge,"
  },
  {
    "path": "README.md",
    "chars": 13449,
    "preview": "hessian.js\n=========\n\n[![NPM version][npm-image]][npm-url]\n[![build status][github-action-image]][github-action-url]\n[!["
  },
  {
    "path": "benchmark/README.md",
    "chars": 2867,
    "preview": "benchmark result\n----------\n\n```\nnode benchmark/encode.js\n\n  Hessian Encode Benchmark\n  node version: v0.11.12, date: Tu"
  },
  {
    "path": "benchmark/cache.js",
    "chars": 1239,
    "preview": "'use strict';\n\nvar Benchmark = require('benchmark');\nvar benchmarks = require('beautify-benchmark');\nvar path = require("
  },
  {
    "path": "benchmark/decode.js",
    "chars": 8038,
    "preview": "'use strict';\n\nvar ByteBuffer = require('byte');\nvar Benchmark = require('benchmark');\nvar benchmarks = require('beautif"
  },
  {
    "path": "benchmark/encode.js",
    "chars": 6658,
    "preview": "'use strict';\n\nvar ByteBuffer = require('byte');\nvar Benchmark = require('benchmark');\nvar benchmarks = require('beautif"
  },
  {
    "path": "benchmark/reg.js",
    "chars": 1195,
    "preview": "'use strict';\n\nvar Benchmark = require('benchmark');\nvar benchmarks = require('beautify-benchmark');\n\nvar suite = new Be"
  },
  {
    "path": "benchmark/string.js",
    "chars": 3980,
    "preview": "'use strict';\n\nconst Benchmark = require('benchmark');\nconst benchmarks = require('beautify-benchmark');\nconst assert = "
  },
  {
    "path": "index.js",
    "chars": 1420,
    "preview": "'use strict';\n\nvar EncoderV1 = exports.EncoderV1 = exports.Encoder = require('./lib/v1/encoder');\nvar DecoderV1 = export"
  },
  {
    "path": "lib/convert/index.js",
    "chars": 90,
    "preview": "'use strict';\n\nmodule.exports = {\n  'java.util.Locale': require('./java.util.locale'),\n};\n"
  },
  {
    "path": "lib/convert/java.util.locale.js",
    "chars": 142,
    "preview": "'use strict';\n\nmodule.exports = function(obj) {\n  return {\n    $class: 'com.caucho.hessian.io.LocaleHandle',\n    $: { va"
  },
  {
    "path": "lib/custom_handler.js",
    "chars": 647,
    "preview": "'use strict';\n\nvar assert = require('assert');\n\nvar handlers = {};\n\nfunction deregisterDecodeHandler(className) {\n\tdelet"
  },
  {
    "path": "lib/object.js",
    "chars": 3819,
    "preview": "'use strict';\n\nvar util = require('util');\n\nexports.DEFAULT_CLASSNAME = {\n  boolean: 'boolean',\n  int: 'int',\n  long: 'l"
  },
  {
    "path": "lib/utils.js",
    "chars": 1675,
    "preview": "'use strict';\n\nvar debug = require('util').debuglog('hessian.js:utils');\nvar Long = require('long');\nvar object = requir"
  },
  {
    "path": "lib/v1/decoder.js",
    "chars": 12824,
    "preview": "'use strict';\n\nvar debug = require('util').debuglog('hessian:v1:decoder');\nvar ByteBuffer = require('byte');\nvar is = re"
  },
  {
    "path": "lib/v1/encoder.js",
    "chars": 12110,
    "preview": "'use strict';\n\nvar debug = require('util').debuglog('hessian:v1:encoder');\nvar utility = require('utility');\nvar ByteBuf"
  },
  {
    "path": "lib/v2/decoder.js",
    "chars": 21831,
    "preview": "'use strict';\n\nvar debug = require('util').debuglog('hessian:v2:decoder');\nvar util = require('util');\nvar is = require("
  },
  {
    "path": "lib/v2/encoder.js",
    "chars": 16665,
    "preview": "'use strict';\n\nvar debug = require('util').debuglog('hessian:v2:encoder');\nvar is = require('is-type-of');\nvar util = re"
  },
  {
    "path": "lib/v2_optimize/decoder.js",
    "chars": 484,
    "preview": "'use strict';\n\nvar util = require('util');\nvar DecoderV2 = require('../v2/decoder');\nvar DecoderV1 = require('../v1/deco"
  },
  {
    "path": "lib/v2_optimize/encoder.js",
    "chars": 547,
    "preview": "'use strict';\n\nvar util = require('util');\nvar EncoderV2 = require('../v2/encoder');\nvar EncoderV1 = require('../v1/enco"
  },
  {
    "path": "package.json",
    "chars": 1282,
    "preview": "{\n  \"name\": \"hessian.js\",\n  \"version\": \"2.11.0\",\n  \"description\": \"Hessian Serialization written by pure JavaScript, sup"
  },
  {
    "path": "test/array.test.js",
    "chars": 1356,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\n\ndescribe('array.test.js', function () {"
  },
  {
    "path": "test/binary.test.js",
    "chars": 7396,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst utils = require('./utils');\n\ndescr"
  },
  {
    "path": "test/boolean.test.js",
    "chars": 836,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\n\ndescribe('boolean.test.js', function ()"
  },
  {
    "path": "test/convert.test.js",
    "chars": 595,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst java = require('js-to-java');\nconst hessian = require('..');\n\ndes"
  },
  {
    "path": "test/custom_handler.test.js",
    "chars": 4799,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst supportES6Map = require('../lib/ut"
  },
  {
    "path": "test/date.test.js",
    "chars": 4972,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst utils = require('./utils');\n\ndescr"
  },
  {
    "path": "test/decode.circular.test.js",
    "chars": 1575,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst utils = require('./utils');\n\ndescr"
  },
  {
    "path": "test/double.test.js",
    "chars": 15602,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst java = require('js-to-java');\nconst hessian = require('..');\ncons"
  },
  {
    "path": "test/exception.test.js",
    "chars": 6068,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst utils = require('./utils');\n\ndescr"
  },
  {
    "path": "test/fixtures/4k.txt",
    "chars": 9732,
    "preview": "/*!\n * hessian.js - test/double.test.js\n *\n * Copyright(c) 2014\n * MIT Licensed\n *\n * Authors:\n *   fengmk2 <fengmk2@gma"
  },
  {
    "path": "test/int.test.js",
    "chars": 11201,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst utils = require('./utils');\n\ndescr"
  },
  {
    "path": "test/list.test.js",
    "chars": 8506,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst java = require('js-to-java');\nconst hessian = require('..');\ncons"
  },
  {
    "path": "test/long.test.js",
    "chars": 20167,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst java = require('js-to-java');\nconst Long = require('long');\nconst"
  },
  {
    "path": "test/map.test.js",
    "chars": 16826,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst utils = require('./utils');\nconst "
  },
  {
    "path": "test/null.test.js",
    "chars": 576,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\n\ndescribe('null.test.js', function () {\n"
  },
  {
    "path": "test/object.test.js",
    "chars": 23060,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst utils = require('./utils');\nconst "
  },
  {
    "path": "test/string.test.js",
    "chars": 14745,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst utils = require('./utils');\n\ndescr"
  },
  {
    "path": "test/utils.js",
    "chars": 325,
    "preview": "'use strict';\n\nvar fs = require('fs');\nvar path = require('path');\nvar fixtures = path.join(__dirname, 'fixtures');\n\nexp"
  },
  {
    "path": "test/utils.test.js",
    "chars": 428,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst utils = require('../lib/utils');\n\ndescribe('utils.test.js', funct"
  },
  {
    "path": "test/v1.test.js",
    "chars": 20955,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst fs = require('fs');\nconst path = require('path');\nconst hessian ="
  },
  {
    "path": "test/v2.decode.cache.test.js",
    "chars": 10025,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst utils = require('./utils');\nconst "
  },
  {
    "path": "test/v2.list.encode.test.js",
    "chars": 5602,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst java = require('js-to-java');\nconst hessian = require('..');\n\ndes"
  },
  {
    "path": "test/v2.optimize.endecode.test.js",
    "chars": 2208,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst hessian = require('..');\nconst DecoderV2 = require('../lib/v2_opt"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the node-modules/hessian.js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 52 files (313.1 KB), approximately 97.4k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!