weka.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /* jshint esversion: 6 */
  2. // Experimental
  3. var weka = weka || {};
  4. var json = json || require('./json');
  5. var java = {};
  6. weka.ModelFactory = class {
  7. match(context) {
  8. try {
  9. const stream = context.stream;
  10. if (stream.length >= 5) {
  11. const signature = [ 0xac, 0xed ];
  12. if (stream.peek(2).every((value, index) => value === signature[index])) {
  13. const reader = new java.io.InputObjectStream(stream);
  14. const obj = reader.read();
  15. if (obj && obj.$class && obj.$class.name) {
  16. return true;
  17. }
  18. }
  19. }
  20. }
  21. catch (err) {
  22. // continue regardless of error
  23. }
  24. return false;
  25. }
  26. open(context) {
  27. return Promise.resolve().then(() => {
  28. const reader = new java.io.InputObjectStream(context.stream);
  29. const obj = reader.read();
  30. throw new weka.Error("Unsupported type '" + obj.$class.name + "'.");
  31. });
  32. }
  33. };
  34. weka.Error = class extends Error {
  35. constructor(message) {
  36. super(message);
  37. this.name = 'Error loading Weka model.';
  38. }
  39. };
  40. java.io = {};
  41. java.io.InputObjectStream = class {
  42. constructor(stream) {
  43. // Object Serialization Stream Protocol
  44. // https://www.cis.upenn.edu/~bcpierce/courses/629/jdkdocs/guide/serialization/spec/protocol.doc.html
  45. if (stream.length < 5) {
  46. throw new java.io.Error('Invalid stream size');
  47. }
  48. const signature = [ 0xac, 0xed ];
  49. if (!stream.peek(2).every((value, index) => value === signature[index])) {
  50. throw new java.io.Error('Invalid stream signature');
  51. }
  52. this._reader = new java.io.InputObjectStream.BinaryReader(stream.peek());
  53. this._references = [];
  54. this._reader.skip(2);
  55. const version = this._reader.uint16();
  56. if (version !== 0x0005) {
  57. throw new java.io.Error("Unsupported version '" + version + "'.");
  58. }
  59. }
  60. read() {
  61. return this._object();
  62. }
  63. _object() {
  64. const code = this._reader.byte();
  65. switch (code) {
  66. case 0x73: { // TC_OBJECT
  67. const obj = {};
  68. obj.$class = this._classDesc();
  69. this._newHandle(obj);
  70. this._classData(obj);
  71. return obj;
  72. }
  73. case 0x74: { // TC_STRING
  74. return this._newString(false);
  75. }
  76. }
  77. throw new java.io.Error("Unsupported code '" + code + "'.");
  78. }
  79. _classDesc() {
  80. const code = this._reader.byte();
  81. switch (code) {
  82. case 0x72: // TC_CLASSDESC
  83. this._reader.skip(-1);
  84. return this._newClassDesc();
  85. case 0x71: // TC_REFERENCE
  86. return this._references[this._reader.uint32() - 0x7e0000];
  87. case 0x70: // TC_NULL
  88. this._reader.byte();
  89. return null;
  90. }
  91. throw new java.io.Error("Unsupported code '" + code + "'.");
  92. }
  93. _newClassDesc() {
  94. const code = this._reader.byte();
  95. switch (code) {
  96. case 0x72: { // TC_CLASSDESC
  97. const classDesc = {};
  98. classDesc.name = this._reader.string(),
  99. classDesc.id = this._reader.uint64().toString();
  100. this._newHandle(classDesc);
  101. classDesc.flags = this._reader.byte();
  102. classDesc.fields = [];
  103. const count = this._reader.uint16();
  104. for (let i = 0; i < count; i++) {
  105. const field = {};
  106. field.type = String.fromCharCode(this._reader.byte());
  107. field.name = this._reader.string();
  108. if (field.type === '[' || field.type === 'L') {
  109. field.classname = this._object();
  110. }
  111. classDesc.fields.push(field);
  112. }
  113. if (this._reader.byte() !== 0x78) {
  114. throw new java.io.Error('Expected TC_ENDBLOCKDATA.');
  115. }
  116. classDesc.superClass = this._classDesc();
  117. return classDesc;
  118. }
  119. case 0x7D: // TC_PROXYCLASSDESC
  120. break;
  121. }
  122. throw new java.io.Error("Unsupported code '" + code + "'.");
  123. }
  124. _classData(/* obj */) {
  125. /*
  126. const classname = obj.$class.name;
  127. let flags = obj.$class.flags;
  128. let superClass = obj.$class.superClass;
  129. while (superClass) {
  130. flags |= superClass.flags;
  131. superClass = superClass.superClass;
  132. }
  133. if (flags & 0x02) { // SC_SERIALIZABLE
  134. debugger;
  135. var customObject = objects[classname];
  136. var hasReadObjectMethod = customObject && customObject.readObject;
  137. if (flags & 0x01) { // SC_WRITE_METHOD
  138. if (!hasReadObjectMethod) {
  139. throw new Error('Class "'+ classname + '" dose not implement readObject()');
  140. }
  141. customObject.readObject(this, obj);
  142. if (this._reader.byte() !== 0x78) { // TC_ENDBLOCKDATA
  143. throw new java.io.Error('Expected TC_ENDBLOCKDATA.');
  144. }
  145. }
  146. else {
  147. if (hasReadObjectMethod) {
  148. customObject.readObject(this, obj);
  149. if (this._reader.byte() !== 0x78) { // TC_ENDBLOCKDATA
  150. throw new java.io.Error('Expected TC_ENDBLOCKDATA.');
  151. }
  152. }
  153. else {
  154. this._nowrclass(obj);
  155. }
  156. }
  157. }
  158. else if (flags & 0x04) { // SC_EXTERNALIZABLE
  159. if (flags & 0x08) { // SC_BLOCK_DATA
  160. this._objectAnnotation(obj);
  161. }
  162. else {
  163. this._externalContents();
  164. }
  165. }
  166. else {
  167. throw new Error('Illegal flags: ' + flags);
  168. }
  169. */
  170. }
  171. _newString(long) {
  172. const value = this._reader.string(long);
  173. this._newHandle(value);
  174. return value;
  175. }
  176. _newHandle(obj) {
  177. this._references.push(obj);
  178. }
  179. };
  180. java.io.InputObjectStream.BinaryReader = class {
  181. constructor(buffer) {
  182. this._buffer = buffer;
  183. this._position = 0;
  184. this._length = buffer.length;
  185. this._view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  186. this._decoder = new TextDecoder('utf-8');
  187. }
  188. skip(offset) {
  189. this._position += offset;
  190. if (this._position > this._end) {
  191. throw new java.io.Error('Expected ' + (this._position - this._end) + ' more bytes. The file might be corrupted. Unexpected end of file.');
  192. }
  193. }
  194. byte() {
  195. const position = this._position;
  196. this.skip(1);
  197. return this._buffer[position];
  198. }
  199. uint16() {
  200. const position = this._position;
  201. this.skip(2);
  202. return this._view.getUint16(position, false);
  203. }
  204. uint32() {
  205. const position = this._position;
  206. this.skip(4);
  207. return this._view.getUint32(position, false);
  208. }
  209. uint64() {
  210. const position = this._position;
  211. this.skip(8);
  212. return this._view.getUint64(position, false);
  213. }
  214. string(long) {
  215. const size = long ? this.uint64().toNumber() : this.uint16();
  216. const position = this._position;
  217. this.skip(size);
  218. return this._decoder.decode(this._buffer.subarray(position, this._position));
  219. }
  220. };
  221. java.io.Error = class extends Error {
  222. constructor(message) {
  223. super(message);
  224. this.name = 'Error loading Object Serialization Stream Protocol.';
  225. }
  226. };
  227. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  228. module.exports.ModelFactory = weka.ModelFactory;
  229. }