parser.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. /*jshint esversion: 6 */
  2. const DNA1 = 826363460;
  3. const ENDB = 1111772741;
  4. /* Note: Blender coordinates treat the Z axis as the vertical an Y as depth. */
  5. module.exports = (function(unzipper) {
  6. //web worker not functional in this version
  7. USE_WEBWORKER = false;
  8. var worker = null,
  9. FR = new FileReader(),
  10. return_object = {
  11. loadBlendFromArrayBuffer: function(array_buffer) {
  12. return_object.ready = false;
  13. if (USE_WEBWORKER) {
  14. worker.postMessage(array_buffer, array_buffer);
  15. } else {
  16. worker.onmessage({
  17. data: array_buffer
  18. });
  19. }
  20. },
  21. loadBlendFromBlob: function(blob) {
  22. FR.onload = function() {
  23. return_object.loadBlendFromArrayBuffer(this.result);
  24. };
  25. FR.readAsArrayBuffer(blob);
  26. },
  27. ready: true,
  28. onParseReady: function() {},
  29. };
  30. worker = new worker_code();
  31. worker.postMessage = function(message) {
  32. return_object.onParseReady(message);
  33. };
  34. function worker_code() {
  35. "use strict";
  36. var data = null,
  37. _data = null,
  38. BIG_ENDIAN = false,
  39. pointer_size = 0,
  40. struct_names = [],
  41. offset = 0,
  42. working_blend_file = null,
  43. current_SDNA_template = null,
  44. templates = {},
  45. finished_objects = [],
  46. FILE = null,
  47. ERROR = null,
  48. AB = null;
  49. function parseFile(msg) {
  50. var self = this;
  51. if (typeof msg.data == "object") {
  52. // reset global variables
  53. AB = null;
  54. data = null;
  55. BIG_ENDIAN = false;
  56. pointer_size = 0;
  57. struct_names = [];
  58. offset = 0;
  59. working_blend_file = null;
  60. finished_objects = [];
  61. current_SDNA_template = null;
  62. // set data
  63. _data = msg.data;
  64. AB = _data.slice();
  65. data = new DataView(_data);
  66. FILE = new BLENDER_FILE(AB);
  67. //start parsing
  68. readFile();
  69. //export parsed data
  70. self.postMessage(FILE, ERROR);
  71. }
  72. }
  73. /*
  74. Export object for a parsed __blender_file__.
  75. */
  76. var BLENDER_FILE = function(AB) {
  77. this.AB = AB;
  78. //this.double = new Float64Array(AB);
  79. this.byte = new Uint8Array(AB);
  80. this.dv = new DataView(AB);
  81. this.objects = {};
  82. this.memory_lookup = {},
  83. this.object_array = [];
  84. this.template = null;
  85. };
  86. BLENDER_FILE.prototype = {
  87. addObject: function(obj) {
  88. this.object_array.push(obj);
  89. if (!this.objects[obj.blender_name]) this.objects[obj.blender_name] = [];
  90. this.objects[obj.blender_name].push(obj);
  91. },
  92. getPointer: function(offset) {
  93. var pointerLow = this.dv.getUint32(offset, this.template.endianess);
  94. if (this.template.pointer_size > 4) {
  95. var pointerHigh = this.dv.getUint32(offset + 4, this.template.endianess);
  96. if (this.template.endianess) {
  97. return (pointerLow) + "l|h" + pointerHigh;
  98. } else {
  99. return (pointerHigh) + "h|l" + pointerLow;
  100. }
  101. } else {
  102. return pointerLow;
  103. }
  104. }
  105. };
  106. self.onmessage = parseFile;
  107. this.onmessage = parseFile;
  108. /*
  109. These functions map offsets in the blender __blender_file__ to basic types (byte,short,int,float) through TypedArrays;
  110. This allows the underlying binary data to be changed.
  111. */
  112. function float64Prop(offset, Blender_Array_Length, length) {
  113. return {
  114. get: function() {
  115. return (Blender_Array_Length > 1) ?
  116. new Float64Array(this.__blender_file__.AB, this.__data_address__ + offset, length) :
  117. this.__blender_file__.dv.getFloat64(this.__data_address__ + offset, this.__blender_file__.template.endianess);
  118. },
  119. set: function(float) {
  120. if (Blender_Array_Length > 1) {} else {
  121. this.__blender_file__.dv.setFloat64(this.__data_address__ + offset, float, this.__blender_file__.template.endianess);
  122. }
  123. },
  124. };
  125. }
  126. function floatProp(offset, Blender_Array_Length, length) {
  127. return {
  128. get: function() {
  129. return (Blender_Array_Length > 1) ?
  130. new Float32Array(this.__blender_file__.AB, this.__data_address__ + offset, length) :
  131. this.__blender_file__.dv.getFloat32(this.__data_address__ + offset, this.__blender_file__.template.endianess);
  132. },
  133. set: function(float) {
  134. if (Blender_Array_Length > 1) {} else {
  135. this.__blender_file__.dv.setFloat32(this.__data_address__ + offset, float, this.__blender_file__.template.endianess);
  136. }
  137. },
  138. };
  139. }
  140. function intProp(offset, Blender_Array_Length, length) {
  141. return {
  142. get: function() {
  143. return (Blender_Array_Length > 1) ?
  144. new Int32Array(this.__blender_file__.AB, this.__data_address__ + offset, length) :
  145. this.__blender_file__.dv.getInt32(this.__data_address__ + offset, this.__blender_file__.template.endianess);
  146. },
  147. set: function(int) {
  148. if (Blender_Array_Length > 1) {} else {
  149. this.__blender_file__.dv.setInt32(this.__data_address__ + offset, float, this.__blender_file__.template.endianess);
  150. }
  151. },
  152. };
  153. }
  154. function uIntProp(offset, Blender_Array_Length, length) {
  155. return {
  156. get: function() {
  157. return (Blender_Array_Length > 1) ?
  158. new Uint32Array(this.__blender_file__.AB, this.__data_address__ + offset, length) :
  159. this.__blender_file__.dv.getUint32(this.__data_address__ + offset, this.__blender_file__.template.endianess);
  160. },
  161. set: function(int) {
  162. if (Blender_Array_Length > 1) {} else {
  163. this.__blender_file__.dv.setUint32(this.__data_address__ + offset, float, this.__blender_file__.template.endianess);
  164. }
  165. },
  166. };
  167. }
  168. function shortProp(offset, Blender_Array_Length, length) {
  169. return {
  170. get: function() {
  171. return (Blender_Array_Length > 1) ?
  172. new Int16Array(this.__blender_file__.AB, this.__data_address__ + offset, length) :
  173. this.__blender_file__.dv.getInt16(this.__data_address__ + offset, this.__blender_file__.template.endianess);
  174. },
  175. set: function(float) {
  176. if (Blender_Array_Length > 1) {} else {
  177. this.__blender_file__.dv.setInt16(this.__data_address__ + offset, float, this.__blender_file__.template.endianess);
  178. }
  179. },
  180. };
  181. }
  182. var uShortProp = (offset, Blender_Array_Length, length) => {
  183. return {
  184. get: function() {
  185. return (Blender_Array_Length > 1) ?
  186. new Uint16Array(this.__blender_file__.AB, this.__data_address__ + offset, length) :
  187. this.__blender_file__.dv.getUint16(this.__data_address__ + offset, this.__blender_file__.template.endianess);
  188. },
  189. set: function(float) {
  190. if (Blender_Array_Length > 1) {} else {
  191. this.__blender_file__.dv.setUint16(this.__data_address__ + offset, float, this.__blender_file__.template.endianess);
  192. }
  193. },
  194. };
  195. };
  196. function charProp(offset, Blender_Array_Length, length) {
  197. return {
  198. get: function() {
  199. if (Blender_Array_Length > 1) {
  200. let start = this.__data_address__ + offset;
  201. let end = start;
  202. let buffer_guard = 0;
  203. while (this.__blender_file__.byte[end] != 0 && buffer_guard++ < length) end++;
  204. return toString(this.__blender_file__.AB, start, end);
  205. }
  206. return this.__blender_file__.byte[(this.__data_address__ + offset)];
  207. },
  208. set: function(byte) {
  209. if (Blender_Array_Length > 1) {
  210. var string = byte + "",
  211. i = 0,
  212. l = string.length;
  213. while (i < length) {
  214. if (i < l) {
  215. this.__blender_file__.byte[(this.__data_address__ + offset + i)] = string.charCodeAt(i) | 0;
  216. } else {
  217. this.__blender_file__.byte[(this.__data_address__ + offset + i)] = 0;
  218. }
  219. i++;
  220. }
  221. } else {
  222. this.__blender_file__.byte[(this.__data_address__ + offset)] = byte | 0;
  223. }
  224. }
  225. };
  226. }
  227. function pointerProp2(offset) {
  228. return {
  229. get: function() {
  230. let pointer = this.__blender_file__.getPointer(this.__data_address__ + offset, this.__blender_file__);
  231. var link = this.__blender_file__.memory_lookup[pointer];
  232. var results = [];
  233. if (link) {
  234. var address = link.__data_address__;
  235. let j = 0;
  236. while (true) {
  237. pointer = this.__blender_file__.getPointer(address + j * 8, this.__blender_file__);
  238. let obj = this.__blender_file__.memory_lookup[pointer];
  239. if (!obj) break;
  240. results.push(obj);
  241. j++;
  242. }
  243. };
  244. return results;
  245. },
  246. set: function() {}
  247. };
  248. }
  249. function pointerProp(offset, Blender_Array_Length, length) {
  250. return {
  251. get: function() {
  252. if (Blender_Array_Length > 1) {
  253. let array = [];
  254. let j = 0;
  255. let off = offset;
  256. while (j < Blender_Array_Length) {
  257. let pointer = this.__blender_file__.getPointer(this.__data_address__ + off, this.__blender_file__);
  258. array.push(this.__blender_file__.memory_lookup[pointer]);
  259. off += length;
  260. j++;
  261. }
  262. return array;
  263. } else {
  264. let pointer = this.__blender_file__.getPointer(this.__data_address__ + offset, this.__blender_file__);
  265. return this.__blender_file__.memory_lookup[pointer];
  266. }
  267. },
  268. set: function() {}
  269. };
  270. }
  271. function compileProp(obj, name, type, offset, array_size, IS_POINTER, pointer_size, length) {
  272. if (!IS_POINTER) {
  273. switch (type) {
  274. case "double":
  275. Object.defineProperty(obj, name, float64Prop(offset, array_size, length >> 3));
  276. break;
  277. case "float":
  278. Object.defineProperty(obj, name, floatProp(offset, array_size, length >> 2));
  279. break;
  280. case "int":
  281. Object.defineProperty(obj, name, intProp(offset, array_size, length >> 2));
  282. break;
  283. case "short":
  284. case "ushort":
  285. Object.defineProperty(obj, name, shortProp(offset, array_size, length >> 1));
  286. break;
  287. case "char":
  288. case "uchar":
  289. Object.defineProperty(obj, name, charProp(offset, array_size, length));
  290. break;
  291. default:
  292. //compile list to
  293. obj[name] = {};
  294. obj.__list__.push(name, type, length, offset, array_size, IS_POINTER);
  295. }
  296. obj._length += length;
  297. offset += length;
  298. } else {
  299. Object.defineProperty(obj, name, pointerProp(offset, array_size, pointer_size));
  300. offset += pointer_size * array_size;
  301. }
  302. return offset;
  303. }
  304. //Store final DNA structs
  305. var MASTER_SDNA_SCHEMA = function(version) {
  306. this.version = version;
  307. this.SDNA_SET = false;
  308. this.byte_size = 0;
  309. this.struct_index = 0;
  310. this.structs = {};
  311. this.SDNA = {};
  312. this.endianess = false;
  313. };
  314. MASTER_SDNA_SCHEMA.prototype = {
  315. getSDNAStructureConstructor: function(name, struct) {
  316. if (struct) {
  317. var blen_struct = Function("function " + name + "(){}; return " + name)();
  318. blen_struct.prototype = new BLENDER_STRUCTURE();
  319. blen_struct.prototype.blender_name = name;
  320. blen_struct.prototype.__pointers = [];
  321. blen_struct.prototype.__list__ = [];
  322. var offset = 0;
  323. //Create properties of struct
  324. for (var i = 0; i < struct.length; i += 3) {
  325. var _name = struct[i],
  326. n = _name,
  327. type = struct[i + 1],
  328. length = struct[i + 2],
  329. array_length = 0,
  330. match = null,
  331. Blender_Array_Length = 1,
  332. Suparray_match = 1,
  333. PointerToArray = false,
  334. Pointer_Match = 0;
  335. var DNA = this.SDNA[name] = {
  336. constructor: blen_struct
  337. };
  338. let original_name = _name;
  339. //mini type parser
  340. if ((match = _name.match(/(\*?)(\*?)(\w+)(\[(\w*)\])?(\[(\w*)\])?/))) {
  341. //base name
  342. _name = match[3];
  343. //pointer type
  344. if (match[1]) {
  345. Pointer_Match = 10;
  346. blen_struct.prototype.__pointers.push(_name);
  347. }
  348. if (match[2]) {
  349. PointerToArray = true;
  350. }
  351. //arrays
  352. if (match[4]) {
  353. if (match[6]) {
  354. Suparray_match = parseInt(match[5]);
  355. Blender_Array_Length = parseInt(match[7]);
  356. } else {
  357. Blender_Array_Length = parseInt(match[5]);
  358. }
  359. }
  360. array_length = Blender_Array_Length * length;
  361. length = array_length * Suparray_match;
  362. }
  363. DNA[n] = {
  364. type: type,
  365. length: length,
  366. isArray: (Blender_Array_Length > 0),
  367. };
  368. if (PointerToArray) {
  369. Object.defineProperty(blen_struct.prototype, _name, pointerProp2(offset));
  370. offset += pointer_size;
  371. } else if (Suparray_match > 1) {
  372. var array_names = new Array(Suparray_match);
  373. //construct sub_array object that will return the correct structs
  374. for (var j = 0; j < Suparray_match; j++) {
  375. let array_name_ = `__${_name}[${j}]__`;
  376. array_names[j] = array_name_;
  377. offset = compileProp(blen_struct.prototype, array_name_, type, offset, Blender_Array_Length, Pointer_Match, pointer_size, array_length);
  378. }
  379. Object.defineProperty(blen_struct.prototype, _name, {
  380. get: (function(array_names) {
  381. return function() {
  382. var array = [];
  383. for (var i = 0; i < array_names.length; i++) {
  384. array.push(this[array_names[i]]);
  385. }
  386. return array;
  387. };
  388. })(array_names)
  389. });
  390. } else {
  391. offset = compileProp(blen_struct.prototype, _name, type, offset, Blender_Array_Length, Pointer_Match, pointer_size, length);
  392. }
  393. }
  394. return this.SDNA[name].constructor;
  395. } else {
  396. if (!this.SDNA[name]) {
  397. return null;
  398. }
  399. return this.SDNA[name].constructor;
  400. }
  401. }
  402. };
  403. var BLENDER_STRUCTURE = function() {
  404. this.__blender_file__ = null;
  405. this.__list__ = null;
  406. this.__super_array_list__ = null;
  407. this.blender_name = "";
  408. this.__pointers = null;
  409. this.address = null;
  410. this.length = 0;
  411. this.__data_address__ = 0;
  412. this.blender_name = "";
  413. this._length = 0;
  414. };
  415. /*
  416. Returns a pre-constructed BLENDER_STRUCTURE or creates a new BLENDER_STRUCTURE to match the DNA struct type
  417. */
  418. var pointer_function = (pointer) => () => {
  419. return FILE.memory_lookup[pointer];
  420. };
  421. function getPointer(offset) {
  422. var pointerLow = data.getUint32(offset, BIG_ENDIAN);
  423. if (pointer_size > 4) {
  424. var pointerHigh = data.getUint32(offset + 4, BIG_ENDIAN);
  425. if (BIG_ENDIAN) {
  426. return (pointerLow) + "" + pointerHigh;
  427. } else {
  428. return (pointerHigh) + "" + pointerLow;
  429. }
  430. } else {
  431. return pointerLow;
  432. }
  433. }
  434. BLENDER_STRUCTURE.prototype = {
  435. setData: function(pointer, _data_offset, data_block_length, BLENDER_FILE) {
  436. if (this.__list__ === null) return this;
  437. BLENDER_FILE.addObject(this);
  438. this.__blender_file__ = BLENDER_FILE;
  439. var struct = this.__list__,
  440. j = 0,
  441. i = 0,
  442. obj, name = "",
  443. type, length, Blender_Array_Length, Pointer_Match, offset, constructor;
  444. this.__data_address__ = _data_offset;
  445. if (struct === null) return this;
  446. for (i = 0; i < struct.length; i += 6) {
  447. obj = null;
  448. name = struct[i];
  449. type = struct[i + 1];
  450. Blender_Array_Length = struct[i + 4];
  451. Pointer_Match = struct[i + 5];
  452. offset = this.__data_address__ + struct[i + 3];
  453. if (Blender_Array_Length > 1) {
  454. this[name] = [];
  455. j = 0;
  456. while (j < Blender_Array_Length) {
  457. if (current_SDNA_template.getSDNAStructureConstructor(type)) {
  458. constructor = current_SDNA_template.getSDNAStructureConstructor(type);
  459. this[name].push((new constructor()).setData(0, offset, offset + length / Blender_Array_Length, BLENDER_FILE));
  460. } else this[name].push(null);
  461. offset += length / Blender_Array_Length;
  462. j++;
  463. }
  464. } else {
  465. if (current_SDNA_template.getSDNAStructureConstructor(type)) {
  466. constructor = current_SDNA_template.getSDNAStructureConstructor(type);
  467. this[name] = (new constructor()).setData(0, offset, length + offset, BLENDER_FILE);
  468. } else this[name] = null;
  469. }
  470. }
  471. //break connection to configuration list
  472. this.__list__ = null;
  473. return this;
  474. },
  475. get aname() {
  476. if (this.id) return this.id.name.slice(2);
  477. else return undefined;
  478. }
  479. };
  480. function toString(buffer, _in, _out) {
  481. return String.fromCharCode.apply(String, new Uint8Array(buffer, _in, _out - _in));
  482. }
  483. //Begin parsing blender __blender_file__
  484. function readFile() {
  485. var count = 0;
  486. var offset2 = 0;
  487. var root = 0;
  488. var i = 0;
  489. var data_offset = 0;
  490. var sdna_index = 0;
  491. var code = "";
  492. var block_length = 0;
  493. var curr_count = 0;
  494. var curr_count2 = 0;
  495. FILE.memory_lookup = {};
  496. struct_names = [];
  497. offset = 0;
  498. // Make sure we have a .blend __blender_file__. All blend files have the first 12bytes
  499. // set with BLENDER-v### in Utf-8
  500. if (toString(_data, offset, 7) !== "BLENDER") return ERROR = "File supplied is not a .blend compatible Blender file.";
  501. // otherwise get templete from save version.
  502. offset += 7;
  503. pointer_size = ((toString(_data, offset++, offset)) == "_") ? 4 : 8;
  504. BIG_ENDIAN = toString(_data, offset++, offset) !== "V";
  505. var version = toString(_data, offset, offset + 3);
  506. //create new master template if none exist for current blender version;
  507. if (!templates[version]) {
  508. templates[version] = new MASTER_SDNA_SCHEMA(version);
  509. }
  510. current_SDNA_template = templates[version];
  511. FILE.template = current_SDNA_template;
  512. offset += 3;
  513. //Set SDNA structs if template hasn't been set.
  514. //Todo: Move the following block into the MASTER_SDNA_SCHEMA object.
  515. //*Like so:*/ current_SDNA_template.set(AB);
  516. if (!current_SDNA_template.SDNA_SET) {
  517. current_SDNA_template.endianess = BIG_ENDIAN;
  518. current_SDNA_template.pointer_size = pointer_size;
  519. //find DNA1 data block
  520. offset2 = offset;
  521. while (true) {
  522. sdna_index = data.getInt32(offset2 + pointer_size + 8, BIG_ENDIAN);
  523. code = toString(_data, offset2, offset2 + 4).replace(/\u0000/g, "");
  524. block_length = data.getInt32(offset2 + 4, true);
  525. offset2 += 16 + (pointer_size);
  526. if (code === "DNA1") {
  527. // DNA found; This is the core of the __blender_file__ and contains all the structure for the various data types used in Blender.
  528. count = 0;
  529. var types = [],
  530. fields = [],
  531. names = [],
  532. lengths = [],
  533. name = "",
  534. curr_name = "";
  535. //skip SDNA and NAME identifiers
  536. offset2 += 8;
  537. //Number of structs.
  538. count = data.getInt32(offset2, true);
  539. offset2 += 4;
  540. curr_count = 0;
  541. //Build up list of names for structs
  542. while (curr_count < count) {
  543. curr_name = "";
  544. while (data.getInt8(offset2) !== 0) {
  545. curr_name += toString(_data, offset2, offset2 + 1);
  546. offset2++;
  547. }
  548. names.push(curr_name);
  549. offset2++;
  550. curr_count++;
  551. }
  552. //Adjust for 4byte alignment
  553. if ((offset2 % 4) > 0) offset2 = (4 - (offset2 % 4)) + offset2;
  554. offset2 += 4;
  555. //Number of struct types
  556. count = data.getInt32(offset2, true);
  557. offset2 += 4;
  558. curr_count = 0;
  559. //Build up list of types
  560. while (curr_count < count) {
  561. curr_name = "";
  562. while (data.getInt8(offset2) !== 0) {
  563. curr_name += toString(_data, offset2, offset2 + 1);
  564. offset2++;
  565. }
  566. types.push(curr_name);
  567. offset2++;
  568. curr_count++;
  569. }
  570. //Adjust for 4byte alignment
  571. if ((offset2 % 4) > 0) offset2 = (4 - (offset2 % 4)) + offset2;
  572. offset2 += 4;
  573. curr_count = 0;
  574. //Build up list of byte lengths for types
  575. while (curr_count < count) {
  576. lengths.push(data.getInt16(offset2, BIG_ENDIAN));
  577. offset2 += 2;
  578. curr_count++;
  579. }
  580. //Adjust for 4byte alignment
  581. if ((offset2 % 4) > 0) offset2 = (4 - (offset2 % 4)) + offset2;
  582. offset2 += 4;
  583. //Number of structures
  584. var structure_count = data.getInt32(offset2, BIG_ENDIAN);
  585. offset2 += 4;
  586. curr_count = 0;
  587. //Create constructor objects from list of SDNA structs
  588. while (curr_count < structure_count) {
  589. var struct_name = types[data.getInt16(offset2, BIG_ENDIAN)];
  590. offset2 += 2;
  591. obj = [];
  592. count = data.getInt16(offset2, BIG_ENDIAN);
  593. offset2 += 2;
  594. curr_count2 = 0;
  595. struct_names.push(struct_name);
  596. //Fill an array with name, type, and length for each SDNA struct property
  597. while (curr_count2 < count) {
  598. obj.push(names[data.getInt16(offset2 + 2, BIG_ENDIAN)], types[data.getInt16(offset2, BIG_ENDIAN)], lengths[data.getInt16(offset2, BIG_ENDIAN)]);
  599. offset2 += 4;
  600. curr_count2++;
  601. }
  602. //Create a SDNA constructor by passing [type,name,lenth] array as second argument
  603. current_SDNA_template.getSDNAStructureConstructor(struct_name, obj);
  604. curr_count++;
  605. }
  606. current_SDNA_template.SDNA_SET = true;
  607. current_SDNA_template.SDNA_NAMES = struct_names;
  608. break;
  609. }
  610. offset2 += block_length;
  611. }
  612. }
  613. //parse the rest of the data, starting back at the top.
  614. //TODO: turn into "on-demand" parsing.
  615. while (true) {
  616. if ((offset % 4) > 0) {
  617. offset = (4 - (offset % 4)) + offset;
  618. }
  619. data_offset = offset;
  620. sdna_index = data.getInt32(offset + pointer_size + 8, BIG_ENDIAN);
  621. let code_uint = data.getUint32(offset, BIG_ENDIAN);
  622. offset2 = offset + 16 + (pointer_size);
  623. offset += data.getInt32(offset + 4, true) + 16 + (pointer_size);
  624. if (code_uint === DNA1); //skip - already processed at this point
  625. else if (code_uint === ENDB) break; //end of __blender_file__ found
  626. else {
  627. //Create a Blender object using a constructor template from current_SDNA_template
  628. var data_start = data_offset + pointer_size + 16;
  629. //Get a SDNA constructor by name;
  630. var constructor = current_SDNA_template.getSDNAStructureConstructor(current_SDNA_template.SDNA_NAMES[sdna_index]);
  631. var size = data.getInt32(data_offset + 4, BIG_ENDIAN);
  632. count = data.getInt32(data_offset + 12 + pointer_size, BIG_ENDIAN);
  633. if (count > 0) {
  634. var obj = new constructor();
  635. var length = constructor.prototype._length;
  636. var address = FILE.getPointer(data_offset + 8);
  637. obj.address = address + "";
  638. obj.setData(address, data_start, data_start + size, FILE);
  639. if (count > 1) {
  640. let array = [];
  641. array.push(obj);
  642. for (var u = 1; u < count; u++) {
  643. obj = new constructor();
  644. obj.setData(address, data_start + length * u, data_start + (length * u) + length, FILE);
  645. array.push(obj);
  646. }
  647. FILE.memory_lookup[address] = array;
  648. } else {
  649. FILE.memory_lookup[address] = obj;
  650. }
  651. }
  652. }
  653. }
  654. }
  655. }
  656. return return_object;
  657. });