fun parseStringCharacters()

in terraform/src/org/intellij/terraform/hcl/psi/impl/HCLStringLiteralTextEscaper.kt [35:176]


    fun parseStringCharacters(chars: String, outChars: StringBuilder, sourceOffsets: IntArray?, interpolations: Boolean): Boolean {
      assert(sourceOffsets == null || sourceOffsets.size == chars.length + 1)

      if (chars.indexOf('\\') < 0) {
        outChars.append(chars)
        if (sourceOffsets != null) for (i in sourceOffsets.indices) {
          sourceOffsets[i] = i
        }
        return true
      }

      var index = 0
      val outOffset = outChars.length
      var braces = 0
      while (index < chars.length) {
        var c = chars[index++]
        if (sourceOffsets != null) {
          sourceOffsets[outChars.length - outOffset] = index - 1
          sourceOffsets[outChars.length + 1 - outOffset] = index
        }

        if (interpolations && braces == 0 && c == '$' && index < chars.length && chars[index] == '{') {
          outChars.append(c)
          c = chars[index++]
          if (sourceOffsets != null) {
            sourceOffsets[outChars.length - outOffset] = index - 1
            sourceOffsets[outChars.length + 1 - outOffset] = index
          }
          outChars.append(c)
          braces++
          continue
        }
        if (braces > 0) {
          if (c == '{') braces++
          else if (c == '}') braces--
          outChars.append(c)
          continue
        }

        if (c != '\\') {
          outChars.append(c)
          continue
        }
        if (index == chars.length) return false
        c = chars[index++]
        when (c) {
          'a' -> outChars.append(0x07.toChar())
          'b' -> outChars.append('\b')
          'f' -> outChars.append(0x0c.toChar())
          'n' -> outChars.append('\n')
          't' -> outChars.append('\t')
          'r' -> outChars.append('\r')
          'v' -> outChars.append(0x0b.toChar())

          '\\' -> outChars.append('\\')
          '"' -> outChars.append('"')

          in '0'..'7' -> {
            // TODO: Consider simplify to just three digits
            val startC = c
            var v = c - '0'
            if (index < chars.length) {
              c = chars[index++]
              if (c in '0'..'7') {
                v = v shl 3
                v += c - '0'
                if (startC <= '3' && index < chars.length) {
                  c = chars[index++]
                  if (c in '0'..'7') {
                    v = v shl 3
                    v += c - '0'
                  } else {
                    index--
                  }
                }
              } else {
                index--
              }
            }
            outChars.append(v.toChar())
          }

          'X' -> {
            if (index + 2 <= chars.length) {
              try {
                val code = Integer.parseInt(chars.substring(index, index + 2), 16)
                //line separators are invalid here
                if (code == 0x000a || code == 0x000d) return false // WTF?
                c = chars[index]
                if (c == '+' || c == '-') return false // WTF?
                outChars.append(code.toChar())
                index += 2
              } catch (e: Exception) {
                return false
              }
            } else {
              return false
            }
          }
          'u' -> {
            if (index + 4 <= chars.length) {
              try {
                val code = Integer.parseInt(chars.substring(index, index + 4), 16)
                //line separators are invalid here
                if (code == 0x000a || code == 0x000d) return false // WTF?
                c = chars[index]
                if (c == '+' || c == '-') return false // WTF?
                outChars.append(code.toChar())
                index += 4
              } catch (e: Exception) {
                return false
              }
            } else {
              return false
            }
          }
          'U' -> {
            if (index + 8 <= chars.length) {
              try {
                val code = java.lang.Long.parseLong(chars.substring(index, index + 8), 16)
                //line separators are invalid here
                if (code == 0x000aL || code == 0x000dL) return false // WTF?
                c = chars[index]
                if (c == '+' || c == '-') return false // WTF?
                outChars.append(code.toInt().toChar())
                index += 8
              } catch (e: Exception) {
                return false
              }
            } else {
              return false
            }
          }

          else -> return false
        }
        if (sourceOffsets != null) {
          sourceOffsets[outChars.length - outOffset] = index
        }
      }
      return true
    }