├── cli
├── .gitignore
├── .eclipse-pmd
├── src
│ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── dexesttp
│ │ │ └── hkxpack
│ │ │ └── cli
│ │ │ ├── commands
│ │ │ ├── Command.java
│ │ │ ├── CommandFactory.java
│ │ │ ├── Command_quick.java
│ │ │ ├── Command_unpack.java
│ │ │ ├── Command_help.java
│ │ │ └── Command_pack.java
│ │ │ ├── utils
│ │ │ ├── WrongSizeException.java
│ │ │ ├── FileNameCreationException.java
│ │ │ └── StaticProperties.java
│ │ │ ├── ConsoleView.java
│ │ │ └── loggers
│ │ │ └── DirectoryWalkerLoggerFactory.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── dexesttp
│ │ │ └── hkxpack
│ │ │ └── cli
│ │ │ └── utils
│ │ │ ├── ArgsParserTest.java
│ │ │ ├── ArgsParserEmptyTest.java
│ │ │ ├── ArgsParserExceptionTest.java
│ │ │ └── ArgsParserExistTest.java
│ └── debug
│ │ └── java
│ │ └── com
│ │ └── dexesttp
│ │ └── hkxpack
│ │ └── cli
│ │ ├── TestView.java
│ │ └── components
│ │ ├── Read.java
│ │ ├── Write.java
│ │ ├── XMLTest.java
│ │ └── HKXTest.java
└── pom.xml
├── doc
├── uml
│ ├── FileReader.png
│ └── FileReader.uml
└── hkx findings
│ ├── 01 - New data after first tests.txt
│ ├── Notes on behavior files.txt
│ ├── Applying FNIS findings to FO4.txt
│ ├── studying __data2__ of Bloatfly.txt
│ ├── Studying __data1__ of BloatflyRootBehavior.txt
│ ├── Studying animation- DeathChest01 .txt
│ ├── studying __data3__ of Bloatfly.txt
│ └── 00 - Findings on HKX files.txt
├── core
├── .gitignore
├── src
│ ├── test
│ │ ├── resources
│ │ │ ├── test-base.hkx
│ │ │ └── test-base.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── dexesttp
│ │ │ └── hkxpack
│ │ │ ├── hkxreader
│ │ │ ├── HKXReaderTest.java
│ │ │ ├── HKXTestBase.java
│ │ │ └── HKXReaderExternalResource.java
│ │ │ ├── tagreader
│ │ │ ├── TagXMLReaderTest.java
│ │ │ ├── TagXMLTestBase.java
│ │ │ ├── TagXMLReaderExceptionTest.java
│ │ │ └── TagXMLReaderExternalResource.java
│ │ │ ├── files
│ │ │ ├── ReaderExternalResource.java
│ │ │ └── TestBase.java
│ │ │ ├── resources
│ │ │ └── byteutils
│ │ │ │ ├── ULongByteUtilsTest.java
│ │ │ │ └── SLongByteUtilsTest.java
│ │ │ └── tagwriter
│ │ │ └── TagXMLWriterTest.java
│ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── dexesttp
│ │ │ └── hkxpack
│ │ │ ├── descriptor
│ │ │ ├── enums
│ │ │ │ ├── HKXTypeFamily.java
│ │ │ │ └── Flag.java
│ │ │ ├── exceptions
│ │ │ │ ├── ClassFileReadException.java
│ │ │ │ └── ClassListReadException.java
│ │ │ ├── reader
│ │ │ │ ├── ClassXMLReaderFactory.java
│ │ │ │ └── ClassXMLList.java
│ │ │ ├── HKXDescriptor.java
│ │ │ ├── HKXDescriptorFactory.java
│ │ │ └── HKXEnumResolver.java
│ │ │ ├── data
│ │ │ ├── HKXData.java
│ │ │ ├── members
│ │ │ │ ├── HKXMember.java
│ │ │ │ ├── HKXFailedMember.java
│ │ │ │ ├── HKXStringMember.java
│ │ │ │ ├── HKXDirectMember.java
│ │ │ │ └── HKXPointerMember.java
│ │ │ └── HKXObject.java
│ │ │ ├── hkxwriter
│ │ │ ├── utils
│ │ │ │ ├── PointerObject.java
│ │ │ │ └── PointerResolver.java
│ │ │ ├── object
│ │ │ │ ├── callbacks
│ │ │ │ │ ├── HKXArrayMemberCallback.java
│ │ │ │ │ ├── HKXMemberCallback.java
│ │ │ │ │ ├── HKXBaseArrayMemberCallback.java
│ │ │ │ │ ├── HKXPointerArrayMemberCallback.java
│ │ │ │ │ ├── HKXRelArrayMemberCallback.java
│ │ │ │ │ └── HKXDefaultArrayMemberCallback.java
│ │ │ │ ├── HKXMemberHandler.java
│ │ │ │ ├── HKXDirectMemberHandler.java
│ │ │ │ ├── HKXPointerMemberHandler.java
│ │ │ │ ├── array
│ │ │ │ │ └── HKXArrayPointerMemberHandler.java
│ │ │ │ ├── HKXObjectMemberHandler.java
│ │ │ │ ├── HKXEnumMemberHandler.java
│ │ │ │ ├── HKXStringMemberHandler.java
│ │ │ │ └── HKXInternalObjectHandler.java
│ │ │ ├── exceptions
│ │ │ │ └── WrongInputCastException.java
│ │ │ ├── header
│ │ │ │ └── HKXHeaderFactory.java
│ │ │ └── classnames
│ │ │ │ └── HKXClassnamesHandler.java
│ │ │ ├── hkx
│ │ │ ├── data
│ │ │ │ ├── DataInternal.java
│ │ │ │ ├── DataExternal.java
│ │ │ │ └── DataInterface.java
│ │ │ ├── exceptions
│ │ │ │ ├── UnsupportedVersionError.java
│ │ │ │ └── InvalidPositionException.java
│ │ │ ├── header
│ │ │ │ ├── HeaderData.java
│ │ │ │ ├── internals
│ │ │ │ │ ├── versions
│ │ │ │ │ │ └── HeaderDescriptor_v11.java
│ │ │ │ │ ├── SectionDescriptor.java
│ │ │ │ │ └── HeaderDescriptor.java
│ │ │ │ └── SectionData.java
│ │ │ ├── classnames
│ │ │ │ ├── Classname.java
│ │ │ │ └── ClassnamesData.java
│ │ │ ├── types
│ │ │ │ ├── handlers
│ │ │ │ │ ├── MemberHandler.java
│ │ │ │ │ ├── MemberHandlerFactory.java
│ │ │ │ │ ├── Vector4Handler.java
│ │ │ │ │ ├── BigMemberHandlers.java
│ │ │ │ │ ├── MediumMemberHandlers.java
│ │ │ │ │ └── NormalMemberHandlers.java
│ │ │ │ ├── object
│ │ │ │ │ ├── PrimitiveSnap.java
│ │ │ │ │ └── ObjectSnap.java
│ │ │ │ ├── ObjectSizeResolver.java
│ │ │ │ ├── MemberDataResolver.java
│ │ │ │ └── MemberSizeResolver.java
│ │ │ └── HKXUtils.java
│ │ │ ├── tagreader
│ │ │ ├── exceptions
│ │ │ │ └── InvalidTagXMLException.java
│ │ │ ├── serialized
│ │ │ │ ├── TagXMLSerializedHandler.java
│ │ │ │ ├── TagXMLComplexSerializedHandler.java
│ │ │ │ ├── TagXMLEmbeddedObjectSerializedHandler.java
│ │ │ │ └── TagXMLDirectSerializedHandler.java
│ │ │ ├── members
│ │ │ │ ├── TagXMLContentsHandler.java
│ │ │ │ └── TagXMLEmbeddedObjectHandler.java
│ │ │ └── TagXMLNodeHandler.java
│ │ │ ├── resources
│ │ │ ├── byteutils
│ │ │ │ ├── package-info.java
│ │ │ │ ├── StringByteUtils.java
│ │ │ │ ├── FloatByteUtils.java
│ │ │ │ ├── SLongByteUtils.java
│ │ │ │ └── ULongByteUtils.java
│ │ │ ├── DisplayProperties.java
│ │ │ └── LoggerUtil.java
│ │ │ ├── hkxreader
│ │ │ ├── member
│ │ │ │ ├── HKXMemberReader.java
│ │ │ │ ├── arrays
│ │ │ │ │ ├── HKXArrayContentsReader.java
│ │ │ │ │ ├── HKXDirectArrayContentsReader.java
│ │ │ │ │ ├── HKXObjectArrayContentsReader.java
│ │ │ │ │ ├── HKXPointerArrayContentsReader.java
│ │ │ │ │ └── HKXStringArrayContentsReader.java
│ │ │ │ ├── HKXObjectMemberReader.java
│ │ │ │ ├── HKXDirectMemberReader.java
│ │ │ │ ├── HKXPointerMemberReader.java
│ │ │ │ ├── HKXStringMemberReader.java
│ │ │ │ ├── HKXRelArrayMemberReader.java
│ │ │ │ └── HKXEnumMemberReader.java
│ │ │ ├── HKXDescriptorReader.java
│ │ │ ├── PointerNameGenerator.java
│ │ │ └── HKXReaderConnector.java
│ │ │ ├── l10n
│ │ │ └── SBundle.java
│ │ │ └── tagwriter
│ │ │ ├── TagXMLDataCreator.java
│ │ │ ├── TagXMLWriter.java
│ │ │ └── TagXMLDirectMemberHandler.java
│ │ └── resources
│ │ └── l10n
│ │ └── locale_en.properties
├── .eclipse-pmd
└── pom.xml
├── .github
└── PULL_REQUEST_TEMPLATE.md
├── .eclipse-pmd
├── LICENSE
├── pom.xml
└── .gitignore
/cli/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/doc/uml/FileReader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dexesttp/hkxpack/HEAD/doc/uml/FileReader.png
--------------------------------------------------------------------------------
/core/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /src/main/resources/classxml/
3 | /src/main/resources/properties/classxmllist.txt
4 |
--------------------------------------------------------------------------------
/core/src/test/resources/test-base.hkx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dexesttp/hkxpack/HEAD/core/src/test/resources/test-base.hkx
--------------------------------------------------------------------------------
/core/src/test/resources/test-base.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/descriptor/enums/HKXTypeFamily.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.descriptor.enums;
2 |
3 | /**
4 | * Classify the HKX types into "families" These families usually have an impact
5 | * on data reading and writing.
6 | */
7 | public enum HKXTypeFamily {
8 | UNKNOWN, DIRECT, COMPLEX, ENUM, ARRAY, POINTER, STRING, OBJECT
9 | }
10 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | #
2 |
3 | ## Scope
4 |
5 |
6 |
7 | ## Additions
8 |
9 | -
10 |
11 |
12 |
13 | -
14 |
15 | ## Fixes
16 |
17 | -
18 |
19 |
20 |
21 | -
22 |
23 | ## Notes
24 |
25 | -
26 | -
27 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/data/HKXData.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.data;
2 |
3 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
4 |
5 | /**
6 | * General purpose data storage for a HKX file DOM equivalent.
7 | */
8 | public interface HKXData {
9 | /**
10 | * Get this object's type.
11 | *
12 | * @return this object's {@link HKXType}.
13 | */
14 | HKXType getType();
15 | }
16 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/utils/PointerObject.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.utils;
2 |
3 | /**
4 | * Handles pointing from a file location to an object name
5 | */
6 | public class PointerObject {
7 | /**
8 | * The location the object is pointed from
9 | */
10 | public long from;
11 | /**
12 | * The name of the target object.
13 | */
14 | public String to;
15 | }
16 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/data/DataInternal.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.data;
2 |
3 | /**
4 | * A data position descriptor aimed at the current section.
5 | */
6 | public class DataInternal {
7 | /**
8 | * The data parent, in the current section.
9 | */
10 | public long from;
11 |
12 | /**
13 | * The data position, in the current section.
14 | */
15 | public long to;
16 | }
17 |
--------------------------------------------------------------------------------
/.eclipse-pmd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/cli/.eclipse-pmd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/doc/hkx findings/01 - New data after first tests.txt:
--------------------------------------------------------------------------------
1 | Apaprently, the data is organized differently from what I thought :
2 |
3 | - Members have a flage value, that can be either NONE or SERIALIZED
4 | - Serialized memebrs must not be included in data mining, but be included as comment in the output XML.
5 | - Data3 seems to contain the actual class architecture, while data2 and data1 contains respectvely enums (?) and actual data.
6 |
--------------------------------------------------------------------------------
/core/.eclipse-pmd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/hkxreader/HKXReaderTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader;
2 |
3 | import org.junit.runner.RunWith;
4 | import org.junit.runners.Suite;
5 | import org.junit.runners.Suite.SuiteClasses;
6 |
7 | @RunWith(Suite.class)
8 | @SuiteClasses({ HKXReaderExceptionTest.class, HKXTestBase.class })
9 | /**
10 | * Launches the relevant test suite for the {@link HKXReader} class
11 | */
12 | public class HKXReaderTest {
13 | // NO CONTENT
14 | }
15 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/tagreader/TagXMLReaderTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader;
2 |
3 | import org.junit.runner.RunWith;
4 | import org.junit.runners.Suite;
5 | import org.junit.runners.Suite.SuiteClasses;
6 |
7 | @RunWith(Suite.class)
8 | @SuiteClasses({ TagXMLReaderExceptionTest.class, TagXMLTestBase.class })
9 | /**
10 | * Launches the test suite for the {@link TagXMLReader}
11 | */
12 | public class TagXMLReaderTest {
13 | // NO CONTENT
14 | }
15 |
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/commands/Command.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.commands;
2 |
3 | /**
4 | * A command is a routed behavior of the Command Line Interface. It should be
5 | * returned only by a {@link CommandFactory}.
6 | */
7 | public interface Command {
8 | /**
9 | * Executes the command.
10 | *
11 | * @param parameters all the command-line arguments
12 | * @return the execution result value
13 | */
14 | int execute(String... parameters);
15 | }
16 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/data/DataExternal.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.data;
2 |
3 | /**
4 | * A data position descriptor aimed at a given section.
5 | */
6 | public class DataExternal {
7 | /**
8 | * The data parent, in the current section.
9 | */
10 | public long from;
11 |
12 | /**
13 | * The section the data is in.
14 | */
15 | public int section;
16 |
17 | /**
18 | * The data position, in the given section.
19 | */
20 | public long to;
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/data/members/HKXMember.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.data.members;
2 |
3 | import com.dexesttp.hkxpack.data.HKXData;
4 | import com.dexesttp.hkxpack.data.HKXObject;
5 |
6 | /**
7 | * A {@link HKXData} type used as children of a {@link HKXObject}.
8 | */
9 | public interface HKXMember extends HKXData {
10 | /**
11 | * Get the name of this member.
12 | *
13 | * @return the member's name, as a {@link String}.
14 | */
15 | String getName();
16 | }
17 |
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/utils/WrongSizeException.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.utils;
2 |
3 | /**
4 | * Thrown if there was an error while parsing arguments.
5 | */
6 | public class WrongSizeException extends Exception {
7 | private static final long serialVersionUID = -4241588440572992978L;
8 |
9 | /**
10 | * Create a {@link WrongSizeException}.
11 | *
12 | * @param option the option that had the wrong size.
13 | */
14 | public WrongSizeException(final String option) {
15 | super(option);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagreader/exceptions/InvalidTagXMLException.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader.exceptions;
2 |
3 | /**
4 | * Thrown where a non XML error was enocuntered while understanding the TagXML
5 | * file.
6 | */
7 | public class InvalidTagXMLException extends Exception {
8 | private static final long serialVersionUID = -7902902818953946055L;
9 |
10 | /**
11 | * Creates an {@link InvalidTagXMLException}.
12 | *
13 | * @param string the message.
14 | */
15 | public InvalidTagXMLException(final String string) {
16 | super(string);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/exceptions/UnsupportedVersionError.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.exceptions;
2 |
3 | /**
4 | * Thrown if a file with a non-supported version was attempted to be read.
5 | */
6 | public class UnsupportedVersionError extends Exception {
7 | private static final long serialVersionUID = -1869309792519998570L;
8 |
9 | /**
10 | * Creates an {@link UnsupportedVersionError}.
11 | *
12 | * @param versionName the illegal version name
13 | */
14 | public UnsupportedVersionError(final String versionName) {
15 | super("File version not supported : " + versionName);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/hkxreader/HKXTestBase.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader;
2 |
3 | import org.junit.ClassRule;
4 |
5 | import com.dexesttp.hkxpack.files.ReaderExternalResource;
6 | import com.dexesttp.hkxpack.files.TestBase;
7 |
8 | /**
9 | * {@link TestBase} extension for the HKX file.
10 | */
11 | public class HKXTestBase extends TestBase {
12 | @ClassRule
13 | public static ReaderExternalResource resource = new HKXReaderExternalResource(BASE_FILE_RESOURCE_NAME);
14 |
15 | /**
16 | * Creates the {@link HKXTestBase}.
17 | */
18 | public HKXTestBase() {
19 | super(resource.file);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/resources/byteutils/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Contains data to handle reading and writing from either {@link byte} arrays
3 | * or a {@link java.nio.ByteBuffer}.
4 | * The main entry point is
5 | * {@link com.dexesttp.hkxpack.resources.byteutils.ByteUtils}.
6 | *
7 | *
8 | * @see com.dexesttp.hkxpack.resources.byteutils.FloatByteUtils
9 | * @see com.dexesttp.hkxpack.resources.byteutils.SLongByteUtils
10 | * @see com.dexesttp.hkxpack.resources.byteutils.ULongByteUtils
11 | * @see com.dexesttp.hkxpack.resources.byteutils.StringByteUtils
12 | */
13 | package com.dexesttp.hkxpack.resources.byteutils;
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/tagreader/TagXMLTestBase.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader;
2 |
3 | import org.junit.ClassRule;
4 |
5 | import com.dexesttp.hkxpack.files.ReaderExternalResource;
6 | import com.dexesttp.hkxpack.files.TestBase;
7 |
8 | /**
9 | * Tests for the TagXML version of the test base
10 | */
11 | public class TagXMLTestBase extends TestBase {
12 | @ClassRule
13 | public static ReaderExternalResource resource = new TagXMLReaderExternalResource(BASE_FILE_RESOURCE_NAME);
14 |
15 | /**
16 | * Creates a {@link TagXMLTestBase}
17 | */
18 | public TagXMLTestBase() {
19 | super(resource.file);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/header/HeaderData.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.header;
2 |
3 | /**
4 | * Contains information about a HKX File version and format.
5 | */
6 | public class HeaderData {
7 | /**
8 | * The version of the file, as an integer.
9 | */
10 | public int version;
11 |
12 | /**
13 | * The version name and identifier, contains additionnal information about the
14 | * file's version.
15 | */
16 | public String versionName;
17 |
18 | /**
19 | * The padding after the header. Supported paddings are 0x00 (for most files)
20 | * and 0x10 (for animation files).
21 | */
22 | public long paddingAfter;
23 | }
24 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/callbacks/HKXArrayMemberCallback.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object.callbacks;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * General purpose callback handler for an Array
7 | */
8 | public interface HKXArrayMemberCallback {
9 | /**
10 | * Proces an array component callback list to its end.
11 | *
12 | * @param memberCallbacks the {@link HKXMemberCallback} to process
13 | * @param position the start position of the array values
14 | * @return the first valid position after the array
15 | */
16 | long process(List memberCallbacks, long position);
17 | }
18 |
--------------------------------------------------------------------------------
/doc/hkx findings/Notes on behavior files.txt:
--------------------------------------------------------------------------------
1 | BloatflyRootBehavior
2 | Tests :
3 | - Duplicated 850 - 8EF
4 | > Crash
5 | - Duplicated 18F0-1B4F
6 | > Crash
7 | - Changed header value 7A8 (03 to 06)
8 | - 06
9 | - 00
10 | - 04
11 | - F3
12 | > Animation : rotation stopped ?!?
13 | > No location change (stuck in place)
14 | - Changed header value 7A5 (00 to 03)
15 | > Crash
16 | - Changed header value 7A9 to 03 from 00
17 | > Same as 7A8
18 | - Checked ~36E0 in file (there is data for targeting).
19 | - Changed "enable" to "disable" @3690
20 | > No notable change
21 | - Changed "2" to "3" @36AE
22 | > No effect
23 | - Changed 20 to 21 @7C5
24 | > No notable change
25 | -
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/descriptor/enums/Flag.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.descriptor.enums;
2 |
3 | /**
4 | * List of known flag values for ClassXML components.
5 | */
6 | public enum Flag {
7 | UNKNOWN, FLAGS_NONE, NOT_OWNED, ALIGN_8, ALIGN_16, SERIALIZE_IGNORED;
8 |
9 | /**
10 | * Get the relevant {@link Flag} from its name as a {@link String}.
11 | *
12 | * @param string the name of the {@link Flag}.
13 | * @return the {@link Flag} instance.
14 | */
15 | public static Flag fromString(final String string) {
16 | try {
17 | return Flag.valueOf(string);
18 | } catch (IllegalArgumentException e) {
19 | return Flag.UNKNOWN;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/resources/DisplayProperties.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.resources;
2 |
3 | /**
4 | * DisplayProperties is used when outputting data in the middle of the HKXPack
5 | * core. I'm not usre it's useful anymore as all data is logged in
6 | * {@link LoggerUtil}.
7 | */
8 | public class DisplayProperties {
9 | // Output properties
10 | public static boolean ignoreSerialized = true;
11 | public static boolean displayEmbeddedData;
12 | // Display properties
13 | public static boolean displayDebugInfo;
14 | public static boolean displayFileDebugInfo;
15 | public static boolean displayReadTypesInfo;
16 | public static boolean displayClassImportsInfo;
17 | }
18 |
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/utils/FileNameCreationException.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.utils;
2 |
3 | /**
4 | * Thrown when a file couldn't be converted to its HKX or XML equivalent.
5 | */
6 | public class FileNameCreationException extends Exception {
7 | private static final long serialVersionUID = -4150191898446776060L;
8 |
9 | /**
10 | * Create a {@link FileNameCreationException}
11 | *
12 | * @param message the message of the exception
13 | * @param innerException the exception that causes this exception to be thrown
14 | */
15 | public FileNameCreationException(final String message, final Exception innerException) {
16 | super(message, innerException);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/cli/src/test/java/com/dexesttp/hkxpack/cli/utils/ArgsParserTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.utils;
2 |
3 | import org.junit.runner.RunWith;
4 | import org.junit.runners.Suite;
5 | import org.junit.runners.Suite.SuiteClasses;
6 |
7 | @RunWith(Suite.class)
8 | @SuiteClasses({ ArgsParserEmptyTest.class, ArgsParserExistTest.class, ArgsParserSizeTest.class,
9 | ArgsParserValuesTest.class, ArgsParserExceptionTest.class, ArgsParserComplexTest.class, })
10 | /**
11 | * {@inheritDoc}
12 | */
13 | public class ArgsParserTest {
14 | public static final String TEST = "test";
15 | public static final String TEST2 = "test2";
16 | public static final String TEST3 = "test3";
17 | public static final String TEST4 = "test4";
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/callbacks/HKXMemberCallback.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object.callbacks;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Defines a {@link HKXMember} post operations
7 | *
8 | * @see #process(List, long)
9 | */
10 | public interface HKXMemberCallback {
11 | /**
12 | * Handles a {@link HKXMember} post operations.
13 | *
14 | * @param memberCallbacks the callback list to add to.
15 | * @param position the position in the file at the beginning of the post
16 | * process
17 | * @return the next valid position at the end of the post process
18 | */
19 | long process(List memberCallbacks, long position);
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/HKXMemberHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXMember;
4 | import com.dexesttp.hkxpack.hkxwriter.object.callbacks.HKXMemberCallback;
5 |
6 | /**
7 | * Handles writing a {@link HKXMember} to a HKX File.
8 | *
9 | * @see #write(HKXMember, long)
10 | */
11 | public interface HKXMemberHandler {
12 | /**
13 | * Writes a {@link HKXMember}'s contents to the HKX File.
14 | *
15 | * @param member the {@link HKXMember} to write
16 | * @param currentPos the current position of the class in the file
17 | * @return this member's delayed operation while writing.
18 | */
19 | HKXMemberCallback write(HKXMember member, long currentPos);
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/HKXMemberReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXMember;
4 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
5 |
6 | /**
7 | * Reads a {@link HKXMember} from a HKX file.
8 | */
9 | public interface HKXMemberReader {
10 | /**
11 | * Reads a {@link HKXMember} from the HKX file.
12 | *
13 | * @param classOffset the offset of the class that contains the member.
14 | * @return the read {@link HKXMember}.
15 | * @throws InvalidPositionException if there was a position error while reading
16 | * the {@link HKXMember}.
17 | */
18 | HKXMember read(long classOffset) throws InvalidPositionException;
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/arrays/HKXArrayContentsReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member.arrays;
2 |
3 | import com.dexesttp.hkxpack.data.HKXData;
4 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
5 |
6 | /**
7 | * Reads array-specific contents.
8 | */
9 | public interface HKXArrayContentsReader {
10 | /**
11 | * Reads array contents as {@link HKXData}.
12 | *
13 | * @param arrayStart the start of the array contents.
14 | * @param position the position in the array
15 | * @return the read {@link HKXData}.
16 | * @throws InvalidPositionException if there was an error accessing the array
17 | * data.
18 | */
19 | HKXData getContents(long arrayStart, int position) throws InvalidPositionException;
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/classnames/Classname.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.classnames;
2 |
3 | /**
4 | * Represents a ClassName object in the {@literal __classnames__} section of a
5 | * HKX File.
6 | */
7 | public class Classname {
8 | /**
9 | * the name of the class
10 | */
11 | public transient String name;
12 | /**
13 | * the UUID of the class.
14 | */
15 | public transient byte[] uuid;
16 |
17 | /**
18 | * Create a ClassName either to write it to the file or when it was read from a
19 | * file.
20 | *
21 | * @param classname the class name.
22 | * @param uuid the class UUID, as defined in the relevant classXML.
23 | */
24 | public Classname(final String classname, final byte[] uuid) {
25 | this.name = classname;
26 | this.uuid = uuid.clone();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/main/resources/l10n/locale_en.properties:
--------------------------------------------------------------------------------
1 | # General strings
2 | bug.known = This is a known bug. Please do not report it.
3 | # Error strings
4 | error.hkx.read.type = Can't read type :
5 | error.hkx.read.subtype = Can't read array of subtype :
6 | error.hkx.write.cast = Error while trying to write a parameter. It might be a failed parameter.
7 | error.tag.create.type.unknown = The Tag parser attempted to write a wrong data type to the file.
8 | error.tag.read.type.unknown = The Tag parser attempted to read a wrong data type from the file.
9 | error.tag.read.hkpackfile = There is a wrong number of hkpackfile elements : expected 1, found
10 | error.tag.read.section = The following hksection couldn't be found :
11 | error.tag.read.member = The following member wasn't found in the XML :
12 | error.tag.read.sobject = The following sub-object wasn't found in the XML :
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/types/handlers/MemberHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.types.handlers;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXMember;
4 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
5 |
6 | /**
7 | * Handles a member based on its type
8 | */
9 | public interface MemberHandler {
10 | /**
11 | * Creates a member from the given arguments.
12 | *
13 | * @param name
14 | * @param type
15 | * @param byteArray
16 | * @return
17 | */
18 | HKXMember createMember(String name, HKXType type, byte[] byteArray);
19 |
20 | /**
21 | * Reads a member into a byteArray
22 | *
23 | * @param member the member to read
24 | * @return the read byteArray
25 | */
26 | byte[] readMember(HKXMember member);
27 |
28 | /**
29 | * Retrieves the size of this member
30 | *
31 | * @return the member size
32 | */
33 | long getSize();
34 | }
35 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagreader/serialized/TagXMLSerializedHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader.serialized;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXMember;
4 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
5 | import com.dexesttp.hkxpack.descriptor.members.HKXMemberTemplate;
6 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
7 |
8 | /**
9 | * Handles a serialized member.
10 | */
11 | public interface TagXMLSerializedHandler {
12 | /**
13 | * Creates a {@link HKXMember} based on a member's content description as a
14 | * {@link HKXMemberTemplate}
15 | *
16 | * @param memberTemplate the {@link HKXMemberTemplate} to build
17 | * @return an empty {@link HKXMember}
18 | * @throws InvalidTagXMLException
19 | * @throws ClassFileReadException
20 | */
21 | HKXMember handleMember(HKXMemberTemplate memberTemplate) throws ClassFileReadException, InvalidTagXMLException;
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/resources/LoggerUtil.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.resources;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * Handles all logged operations.
8 | */
9 | public final class LoggerUtil {
10 | private static List eList = new ArrayList<>();
11 |
12 | private LoggerUtil() {
13 | // NO OP
14 | }
15 |
16 | /**
17 | * Add an exception as a log.
18 | *
19 | * @param exception the exception to add.
20 | */
21 | public static void add(final Throwable exception) {
22 | eList.add(exception);
23 | }
24 |
25 | /**
26 | * Add a new generic exception as a log, by its message.
27 | *
28 | * @param message the message to add
29 | */
30 | public static void addNewException(final String message) {
31 | eList.add(new Exception(message));
32 | }
33 |
34 | /**
35 | * Get the logger list.
36 | *
37 | * @return
38 | */
39 | public static List getList() {
40 | return eList;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/ConsoleView.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli;
2 |
3 | import com.dexesttp.hkxpack.cli.commands.Command;
4 | import com.dexesttp.hkxpack.cli.commands.CommandFactory;
5 | import com.dexesttp.hkxpack.cli.commands.Command_help;
6 |
7 | /**
8 | * Entry point for the Command Line Interface.
9 | */
10 | public final class ConsoleView {
11 | private static final int MINIMUM_ARG_COUNT = 1;
12 |
13 | private ConsoleView() {
14 | // NO OP
15 | }
16 |
17 | /**
18 | * Entry point for the console
19 | *
20 | * @param args the console arguments.
21 | */
22 | public static void main(final String... args) {
23 | // Set the logging properties
24 | System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$s] %5$s%n");
25 | Command command;
26 | if (args.length < MINIMUM_ARG_COUNT) {
27 | command = new Command_help();
28 | } else {
29 | command = new CommandFactory().newInstance(args[0]);
30 | }
31 | command.execute(args);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/files/ReaderExternalResource.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.files;
2 |
3 | import java.io.IOException;
4 |
5 | import javax.xml.parsers.ParserConfigurationException;
6 |
7 | import org.junit.rules.ExternalResource;
8 | import org.xml.sax.SAXException;
9 |
10 | import com.dexesttp.hkxpack.data.HKXFile;
11 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
12 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
13 |
14 | /**
15 | * General purpose resource for a ReaderExternalResource
16 | */
17 | public abstract class ReaderExternalResource extends ExternalResource {
18 | /**
19 | * The loaded {@link HKXFile}.
20 | */
21 | public HKXFile file;
22 |
23 | /**
24 | * Override by the loader for {@link #file}
25 | *
26 | * @throws InvalidPositionException
27 | */
28 | @Override
29 | public abstract void before() throws IOException, ParserConfigurationException, SAXException,
30 | InvalidTagXMLException, InvalidPositionException;
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/resources/byteutils/StringByteUtils.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.resources.byteutils;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | /**
6 | * Provides utility functions to read a String from a {@link ByteBuffer}.
7 | */
8 | final class StringByteUtils {
9 | private StringByteUtils() {
10 | // NO OP
11 | }
12 |
13 | /**
14 | * Reads the next 0-terminated string from the given {@link ByteBuffer}.
15 | * This will change the {@link ByteBuffer#position()} value to just after the 0
16 | * of the Null-terminated string.
17 | *
18 | * @param inputByteBuffer the {@link ByteBuffer} to read from
19 | * @return the read {@link String}
20 | */
21 | static String readString(final ByteBuffer inputByteBuffer) {
22 | byte readByte = inputByteBuffer.get();
23 | StringBuffer resultBuffer = new StringBuffer();
24 | while (readByte != 0) {
25 | resultBuffer.append((char) readByte);
26 | readByte = inputByteBuffer.get();
27 | }
28 | return resultBuffer.toString();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 DexesTTP
2 |
3 | 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:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | 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.
8 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/header/internals/versions/HeaderDescriptor_v11.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.header.internals.versions;
2 |
3 | import com.dexesttp.hkxpack.hkx.header.internals.HeaderDescriptor;
4 |
5 | /**
6 | * Describes the v11 version of the header.
7 | */
8 | public class HeaderDescriptor_v11 extends HeaderDescriptor {
9 | /**
10 | * The version where this header is necessary
11 | */
12 | public static final int VERSION_11 = 11;
13 | /**
14 | * Padding bytes found after the Header descriptor, if there is padding.
15 | */
16 | public byte[] padding = new byte[] { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
17 |
18 | /**
19 | * Creates a {@link HeaderDescriptor_v11}.
20 | */
21 | public HeaderDescriptor_v11() {
22 | super();
23 | version = new byte[] { 11, 0, 0, 0 };
24 | extras = new byte[] { 8, 1, 0, 1 };
25 | verName = new byte[] { 'h', 'k', '_', '2', '0', '1', '4', '.', '1', '.', '0', '-', 'r', '1' };
26 | extras11 = new byte[] { 21, 0 };
27 | padding11 = new byte[] { 16, 0 };
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/core/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.dexesttp
8 | hkxpack
9 | 0.1.6-beta
10 |
11 |
12 | com.dexesttp.hkxpack
13 | core
14 |
15 | HKXPack Core
16 | Set of core modules containing the logic to unpack and pack the hkx files
17 |
18 |
19 | com.google.guava
20 | guava
21 | 19.0
22 |
23 |
24 | junit
25 | junit
26 | 4.12
27 | test
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/l10n/SBundle.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.l10n;
2 |
3 | import java.util.Locale;
4 | import java.util.ResourceBundle;
5 |
6 | /**
7 | * Contains the ResourceBundle for localizaton stuff.
8 | */
9 | public final class SBundle {
10 | private static String baseName = "l10n/locale";
11 | private static ResourceBundle instance;
12 |
13 | private SBundle() {
14 | // NO OP
15 | }
16 |
17 | /**
18 | * Get a localized string.
19 | *
20 | * @param stringName the string name
21 | * @return the localized string
22 | */
23 | public static String getString(final String stringName) {
24 | return getInstance().getString(stringName);
25 | }
26 |
27 | /**
28 | * Get the localized ResourceBundle.
29 | *
30 | * @return the localized {@link ResourceBundle}.
31 | */
32 | public static ResourceBundle getInstance() {
33 | if (instance == null) {
34 | initInstance();
35 | }
36 | return instance;
37 | }
38 |
39 | private static void initInstance() {
40 | instance = ResourceBundle.getBundle(baseName, Locale.ENGLISH);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/resources/byteutils/ULongByteUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.resources.byteutils;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Tests the {@link ULongByteUtils} class
9 | */
10 | public class ULongByteUtilsTest {
11 | @Test
12 | /**
13 | * Test
14 | */
15 | public void getUIntSize2ShouldWorkFor0() {
16 | assertArrayEquals("Long(2) : 0 => 0", new byte[] { 0, 0 }, ULongByteUtils.fromLong(0, 2));
17 | }
18 |
19 | @Test
20 | /**
21 | * Test
22 | */
23 | public void getUIntSize2ShouldWorkFor1() {
24 | assertArrayEquals("Long(2) : 1 => 1", new byte[] { 1, 0 }, ULongByteUtils.fromLong(1, 2));
25 | }
26 |
27 | @Test
28 | /**
29 | * Test
30 | */
31 | public void getUIntSize2ShouldWorkForMaxValue() {
32 | assertArrayEquals("Long(2) : 65535 => 65535", new byte[] { -1, -1 }, ULongByteUtils.fromLong(65535, 2));
33 | }
34 |
35 | @Test
36 | /**
37 | * Test
38 | */
39 | public void getUIntSize2ShouldWorkFor30() {
40 | assertArrayEquals("Long(2) : 30 => 30", new byte[] { 30, 0 }, ULongByteUtils.fromLong(30, 2));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagreader/members/TagXMLContentsHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader.members;
2 |
3 | import org.w3c.dom.Node;
4 |
5 | import com.dexesttp.hkxpack.data.members.HKXMember;
6 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
7 | import com.dexesttp.hkxpack.descriptor.members.HKXMemberTemplate;
8 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
9 |
10 | /**
11 | * Handle the contents of a {@link Node} into a {@link HKXMember}
12 | */
13 | public interface TagXMLContentsHandler {
14 | /**
15 | * Creates a {@link HKXMember} based on a {@link Node} and its contents
16 | * description as a {@link HKXMemberTemplate}
17 | *
18 | * @param member the {@link Node} to read.
19 | * @param memberTemplate the {@link HKXMemberTemplate} describing the
20 | * {@link Node}'s contents
21 | * @return a {@link HKXMember} containing all relevant data.
22 | * @throws InvalidTagXMLException
23 | * @throws ClassFileReadException
24 | */
25 | HKXMember handleNode(Node member, HKXMemberTemplate memberTemplate)
26 | throws ClassFileReadException, InvalidTagXMLException;
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/header/internals/SectionDescriptor.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.header.internals;
2 |
3 | /**
4 | * A general purpose Section descriptor, designed on the v8 and v11 sections.
5 | */
6 | public class SectionDescriptor {
7 | /**
8 | * Name of the section, null-terminated
9 | */
10 | public byte[] secName = new byte[16];
11 | /**
12 | * Constant value
13 | */
14 | public byte[] constant = new byte[] { 0, 0, 0, -1 };
15 | /**
16 | * Offset of the section (from the beginning of the file)
17 | */
18 | public byte[] offset = new byte[4];
19 | /**
20 | * First data part (position from the offset).
21 | */
22 | public byte[] data1 = new byte[4];
23 | /**
24 | * Second data part (position from the offset).
25 | */
26 | public byte[] data2 = new byte[4];
27 | /**
28 | * Third data part (position from the offset).
29 | */
30 | public byte[] data3 = new byte[4];
31 | /**
32 | * Fourth data part (position from the offset).
33 | */
34 | public byte[] data4 = new byte[4];
35 | /**
36 | * Fifth data part (position from the offset).
37 | */
38 | public byte[] data5 = new byte[4];
39 | /**
40 | * End of the section (from the offset)
41 | */
42 | public byte[] end = new byte[4];
43 | }
44 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/HKXObjectMemberReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXMember;
4 | import com.dexesttp.hkxpack.descriptor.HKXDescriptor;
5 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
6 | import com.dexesttp.hkxpack.hkxreader.HKXObjectReader;
7 |
8 | /**
9 | * Create a {@link HKXObject} from a HKX file, and returns it as
10 | * {@link HKXMember}.
11 | */
12 | class HKXObjectMemberReader implements HKXMemberReader {
13 | private final transient HKXDescriptor descriptor;
14 | private final transient HKXObjectReader objectReader;
15 | private final transient String name;
16 | private final transient long offset;
17 |
18 | HKXObjectMemberReader(final HKXObjectReader objectReader, final String name, final long offset,
19 | final HKXDescriptor descriptor) {
20 | this.objectReader = objectReader;
21 | this.name = name;
22 | this.offset = offset;
23 | this.descriptor = descriptor;
24 | }
25 |
26 | @Override
27 | /**
28 | * {@inheritDoc}
29 | */
30 | public HKXMember read(final long classOffset) throws InvalidPositionException {
31 | return objectReader.createHKXObject(name, classOffset + offset, descriptor);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.dexesttp
8 | hkxpack
9 | 0.1.6-beta
10 | pom
11 |
12 | HKXPack
13 | HKXPack is a tool to 'pack' and 'unpack' to and from hkx files, which is the Havok compressed file format.
14 |
15 |
16 | core
17 | cli
18 |
19 |
20 |
21 | UTF-8
22 |
23 |
24 |
25 | hkxpack-${project.artifactId}
26 |
27 |
28 | org.apache.maven.plugins
29 | maven-compiler-plugin
30 | 3.3
31 |
32 | 1.8
33 | 1.8
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/utils/PointerResolver.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.utils;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.Optional;
6 |
7 | import com.dexesttp.hkxpack.hkx.data.DataExternal;
8 |
9 | /**
10 | * Resolves a pointer into an address
11 | */
12 | public class PointerResolver {
13 | private final transient Map map = new HashMap<>();
14 |
15 | /**
16 | * Add a new known pointer.
17 | *
18 | * @param name the name of the object.
19 | * @param position the position the object was written at.
20 | */
21 | public void add(final String name, final long position) {
22 | map.put(name, position);
23 | }
24 |
25 | /**
26 | * Resolves a pointer.
27 | *
28 | * @param object the {@link PointerObject} to resolve.
29 | * @return the resolved and filled {@link DataExternal}, or "null" if the
30 | * resolution failed.
31 | */
32 | public Optional resolve(final PointerObject object) {
33 | if (!map.keySet().contains(object.to)) {
34 | return Optional.empty();
35 | }
36 | DataExternal res = new DataExternal();
37 | res.section = 0x02;
38 | res.from = object.from;
39 | res.to = map.get(object.to);
40 | return Optional.of(res);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/doc/hkx findings/Applying FNIS findings to FO4.txt:
--------------------------------------------------------------------------------
1 | Working on the Bloatfly (BloatflyRootBehavior.hkx)
2 |
3 | => header (checking)
4 | __classnames __
5 | [00 01] [D0 03]*8
6 | => @100 -> Beginning of class definitions
7 | => @100+3D0 @4D0 -> end of class definitions
8 | __types__
9 | [D0 04] [00 00]*8
10 | => @4D0 is the end of class definitions
11 | __data__
12 | [D0 04] [40 69] [C0 7A] [40 7E] [90 81]*3
13 | => @4D0 end of __classnames__
14 | => @6940+4D0 @6E10 beginning of __data__1
15 | => @7AC0+4D0 @7F90 beginning of __data__2
16 | > no more 4 bytes values after
17 | => @7E40+4D0 @8310 beginning of __data__3
18 | > @8308 is all FFs until @8310
19 | => @8190+4D0 @8660
20 | > EOF allright
21 |
22 | => Classes values
23 | => Most class value changed
24 | e.g. "hkbBehaviorGraphData" went from "5D CA 5A 09" [SK] to "22 82 7A 90" [F4]
25 | => Checked throughout two files
26 | => Need to find new value for "hkbBehaviorReferenceGenerator" in the files and/or in the doc.
27 |
28 | => Structure of __data__1 part (@6E10)
29 | [18 00] @18+4D0 @4E8 => value ? 0's
30 | [40 00] @40+4D0 @510 => hkbBehaviorGraph
31 | [98 00] @98+4D0 @568 => value ? 0's
32 | [10 02] @210+4D0 @6E0 => BloatflyRootBehavior.hkb
33 | => Seems like __data__1 format didn't change format.
34 |
35 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/exceptions/WrongInputCastException.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.exceptions;
2 |
3 | /**
4 | * Throwed when an object content doesn't match with its template.
5 | */
6 | public class WrongInputCastException extends Exception {
7 | private static final long serialVersionUID = 6483999356904172141L;
8 |
9 | /**
10 | * Creates a {@link WrongInputCastException}.
11 | *
12 | * @param message the error message
13 | */
14 | public WrongInputCastException(final String message) {
15 | super(message);
16 | }
17 |
18 | /**
19 | * Creates a {@link WrongInputCastException}.
20 | *
21 | * @param previousException the exception that caused the
22 | * {@link WrongInputCastException}.
23 | */
24 |
25 | public WrongInputCastException(final Throwable previousException) {
26 | super(previousException);
27 | }
28 |
29 | /**
30 | * Creates a {@link WrongInputCastException}.
31 | *
32 | * @param message the error message
33 | * @param previousException the exception that caused the
34 | * {@link WrongInputCastException}.
35 | */
36 | public WrongInputCastException(final String message, final Throwable previousException) {
37 | super(message, previousException);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/descriptor/exceptions/ClassFileReadException.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.descriptor.exceptions;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * A {@link ClassFileReadException} is thrown when a class file described in the
7 | * class list couldn't be read.
8 | */
9 | public class ClassFileReadException extends IOException {
10 | private static final long serialVersionUID = 3053825597885294212L;
11 |
12 | /**
13 | * Create a {@link ClassFileReadException}.
14 | *
15 | * @param message the error message
16 | */
17 | public ClassFileReadException(final String message) {
18 | super(message);
19 | }
20 |
21 | /**
22 | * Create a {@link ClassFileReadException}.
23 | *
24 | * @param throwable the exception that caused the
25 | * {@link ClassFileReadException}.
26 | */
27 | public ClassFileReadException(final Throwable throwable) {
28 | super(throwable);
29 | }
30 |
31 | /**
32 | * Create a {@link ClassFileReadException}.
33 | *
34 | * @param message the error message
35 | * @param throwable the exception that caused the
36 | * {@link ClassFileReadException}.
37 | */
38 | public ClassFileReadException(final String message, final Throwable throwable) {
39 | super(message, throwable);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Eclipse
2 | .metadata
3 | bin/
4 | tmp/
5 | *.tmp
6 | *.bak
7 | *.swp
8 | *~.nib
9 | local.properties
10 | .settings/
11 | .loadpath
12 |
13 | # Eclipse Core
14 | .project
15 |
16 | # External tool builders
17 | .externalToolBuilders/
18 |
19 | # Locally stored "Eclipse launch configurations"
20 | *.launch
21 |
22 | # PyDev specific (Python IDE for Eclipse)
23 | *.pydevproject
24 |
25 | # CDT-specific (C/C++ Development Tooling)
26 | .cproject
27 |
28 | # JDT-specific (Eclipse Java Development Tools)
29 | .classpath
30 |
31 | # Java annotation processor (APT)
32 | .factorypath
33 |
34 | # PDT-specific (PHP Development Tools)
35 | .buildpath
36 |
37 | # sbteclipse plugin
38 | .target
39 |
40 | # TeXlipse plugin
41 | .texlipse
42 |
43 | # STS (Spring Tool Suite)
44 | .springBeans
45 |
46 |
47 | # Java
48 | *.class
49 |
50 | # Mobile Tools for Java (J2ME)
51 | .mtj.tmp/
52 |
53 | # Package Files #
54 | *.jar
55 | *.war
56 | *.ear
57 |
58 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
59 | hs_err_pid*
60 |
61 |
62 | # Maven
63 | /target/
64 | pom.xml.tag
65 | pom.xml.releaseBackup
66 | pom.xml.versionsBackup
67 | pom.xml.next
68 | release.properties
69 | dependency-reduced-pom.xml
70 | buildNumber.properties
71 | .mvn/timing.properties
72 | /classxml/
73 | /properties/
74 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/data/members/HKXFailedMember.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.data.members;
2 |
3 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
4 |
5 | /**
6 | * Represents a member that failed to be imported.
7 | */
8 | public class HKXFailedMember implements HKXMember {
9 | private final String name;
10 | private final HKXType type;
11 | private final String failMessage;
12 |
13 | /**
14 | * Creates a {@link HKXFailedMember}.
15 | *
16 | * @param name the name of the failed member.
17 | * @param type the intended type of the failed member.
18 | * @param failMessage why the member failed to be imported.
19 | */
20 | public HKXFailedMember(final String name, final HKXType type, final String failMessage) {
21 | this.name = name;
22 | this.type = type;
23 | this.failMessage = failMessage;
24 | }
25 |
26 | /**
27 | * Returns a sensible message, in english, about the import fail.
28 | *
29 | * @return
30 | */
31 | public String getFailMessage() {
32 | return "Couldn't read " + name + " : " + failMessage;
33 | }
34 |
35 | @Override
36 | /**
37 | * {@inheritDoc}
38 | */
39 | public String getName() {
40 | return name;
41 | }
42 |
43 | @Override
44 | /**
45 | * {@inheritDoc}
46 | */
47 | public HKXType getType() {
48 | return type;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/cli/src/debug/java/com/dexesttp/hkxpack/cli/TestView.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli;
2 |
3 | import java.util.logging.Logger;
4 |
5 | import com.dexesttp.hkxpack.cli.components.HKXTest;
6 | import com.dexesttp.hkxpack.cli.components.Read;
7 | import com.dexesttp.hkxpack.cli.components.Write;
8 | import com.dexesttp.hkxpack.cli.components.XMLTest;
9 | import com.dexesttp.hkxpack.resources.LoggerUtil;
10 |
11 | /**
12 | * Testing interface, used to perform live tests with Eclipse.
13 | *
14 | * @see HKXTest#exec(String, String)
15 | * @see XMLTest#exec(String, String)
16 | * @see Read#exec(String, String)
17 | * @see Write#exec(String, String)
18 | */
19 | final class TestView {
20 | public static final Logger LOGGER = Logger.getLogger(TestView.class.getName());
21 | private static final String ROOT_NAME = "D:\\Documents\\SANDBOX\\FO4\\hkx_files\\";
22 | private static final String TEST_FILE_NAME = "skeleton";
23 |
24 | /**
25 | * Testing entry point
26 | * @param args
27 | */
28 | public static void main(final String... args) {
29 | Read.exec(ROOT_NAME, TEST_FILE_NAME);
30 | Write.exec(ROOT_NAME, TEST_FILE_NAME);
31 | Read.exec(ROOT_NAME, TEST_FILE_NAME + "-new");
32 | for(Throwable e: LoggerUtil.getList()) {
33 | LOGGER.throwing(TestView.class.getName(), "main", e);
34 | }
35 | }
36 |
37 | private TestView() {
38 | // NO OP
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/resources/byteutils/SLongByteUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.resources.byteutils;
2 |
3 | import static org.junit.Assert.assertArrayEquals;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Tests for the {@link SLongByteUtils} class
9 | */
10 | public class SLongByteUtilsTest {
11 | @Test
12 | /**
13 | * Test
14 | */
15 | public void getSLongSize2WorksFor0() {
16 | assertArrayEquals("SLong(2) : 0 => 0", new byte[] { 0, 0 }, SLongByteUtils.fromLong(0, 2));
17 | }
18 |
19 | @Test
20 | /**
21 | * Test
22 | */
23 | public void getSLongSize2WorksFor1() {
24 | assertArrayEquals("SLong(2) : 1 => 1", new byte[] { 1, 0 }, SLongByteUtils.fromLong(1, 2));
25 | }
26 |
27 | @Test
28 | /**
29 | * Test
30 | */
31 | public void getSLongSize2WorksForMinus1() {
32 | assertArrayEquals("SLong(2) : -1 => -1", new byte[] { -1, -1 }, SLongByteUtils.fromLong(-1, 2));
33 | }
34 |
35 | @Test
36 | /**
37 | * Test
38 | */
39 | public void getSILongSize2WorksForMaxValue() {
40 | assertArrayEquals("SLong(2) : 32767 => 32767", new byte[] { -1, 127 }, SLongByteUtils.fromLong(32767, 2));
41 | }
42 |
43 | @Test
44 | /**
45 | * Test
46 | */
47 | public void getSIntSize2WorksForMinValue() {
48 | assertArrayEquals("SLong(2) : -32768 => -32768", new byte[] { 0, -128 }, SLongByteUtils.fromLong(-32768, 2));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/commands/CommandFactory.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.commands;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.Optional;
6 |
7 | /**
8 | * Routes a command line interface into the relevant {@link Command}.
9 | */
10 | public class CommandFactory {
11 | /**
12 | * List of commands associated with the class to execute on read
13 | */
14 | @SuppressWarnings("rawtypes")
15 | public static Map commandParser = new HashMap<>();
16 | static {
17 | commandParser.put("extract", Command_unpack.class);
18 | commandParser.put("unpack", Command_unpack.class);
19 | commandParser.put("compress", Command_pack.class);
20 | commandParser.put("pack", Command_pack.class);
21 | commandParser.put("help", Command_help.class);
22 | }
23 |
24 | /**
25 | * Retrieves the relevant {@link Command}.
26 | *
27 | * @param commandName the first argument passed to main.
28 | * @return the relevant {@link Command}.
29 | */
30 | public Command newInstance(final String commandName) {
31 | @SuppressWarnings("rawtypes")
32 | Optional commandClass = Optional.ofNullable(commandParser.get(commandName));
33 | try {
34 | return (Command) commandClass.orElse(Command_quick.class).newInstance();
35 | } catch (InstantiationException | IllegalAccessException e) {
36 | return new Command_quick();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/resources/byteutils/FloatByteUtils.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.resources.byteutils;
2 |
3 | /**
4 | * Handles converting {@link float} and {@link double} values from and to
5 | * Little-Endian {@link byte} arrays
6 | */
7 | final class FloatByteUtils {
8 | private static final int DOUBLE_SIZE = 0x08;
9 |
10 | private FloatByteUtils() {
11 | // NO OP
12 | }
13 |
14 | /**
15 | * Convert a {@link double} value to a {@link byte} array.
16 | *
17 | * @param value the {@link double} value to convert
18 | * @param numBytes the number of bytes in the {@link byte} array
19 | * @return the relevant {@link byte} array
20 | */
21 | static byte[] fromFloat(final double value, final int numBytes) {
22 | if (numBytes == DOUBLE_SIZE) {
23 | long temp = Double.doubleToLongBits(value);
24 | return ULongByteUtils.fromLong(temp, numBytes);
25 | } else {
26 | int temp = Float.floatToIntBits((float) value);
27 | return ULongByteUtils.fromLong(temp, numBytes);
28 | }
29 | }
30 |
31 | /**
32 | * Convert a {@link byte} array containing a {@link float} value to a
33 | * {@link float}.
34 | *
35 | * @param value the {@link byte} array to convert
36 | * @return the converted {@link float}
37 | */
38 | static float getFloat(final byte[] value) {
39 | int val = (int) ULongByteUtils.getLong(value);
40 | return Float.intBitsToFloat(val);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/header/internals/HeaderDescriptor.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.header.internals;
2 |
3 | /**
4 | * A general purpose Header descriptor, designed based on the v8 and v11
5 | * headers.
6 | */
7 | public class HeaderDescriptor {
8 | /**
9 | * The file id, same for all hkx files (I assume says that it's a hkx file)
10 | */
11 | public byte[] fileID = new byte[] { 87, -32, -32, 87, 16, -64, -64, 16, 0, 0, 0, 0 };
12 | /**
13 | * The file version, over 4 bytes. See docs for what versions are what.
14 | */
15 | public byte[] version = new byte[4];
16 | /**
17 | * Extra data. This isn't labeled as constants as it changes between version 8
18 | * and 11.
19 | */
20 | public byte[] extras = new byte[4];
21 | /**
22 | * Some constant data. No idea what it is for.
23 | */
24 | public byte[] constants = new byte[] { 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, 0, 0 };
25 | /**
26 | * A string containing the version name.
27 | */
28 | public byte[] verName = new byte[14];
29 | /**
30 | * Some more constants.
31 | */
32 | public byte[] constants2 = new byte[] { 0, -1, 0, 0, 0, 0 };
33 | /**
34 | * This is either FF on version 8, or some data on version 11.
35 | */
36 | public byte[] extras11 = new byte[2];
37 | /**
38 | * This appears to be a padding before the next data chunk for version 11.
39 | */
40 | public byte[] padding11 = new byte[2];
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/HKXDescriptorReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader;
2 |
3 | import com.dexesttp.hkxpack.data.HKXObject;
4 | import com.dexesttp.hkxpack.descriptor.HKXDescriptor;
5 |
6 | /**
7 | * Reads an {@link HKXObject} based on its {@link HKXDescriptor}.
8 | */
9 | class HKXDescriptorReader {
10 | private final transient HKXObjectReader creator;
11 | private final transient PointerNameGenerator generator;
12 |
13 | /**
14 | * Create a new HKXDescriptorReader
15 | *
16 | * @param creator the {@link HKXObjectReader} to use while creating the
17 | * {@link HKXObject}.
18 | * @param generator the {@link PointerNameGenerator} to generate names from.
19 | */
20 | HKXDescriptorReader(final HKXObjectReader creator, final PointerNameGenerator generator) {
21 | this.creator = creator;
22 | this.generator = generator;
23 | }
24 |
25 | /**
26 | * Read an HKXObject from the file.
27 | *
28 | * @param position the position the {@link HKXObject} shoud be read from.
29 | * @param descriptor the {@link HKXDescriptor} describing the {@link HKXObject}
30 | * to read.
31 | * @return an {@link HKXObject} containing all the read contents.
32 | */
33 | HKXObject read(final long position, final HKXDescriptor descriptor) {
34 | String objectName = generator.get(position);
35 | return creator.createHKXObject(objectName, position, descriptor);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/header/HKXHeaderFactory.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.header;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.dexesttp.hkxpack.data.HKXFile;
7 | import com.dexesttp.hkxpack.data.HKXObject;
8 | import com.dexesttp.hkxpack.hkx.header.HeaderData;
9 |
10 | /**
11 | * Creates a {@link HeaderData} object from the given {@link HKXFile}.
12 | */
13 | public class HKXHeaderFactory {
14 | private final transient List animClassesList = new ArrayList<>();
15 |
16 | /**
17 | * Creates a {@link HKXHeaderFactory}
18 | */
19 | public HKXHeaderFactory() {
20 | animClassesList.add("hkaAnimationContainer");
21 | animClassesList.add("hclClothData");
22 | }
23 |
24 | /**
25 | * Creates a {@link HeaderData} from a {@link HKXFile}.
26 | *
27 | * @param file the {@link HKXFile} to get the header from.
28 | * @return the relevant {@link HeaderData}.
29 | */
30 | public HeaderData create(final HKXFile file) {
31 | boolean isAnim = false;
32 | for (HKXObject object : file.getContentCollection()) {
33 | if (animClassesList.contains(object.getDescriptor().getName())) {
34 | isAnim = true;
35 | }
36 | }
37 |
38 | HeaderData header = new HeaderData();
39 | header.version = file.getClassVersion();
40 | header.versionName = file.getContentsVersion();
41 | header.paddingAfter = isAnim ? 0x10 : 0x00;
42 |
43 | return header;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/resources/byteutils/SLongByteUtils.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.resources.byteutils;
2 |
3 | /**
4 | * Handles converting signed {@link long} values from and to Little-Endian
5 | * {@link byte} arrays
6 | */
7 | final class SLongByteUtils {
8 | private static final long BYTE_MASK = 0xFF;
9 |
10 | private SLongByteUtils() {
11 | // NO OP
12 | }
13 |
14 | /**
15 | * Get a signed long from a {@link byte} array.
16 | *
17 | * @param list the Little-Endian {@link byte} array to convert
18 | * @return the converted signed {@link long} value.
19 | */
20 | static long getLong(final byte[] list) {
21 | final int len = list.length;
22 | int accu = 1;
23 | int res = 0;
24 | for (int i = 0; i < len; i++) {
25 | res += ((int) (list[i] & 0xFF)) * accu;
26 | accu *= 256;
27 | }
28 | return res;
29 | }
30 |
31 | /**
32 | * Get a {@link byte} array from a signed {@link long} value.
33 | *
34 | * @param value the value to convert
35 | * @param numBytes the number of bytes in the output {@link byte} array
36 | * @return a Little-Endian {@link byte} array.
37 | */
38 | static byte[] fromLong(final long value, final int numBytes) {
39 | long shiftedValue = value;
40 | byte[] res = new byte[numBytes];
41 | for (int i = 0; i < numBytes; i++) {
42 | res[i] = (byte) (shiftedValue & BYTE_MASK);
43 | shiftedValue = shiftedValue >> 8;
44 | }
45 | return res;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/resources/byteutils/ULongByteUtils.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.resources.byteutils;
2 |
3 | /**
4 | * Handles converting unsigned {@link long} values from and to Little-Endian
5 | * {@link byte} arrays
6 | */
7 | final class ULongByteUtils {
8 | private static final long BYTE_MASK = 0xFF;
9 |
10 | private ULongByteUtils() {
11 | // NO OP
12 | }
13 |
14 | /**
15 | * Get an unsigned long from a {@link byte} array.
16 | *
17 | * @param list the Little-Endian {@link byte} array to convert
18 | * @return the converted unsigned {@link long} value.
19 | */
20 | static long getLong(final byte[] list) {
21 | final int len = list.length;
22 | long accu = 1;
23 | long res = 0;
24 | for (int i = 0; i < len; i++) {
25 | res += ((long) (list[i] & 0xFF)) * accu;
26 | accu *= 256;
27 | }
28 | return res;
29 | }
30 |
31 | /**
32 | * Get a {@link byte} array from an unsigned {@link long} value.
33 | *
34 | * @param value the value to convert
35 | * @param numBytes the number of bytes in the output {@link byte} array
36 | * @return a Little-Endian {@link byte} array.
37 | */
38 | static byte[] fromLong(final long value, final int numBytes) {
39 | long leftedValue = value;
40 | byte[] res = new byte[numBytes];
41 | for (int i = 0; i < numBytes; i++) {
42 | res[i] = (byte) (leftedValue & BYTE_MASK);
43 | leftedValue = leftedValue >> 8;
44 | }
45 | return res;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/hkxreader/HKXReaderExternalResource.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader;
2 |
3 | import java.io.IOException;
4 | import java.nio.ByteBuffer;
5 |
6 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
7 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
8 | import com.dexesttp.hkxpack.files.ReaderExternalResource;
9 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
10 | import com.dexesttp.hkxpack.utils.FileUtils;
11 |
12 | /**
13 | * The external resource to handle the HKX file.
14 | */
15 | public class HKXReaderExternalResource extends ReaderExternalResource {
16 | private final transient String baseFileResourceName;
17 |
18 | /**
19 | * Creates the HKXReader external resource
20 | *
21 | * @param baseFileResourceName
22 | */
23 | public HKXReaderExternalResource(final String baseFileResourceName) {
24 | super();
25 | this.baseFileResourceName = baseFileResourceName;
26 | }
27 |
28 | @Override
29 | /**
30 | * {@inheritDoc}
31 | */
32 | public void before() throws IOException, InvalidPositionException {
33 | ByteBuffer buffer = FileUtils.resourceToHKXByteBuffer(baseFileResourceName + ".hkx");
34 | HKXEnumResolver enumResolver = new HKXEnumResolver();
35 | HKXDescriptorFactory descriptorFactory = new HKXDescriptorFactory(enumResolver);
36 | HKXReader reader = new HKXReader(buffer, descriptorFactory, enumResolver);
37 | file = reader.read();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/descriptor/exceptions/ClassListReadException.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.descriptor.exceptions;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * A ClassListReadError is thrown when the class list couldn't be read properly.
7 | *
8 | * The ClassList path is supposed to be defined as a static, final resource in
9 | * {@link com.dexesttp.hkxpack.descriptor.reader.ClassXMLList}.
10 | */
11 | public class ClassListReadException extends IOException {
12 | private static final long serialVersionUID = -6189166645845112170L;
13 |
14 | /**
15 | * Creates a {@link ClassListReadException}.
16 | *
17 | * @param message a message to explain the exception.
18 | */
19 | public ClassListReadException(final String message) {
20 | super(message);
21 | }
22 |
23 | /**
24 | * Creates a {@link ClassListReadException}.
25 | *
26 | * @param throwable the exception that caused the
27 | * {@link ClassListReadException}.
28 | */
29 | public ClassListReadException(final Throwable throwable) {
30 | super(throwable);
31 | }
32 |
33 | /**
34 | * Creates a {@link ClassListReadException}.
35 | *
36 | * @param message a message to explain the exception.
37 | * @param throwable the exception that caused the
38 | * {@link ClassListReadException}.
39 | */
40 | public ClassListReadException(final String message, final Throwable throwable) {
41 | super(message, throwable);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/exceptions/InvalidPositionException.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.exceptions;
2 |
3 | /**
4 | * An {@link InvalidPositionException} signals a reading error due to the fact a
5 | * HKXDescriptor asked the HKXFile reading components to go over the file's
6 | * section limits.
7 | * Please report any instance of {@link InvalidPositionException} as a HKXPack
8 | * issue, as it is not intended behavior and can provide additional insight
9 | * about the HXK structure.
10 | * Make sure to provide a copy of the file you attempted to read, or information
11 | * about how to retrieve the file if given file is under copyright.
12 | * Link to HKXPack's issue
13 | * tracker
14 | */
15 | public class InvalidPositionException extends Exception {
16 | private static final long serialVersionUID = 5256901069828621035L;
17 | private final String section;
18 |
19 | /**
20 | * Creates an {@link InvalidPositionException}.
21 | *
22 | * @param sectName the section name where the exception happened
23 | * @param pos the invalid position
24 | */
25 | public InvalidPositionException(final String sectName, final long pos) {
26 | super("Invalid position in " + sectName + " : " + pos);
27 | this.section = sectName;
28 | }
29 |
30 | /**
31 | * Get this invalid section's name.
32 | *
33 | * @return the name
34 | */
35 | public String getSection() {
36 | return section;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/doc/hkx findings/studying __data2__ of Bloatfly.txt:
--------------------------------------------------------------------------------
1 | Values seems to be ordered by 3 :
2 | 2
3 |
4 | Tests on 2 first vals and 2 last ones
5 |
6 | <20> 2 <60> => 40 (d64)
7 | <120> 2 <230> => 110 (d272)
8 | ...
9 | <3308> 2 <3D40> => A38 (d2616)
10 | <3388> 2 <3E90> => B08 (d2824)
11 |
12 | => Inference :
13 | val1 => source
14 | val3 => destination
15 |
16 | === Beginning of part 2 === @7AC0+4D0 @7F90
17 |
18 | 20 00 00 00 @20+4D0 @4F0 8-block ?
19 | 02 00 00 00 2
20 | 60 00 00 00 @60+of2 @
21 | 20 01 00 00 @120+4D0 @5F0 8-block
22 |
23 | 02 00 00 00 2
24 | 30 02 00 00 @230+of2 @
25 | 28 01 00 00 @128+4D0 @5F8 8-block (or +)
26 | 02 00 00 00 2
27 |
28 | 20 33 00 00 @3320+of2 @
29 | 90 03 00 00 @390+4D0 @860 8-bloc
30 | 02 00 00 00 2
31 | A0 03 00 00 @3A0+of2 @
32 |
33 | 98 03 00 00 @398+4D0 @868 8-bloc (or +)
34 | 02 00 00 00 2
35 | A0 29 00 00 @29A0+of2 @
36 | E8 03 00 00 @38E+4D0 @85E 8-bloc
37 |
38 | 02 00 00 00 2
39 | 30 04 00 00 @430+of2 @
40 | F8 03 00 00 @3F8+4D0 @8C8 8-bloc => /!\ Possibly overlapping a value.
41 | 02 00 00 00 2
42 |
43 | 60 04 00 00 @460+of2
44 | D0 05 00 00 @5D0+4D0 @AA0 8-bloc too.
45 | 02 00 00 00 2
46 | E0 05 00 00 @5E0+of2
47 |
48 | D8 05 00 00
49 | 02 00 00 00
50 | E0 1D 00 00
51 | 40 05 00 00
52 |
53 | 02 00 00 00
54 | 20 29 00 00
55 | 38 06 00 00
56 | 02 00 00 00
57 |
58 | Remark : the value 3 seems similar to data3's value 1.
59 | => After testing, all data2's value3 are in data3's value1 AND BACK despite the size differential
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/data/members/HKXStringMember.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.data.members;
2 |
3 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
4 |
5 | /**
6 | * A {@link HKXMember} whose content is a String.
7 | */
8 | public class HKXStringMember implements HKXMember {
9 | private final String name;
10 | private final HKXType type;
11 | private transient String value;
12 |
13 | /**
14 | * Creates a {@link HKXStringMember}.
15 | *
16 | * @param name the name of the {@link HKXStringMember}.
17 | * @param type the {@link HKXType} of the {@link HKXStringMember}. Note that
18 | * {@link HKXType#getFamily()} should return
19 | * {@link HKXTypeFamily#STRING}, although this isn't checked.
20 | */
21 | public HKXStringMember(final String name, final HKXType type) {
22 | this.name = name;
23 | this.type = type;
24 | }
25 |
26 | /**
27 | * Set the String of this member.
28 | *
29 | * @param value the new String to affect.
30 | */
31 | public void set(final String value) {
32 | this.value = value;
33 | }
34 |
35 | /**
36 | * Get this {@link HKXStringMember}'s content.
37 | *
38 | * @return the value of this member.
39 | */
40 | public String get() {
41 | return value;
42 | }
43 |
44 | @Override
45 | /**
46 | * {@inheritDoc}
47 | */
48 | public String getName() {
49 | return name;
50 | }
51 |
52 | @Override
53 | /**
54 | * {@inheritDoc}
55 | */
56 | public HKXType getType() {
57 | return type;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/HKXDirectMemberHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object;
2 |
3 | import java.nio.Buffer;
4 | import java.nio.ByteBuffer;
5 |
6 | import com.dexesttp.hkxpack.data.members.HKXDirectMember;
7 | import com.dexesttp.hkxpack.data.members.HKXMember;
8 | import com.dexesttp.hkxpack.hkx.types.MemberDataResolver;
9 | import com.dexesttp.hkxpack.hkxwriter.object.callbacks.HKXMemberCallback;
10 |
11 | /**
12 | * Handles a {@link HKXDirectMember} for writing to a HKX File.
13 | *
14 | * @see MemberDataResolver#fromMember(HKXMember)
15 | */
16 | public class HKXDirectMemberHandler implements HKXMemberHandler {
17 | private final transient ByteBuffer outFile;
18 | private final transient long memberOffset;
19 |
20 | /**
21 | * Creates a {@link HKXDirectMemberHandler}.
22 | *
23 | * @param outFile the {@link ByteBuffer} to write to.
24 | * @param memberOffset the member offset in its class.
25 | */
26 | HKXDirectMemberHandler(final ByteBuffer outFile, final long memberOffset) {
27 | this.outFile = outFile;
28 | this.memberOffset = memberOffset;
29 | }
30 |
31 | @Override
32 | /**
33 | * {@inheritDoc}
34 | */
35 | public HKXMemberCallback write(final HKXMember member, final long currentPos) {
36 | byte[] value = MemberDataResolver.fromMember(member);
37 | ((Buffer) outFile).position((int) (currentPos + memberOffset));
38 | outFile.put(value);
39 | return (memberCallbacks, position) -> {
40 | return 0;
41 | };
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/types/object/PrimitiveSnap.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.types.object;
2 |
3 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
4 |
5 | /**
6 | * Contains all the primitive snap sizes
7 | */
8 | final class PrimitiveSnap {
9 | private static final long PTR_SIZE = 0x08;
10 |
11 | private PrimitiveSnap() {
12 | // NO OP
13 | }
14 |
15 | /**
16 | * Get the snap sizes for all primitive types
17 | */
18 | static long primitiveSnap(final HKXType type) {
19 | switch (type) {
20 | // Base values
21 | case TYPE_BOOL:
22 | case TYPE_CHAR:
23 | case TYPE_UINT8:
24 | case TYPE_INT8:
25 | return 0X01;
26 | case TYPE_HALF:
27 | case TYPE_UINT16:
28 | case TYPE_INT16:
29 | return 0X02;
30 | case TYPE_ULONG:
31 | case TYPE_UINT32:
32 | case TYPE_INT32:
33 | case TYPE_REAL:
34 | // Complex values
35 | case TYPE_VECTOR4:
36 | case TYPE_QUATERNION:
37 | case TYPE_TRANSFORM:
38 | case TYPE_QSTRANSFORM:
39 | case TYPE_MATRIX3:
40 | case TYPE_MATRIX4:
41 | // Relative Arrays
42 | case TYPE_RELARRAY:
43 | return 0x04;
44 | // Big base values
45 | case TYPE_UINT64:
46 | case TYPE_INT64:
47 | return 0X08;
48 | // Strings and ptrs
49 | case TYPE_CSTRING:
50 | case TYPE_STRINGPTR:
51 | case TYPE_FUNCTIONPOINTER:
52 | case TYPE_POINTER:
53 | // Arrays
54 | case TYPE_ARRAY:
55 | case TYPE_SIMPLEARRAY:
56 | return PTR_SIZE;
57 | case TYPE_NONE:
58 | case TYPE_VOID:
59 | default:
60 | return 0x00;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/PointerNameGenerator.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | /**
7 | * Generate a name based on a file position
8 | */
9 | public class PointerNameGenerator {
10 | private static final int START_VALUE = 90;
11 | private static final int INCREMENT = 1;
12 | private transient int position;
13 | private final transient Map contents = new HashMap<>();
14 |
15 | /**
16 | * Create a new {@link PointerNameGenerator}, starting at the
17 | * {@value #START_VALUE} value.
18 | */
19 | PointerNameGenerator() {
20 | this(START_VALUE);
21 | }
22 |
23 | /**
24 | * Create a new {@link PointerNameGenerator}, with names starting at the given
25 | * value.
26 | *
27 | * @param startValue the starting values for names.
28 | */
29 | public PointerNameGenerator(final int startValue) {
30 | this.position = startValue;
31 | }
32 |
33 | /**
34 | * Creates the next name
35 | *
36 | * @return
37 | */
38 | private String createName() {
39 | int nameID = position;
40 | position += INCREMENT;
41 | return "#" + nameID;
42 | }
43 |
44 | /**
45 | * Get the name associated with a file position
46 | *
47 | * @param position
48 | * @return
49 | */
50 | public String get(final long position) {
51 | if (contents.containsKey(position)) {
52 | return contents.get(position);
53 | }
54 | String name = createName();
55 | contents.put(position, name);
56 | return name;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/arrays/HKXDirectArrayContentsReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member.arrays;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import com.dexesttp.hkxpack.data.HKXData;
6 | import com.dexesttp.hkxpack.data.members.HKXDirectMember;
7 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
8 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
9 | import com.dexesttp.hkxpack.hkx.types.MemberDataResolver;
10 | import com.dexesttp.hkxpack.hkx.types.MemberSizeResolver;
11 | import com.dexesttp.hkxpack.hkxreader.HKXReaderConnector;
12 |
13 | /**
14 | * Reads a {@link HKXDirectMember} from an array.
15 | */
16 | class HKXDirectArrayContentsReader implements HKXArrayContentsReader {
17 | private final transient HKXReaderConnector connector;
18 | private final transient HKXType contentType;
19 |
20 | HKXDirectArrayContentsReader(final HKXReaderConnector connector, final HKXType contentType) {
21 | this.connector = connector;
22 | this.contentType = contentType;
23 | }
24 |
25 | @Override
26 | /**
27 | * {@inheritDoc}
28 | */
29 | public HKXData getContents(final long arrayStart, final int position) throws InvalidPositionException {
30 | final int contentSize = (int) MemberSizeResolver.getSize(contentType);
31 | byte[] bytesToRead = new byte[contentSize];
32 | ByteBuffer file = connector.data.setup(arrayStart + position * contentSize);
33 | file.get(bytesToRead);
34 | return MemberDataResolver.getMember("", contentType, bytesToRead);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/doc/hkx findings/Studying __data1__ of BloatflyRootBehavior.txt:
--------------------------------------------------------------------------------
1 | val addr+4D0 content
2 | 00 00 00 00 @4D0 28 block (10 w/ 80)
3 | 10 00 00 00 @4E0 18 block
4 | 10 00 00 00 @4E0 18 block
5 | 28 00 00 00 @4F8 text (class) (18 block ?)
6 |
7 | 18 00 00 00 @4E8 10 block
8 | 40 00 00 00 @510 text (class?)
9 | 98 00 00 00 @5C8 >40 block (8 w/ 80)
10 | 10 02 00 00 @6E0 text (file) (40 block ?) (48 w/ 80)
11 |
12 | 68 02 00 00 @738 >40 block
13 | 80 03 00 00 @850 text (name)
14 | 00 03 00 00 @7D0 >40 block (10 w/ 80)
15 | 90 03 00 00 @860 >40 block (38 w/ 80)
16 |
17 | 00 04 00 00 @8D0 20 block (10 w/ 803F)
18 | 20 04 00 00 @8F0 text (name)
19 | 40 04 00 00 @910 >40 block (10 w/ 80)
20 | 50 04 00 00 @920 >40 block (38 w/ 80)
21 |
22 | 98 04 00 00 @968 >40 block
23 | B0 05 00 00 @A80 text (name)
24 | 30 05 00 00 @A00 >40 block (10 w/ 80)
25 | D0 05 00 00 @AA0 >40 block (38 w/ 80)
26 |
27 | 40 06 00 00 @B10 20 block (10 w/ 803F)
28 | 60 06 00 00 @B30 text (name)
29 | B8 06 00 00 @B88 >40 block
30 | 20 07 00 00 @BF0 text (name)
31 |
32 | 68 07 00 00 @C38 38 block (30 w/ 80)
33 | A0 07 00 00 @C70 text (name)
34 | 88 07 00 00 @C58 18 block (10 w/ 80)
35 | B0 07 00 00 @C80 >40 block
36 |
37 | 08 08 00 00 @CD8 >40 block (34 w/ 803F)
38 | 60 08 00 00 @D30 text (name)
39 | A8 08 00 00 @D78 38 block (30 w/ 80)
40 | E0 08 00 00 @DB0 text (name)
41 |
42 | 30 09 00 00 @E00 >40 block (10 w/ 80)
43 | 40 09 00 00 @E10 >40 block
44 | => Values counting from 00 to 16
45 | A8 09 00 00 @E78 >40 block (weird) (38 w/ 803F)
46 | 20 0A 00 00 @EF0 text (name)
47 |
48 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/HKXPointerMemberHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object;
2 |
3 | import java.util.List;
4 |
5 | import com.dexesttp.hkxpack.data.members.HKXMember;
6 | import com.dexesttp.hkxpack.data.members.HKXPointerMember;
7 | import com.dexesttp.hkxpack.hkxwriter.object.callbacks.HKXMemberCallback;
8 | import com.dexesttp.hkxpack.hkxwriter.utils.PointerObject;
9 |
10 | /**
11 | * Handles a {@link HKXPointerMember} for writing to a HKX File
12 | */
13 | public class HKXPointerMemberHandler implements HKXMemberHandler {
14 | private final transient long offset;
15 | private final transient List data2;
16 |
17 | /**
18 | * Creates a {@link HKXPointerMemberHandler}.
19 | *
20 | * @param offset the offset of the mmember in the class.
21 | * @param data2List the list of external pointers to put the pointer resolver
22 | * into.
23 | */
24 | HKXPointerMemberHandler(final long offset, final List data2List) {
25 | this.offset = offset;
26 | this.data2 = data2List;
27 | }
28 |
29 | @Override
30 | /**
31 | * {@inheritDoc}
32 | */
33 | public HKXMemberCallback write(final HKXMember member, final long currentPos) {
34 | HKXPointerMember ptrMember = (HKXPointerMember) member;
35 | PointerObject ptrObject = new PointerObject();
36 | ptrObject.from = currentPos + offset;
37 | ptrObject.to = ptrMember.get();
38 | data2.add(ptrObject);
39 | return (callbacks, position) -> {
40 | return 0;
41 | };
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/tagreader/TagXMLReaderExceptionTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 |
6 | import javax.xml.parsers.ParserConfigurationException;
7 |
8 | import org.junit.Before;
9 | import org.junit.Test;
10 | import org.xml.sax.SAXException;
11 |
12 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
13 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
14 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
15 | import com.dexesttp.hkxpack.utils.FileUtils;
16 |
17 | /**
18 | * Tests for exception throwing in the TagXMLReader class
19 | */
20 | public class TagXMLReaderExceptionTest {
21 | public static final String TEST_BASE_RESOURCE = "/test-base.xml";
22 | private transient HKXDescriptorFactory descriptorFactory;
23 |
24 | @Before
25 | /**
26 | * Set up the TagXMLReader tests
27 | */
28 | public void setUp() throws Exception {
29 | HKXEnumResolver enumResolver = new HKXEnumResolver();
30 | this.descriptorFactory = new HKXDescriptorFactory(enumResolver);
31 | }
32 |
33 | @Test
34 | /**
35 | * Test reading the file.
36 | *
37 | * @throws Exception
38 | */
39 | public void baseFileReadingUsingFileDoesntThrowAnException()
40 | throws IOException, ParserConfigurationException, SAXException, InvalidTagXMLException {
41 | File toRead = FileUtils.resourceToTemporaryFile(TEST_BASE_RESOURCE);
42 | TagXMLReader reader = new TagXMLReader(toRead, descriptorFactory);
43 | reader.read();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/descriptor/reader/ClassXMLReaderFactory.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.descriptor.reader;
2 |
3 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
4 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
5 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassListReadException;
6 |
7 | /**
8 | * Creates a {@link ClassXMLReader} from a
9 | * {@link com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory}.
10 | *
11 | * It is expected for the HKXDescriptorFactory to have the ClassXMLReader as
12 | * internal reader.
13 | * That means you must be doing something very technical to have to use a
14 | * ClassXMLReaderFactory yourself.
15 | */
16 | public class ClassXMLReaderFactory {
17 | private final transient HKXEnumResolver enumResolver;
18 |
19 | /**
20 | * Create a new ClassXMLReaderFactory.
21 | *
22 | * @param enumResolver
23 | * @see ClassXMLReaderFactory
24 | */
25 | public ClassXMLReaderFactory(final HKXEnumResolver enumResolver) {
26 | this.enumResolver = enumResolver;
27 | }
28 |
29 | /**
30 | * Create a {@link ClassXMLReader}, linked to a {@link HKXDescriptorFactory}.
31 | *
32 | * @param descriptor the {@link HKXDescriptorFactory} to use.
33 | * @return a new {@link ClassXMLReader}
34 | * @throws ClassListReadException
35 | */
36 | public ClassXMLReader create(final HKXDescriptorFactory descriptor) throws ClassListReadException {
37 | ClassXMLList list = new ClassXMLList();
38 | return new ClassXMLReader(descriptor, list, enumResolver);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/arrays/HKXObjectArrayContentsReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member.arrays;
2 |
3 | import com.dexesttp.hkxpack.data.HKXData;
4 | import com.dexesttp.hkxpack.data.HKXObject;
5 | import com.dexesttp.hkxpack.descriptor.HKXDescriptor;
6 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
7 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
8 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
9 | import com.dexesttp.hkxpack.hkx.types.ObjectSizeResolver;
10 | import com.dexesttp.hkxpack.hkxreader.HKXObjectReader;
11 |
12 | /**
13 | * Reads an {@link HKXObject} from an array.
14 | */
15 | class HKXObjectArrayContentsReader implements HKXArrayContentsReader {
16 | private final transient HKXObjectReader reader;
17 | private final transient HKXDescriptor descriptor;
18 | private final transient int contentSize;
19 |
20 | HKXObjectArrayContentsReader(final HKXObjectReader reader, final HKXDescriptorFactory descriptorFactory,
21 | final HKXDescriptor descriptor) throws ClassFileReadException {
22 | this.reader = reader;
23 | this.descriptor = descriptor;
24 | this.contentSize = (int) ObjectSizeResolver.getSize(descriptor, descriptorFactory);
25 | }
26 |
27 | @Override
28 | /**
29 | * {@inheritDoc}
30 | */
31 | public HKXData getContents(final long arrayStart, final int position) throws InvalidPositionException {
32 | long contentsPos = arrayStart + position * contentSize;
33 | return reader.createHKXObject("", contentsPos, descriptor);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/descriptor/HKXDescriptor.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.descriptor;
2 |
3 | import java.util.List;
4 |
5 | import com.dexesttp.hkxpack.descriptor.members.HKXMemberTemplate;
6 |
7 | /**
8 | * A HKXDescriptor contains a name, a flag and a list of members.
9 | */
10 | public class HKXDescriptor {
11 | private final String name;
12 | private final long signature;
13 | private final transient List members;
14 |
15 | /**
16 | * Creates a HKXDescriptor
17 | *
18 | * Note : you should use {@link HKXDescriptorFactory#get(String)} to get a
19 | * HKXDescriptor, unless you're doing something very technical.
20 | *
21 | * @param name
22 | * @param signature
23 | * @param members
24 | */
25 | public HKXDescriptor(final String name, final long signature, final List members) {
26 | this.name = name;
27 | this.signature = signature;
28 | this.members = members;
29 | }
30 |
31 | /**
32 | * Get the descriptor's name.
33 | *
34 | * @return the name, as a {@link String}
35 | */
36 | public String getName() {
37 | return name;
38 | }
39 |
40 | /**
41 | * Get the descriptor's signature.
42 | *
43 | * @return the signature, as a {@link long}
44 | */
45 | public long getSignature() {
46 | return signature;
47 | }
48 |
49 | /**
50 | * Get a {@link List} of all the member's templates, as
51 | * {@link HKXMemberTemplate}.
52 | *
53 | * @return the list of members.
54 | */
55 | public List getMemberTemplates() {
56 | return members;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/arrays/HKXPointerArrayContentsReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member.arrays;
2 |
3 | import com.dexesttp.hkxpack.data.HKXData;
4 | import com.dexesttp.hkxpack.data.members.HKXPointerMember;
5 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
6 | import com.dexesttp.hkxpack.hkx.data.DataExternal;
7 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
8 | import com.dexesttp.hkxpack.hkxreader.HKXReaderConnector;
9 | import com.dexesttp.hkxpack.hkxreader.PointerNameGenerator;
10 |
11 | /**
12 | * Reads a {@link HKXPointerMember} from an array.
13 | */
14 | public class HKXPointerArrayContentsReader implements HKXArrayContentsReader {
15 | private final transient PointerNameGenerator generator;
16 | private final transient HKXReaderConnector connector;
17 |
18 | HKXPointerArrayContentsReader(final HKXReaderConnector connector, final PointerNameGenerator generator) {
19 | this.connector = connector;
20 | this.generator = generator;
21 | }
22 |
23 | @Override
24 | /**
25 | * {@inheritDoc}
26 | */
27 | public HKXData getContents(final long arrayStart, final int position) throws InvalidPositionException {
28 | long contentsPosition = arrayStart + position * 0x08;
29 | DataExternal data = connector.data2.readNext();
30 | String target = "null";
31 | if (data.from == contentsPosition) {
32 | target = generator.get(data.to);
33 | } else {
34 | connector.data2.backtrack();
35 | }
36 | return new HKXPointerMember("", HKXType.TYPE_POINTER, HKXType.TYPE_NONE, target);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/array/HKXArrayPointerMemberHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object.array;
2 |
3 | import java.util.List;
4 |
5 | import com.dexesttp.hkxpack.data.members.HKXPointerMember;
6 | import com.dexesttp.hkxpack.hkx.data.DataExternal;
7 | import com.dexesttp.hkxpack.hkxwriter.utils.PointerObject;
8 |
9 | /**
10 | * Handle a {@link HKXPointerMember}'s array contents by deferring the position
11 | * and content value definition, and deferring its inclusion into the
12 | * {@link DataExternal} list.
13 | */
14 | public class HKXArrayPointerMemberHandler {
15 | private final transient List data2;
16 | private transient PointerObject data2Instance;
17 |
18 | /**
19 | * Creates a {@link HKXArrayPointerMemberHandler}
20 | *
21 | * @param data2List the {@link DataExternal} list to write the Pointer resolver
22 | * to
23 | */
24 | public HKXArrayPointerMemberHandler(final List data2List) {
25 | this.data2 = data2List;
26 | }
27 |
28 | /**
29 | * Set this pointer handler's value.
30 | *
31 | * @param internalPointer the {@link HKXPointerMember} to set.
32 | */
33 | public void setPointer(final HKXPointerMember internalPointer) {
34 | data2Instance = new PointerObject();
35 | data2Instance.to = internalPointer.get();
36 | data2.add(data2Instance);
37 | }
38 |
39 | /**
40 | * Resolve the current pointer to a position.
41 | *
42 | * @param newPos
43 | */
44 | public void resolve(final long newPos) {
45 | data2Instance.from = newPos;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/types/ObjectSizeResolver.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.types;
2 |
3 | import com.dexesttp.hkxpack.data.HKXObject;
4 | import com.dexesttp.hkxpack.descriptor.HKXDescriptor;
5 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
6 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
7 | import com.dexesttp.hkxpack.hkx.types.object.ObjectSize;
8 |
9 | /**
10 | * Resolve the size of a {@link HKXObject} or a {@link HKXDescriptor}.
11 | */
12 | public final class ObjectSizeResolver {
13 |
14 | private ObjectSizeResolver() {
15 | // NO OP
16 | }
17 |
18 | /**
19 | * Retrieves the size of a {@link HKXDescriptor}, including end padding if
20 | * needed.
21 | *
22 | * @param descriptor the {@link HKXDescriptor} to retrieve the size from.
23 | * @return the {@link HKXDescriptor}'s size, in bytes.
24 | * @throws ClassFileReadException if there was an error resolving this
25 | * {@link HKXDescriptor}'s subclass
26 | */
27 | public static long getSize(final HKXDescriptor descriptor, final HKXDescriptorFactory descriptorFactory)
28 | throws ClassFileReadException {
29 | return ObjectSize.getSize(descriptor, descriptorFactory);
30 | }
31 |
32 | /**
33 | * Retrieves the size of a {@link HKXObject}, including end padding if needed.
34 | *
35 | * @param object the {@link HKXObject} to retrieve the size from.
36 | * @return the {@link HKXObject}'s size, in bytes.
37 | */
38 | public static long getSize(final HKXObject object) {
39 | return ObjectSize.getSize(object);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagreader/serialized/TagXMLComplexSerializedHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader.serialized;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXDirectMember;
4 | import com.dexesttp.hkxpack.data.members.HKXMember;
5 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
6 | import com.dexesttp.hkxpack.descriptor.members.HKXMemberTemplate;
7 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
8 |
9 | /**
10 | * Handles generation of complex serialized members.
11 | */
12 | class TagXMLComplexSerializedHandler implements TagXMLSerializedHandler {
13 |
14 | @Override
15 | /**
16 | * {@inheritDoc}
17 | */
18 | public HKXMember handleMember(final HKXMemberTemplate memberTemplate)
19 | throws ClassFileReadException, InvalidTagXMLException {
20 | return emptyMember(memberTemplate);
21 | }
22 |
23 | private HKXMember emptyMember(final HKXMemberTemplate memberTemplate) {
24 | HKXDirectMember member = new HKXDirectMember<>(memberTemplate.name, memberTemplate.vtype);
25 | switch (memberTemplate.vtype) {
26 | case TYPE_VECTOR4:
27 | case TYPE_QUATERNION:
28 | member.set(new Double[] { 0., 0., 0., 0. });
29 | break;
30 | case TYPE_MATRIX3:
31 | case TYPE_QSTRANSFORM:
32 | member.set(new Double[] { 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. });
33 | break;
34 | case TYPE_MATRIX4:
35 | case TYPE_TRANSFORM:
36 | member.set(new Double[] { 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. });
37 | break;
38 | default:
39 | break;
40 | }
41 | return member;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/data/DataInterface.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.data;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.nio.Buffer;
5 |
6 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
7 | import com.dexesttp.hkxpack.hkx.header.SectionData;
8 |
9 | /**
10 | * Interface to connect to the Data section of the file.
11 | */
12 | public class DataInterface {
13 | private transient ByteBuffer file;
14 | private transient SectionData header;
15 |
16 | /**
17 | * Connect this {@link DataInterface} to a {@link ByteBuffer}, using information
18 | * from the file's header.
19 | *
20 | * @param file the {@link ByteBuffer} to connect to.
21 | * @param dataHeader the {@link SectionData} information relative to the Data
22 | * sections.
23 | */
24 | public void connect(final ByteBuffer file, final SectionData dataHeader) {
25 | this.file = file;
26 | this.header = dataHeader;
27 | }
28 |
29 | /**
30 | * Setup the file to a specific position.
31 | *
32 | * @param position the position to setup the file in Data at.
33 | * @return the {@link ByteBuffer}, at the given position in Data.
34 | * @throws InvalidPositionException if the position is outside the file's Data
35 | * definition.
36 | */
37 | public ByteBuffer setup(final long position) throws InvalidPositionException {
38 | if (position < 0 || position > header.data1) {
39 | throw new InvalidPositionException("DATA", position);
40 | }
41 | ((Buffer) file).position((int) (header.offset + position));
42 | return file;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/HKXDirectMemberReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import com.dexesttp.hkxpack.data.members.HKXMember;
6 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
7 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
8 | import com.dexesttp.hkxpack.hkx.types.MemberDataResolver;
9 | import com.dexesttp.hkxpack.hkx.types.MemberSizeResolver;
10 | import com.dexesttp.hkxpack.hkxreader.HKXReaderConnector;
11 |
12 | /**
13 | * Reads a direct or complex member from a HKX file.
14 | *
15 | * @see MemberDataResolver
16 | */
17 | class HKXDirectMemberReader implements HKXMemberReader {
18 | private final transient HKXReaderConnector connector;
19 | private final transient String name;
20 | private final transient HKXType vtype;
21 | private final transient long memberOffset;
22 |
23 | HKXDirectMemberReader(final HKXReaderConnector connector, final String name, final HKXType contentType,
24 | final long offset) {
25 | this.connector = connector;
26 | this.name = name;
27 | this.vtype = contentType;
28 | this.memberOffset = offset;
29 | }
30 |
31 | @Override
32 | /**
33 | * {@inheritDoc}
34 | */
35 | public HKXMember read(final long classOffset) throws InvalidPositionException {
36 | final int memberSize = (int) MemberSizeResolver.getSize(vtype);
37 | ByteBuffer file = connector.data.setup(classOffset + memberOffset);
38 | byte[] bytesToRead = new byte[memberSize];
39 | file.get(bytesToRead);
40 | return MemberDataResolver.getMember(name, vtype, bytesToRead);
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/callbacks/HKXBaseArrayMemberCallback.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object.callbacks;
2 |
3 | import java.util.List;
4 |
5 | import com.dexesttp.hkxpack.hkx.data.DataInternal;
6 |
7 | /**
8 | * The base array's callback.
9 | *
10 | * @see HKXArrayMemberCallback
11 | */
12 | public class HKXBaseArrayMemberCallback implements HKXMemberCallback {
13 | private final transient HKXArrayMemberCallback callbackProcessor;
14 | private final transient List data1;
15 | private final transient DataInternal arrData;
16 |
17 | /**
18 | * Create a {@link HKXBaseArrayMemberCallback}.
19 | *
20 | * @param callbackProcessor the {@link HKXArrayMemberCallback} to use for each
21 | * array member.
22 | * @param data1 the {@link DataInternal} list to fill the array's
23 | * position into.
24 | * @param arrData the {@link DataInternal} prepared with the array
25 | * hook's position.
26 | */
27 | public HKXBaseArrayMemberCallback(final HKXArrayMemberCallback callbackProcessor, final List data1,
28 | final DataInternal arrData) {
29 | this.callbackProcessor = callbackProcessor;
30 | this.data1 = data1;
31 | this.arrData = arrData;
32 | }
33 |
34 | @Override
35 | /**
36 | * {@inheritDoc}
37 | */
38 | public long process(final List memberCallbacks, final long position) {
39 | arrData.to = position;
40 | data1.add(arrData);
41 | return callbackProcessor.process(memberCallbacks, position);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/doc/hkx findings/Studying animation- DeathChest01 .txt:
--------------------------------------------------------------------------------
1 | What we know (from Highflex's Havok2FBX tool) :
2 |
3 | - Animations conversion software use the following files to create the actual animation data :
4 | A skeleton
5 | An animation file
6 |
7 | - The output can be put in a FBX fle, which will then be self-sufficient.
8 | An FBX file contains :
9 |
10 | There is a number of members that can be related easily to each other :
11 |
12 | hkaSplineCompressedAnimation [#92]:
13 | Number of transform tracks <=> annotation tracks (size)
14 | Num frames <=> reference Frame samples (size) of target extractedMotion
15 | maxFramesPerBlock * frameDuration => blockDuration
16 | 1 / blockDuration => blockInverseDuration
17 | duration <=> blockDuration * numFrames / maxFramesPerBlock
18 |
19 | hkaAnimationBinding [#94]:
20 | Transform Track To Bone Indice (size) <=> number of Transform Tracks of target animation
21 |
22 | Compressed Spline :
23 | http://anarchy.cn/manual/12/HavokSdk_ProgrammersManual/animationcompression.html
24 | B-Splines, or NURBS, are a way to store data in "knots". In addition to this storage, there is a way to remove some of the nodes and replace it by extra data less costly in weight. There is also a general compression algorithm.
25 | => see also : http://dsanta.users.ch/research/These-2770-SantaCruz.pdf (thesis on B-Spline compression)
26 | => the algorithm may be protected behind some patent or commercial secret. In this case, it may not be possible to write an open-source converter.
27 | => There is also the posibility that the algorithm is publicly available, through research papers.
28 | => Thanks to Aerisam for his help
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/commands/Command_quick.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.commands;
2 |
3 | import java.io.File;
4 | import java.util.logging.Logger;
5 |
6 | import com.dexesttp.hkxpack.cli.ConsoleView;
7 |
8 | /**
9 | * Routes an unknown command to either a help, pack or unpack command.
10 | */
11 | public class Command_quick implements Command {
12 | private static final Logger LOGGER = Logger.getLogger(ConsoleView.class.getName());
13 | private static final int MINIMUM_PARAMETERS_COUNT = 1;
14 |
15 | @Override
16 | /**
17 | * {@inheritDoc}
18 | */
19 | public int execute(final String... parameters) {
20 | if (parameters.length > MINIMUM_PARAMETERS_COUNT) {
21 | return new Command_help().execute(parameters);
22 | }
23 | Command command = null;
24 | String inName = parameters[0];
25 | File inFile = new File(inName);
26 | String name = inFile.getName();
27 | String commandArg = "";
28 | try {
29 | if (!inFile.isFile()) {
30 | throw new IllegalArgumentException("The given parameter isn't a HKX or XML file.");
31 | }
32 | String ext = name.substring(name.lastIndexOf('.') + 1);
33 | if (ext.equals("hkx")) {
34 | command = new Command_unpack();
35 | commandArg = "unpack";
36 | } else if (ext.equals("xml")) {
37 | command = new Command_pack();
38 | commandArg = "pack";
39 | } else {
40 | throw new IllegalArgumentException("Unsupported file type.");
41 | }
42 | } catch (IllegalArgumentException e) {
43 | LOGGER.throwing(this.getClass().getName(), "execute", e);
44 | return 1;
45 | }
46 | return command.execute(commandArg, inName);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/tagreader/TagXMLReaderExternalResource.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 |
6 | import javax.xml.parsers.ParserConfigurationException;
7 |
8 | import org.xml.sax.SAXException;
9 |
10 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
11 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
12 | import com.dexesttp.hkxpack.files.ReaderExternalResource;
13 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
14 | import com.dexesttp.hkxpack.utils.FileUtils;
15 |
16 | /**
17 | * External resource handler for the TagXML file.
18 | */
19 | public class TagXMLReaderExternalResource extends ReaderExternalResource {
20 | private final transient String baseFileResourceName;
21 |
22 | /**
23 | * Creates a {@link TagXMLReaderExternalResource}
24 | *
25 | * @param baseFileResourceName the resource file's name, without its extension
26 | */
27 | public TagXMLReaderExternalResource(final String baseFileResourceName) {
28 | super();
29 | this.baseFileResourceName = baseFileResourceName;
30 | }
31 |
32 | /**
33 | * Set up the resource as the {@link #file} member
34 | */
35 | @Override
36 | public void before() throws IOException, ParserConfigurationException, SAXException, InvalidTagXMLException {
37 | File baseFile = FileUtils.resourceToTemporaryFile(baseFileResourceName + ".xml");
38 | HKXEnumResolver enumResolver = new HKXEnumResolver();
39 | HKXDescriptorFactory descriptorFactory = new HKXDescriptorFactory(enumResolver);
40 | TagXMLReader reader = new TagXMLReader(baseFile, descriptorFactory);
41 | file = reader.read();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/arrays/HKXStringArrayContentsReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member.arrays;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import com.dexesttp.hkxpack.data.HKXData;
6 | import com.dexesttp.hkxpack.data.members.HKXStringMember;
7 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
8 | import com.dexesttp.hkxpack.hkx.data.DataInternal;
9 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
10 | import com.dexesttp.hkxpack.hkxreader.HKXReaderConnector;
11 | import com.dexesttp.hkxpack.resources.byteutils.ByteUtils;
12 |
13 | /**
14 | * Reads a {@link HKXStringMember} from an array
15 | */
16 | class HKXStringArrayContentsReader implements HKXArrayContentsReader {
17 | private final transient HKXReaderConnector connector;
18 | private final transient HKXType contentsType;
19 |
20 | HKXStringArrayContentsReader(final HKXReaderConnector connector, final HKXType contentsType) {
21 | this.connector = connector;
22 | this.contentsType = contentsType;
23 | }
24 |
25 | @Override
26 | /**
27 | * {@inheritDoc}
28 | */
29 | public HKXData getContents(final long arrayStart, final int position) throws InvalidPositionException {
30 | long descriptorPosition = arrayStart + position * 0x08;
31 | DataInternal data = connector.data1.readNext();
32 | String contents = "";
33 | if (data.from == descriptorPosition) {
34 | ByteBuffer file = connector.data.setup(data.to);
35 | contents = ByteUtils.readString(file);
36 | } else {
37 | connector.data1.backtrack();
38 | }
39 | HKXStringMember result = new HKXStringMember("", contentsType);
40 | result.set(contents);
41 | return result;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/types/handlers/MemberHandlerFactory.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.types.handlers;
2 |
3 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
4 |
5 | /**
6 | * Creates a MemberHandler
7 | */
8 | public final class MemberHandlerFactory {
9 | private MemberHandlerFactory() {
10 | // NO OP
11 | }
12 |
13 | /**
14 | * Get a {@link MemberHandler} from a {@link HKXType}.
15 | *
16 | * @param type the {@link HKXType}.
17 | * @return the {@link MemberHandler}.
18 | */
19 | public static MemberHandler getMemberHandler(final HKXType type) {
20 | switch (type) {
21 | // Base values
22 | case TYPE_BOOL:
23 | case TYPE_CHAR:
24 | case TYPE_UINT8:
25 | case TYPE_INT8:
26 | return SmallMemberHandlers.createMemberHandler(type);
27 | case TYPE_UINT16:
28 | case TYPE_INT16:
29 | return MediumMemberHandlers.createMemberHandler(type);
30 | case TYPE_INT32:
31 | case TYPE_UINT32:
32 | return NormalMemberHandlers.createMemberHandler(type);
33 | case TYPE_ULONG:
34 | case TYPE_UINT64:
35 | case TYPE_INT64:
36 | return BigMemberHandlers.createMemberHandler(type);
37 | case TYPE_HALF:
38 | case TYPE_REAL:
39 | return RealMemberHandlers.createMemberHandler(type);
40 | // Complex values
41 | case TYPE_VECTOR4:
42 | case TYPE_QUATERNION:
43 | return new Vector4Handler();
44 | case TYPE_MATRIX3:
45 | case TYPE_QSTRANSFORM:
46 | return new Matrix3Handler();
47 | case TYPE_MATRIX4:
48 | case TYPE_TRANSFORM:
49 | return new Matrix4Handler();
50 | // Default
51 | default:
52 | break;
53 | }
54 | throw new IllegalArgumentException(type + " can't be analyzed with MemberTypeResolver#getMember");
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/cli/src/test/java/com/dexesttp/hkxpack/cli/utils/ArgsParserEmptyTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.utils;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import org.junit.Before;
6 | import org.junit.Test;
7 |
8 | import com.dexesttp.hkxpack.cli.utils.ArgsParser.Options;
9 |
10 | /**
11 | * Tests for the {@link ArgsParser}, on empty argument list
12 | */
13 | public class ArgsParserEmptyTest {
14 | private transient ArgsParser argsParser;
15 |
16 | @Before
17 | /**
18 | * {@inheritDoc}
19 | */
20 | public void setUp() {
21 | argsParser = new ArgsParser();
22 | argsParser.addOption("-a");
23 | argsParser.addOption("-b", 0);
24 | argsParser.addOption("-c", 1);
25 | }
26 |
27 | @Test
28 | /**
29 | * {@inheritDoc}
30 | */
31 | public void itShouldNotCatchSpecialOptionsIfThereIsNoArgument() throws WrongSizeException {
32 | Options result = argsParser.parse("");
33 | assertEquals(1, result.size());
34 | }
35 |
36 | @Test
37 | /**
38 | * {@inheritDoc}
39 | */
40 | public void itShouldReturnAnEmptyStringForARequestThatDoesNotExist1() throws WrongSizeException {
41 | Options result = argsParser.parse("");
42 | assertEquals("", result.get("", 1));
43 | }
44 |
45 | @Test
46 | /**
47 | * {@inheritDoc}
48 | */
49 | public void itShouldReturnAnEmptyStringForARequestThatDoesNotExist2() throws WrongSizeException {
50 | Options result = argsParser.parse("");
51 | assertEquals("", result.get("-a", 0));
52 | }
53 |
54 | @Test
55 | /**
56 | * {@inheritDoc}
57 | */
58 | public void itShouldReturnAnEmptyStringForARequestThatDoesNotExist3() throws WrongSizeException {
59 | Options result = argsParser.parse("");
60 | assertEquals("", result.get("-a", 1));
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/data/members/HKXDirectMember.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.data.members;
2 |
3 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
4 |
5 | /**
6 | * Stores all basic data found as members of an object.
7 | *
8 | * @param the Java type of the stored data. It may be a boxed type, a custom
9 | * object or an array.
10 | */
11 | public class HKXDirectMember implements HKXMember {
12 | private final HKXType type;
13 | private final String name;
14 | private transient T value;
15 |
16 | /**
17 | * Creates a {@link HKXDirectMember}.
18 | *
19 | * @param name the name of the {@link HKXDirectMember}.
20 | * @param type the type of the {@link HKXDirectMember}, as {@link HKXType}. Note
21 | * that {@link HKXType#getFamily()} should return either
22 | * {@link HKXTypeFamily#DIRECT} or {@link HKXTypeFamily#COMPLEX},
23 | * although this isn't checked.
24 | */
25 | public HKXDirectMember(final String name, final HKXType type) {
26 | this.name = name;
27 | this.type = type;
28 | }
29 |
30 | /**
31 | * Set this {@link HKXDirectMember}'s value.
32 | *
33 | * @param value the value to set the member's content to.
34 | */
35 | public void set(final T value) {
36 | this.value = value;
37 | }
38 |
39 | /**
40 | * Get this {@link HKXDirectMember}'s value.
41 | *
42 | * @return the requested value.
43 | */
44 | public T get() {
45 | return value;
46 | }
47 |
48 | @Override
49 | /**
50 | * {@inheritDoc}
51 | */
52 | public String getName() {
53 | return name;
54 | }
55 |
56 | @Override
57 | /**
58 | * {@inheritDoc}
59 | */
60 | public HKXType getType() {
61 | return type;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/doc/hkx findings/studying __data3__ of Bloatfly.txt:
--------------------------------------------------------------------------------
1 | Value also seems to be ordered by 3
2 | 00 00 00 00 00
3 | 00 00 00 00 (standard 00 ?)
4 | 4B 00 00 00 #4B => @1730 text (pelvisIndex)
5 | @4B+4D0 @51B middle of text
6 | @4B+100 @14B text (hkRootLevelContainer)
7 | 60 00 00 00 #60 => @1DB8 18-block w/ FF
8 | @60+4D0 @530 28-block w/ 80
9 | @60+100 @160 Class UUID (hkbBehaviorGraph)
10 | 00 00 00 00 (standard 00 ?)
11 | 65 00 00 00 #65 => @1610 30-block
12 | @65+100 @165 text (hkbBehaviorGraph)
13 | 30 02 00 00 @230+4D0 28-bloc w/ 80
14 | 00 00 00 00 (standard)
15 |
16 | 7B 00 00 00 @7B+100 @17B hkbStateMachine
17 | A0 03 00 00 @3A0+4D0 28-bloc w/ 80
18 | 00 00 00 00
19 | 90 00 00 00 @190
20 |
21 | 30 04 00 00
22 | 00 00 00 00
23 | AE 00 00 00 @1AE
24 | 60 04 00 00
25 |
26 | 00 00 00 00
27 | 7B 00 00 00 @17B
28 | E0 05 00 00
29 | 00 00 00 00
30 |
31 | 90 00 00 00 @190
32 | 80 06 00 00
33 | 00 00 00 00
34 | D5 00 00 00 @1D5
35 |
36 | 30 07 00 00 @730+4D0 28-block w/ 80
37 | 00 00 00 00
38 | EF 00 00 00 @1EF
39 | D0 07 00 00 @7D0+4D0 28-block w/ 80
40 |
41 | 00 00 00 00
42 | 04 01 00 00 @204 hkbGetUpModifier
43 | 70 08 00 00 @870+1D0 28-block w/ 80
44 | 00 00 00 00
45 |
46 | ...
47 | 81 03 00 00 @481 hkbBehaviorGraphData
48 |
49 | 40 3D 00 00 @3D40+4D0 20-block w/ 80 AND DATA
50 | 00 00 00 00
51 | 9B 03 00 00 @49B hkbVariableValueSet
52 |
53 | 90 3E 00 00 @3E90+4D0 20-block w/ 80 AND DATA
54 | 00 00 00 00
55 | B4 03 00 00 @4B4 hkbBehaviorGraphStringData
56 |
57 | Offsets in file ?
58 | >0 - 0 - 4B
59 | >60 - 0 - 65
60 | >3D40 - 0 - 039B
61 | => @3D40+4D0 @4210
62 | Only 0's (not illogical given there is no AttNames, believed to be second to last values in file)
63 | => @039B+4210 @
64 | >3E90 - 0 - 03B4
65 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/descriptor/reader/ClassXMLList.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.descriptor.reader;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 | import java.net.URL;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassListReadException;
11 |
12 | /**
13 | * List of all the available ClassXML resources.
14 | */
15 | class ClassXMLList {
16 | private static final String CLASS_RESOURCES_LIST = "/properties/classxmllist.txt";
17 | public final transient Map filenameConverter = new HashMap();
18 |
19 | ClassXMLList() throws ClassListReadException {
20 | try {
21 | readEntries();
22 | } catch (IOException e) {
23 | throw new ClassListReadException(e);
24 | }
25 | }
26 |
27 | private void readEntries() throws IOException {
28 | URL paths = ClassXMLList.class.getResource(CLASS_RESOURCES_LIST);
29 | BufferedReader reader = new BufferedReader(new InputStreamReader(paths.openStream()));
30 | String fileEntry = reader.readLine();
31 | while (fileEntry != null) {
32 | String className = extractName(fileEntry);
33 | filenameConverter.put(className, "/classxml/" + fileEntry);
34 | fileEntry = reader.readLine();
35 | }
36 | }
37 |
38 | /**
39 | * Retrieve a filename from the class name
40 | *
41 | * @param classname the class name
42 | * @return the file name to retrieve data from
43 | */
44 | String getFileName(final String classname) {
45 | return filenameConverter.get(classname);
46 | }
47 |
48 | private String extractName(final String fullName) {
49 | return fullName.substring(0, fullName.indexOf('_'));
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/callbacks/HKXPointerArrayMemberCallback.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object.callbacks;
2 |
3 | import java.util.List;
4 |
5 | import com.dexesttp.hkxpack.data.members.HKXArrayMember;
6 | import com.dexesttp.hkxpack.data.members.HKXPointerMember;
7 | import com.dexesttp.hkxpack.hkx.HKXUtils;
8 | import com.dexesttp.hkxpack.hkx.types.MemberSizeResolver;
9 | import com.dexesttp.hkxpack.hkxwriter.object.array.HKXArrayPointerMemberHandler;
10 |
11 | /**
12 | * Handles callbacks for {@link HKXPointerMember}'s array components.
13 | */
14 | public class HKXPointerArrayMemberCallback implements HKXArrayMemberCallback {
15 | private final transient HKXArrayMember arrMember;
16 | private final transient List apmhList;
17 |
18 | /**
19 | * Creates a {@link HKXPointerArrayMemberCallback}
20 | *
21 | * @param arrMember the {@link HKXArrayMember} the callback is for
22 | * @param apmhList the {@link HKXArrayPointerMemberHandler} to base the
23 | * callback on.
24 | */
25 | public HKXPointerArrayMemberCallback(final HKXArrayMember arrMember,
26 | final List apmhList) {
27 | this.arrMember = arrMember;
28 | this.apmhList = apmhList;
29 | }
30 |
31 | @Override
32 | /**
33 | * {@inheritDoc}
34 | */
35 | public long process(final List memberCallbacks, final long position) {
36 | long newPos = position;
37 | for (HKXArrayPointerMemberHandler apmh : apmhList) {
38 | long objectSize = MemberSizeResolver.getSize(arrMember.getSubType());
39 | apmh.resolve(newPos);
40 | newPos += objectSize;
41 | }
42 | return HKXUtils.snapLine(newPos) - position;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/classnames/HKXClassnamesHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.classnames;
2 |
3 | import com.dexesttp.hkxpack.data.HKXFile;
4 | import com.dexesttp.hkxpack.data.HKXObject;
5 | import com.dexesttp.hkxpack.hkx.classnames.ClassnamesData;
6 | import com.dexesttp.hkxpack.resources.byteutils.ByteUtils;
7 |
8 | /**
9 | * Creates a {@link ClassnamesData} from a {@link HKXFile}.
10 | */
11 | public class HKXClassnamesHandler {
12 | private static final long HK_CLASS_ID = 0x33D42383;
13 | private static final long HK_CLASS_MEMBER_ID = 0xB0EFA719;
14 | private static final long HK_CLASS_ENUM_ID = 0x8A3609CF;
15 | private static final long HK_CLASS_ENUM_ITEM_ID = 0xCE6F8A6C;
16 |
17 | /**
18 | * Creates a {@link ClassnamesData} instance from the given {@link HKXFile}.
19 | *
20 | * @param file the {@link HKXFile} to extract data from.
21 | * @return the relevant {@link ClassnamesData}.
22 | */
23 | public ClassnamesData getClassnames(final HKXFile file) {
24 | ClassnamesData data = new ClassnamesData();
25 | data.put(5, "hkClass", ByteUtils.fromULong(HK_CLASS_ID, 4));
26 | data.put(18, "hkClassMember", ByteUtils.fromULong(HK_CLASS_MEMBER_ID, 4));
27 | data.put(37, "hkClassEnum", ByteUtils.fromULong(HK_CLASS_ENUM_ID, 4));
28 | data.put(54, "hkClassEnumItem", ByteUtils.fromULong(HK_CLASS_ENUM_ITEM_ID, 4));
29 | int i = 75;
30 | for (HKXObject object : file.getContentCollection()) {
31 | if (!data.containsClass(object.getDescriptor().getName())) {
32 | data.put(i, object.getDescriptor().getName(),
33 | ByteUtils.fromULong(object.getDescriptor().getSignature(), 4));
34 | i += object.getDescriptor().getName().length() + 0x06;
35 | }
36 | }
37 | return data;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/HKXPointerMemberReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXMember;
4 | import com.dexesttp.hkxpack.data.members.HKXPointerMember;
5 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
6 | import com.dexesttp.hkxpack.hkx.data.DataExternal;
7 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
8 | import com.dexesttp.hkxpack.hkxreader.HKXReaderConnector;
9 | import com.dexesttp.hkxpack.hkxreader.PointerNameGenerator;
10 |
11 | /**
12 | * Reads a {@link HKXPointerMember} from a HKX file.
13 | */
14 | class HKXPointerMemberReader implements HKXMemberReader {
15 | private final transient HKXReaderConnector connector;
16 | private final transient PointerNameGenerator generator;
17 | private final transient String name;
18 | private final transient HKXType vtype;
19 | private final transient long memberOffset;
20 |
21 | HKXPointerMemberReader(final HKXReaderConnector connector, final PointerNameGenerator generator, final String name,
22 | final HKXType contentType, final long offset) {
23 | this.connector = connector;
24 | this.generator = generator;
25 | this.name = name;
26 | this.vtype = contentType;
27 | this.memberOffset = offset;
28 | }
29 |
30 | @Override
31 | /**
32 | * {@inheritDoc}
33 | */
34 | public HKXMember read(final long classOffset) throws InvalidPositionException {
35 | DataExternal data = connector.data2.readNext();
36 | String target = "null";
37 | if (data.from == memberOffset + classOffset) {
38 | target = generator.get(data.to);
39 | } else {
40 | connector.data2.backtrack();
41 | }
42 | return new HKXPointerMember(name, HKXType.TYPE_POINTER, vtype, target);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/types/MemberDataResolver.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.types;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXMember;
4 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
5 | import com.dexesttp.hkxpack.hkx.types.handlers.MemberHandlerFactory;
6 |
7 | /**
8 | * Intended to retrieve {@link HKXType}-specific data.
9 | * {@link #getMember(String, HKXType, byte[])} converts a {@link byte} array to
10 | * a {@link HKXMember}, given the {@link HKXType} of the member is standard.
11 | */
12 | public final class MemberDataResolver {
13 | private MemberDataResolver() {
14 | // NO OP
15 | }
16 |
17 | /**
18 | * Read a simple / defined member from a byte array.
19 | *
20 | * @param name the name of the member to create.
21 | * @param type the {@link HKXType} of data to convert the array into.
22 | * @param byteArray the {@link byte} array to read the member from.
23 | * @return the {@link HKXMember} containing the data.
24 | * @throws IllegalArgumentException if the given {@link HKXType} isn't standard.
25 | */
26 | public static HKXMember getMember(final String name, final HKXType type, final byte[] byteArray) {
27 | return MemberHandlerFactory.getMemberHandler(type).createMember(name, type, byteArray);
28 | }
29 |
30 | /**
31 | * Write a simple / defined member to a byte array.
32 | *
33 | * @param member the {@link HKXMember} of data to create the array from.
34 | * @return the byte aray containing the data.
35 | * @throws IllegalArgumentException if the given {@link HKXMember} isn't
36 | * standard.
37 | */
38 | public static byte[] fromMember(final HKXMember member) {
39 | return MemberHandlerFactory.getMemberHandler(member.getType()).readMember(member);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/HKXUtils.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx;
2 |
3 | /**
4 | * Contain utils for the HKX classes.
5 | */
6 | public final class HKXUtils {
7 | private static final long HALF_LINE = 0x08;
8 | private static final long FULL_LINE = 0x10;
9 |
10 | private HKXUtils() {
11 | // NO OP
12 | }
13 |
14 | /**
15 | * Snap the object's position to the relevant byte.
16 | *
17 | * @param currentPos
18 | * @return
19 | */
20 | public static long snapObject(final long currentPos) {
21 | if (currentPos % FULL_LINE == 0) {
22 | return currentPos;
23 | }
24 | return (1 + currentPos / FULL_LINE) * FULL_LINE;
25 | }
26 |
27 | /**
28 | * Snap the given position to the next line.
29 | *
30 | * @param currentPos
31 | * @return
32 | */
33 | public static long snapLine(final long currentPos) {
34 | if (currentPos % FULL_LINE == 0) {
35 | return currentPos;
36 | }
37 | return (1 + currentPos / FULL_LINE) * FULL_LINE;
38 | }
39 |
40 | /**
41 | * Snap the string's size to the relevant size.
42 | *
43 | * @param currentSize the string size.
44 | * @return the snapped size.
45 | */
46 | public static long snapString(final long currentSize) {
47 | if (currentSize < HALF_LINE) {
48 | return HALF_LINE;
49 | }
50 | if (currentSize % FULL_LINE == 0) {
51 | return currentSize;
52 | }
53 | return (1 + currentSize / FULL_LINE) * FULL_LINE;
54 | }
55 |
56 | /**
57 | * Snap a size to the given snap and offset to the given offset.
58 | *
59 | * @param offset the offset to snap
60 | * @param snap the snap.
61 | * @return
62 | */
63 | public static long snapSize(final long offset, final long snap) {
64 | if (offset % snap == 0) {
65 | return offset;
66 | }
67 | return (1 + offset / snap) * snap;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/utils/StaticProperties.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.utils;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.util.Properties;
6 |
7 | /**
8 | * Contains a list of static final properties.
9 | */
10 | public final class StaticProperties {
11 | private static final String VERSION_NUMBER;
12 |
13 | static {
14 | Properties prop = new Properties();
15 | String vNum = "";
16 | try {
17 | InputStream in = StaticProperties.class
18 | .getResourceAsStream("/META-INF/maven/com.dexesttp.hkxpack/cli/pom.properties");
19 | prop.load(in);
20 | in.close();
21 | vNum = prop.getProperty("version");
22 | } catch (IOException e) {
23 | vNum = "error loading version number";
24 | }
25 | VERSION_NUMBER = vNum;
26 | }
27 |
28 | private StaticProperties() {
29 | // NO OP
30 | }
31 |
32 | /**
33 | *
34 | * Versioning convention:
35 | * 1st digit : main version identifier
36 | * * Supposed to be used in case of a huge fonctionnality change.
37 | * * A change shows a compatibility loss with previous versions.
38 | *
39 | * 2nd digit : version iteration
40 | * * Supposed to be used when a new functionnality set is added.
41 | *
42 | * 3rd digit : version state
43 | * * Even = stable, odd = unstable
44 | * * Changed each time a functionnality is added for release.
45 | *
46 | * Hyphen : state identifier
47 | * * Either alpha|beta|theta|gamma or any state identifier (unstable, snapshot, etc.. works)
48 | * * Linguistic representation of the 1st, 2nd and 3rd digit.
49 | * * Doesn't exist with stable releases (no -HOTFIX or similar, this goes into the merge data or changelog !)
50 | *
51 | */
52 | public static String getVersionNumber() {
53 | return VERSION_NUMBER;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/cli/src/test/java/com/dexesttp/hkxpack/cli/utils/ArgsParserExceptionTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.utils;
2 |
3 | import org.junit.Before;
4 | import org.junit.Test;
5 |
6 | /**
7 | * Test the behavior of thrown exceptions from {@link ArgsParser}.
8 | */
9 | public class ArgsParserExceptionTest {
10 | private transient ArgsParser argsParser;
11 |
12 | @Before
13 | /**
14 | * {@inheritDoc}
15 | */
16 | public void setUp() {
17 | argsParser = new ArgsParser();
18 | argsParser.addOption("-a");
19 | argsParser.addOption("-b", 0);
20 | argsParser.addOption("-c", 1);
21 | }
22 |
23 | @Test(expected = WrongSizeException.class)
24 | /**
25 | * {@inheritDoc}
26 | */
27 | public void itShouldThrowAnExceptionIfThereWasNotEnoughArgumentForASizedOptionWithoutAnythingAfter()
28 | throws WrongSizeException {
29 | argsParser.parse(ArgsParserTest.TEST, "-c");
30 | }
31 |
32 | @Test(expected = WrongSizeException.class)
33 | /**
34 | * {@inheritDoc}
35 | */
36 | public void itShouldThrowAnExceptionIfThereWasNotEnoughArgumentForASizedOptionWithThingsAfter()
37 | throws WrongSizeException {
38 | argsParser.parse(ArgsParserTest.TEST, "-c", "-b", ArgsParserTest.TEST2);
39 | }
40 |
41 | @Test(expected = WrongSizeException.class)
42 | /**
43 | * {@inheritDoc}
44 | */
45 | public void itShouldThrowAnExceptionIfThereWasAnOtherAppearanceOfASizedOption() throws WrongSizeException {
46 | argsParser.parse(ArgsParserTest.TEST, "-c", ArgsParserTest.TEST2, "-c", ArgsParserTest.TEST3);
47 | }
48 |
49 | @Test(expected = WrongSizeException.class)
50 | /**
51 | * {@inheritDoc}
52 | */
53 | public void itShouldHandleAComplexIncorrectCommandLine() throws WrongSizeException {
54 | argsParser.parse(ArgsParserTest.TEST, "-a", ArgsParserTest.TEST2, "-b", ArgsParserTest.TEST3,
55 | ArgsParserTest.TEST4, "-c");
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/classnames/ClassnamesData.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.classnames;
2 |
3 | import java.util.LinkedHashMap;
4 |
5 | /**
6 | * Stores all the ClassNames from a file or intended to be stored in a file.
7 | */
8 | public class ClassnamesData extends LinkedHashMap {
9 | private static final long serialVersionUID = 5525421716171216039L;
10 |
11 | /**
12 | * Add a classname to this ClassnamesData
13 | *
14 | * @param position the position (in {@link bytes}) the classname whould be found
15 | * at.
16 | * @param name the name of the classname to add.
17 | * @param uuid the UUID of the classname to add.
18 | * @return the added {@link Classname} object.
19 | */
20 | public Classname put(final long position, final String name, final byte[] uuid) {
21 | return super.put(position, new Classname(name, uuid));
22 | }
23 |
24 | /**
25 | * Returns {@link true} if the {@link ClassnamesData} contains the given
26 | * classname.
27 | *
28 | * @param name the classname to check the existence of.
29 | * @return the existence of the classname.
30 | */
31 | public boolean containsClass(final String name) {
32 | for (Classname classname : this.values()) {
33 | if (classname.name.equals(name)) {
34 | return true;
35 | }
36 | }
37 | return false;
38 | }
39 |
40 | /**
41 | * Retrieves the position of the given classname, or {@literal 0x05} if no
42 | * position was found.
43 | *
44 | * @param name the name to check against.
45 | * @return the classname's position in the {@literal __classnames__} section
46 | */
47 | public long getPosition(final String name) {
48 | for (java.util.Map.Entry entries : this.entrySet()) {
49 | if (entries.getValue().name.equals(name)) {
50 | return entries.getKey();
51 | }
52 | }
53 | return 0x05;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/cli/src/test/java/com/dexesttp/hkxpack/cli/utils/ArgsParserExistTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.utils;
2 |
3 | import static org.junit.Assert.assertFalse;
4 | import static org.junit.Assert.assertNull;
5 | import static org.junit.Assert.assertTrue;
6 |
7 | import org.junit.Before;
8 | import org.junit.Test;
9 |
10 | import com.dexesttp.hkxpack.cli.utils.ArgsParser.Options;
11 |
12 | /**
13 | * Tests the behavior of {@link ArgsParser.Options#exists(String)}
14 | */
15 | public class ArgsParserExistTest {
16 | private transient ArgsParser argsParser;
17 |
18 | @Before
19 | /**
20 | * {@inheritDoc}
21 | */
22 | public void setUp() {
23 | argsParser = new ArgsParser();
24 | argsParser.addOption("-a");
25 | argsParser.addOption("-b", 0);
26 | argsParser.addOption("-c", 1);
27 | }
28 |
29 | @Test
30 | /**
31 | * {@inheritDoc}
32 | */
33 | public void itShouldNotCatchOneExtraEmptyOptionIfThereIsNoExtraOption() throws WrongSizeException {
34 | Options result = argsParser.parse(ArgsParserTest.TEST, "-a");
35 | assertNull(result.get("-b"));
36 | }
37 |
38 | @Test
39 | /**
40 | * {@inheritDoc}
41 | */
42 | public void itShouldShowTheOptionAsExistingIfTheOptionExists() throws WrongSizeException {
43 | Options result = argsParser.parse(ArgsParserTest.TEST, "-a");
44 | assertTrue(result.exists("-a"));
45 | }
46 |
47 | @Test
48 | /**
49 | * {@inheritDoc}
50 | */
51 | public void itShouldShowTheOptionAsNotExistingIfTheOptionDoesNotExists() throws WrongSizeException {
52 | Options result = argsParser.parse(ArgsParserTest.TEST, "-a");
53 | assertFalse(result.exists("-b"));
54 | }
55 |
56 | @Test
57 | /**
58 | * {@inheritDoc}
59 | */
60 | public void itShouldShowTheOptionAsNotExistingIfTheOptionIsNotDefined() throws WrongSizeException {
61 | Options result = argsParser.parse(ArgsParserTest.TEST, "-a");
62 | assertFalse(result.exists("-d"));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/cli/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.dexesttp
8 | hkxpack
9 | 0.1.6-beta
10 |
11 |
12 | com.dexesttp.hkxpack
13 | cli
14 |
15 | HKXPack Command Line Interface
16 | Command Line interface for HKX Pack
17 |
18 |
19 |
20 | com.dexesttp.hkxpack
21 | core
22 | ${project.version}
23 |
24 |
25 | junit
26 | junit
27 | 4.12
28 | test
29 |
30 |
31 |
32 |
33 |
34 |
35 | org.apache.maven.plugins
36 | maven-shade-plugin
37 | 2.4.3
38 |
39 |
40 |
42 | com.dexesttp.hkxpack.cli.ConsoleView
43 |
44 |
45 | false
46 |
47 |
48 |
49 | package
50 |
51 | shade
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/header/SectionData.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.header;
2 |
3 | /**
4 | * Contains information about a given section of the file.
5 | */
6 | public class SectionData {
7 | /**
8 | * Name of the section Supported sections are __classnames__, __types__ and
9 | * __data__
10 | */
11 | public String name;
12 |
13 | /**
14 | * Offset of the section in the file.
15 | *
16 | * Note that this is a general offset, from the beginning of the file.
17 | */
18 | public long offset;
19 |
20 | /**
21 | * Internal offset of the file's first extra data component.
22 | *
23 | * Note that this is an internal offset, based on the general {@link offset} of
24 | * the section.
25 | */
26 | public long data1;
27 |
28 | /**
29 | * Internal offset of the file's second extra data component.
30 | *
31 | * Note that this is an internal offset, based on the general {@link offset} of
32 | * the section.
33 | */
34 | public long data2;
35 |
36 | /**
37 | * Internal offset of the file's third extra data component.
38 | *
39 | * Note that this is an internal offset, based on the general {@link offset} of
40 | * the section.
41 | */
42 | public long data3;
43 |
44 | /**
45 | * Internal offset of the file's fourth extra data component.
46 | *
47 | * Note that this is an internal offset, based on the general {@link offset} of
48 | * the section.
49 | */
50 | public long data4;
51 |
52 | /**
53 | * Internal offset of the file's fifth extra data component.
54 | *
55 | * Note that this is an internal offset, based on the general {@link offset} of
56 | * the section.
57 | */
58 | public long data5;
59 |
60 | /**
61 | * Internal offset of the file's section end.
62 | *
63 | * Note that this is an internal offset, based on the general {@link offset} of
64 | * the section.
65 | */
66 | public long end;
67 | }
68 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/HKXStringMemberReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import com.dexesttp.hkxpack.data.members.HKXMember;
6 | import com.dexesttp.hkxpack.data.members.HKXStringMember;
7 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
8 | import com.dexesttp.hkxpack.hkx.data.DataInternal;
9 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
10 | import com.dexesttp.hkxpack.hkxreader.HKXReaderConnector;
11 | import com.dexesttp.hkxpack.resources.byteutils.ByteUtils;
12 |
13 | /**
14 | * Reads a {@link HKXStringMember} from a HKX file.
15 | */
16 | class HKXStringMemberReader implements HKXMemberReader {
17 | private final transient HKXReaderConnector connector;
18 | private final transient String name;
19 | private final transient long memberOffset;
20 | private final transient HKXType vtype;
21 |
22 | HKXStringMemberReader(final HKXReaderConnector connector, final String name, final HKXType vtype,
23 | final long offset) {
24 | this.connector = connector;
25 | this.name = name;
26 | this.memberOffset = offset;
27 | this.vtype = vtype;
28 | }
29 |
30 | @Override
31 | /**
32 | * {@inheritDoc}
33 | */
34 | public HKXMember read(final long classOffset) throws InvalidPositionException {
35 | String contents = "";
36 | try {
37 | DataInternal data = connector.data1.readNext();
38 | if (data.from == memberOffset + classOffset) {
39 | ByteBuffer file = connector.data.setup(data.to);
40 | contents = ByteUtils.readString(file);
41 | } else {
42 | connector.data1.backtrack();
43 | }
44 | } catch (InvalidPositionException e) {
45 | // NO OP. Met when the last item of the HKX file is a String and is empty.
46 | contents = "";
47 | }
48 | HKXStringMember result = new HKXStringMember(name, vtype);
49 | result.set(contents);
50 | return result;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/tagwriter/TagXMLWriterTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagwriter;
2 |
3 | import static org.junit.Assert.assertArrayEquals;
4 |
5 | import java.io.File;
6 |
7 | import org.junit.BeforeClass;
8 | import org.junit.Test;
9 |
10 | import com.dexesttp.hkxpack.data.HKXFile;
11 | import com.dexesttp.hkxpack.data.HKXObject;
12 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
13 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
14 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
15 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassListReadException;
16 | import com.dexesttp.hkxpack.utils.FileUtils;
17 | import com.google.common.io.Files;
18 |
19 | /**
20 | * Tests for a TagXMLWriter
21 | */
22 | public class TagXMLWriterTest {
23 | public static final String TEST_BASE_OUTPUT_FILE = "test-base.xml";
24 | public static final String TEST_BASE_TARGET_RESOURCE = "/test-base.xml";
25 | private static HKXFile file;
26 |
27 | @BeforeClass
28 | /**
29 | * Set up the test environnement
30 | */
31 | public static void setupClass() throws ClassListReadException, ClassFileReadException {
32 | HKXEnumResolver enumResolver = new HKXEnumResolver();
33 | HKXDescriptorFactory descriptorFactory = new HKXDescriptorFactory(enumResolver);
34 | file = new HKXFile("hk-2014.1.0-r1", 11);
35 | file.getContentCollection().add(new HKXObject("#test", descriptorFactory.get("hkBaseObject")));
36 | }
37 |
38 | @Test
39 | /**
40 | * Tests if the TagXMLWriter output file is equals to the target file.
41 | */
42 | public void testWriteDefaultFileToPhysicalFile() throws Exception {
43 | File outputFile = File.createTempFile(TEST_BASE_OUTPUT_FILE, "");
44 | TagXMLWriter writer = new TagXMLWriter(outputFile);
45 | writer.write(file);
46 | assertArrayEquals(Files.toByteArray(outputFile), FileUtils.resourceToByteArray(TEST_BASE_TARGET_RESOURCE));
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagreader/serialized/TagXMLEmbeddedObjectSerializedHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader.serialized;
2 |
3 | import com.dexesttp.hkxpack.data.HKXObject;
4 | import com.dexesttp.hkxpack.data.members.HKXMember;
5 | import com.dexesttp.hkxpack.descriptor.HKXDescriptor;
6 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
7 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
8 | import com.dexesttp.hkxpack.descriptor.members.HKXMemberTemplate;
9 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
10 |
11 | /**
12 | * Handles embedded {@link HKXObject} members in TagXML files.
13 | */
14 | class TagXMLEmbeddedObjectSerializedHandler implements TagXMLSerializedHandler {
15 | private final transient HKXDescriptorFactory descriptorFactory;
16 | private final transient TagXMLSerializedHandlerFactory serializedHandlerFactory;
17 |
18 | TagXMLEmbeddedObjectSerializedHandler(final TagXMLSerializedHandlerFactory tagXMLSerializedHandlerFactory,
19 | final HKXDescriptorFactory descriptorFactory) {
20 | this.serializedHandlerFactory = tagXMLSerializedHandlerFactory;
21 | this.descriptorFactory = descriptorFactory;
22 |
23 | }
24 |
25 | @Override
26 | /**
27 | * {@inheritDoc}
28 | */
29 | public HKXMember handleMember(final HKXMemberTemplate objectTemplate)
30 | throws ClassFileReadException, InvalidTagXMLException {
31 | HKXDescriptor classDescriptor = descriptorFactory.get(objectTemplate.target);
32 | // Create object
33 | HKXObject result = new HKXObject("", classDescriptor);
34 |
35 | // Fill object
36 | for (HKXMemberTemplate memberTemplate : classDescriptor.getMemberTemplates()) {
37 | TagXMLSerializedHandler memberHandler = serializedHandlerFactory.getSerializedHandler(memberTemplate.vtype);
38 | result.getMembersList().add(memberHandler.handleMember(memberTemplate));
39 | }
40 |
41 | return result;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/callbacks/HKXRelArrayMemberCallback.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object.callbacks;
2 |
3 | import java.nio.Buffer;
4 | import java.nio.ByteBuffer;
5 | import java.util.List;
6 |
7 | import com.dexesttp.hkxpack.resources.byteutils.ByteUtils;
8 |
9 | /**
10 | * Handles the {@link HKXMemberCallback} for a Rel (relative)
11 | * {@link HKXArrayMember}.
12 | */
13 | public class HKXRelArrayMemberCallback implements HKXMemberCallback {
14 | private final transient HKXArrayMemberCallback callbackProcessor;
15 | private final transient ByteBuffer outFile;
16 | private final transient long classPos;
17 | private final transient long argPos;
18 |
19 | /**
20 | * Create a {@link HKXRelArrayMemberCallback}.
21 | *
22 | * @param callbackProcessor the {@link HKXArrayMemberCallback} to use for each
23 | * array member.
24 | * @param outFile the {@link ByteBuffer} to write this array's
25 | * position to.
26 | * @param classPos the position of the array's class.
27 | * @param argPos the position of the RelArray's argument from the
28 | * beginning of the class.
29 | */
30 | public HKXRelArrayMemberCallback(final HKXArrayMemberCallback callbackProcessor, final ByteBuffer outFile,
31 | final long classPos, final long argPos) {
32 | this.callbackProcessor = callbackProcessor;
33 | this.outFile = outFile;
34 | this.classPos = classPos;
35 | this.argPos = argPos;
36 | }
37 |
38 | @Override
39 | /**
40 | * {@inheritDoc}
41 | */
42 | public long process(final List memberCallbacks, final long position) {
43 | byte[] offset = ByteUtils.fromULong(position - classPos, 2);
44 | ((Buffer) outFile).position((int) (classPos + argPos + 2));
45 | outFile.put(offset);
46 | return callbackProcessor.process(memberCallbacks, position);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/descriptor/HKXDescriptorFactory.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.descriptor;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
7 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassListReadException;
8 | import com.dexesttp.hkxpack.descriptor.reader.ClassXMLReader;
9 | import com.dexesttp.hkxpack.descriptor.reader.ClassXMLReaderFactory;
10 |
11 | /**
12 | * A HKXDescriptorFactory uses lazy instanciation to retrieve a non-unique
13 | * HKXDescriptor. Data may be reread when a different factory is used.
14 | */
15 | public class HKXDescriptorFactory {
16 | private final transient ClassXMLReader reader;
17 | private final transient Map contents = new HashMap<>();
18 |
19 | /**
20 | * Retrieves a new HKXDescriptorFactory.
21 | *
22 | * @param enumResolver the {@link HKXEnumResolver} to put the read enums into.
23 | * @throws ClassListReadException if there was an error while reading the Class
24 | * List.
25 | */
26 | public HKXDescriptorFactory(final HKXEnumResolver enumResolver) throws ClassListReadException {
27 | ClassXMLReaderFactory factory = new ClassXMLReaderFactory(enumResolver);
28 | reader = factory.create(this);
29 | }
30 |
31 | /**
32 | * Retrieves a HKXDescriptor from the class name.
33 | *
34 | * @param name the HKXDescriptor's name
35 | * @return the HKXDescriptor
36 | * @throws ClassFileReadException if there was an error while reading the Class
37 | * File.
38 | */
39 | public HKXDescriptor get(final String name) throws ClassFileReadException {
40 | synchronized (this) {
41 | if (contents.containsKey(name)) {
42 | return contents.get(name);
43 | }
44 | HKXDescriptor descriptor = reader.get(name);
45 | contents.put(name, descriptor);
46 | return descriptor;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/HKXObjectMemberHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object;
2 |
3 | import java.util.List;
4 |
5 | import com.dexesttp.hkxpack.data.HKXObject;
6 | import com.dexesttp.hkxpack.data.members.HKXMember;
7 | import com.dexesttp.hkxpack.hkxwriter.object.callbacks.HKXMemberCallback;
8 |
9 | /**
10 | * Handles a {@link HKXObject} as a member of a class to write to a HKX File.
11 | */
12 | public class HKXObjectMemberHandler implements HKXMemberHandler {
13 | private final transient HKXMemberHandlerFactory memberHandlerFactory;
14 | private final transient List memberCallbacks;
15 | private final transient long offset;
16 |
17 | /**
18 | * Creates a {@link HKXObjectMemberHandler}.
19 | *
20 | * @param offset the offset of the {@link HKXObject} member in the
21 | * class.
22 | * @param memberHandlerFactory the {@link HKXMemberHandlerFactory} to use while
23 | * resolving the object.
24 | * @param memberCallbacks the list of callbacks to add this object's
25 | * members to.
26 | */
27 | public HKXObjectMemberHandler(final long offset, final HKXMemberHandlerFactory memberHandlerFactory,
28 | final List memberCallbacks) {
29 | this.offset = offset;
30 | this.memberHandlerFactory = memberHandlerFactory;
31 | this.memberCallbacks = memberCallbacks;
32 | }
33 |
34 | @Override
35 | /**
36 | * {@inheritDoc}
37 | */
38 | public HKXMemberCallback write(final HKXMember member, final long currentPos) {
39 | final HKXObject object = (HKXObject) member;
40 | HKXInternalObjectHandler internalObjectHandler = new HKXInternalObjectHandler(memberHandlerFactory,
41 | memberCallbacks);
42 | internalObjectHandler.write(object, currentPos + offset);
43 | return (memberCallbacks, position) -> {
44 | return 0;
45 | };
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/loggers/DirectoryWalkerLoggerFactory.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.loggers;
2 |
3 | import java.util.logging.Level;
4 | import java.util.logging.Logger;
5 |
6 | import com.dexesttp.hkxpack.cli.ConsoleView;
7 | import com.dexesttp.hkxpack.resources.LoggerUtil;
8 |
9 | /**
10 | * Creates a {@link DirectoryWalkerLogger} based on the relevant
11 | * {@link CLIProperties}.
12 | */
13 | public class DirectoryWalkerLoggerFactory {
14 | private static final Logger LOGGER = Logger.getLogger(ConsoleView.class.getName());
15 |
16 | /**
17 | * Retrieves a suitable {@link DirectoryWalkerLogger}.
18 | *
19 | * @param total the total number of files to walk through.
20 | * @return a suitable {@link DirectoryWalkerLogger}.
21 | */
22 | public DirectoryWalkerLogger newLogger(final int total) {
23 | if (LOGGER.isLoggable(Level.FINE)) {
24 | LOGGER.info("Detected " + total + " files to handle.");
25 | return (done) -> {
26 | LOGGER.fine("Handled " + done + " files (" + ((float) done / (float) total) + "%)");
27 | handleErrors();
28 | };
29 | } else if (LOGGER.isLoggable(Level.INFO)) {
30 | LOGGER.info("Detected " + total + " files to handle.");
31 | return (done) -> {
32 | handleErrors();
33 | };
34 | } else if (LOGGER.isLoggable(Level.SEVERE)) {
35 | return (done) -> {
36 | handleErrors();
37 | };
38 | }
39 | return (done) -> {
40 | };
41 | }
42 |
43 | /**
44 | * Handles the {@link LoggerUtil} logging.
45 | */
46 | private void handleErrors() {
47 | while (!LoggerUtil.getList().isEmpty()) {
48 | Throwable e = LoggerUtil.getList().remove(0);
49 | LOGGER.throwing(this.getClass().getName(), "handleErrors", e);
50 | }
51 | }
52 |
53 | /**
54 | * Logs a Directory walking progress.
55 | */
56 | public interface DirectoryWalkerLogger {
57 | /**
58 | * Logs the progress of the walk.
59 | *
60 | * @param done the number of files already walked through.
61 | */
62 | void log(long done);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagwriter/TagXMLDataCreator.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagwriter;
2 |
3 | import org.w3c.dom.Document;
4 | import org.w3c.dom.Node;
5 |
6 | import com.dexesttp.hkxpack.data.HKXData;
7 | import com.dexesttp.hkxpack.data.HKXObject;
8 | import com.dexesttp.hkxpack.data.members.HKXMember;
9 | import com.dexesttp.hkxpack.l10n.SBundle;
10 |
11 | /**
12 | * Creates {@link Node} from {@link HKXData}.
13 | */
14 | class TagXMLDataCreator {
15 | private final transient Document document;
16 | private final transient TagXMLMemberCreator memberCreator;
17 | private final transient TagXMLObjectCreator objectCreator;
18 |
19 | /**
20 | * Initialize the {@link TagXMLDataCreator}, linking it definitely to a
21 | * {@link Document}.
22 | *
23 | * @param document
24 | */
25 | TagXMLDataCreator(final Document document) {
26 | this.document = document;
27 | this.memberCreator = new TagXMLMemberCreator(this);
28 | this.objectCreator = new TagXMLObjectCreator(this);
29 | }
30 |
31 | /**
32 | * Creates a {@link Node} from a {@link HKXData} component.
33 | *
34 | * @param content the {@link HKXData} to convert.
35 | * @return a {@link Node} containing the data.
36 | */
37 | Node create(final HKXData content) {
38 | if (content instanceof HKXObject) {
39 | return objectCreator.create((HKXObject) content);
40 | }
41 | if (content instanceof HKXMember) {
42 | return memberCreator.create((HKXMember) content);
43 | }
44 | throw new IllegalArgumentException(SBundle.getString("error.tag.create.type.unknown") + "[#060]");
45 | }
46 |
47 | /**
48 | * Retrieves the specialized {@link TagXMLMemberCreator}.
49 | *
50 | * @return the embedded {@link TagXMLMemberCreator}.
51 | */
52 | TagXMLMemberCreator getMemberCreator() {
53 | return memberCreator;
54 | }
55 |
56 | /**
57 | * Retrieves the linked {@link Document}
58 | *
59 | * @return the linked {@link Document}
60 | */
61 | Document getDocument() {
62 | return document;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagreader/members/TagXMLEmbeddedObjectHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader.members;
2 |
3 | import org.w3c.dom.Node;
4 | import org.w3c.dom.NodeList;
5 |
6 | import com.dexesttp.hkxpack.data.HKXObject;
7 | import com.dexesttp.hkxpack.data.members.HKXMember;
8 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
9 | import com.dexesttp.hkxpack.descriptor.members.HKXMemberTemplate;
10 | import com.dexesttp.hkxpack.l10n.SBundle;
11 | import com.dexesttp.hkxpack.tagreader.TagXMLNodeHandler;
12 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
13 |
14 | /**
15 | * Handles reading an embedded {@link HKXObject} form a TagXML file.
16 | */
17 | public class TagXMLEmbeddedObjectHandler implements TagXMLContentsHandler {
18 | private final transient TagXMLNodeHandler nodeHandler;
19 |
20 | /**
21 | * Create a {@link TagXMLEmbeddedObjectHandler}.
22 | *
23 | * @param nodeHandler the {@link TagXMLNodeHandler} to use while reading this
24 | * object's members.
25 | */
26 | public TagXMLEmbeddedObjectHandler(final TagXMLNodeHandler nodeHandler) {
27 | this.nodeHandler = nodeHandler;
28 | }
29 |
30 | @Override
31 | /**
32 | * {@inheritDoc}
33 | */
34 | public HKXMember handleNode(final Node member, final HKXMemberTemplate memberTemplate)
35 | throws ClassFileReadException, InvalidTagXMLException {
36 | String target = memberTemplate.target;
37 | NodeList children = member.getChildNodes();
38 | for (int i = 0; i < children.getLength(); i++) {
39 | Node objectNode = children.item(i);
40 | if (objectNode.getNodeName().equals("hkobject")) {
41 | return handleNode(objectNode, target);
42 | }
43 | }
44 | throw new InvalidTagXMLException(SBundle.getString("error.tag.read.member") + memberTemplate.name);
45 | }
46 |
47 | HKXMember handleNode(final Node member, final String target) throws ClassFileReadException, InvalidTagXMLException {
48 | return nodeHandler.handleSubObject(member, target);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/commands/Command_unpack.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.commands;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 |
6 | import javax.xml.parsers.ParserConfigurationException;
7 | import javax.xml.transform.TransformerException;
8 |
9 | import com.dexesttp.hkxpack.cli.utils.FileNameCreationException;
10 | import com.dexesttp.hkxpack.data.HKXFile;
11 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
12 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
13 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
14 | import com.dexesttp.hkxpack.hkxreader.HKXReader;
15 | import com.dexesttp.hkxpack.tagwriter.TagXMLWriter;
16 |
17 | /**
18 | * Unpacks a HKX file into a XML file.
19 | *
20 | * @see Command_IO
21 | */
22 | public class Command_unpack extends Command_IO {
23 | @Override
24 | protected void executionCore(final String inputFileName, final String outputFileName,
25 | final HKXEnumResolver enumResolver, final HKXDescriptorFactory descriptorFactory)
26 | throws IOException, InvalidPositionException, TransformerException, ParserConfigurationException {
27 | // Read HKX file
28 | File inFile = new File(inputFileName);
29 | HKXReader reader = new HKXReader(inFile, descriptorFactory, enumResolver);
30 | HKXFile hkxFile = reader.read();
31 |
32 | // Write XML file
33 | File outFile = new File(outputFileName);
34 | TagXMLWriter writer = new TagXMLWriter(outFile);
35 | writer.write(hkxFile);
36 | }
37 |
38 | @Override
39 | protected String extractFileName(final String ogName) throws FileNameCreationException {
40 | String newName = "";
41 | try {
42 | newName = ogName.substring(0, ogName.lastIndexOf('.')) + ".xml";
43 | } catch (StringIndexOutOfBoundsException e) {
44 | throw new FileNameCreationException("The file : " + ogName + " has a name that can't be converted.", e);
45 | }
46 | return newName;
47 | }
48 |
49 | @Override
50 | protected String[] getFileExtensions() {
51 | return new String[] { ".hkx" };
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/HKXEnumMemberHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object;
2 |
3 | import java.nio.Buffer;
4 | import java.nio.ByteBuffer;
5 |
6 | import com.dexesttp.hkxpack.data.members.HKXEnumMember;
7 | import com.dexesttp.hkxpack.data.members.HKXMember;
8 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
9 | import com.dexesttp.hkxpack.hkx.types.MemberSizeResolver;
10 | import com.dexesttp.hkxpack.hkxwriter.object.callbacks.HKXMemberCallback;
11 | import com.dexesttp.hkxpack.resources.byteutils.ByteUtils;
12 |
13 | /**
14 | * Handles {@link HKXEnumMember} for writing them to a HKX File
15 | */
16 | public class HKXEnumMemberHandler implements HKXMemberHandler {
17 | private final transient ByteBuffer outFile;
18 | private final transient long offset;
19 | private final transient HKXEnumResolver enumResolver;
20 |
21 | /**
22 | * Creates a {@link HKXEnumMemberHandler}.
23 | *
24 | * @param outFile the output {@link ByteBuffer} to write to.
25 | * @param offset the offset of the memebr in the class.
26 | * @param enumResolver the {@link HKXEnumResolver} to use to resolve the
27 | * enumeration into a value.
28 | */
29 | public HKXEnumMemberHandler(final ByteBuffer outFile, final long offset, final HKXEnumResolver enumResolver) {
30 | this.outFile = outFile;
31 | this.offset = offset;
32 | this.enumResolver = enumResolver;
33 | }
34 |
35 | @Override
36 | /**
37 | * {@inheritDoc}
38 | */
39 | public HKXMemberCallback write(final HKXMember member, final long currentPos) {
40 | HKXEnumMember enumMember = (HKXEnumMember) member;
41 | if (!enumMember.getEnumerationName().isEmpty()) {
42 | ((Buffer) outFile).position((int) (currentPos + offset));
43 | long enumVal = enumResolver.resolve(enumMember.getEnumerationName(), enumMember.get());
44 | byte[] res = ByteUtils.fromULong(enumVal, (int) MemberSizeResolver.getSize(enumMember.getSubtype()));
45 | outFile.put(res);
46 | }
47 | return (memberCallbacks, position) -> {
48 | return 0;
49 | };
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/doc/hkx findings/00 - Findings on HKX files.txt:
--------------------------------------------------------------------------------
1 | === HKX File format ===
2 |
3 | The HKX file format (Havok Packed File) is defined by its header.
4 |
5 | The header contains :
6 | - 64 bytes of pure header data
7 | - three sections
8 | classname
9 | types
10 | data
11 |
12 | === HKX pure header ==
13 | Constant value 57E0 E057
14 | 10C0 C010
15 | 0000 0000
16 | Version number <4 bytes>
17 | A 4-byte value
18 | version 8 04 01 00 00
19 | version 11 08 01 00 00
20 | Constant values 0300 0000
21 | 0200 0000
22 | 0000 0000
23 | 0000 0000
24 | 4B00 0000
25 | the version name <16 bytes>
26 | 4 empty bytes 0000 0000
27 | <4 bytes>
28 | An offset (v. 11) or FF's (v. 8) over 4 bytes
29 |
30 | === HKX Header Sections ===
31 | You have to move bytes if v. 11
32 |
33 | The section name <16 bytes>
34 | Constant value 00 00 00 FF
35 | general offset <4 bytes>
36 | part 1 offset <4 bytes>
37 | part 2 offset <4 bytes>
38 | part 3 offset <4 bytes>
39 | part 4 offset <4 bytes>
40 | part 5 offset <4 bytes>
41 | part 6 offset <4 bytes>
42 |
43 | You have to skip 16 bytes if v. 11 (FF bytes)
44 |
45 | === HKX Content : how to read it ===
46 |
47 | Build a VLookup of class names using the following format :
48 | ~ FSeek(data.offset + data.part3offset)
49 | ~ UUID <4 bytes>
50 | ~ empty 0000 0000
51 | ~ class address <4 bytes>
52 | ~ goto l.2 until pos + 12 >= (data.offset + data.part4offset)
53 |
54 | You might want to resolve the class address into name and ID by :
55 | ~ FSeek(class address);
56 | ~ readString();
57 | ~ FSeek(class address - 5);
58 | ~ readClassID (4 bytes)
59 |
60 | Read the following values :
61 | data2 value :
62 | ~ mystery <4 bytes>
63 | ~ const 0200 0000
64 | ~ UUID <4 bytes>
65 | ~ readData(UUID);
66 | ~ goto l.2 until pos + 12 > (data.offset + data.part4offset)
67 |
68 | with readData as such :
69 | ~ For each data needed for the UUID class
70 | ~ read data1
71 | ~ Store data1 as data
72 | ~ Solve data1 from data type needed in class
73 |
74 | and Data1 with the format
75 | ~ source <4 bytes>
76 | ~ value
77 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/data/HKXObject.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.data;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.dexesttp.hkxpack.data.members.HKXMember;
7 | import com.dexesttp.hkxpack.descriptor.HKXDescriptor;
8 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
9 |
10 | /**
11 | * Represents a HKX object instantiating a class, stored in memory.
12 | */
13 | public class HKXObject implements HKXMember {
14 | private final String name;
15 | private final HKXDescriptor descriptor;
16 | private final transient List members;
17 |
18 | /**
19 | * Creates a {@link HKXObject}.
20 | *
21 | * @param name the name of the object to create
22 | * @param template the template to create the object from.
23 | */
24 | public HKXObject(final String name, final HKXDescriptor template) {
25 | this(name, template, new ArrayList());
26 | }
27 |
28 | /**
29 | * Creates a {@link HKXObject}
30 | *
31 | * @param name the name of the object to create
32 | * @param descriptor the descriptor to create the object from.
33 | * @param members the list of members to add to the object.
34 | */
35 | public HKXObject(final String name, final HKXDescriptor descriptor, final List members) {
36 | this.name = name;
37 | this.descriptor = descriptor;
38 | this.members = members;
39 | }
40 |
41 | /**
42 | * Get this object's name.
43 | */
44 | public String getName() {
45 | return name;
46 | }
47 |
48 | /**
49 | * Get this object's descriptor.
50 | *
51 | * @return the {@link HKXDescriptor} that represents this object.
52 | */
53 | public HKXDescriptor getDescriptor() {
54 | return descriptor;
55 | }
56 |
57 | /**
58 | * Get this {@link HKXObject}'s member list.
59 | *
60 | * @return an ordered list of all the members of this object.
61 | */
62 | public List getMembersList() {
63 | return members;
64 | }
65 |
66 | @Override
67 | /**
68 | * {@inheritDoc}
69 | */
70 | public HKXType getType() {
71 | return HKXType.TYPE_STRUCT;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/HKXRelArrayMemberReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import com.dexesttp.hkxpack.data.members.HKXArrayMember;
6 | import com.dexesttp.hkxpack.data.members.HKXMember;
7 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
8 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
9 | import com.dexesttp.hkxpack.hkxreader.HKXReaderConnector;
10 | import com.dexesttp.hkxpack.hkxreader.member.arrays.HKXArrayContentsReader;
11 | import com.dexesttp.hkxpack.resources.byteutils.ByteUtils;
12 |
13 | /**
14 | * Reads a Relative-positionned Array as a {@link HKXArrayMember} from the HKX
15 | * file.
16 | *
17 | * @see HKXArrayContentsReader
18 | */
19 | public class HKXRelArrayMemberReader implements HKXMemberReader {
20 | private final transient HKXReaderConnector connector;
21 | private final transient String name;
22 | private final transient HKXType subtype;
23 | private final transient long offset;
24 | private final transient HKXArrayContentsReader internals;
25 |
26 | HKXRelArrayMemberReader(final HKXReaderConnector connector, final String name, final HKXType subtype,
27 | final HKXArrayContentsReader arrayContentsReader, final long offset) {
28 | this.connector = connector;
29 | this.name = name;
30 | this.subtype = subtype;
31 | this.internals = arrayContentsReader;
32 | this.offset = offset;
33 | }
34 |
35 | @Override
36 | /**
37 | * {@inheritDoc}
38 | */
39 | public HKXMember read(final long classOffset) throws InvalidPositionException {
40 | ByteBuffer file = connector.data.setup(classOffset + offset);
41 | byte[] bSize = new byte[2];
42 | byte[] bOff = new byte[2];
43 | file.get(bSize);
44 | file.get(bOff);
45 | int size = ByteUtils.getUInt(bSize) - 1;
46 | int offset = ByteUtils.getUInt(bOff);
47 | HKXArrayMember res = new HKXArrayMember(name, HKXType.TYPE_RELARRAY, subtype);
48 | for (int i = 0; i < size; i++) {
49 | res.add(internals.getContents(classOffset + offset, i));
50 | }
51 | return res;
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagreader/serialized/TagXMLDirectSerializedHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader.serialized;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXDirectMember;
4 | import com.dexesttp.hkxpack.data.members.HKXMember;
5 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
6 | import com.dexesttp.hkxpack.descriptor.members.HKXMemberTemplate;
7 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
8 |
9 | /**
10 | * Handles direct serialized members generation.
11 | */
12 | class TagXMLDirectSerializedHandler implements TagXMLSerializedHandler {
13 |
14 | @Override
15 | /**
16 | * {@inheritDoc}
17 | */
18 | public HKXMember handleMember(final HKXMemberTemplate memberTemplate)
19 | throws ClassFileReadException, InvalidTagXMLException {
20 | return emptyMember(memberTemplate);
21 | }
22 |
23 | @SuppressWarnings("unchecked")
24 | private HKXMember emptyMember(final HKXMemberTemplate memberTemplate) {
25 | HKXMember result = null;
26 | switch (memberTemplate.vtype) {
27 | case TYPE_BOOL:
28 | result = new HKXDirectMember(memberTemplate.name, memberTemplate.vtype);
29 | ((HKXDirectMember) result).set(Boolean.FALSE);
30 | break;
31 | case TYPE_CHAR:
32 | case TYPE_UINT8:
33 | case TYPE_INT8:
34 | result = new HKXDirectMember(memberTemplate.name, memberTemplate.vtype);
35 | ((HKXDirectMember) result).set(Character.valueOf((char) 0));
36 | break;
37 | case TYPE_UINT16:
38 | case TYPE_ULONG:
39 | case TYPE_UINT32:
40 | case TYPE_UINT64:
41 | case TYPE_INT16:
42 | case TYPE_INT32:
43 | case TYPE_INT64:
44 | result = new HKXDirectMember(memberTemplate.name, memberTemplate.vtype);
45 | ((HKXDirectMember) result).set(Integer.valueOf(0));
46 | break;
47 | case TYPE_HALF:
48 | case TYPE_REAL:
49 | result = new HKXDirectMember(memberTemplate.name, memberTemplate.vtype);
50 | ((HKXDirectMember) result).set(Double.valueOf(0));
51 | break;
52 | default:
53 | break;
54 | }
55 | return result;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagwriter/TagXMLWriter.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagwriter;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 |
6 | import javax.xml.parsers.ParserConfigurationException;
7 | import javax.xml.transform.TransformerException;
8 |
9 | import org.w3c.dom.Document;
10 | import org.w3c.dom.Element;
11 | import org.w3c.dom.Node;
12 |
13 | import com.dexesttp.hkxpack.data.HKXFile;
14 | import com.dexesttp.hkxpack.data.HKXObject;
15 |
16 | /**
17 | * Handles writing {@link HKXFile} data into a {@link File} using the TagXML
18 | * notation.
19 | */
20 | public class TagXMLWriter {
21 | private final transient File outFile;
22 |
23 | /**
24 | * Creates a {@link TagXMLWriter}.
25 | *
26 | * @param outputFile the file to output the data into.
27 | */
28 | public TagXMLWriter(final File outputFile) {
29 | this.outFile = outputFile;
30 | }
31 |
32 | /**
33 | * Write an {@link HKXFile} as an XML file.
34 | *
35 | * @param hkxFile the HKXFiel to write.
36 | * @throws IOException if the XML file couldn't be written.
37 | * @throws TransformerException if there was a problem handling the
38 | * {@link HKXFile}'s content.
39 | * @throws ParserConfigurationException if there was a problem creating the XML
40 | * {@link Document}.
41 | */
42 | public void write(final HKXFile hkxFile) throws IOException, TransformerException, ParserConfigurationException {
43 | TagXMLHandler handler = new TagXMLHandler();
44 | // Create the new Document
45 | Document document = handler.createDOM(hkxFile.getContentsVersion(), hkxFile.getClassVersion());
46 |
47 | // Create the "__data__" section in the document.
48 | Element root = handler.createSection(document, "__data__");
49 |
50 | TagXMLDataCreator creator = new TagXMLDataCreator(document);
51 |
52 | for (HKXObject content : hkxFile.getContentCollection()) {
53 | Node contentXML = creator.create(content);
54 | root.appendChild(contentXML);
55 | }
56 | handler.writeToFile(document, outFile);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/callbacks/HKXDefaultArrayMemberCallback.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object.callbacks;
2 |
3 | import java.util.List;
4 |
5 | import com.dexesttp.hkxpack.data.HKXData;
6 | import com.dexesttp.hkxpack.data.members.HKXArrayMember;
7 | import com.dexesttp.hkxpack.data.members.HKXMember;
8 | import com.dexesttp.hkxpack.hkx.HKXUtils;
9 | import com.dexesttp.hkxpack.hkx.types.MemberSizeResolver;
10 | import com.dexesttp.hkxpack.hkxwriter.object.HKXMemberHandler;
11 | import com.dexesttp.hkxpack.hkxwriter.object.HKXMemberHandlerFactory;
12 |
13 | /**
14 | * Handles callbacks for most members.
15 | */
16 | public class HKXDefaultArrayMemberCallback implements HKXArrayMemberCallback {
17 | private final transient HKXArrayMember arrMember;
18 | private final transient HKXMemberHandlerFactory memberHandlerFactory;
19 |
20 | /**
21 | * Creates a {@link HKXDefaultArrayMemberCallback}
22 | *
23 | * @param arrMember the {@link HKXArrayMember} this callback handles
24 | * @param memberHandlerFactory the {@link HKXMemberHandlerFactory} to use while
25 | * creating the array component's handlers.
26 | */
27 | public HKXDefaultArrayMemberCallback(final HKXArrayMember arrMember,
28 | final HKXMemberHandlerFactory memberHandlerFactory) {
29 | this.arrMember = arrMember;
30 | this.memberHandlerFactory = memberHandlerFactory;
31 | }
32 |
33 | @Override
34 | /**
35 | * {@inheritDoc}
36 | */
37 | public long process(final List memberCallbacks, final long position) {
38 | long newPos = position;
39 | long memberSize = MemberSizeResolver.getSize(arrMember.getSubType());
40 | for (HKXData data : arrMember.getContentsList()) {
41 | if (data instanceof HKXMember) {
42 | HKXMember internalMember = (HKXMember) data;
43 | HKXMemberHandler memberHandler = memberHandlerFactory.create(internalMember.getType(), 0);
44 | memberCallbacks.add(memberHandler.write(internalMember, newPos));
45 | newPos += memberSize;
46 | }
47 | }
48 | return HKXUtils.snapLine(newPos) - position;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/commands/Command_help.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.commands;
2 |
3 | import java.util.logging.Level;
4 | import java.util.logging.Logger;
5 |
6 | import com.dexesttp.hkxpack.cli.ConsoleView;
7 | import com.dexesttp.hkxpack.cli.utils.StaticProperties;
8 |
9 | /**
10 | * Displays the help of the Command Line Interface.
11 | */
12 | public class Command_help implements Command {
13 | private static final Logger LOGGER = Logger.getLogger(ConsoleView.class.getName());
14 |
15 | @Override
16 | /**
17 | * {@inheritDoc}
18 | */
19 | // TODO prettify help.
20 | public int execute(final String... parameters) {
21 | boolean verbose = false;
22 | if (parameters.length >= 2 && parameters[1].equals("-v")) {
23 | verbose = true;
24 | }
25 | System.setProperty("java.util.logging.SimpleFormatter.format", "%5$s%n");
26 | LOGGER.setLevel(Level.INFO);
27 |
28 | if (LOGGER.isLoggable(Level.INFO)) {
29 | LOGGER.info("HKXPack version " + StaticProperties.getVersionNumber());
30 | LOGGER.info("Use : java -jar hkxpack-cli.jar ");
31 | LOGGER.info("Arguments :");
32 | LOGGER.info("\t" + "unpack" + "\t" + "\t" + "Extracts .hkx into .xml");
33 | LOGGER.info("\t" + "pack" + "\t" + "\t" + "Compress .xml into .hkx");
34 | LOGGER.info("\t" + "help" + "\t\t\t" + "Show this window");
35 | LOGGER.info("Options :");
36 | LOGGER.info("\t" + "-q\t\t" + "Quiet output");
37 | LOGGER.info("\t" + "-v\t\t" + "Verbose output");
38 | LOGGER.info("\t" + "-o \t" + "Set the output file");
39 | LOGGER.info("Advanced options :");
40 | if (verbose) {
41 | LOGGER.info("\t" + "-d\t\t" + "Debug output");
42 | LOGGER.info("\t" + "-t " + "\t" + "Set the maximum numbers of threads to use");
43 | LOGGER.info("\t" + "-b " + "\t" + "Set the buffer size");
44 | } else {
45 | LOGGER.info("\t" + "Use the 'help -v' option to see advanced options");
46 | }
47 | LOGGER.info("");
48 | LOGGER.info("Report bugs or findings at github.com/dexesttp/hkxpack");
49 | }
50 | return 0;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/member/HKXEnumMemberReader.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader.member;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import com.dexesttp.hkxpack.data.members.HKXEnumMember;
6 | import com.dexesttp.hkxpack.data.members.HKXMember;
7 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
8 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
9 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
10 | import com.dexesttp.hkxpack.hkx.types.MemberSizeResolver;
11 | import com.dexesttp.hkxpack.hkxreader.HKXReaderConnector;
12 | import com.dexesttp.hkxpack.resources.byteutils.ByteUtils;
13 |
14 | /**
15 | * Reads an enumeration as a {@link HKXEnumMember} from a HKX file.
16 | */
17 | public class HKXEnumMemberReader implements HKXMemberReader {
18 | private final transient HKXReaderConnector connector;
19 | private final transient HKXEnumResolver enumResolver;
20 | private final transient String name;
21 | private final transient HKXType vtype;
22 | private final transient HKXType vsubtype;
23 | private final transient String etype;
24 | private final transient long memberOffset;
25 |
26 | HKXEnumMemberReader(final HKXReaderConnector connector, final HKXEnumResolver enumResolver, final String name,
27 | final HKXType vtype, final HKXType vsubtype, final String target, final long offset) {
28 | this.connector = connector;
29 | this.enumResolver = enumResolver;
30 | this.name = name;
31 | this.vtype = vtype;
32 | this.vsubtype = vsubtype;
33 | this.etype = target;
34 | this.memberOffset = offset;
35 | }
36 |
37 | @Override
38 | /**
39 | * {@inheritDoc}
40 | */
41 | public HKXMember read(final long classOffset) throws InvalidPositionException {
42 | final int memberSize = (int) MemberSizeResolver.getSize(vsubtype);
43 | ByteBuffer file = connector.data.setup(classOffset + memberOffset);
44 | byte[] bytesToRead = new byte[memberSize];
45 | file.get(bytesToRead);
46 | int contents = ByteUtils.getUInt(bytesToRead);
47 | HKXEnumMember result = new HKXEnumMember(name, vtype, vsubtype, etype);
48 | result.set(enumResolver.resolve(etype, contents));
49 | return result;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/types/handlers/Vector4Handler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.types.handlers;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXDirectMember;
4 | import com.dexesttp.hkxpack.data.members.HKXMember;
5 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
6 | import com.dexesttp.hkxpack.resources.byteutils.ByteUtils;
7 |
8 | /**
9 | * Handles quaternions
10 | */
11 | class Vector4Handler implements MemberHandler {
12 | @Override
13 | /**
14 | * {@inheritDoc}
15 | */
16 | public long getSize() {
17 | return 0x10;
18 | }
19 |
20 | @Override
21 | /**
22 | * {@inheritDoc}
23 | */
24 | public HKXMember createMember(final String name, final HKXType type, final byte[] byteArray) {
25 | byte[] b21 = new byte[] { byteArray[0], byteArray[1], byteArray[2], byteArray[3] };
26 | byte[] b22 = new byte[] { byteArray[4], byteArray[5], byteArray[6], byteArray[7] };
27 | byte[] b23 = new byte[] { byteArray[8], byteArray[9], byteArray[10], byteArray[11] };
28 | byte[] b24 = new byte[] { byteArray[12], byteArray[13], byteArray[14], byteArray[15] };
29 | HKXDirectMember member8 = new HKXDirectMember<>(name, type);
30 | member8.set(new Double[] { (double) ByteUtils.getFloat(b21), (double) ByteUtils.getFloat(b22),
31 | (double) ByteUtils.getFloat(b23), (double) ByteUtils.getFloat(b24) });
32 | return member8;
33 | }
34 |
35 | @SuppressWarnings("unchecked")
36 | @Override
37 | /**
38 | * {@inheritDoc}
39 | */
40 | public byte[] readMember(final HKXMember member) {
41 | HKXDirectMember memberTransform = (HKXDirectMember) member;
42 | byte[] memberTr1 = ByteUtils.fromFloat(memberTransform.get()[0], 4);
43 | byte[] memberTr2 = ByteUtils.fromFloat(memberTransform.get()[1], 4);
44 | byte[] memberTr3 = ByteUtils.fromFloat(memberTransform.get()[2], 4);
45 | byte[] memberTr4 = ByteUtils.fromFloat(memberTransform.get()[3], 4);
46 | return new byte[] { memberTr1[0], memberTr1[1], memberTr1[2], memberTr1[3], memberTr2[0], memberTr2[1],
47 | memberTr2[2], memberTr2[3], memberTr3[0], memberTr3[1], memberTr3[2], memberTr3[3], memberTr4[0],
48 | memberTr4[1], memberTr4[2], memberTr4[3] };
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/HKXStringMemberHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object;
2 |
3 | import java.nio.Buffer;
4 | import java.nio.ByteBuffer;
5 | import java.util.List;
6 |
7 | import com.dexesttp.hkxpack.data.members.HKXMember;
8 | import com.dexesttp.hkxpack.data.members.HKXStringMember;
9 | import com.dexesttp.hkxpack.hkx.HKXUtils;
10 | import com.dexesttp.hkxpack.hkx.data.DataInternal;
11 | import com.dexesttp.hkxpack.hkxwriter.object.callbacks.HKXMemberCallback;
12 |
13 | /**
14 | * Handles a {@link HKXStringMember} for output to a HKX file.
15 | *
16 | * @see HKXMemberHandler
17 | */
18 | public class HKXStringMemberHandler implements HKXMemberHandler {
19 | private final transient ByteBuffer outFile;
20 | private final transient long offset;
21 | private final transient List data1;
22 |
23 | /**
24 | * Creates a {@link HKXStringMemberHandler}.
25 | *
26 | * @param outFile the file to output to
27 | * @param offset the member's offset in the object
28 | * @param data1List the list of internal pointers to put the {@link String}'s
29 | * location reference in.
30 | */
31 | public HKXStringMemberHandler(final ByteBuffer outFile, final long offset, final List data1List) {
32 | this.outFile = outFile;
33 | this.offset = offset;
34 | this.data1 = data1List;
35 | }
36 |
37 | @Override
38 | /**
39 | * {@inheritDoc}
40 | */
41 | public HKXMemberCallback write(final HKXMember member, final long currentPos) {
42 | final HKXStringMember strMember = (HKXStringMember) member;
43 | if (strMember.get() == null || strMember.get().isEmpty()) {
44 | return (callbacks, position) -> {
45 | return 0;
46 | };
47 | }
48 | final DataInternal stringData = new DataInternal();
49 | stringData.from = currentPos + offset;
50 | return (callbacks, position) -> {
51 | stringData.to = position;
52 | data1.add(stringData);
53 | ((Buffer) outFile).position((int) position);
54 | outFile.put(strMember.get().getBytes());
55 | outFile.put((byte) 0x00);
56 | return HKXUtils.snapString(position + strMember.get().length() + 1) - position;
57 | };
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagwriter/TagXMLDirectMemberHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagwriter;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXDirectMember;
4 |
5 | /**
6 | * Handles the conversion between a {@link HKXDirectMember} member and its
7 | * content as a {@link String}.
8 | */
9 | class TagXMLDirectMemberHandler {
10 | public static final int VECTOR4_LENGTH = 4;
11 | public static final int QSTRANSFORM_LENGTH = 12;
12 |
13 | /**
14 | * Converts a {@link HKXDirectMember} into a {@link String}.
15 | *
16 | * @param member the {@link HKXDirectMember} to convert
17 | * @return a {@link String} containign the value of the {@link HKXDirectMember}.
18 | */
19 | @SuppressWarnings("unchecked")
20 | String getStringValue(final HKXDirectMember> member) {
21 | if (member.get() instanceof Double[]) {
22 | Double[] contents = (Double[]) member.get();
23 | if (contents.length <= VECTOR4_LENGTH) {
24 | StringBuffer contentsAccu = new StringBuffer();
25 | contentsAccu.append('(');
26 | for (int i = 0; i < contents.length; i++) {
27 | contentsAccu.append(contents[i]).append(' ');
28 | }
29 | return contentsAccu.substring(0, contentsAccu.length() - 1) + ")";
30 | } else {
31 | if (contents.length == QSTRANSFORM_LENGTH) {
32 | return "(" + contents[0] + " " + contents[1] + " " + contents[2] + " " + contents[3] + ")" + "("
33 | + contents[4] + " " + contents[5] + " " + contents[6] + " " + contents[7] + ")" + "("
34 | + contents[8] + " " + contents[9] + " " + contents[10] + " " + contents[11] + ")";
35 | } else {
36 | return "(" + contents[0] + " " + contents[1] + " " + contents[2] + " " + contents[3] + ")" + "("
37 | + contents[4] + " " + contents[5] + " " + contents[6] + " " + contents[7] + ")" + "("
38 | + contents[8] + " " + contents[9] + " " + contents[10] + " " + contents[11] + ")" + "("
39 | + contents[12] + " " + contents[13] + " " + contents[14] + " " + contents[15] + ")";
40 | }
41 | }
42 | }
43 | if (member.get() instanceof Character) {
44 | return Integer.toString((int) ((char) ((HKXDirectMember) member).get()));
45 | }
46 | return member.get().toString();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/test/java/com/dexesttp/hkxpack/files/TestBase.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.files;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import org.junit.Ignore;
7 | import org.junit.Test;
8 |
9 | import com.dexesttp.hkxpack.data.HKXFile;
10 | import com.dexesttp.hkxpack.data.HKXObject;
11 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
12 |
13 | /**
14 | * The content reading tests for all files based on the "base" file.
15 | */
16 | @Ignore
17 | public class TestBase {
18 | protected final static String BASE_FILE_RESOURCE_NAME = "/test-base";
19 | protected final transient HKXFile file;
20 |
21 | /**
22 | * Creates a {@link TestBase}.
23 | *
24 | * @param file the {@link HXKFile} to test
25 | */
26 | protected TestBase(final HKXFile file) {
27 | this.file = file;
28 | }
29 |
30 | @Test
31 | /**
32 | * Tests if there is the right number of objects in the base file (1)
33 | */
34 | public void testIfThereIsTheRightNumberOfObjects() {
35 | assertEquals(1, file.getContentCollection().size());
36 | }
37 |
38 | @Test
39 | /**
40 | * Tests if the the read object's Type is the right one (a STRUCT)
41 | */
42 | public void testIfTheRightObjectIsPresent() {
43 | for (final HKXObject object : file.getContentCollection()) {
44 | assertEquals(HKXType.TYPE_STRUCT, object.getType());
45 | }
46 | }
47 |
48 | @Test
49 | /**
50 | * Tests if the the read object's name is valid (not null)
51 | */
52 | public void testTheObjectName() {
53 | for (final HKXObject object : file.getContentCollection()) {
54 | assertNotNull(object.getName());
55 | }
56 | }
57 |
58 | @Test
59 | /**
60 | * Tests if the the read object's class name is the right one (hkBaseObject)
61 | */
62 | public void testTheObjectClassName() {
63 | for (final HKXObject object : file.getContentCollection()) {
64 | assertEquals("hkBaseObject", object.getDescriptor().getName());
65 | }
66 | }
67 |
68 | @Test
69 | /**
70 | * Tests if the the read object's content size is right (0)
71 | */
72 | public void testTheObjectContentsSize() {
73 | for (final HKXObject object : file.getContentCollection()) {
74 | assertEquals(0, object.getMembersList().size());
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/types/MemberSizeResolver.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.types;
2 |
3 | import com.dexesttp.hkxpack.descriptor.HKXDescriptor;
4 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
5 | import com.dexesttp.hkxpack.hkx.types.handlers.MemberHandlerFactory;
6 |
7 | /**
8 | * Intended to retrieve {@link HKXType}-specific data.
9 | *
10 | * {@link #getSize(HKXType)} retrieves the size of a {@link HKXType}
11 | * {@link #getSize(HKXDescriptor)} retrieves the size of a
12 | * {@link HKXDescriptor}, including padding.
13 | */
14 | public final class MemberSizeResolver {
15 | private static final long PTR_SIZE = 0x08;
16 |
17 | private MemberSizeResolver() {
18 | // NO OP
19 | }
20 |
21 | /**
22 | * Retrieve the size of a standard {@link HKXType}.
23 | *
24 | * @param type the {@link HKXType} to retrieve the size of.
25 | * @return the {@link HKXType}'s size.
26 | * @throws IllegalArgumentException if the given {@link HKXType} isn't standard.
27 | */
28 | public static long getSize(final HKXType type) {
29 | switch (type) {
30 | case TYPE_NONE:
31 | case TYPE_VOID:
32 | return 0X00;
33 | case TYPE_ENUM:
34 | case TYPE_FLAGS:
35 | return 0X04;
36 | // Base values
37 | case TYPE_BOOL:
38 | case TYPE_CHAR:
39 | case TYPE_UINT8:
40 | case TYPE_INT8:
41 | case TYPE_HALF:
42 | case TYPE_UINT16:
43 | case TYPE_INT16:
44 | case TYPE_ULONG:
45 | case TYPE_UINT32:
46 | case TYPE_INT32:
47 | case TYPE_UINT64:
48 | case TYPE_INT64:
49 | case TYPE_REAL:
50 | // Complex values
51 | case TYPE_VECTOR4:
52 | case TYPE_QUATERNION:
53 | case TYPE_QSTRANSFORM:
54 | case TYPE_MATRIX3:
55 | case TYPE_TRANSFORM:
56 | case TYPE_MATRIX4:
57 | return MemberHandlerFactory.getMemberHandler(type).getSize();
58 | // Strings and ptrs
59 | case TYPE_CSTRING:
60 | case TYPE_STRINGPTR:
61 | return PTR_SIZE;
62 | case TYPE_FUNCTIONPOINTER:
63 | case TYPE_POINTER:
64 | return PTR_SIZE;
65 | // Arrays
66 | case TYPE_RELARRAY:
67 | return 0x4;
68 | case TYPE_ARRAY:
69 | case TYPE_SIMPLEARRAY:
70 | return 0X10;
71 | default:
72 | break;
73 | }
74 | throw new IllegalArgumentException(type.toString() + " can't be analyzed with MemberTypeResolver#getSize");
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxreader/HKXReaderConnector.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxreader;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import com.dexesttp.hkxpack.hkx.classnames.ClassnamesData;
6 | import com.dexesttp.hkxpack.hkx.classnames.ClassnamesInterface;
7 | import com.dexesttp.hkxpack.hkx.data.Data1Interface;
8 | import com.dexesttp.hkxpack.hkx.data.Data2Interface;
9 | import com.dexesttp.hkxpack.hkx.data.Data3Interface;
10 | import com.dexesttp.hkxpack.hkx.data.DataInterface;
11 | import com.dexesttp.hkxpack.hkx.header.HeaderData;
12 | import com.dexesttp.hkxpack.hkx.header.HeaderInterface;
13 | import com.dexesttp.hkxpack.hkx.header.SectionData;
14 | import com.dexesttp.hkxpack.hkx.header.SectionInterface;
15 |
16 | /**
17 | * Handles connexion between a {@link ByteBuffer} and a {@link HKXReader}.
18 | *
19 | * Created and managed by {@link HKXReader}.
20 | */
21 | public class HKXReaderConnector {
22 | public final transient HeaderData header;
23 | public final transient SectionData classnamesHead;
24 | public final transient SectionData dataHead;
25 | public final transient ClassnamesData classnamesdata;
26 | public final transient DataInterface data;
27 | public final transient Data1Interface data1;
28 | public final transient Data2Interface data2;
29 | public final transient Data3Interface data3;
30 |
31 | HKXReaderConnector(final ByteBuffer file) {
32 | // Extract the header
33 | HeaderInterface headInt = new HeaderInterface();
34 | headInt.connect(file);
35 | header = headInt.extract();
36 |
37 | // Extract the section interfaces
38 | SectionInterface sectInt = new SectionInterface();
39 | sectInt.connect(file, header);
40 | classnamesHead = sectInt.extract(0);
41 | dataHead = sectInt.extract(2);
42 |
43 | // Extract the classnames
44 | ClassnamesInterface cnamesInt = new ClassnamesInterface();
45 | cnamesInt.connect(file, classnamesHead);
46 | classnamesdata = cnamesInt.extract();
47 |
48 | // Connect the interfaces
49 | data1 = new Data1Interface();
50 | data1.connect(file, dataHead);
51 | data2 = new Data2Interface();
52 | data2.connect(file, dataHead);
53 | data3 = new Data3Interface();
54 | data3.connect(file, dataHead);
55 | data = new DataInterface();
56 | data.connect(file, dataHead);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/cli/src/main/java/com/dexesttp/hkxpack/cli/commands/Command_pack.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.commands;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 |
6 | import javax.xml.parsers.ParserConfigurationException;
7 |
8 | import org.xml.sax.SAXException;
9 |
10 | import com.dexesttp.hkxpack.cli.utils.FileNameCreationException;
11 | import com.dexesttp.hkxpack.data.HKXFile;
12 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
13 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
14 | import com.dexesttp.hkxpack.hkx.exceptions.UnsupportedVersionError;
15 | import com.dexesttp.hkxpack.hkxwriter.HKXWriter;
16 | import com.dexesttp.hkxpack.tagreader.TagXMLReader;
17 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
18 |
19 | /**
20 | * Packs a XML file into a HKX file.
21 | *
22 | * @see Command_IO
23 | */
24 | public class Command_pack extends Command_IO {
25 | @Override
26 | /**
27 | * {@inheritDoc}
28 | */
29 | protected void executionCore(final String inputFileName, final String outputFileName,
30 | final HKXEnumResolver enumResolver, final HKXDescriptorFactory descriptorFactory)
31 | throws ParserConfigurationException, SAXException, IOException, InvalidTagXMLException,
32 | UnsupportedVersionError {
33 | // Read XML file
34 | File inFile = new File(inputFileName);
35 | TagXMLReader reader = new TagXMLReader(inFile, descriptorFactory);
36 | HKXFile file = reader.read();
37 |
38 | // Write HKX file
39 | File outFile = new File(outputFileName);
40 | outFile.createNewFile();
41 | HKXWriter writer = new HKXWriter(outFile, enumResolver, bufferSize);
42 | writer.write(file);
43 | }
44 |
45 | @Override
46 | /**
47 | * {@inheritDoc}
48 | */
49 | protected String extractFileName(final String ogName) throws FileNameCreationException {
50 | String newName = "";
51 | try {
52 | newName = ogName.substring(0, ogName.lastIndexOf('.')) + ".hkx";
53 | } catch (StringIndexOutOfBoundsException e) {
54 | throw new FileNameCreationException("The file : " + ogName + " has a name that can't be converted.", e);
55 | }
56 | return newName;
57 | }
58 |
59 | @Override
60 | /**
61 | * {@inheritDoc}
62 | */
63 | protected String[] getFileExtensions() {
64 | return new String[] { ".xml" };
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/cli/src/debug/java/com/dexesttp/hkxpack/cli/components/Read.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.components;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.logging.Logger;
6 |
7 | import javax.xml.parsers.ParserConfigurationException;
8 | import javax.xml.transform.TransformerException;
9 |
10 | import com.dexesttp.hkxpack.data.HKXFile;
11 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
12 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
13 | import com.dexesttp.hkxpack.hkx.exceptions.InvalidPositionException;
14 | import com.dexesttp.hkxpack.hkxreader.HKXReader;
15 | import com.dexesttp.hkxpack.resources.DisplayProperties;
16 | import com.dexesttp.hkxpack.tagwriter.TagXMLWriter;
17 |
18 | /**
19 | * Testing interface, used to perform live tests with Eclipse.
20 | */
21 | public final class Read {
22 | private static final Logger LOGGER = Logger.getLogger(Read.class.getName());
23 | private Read() {
24 | // NO OP
25 | }
26 | /**
27 | * Tests a HKX file {@code .hkx} by reading it and writing it back under {@code .xml}
28 | * @param rootName the root directory
29 | * @param testName the file to test, without its extension
30 | */
31 | public static void exec(final String rootName, final String name) {
32 | String inputFileName = rootName + name + ".hkx";
33 | String outputFileName = rootName + name + ".xml";
34 | DisplayProperties.displayDebugInfo = true;
35 | DisplayProperties.displayFileDebugInfo = true;
36 | DisplayProperties.displayReadTypesInfo = true;
37 | DisplayProperties.displayClassImportsInfo = true;
38 | DisplayProperties.displayEmbeddedData = true;
39 | try {
40 | // Read file
41 | File inFile = new File(inputFileName);
42 | HKXEnumResolver enumResolver = new HKXEnumResolver();
43 | HKXDescriptorFactory descriptorFactory = new HKXDescriptorFactory(enumResolver);
44 | HKXReader reader = new HKXReader(inFile, descriptorFactory, enumResolver);
45 | HKXFile hkxFile = reader.read();
46 |
47 | // Write file
48 | File outFile = new File(outputFileName);
49 | TagXMLWriter writer = new TagXMLWriter(outFile);
50 | writer.write(hkxFile);
51 | } catch (IOException | TransformerException | ParserConfigurationException | InvalidPositionException e) {
52 | LOGGER.throwing(Read.class.getName(), "exec", e);
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/types/object/ObjectSnap.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.types.object;
2 |
3 | import java.util.List;
4 |
5 | import com.dexesttp.hkxpack.data.HKXObject;
6 | import com.dexesttp.hkxpack.descriptor.HKXDescriptor;
7 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
8 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
9 | import com.dexesttp.hkxpack.descriptor.enums.HKXTypeFamily;
10 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
11 | import com.dexesttp.hkxpack.descriptor.members.HKXMemberTemplate;
12 |
13 | /**
14 | * Handle object snapping
15 | */
16 | final class ObjectSnap {
17 | private ObjectSnap() {
18 | // NO OP
19 | }
20 |
21 | static long getSnap(final HKXDescriptor descriptor, final HKXDescriptorFactory descriptorFactory)
22 | throws ClassFileReadException {
23 | long bestSnap = 0;
24 | List list = descriptor.getMemberTemplates();
25 | for (int i = 0; i < list.size(); i++) {
26 | HKXMemberTemplate template = list.get(i);
27 | long currSnap = 0;
28 | if (template.vtype.getFamily() == HKXTypeFamily.ENUM) {
29 | currSnap = PrimitiveSnap.primitiveSnap(template.vsubtype);
30 | } else if (template.vtype == HKXType.TYPE_STRUCT) {
31 | HKXDescriptor internalDescriptor = descriptorFactory.get(template.target);
32 | currSnap = getSnap(internalDescriptor, descriptorFactory);
33 | } else {
34 | currSnap = PrimitiveSnap.primitiveSnap(template.vtype);
35 | }
36 | bestSnap = currSnap > bestSnap ? currSnap : bestSnap;
37 | }
38 | return bestSnap;
39 | }
40 |
41 | static long getSnap(final HKXObject object) {
42 | long bestSnap = 0;
43 | List list = object.getDescriptor().getMemberTemplates();
44 | for (int i = 0; i < list.size(); i++) {
45 | HKXMemberTemplate template = list.get(i);
46 | long currSnap = 0;
47 | if (template.vtype.getFamily() == HKXTypeFamily.ENUM) {
48 | currSnap = PrimitiveSnap.primitiveSnap(template.vsubtype);
49 | } else if (template.vtype == HKXType.TYPE_STRUCT) {
50 | HKXObject internalObject = (HKXObject) object.getMembersList().get(i);
51 | currSnap = getSnap(internalObject);
52 | } else {
53 | currSnap = PrimitiveSnap.primitiveSnap(template.vtype);
54 | }
55 | bestSnap = currSnap > bestSnap ? currSnap : bestSnap;
56 | }
57 | return bestSnap;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/data/members/HKXPointerMember.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.data.members;
2 |
3 | import com.dexesttp.hkxpack.data.HKXObject;
4 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
5 |
6 | /**
7 | * A {@link HKXMember} referencing another {@link HKXObject}
8 | */
9 | public class HKXPointerMember implements HKXMember {
10 | private final String name;
11 | private final HKXType type;
12 | private final HKXType subtype;
13 | private transient String targetObjectName;
14 |
15 | /**
16 | * Create a {@link HKXPointerMember}, a link to a given {@link HKXObject}.
17 | *
18 | * @param name the name of the {@link HKXPointerMember}.
19 | * @param type the type of the {@link HKXPointerMember}. Note that
20 | * the {@link HKXType#getFamily()} function should be
21 | * {@link HKXTypeFamily#POINTER}, although this isn't
22 | * checked.
23 | * @param subtype the type of the target of the
24 | * {@link HKXPointerMember}, if described in the
25 | * classXML.
26 | * @param targetObjectName the target object's name.
27 | */
28 | public HKXPointerMember(final String name, final HKXType type, final HKXType subtype,
29 | final String targetObjectName) {
30 | this.name = name;
31 | this.type = type;
32 | this.subtype = subtype;
33 | this.targetObjectName = targetObjectName;
34 | }
35 |
36 | /**
37 | * Set this {@link HKXPointerMember}'s target name.
38 | *
39 | * @param targetObjectName the name of the target object
40 | */
41 | public void set(final String targetObjectName) {
42 | this.targetObjectName = targetObjectName;
43 | }
44 |
45 | /**
46 | * Get this {@link HKXPointerMember}'s target name.
47 | *
48 | * @return the name of the target object.
49 | */
50 | public String get() {
51 | return targetObjectName;
52 | }
53 |
54 | /**
55 | * get this {@link HKXPointerMember}'s subtype, if renseigned by the classXML.
56 | *
57 | * @return
58 | */
59 | public HKXType getSubtype() {
60 | return subtype;
61 | }
62 |
63 | @Override
64 | /**
65 | * {@inheritDoc}
66 | */
67 | public String getName() {
68 | return name;
69 | }
70 |
71 | @Override
72 | /**
73 | * {@inheritDoc}
74 | */
75 | public HKXType getType() {
76 | return type;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkxwriter/object/HKXInternalObjectHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkxwriter.object;
2 |
3 | import java.util.List;
4 |
5 | import com.dexesttp.hkxpack.data.HKXObject;
6 | import com.dexesttp.hkxpack.data.members.HKXMember;
7 | import com.dexesttp.hkxpack.descriptor.members.HKXMemberTemplate;
8 | import com.dexesttp.hkxpack.hkx.types.ObjectSizeResolver;
9 | import com.dexesttp.hkxpack.hkxwriter.object.callbacks.HKXMemberCallback;
10 |
11 | /**
12 | * Handles a {@link HKXObject} as a {@link HKXMember} for writing it back to a
13 | * HKX file.
14 | */
15 | public class HKXInternalObjectHandler {
16 | private final transient HKXMemberHandlerFactory memberHandlerFactory;
17 | private final transient List memberCallbacks;
18 |
19 | /**
20 | * Associates a handler to a series of callbacks for writing to
21 | *
22 | * @param factory the {@link HKXMemberHandlerFactory} to use while
23 | * solving the {@link HKXObject}'s members.
24 | * @param memberCallbacks the list of {@link HKXMemberCallback} to add callbacks
25 | * into.
26 | */
27 | public HKXInternalObjectHandler(final HKXMemberHandlerFactory factory,
28 | final List memberCallbacks) {
29 | this.memberHandlerFactory = factory;
30 | this.memberCallbacks = memberCallbacks;
31 | }
32 |
33 | /**
34 | * Writes the internal object back to the HKX File.
35 | *
36 | * @param objectAsMember the {@link HKXObject} to write, as a {@link HKXMember}.
37 | * @param currentPos the position of the class.
38 | * @return the new position.
39 | */
40 | public long write(final HKXMember objectAsMember, final long currentPos) {
41 | HKXObject object = (HKXObject) objectAsMember;
42 | // Prepare the member handlers, and fill the raw structure.
43 | List members = object.getMembersList();
44 | List memberTemplates = object.getDescriptor().getMemberTemplates();
45 | for (int i = 0; i < memberTemplates.size(); i++) {
46 | HKXMember member = members.get(i);
47 | HKXMemberTemplate memberTemplate = memberTemplates.get(i);
48 | HKXMemberHandler memberHandler = memberHandlerFactory.create(memberTemplate.vtype, memberTemplate.offset);
49 | memberCallbacks.add(memberHandler.write(member, currentPos));
50 | }
51 | return currentPos + ObjectSizeResolver.getSize(object);
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/cli/src/debug/java/com/dexesttp/hkxpack/cli/components/Write.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.components;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.logging.Logger;
6 |
7 | import javax.xml.parsers.ParserConfigurationException;
8 |
9 | import org.xml.sax.SAXException;
10 |
11 | import com.dexesttp.hkxpack.data.HKXFile;
12 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
13 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
14 | import com.dexesttp.hkxpack.hkx.exceptions.UnsupportedVersionError;
15 | import com.dexesttp.hkxpack.hkxwriter.HKXWriter;
16 | import com.dexesttp.hkxpack.resources.DisplayProperties;
17 | import com.dexesttp.hkxpack.tagreader.TagXMLReader;
18 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
19 |
20 | /**
21 | * Testing interface, used to perform live tests with Eclipse.
22 | */
23 | public final class Write {
24 | private static final Logger LOGGER = Logger.getLogger(Write.class.getName());
25 | private Write() {
26 | // NO OP
27 | }
28 | /**
29 | * Tests a HKX file {@code .xml} by reading it and writing it back under {@code .hkx}
30 | * @param rootName the root directory
31 | * @param testName the file to test, without its extension
32 | */
33 | public static void exec(final String rootName, final String testName) {
34 | String inputFileName = rootName + testName + ".xml";
35 | String outputFileName = rootName + testName + "-new.hkx";
36 | DisplayProperties.displayDebugInfo = true;
37 | DisplayProperties.displayFileDebugInfo = true;
38 | DisplayProperties.displayReadTypesInfo = true;
39 | DisplayProperties.displayClassImportsInfo = true;
40 | DisplayProperties.displayEmbeddedData = true;
41 | try {
42 | // Read file
43 | File inFile = new File(inputFileName);
44 | HKXEnumResolver enumResolver = new HKXEnumResolver();
45 | HKXDescriptorFactory descriptorFactory = new HKXDescriptorFactory(enumResolver);
46 | TagXMLReader reader = new TagXMLReader(inFile, descriptorFactory);
47 | HKXFile file = reader.read();
48 |
49 | File outFile = new File(outputFileName);
50 | HKXWriter writer = new HKXWriter(outFile, enumResolver);
51 | writer.write(file);
52 | } catch (IOException | UnsupportedVersionError | ParserConfigurationException | SAXException | InvalidTagXMLException e) {
53 | LOGGER.throwing(Write.class.getName(), "exec", e);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/cli/src/debug/java/com/dexesttp/hkxpack/cli/components/XMLTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.components;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.logging.Logger;
6 |
7 | import javax.xml.parsers.ParserConfigurationException;
8 | import javax.xml.transform.TransformerException;
9 |
10 | import org.xml.sax.SAXException;
11 |
12 | import com.dexesttp.hkxpack.data.HKXFile;
13 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
14 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
15 | import com.dexesttp.hkxpack.resources.DisplayProperties;
16 | import com.dexesttp.hkxpack.tagreader.TagXMLReader;
17 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
18 | import com.dexesttp.hkxpack.tagwriter.TagXMLWriter;
19 |
20 | /**
21 | * Testing interface, used to perform live tests with Eclipse.
22 | */
23 | public final class XMLTest {
24 | private static final Logger LOGGER = Logger.getLogger(XMLTest.class.getName());
25 | private XMLTest() {
26 | // NO OP
27 | }
28 | /**
29 | * Tests a XML file {@code .xml} by reading it and writing it back under {@code -new.xml}
30 | * @param rootName the root directory
31 | * @param testName the file to test, without its extension
32 | */
33 | public static void exec(final String rootName, final String testName) {
34 | String inputFileName = rootName + testName + ".xml";
35 | String outputFileName = rootName + testName + "-new.xml";
36 | DisplayProperties.displayDebugInfo = true;
37 | DisplayProperties.displayFileDebugInfo = true;
38 | DisplayProperties.displayReadTypesInfo = true;
39 | DisplayProperties.displayClassImportsInfo = true;
40 | DisplayProperties.displayEmbeddedData = true;
41 | try {
42 | // Read XML file
43 | File inFile = new File(inputFileName);
44 | HKXEnumResolver enumResolver = new HKXEnumResolver();
45 | HKXDescriptorFactory descriptorFactory = new HKXDescriptorFactory(enumResolver);
46 | TagXMLReader reader = new TagXMLReader(inFile, descriptorFactory);
47 | HKXFile hkxFile = reader.read();
48 |
49 | // Write XML file
50 | File outFile = new File(outputFileName);
51 | TagXMLWriter writer = new TagXMLWriter(outFile);
52 | writer.write(hkxFile);
53 | } catch (IOException | TransformerException | ParserConfigurationException | SAXException | InvalidTagXMLException e) {
54 | LOGGER.throwing(XMLTest.class.getName(), "exec", e);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/cli/src/debug/java/com/dexesttp/hkxpack/cli/components/HKXTest.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.cli.components;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.logging.Logger;
6 |
7 | import javax.xml.parsers.ParserConfigurationException;
8 | import javax.xml.transform.TransformerException;
9 |
10 | import org.xml.sax.SAXException;
11 |
12 | import com.dexesttp.hkxpack.data.HKXFile;
13 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
14 | import com.dexesttp.hkxpack.descriptor.HKXEnumResolver;
15 | import com.dexesttp.hkxpack.resources.DisplayProperties;
16 | import com.dexesttp.hkxpack.tagreader.TagXMLReader;
17 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
18 | import com.dexesttp.hkxpack.tagwriter.TagXMLWriter;
19 |
20 | /**
21 | * Testing interface, used to perform live tests with Eclipse.
22 | */
23 | public final class HKXTest {
24 | private static final Logger LOGGER = Logger.getLogger(HKXTest.class.getName());
25 | private HKXTest() {
26 | // NO OP
27 | }
28 | /**
29 | * Tests a HKX file {@code .hkx} by reading it and writing it back under {@code -new.hkx}
30 | * @param rootName the root directory
31 | * @param testName the file to test, without its extension
32 | */
33 | public static void exec(final String rootName, final String testName) {
34 | String inputFileName = rootName + testName + ".hkx";
35 | String outputFileName = rootName + testName + "-new.hkx";
36 | DisplayProperties.displayDebugInfo = true;
37 | DisplayProperties.displayFileDebugInfo = true;
38 | DisplayProperties.displayReadTypesInfo = true;
39 | DisplayProperties.displayClassImportsInfo = true;
40 | DisplayProperties.displayEmbeddedData = true;
41 | try {
42 | // Read XML file
43 | File inFile = new File(inputFileName);
44 | HKXEnumResolver enumResolver = new HKXEnumResolver();
45 | HKXDescriptorFactory descriptorFactory = new HKXDescriptorFactory(enumResolver);
46 | TagXMLReader reader = new TagXMLReader(inFile, descriptorFactory);
47 | HKXFile hkxFile = reader.read();
48 |
49 | // Write XML file
50 | File outFile = new File(outputFileName);
51 | TagXMLWriter writer = new TagXMLWriter(outFile);
52 | writer.write(hkxFile);
53 | } catch (IOException | TransformerException | ParserConfigurationException | SAXException | InvalidTagXMLException e) {
54 | LOGGER.throwing(HKXTest.class.getName(), "exec", e);
55 | }
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/doc/uml/FileReader.uml:
--------------------------------------------------------------------------------
1 | @startuml
2 | package commons {
3 | package parser {
4 | interface Reader {
5 | +connect(RandomAccessFile, position)
6 | +T read()
7 | }
8 | abstract class ConstantReader
9 | abstract class FixedReader
10 | abstract class RandomReader
11 | Reader <|-- ConstantReader
12 | Reader <|-- FixedReader
13 | Reader <|-- RandomReader
14 | }
15 | package resolver {
16 | interface Definer {
17 | +setNext(Resolver)
18 | }
19 | interface Resolver
20 | Definer <|-- RandomReader
21 | Resolver o-- Definer : uses
22 | }
23 | }
24 |
25 | package hkxpack {
26 | package hkx {
27 | package reader {
28 | abstract class TripleLinkReader
29 | ConstantReader <|-- HeaderReader #green
30 | FixedReader <|-- InternalLinkReader #green
31 | RandomReader <|-- TypeReader #green
32 | FixedReader <|-- TripleLinkReader #green
33 | TripleLinkReader <|-- ExternalLinkReader
34 | TripleLinkReader <|-- VirtualLinkReader
35 | InternalLinkReader o-- HeaderReader : creates
36 | ExternalLinkReader o-- HeaderReader : creates
37 | VirtualLinkReader o-- HeaderReader : creates
38 | TypeReader o-- HeaderReader : creates
39 | }
40 | package flags {
41 | interface FlagHandler
42 | class FlagsRef {
43 | +resolve()
44 | }
45 | FlagHandler <|-- FlagsRef
46 | class FlagsData {
47 | ~byte Content
48 | }
49 | FlagsData o-- FlagsRef : resolves into
50 | FlagHandler <|-- FlagsData
51 | ExternalLinkReader *-- FlagHandler : T
52 | VirtualLinkReader *-- FlagHandler : T
53 | }
54 | package classes {
55 | interface ClassHandler
56 | class ClassRef {
57 | +resolve()
58 | }
59 | ClassHandler <|-- ClassRef
60 | class ResolvedClass
61 | ClassHandler <|-- ResolvedClass
62 | ResolvedClass o-- ClassRef : resolved into
63 | TypeReader *-- ResolvedClass : T
64 | InternalLinkReader *-- ClassRef : T
65 | }
66 | }
67 | package xml {
68 | package classxml {
69 | class ClassXMLList << (S, #FF7700) >> {
70 | +ClassXMLDescriptor getClass(String)
71 | }
72 | class ClassXMLDescriptor
73 | class ClassXMLResolver
74 | Resolver <|-- ClassXMLResolver
75 | ClassXMLDescriptor o-u- ClassXMLResolver : uses
76 | ClassXMLList o-u- ClassXMLResolver : uses
77 | }
78 | }
79 | package main {
80 | class Main {
81 | }
82 | HeaderReader o-- Main #blue
83 | ClassHandler o-- Main #blue
84 | FlagHandler o-- Main #blue
85 | ClassXMLList o-- Main #blue
86 | }
87 | }
88 | @enduml
89 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/tagreader/TagXMLNodeHandler.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.tagreader;
2 |
3 | import org.w3c.dom.Node;
4 |
5 | import com.dexesttp.hkxpack.data.HKXObject;
6 | import com.dexesttp.hkxpack.data.members.HKXMember;
7 | import com.dexesttp.hkxpack.descriptor.HKXDescriptorFactory;
8 | import com.dexesttp.hkxpack.descriptor.exceptions.ClassFileReadException;
9 | import com.dexesttp.hkxpack.resources.DOMUtils;
10 | import com.dexesttp.hkxpack.tagreader.exceptions.InvalidTagXMLException;
11 |
12 | /**
13 | * Handles general node data retrieval, discrimining between root
14 | * {@link HKXObject}, embedded {@link HKXObject} and {@link HKXMember}s.
15 | */
16 | public class TagXMLNodeHandler {
17 | private final transient TagXMLObjectHandler objectHandler;
18 |
19 | TagXMLNodeHandler(final HKXDescriptorFactory descriptorFactory) {
20 | TagXMLMemberHandler memberHandler = new TagXMLMemberHandler(this, descriptorFactory);
21 | this.objectHandler = new TagXMLObjectHandler(descriptorFactory, memberHandler);
22 | }
23 |
24 | /**
25 | * Handles an object {@link Node} into a {@link HKXObject}.
26 | *
27 | * @param objectNode the {@link Node} to handle.
28 | * @return the relevant {@link HKXObject}.
29 | * @throws ClassFileReadException if there was a problem reading the Class data
30 | * from the program's resources.
31 | * @throws InvalidTagXMLException if there was an error parsing the TagXML file.
32 | */
33 | HKXObject handleObject(final Node objectNode) throws ClassFileReadException, InvalidTagXMLException {
34 | // Retrieve descriptor
35 | String className = DOMUtils.getNodeAttr("class", objectNode);
36 | return objectHandler.handleObject(objectNode, className);
37 | }
38 |
39 | /**
40 | * Handles a subobject (an object with no name nor class, but the className is
41 | * given).
42 | *
43 | * @param objectNode the {@link Node} to read the object from.
44 | * @param className the class name of the object.
45 | * @return the relevant {@link HKXObject}.
46 | * @throws ClassFileReadException if there was a problem reading the Class data
47 | * from the program's resources.
48 | * @throws InvalidTagXMLException if there was an error parsing the TagXML file.
49 | */
50 | public HKXObject handleSubObject(final Node objectNode, final String className)
51 | throws ClassFileReadException, InvalidTagXMLException {
52 | return objectHandler.handleObject(objectNode, className);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/types/handlers/BigMemberHandlers.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.types.handlers;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXDirectMember;
4 | import com.dexesttp.hkxpack.data.members.HKXMember;
5 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
6 | import com.dexesttp.hkxpack.resources.byteutils.ByteUtils;
7 |
8 | /**
9 | * Handles big (64) members
10 | */
11 | final class BigMemberHandlers {
12 | private BigMemberHandlers() {
13 | // NO OP
14 | }
15 |
16 | static MemberHandler createMemberHandler(final HKXType type) {
17 | switch (type) {
18 | case TYPE_UINT64:
19 | case TYPE_ULONG:
20 | return new UInt64Handler();
21 | case TYPE_INT64:
22 | return new SInt64Handler();
23 | default:
24 | return null;
25 | }
26 | }
27 |
28 | /**
29 | * Handles UInt64/ULong
30 | */
31 | static class UInt64Handler implements MemberHandler {
32 | @Override
33 | /**
34 | * {@inheritDoc}
35 | */
36 | public long getSize() {
37 | return 0x08;
38 | }
39 |
40 | @Override
41 | /**
42 | * {@inheritDoc}
43 | */
44 | public HKXMember createMember(final String name, final HKXType type, final byte[] byteArray) {
45 | HKXDirectMember member3 = new HKXDirectMember<>(name, type);
46 | member3.set((long) ByteUtils.getULong(byteArray));
47 | return member3;
48 | }
49 |
50 | @SuppressWarnings("unchecked")
51 | @Override
52 | /**
53 | * {@inheritDoc}
54 | */
55 | public byte[] readMember(final HKXMember member) {
56 | HKXDirectMember memberUInt64 = (HKXDirectMember) member;
57 | return ByteUtils.fromULong(memberUInt64.get(), 8);
58 | }
59 | }
60 |
61 | /**
62 | * Handles Int64
63 | */
64 | static class SInt64Handler implements MemberHandler {
65 | @Override
66 | /**
67 | * {@inheritDoc}
68 | */
69 | public long getSize() {
70 | return 0x08;
71 | }
72 |
73 | @Override
74 | /**
75 | * {@inheritDoc}
76 | */
77 | public HKXMember createMember(final String name, final HKXType type, final byte[] byteArray) {
78 | HKXDirectMember member4 = new HKXDirectMember<>(name, type);
79 | member4.set((long) ByteUtils.getSInt(byteArray));
80 | return member4;
81 | }
82 |
83 | @SuppressWarnings("unchecked")
84 | @Override
85 | /**
86 | * {@inheritDoc}
87 | */
88 | public byte[] readMember(final HKXMember member) {
89 | HKXDirectMember memberInt64 = (HKXDirectMember) member;
90 | return ByteUtils.fromULong(memberInt64.get(), 8);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/hkx/types/handlers/MediumMemberHandlers.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.hkx.types.handlers;
2 |
3 | import com.dexesttp.hkxpack.data.members.HKXDirectMember;
4 | import com.dexesttp.hkxpack.data.members.HKXMember;
5 | import com.dexesttp.hkxpack.descriptor.enums.HKXType;
6 | import com.dexesttp.hkxpack.resources.byteutils.ByteUtils;
7 |
8 | /**
9 | * Handles medium (16-32) members
10 | */
11 | class MediumMemberHandlers {
12 | private MediumMemberHandlers() {
13 | // NO OP
14 | }
15 |
16 | static MemberHandler createMemberHandler(final HKXType type) {
17 | switch (type) {
18 | case TYPE_UINT16:
19 | return new UInt16MemberHandler();
20 | case TYPE_INT16:
21 | return new SInt16MemberHandler();
22 | default:
23 | return null;
24 | }
25 | }
26 |
27 | /**
28 | * Handles UInt16
29 | */
30 | static class UInt16MemberHandler implements MemberHandler {
31 | @Override
32 | /**
33 | * {@inheritDoc}
34 | */
35 | public long getSize() {
36 | return 0x02;
37 | }
38 |
39 | @Override
40 | /**
41 | * {@inheritDoc}
42 | */
43 | public HKXMember createMember(final String name, final HKXType type, final byte[] byteArray) {
44 | HKXDirectMember member3 = new HKXDirectMember<>(name, type);
45 | member3.set((int) ByteUtils.getUInt(byteArray));
46 | return member3;
47 | }
48 |
49 | @SuppressWarnings("unchecked")
50 | @Override
51 | /**
52 | * {@inheritDoc}
53 | */
54 | public byte[] readMember(final HKXMember member) {
55 | HKXDirectMember memberUInt16 = (HKXDirectMember) member;
56 | return ByteUtils.fromULong(memberUInt16.get(), 2);
57 | }
58 | }
59 |
60 | /**
61 | * Handles Int16
62 | */
63 | static class SInt16MemberHandler implements MemberHandler {
64 | @Override
65 | /**
66 | * {@inheritDoc}
67 | */
68 | public long getSize() {
69 | return 0x02;
70 | }
71 |
72 | @Override
73 | /**
74 | * {@inheritDoc}
75 | */
76 | public HKXMember createMember(final String name, final HKXType type, final byte[] byteArray) {
77 | HKXDirectMember member4 = new HKXDirectMember<>(name, type);
78 | member4.set((int) ByteUtils.getSInt(byteArray));
79 | return member4;
80 | }
81 |
82 | @SuppressWarnings("unchecked")
83 | @Override
84 | /**
85 | * {@inheritDoc}
86 | */
87 | public byte[] readMember(final HKXMember member) {
88 | HKXDirectMember memberInt16 = (HKXDirectMember) member;
89 | return ByteUtils.fromSLong(memberInt16.get(), 2);
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/core/src/main/java/com/dexesttp/hkxpack/descriptor/HKXEnumResolver.java:
--------------------------------------------------------------------------------
1 | package com.dexesttp.hkxpack.descriptor;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import com.dexesttp.hkxpack.descriptor.reader.ClassXMLReader;
7 | import com.google.common.collect.BiMap;
8 |
9 | /**
10 | * An HKXEnumResolver stores all read enumerations as accessible values.
11 | */
12 | public class HKXEnumResolver {
13 | private final transient Map contents = new HashMap<>();
14 |
15 | /**
16 | * An enumeration extracted from a classXML file.
17 | */
18 | private class HKXEnum {
19 | private final transient BiMap contents;
20 |
21 | HKXEnum(final BiMap contents) {
22 | this.contents = contents;
23 | }
24 |
25 | String get(final int index) {
26 | if (contents.containsValue(index)) {
27 | return contents.inverse().get(index);
28 | }
29 | return Integer.toString(index);
30 | }
31 |
32 | int get(final String enumName) {
33 | if (contents.containsKey(enumName)) {
34 | return contents.get(enumName);
35 | }
36 | try {
37 | return Integer.parseInt(enumName);
38 | } catch (NumberFormatException e) {
39 | return 0;
40 | }
41 | }
42 | }
43 |
44 | /**
45 | * Add a new Enum to the resolver.
46 | *