Files and Folders Listing - ROT decoding

I’m trying to decode an encoded string but my encoding routines generates a really long string. So long in fact, that it causes the program to crash. Runs out of heap memory.

Please help me works this out.

Here is the script:

import java.io.File
if( args.isEmpty()) {
    println("[no args]")
} else {
    println("Args:\n${args.joinToString("\n")}")
}
fun charInt( n: Int ) : Int {
    var intChar = n
    if( intChar > 'z'.toInt()) {
        intChar = 'a'.toInt() + n % ('z'.toInt() - 'a'.toInt())
    }
    return intChar
}
fun encryptString( string: String, n: Int) : String {
    var encryptedString: List<Char>
    encryptedString = string.map( { (charInt(it.toInt() + n)).toChar() } )
    return encryptedString.toString()
}


fun currentFolder(): File {
    return File("").absoluteFile
}
val current = currentFolder()
println("Current folder: ${current.fileNames().joinToString("\n")}")
fun File.contents(): List<File> {
    return this.listFiles().toList()
}
fun File.fileNames(): List<String> {
    return this.files().map { it.name }
}
fun File.folderNames(): List<String> {
    return this.folders().map{ it.name }
}
fun File.folders(): List<File> {
    return this.contents().filter { it.isDirectory }
}
fun File.files(): List<File> {
    return this.contents().filter { it.isFile }
}
fun File.printFolderInfo( progparam: String?) {
    //val arg = args.SecondOrNull { it.startsWith( this.path)}
    // 1
    var displayHidden = false
    if( progparam != null) {
        if( progparam.toString() == "true") {
            displayHidden = true
        }
    }
    println("Contents of '${this.name}':")
    // 2
    if (this.folders().isNotEmpty()) {
        for( i in 0..this.folders().size - 1) {
            if (this.folders()[i].name[0] != '.' || displayHidden) {
                println("- folders:\n    ${this.folderNames().joinToString("\n    ")}")
            }
        }
    }

    // 3
    if( this.files().isNotEmpty()) {
        for (i in 0..this.files().size - 1) {
            if (this.files()[i].name[0] != '.' || displayHidden ) {
                println("- Files:\n    ${this.fileNames().joinToString("\n")}")
            }
        }
    }
    // 4
    println("Parent: ${this.parentFile.name}")
}
current.printFolderInfo(null)

fun valueFromArgsForPrefix( prefix: String) : String? {
    val arg = args.firstOrNull { it.startsWith( prefix)}

    if( arg == null) return null

    val pieces = arg.split("=")
    return if (pieces.size == 2) {
        pieces[1]
    }
    else {
        null
    }
}
val folderPrefix = "folder="
val folderPrefix2 = "hidden="
val folderPrefix3 = "rotation="
val folderValue = valueFromArgsForPrefix(folderPrefix)
val folderValue2 = valueFromArgsForPrefix(folderPrefix2)
val folderValue3 = valueFromArgsForPrefix(folderPrefix3)
var printedDirectoriesEtc = false
if( folderValue != null) {
    val folder = File(folderValue).absoluteFile
    folder.printFolderInfo(null)
    printedDirectoriesEtc = true
} else {
    println("No path provided, printing working directory info")
    currentFolder().printFolderInfo(null)
    printedDirectoriesEtc = true
}
if( folderValue2 != null && printedDirectoriesEtc == false) {
    val folder2 = File(folderValue2).absoluteFile
    folder2.printFolderInfo(folderValue2)
}
val string: String = "hereisastring"
var encodedString: String = ""
if( folderPrefix3 != null) {
    encodedString = encryptString(string, folderValue3!!.toInt())
    var encodedString2 = string
    for( i in 0..folderValue3.toInt()) {
        encodedString2 = encryptString(encodedString2, -1)
    }
    assert( encodedString2 == encodedString)
    // Decode the string using hard way
}
println("$encodedString")

My program is not constructed to deal with counter rotations. I will make the changes.

1 Like

I made the changes and it still doesn’t work. It’s meant to decode the string by looping through all call to the main routine which decoded the string - at the moment it returns a large list of characters no off which appear to be the correct values - the string gets so long that it crashes the program.

That’s a lot of code to look at and understand. If you’re asking other people to look at it, it’s generally better to cut it down to a minimal reproducible example. (Not only does that make it easier for anyone trying to solve your problem, the process of creating it may lead you to the problem, or at least to understanding your program better.)

I haven’t run it myself, but I’ve an idea where the problem is — and it’s something you should be able to find yourself with a bit of debugging (which seems to be a rarely-taught skill). You can use debuggers or various tools, but I always find myself coming down to a simple technique that’s available in almost every language and platform: printing stuff out! Have you tried printing out the values of variables as the program runs? That can give you a good idea of what’s wrong and help you narrow down where it goes astray.

In particular, have you viewed the output of encryptString()? Spoiler alert: it’s probably a lot longer than its argument. Which would easily explain your running out of memory: by calling that repeatedly (as you do at the bottom), it gets exponentially longer.

If I’m right, the cause is the line:

return encryptedString.toString()

encryptedString is a List<Char> — and calling toString() on that works similarly to how it does on every other type of list: it converts each of the elements to a String, separates them with , , and surrounds the lot with []. The resulting string is over 3× longer.

The simplest way to join the characters together without that is probably joinToString(""). (Other ways include calling toCharArray() and then passing that to a String() constructor or calling concatToString().)

2 Likes

Thanks, I was wondering why it was screwing up so badly.