Writing a string to disk without any character conversion in Groovy - jenkins

I have a String object, now because it comes a diff of a folder containing different file types, not everything in it is encoded in the same character set.
The correct codes are in the string, but whenever I try to access the string, groovy tries to be helpful and decode the string, which messes things up.
Now the following seems to do what I need
String decoded_diff = "String that contains codes from different character encodings"
patch_file_name = 'changes.patch'
patch_file = new File(pwd(), patch_file_name)
patch_file.delete()
max_block_size = 1024 * 1024
char[] char_buffer = new char[max_block_size]
block_start = 0
patch_length = decoded_diff.length()
while (true) {
block_size = Math.min(patch_length - block_start, max_block_size)
decoded_diff.getChars(block_start, block_start + block_size, char_buffer, 0)
block_start += block_size
byte[] byte_buffer = new byte[block_size]
for (int i = 0; i < block_size; i++) {
byte_buffer[i] = (int) char_buffer[i]
}
patch_file.append(byte_buffer)
if (block_start == patch_length) break
}
However, it is sloooow
Is there a faster way to achieve the same thing? The final patch file must be identical to the original diff to work. Unfortunately I can't send the file itself (jenkins currently doesn't support file parameters in pipeline jobs) so I have to escape it and send it as part of a json parameter list, hence this painful rigmarole on the receiving end.

Why not:
String decoded_diff = "String that contains codes from different character encodings"
patch_file_name = 'changes.patch'
patch_file = new File(pwd(), patch_file_name)
patch_file.delete()
patchFile.withOutputStream { os ->
os << decoded_diff.bytes
}

Related

Writing a native messaging host in GJS

I'm trying to write a native messaging host for a chrome/firefox extension in GJS (since it will rely on code already written in GJS) but encountering some hurdles. I'm using chrome-gnome-shell as a rough template since it also uses GLib/Gio instrospection and GApplication, but it has the advantage of python struct that I don't have.
Quickly, native messaging hosts exchange messages through stdin/stdout which are an Int32 (4-bytes) length following by a string of utf-8 encoded JSON.
chrome-gnome-shell uses GLib.IOChannel with set_encoding('utf-8') and struct to handle int32 bytes. I've had trouble using that class in GJS and don't have struct so have been trying Gio.UnixInputStream wrapped in Gio.DataInputStream (and output counterparts), with put_int32()/read_int32() and put_string()/read_string().
Apparently I'm mightily confused about what I'm doing. If I call Gio.DataInputStream.read_int32() it returns a number 369098752, so I'm guessing the int32 is not being converted to a regular Number. If I call Gio.DataInputStream.read_bytes(4, null).unref_to_array() to get a ByteArray; ByteArray.toString() returns '\u0016' while ByteArray[0] returns '22' which appears to be the actual length.
Some pointers on reading/writing int32's to a datastream and would be much appreciated.
chrome-gnome-shell references:
on_input()
send_message()
I don't know if this is the best way to solve this, but here's what I came up with.
Two functions using the ByteArray import (modified from somewhere on SO):
const ByteArray = imports.byteArray;
function fromInt32 (byteArray) {
var value = 0;
for (var i = byteArray.length - 1; i >= 0; i--) {
value = (value * 256) + byteArray[i];
}
return value;
};
function toInt32 (num) {
var byteArray = [0, 0, 0, 0];
for (var index_ = 0; index_ < byteArray.length; index_++) {
var byte = num & 0xff;
byteArray [index_] = byte;
num = (num - byte) / 256 ;
}
return ByteArray.fromArray(byteArray);
};
For receiving/sending:
const Gio = imports.gi.Gio;
// Receiving
let stdin = new Gio.DataInputStream({
base_stream: new Gio.UnixInputStream({ fd: 0 })
});
let int32 = stdin.read_bytes(4, null).toArray();
let length = fromInt32(int32);
let data = stdin.read_bytes(length, null).toArray().toString();
let message = JSON.parse(data);
// Sending
let stdout = new Gio.DataOutputStream({
base_stream: new Gio.UnixOutputStream({ fd: 1 })
});
let data = JSON.stringify(message);
let int32 = toInt32(data.length);
stdout.write(int32, null);
stdout.put_string(data, null);
Of course, you should wrap these in try-catch as appropriate and you'll probably want to connect a source to the input (you can use the Gio.UnixInputStream):
let source = stdin.base_stream.create_source(null);
source.set_callback(onReceiveFunc);
source.attach(null);
You may be able to use Gio.DataOutputStream.put_int32() and Gio.DataInputStream.read_int32() the same way as you use read_bytes() and put_string().

retrieving id and incrementing it swift3

I have a id whose format is 1223-3939-ABC.1 and I would like to retrieve the last value i.e. 1 and increment it so now it looks like 1223-3939-ABC.2. But its possible that "1" is not there so in that case, I would like to append ".1"
I am trying to achieve this in Swift and here is my code:
var deviceId: String = "1234-ASCD-SCSDS.1"
if (deviceId != "") {
var id: [String] = deviceId.components(separatedBy: ".")
if let incrementedId: String = id.capacity > 1 ? deviceId.components(separatedBy: ".")[1] : "" {
if (incrementedId == "") {
//should append to id
var firstEle = deviceId.components(separatedBy: ".")[0]
firstEle.append(".")
firstEle.append("1")
deviceId = firstEle
} else {
// retrieve that id, convert to int, increment id, convert back to string and replace the old id with new id
let newId: Int = Int(deviceId.components(separatedBy: ".")[1])! + 1
deviceId = deviceId.replacingOccurrences(of: ".\\d", with: ".\(newId)", options: .regularExpression)
}
}
}
Not sure what I'm doing wrong?
Your regular expression for replacing is .\\d where . is actually any symbol. Replace it with \\.\\d and it will operate as expected.
You are referencing capacity but you need to reference count to understand an amount of components.
Based on documentation:
Capacity – the total number of elements that the array can contain without
allocating new storage.
There are several problems, such as
Wrong usage of capacity (as already said by Nikita),
Your code assumes that there is only a single dot, so that id
has exactly two elements.
Your code will crash if the dot is not followed by an integer.
The main problem is that
deviceId = deviceId.replacingOccurrences(of: ".\\d", with: ".\(newId)", options: .regularExpression)
replaces all occurrences of an arbitrary character followed by
any digit with ".\(newId)". It should probably be
deviceId = id[0] + ".\(newId)"
instead.
But the entire problem can be solved much easier:
Find the last occurrence of a dot.
Check if the part of the string following the dot can be converted to an integer.
If yes, replace that part by the increased integer, otherwise append .1
Both checks can be achieved with conditional binding, so that the
if-block is only executed if the device id already has a trailing
number:
var deviceId = "1234-ASCD-SCSDS.1"
if let pos = deviceId.range(of: ".", options: .backwards),
let id = Int(deviceId.substring(from: pos.upperBound)) {
deviceId = deviceId.substring(to: pos.upperBound) + String(id + 1)
} else {
deviceId = deviceId + ".1"
}
print(deviceId) // 1234-ASCD-SCSDS.2

String formatting in Dart

I was looking up string classes and some other resources, trying to see how to format strings. Primarily, I am trying to Pad out a number to a string, but not precision.
example:
int a = 0, b = 5, c = 15, d = 46;
String aout = "", bout = "", cout="", dout="";
//aout = "00"
//bout = "05"
//cout = "15"
//dout = "46"
When i was looking at int to fixed string precision, it was mostly when dealing with decimals and not prepended padding.
My original thought is that I could do something related to sprintf, such as:
String out = sprintf("%02d", a);
but that didnt seem to work, mostly because It was saying that i am getting a nosuchmethod error. I was not sure if sprintf is in a different package other than core, as i thought this would be related directly to strings.
There's a String.padLeft method you can use:
String out = a.toString().padLeft(2, '0');

How to put variable inside text field AND how to convert all elements to string NOT just 1 at a time?

This is a follow up question to How to have 10 characters total and make sure at least one character from 4 different sets is used randomly
this is my code so far
let sets = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", "1234567890", "\"-/:;()$&#.,?!'[]{}#%^\\|~<>€£¥•.,"].map { Array($0.characters) }
var randoms = sets.map { $0.random }
while randoms.count < 10 {
randoms.append(sets.random.random)
}
var convertedElems = String()
let something = randoms.shuffled()
for key in something {
convertedElems = String(key)
}
uniqueRoomID.text = randoms.shuffled()
Im getting an error saying cannot convert [Element] to type "String"
So i tried a for loop but that only converts 1 at a time when its supposed to do all 10
my other question is i tried storing a character in a variable and then setting a text field.text equal to that variable and nothing happened
What am i doing wrong here
Your randoms.shuffled() is an array of Characters. You need to convert it back into a String.
Change this:
uniqueRoomID.text = randoms.shuffled()
to this:
uniqueRoomID.text = String(randoms.shuffled())

Actionscript ByteArray (from NFC) to String

I'm reading an NFC tag in my Adobe AIR mobile app. The data is read as a ByteArray, but I'm having difficulty pulling the full text. The sample text on the tag is "http://www.google.com"
Using this method, I get a portion of the String "http://www.goog", but not all of it. I'm assuming because each character is not a single byte:
private static function convertToString(byte_array : ByteArray) : String {
var arr : Array = [];
for (var i : Number = 1 ; i <= byte_array.bytesAvailable; i++) {
arr.push(byte_array.readUTFBytes(i));
}
var finalString : String = "";
for (var t : Number = 0; t < arr.length;t++) {
finalString = finalString + arr[t].toString();
}
return finalString;
}
I've also tried the method below, but it returns null:
bytes.readUTF();
I'm wondering if I need to convert the byteArray to a base64 string and then decode that. It seems like an extra step, but that's how I've done it before when sending data to/from a server using AMFPHP.
Thanks in advance for any input.
You could even simplify this code by simply calling
private static function convertToString(bytes:ByteArray):String {
bytes.position = 0;
var str:String = bytes.readUTFBytes(bytes.length);
return str;
}
This way you will read all contents of the bytearray in one single method call into your destination string.
Figured it out in the code below.
There were 2 errors, plus some cleanup:
private static function convertToString(bytes : ByteArray) : String {
bytes.position = 0;
var str : String = '';
while (bytes.bytesAvailable > 0) {
str += bytes.readUTFBytes(1);
}
return str;
}
the "bytesAvailable" property decreases as you read from the ByteArray. Here, I'm checking if the bytes > 0 instead of the length
the "readUTFBytes" method takes a length parameter (not position). Position is automatically updated as you read from the ByteArray. I'm passing in "1" instead of "i"

Resources