Try to direct edit texts - unsuccessful.

This commit is contained in:
Jindra Petřík
2025-07-06 14:20:34 +02:00
parent dba9fd702d
commit 07984d5154
20 changed files with 1752 additions and 170 deletions

View File

@@ -16,7 +16,6 @@
*/
package com.jpexs.decompiler.flash.tags;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
@@ -43,10 +42,13 @@ import com.jpexs.decompiler.flash.tags.dynamictext.TextStyle;
import com.jpexs.decompiler.flash.tags.dynamictext.Word;
import com.jpexs.decompiler.flash.tags.enums.TextRenderMode;
import com.jpexs.decompiler.flash.tags.text.ParsedSymbol;
import com.jpexs.decompiler.flash.tags.text.SymbolType;
import com.jpexs.decompiler.flash.tags.text.TextAlign;
import com.jpexs.decompiler.flash.tags.text.TextLexer;
import com.jpexs.decompiler.flash.tags.text.TextParseException;
import com.jpexs.decompiler.flash.tags.text.xml.XmlException;
import com.jpexs.decompiler.flash.tags.text.xml.XmlLexer;
import com.jpexs.decompiler.flash.tags.text.xml.XmlParsedSymbol;
import com.jpexs.decompiler.flash.tags.text.xml.XmlSymbolType;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.DynamicTextGlyphEntry;
@@ -64,28 +66,22 @@ import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.SerializableImage;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.awt.Color;
import java.awt.Font;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* DefineEditText tag - defines an editable text field.
@@ -217,6 +213,154 @@ public class DefineEditTextTag extends TextTag {
readData(sis, data, 0, false, false, false);
}
@Override
public void removeCharacterGlyph(int glyphPos) {
List<TEXTRECORD> recs = getTextRecords(getSwf());
int pos = 0;
for (TEXTRECORD r : recs) {
if (r instanceof AdvancedTextRecord) {
AdvancedTextRecord atr = (AdvancedTextRecord) r;
for (int htmlSourcePos : atr.htmlSourcePositions) {
if (pos == glyphPos) {
char character = initialText.charAt(htmlSourcePos);
if (character == '&') {
int semiPos = initialText.indexOf(";", htmlSourcePos);
if (semiPos != -1) {
initialText = initialText.substring(0, htmlSourcePos) + initialText.substring(semiPos + 1);
return;
}
}
initialText = initialText.substring(0, htmlSourcePos) + initialText.substring(htmlSourcePos + 1);
packHtml();
setModified(true);
return;
}
pos++;
}
}
}
}
private void packHtml() {
try {
XmlLexer lexer = new XmlLexer(new StringReader(initialText));
XmlParsedSymbol s = lexer.yylex();
String tagName = null;
StringBuilder result = new StringBuilder();
StringBuilder cached = new StringBuilder();
boolean hasCharacter = false;
while (s.type != XmlSymbolType.EOF) {
if (s.type == XmlSymbolType.TAG_OPEN) {
if (tagName != null) {
result.append(cached.toString());
}
tagName = (String) s.value;
cached = new StringBuilder();
cached.append(s.rawText);
hasCharacter = false;
} else if (s.type == XmlSymbolType.TAG_CLOSE) {
if (tagName != null) {
if ("font".equals(tagName) && !hasCharacter) {
//ignore
} else {
cached.append(s.rawText);
result.append(cached.toString());
}
} else {
result.append(s.rawText);
}
tagName = null;
} else if (s.type == XmlSymbolType.ATTRIBUTE
|| s.type == XmlSymbolType.ATTRIBUTE_VALUE
|| s.type == XmlSymbolType.TAG_OPEN_END) {
if (tagName != null) {
cached.append(s.rawText);
} else {
result.append(s.rawText);
}
} else if (s.type == XmlSymbolType.CHARACTER) {
hasCharacter = true;
if (tagName != null) {
cached.append(s.rawText);
} else {
result.append(s.rawText);
}
} else {
if (tagName != null) {
cached.append(s.rawText);
} else {
result.append(s.rawText);
}
}
s = lexer.yylex();
}
initialText = result.toString();
} catch (IOException | XmlException ex) {
//ignore
}
}
@Override
public void insertCharacterGlyph(int glyphPos, char character) {
List<TEXTRECORD> recs = getTextRecords(getSwf());
int pos = 0;
String str = "" + character;
switch (character) {
case '&':
str = "&amp;";
break;
case '<':
str = "&lt;";
break;
case '>':
str = "&gt;";
break;
case '\u00A0':
str = "&nbsp;";
break;
}
/*
case '"':
str = "&quot";
break;
case '\'':
str = "&apos;";
break;
*/
int lastHtmlSourcePos = -1;
for (TEXTRECORD r : recs) {
if (r instanceof AdvancedTextRecord) {
AdvancedTextRecord atr = (AdvancedTextRecord) r;
for (int htmlSourcePos : atr.htmlSourcePositions) {
if (pos == glyphPos) {
initialText = initialText.substring(0, htmlSourcePos) + str + initialText.substring(htmlSourcePos);
setModified(true);
return;
}
lastHtmlSourcePos = htmlSourcePos;
pos++;
}
}
}
if (lastHtmlSourcePos == -1) {
initialText = str + initialText;
return;
}
int newHtmlSourcePos = lastHtmlSourcePos + 1;
char prevCharacter = initialText.charAt(lastHtmlSourcePos);
if (character == '&') {
int semiPos = initialText.indexOf(";", lastHtmlSourcePos);
if (semiPos != -1) {
newHtmlSourcePos = semiPos + 1;
}
}
initialText = initialText.substring(0, newHtmlSourcePos) + str + initialText.substring(newHtmlSourcePos);
}
@Override
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
characterID = sis.readUI16("characterID");
@@ -402,107 +546,24 @@ public class DefineEditTextTag extends TextTag {
style.leftMargin = leftMargin;
final List<CharacterWithStyle> ret = new ArrayList<>();
if (html) {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser;
//SAXParserFactory factory = SAXParserFactory.newInstance();
//SAXParser saxParser;
final Stack<TextStyle> styles = new Stack<>();
styles.add(style);
try {
/*try {
saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
private Locator locator;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
TextStyle style = styles.peek();
switch (qName) {
case "p":
// todo: parse the following attribute:
// align
break;
case "a":
// todo: handle link - href, target attributes
break;
case "b":
style = style.clone();
style.bold = true;
styles.add(style);
break;
case "i":
style = style.clone();
style.italic = true;
styles.add(style);
break;
case "u":
style = style.clone();
style.underlined = true;
styles.add(style);
break;
case "font":
style = style.clone();
String color = unescape(attributes.getValue("color"));
if (color != null) {
if (color.startsWith("#")) {
try {
if (color.length() == 7) { //#rrggbb
style.textColor = new RGBA(Color.decode(color));
} else if (color.length() == 9) { //#aarrggbb
style.textColor = RGBA.fromHexARGB(color);
style.textColor.alpha = 255; //no alpha is allowed
}
} catch (NumberFormatException ex) {
//do not change textColor
}
}
}
String size = unescape(attributes.getValue("size"));
if (size != null && size.length() > 0) {
try {
char firstChar = size.charAt(0);
if (firstChar != '+' && firstChar != '-') {
int fontSize = Integer.parseInt(size);
style.fontHeight = (int) Math.round(fontSize * SWF.unitDivisor);
} else {
int fontSizeDelta = (int) Math.round(Integer.parseInt(size.substring(1)) * SWF.unitDivisor);
if (firstChar == '+') {
style.fontHeight = style.fontHeight + fontSizeDelta;
} else {
style.fontHeight = style.fontHeight - fontSizeDelta;
}
}
style.fontLeading = leading;
} catch (NumberFormatException nfe) {
//do not change fontHeight or leading
}
}
String face = unescape(attributes.getValue("face"));
if (face != null && face.length() > 0) {
style.fontFace = face;
}
String letterspacing = unescape(attributes.getValue("letterSpacing"));
if (letterspacing != null && letterspacing.length() > 0) {
try {
style.letterSpacing = Double.parseDouble(letterspacing);
} catch (NumberFormatException nfe) {
//do not change letterSpacing
}
}
String kerning = unescape(attributes.getValue("kerning"));
if (kerning != null && kerning.length() > 0) {
style.kerning = kerning.equals("1");
}
styles.add(style);
break;
case "br":
case "sbr": // what's this?
CharacterWithStyle cs = new CharacterWithStyle();
cs.character = '\n';
cs.style = style;
ret.add(cs);
break;
}
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
@Override
public void startElement(String uri, String localName, String qName, Map<String, String> attributes) throws SAXException {
}
@Override
@@ -555,33 +616,209 @@ public class DefineEditTextTag extends TextTag {
addCharacters(ret, txt, style);
}
};
*/
str = str.replace("&nbsp;", "/{entity-nbsp}");
str = str.replace("&lt;", "/{entity-lt}");
str = str.replace("&gt;", "/{entity-gt}");
str = str.replace("&quot;", "/{entity-quot}");
str = str.replace("&amp;", "/{entity-amp}");
str = str.replace("&apos;", "/{entity-apos}");
str = str.replace("&", "&amp;");
XmlLexer lexer = new XmlLexer(new StringReader(str));
try {
XmlParsedSymbol s = lexer.yylex();
boolean inOpenTag = false;
String attributeName = null;
String tagName = null;
Map<String, String> attributes = new LinkedHashMap<>();
loops:
while (s.type != XmlSymbolType.EOF) {
switch (s.type) {
case TAG_OPEN:
inOpenTag = true;
attributeName = null;
tagName = (String) s.value;
attributes.clear();
break;
case ATTRIBUTE:
attributeName = (String) s.value;
break;
case ATTRIBUTE_VALUE:
if (attributeName == null) {
//Error
break loops;
}
attributes.put(attributeName, unescape((String) s.value));
break;
case TAG_OPEN_END:
style = styles.peek();
switch (tagName) {
case "p":
// todo: parse the following attribute:
// align
break;
case "a":
// todo: handle link - href, target attributes
break;
case "b":
style = style.clone();
style.bold = true;
styles.add(style);
break;
case "i":
style = style.clone();
style.italic = true;
styles.add(style);
break;
case "u":
style = style.clone();
style.underlined = true;
styles.add(style);
break;
case "font":
style = style.clone();
String color = attributes.get("color");
if (color != null) {
if (color.startsWith("#")) {
try {
if (color.length() == 7) { //#rrggbb
style.textColor = new RGBA(Color.decode(color));
} else if (color.length() == 9) { //#aarrggbb
style.textColor = RGBA.fromHexARGB(color);
style.textColor.alpha = 255; //no alpha is allowed
}
} catch (NumberFormatException ex) {
//do not change textColor
}
str = "<!DOCTYPE html [\n"
+ "]><root>" + str + "</root>";
}
}
String size = attributes.get("size");
if (size != null && size.length() > 0) {
try {
char firstChar = size.charAt(0);
if (firstChar != '+' && firstChar != '-') {
int fontSize = Integer.parseInt(size);
style.fontHeight = (int) Math.round(fontSize * SWF.unitDivisor);
} else {
int fontSizeDelta = (int) Math.round(Integer.parseInt(size.substring(1)) * SWF.unitDivisor);
if (firstChar == '+') {
style.fontHeight = style.fontHeight + fontSizeDelta;
} else {
style.fontHeight = style.fontHeight - fontSizeDelta;
}
}
style.fontLeading = leading;
} catch (NumberFormatException nfe) {
//do not change fontHeight or leading
}
}
String face = attributes.get("face");
if (face != null && face.length() > 0) {
style.fontFace = face;
}
String letterspacing = attributes.get("letterSpacing");
if (letterspacing != null && letterspacing.length() > 0) {
try {
style.letterSpacing = Double.parseDouble(letterspacing);
} catch (NumberFormatException nfe) {
//do not change letterSpacing
}
}
String kerning = attributes.get("kerning");
if (kerning != null && kerning.length() > 0) {
style.kerning = kerning.equals("1");
}
styles.add(style);
break;
case "br":
case "sbr": // what's this?
CharacterWithStyle cs = new CharacterWithStyle();
cs.character = '\n';
cs.style = style;
ret.add(cs);
break;
}
tagName = null;
break;
case TAG_CLOSE:
tagName = (String) s.value;
switch (tagName) {
case "b":
case "i":
case "u":
case "font":
styles.pop();
break;
case "p":
style = styles.peek();
CharacterWithStyle cs = new CharacterWithStyle();
cs.character = '\n';
cs.style = style;
ret.add(cs);
break;
}
tagName = null;
break;
case ENTITY:
case CHARACTER:
String txt = (String) s.value;
if (s.type == XmlSymbolType.ENTITY) {
txt = unescape("&" + txt + ";");
}
style = styles.peek();
if (style.fontFace != null && useOutlines) {
CharacterTag ct = swf.getCharacterByExportName(style.fontFace);
if (ct != null && (ct instanceof FontTag)) {
style.font = (FontTag) ct;
} else {
style.font = swf.getFontByNameInTag(style.fontFace, style.bold, style.italic);
}
if (style.font == null) {
style.fontFace = null;
}
}
addCharacters(ret, txt, style, s.position);
break;
}
s = lexer.yylex();
}
} catch (IOException ex) {
//Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex);
} catch (XmlException ex) {
//Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex);
//ex.printStackTrace();
}
/*
str = str.replace("&nbsp;", "/{entity-nbsp}");
str = str.replace("&lt;", "/{entity-lt}");
str = str.replace("&gt;", "/{entity-gt}");
str = str.replace("&quot;", "/{entity-quot}");
str = str.replace("&amp;", "/{entity-amp}");
str = str.replace("&apos;", "/{entity-apos}");
str = str.replace("&", "&amp;");
str = "<!DOCTYPE html [\n"
+ "]><root>" + str + "</root>";
saxParser.parse(new ByteArrayInputStream(str.getBytes(Utf8Helper.charset)), handler);
} catch (ParserConfigurationException | SAXException | IOException ex) {
Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, "Error parsing text " + getCharacterId(), ex);
}
*/
} else {
addCharacters(ret, str, style);
addCharacters(ret, str, style, 0);
}
return ret;
}
private void addCharacters(List<CharacterWithStyle> list, String str, TextStyle style) {
private void addCharacters(List<CharacterWithStyle> list, String str, TextStyle style, int position) {
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
CharacterWithStyle cs = new CharacterWithStyle();
cs.character = ch;
cs.style = style;
if (position > -1) {
cs.htmlSourcePosition = position + i;
}
list.add(cs);
}
}
@@ -705,7 +942,7 @@ public class DefineEditTextTag extends TextTag {
switch (s.type) {
case PARAMETER_IDENTIFIER:
String paramName = (String) s.value;
s = lexer.yylex();
s = lexer.yylex();
String paramValue = (String) s.value;
switch (paramName) {
case "xmin":
@@ -1137,7 +1374,7 @@ public class DefineEditTextTag extends TextTag {
ge.glyphAdvance += font.getCharKerningAdjustment(c, nextChar) / font.getDivider();
}
}
textModel.addGlyph(c, ge);
textModel.addGlyph(c, ge, cs.htmlSourcePosition);
if (Character.isWhitespace(c)) {
lastWasWhiteSpace = true;
}
@@ -1330,8 +1567,10 @@ public class DefineEditTextTag extends TextTag {
tr2.yOffset = yOffset;
}
tr2.glyphEntries = new ArrayList<>(tr.glyphEntries.size());
tr2.htmlSourcePositions = new ArrayList<>(tr.glyphEntries.size());
for (GlyphCharacter ge : tr.glyphEntries) {
tr2.glyphEntries.add(ge.glyphEntry);
tr2.htmlSourcePositions.add(ge.htmlSourcePosition);
}
allTextRecords.add(tr2);
}
@@ -1353,4 +1592,17 @@ public class DefineEditTextTag extends TextTag {
public boolean isSingleFrame() {
return true;
}
private String unescape(String txt) {
if (txt == null) {
return null;
}
txt = txt.replace("&nbsp;", "\u00A0");
txt = txt.replace("&lt;", "<");
txt = txt.replace("&gt;", ">");
txt = txt.replace("&quot;", "\"");
txt = txt.replace("&amp;", "&");
txt = txt.replace("&apos;", "'");
return txt;
}
}

View File

@@ -75,7 +75,7 @@ public class DefineTextTag extends StaticTextTag {
public DefineTextTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
super(sis.getSwf(), ID, NAME, data);
readData(sis, data, 0, false, false, false);
}
}
@Override
public int getTextNum() {

View File

@@ -16,6 +16,7 @@
*/
package com.jpexs.decompiler.flash.tags.base;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.timeline.DepthState;
import com.jpexs.helpers.Cache;
import com.jpexs.helpers.SerializableImage;
@@ -55,11 +56,21 @@ public class RenderContext {
*/
public TextTag mouseOverText;
/**
* Absolute matrix of mouse over text position
*/
public Matrix mouseOverTextAbsMatrix;
/**
* Selection text tag
*/
public TextTag selectionText;
/**
* Selection text abs matrix
*/
public Matrix selectionAbsMatrix;
/**
* Text selection start
*/

View File

@@ -125,6 +125,14 @@ public abstract class StaticTextTag extends TextTag {
}
}
@Override
public void insertCharacterGlyph(int glyphPos, char character) {
}
@Override
public void removeCharacterGlyph(int glyphPos) {
}
/**
* Gets data bytes
*

View File

@@ -92,6 +92,19 @@ public abstract class TextTag extends DrawableTag {
super(swf, id, name, data);
}
/**
* Inserts character at the given position.
* @param glyphPos Glyph position
* @param character Character
*/
public abstract void insertCharacterGlyph(int glyphPos, char character);
/**
* Removes character glyph at the given position
* @param glyphPos Glyph position
*/
public abstract void removeCharacterGlyph(int glyphPos);
/**
* Gets text matrix.
* @return Text matrix

View File

@@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags.dynamictext;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.types.TEXTRECORD;
import java.util.List;
/**
* Text record with font class.
@@ -27,6 +28,8 @@ import com.jpexs.decompiler.flash.types.TEXTRECORD;
public class AdvancedTextRecord extends TEXTRECORD {
public String fontClass = null;
public List<Integer> htmlSourcePositions = null;
@Override
public FontTag getFont(SWF swf) {
if (fontClass != null) {

View File

@@ -32,4 +32,9 @@ public class CharacterWithStyle {
* Style
*/
public TextStyle style;
/**
* Position in HTML source
*/
public int htmlSourcePosition = -1;
}

View File

@@ -58,14 +58,15 @@ public class DynamicTextModel {
* Add glyph.
* @param character Character
* @param glyphEntry Glyph entry
* @param htmlSourcePosition Position in HTML source
*/
public void addGlyph(char character, GLYPHENTRY glyphEntry) {
public void addGlyph(char character, GLYPHENTRY glyphEntry, int htmlSourcePosition) {
if (paragraph == null) {
paragraph = new Paragraph(this);
paragraphs.add(paragraph);
}
paragraph.addGlyph(character, glyphEntry);
paragraph.addGlyph(character, glyphEntry, htmlSourcePosition);
}
/**

View File

@@ -34,16 +34,23 @@ public class GlyphCharacter {
* Character
*/
public char character;
/**
* Position in HTML source
*/
public int htmlSourcePosition = -1;
/**
* Constructor.
*
* @param character Character
* @param glyphEntry Glyph entry
* @param htmlSourcePosition Position in HTML source
*/
public GlyphCharacter(char character, GLYPHENTRY glyphEntry) {
public GlyphCharacter(char character, GLYPHENTRY glyphEntry, int htmlSourcePosition) {
this.character = character;
this.glyphEntry = glyphEntry;
this.htmlSourcePosition = htmlSourcePosition;
}
}

View File

@@ -60,14 +60,15 @@ public class Paragraph {
* Add glyph.
* @param character Character
* @param glyphEntry Glyph entry
* @param htmlSourcePosition Position in HTML source
*/
public void addGlyph(char character, GLYPHENTRY glyphEntry) {
public void addGlyph(char character, GLYPHENTRY glyphEntry, int htmlSourcePosition) {
if (word == null) {
word = new Word(model);
words.add(word);
}
word.addGlyph(character, glyphEntry);
word.addGlyph(character, glyphEntry, htmlSourcePosition);
}
/**

View File

@@ -60,15 +60,16 @@ public class Word {
* Adds glyph.
* @param character Character
* @param glyphEntry Glyph entry
* @param htmlSourcePosition Position in HTML source
*/
public void addGlyph(char character, GLYPHENTRY glyphEntry) {
public void addGlyph(char character, GLYPHENTRY glyphEntry, int htmlSourcePosition) {
if (record == null) {
record = new SameStyleTextRecord();
record.style = model.style;
records.add(record);
}
record.glyphEntries.add(new GlyphCharacter(character, glyphEntry));
record.glyphEntries.add(new GlyphCharacter(character, glyphEntry, htmlSourcePosition));
}
/**

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2010-2025 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.tags.text.xml;
/**
*
* @author JPEXS
*/
public class XmlException extends Exception {
public XmlException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,744 @@
/* The following code was generated by JFlex 1.6.0 */
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License
* at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jpexs.decompiler.flash.tags.text.xml;
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.6.0
* from the specification file <tt>C:/Dropbox/Programovani/JavaSE/FFDec/libsrc/ffdec_lib/lexers/text_xml.flex</tt>
*/
public final class XmlLexer {
/** This character denotes the end of file */
public static final int YYEOF = -1;
/** initial size of the lookahead buffer */
private static final int ZZ_BUFFERSIZE = 16384;
/** lexical states */
public static final int YYINITIAL = 0;
public static final int COMMENT = 2;
public static final int CDATA = 4;
public static final int TAG = 6;
public static final int INSTR = 8;
/**
* ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l
* ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l
* at the beginning of a line
* l is of the form l = 2*k, k a non negative integer
*/
private static final int ZZ_LEXSTATE[] = {
0, 0, 1, 1, 2, 2, 3, 3, 4, 4
};
/**
* Translates characters to character classes
*/
private static final String ZZ_CMAP_PACKED =
"\11\0\1\1\1\3\1\33\1\33\1\2\22\0\1\1\1\7\1\26"+
"\1\31\2\0\1\4\1\27\5\0\1\10\1\13\1\24\12\14\1\11"+
"\1\30\1\6\1\25\1\5\1\15\1\0\1\21\1\11\1\17\1\20"+
"\1\11\16\11\1\22\6\11\1\16\1\0\1\23\1\0\1\11\1\0"+
"\32\12\12\0\1\33\61\0\1\13\10\0\27\0\1\0\37\0\1\0"+
"\u0208\0\160\0\16\0\1\0\u02e1\0\12\32\206\0\12\32\306\0\12\32"+
"\u019c\0\12\32\166\0\12\32\166\0\12\32\166\0\12\32\166\0\12\32"+
"\166\0\12\32\166\0\12\32\166\0\12\32\166\0\12\32\166\0\12\32"+
"\140\0\12\32\166\0\12\32\106\0\12\32\u0116\0\12\32\106\0\12\32"+
"\146\0\u06e0\0\12\32\46\0\12\32\u012c\0\12\32\200\0\12\32\246\0"+
"\12\32\6\0\12\32\266\0\12\32\126\0\12\32\206\0\12\32\6\0"+
"\12\32\u03a6\0\14\0\2\0\32\0\1\33\1\33\27\0\57\0\u0120\0"+
"\u0a70\0\u03f0\0\21\0\u761f\0\12\32\u02a6\0\12\32\46\0\12\32\306\0"+
"\12\32\26\0\12\32\126\0\12\32\u0196\0\12\32\u2c06\0\u0800\0\u1000\0"+
"\u0900\0\u04d0\0\40\0\u0120\0\12\32\344\0\u04a2\0\12\32\u0bbc\0\12\32"+
"\200\0\12\32\74\0\12\32\220\0\12\32\u0116\0\12\32\u01d6\0\12\32"+
"\u0176\0\12\32\146\0\12\32\u0216\0\12\32\u5176\0\12\32\346\0\12\32"+
"\u6c74\0\62\32\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\u280f\0";
/**
* Translates characters to character classes
*/
private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
/**
* Translates DFA states to action switch labels.
*/
private static final int [] ZZ_ACTION = zzUnpackAction();
private static final String ZZ_ACTION_PACKED_0 =
"\5\0\1\1\4\2\1\0\2\2\1\0\1\2\1\3"+
"\1\4\5\2\3\0\1\5\7\0\1\6\1\7\1\0"+
"\1\10\1\0\1\11\1\12\3\0\1\13\2\0\1\14"+
"\1\0\1\15\1\16\1\17\2\0\1\20\1\21\1\22"+
"\4\0\1\23";
private static int [] zzUnpackAction() {
int [] result = new int[61];
int offset = 0;
offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
return result;
}
private static int zzUnpackAction(String packed, int offset, int [] result) {
int i = 0; /* index in packed string */
int j = offset; /* index in unpacked array */
int l = packed.length();
while (i < l) {
int count = packed.charAt(i++);
int value = packed.charAt(i++);
do result[j++] = value; while (--count > 0);
}
return j;
}
/**
* Translates a state to a row index in the transition table
*/
private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
private static final String ZZ_ROWMAP_PACKED_0 =
"\0\0\0\34\0\70\0\124\0\160\0\214\0\250\0\304"+
"\0\340\0\374\0\374\0\u0118\0\u0134\0\u0134\0\u0150\0\u016c"+
"\0\304\0\u0188\0\u01a4\0\u01c0\0\u01dc\0\u01f8\0\u0214\0\u0230"+
"\0\u024c\0\u0268\0\u0284\0\u02a0\0\u02bc\0\u02d8\0\u02f4\0\u0310"+
"\0\u0188\0\304\0\304\0\u01c0\0\304\0\u01dc\0\304\0\304"+
"\0\u032c\0\u0348\0\u0364\0\u0380\0\u039c\0\u03b8\0\304\0\u03d4"+
"\0\304\0\304\0\304\0\u03f0\0\u040c\0\304\0\304\0\304"+
"\0\u0428\0\u0444\0\u0460\0\u047c\0\304";
private static int [] zzUnpackRowMap() {
int [] result = new int[61];
int offset = 0;
offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
return result;
}
private static int zzUnpackRowMap(String packed, int offset, int [] result) {
int i = 0; /* index in packed string */
int j = offset; /* index in unpacked array */
int l = packed.length();
while (i < l) {
int high = packed.charAt(i++) << 16;
result[j++] = high | packed.charAt(i++);
}
return j;
}
/**
* The transition table of the DFA
*/
private static final int [] ZZ_TRANS = zzUnpackTrans();
private static final String ZZ_TRANS_PACKED_0 =
"\4\6\1\7\1\10\1\11\25\6\2\12\1\13\5\12"+
"\1\14\22\12\1\13\2\15\1\16\20\15\1\17\7\15"+
"\1\16\1\10\3\20\1\10\1\21\3\10\2\22\4\10"+
"\4\22\1\10\1\23\1\10\1\24\1\25\3\10\1\0"+
"\1\10\3\20\5\10\2\22\2\10\1\26\1\10\4\22"+
"\3\10\1\24\1\25\3\10\1\0\4\6\3\0\25\6"+
"\12\0\1\27\16\0\1\30\45\0\1\31\1\0\2\32"+
"\2\0\1\33\1\0\4\32\1\0\1\34\7\0\10\13"+
"\1\35\33\13\1\36\23\13\23\16\1\37\33\16\1\40"+
"\10\16\1\0\3\20\40\0\5\41\2\0\4\41\2\0"+
"\1\42\13\0\1\43\26\0\2\44\2\0\22\44\1\45"+
"\5\44\2\46\2\0\23\46\1\45\4\46\5\0\1\47"+
"\40\0\1\27\15\0\1\50\17\0\1\51\15\0\1\51"+
"\11\0\1\52\5\0\1\53\25\0\5\32\2\0\4\32"+
"\22\0\2\54\4\0\4\54\22\0\2\55\4\0\4\55"+
"\11\0\10\13\1\56\30\13\1\57\2\13\1\56\23\13"+
"\23\16\1\60\15\16\1\61\15\16\1\60\10\16\14\0"+
"\1\51\13\0\1\62\1\0\1\51\11\0\1\63\42\0"+
"\1\64\24\0\5\54\2\0\4\54\12\0\3\65\1\0"+
"\1\66\2\0\5\55\2\0\4\55\11\0\5\13\1\67"+
"\2\13\1\56\23\13\5\16\1\70\15\16\1\60\10\16"+
"\20\0\1\71\14\0\3\65\1\0\1\66\47\0\1\72"+
"\34\0\1\73\32\0\1\74\30\0\1\75\15\0";
private static int [] zzUnpackTrans() {
int [] result = new int[1176];
int offset = 0;
offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
return result;
}
private static int zzUnpackTrans(String packed, int offset, int [] result) {
int i = 0; /* index in packed string */
int j = offset; /* index in unpacked array */
int l = packed.length();
while (i < l) {
int count = packed.charAt(i++);
int value = packed.charAt(i++);
value--;
do result[j++] = value; while (--count > 0);
}
return j;
}
/* error codes */
private static final int ZZ_UNKNOWN_ERROR = 0;
private static final int ZZ_NO_MATCH = 1;
private static final int ZZ_PUSHBACK_2BIG = 2;
/* error messages for the codes above */
private static final String ZZ_ERROR_MSG[] = {
"Unkown internal scanner error",
"Error: could not match input",
"Error: pushback value was too large"
};
/**
* ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
*/
private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
private static final String ZZ_ATTRIBUTE_PACKED_0 =
"\5\0\2\1\1\11\2\1\1\0\2\1\1\0\2\1"+
"\1\11\5\1\3\0\1\1\7\0\2\11\1\0\1\11"+
"\1\0\2\11\3\0\1\1\2\0\1\11\1\0\3\11"+
"\2\0\3\11\4\0\1\11";
private static int [] zzUnpackAttribute() {
int [] result = new int[61];
int offset = 0;
offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
return result;
}
private static int zzUnpackAttribute(String packed, int offset, int [] result) {
int i = 0; /* index in packed string */
int j = offset; /* index in unpacked array */
int l = packed.length();
while (i < l) {
int count = packed.charAt(i++);
int value = packed.charAt(i++);
do result[j++] = value; while (--count > 0);
}
return j;
}
/** the input device */
private java.io.Reader zzReader;
/** the current state of the DFA */
private int zzState;
/** the current lexical state */
private int zzLexicalState = YYINITIAL;
/** this buffer contains the current text to be matched and is
the source of the yytext() string */
private char zzBuffer[] = new char[ZZ_BUFFERSIZE];
/** the textposition at the last accepting state */
private int zzMarkedPos;
/** the current text position in the buffer */
private int zzCurrentPos;
/** startRead marks the beginning of the yytext() string in the buffer */
private int zzStartRead;
/** endRead marks the last character in the buffer, that has been read
from input */
private int zzEndRead;
/** number of newlines encountered up to the start of the matched text */
private int yyline;
/** the number of characters up to the start of the matched text */
private int yychar;
/**
* the number of characters from the last newline up to the start of the
* matched text
*/
private int yycolumn;
/**
* zzAtBOL == true <=> the scanner is currently at the beginning of a line
*/
private boolean zzAtBOL = true;
/** zzAtEOF == true <=> the scanner is at the EOF */
private boolean zzAtEOF;
/** denotes if the user-EOF-code has already been executed */
private boolean zzEOFDone;
/**
* The number of occupied positions in zzBuffer beyond zzEndRead.
* When a lead/high surrogate has been read from the input stream
* into the final zzBuffer position, this will have a value of 1;
* otherwise, it will have a value of 0.
*/
private int zzFinalHighSurrogate = 0;
/* user code: */
public XmlLexer() {
super();
}
private static final byte TAG_OPEN = 1;
private static final byte TAG_CLOSE = -1;
private static final byte INSTR_OPEN = 2;
private static final byte INSTR_CLOSE = -2;
private static final byte CDATA_OPEN = 3;
private static final byte CDATA_CLOSE = -3;
private static final byte COMMENT_OPEN = 4;
private static final byte COMMENT_CLOSE = -4;
/**
* Creates a new scanner
*
* @param in the java.io.Reader to read input from.
*/
public XmlLexer(java.io.Reader in) {
this.zzReader = in;
}
/**
* Unpacks the compressed character translation table.
*
* @param packed the packed character translation table
* @return the unpacked character translation table
*/
private static char [] zzUnpackCMap(String packed) {
char [] map = new char[0x110000];
int i = 0; /* index in packed string */
int j = 0; /* index in unpacked array */
while (i < 376) {
int count = packed.charAt(i++);
char value = packed.charAt(i++);
do map[j++] = value; while (--count > 0);
}
return map;
}
/**
* Refills the input buffer.
*
* @return <code>false</code>, iff there was new input.
*
* @exception java.io.IOException if any I/O-Error occurs
*/
private boolean zzRefill() throws java.io.IOException {
/* first: make room (if you can) */
if (zzStartRead > 0) {
zzEndRead += zzFinalHighSurrogate;
zzFinalHighSurrogate = 0;
System.arraycopy(zzBuffer, zzStartRead,
zzBuffer, 0,
zzEndRead-zzStartRead);
/* translate stored positions */
zzEndRead-= zzStartRead;
zzCurrentPos-= zzStartRead;
zzMarkedPos-= zzStartRead;
zzStartRead = 0;
}
/* is the buffer big enough? */
if (zzCurrentPos >= zzBuffer.length - zzFinalHighSurrogate) {
/* if not: blow it up */
char newBuffer[] = new char[zzBuffer.length*2];
System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length);
zzBuffer = newBuffer;
zzEndRead += zzFinalHighSurrogate;
zzFinalHighSurrogate = 0;
}
/* fill the buffer with new input */
int requested = zzBuffer.length - zzEndRead;
int totalRead = 0;
while (totalRead < requested) {
int numRead = zzReader.read(zzBuffer, zzEndRead + totalRead, requested - totalRead);
if (numRead == -1) {
break;
}
totalRead += numRead;
}
if (totalRead > 0) {
zzEndRead += totalRead;
if (totalRead == requested) { /* possibly more input available */
if (Character.isHighSurrogate(zzBuffer[zzEndRead - 1])) {
--zzEndRead;
zzFinalHighSurrogate = 1;
}
}
return false;
}
// totalRead = 0: End of stream
return true;
}
/**
* Closes the input stream.
*/
public final void yyclose() throws java.io.IOException {
zzAtEOF = true; /* indicate end of file */
zzEndRead = zzStartRead; /* invalidate buffer */
if (zzReader != null)
zzReader.close();
}
/**
* Resets the scanner to read from a new input stream.
* Does not close the old reader.
*
* All internal variables are reset, the old input stream
* <b>cannot</b> be reused (internal buffer is discarded and lost).
* Lexical state is set to <tt>ZZ_INITIAL</tt>.
*
* Internal scan buffer is resized down to its initial length, if it has grown.
*
* @param reader the new input stream
*/
public final void yyreset(java.io.Reader reader) {
zzReader = reader;
zzAtBOL = true;
zzAtEOF = false;
zzEOFDone = false;
zzEndRead = zzStartRead = 0;
zzCurrentPos = zzMarkedPos = 0;
zzFinalHighSurrogate = 0;
yyline = yychar = yycolumn = 0;
zzLexicalState = YYINITIAL;
if (zzBuffer.length > ZZ_BUFFERSIZE)
zzBuffer = new char[ZZ_BUFFERSIZE];
}
/**
* Returns the current lexical state.
*/
public final int yystate() {
return zzLexicalState;
}
/**
* Enters a new lexical state
*
* @param newState the new lexical state
*/
public final void yybegin(int newState) {
zzLexicalState = newState;
}
/**
* Returns the text matched by the current regular expression.
*/
public final String yytext() {
return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead );
}
/**
* Returns the character at position <tt>pos</tt> from the
* matched text.
*
* It is equivalent to yytext().charAt(pos), but faster
*
* @param pos the position of the character to fetch.
* A value from 0 to yylength()-1.
*
* @return the character at position pos
*/
public final char yycharat(int pos) {
return zzBuffer[zzStartRead+pos];
}
/**
* Returns the length of the matched text region.
*/
public final int yylength() {
return zzMarkedPos-zzStartRead;
}
/**
* Reports an error that occured while scanning.
*
* In a wellformed scanner (no or only correct usage of
* yypushback(int) and a match-all fallback rule) this method
* will only be called with things that "Can't Possibly Happen".
* If this method is called, something is seriously wrong
* (e.g. a JFlex bug producing a faulty scanner etc.).
*
* Usual syntax/scanner level error handling should be done
* in error fallback rules.
*
* @param errorCode the code of the errormessage to display
*/
private void zzScanError(int errorCode) {
String message;
try {
message = ZZ_ERROR_MSG[errorCode];
}
catch (ArrayIndexOutOfBoundsException e) {
message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
}
throw new Error(message);
}
/**
* Pushes the specified amount of characters back into the input stream.
*
* They will be read again by then next call of the scanning method
*
* @param number the number of characters to be read again.
* This number must not be greater than yylength()!
*/
public void yypushback(int number) {
if ( number > yylength() )
zzScanError(ZZ_PUSHBACK_2BIG);
zzMarkedPos -= number;
}
/**
* Resumes scanning until the next regular expression is matched,
* the end of input is encountered or an I/O-Error occurs.
*
* @return the next token
* @exception java.io.IOException if any I/O-Error occurs
*/
public XmlParsedSymbol yylex() throws java.io.IOException, XmlException {
int zzInput;
int zzAction;
// cached fields:
int zzCurrentPosL;
int zzMarkedPosL;
int zzEndReadL = zzEndRead;
char [] zzBufferL = zzBuffer;
char [] zzCMapL = ZZ_CMAP;
int [] zzTransL = ZZ_TRANS;
int [] zzRowMapL = ZZ_ROWMAP;
int [] zzAttrL = ZZ_ATTRIBUTE;
while (true) {
zzMarkedPosL = zzMarkedPos;
yychar+= zzMarkedPosL-zzStartRead;
zzAction = -1;
zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
zzState = ZZ_LEXSTATE[zzLexicalState];
// set up zzAction for empty match case:
int zzAttributes = zzAttrL[zzState];
if ( (zzAttributes & 1) == 1 ) {
zzAction = zzState;
}
zzForAction: {
while (true) {
if (zzCurrentPosL < zzEndReadL) {
zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL);
zzCurrentPosL += Character.charCount(zzInput);
}
else if (zzAtEOF) {
zzInput = YYEOF;
break zzForAction;
}
else {
// store back cached positions
zzCurrentPos = zzCurrentPosL;
zzMarkedPos = zzMarkedPosL;
boolean eof = zzRefill();
// get translated positions and possibly new buffer
zzCurrentPosL = zzCurrentPos;
zzMarkedPosL = zzMarkedPos;
zzBufferL = zzBuffer;
zzEndReadL = zzEndRead;
if (eof) {
zzInput = YYEOF;
break zzForAction;
}
else {
zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL);
zzCurrentPosL += Character.charCount(zzInput);
}
}
int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
if (zzNext == -1) break zzForAction;
zzState = zzNext;
zzAttributes = zzAttrL[zzState];
if ( (zzAttributes & 1) == 1 ) {
zzAction = zzState;
zzMarkedPosL = zzCurrentPosL;
if ( (zzAttributes & 8) == 8 ) break zzForAction;
}
}
}
// store back cached position
zzMarkedPos = zzMarkedPosL;
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
case 1:
{ return new XmlParsedSymbol(XmlSymbolType.CHARACTER, yytext(), yytext(), yychar);
}
case 20: break;
case 2:
{ throw new XmlException("Incorrect text: \"" + yytext() + "\"");
}
case 21: break;
case 3:
{ return new XmlParsedSymbol(XmlSymbolType.WHITESPACE, yytext(), yychar);
}
case 22: break;
case 4:
{ yybegin(YYINITIAL);
return new XmlParsedSymbol(XmlSymbolType.TAG_OPEN_END, yytext(), yychar);
}
case 23: break;
case 5:
{ yybegin(TAG);
return new XmlParsedSymbol(XmlSymbolType.TAG_OPEN, yytext().substring(1), yytext(), yychar);
}
case 24: break;
case 6:
{ return new XmlParsedSymbol(XmlSymbolType.ATTRIBUTE, yytext().substring(0, yytext().length() - 1).trim(), yytext(), yychar);
}
case 25: break;
case 7:
{ yybegin(YYINITIAL);
return new XmlParsedSymbol(XmlSymbolType.TAG_CLOSE, yytext(), yychar);
}
case 26: break;
case 8:
{ return new XmlParsedSymbol(XmlSymbolType.ATTRIBUTE_VALUE, yytext().substring(1, yytext().length() - 1), yytext(), yychar);
}
case 27: break;
case 9:
{ yybegin(YYINITIAL);
return new XmlParsedSymbol(XmlSymbolType.INSTR_CLOSE, yytext(), yychar);
}
case 28: break;
case 10:
{ return new XmlParsedSymbol(XmlSymbolType.ENTITY, yytext().substring(1, yytext().length() - 1), yytext(), yychar);
}
case 29: break;
case 11:
{ yybegin(INSTR);
return new XmlParsedSymbol(XmlSymbolType.INSTR_OPEN, yytext(), yychar);
}
case 30: break;
case 12:
{ yybegin(YYINITIAL);
return new XmlParsedSymbol(XmlSymbolType.COMMENT_CLOSE, yytext(), yychar);
}
case 31: break;
case 13:
{ yybegin(YYINITIAL);
return new XmlParsedSymbol(XmlSymbolType.CDATA_CLOSE, yytext(), yychar);
}
case 32: break;
case 14:
{ return new XmlParsedSymbol(XmlSymbolType.ENTITY_NUMERIC, Integer.parseInt(yytext().substring(1, yytext().length() - 1)), yytext(), yychar);
}
case 33: break;
case 15:
{ yybegin(COMMENT);
return new XmlParsedSymbol(XmlSymbolType.COMMENT_OPEN, yytext(), yychar);
}
case 34: break;
case 16:
{ return new XmlParsedSymbol(XmlSymbolType.TAG_CLOSE, yytext().substring(2, yytext().length() - 1), yytext(), yychar);
}
case 35: break;
case 17:
{ yypushback(3);
return new XmlParsedSymbol(XmlSymbolType.COMMENT, yytext().substring(yytext().length() - 3), yytext().substring(yytext().length() - 3), yychar);
}
case 36: break;
case 18:
{ yypushback(3);
return new XmlParsedSymbol(XmlSymbolType.CDATA, yytext().substring(yytext().length() - 3), yytext().substring(yytext().length() - 3), yychar);
}
case 37: break;
case 19:
{ yybegin(CDATA);
return new XmlParsedSymbol(XmlSymbolType.CDATA_OPEN, yytext(), yychar);
}
case 38: break;
default:
if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
zzAtEOF = true;
switch (zzLexicalState) {
case YYINITIAL: {
return new XmlParsedSymbol(XmlSymbolType.EOF, "", -1);
}
case 62: break;
case COMMENT: {
return new XmlParsedSymbol(XmlSymbolType.EOF, "", -1);
}
case 63: break;
case CDATA: {
return new XmlParsedSymbol(XmlSymbolType.EOF, "", -1);
}
case 64: break;
case TAG: {
return new XmlParsedSymbol(XmlSymbolType.EOF, "", -1);
}
case 65: break;
case INSTR: {
return new XmlParsedSymbol(XmlSymbolType.EOF, "", -1);
}
case 66: break;
default:
return null;
}
}
else {
zzScanError(ZZ_NO_MATCH);
}
}
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2010-2025 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.tags.text.xml;
/**
*
* @author JPEXS
*/
public class XmlParsedSymbol {
public Object value;
public XmlSymbolType type;
public String rawText;
public int position;
public XmlParsedSymbol(XmlSymbolType type, String rawText, int position) {
this.type = type;
this.value = "";
this.rawText = rawText;
this.position = position;
}
public XmlParsedSymbol(XmlSymbolType type, Object value, String rawText, int position) {
this.type = type;
this.value = value;
this.rawText = rawText;
this.position = position;
}
@Override
public String toString() {
return type.toString() + " " + value.toString();
}
public boolean isType(XmlSymbolType... types) {
for (XmlSymbolType t : types) {
if (type == t) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2010-2025 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.tags.text.xml;
/**
*
* @author JPEXS
*/
public enum XmlSymbolType {
ENTITY,
ENTITY_NUMERIC,
INSTR_OPEN,
TAG_OPEN,
TAG_OPEN_END,
TAG_CLOSE,
COMMENT_OPEN,
COMMENT,
COMMENT_CLOSE,
CDATA_OPEN,
CDATA,
CDATA_CLOSE,
CHARACTER,
ATTRIBUTE,
ATTRIBUTE_VALUE,
INSTR_CLOSE,
WHITESPACE,
EOF
}

View File

@@ -1231,28 +1231,30 @@ public class Timeline {
}
if (drawable instanceof TextTag) {
if (renderContext.cursorPosition != null && renderContext.enableTexts) {
TextTag textTag = (TextTag) drawable;
Matrix textMatrix = new Matrix(textTag.getTextMatrix());
if (drawable == renderContext.selectionText) {
renderContext.selectionAbsMatrix = absMat.concatenate(textMatrix);
}
if (renderContext.enableTexts) {
int dx = (int) (viewRect.xMin * unzoom);
int dy = (int) (viewRect.yMin * unzoom);
Point cursorPositionInView = new Point((int) Math.round(renderContext.cursorPosition.x * unzoom) - dx, (int) Math.round(renderContext.cursorPosition.y * unzoom) - dy);
Point cursorPositionInView = renderContext.cursorPosition == null ? new Point(0, 0) : new Point((int) Math.round(renderContext.cursorPosition.x * unzoom) - dx, (int) Math.round(renderContext.cursorPosition.y * unzoom) - dy);
Shape textShape = ((TextTag) drawable).getOutline(true, 0, 0, 0, renderContext, absMat, true, viewRect, unzoom);
TextTag textTag = (TextTag) drawable;
if (textShape.contains(cursorPositionInView)) {
renderContext.mouseOverText = textTag;
renderContext.mouseOverTextAbsMatrix = absMat;
}
if (textShape.contains(cursorPositionInView) || (drawable == renderContext.selectionText && renderContext.mouseButton == 1)) {
Rectangle textBounds = textShape.getBounds();
List<TEXTRECORD> textRecords = new ArrayList<>();
Matrix textMatrix = new Matrix();
if (textTag instanceof StaticTextTag) {
textRecords = ((StaticTextTag) textTag).textRecords;
MATRIX tm = ((StaticTextTag) textTag).textMatrix;
if (tm != null) {
textMatrix = new Matrix(tm);
}
textRecords = ((StaticTextTag) textTag).textRecords;
}
if (textTag instanceof DefineEditTextTag) {
textRecords = ((DefineEditTextTag) textTag).getTextRecords(textTag.getSwf());
@@ -1264,6 +1266,8 @@ public class Timeline {
int closestPos = -1;
double closestDistance = Double.MAX_VALUE;
Point cursorPosNoTrans = absMat.concatenate(textMatrix).inverse().transform(cursorPositionInView);
pos = 0;
for (RECT gp : glyphPositions) {
/*Rectangle2D r = new Rectangle2D.Double(
textBounds.x + gp.Xmin * unzoom,
@@ -1301,6 +1305,12 @@ public class Timeline {
break;
}
/*if (drawable == renderContext.selectionText && pos == renderContext.selectionStart) {
closestPos = pos;
closestDistance = 0;
break;
}*/
if (cursorPosNoTrans.y >= r.getY() && cursorPosNoTrans.y <= r.getMaxY()) {
double tx = Math.max(r.getMinX() - cursorPosNoTrans.getX(), 0);
tx = Math.max(tx, cursorPosNoTrans.getX() - r.getMaxX());
@@ -1331,12 +1341,12 @@ public class Timeline {
pos++;
}
if (closestPos == -1) {
if (closestPos == -1 && renderContext.mouseButton == 1) {
if (!glyphPositions.isEmpty()) {
RECT gp = glyphPositions.get(0);
Rectangle2D r = new Rectangle2D.Double(
gp.Xmin * unzoom,
gp.Ymin * unzoom,
gp.Xmin,
gp.Ymin,
gp.Xmax - gp.Xmin,
gp.Ymax - gp.Ymin
);
@@ -1346,8 +1356,8 @@ public class Timeline {
gp = glyphPositions.get(glyphPositions.size() - 1);
r = new Rectangle2D.Double(
gp.Xmin * unzoom,
gp.Ymin * unzoom,
gp.Xmin,
gp.Ymin,
gp.Xmax - gp.Xmin,
gp.Ymax - gp.Ymin
);
@@ -1360,8 +1370,8 @@ public class Timeline {
if (closestPos > -1) {
RECT gp = glyphPositions.get(closestPos);
Rectangle2D r = new Rectangle2D.Double(
gp.Xmin * unzoom,
gp.Ymin * unzoom,
gp.Xmin,
gp.Ymin,
gp.Xmax - gp.Xmin,
gp.Ymax - gp.Ymin
);