123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /**
- * STEP.js
- *
- * @author realor
- */
- const HEADER_SCHEMA = {}
- class STEPFile {
- name = null
- description = null
- schema = null // schema definition
- tags = {}
- references = []
- }
- class STEPParser {
- schema = null // classes map
- getSchemaTypes = null // called to get schema types
- onEntityCreated = null // called each time an entity is created
- decodeSTEPString(str) {
- return str.replace(/\\X2\\[\dA-F]{4}\\X0\\|\\X\\[\dA-F]{2}/gi, function(match) {
- var code = match.length === 12 ? match.substring(4, 8) : match.substring(3, 5)
- return String.fromCharCode(parseInt(code, 16))
- })
- }
- parse(text) {
- const t0 = Date.now()
- const file = new STEPFile()
- let tags = file.tags
- let references = file.references
- let lineCount = 0
- let builder = null
- let stack = []
- let token = ''
- let tag = null
- let inString = false
- let inComment = false
- for (let i = 0; i < text.length; i++) {
- let ch = text[i]
- if (inString) {
- if (ch === "'") {
- let nextCh = i < text.length - 1 ? text[i + 1] : null
- if (nextCh === "'") {
- // quote '' => '
- token += "'"
- i++
- } else {
- if (builder) {
- builder.add(this.decodeSTEPString(token))
- }
- token = ''
- inString = false
- }
- } else {
- token += ch
- }
- } else if (inComment) {
- token += ch
- if (token.endsWith('*/')) {
- inComment = false
- token = ''
- }
- } // out of string and comment
- else {
- if (ch === "'") {
- inString = true
- } else if (ch === ' ') {
- // ignore
- } else if (ch === '(') {
- let typeName = token.length > 0 ? token.toUpperCase() : 'Array'
- let schema = tag ? this.schema : HEADER_SCHEMA
- let newBuilder = new STEPBuilder(typeName, schema)
- if (builder) {
- // previous builder
- stack.push(builder) // save previous builder
- builder.add(newBuilder.instance)
- }
- builder = newBuilder
- token = ''
- } else if (ch === ',' || ch === ')') {
- if (builder === null) {
- console.warn('Parse error in line ' + (lineCount + 1))
- return null
- }
- if (token.length > 0) {
- if (token === '$') {
- builder.add(null)
- } else if ('0123456789-'.indexOf(token[0]) !== -1) {
- builder.add(parseFloat(token))
- } else if (token.charAt(0) === '#') {
- if (builder.instance) {
- references.push(new STEPReference(builder, token))
- }
- builder.add(null)
- } else {
- builder.add(token)
- }
- token = ''
- }
- if (ch === ')') {
- if (stack.length > 0) {
- builder = stack.pop()
- }
- }
- } else if (ch === ';') {
- if (tag) {
- if (builder && builder.instance) {
- tags[tag] = builder.instance
- if (this.onEntityCreated) {
- this.onEntityCreated(builder.instance)
- }
- }
- } // process header elements
- else {
- if (builder) {
- let instance = builder.instance
- if (instance instanceof FILE_SCHEMA) {
- file.schema = instance
- let schemaName = file.schema.Schemas[0]
- if (this.getSchemaTypes) {
- this.schema = this.getSchemaTypes(schemaName)
- }
- } else if (instance instanceof FILE_NAME) {
- file.name = instance
- } else if (instance instanceof FILE_DESCRIPTION) {
- file.description = instance
- }
- }
- }
- token = ''
- tag = null
- builder = null
- } else if (ch === '\t') {
- // ignore
- } else if (ch === '\n') {
- if (i === 0 || (i > 0 && text[i - 1] !== '\r')) lineCount++
- } else if (ch === '\r') {
- if (i === 0 || (i > 0 && text[i - 1] !== '\n')) lineCount++
- } else if (ch === '=') {
- token = token.trim()
- if (token.indexOf('#') === 0) {
- tag = token.trim()
- }
- token = ''
- } else {
- token += ch
- if (token.startsWith('/*')) {
- inComment = true
- }
- }
- }
- }
- // dereference references
- for (let i = 0; i < references.length; i++) {
- let reference = references[i]
- let instance = reference.instance
- let referencedInstance = tags[reference.tag] || null
- if (reference.property) {
- instance[reference.property] = referencedInstance
- } // Array
- else {
- let index = reference.index
- instance[index] = referencedInstance
- }
- }
- const t1 = Date.now()
- console.info('STEP File parsed in ' + (t1 - t0) + ' millis.')
- console.info('File contains ' + lineCount + ' lines.')
- return file
- }
- }
- class STEPBuilder {
- constructor(typeName, schema) {
- this.index = 0
- if (typeName === 'Array') {
- this.instance = []
- } else {
- let cls = schema ? schema[typeName] : HEADER_SCHEMA[typeName]
- if (cls) {
- this.instance = new cls()
- this.properties = Object.getOwnPropertyNames(this.instance)
- } else {
- this.instance = null
- console.warn('Unsupported entity ' + typeName)
- }
- }
- }
- add(element) {
- var instance = this.instance
- if (instance instanceof Array) {
- instance.push(element)
- } else if (instance !== null) {
- instance[this.properties[this.index]] = element
- }
- this.index++
- }
- }
- class STEPReference {
- constructor(builder, tag) {
- this.instance = builder.instance
- this.index = builder.index
- this.tag = tag // #<number>
- this.property = builder.properties ? builder.properties[builder.index] : null
- }
- }
- /* STEP header elements */
- class FILE_DESCRIPTION {
- Description = null
- ImplementationLevel = null
- }
- class FILE_NAME {
- Name = null
- TimeStamp = null
- Author = null
- Organization = null
- PreprocessorVersion = null
- Authorization = null
- Other = null
- }
- class FILE_SCHEMA {
- Schemas = null
- }
- HEADER_SCHEMA.FILE_DESCRIPTION = FILE_DESCRIPTION
- HEADER_SCHEMA.FILE_NAME = FILE_NAME
- HEADER_SCHEMA.FILE_SCHEMA = FILE_SCHEMA
- export { STEPParser, STEPFile }
|