Below is the code snippet:
I am trying to upload a file having long as a datatype and storing that file size in a byte array.
long fileSize = uploadedFile.getSize();
byte techGuide[] = new byte[fileSize];
I got the build error:
error: incompatible types: possible lossy conversion from long to int
Please suggest what i am missing and what should i try?
Path path = uploadedFile.toPath(); // File.toPath.
Repair of your code:
// Not needed for readAllBytes.
long fileSize = Files.size(path);
if (fileSize > Integer.MAX) {
throw new IllegalArgumentException("File too large");
}
byte[] techGuide = new byte[(int)fileSize];
New code:
byte[] techGuide = Files.readAllBytes(path);
Arrays are limited by their int index. You would need to cast the fileSize to an int (and check an overflow). However Files.readAllBytes does that for you, throwing an OutOfMemoryError of > Integer.MAX - 8.
Related
I'm making a data logging system, just for fun and learning the language. If I want to save a variable ".txt" file with an INT it works fine. Now I bought an RTC and I want the name to be as following: "Data_'DATE&TIME'.txt".
As you can see in the code below, I made a function newFileName what should be doing this, but my output also below is nothing like it. And on the SD card nothing even saves.
The things in comments are things I tried.
int CURRENT_FILE = 1;
String dataString = "";
String currentFileName = "";
String currentTimeStamp = "";
void setDatumTijd(){
t = rtc.getTime();
currentTimeStamp = rtc.getDateStr();
currentTimeStamp += "--";
currentTimeStamp += rtc.getTimeStr();
currentTimeStamp.replace(':', '.');
delay(50);
}
void makeNewFile(String currentTimeStamp){
char fileName[50];
char timeStamp[20];
// sprintf(timeStamp, currentTimeStamp.c_str());
sprintf(fileName, "Data_%d.txt", currentTimeStamp.c_str());
//currentFileName = fileName;
//currentFileName.toCharArray(fileName,50);
//currentTimeStamp += ".txt";
//currentTimeStamp.toCharArray(fileName, (currentTimeStamp.length()+1));
Serial.println(fileName);
currentFileName = fileName;
File dataFile = SD.open(fileName, FILE_WRITE);
saveHeader(currentFileName, currentTimeStamp);
dataFile.close();
}
enter image description here
The library that comes with Arduino doesn't support long filenames, it only supports "8 bytes for filename"."3 bytes for file type", and in your case, it is clearly exceeding that limit.
This all is due to the reason that most of the Arduino boards has lesser RAM.
But if you still want to go ahead, you can use the following library.
https://github.com/greiman/SdFat
This library supports Long File names and if I remember correctly, the Arduino Standard Library is also the wrapper of the library created by the same author.
https://forum.arduino.cc/index.php?topic=58549.msg421288#msg421288
Note: Long File Names consumes much RAM.
The following test fails on Java 9 while passes in Java 8:
#Test
public void getImage_SetValueUsingConstructor_ShouldReturnCorrectValue() throws Exception {
String base64ImageString = "iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAAEUlEQVR42mNgQAP/wQAbBw4ANwsL9Zo6V30AAAAASUVORK5CYII=";
byte[] rawImageBytes = Base64.getDecoder().decode(base64ImageString);
ByteArrayInputStream bis = new ByteArrayInputStream(rawImageBytes);
RenderedImage image = ImageIO.read(bis);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(image, "PNG", bos);
byte[] imageBytesFromImage = bos.toByteArray();
assertArrayEquals(imageBytesFromImage, rawImageBytes);
}
Java 9 output:
arrays first differed at element [42];
Expected :94
Actual :-38
Can anyone help me understand what was changed in Java 9, and is there a way to write this code so that it will work for both Java 8 & 9?
As #Holger has pointed out in the comments, it is really the test that is flawed. While identical Base64 representations will give identical images, different Base64 representations does not mean the image data is different. It could mean only that the same image data is encoded differently, and will decode to the exact same image (which is the case here).
The reason your test used to pass without error, is probably that you used the Java 8 PNGImageWriter (or earlier, it hasn't really changed much since Java 1.4), which is the writer plugin used if you do ImageIO.write(image, "PNG", output), to encode the image and created the Base64 representation from it. If you had created the Base64 representation of the bytes from a file created by a different program/library, it would almost certainly be different.
You should rewrite your test, it is however not really clear to me what you are trying to test here.
If you only care about pixel data, you could just loop over the pixels and test for equality:
BufferedImage original = ImageIO.read(..);
BufferedImage current = ImageIO.read(..);
assertEquals(original.getWidth(), current.getWidth());
assertEquals(original.getHeight(), current.getHeight());
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 0; x < original.getWidth(); x++) {
assertEquals(original.getRGB(x, y), current.getRGB(x, y));
}
}
If you also need the metadata to be preserved, you also need to test for equality there. But PNG doesn't really contain much interesting metadata, so I doubt you need that.
Thanks to Holger for the comments, what I did is to decode an image from the byte array and then compare the dataBuffer of both images.
The test below passed on both Java 8 and
#Test
public void imageTest() throws Exception {
String base64ImageString = "iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAAEUlEQVR42mNgQAP/wQAbBw4ANwsL9Zo6V30AAAAASUVORK5CYII=";
byte[] rawImageBytes = Base64.getDecoder().decode(base64ImageString);
ByteArrayInputStream bis = new ByteArrayInputStream(rawImageBytes);
RenderedImage image = ImageIO.read(bis);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(image, "PNG", bos);
byte[] imageBytesFromImage = bos.toByteArray();
//assertArrayEquals(imageBytesFromImage, rawImageBytes); //fails on Java 9!
bis = new ByteArrayInputStream(imageBytesFromImage);
RenderedImage image2 = ImageIO.read(bis);
DataBuffer dbA = image.getData().getDataBuffer();
int sizeA = dbA.getSize();
DataBuffer dbB = image2.getData().getDataBuffer();
int sizeB = dbB.getSize();
// compare data-buffer objects //
assertEquals(sizeA, sizeB);
for (int i = 0; i < sizeA; i++) {
assertEquals(dbA.getElem(i), dbB.getElem(i));
}
}
The compare images code was taken from: How to compare images for similarity using java
Background
I've been struggling with decrypting an apparently well-formed cipher text for about a day. Assume we've got the following hex-encoded cipher text which contains exactly 160 characters thereby having 80 bytes.
QString c = "1BFAC407AF0D440A2D6176C0B5D125AA96088490299AC18C74623C0EF1BB1372E554FC4150A8066220E943697BE2491D8AE13AA036B298425AC510A8A917D59EBB69708B9040AB3A84C63043EAD4AB07";
QString k = CryptoUtils::hexEncode("abc");
QString p = CryptoUtils::decrypt(c, k);
qDebug() << p;
Provided we're using AES 256, AFAIK, the key must be of length 32 bytes and cipher text of a length of multiple of 16 bytes, which all these consditions are met regarding my snippet code.
Please note that I'm using SHA256 feeding with a pass phrase to generate a 32 bytes key. So, this ensures that all keys are of length 32 bytes.
Full source codes of those function can be found on my repo on GitHub (at branch Part1).
My Question
When I want to run this code, my app crashes. Here's the exception:
terminate called after throwing an instance of 'CryptoPP::InvalidCiphertext'
what(): StreamTransformationFilter: invalid PKCS #7 block padding found
The program has unexpectedly finished.
I searched around about this problem and figured out it could be because of the trailing \0 once you encrypted the plain text. However, I couldn't just solve the problem. Please help me out, it's just driving me crazy.
Full source codes of those function can be found on my repo on GitHub
I'd make these changes at minimum:
QString CryptoUtils::encrypt(QString text, QString keyhex)
{
...
// name the variable, kill the memory leak
SHA256 sha256;
StringSource ss1(decodedKey, size, true, new HashFilter(sha256, new ArraySink(key, AES::MAX_KEYLENGTH)));
...
// name the variable
StringSource ss2(plain, true, new StreamTransformationFilter(Encryptor, new HexEncoder(new StringSink(encrypted))));
// verify embedded NULLs don't affect results
QString qs = QString::fromStdString(encrypted);
assert(qs.length() == encrypted.length());
}
And:
QString CryptoUtils::decrypt(QString text, QString keyhex)
{
// bad karma here...
string encrypted = text.toStdString();
assert(encrypted.length() == text.length());
...
// name the variable, kill the memory leak
SHA256 sha256;
StringSource ss1(decodedKey, size, true, new HashFilter(sha256, new ArraySink(key, AES::MAX_KEYLENGTH)));
...
// name the variable,
StringSource ss2(encrypted, true, new HexDecoder(new StreamTransformationFilter(Decryptor, new StringSink(plain))));
// verify embedded NULLs don't affect results
QString qs = QString::fromStdString(plain);
assert(qs.length() == plain.length());
}
The hexEncode function seems to misbehave:
QString CryptoUtils::hexEncode(QString text)
{
byte *bytearray = (byte *) text.toLatin1().data();
int length = text.toLatin1().length();
return hexEncode(bytearray, length);
}
Should be replaced with:
QString CryptoUtils::hexEncode(QString text)
{
byte *bytearray = (byte *) text.toStdString().data();
int length = text.length();
return hexEncode(bytearray, length);
}
I am attempting to write a png to a SQLite3 database in C#. I have managed to correctly import the external DLL function sqlite3_bind_blob thanks to the answer here. But now I am getting an error when I write the image to my SQLite3 database.
Can you tell me what I am doing wrong? The function function sqlite3_bind_blob is returning the error 21 - SQLITE_MISMATCH 20 - Data type mismatch. I am unsure what exactly is going wrong.
Heres my code:
string query = string.Format("INSERT OR REPLACE INTO myTable(lat, lon, image) VALUES({0}, {1}, ?1);", lat, lon);
if (sqlite3_prepare_v2 (_connection, query, query.Length, out stmHandle, IntPtr.Zero) != SQLITE_OK) {
IntPtr errorMsg = sqlite3_errmsg (_connection);
throw new SqliteException (Marshal.PtrToStringAnsi (errorMsg));
}
IntPtr SQLITE_TRANSIENT = new IntPtr(-1); // Represents SQLITE_TRANSIENT
int res = sqlite3_bind_blob (stmHandle, 1, blob, blob.Length, SQLITE_TRANSIENT);
// res always equals 21
From my debugging I know that the blob correctly contains valid png data because I can write it out to a file and open that file. I also know that the length of the blob is correct aswell. Maybe its my query string INSERT OR REPLACE INTO myTable(lat, lon, image) VALUES({0}, {1}, ?1);?
You are mixing managed with unmanaged code.
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
You are providing managed IntPtr blob instead of unmanaged const void*blob.
You should be very sure about what you're doing when mixing managed with unmanaged code - and it seam you're not...
You may workaround this situation something like this (I don't have compiler right now) using:
unsafe { //this is for C#... probably not needed in C++/CLI
int res = sqlite3_bind_blob (stmHandle, 1, (const void*) blob.ToPointer(), (int) blob.Length, SQLITE_TRANSIENT);
}
Anyways, unless you're pretty sure you need this stuff, I recommend you to go on managed system.data.sqlite and abandon SQLite3 CAPI.
In Dart, I want to read BMP, so could be BIG file.
I do it like this :
var inputStream = imageFile.openInputStream();
inputStream.onData = () {
print(inputStream.available());
inputStream.read(18); // Some headers
int width = _readInt(inputStream.read(4));
int height = _readInt(inputStream.read(4));
// Another stuff ...
}
It works well with little image but when I a read a 3Mo file, the onData is executed many times. Indeed, the onData is trigged by 65536 bytes packets.
What the best practice ?
Should I write a automat with state like HEADER_STATE, COLORS_STATES, ... to set what is my reading state and consider by inputStream.read is a buffer ?
Or I miss a reader class ?
I fear to miss some bytes between 2 packets.
I'm a little disappointed about this, when I do it in java, I just write :
inputStream.read(numberOfBytes);
More easy to use.
Once you have your RandomAccessFile open, you can do something like this:
RandomAccessFile raf; // Initialized elsewhere
int bufferSize = 1024*1024; // 1 MB
int offsetIntoFile = 0;
Uint8List byteBuffer = new Uint8List(bufferSize); // 1 MB
Future<int> bytesReadFuture = raf.readList(byteBuffer, offsetIntoFile, bufferSize);
bytesReadFuture.then((bytesRead) {
Do something with byteBuffer here.
});
There is also a synchronous call readListSync.
John