The support forum is temporarily read-only. For urgent requests, please email contact[at]psyberia.net

Help parse .are to Json

Any question about the app? Ask it here
Post Reply
Vancltkin
Posts: 4
Joined: Fri May 19, 2023 1:53 pm

Help parse .are to Json

Post by Vancltkin »

I'm trying to parse the file according to the 2022.10.14 benefit, but apparently I'll file it at the wrong time. I think either I'm doing something wrong or something has changed
The error lies in the fact that I read the name and add the number of bytes, apparently I'm going to the wrong place
MultiArea file
Type Description
int file magic (3 bytes, 0x50500D) + version (1 byte)
int header size (bytes before {AreaPolygons})
{Metadata} technical metadata
{Metadata} user metadata
{AreaPolygons} polygons

Code: Select all

private fun parseAreDataForFileInfo(dataBuffer: ByteBuffer): LandmarksFile.MultiAreaFile {
        val fileMagic = dataBuffer.int // magicNumber 3byte + version 1byte
        val magicNumber = fileMagic shr 8
        val version = fileMagic and 0xFF

        if (magicNumber != 0x50500D) {
            throw IllegalArgumentException("Invalid magic number for parseAreDataForFileInfo")
        }

        val headerSize = dataBuffer.int
        val positionBeforeAreaPolygons = dataBuffer.position() + headerSize

        val technicalMetadata = parseMetadata(dataBuffer)
        val userMetadata = parseMetadata(dataBuffer)

        dataBuffer.position(positionBeforeAreaPolygons)
        val polygons = parseAreaPolygons(dataBuffer)

        return LandmarksFile.MultiAreaFile(
            fileMagic,
            headerSize,
            technicalMetadata,
            userMetadata,
            //locations,
            polygons
        )
    }

Code: Select all

private fun parseMetadata(dataBuffer: ByteBuffer): LandmarksMetadata {
        val mainContent = parseMetadataContent(dataBuffer)
        val extensions = parseMetadataExtensions(dataBuffer)
        return LandmarksMetadata(mainContent, extensions)
    }

    private fun parseMetadataContent(dataBuffer: ByteBuffer): LandmarksMetadataContent {
        val numberMetadataEntries = dataBuffer.int
        val entries = mutableListOf<LandmarksMetadataContentEntry>()
        if (numberMetadataEntries != -1){

            repeat(numberMetadataEntries) {
                val entry = parseMetadataContentEntry(dataBuffer)
                entries.add(entry)
            }

        }

        val metadataVersion = if (numberMetadataEntries >= 0) dataBuffer.int else null

        return LandmarksMetadataContent(numberMetadataEntries, entries, metadataVersion)
    }

    private fun parseMetadataContentEntry(buffer: ByteBuffer): LandmarksMetadataContentEntry {
        val name = readStringName(buffer)
        val dataLen = buffer.int
        val type: String?
        val data = when (dataLen) {
            -1 -> {
                type = "boolean"
                buffer.get().toInt() != 0

            }
            -2 -> {
                type = "long"
                buffer.long
            }
            -3 -> {
                type = "double"
                buffer.double
            }
            -4 -> {
                type = "raw data"
                val byteArray = ByteArray(dataLen)
                buffer.get(byteArray, 0, dataLen)
                byteArray
            }
            in 0..Int.MAX_VALUE -> {
                type = "string"
                readStringData(buffer, dataLen)
            }

            else -> throw IllegalArgumentException("Invalid data for readMetadataContentEntry")
        }
        val landmarksMetadataContentEntry = when (type) {
            "boolean" -> LandmarksMetadataContentEntry.BooleanLandmarksMetadataContentEntry(
                name,
                type,
                dataLen,
                data as Boolean
            )
            "long" -> LandmarksMetadataContentEntry.LongLandmarksMetadataContentEntry(
                name,
                type,
                dataLen,
                data as Long
            )
            "double" -> LandmarksMetadataContentEntry.DoubleLandmarksMetadataContentEntry(
                name,
                type,
                dataLen,
                data as Double
            )
            "raw data" -> LandmarksMetadataContentEntry.RawLandmarksMetadataContentEntry(
                name,
                type,
                dataLen,
                data as ByteArray
            )
            "string" -> LandmarksMetadataContentEntry.StringLandmarksMetadataContentEntry(
                name,
                type,
                dataLen,
                data as String
            )
            else -> throw IllegalArgumentException("Invalid data type for readMetadataContentEntry")
        }
        return landmarksMetadataContentEntry
    }
    
    private fun parseMetadataExtensions(dataBuffer: ByteBuffer): LandmarksMetadataExtensions {
        val numExtensions = dataBuffer.int
        val metadataExtensions = mutableListOf<LandmarksMetadataExtension>()

        if (numExtensions != -1) {

            repeat(numExtensions) {
                val extension = parseMetadataExtension(dataBuffer)
                metadataExtensions.add(extension)
            }

        }

        return LandmarksMetadataExtensions(numExtensions, metadataExtensions)
    }


    private fun parseMetadataExtension(dataBuffer: ByteBuffer): LandmarksMetadataExtension {
        val extensionName = readStringName(dataBuffer)
        val extensionContent = parseMetadataContent(dataBuffer)

        return LandmarksMetadataExtension(extensionName, extensionContent)
    }

Code: Select all

 private fun readStringName(buffer: ByteBuffer): String {
        val length = buffer.int
        Log.d("MyLog", "length: $length")
        val bytes = ByteArray(length)
        buffer.get(bytes, 0, length)
        return String(bytes, StandardCharsets.UTF_8)
    }

    private fun readStringData(buffer: ByteBuffer, length: Int): String {
        val bytes = ByteArray(length)
        buffer.get(bytes, 0, length)
        return String(bytes, StandardCharsets.UTF_8)
    }

Code: Select all

private fun parseAreaPolygons(dataBuffer: ByteBuffer): AreaPolygons {
        val numberOfPolygons = dataBuffer.int
        val polygons = mutableListOf<AreaPolygon>()

        repeat(numberOfPolygons) {
            val polygon = parseAreaPolygon(dataBuffer)
            polygons.add(polygon)
        }

        return AreaPolygons(numberOfPolygons, polygons)
    }

    private fun parseAreaPolygon(dataBuffer: ByteBuffer): AreaPolygon {
        val metadata = parseMetadata(dataBuffer)
        val locations = parseLocations(dataBuffer)

        val numberOfHoles = dataBuffer.int
        val holes = mutableListOf<Locations>()

        repeat(numberOfHoles) {
            val hole = parseLocations(dataBuffer)
            holes.add(hole)
        }

        return AreaPolygon(metadata, locations, numberOfHoles, holes)
    }
crash occurs after going to parseAreaPolygons ->parseAreaPolygon ->parseMetadata->parseMetadataExtensions ->parseMetadataExtension->readStringName

Attached is the file I am using.
Attachments
0.ldk
(2.5 KiB) Downloaded 376 times
Psyberia-Support
Site Admin
Posts: 6408
Joined: Wed Apr 14, 2010 9:41 pm

Re: Help parse .are to Json

Post by Psyberia-Support »

Hi,
I don't know if this is it, but in "parseMetadata", you must only call "parseMetadataExtensions" if the number of entries of the main metadata content is >=0, and not if the first byte it "-1".
Do you like AlpineQuest ? Leave a small comment on Google Play !
Vancltkin
Posts: 4
Joined: Fri May 19, 2023 1:53 pm

Re: Help parse .are to Json

Post by Vancltkin »

I think I have the same problem and the problem is in another place, I really need help
Vancltkin
Posts: 4
Joined: Fri May 19, 2023 1:53 pm

Re: Help parse .are to Json

Post by Vancltkin »

I am performing an additional check that is not equal to if (numberMetadataEntries != -1). Although the code inside will only be executed if numberMetadataEntries >= 0.
Vancltkin
Posts: 4
Joined: Fri May 19, 2023 1:53 pm

Re: Help parse .are to Json

Post by Vancltkin »

Thanks good work!!

Code: Select all

private fun parseMetadata(dataBuffer: ByteBuffer): LandmarksMetadata {
        val mainContent = parseMetadataContent(dataBuffer)
        var metadataExtensions:LandmarksMetadataExtensions? = null

        if (mainContent.numberMetadataEntries >= 0){
            metadataExtensions = parseMetadataExtensions(dataBuffer)
        }

        return LandmarksMetadata(mainContent, metadataExtensions)
    }
Psyberia-Support
Site Admin
Posts: 6408
Joined: Wed Apr 14, 2010 9:41 pm

Re: Help parse .are to Json

Post by Psyberia-Support »

Ok great!
Do you like AlpineQuest ? Leave a small comment on Google Play !
Post Reply