替换原本ole.js为cfb.js
parent
d3e33c2f4a
commit
436d87c64c
113
altium_sch.html
113
altium_sch.html
|
@ -7,6 +7,8 @@
|
|||
<script type="text/javascript" src="altium_sch_document.js"></script>
|
||||
<script type="text/javascript" src="altium_sch_renderer.js"></script>
|
||||
<script type="text/javascript" src="test_schdoc.js"></script>
|
||||
<script type="text/javascript" src="cfb.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div><input type="file" id="altium-file"></input></div>
|
||||
|
@ -14,10 +16,11 @@
|
|||
<div><pre id="results"></pre></div>
|
||||
<script type="text/javascript">
|
||||
|
||||
renderSchematic(getTestFile());
|
||||
// renderSchematic(getTestFile());
|
||||
|
||||
function readSchematicFile(e)
|
||||
{
|
||||
console.log(e)
|
||||
let file = e.target.files[0];
|
||||
if (!file)
|
||||
{
|
||||
|
@ -27,20 +30,118 @@ function readSchematicFile(e)
|
|||
reader.onload = function(e)
|
||||
{
|
||||
let contents = e.target.result;
|
||||
renderSchematic(contents);
|
||||
let cfbs = window.cfb
|
||||
console.log(contents)
|
||||
var dec = new TextDecoder("utf-8");
|
||||
|
||||
let arr = Array.prototype.slice.call(new Uint8Array(contents ));
|
||||
var ss = cfbs.read(arr,{type: 'binary'});
|
||||
console.log(ss)
|
||||
var schdat = cfbs.find(ss, 'FileHeader');
|
||||
var data = schdat.content;
|
||||
let arrayBuffer = new Uint8Array(data).buffer;
|
||||
console.log(dec.decode(arrayBuffer))
|
||||
renderSchematic(arrayBuffer);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
document.getElementById('altium-file').addEventListener('change', readSchematicFile, false);
|
||||
|
||||
// ArrayBuffer转16进制字符串
|
||||
function ab2hex(buffer) {
|
||||
const hexArr = Array.prototype.map.call(
|
||||
new Uint8Array(buffer),
|
||||
function (bit) {
|
||||
return (('00' + bit.toString(16)).slice(-2) + " ")
|
||||
}
|
||||
)
|
||||
return hexArr.join('')
|
||||
}
|
||||
|
||||
function doSave(value, type, name) {
|
||||
|
||||
var blob;
|
||||
|
||||
if (typeof window.Blob == "function") {
|
||||
|
||||
blob = new Blob([value], {
|
||||
|
||||
type: type
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
var BlobBuilder = window.BlobBuilder || window.MozBlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder;
|
||||
|
||||
var bb = new BlobBuilder();
|
||||
|
||||
bb.append(value);
|
||||
|
||||
blob = bb.getBlob(type);
|
||||
|
||||
}
|
||||
|
||||
var URL = window.URL || window.webkitURL;
|
||||
|
||||
var bloburl = URL.createObjectURL(blob);
|
||||
|
||||
var anchor = document.createElement("a");
|
||||
|
||||
if ('download' in anchor) {
|
||||
|
||||
anchor.style.visibility = "hidden";
|
||||
|
||||
anchor.href = bloburl;
|
||||
|
||||
anchor.download = name;
|
||||
|
||||
document.body.appendChild(anchor);
|
||||
|
||||
var evt = document.createEvent("MouseEvents");
|
||||
|
||||
evt.initEvent("click", true, true);
|
||||
|
||||
anchor.dispatchEvent(evt);
|
||||
|
||||
document.body.removeChild(anchor);
|
||||
|
||||
} else if (navigator.msSaveBlob) {
|
||||
|
||||
navigator.msSaveBlob(blob, name);
|
||||
|
||||
} else {
|
||||
|
||||
location.href = bloburl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function arrayToAscii(strArray) {
|
||||
return strArray.flatMap(str => {
|
||||
// 將每個字符串轉換為字符數組
|
||||
return Array.from(str, char => {
|
||||
// 取得字符的Unicode編碼
|
||||
const charCode = char.charCodeAt(0);
|
||||
// 判斷是否為ASCII字符(0-127)
|
||||
if (charCode <= 127) {
|
||||
// 如果是ASCII字符,返回對應的ASCII值
|
||||
return charCode;
|
||||
} else {
|
||||
// 如果不是ASCII字符,返回null或undefined(根據需要處理)
|
||||
return null;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderSchematic(data)
|
||||
{
|
||||
let canvas = document.getElementById("canvas");
|
||||
let ole = new OLE(data);
|
||||
let fhEntry = ole.directory_entries.find((de) => de.name == "FileHeader");
|
||||
let fhData = fhEntry.read_all();
|
||||
let altiumDocument = new AltiumDocument(fhData);
|
||||
// console.log(new TextDecoder('utf-8').decod*****************e(fhData))
|
||||
let altiumDocument = new AltiumDocument(data);
|
||||
window.altiumDocument = altiumDocument;
|
||||
let renderer = new AltiumSchematicRenderer(canvas, altiumDocument);
|
||||
renderer.render();
|
||||
|
|
|
@ -45,17 +45,21 @@ class AltiumRecord
|
|||
constructor(stream, index)
|
||||
{
|
||||
this.record_index = index;
|
||||
this.stream = stream;
|
||||
this.stream = new U8Stream(stream);
|
||||
this.position = stream.u8stream_position;
|
||||
this.payload_length = stream.read_u16_le();
|
||||
this.padding = stream.read_u8();
|
||||
if (this.padding != 0)
|
||||
console.warn("Padding byte on record index " + index.toString() + " was non-zero.");
|
||||
this.record_type = stream.read_u8();
|
||||
console.warn(this.position)
|
||||
if (this.record_type != 0)
|
||||
throw new Error("Invalid record type.");
|
||||
this.data = stream.read(this.payload_length);
|
||||
this.record_id = -1;
|
||||
console.warn(this.data)
|
||||
console.log(new TextDecoder('utf-8').decode(this.data))
|
||||
|
||||
if (this.data.length > "|RECORD=255|".length)
|
||||
{
|
||||
// check if this starts with |RECORD=
|
||||
|
@ -679,11 +683,12 @@ class AltiumImplementationParameterList extends AltiumObject
|
|||
|
||||
class AltiumDocument
|
||||
{
|
||||
constructor(stream)
|
||||
constructor(streams)
|
||||
{
|
||||
this.stream = stream;
|
||||
this.stream = new U8Stream(streams);
|
||||
this.records = [];
|
||||
let index = -1; // header comes first, so give it an index of -1
|
||||
console.log(this.stream.length)
|
||||
while (this.stream.u8stream_position < this.stream.length)
|
||||
{
|
||||
this.records.push(new AltiumRecord(this.stream, index));
|
||||
|
|
|
@ -150,7 +150,6 @@ class AltiumSchematicRenderer
|
|||
}
|
||||
results.innerText = bom.join("\n");
|
||||
|
||||
|
||||
for (let obj of doc.objects.filter((o) => o instanceof AltiumWire))
|
||||
{
|
||||
if (!this.#shouldShow(obj)) continue;
|
||||
|
|
189
ole.js
189
ole.js
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
|
||||
altium.js OLE parser
|
||||
|
||||
Copyright (c) 2022 Graham Sutherland
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
class OLE
|
||||
{
|
||||
static get ExpectedMagicNumber() { return new Uint8Array([ 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 ]) }
|
||||
static get ExpectedMajorVersion() { return 0x0003; }
|
||||
static get ExpectedMinorVersion() { return 0x003E; }
|
||||
static get ExpectedByteOrder() { return 0xFFFE; }
|
||||
static get ExpectedSectorShift() { return 0x0009; }
|
||||
static get ExpectedMiniSectorShift() { return 0x0006; }
|
||||
static get ExpectedNumberOfDirectorySectors() { return 0; }
|
||||
|
||||
constructor(fileData)
|
||||
{
|
||||
this.stream = new U8Stream(fileData);
|
||||
|
||||
if (fileData.length < 76)
|
||||
{
|
||||
throw new Error("File is too small to be a valid OLE compound document.");
|
||||
}
|
||||
|
||||
this.header = {};
|
||||
|
||||
this.header.signature = this.stream.read(8);
|
||||
if (!this.header.signature.compare_to(OLE.ExpectedMagicNumber))
|
||||
{
|
||||
throw new Error("File does not start with the correct OLE header signature.");
|
||||
}
|
||||
|
||||
this.header.clsid = this.stream.read(16);
|
||||
if (!this.header.clsid.every((b) => b === 0))
|
||||
{
|
||||
console.warn("OLE header CLSID was not set to all zeroes.");
|
||||
}
|
||||
|
||||
this.header.minor_version = this.stream.read_u16_le();
|
||||
this.header.major_version = this.stream.read_u16_le();
|
||||
if (this.header.major_version != OLE.ExpectedMajorVersion || this.header.minor_version != OLE.ExpectedMinorVersion)
|
||||
{
|
||||
throw new Error("OLE header does not have expected OLE version number.");
|
||||
}
|
||||
|
||||
this.header.byte_order = this.stream.read_u16_le();
|
||||
if (this.header.byte_order != OLE.ExpectedByteOrder)
|
||||
{
|
||||
throw new Error("OLE header does not have expected byte order value.");
|
||||
}
|
||||
|
||||
this.header.sector_shift = this.stream.read_u16_le();
|
||||
if (this.header.sector_shift != OLE.ExpectedSectorShift)
|
||||
{
|
||||
throw new Error("OLE header does not have expected sector shift value.");
|
||||
}
|
||||
this.header.sector_size = 1 << this.header.sector_shift;
|
||||
|
||||
this.header.mini_sector_shift = this.stream.read_u16_le();
|
||||
if (this.header.mini_sector_shift != OLE.ExpectedMiniSectorShift)
|
||||
{
|
||||
throw new Error("OLE header does not have expected mini sector shift value.");
|
||||
}
|
||||
this.header.mini_sector_size = 1 << this.header.mini_sector_shift;
|
||||
|
||||
if (!this.stream.read(6).every((b) => b === 0))
|
||||
{
|
||||
console.warn("OLE header reserved field was not set to all zeroes.");
|
||||
}
|
||||
|
||||
// directory sectors are unsupported for V3
|
||||
this.header.directory_sector_count = this.stream.read_u32_le();
|
||||
if (this.header.directory_sector_count != OLE.ExpectedNumberOfDirectorySectors)
|
||||
{
|
||||
throw new Error("OLE header does not have expected number of directory sectors.");
|
||||
}
|
||||
|
||||
this.header.fat_sector_count = this.stream.read_u32_le();
|
||||
this.header.first_directory_sector_location = this.stream.read_u32_le();
|
||||
this.header.transaction_signature_number = this.stream.read_u32_le();
|
||||
this.header.mini_stream_cutoff_size = this.stream.read_u32_le();
|
||||
this.header.fist_mini_fat_sector_location = this.stream.read_u32_le();
|
||||
this.header.number_of_mini_fat_sectors = this.stream.read_u32_le();
|
||||
this.header.first_difat_sector_location = this.stream.read_u32_le();
|
||||
this.header.number_of_difat_sectors = this.stream.read_u32_le();
|
||||
|
||||
this.header.difat = new Uint32Array(this.stream.read(436, true));
|
||||
this.fat_sectors = [];
|
||||
for (let i = 0; i < 109; i++)
|
||||
{
|
||||
this.fat_sectors[i] = new FATSector(this, this.header.difat[i]);
|
||||
}
|
||||
this.directory_entries = [];
|
||||
this.directory_entries[0] = new DirectoryEntry(this, (this.header.first_directory_sector_location + 1) * this.header.sector_size);
|
||||
this.directory_entries[1] = new DirectoryEntry(this, (this.header.first_directory_sector_location + 1) * this.header.sector_size + 128);
|
||||
this.directory_entries[2] = new DirectoryEntry(this, (this.header.first_directory_sector_location + 1) * this.header.sector_size + 256);
|
||||
this.directory_entries[3] = new DirectoryEntry(this, (this.header.first_directory_sector_location + 1) * this.header.sector_size + 384);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class FATSector
|
||||
{
|
||||
constructor(ole, sector_location)
|
||||
{
|
||||
this.ole = ole;
|
||||
this.sector_location = sector_location;
|
||||
const typeMap = [
|
||||
{ value: 0xFFFFFFFC, name: "DIFSECT" },
|
||||
{ value: 0xFFFFFFFD, name: "FATSECT" },
|
||||
{ value: 0xFFFFFFFE, name: "ENDOFCHAIN" },
|
||||
{ value: 0xFFFFFFFF, name: "FREESECT" },
|
||||
];
|
||||
if (this.sector_location >= 0xFFFFFFC)
|
||||
{
|
||||
this.entries = [];
|
||||
this.type = typeMap.find(tm => tm.value == this.sector_location).name;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.type = "FAT";
|
||||
ole.stream.seek_to((this.sector_location + 1) * ole.header.sector_size);
|
||||
this.entries = new Uint32Array(ole.stream.read(ole.header.sector_size - 4, true));
|
||||
this.next_difat_sector = ole.stream.read_u32_le();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DirectoryEntry
|
||||
{
|
||||
constructor(ole, position)
|
||||
{
|
||||
this.ole = ole;
|
||||
this.position = position;
|
||||
ole.stream.seek_to(position);
|
||||
|
||||
let name_bytes = ole.stream.read(64);
|
||||
let name_len = ole.stream.read_u16_le();
|
||||
if (name_len > 64)
|
||||
{
|
||||
throw new Error("Name length field exceeded maximum size of 64.");
|
||||
}
|
||||
this.name_field_length = name_len;
|
||||
this.name = new TextDecoder("utf-16").decode(name_bytes.slice(0, name_len));
|
||||
if (this.name.endsWith("\u0000"))
|
||||
this.name = this.name.slice(0, this.name.indexOf("\u0000"));
|
||||
|
||||
this.object_type = ole.stream.read_u8();
|
||||
this.colour_flag = ole.stream.read_u8();
|
||||
this.left_sibling = ole.stream.read_u32_le();
|
||||
this.right_sibling = ole.stream.read_u32_le();
|
||||
this.child_id = ole.stream.read_u32_le();
|
||||
this.clsid = ole.stream.read(16);
|
||||
this.state_bits = ole.stream.read_u32_le();
|
||||
this.creation_time = ole.stream.read_u64_le();
|
||||
this.modified_time = ole.stream.read_u64_le();
|
||||
this.starting_sector_location = ole.stream.read_u32_le();
|
||||
this.stream_size = ole.stream.read_u64_le();
|
||||
}
|
||||
|
||||
read_all()
|
||||
{
|
||||
this.ole.stream.seek_to((this.starting_sector_location + 1) * this.ole.header.sector_size);
|
||||
return new U8Stream(this.ole.stream.read(Number(this.stream_size)));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue