mirror of
https://github.com/revanced/revanced-patcher.git
synced 2025-06-13 05:37:38 +02:00
feat: exclusive mutable access to files
This commit is contained in:
@ -19,31 +19,66 @@ class ResourceData(private val resourceCacheDirectory: File) : Data, Iterable<Fi
|
|||||||
override fun iterator() = resourceCacheDirectory.walkTopDown().iterator()
|
override fun iterator() = resourceCacheDirectory.walkTopDown().iterator()
|
||||||
|
|
||||||
inner class XmlFileHolder {
|
inner class XmlFileHolder {
|
||||||
operator fun get(inputStream: InputStream, outputStream: OutputStream) =
|
operator fun get(inputStream: InputStream) =
|
||||||
DomFileEditor(inputStream, lazyOf(outputStream))
|
DomFileEditor(inputStream)
|
||||||
|
|
||||||
|
operator fun get(path: String): DomFileEditor {
|
||||||
|
return DomFileEditor(this@ResourceData[path])
|
||||||
|
}
|
||||||
|
|
||||||
operator fun get(path: String) = DomFileEditor(this@ResourceData[path])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DomFileEditor is a wrapper for a file that can be edited as a dom document.
|
||||||
|
*
|
||||||
|
* @param inputStream the input stream to read the xml file from.
|
||||||
|
* @param outputStream the output stream to write the xml file to. If null, the file will not be written.
|
||||||
|
*/
|
||||||
class DomFileEditor internal constructor(
|
class DomFileEditor internal constructor(
|
||||||
private val inputStream: InputStream,
|
private val inputStream: InputStream,
|
||||||
private val outputStream: Lazy<OutputStream>,
|
private val outputStream: Lazy<OutputStream>? = null,
|
||||||
) : Closeable {
|
) : Closeable {
|
||||||
|
// path to the xml file to unlock the resource when closing the editor
|
||||||
|
private var filePath: String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The document of the xml file
|
||||||
|
*/
|
||||||
val file: Document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream)
|
val file: Document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream)
|
||||||
.also(Document::normalize)
|
.also(Document::normalize)
|
||||||
|
|
||||||
// lazily open an output stream
|
// lazily open an output stream
|
||||||
// this is required because when constructing a DomFileEditor the output stream is created along with the input stream, which is not allowed
|
// this is required because when constructing a DomFileEditor the output stream is created along with the input stream, which is not allowed
|
||||||
// the workaround is to lazily create the output stream. This way it would be used after the input stream is closed, which happens in the constructor
|
// the workaround is to lazily create the output stream. This way it would be used after the input stream is closed, which happens in the constructor
|
||||||
constructor(file: File) : this(file.inputStream(), lazy { file.outputStream() })
|
constructor(file: File) : this(file.inputStream(), lazy { file.outputStream() }) {
|
||||||
|
filePath = file.path
|
||||||
|
|
||||||
override fun close() {
|
// prevent sharing mutability of the same file between multiple instances of DomFileEditor
|
||||||
val result = StreamResult(outputStream.value)
|
if (locks.contains(filePath))
|
||||||
TransformerFactory.newInstance().newTransformer().transform(DOMSource(file), result)
|
throw IllegalStateException("Can not create a DomFileEditor for that file because it is already locked by another instance of DomFileEditor.")
|
||||||
|
locks.add(filePath!!)
|
||||||
inputStream.close()
|
|
||||||
outputStream.value.close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
inputStream.close()
|
||||||
|
|
||||||
|
// if the output stream is not null, do not close it
|
||||||
|
outputStream?.let {
|
||||||
|
val result = StreamResult(it.value)
|
||||||
|
TransformerFactory.newInstance().newTransformer().transform(DOMSource(file), result)
|
||||||
|
|
||||||
|
it.value.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the lock, if it exists
|
||||||
|
filePath?.let {
|
||||||
|
locks.remove(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
// list of locked file paths
|
||||||
|
val locks = mutableListOf<String>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user