I need to delete files from the cache of APT and with the functions of files that Vala provides not let me.
Someone who can give me a hand?
The code is the following:
//Compile it using: valac --pkg gtk+-3.0 --pkg glib-2.0 --pkg gio-2.0 del-apt-cache.vala
using Gtk;
using GLib;
private int64[] get_info_and_clean (File file, string space = "", Cancellable? cancellable = null) throws Error
{
int64 files = 0;
int64 size = 0;
int64[] data = new int64[2];
Array<string> paths = new Array<string> ();
FileInfo info = null;
FileEnumerator enumerator;
try {//This Try/Catch is to ignore the permissions of '/var/cache/apt/archives/partial'
enumerator = file.enumerate_children (
"standard::*",
FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
cancellable);
} catch (IOError e) {
stderr.printf ("WARNING: Unable to get size of dir '%s': %s\n", file.get_path (), e.message);
data[0] = 0;
data[1] = 0;
return data;
}
while (cancellable.is_cancelled () == false && ((info = enumerator.next_file (cancellable)) != null)) {
if (info.get_file_type () == FileType.DIRECTORY) {
File subdir = file.resolve_relative_path (info.get_name ());
get_info_and_clean (subdir, space + " ", cancellable);
} else {
files += 1;//Sum Files
size += info.get_size ();//Accumulates Size
paths.append_val (file.get_uri () + "/" + info.get_name ());
}
}
if (cancellable.is_cancelled ()) {
throw new IOError.CANCELLED ("Operation was cancelled");
}
data[0] = files;
data[1] = size;
File apt_file;
for (int i = 0; i < paths.length; i++) {
apt_file = File.new_for_uri (paths.index (i));
stdout.printf ("FILE: %s", paths.index (i));
try {
apt_file.delete ();
stdout.printf (" [DELETED]\n");
} catch (Error e) {
stdout.printf (" [ERROR: %s]\n\n", e.message);
}
}
stdout.printf ("APT CACHE FILES: %s\n", files.to_string());
stdout.printf ("APT CACHE SIZE: %s\n", size.to_string());
return data;
}
public static int main (string[] args) {
Gtk.init (ref args);
File APT_CACHE_PATH = File.new_for_path ("/var/cache/apt/archives");
try {
get_info_and_clean (APT_CACHE_PATH, "", new Cancellable ());
} catch (Error e) {
stdout.printf ("ERROR: %s\n", e.message);
}
Gtk.main ();
return 0;
}
When I run the program, I get the following error:
FILE: file:///var/cache/apt/archives/libdbus-1-3_1.10.6-1ubuntu3_amd64.deb [ERROR: Failed to delete file: Permission denied]
There's nothing Vala can do if the operating system is denying you permission. You need to run your Vala program as root either using sudo or setting the “setuid” bit on the application and changing the owner to root.
Related
is it possible to upload files using Web API to a different directory and not just on the App Root Folder? Either folder on the same server outside App Root Folder or another server.
I need to upload files using Web API to another directory with more space.
public HttpResponseMessage Post()
{
try
{
string mydir = "~/Files/"; //-- APP ROOT FOLDER --//
if (!(Directory.Exists(HttpContext.Current.Server.MapPath(mydir))))
{
Directory.CreateDirectory(HttpContext.Current.Server.MapPath(mydir));
}
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
string filename = string.Concat(GetActualFilename(postedFile.FileName), GetExtension(postedFile.FileName));
var filePath = HttpContext.Current.Server.MapPath(mydir + "/" + filename);
postedFile.SaveAs(filePath);
}
}
else
{
return Request.CreateResponse(HttpStatusCode.OK, "No file attached/processed.");
}
return Request.CreateResponse(HttpStatusCode.Created, "Successfully uploaded file(s).");
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.BadRequest, ex.Message);
}
}
private static string GetActualFilename(string filename)
{
for (int i = filename.Length - 1; i >= 0; i--)
{
if (filename[i] == '.')
{
return filename.Substring(0, i);
}
}
return filename;
}
private static string GetExtension(string filename)
{
for (int i = filename.Length - 1; i >= 0; i--)
{
if (filename[i] == '.')
{
return filename.Substring(i);
}
}
return "";
}
First the problem.
The user can upload file from the web with ajax. If the file is relatively big, the uploading takes a while. If the user's connection is lost or something happens during the uploading process, the file is going to be damaged or empty.
How should I secure the upload process so the file remains the same if it fails for some reason?
I'm using the following libraries on the Arduino ESP32:
ESPAsyncWebServer
LITTLEFS
I have a basic file upload handler on my esp32 which looks like this:
server.on("/uploading", HTTP_POST, [](AsyncWebServerRequest * request) {
}, handleFileUpload);
void handleFileUpload(AsyncWebServerRequest * request, String filename,size_t index, uint8_t *data, size_t len, bool final) {
if (!index) {
if (!filename.startsWith("/"))
filename = "/" + filename;
if (LITTLEFS.exists(filename)) {
LITTLEFS.remove(filename);
}
uploadFile = LITTLEFS.open(filename, "w");
}
for (size_t i = 0; i < len; i++) {
uploadFile.write(data[i]);
}
if (final) {
uploadFile.close();
if(filename == "/myHomeProgram.json"){initProgram = true;}
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "File Uploaded;"+filename);
response->addHeader("Access-Control-Allow-Origin","*");
request->send(response);
}
}
This is working pretty well, the files are uploaded correctly 99% of the cases, but if it fails I lost the file data, or if some other part of the program wants to open the same file it fails too.
Should I write to a temporary file and after if it succeeded write the content to the intended file somehow?
Here is an example from client ( JS ) side:
// Example call:
saveFile(JSON.stringify(places),"/myHomeProgram.json","application/json");
function saveFile(data, filename, type) {
var file = new Blob([data], {type: type});
form = new FormData();
form.append("blob", file, filename);
$.ajax({
url: '/uploading',
type: 'POST',
data: form,
processData: false,
contentType: false
}).done(function(resp){
var response = resp.split(";");
$(".saveIconGraph").removeClass("fas fa-spinner fa-spin");
$(".saveIconGraph").addClass("far fa-save");
if(response[1] == "/myHomeProgram.json"){
toast("success","saveOk","progInfo",3500);
showSaved();
setTimeout(() => {
$("#saveMe").fadeOut( "slow", function() {
showSave();
});
}, 1000);
initPlaces();
}
}).fail(function(resp){
var response = resp.split(";");
$(".saveIconGraph").removeClass("fas fa-spinner fa-spin");
$(".saveIconGraph").addClass("far fa-save");
if(response[1] == "/myHomeProgram.json"){
toast("error","saveNotOk","progInfo",3500);
showSaveError();
$("#saveMeBtn").addClass("shakeEffect");
setTimeout(() => {
$("#saveMeBtn").removeClass("shakeEffect");
showSave();
}, 4500);
}
});
}
I could save the file in a temporary char variable before write, and on the final I could match the size of the file and the temporary variable size and if it is not the same, roll back to the previous. Is this manageable?
Something like this:
String uploadTemp = "";
inline boolean saveFileToTemp(String fileName){
uploadTemp = "";
File f = LITTLEFS.open(fileName, "r");
if (!f) {
f.close();
return false;
}else{
for (int i = 0; i < f.size(); i++){
uploadTemp += (char)f.read();
}
}
f.close();
return true;
}
inline boolean revertBackFile(String fileName){
File g = LITTLEFS.open(fileName, "w");
if (!g) {
g.close();
return false;
}else{
g.print(uploadTemp);
}
g.close();
return true;
}
inline boolean matchFileSizes(String fileName,boolean isFileExists){
boolean isCorrect = false;
if(isFileExists){
File writedFile = LITTLEFS.open(fileName, "w");
if( writedFile.size() == uploadTemp.length()){
isCorrect = true;
}else{
isCorrect = false;
}
writedFile.close();
return isCorrect;
}else{
return true;
}
}
void handleFileUpload(AsyncWebServerRequest * request, String filename,size_t index, uint8_t *data, size_t len, bool final) {
String webResponse;
boolean error = false,isFileExists = false;
if (!index) {
if (!filename.startsWith("/"))
filename = "/" + filename;
if (LITTLEFS.exists(filename)) {
isFileExists = true;
// Save the file to a temporary String if it success we continue.
if( saveFileToTemp(filename) ){
LITTLEFS.remove(filename);
}else{
// If the file save was fail we abort everything.
webResponse = "File NOT Uploaded " + filename;
final = true;
error = true;
}
}
if( !error ){
uploadFile = LITTLEFS.open(filename, "w");
}
}
if( !error ){
// Copy content to the actual file
for (size_t i = 0; i < len; i++) {
uploadFile.write(data[i]);
}
}
if (final) {
uploadFile.close();
if( !error ){
if( matchFileSizes(filename,isFileExists) ){
if(filename == "/myHomeProgram.json"){initProgram = true;}
webResponse = "File Uploaded " + filename;
}else{
error = true;
webResponse = "File length mismatch";
}
}
if( error ){
revertBackFile(filename);
}
Serial.println(webResponse);
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", webResponse);
response->addHeader("Access-Control-Allow-Origin","*");
request->send(response);
}
}
It seems to me that the problem solved.
I have managed to replace the String buffer with a char one in external memory. It seems stable but requires more testing. I'll post the solution but if anyone has a better approach feel free to comment here.
Thanks.
char * uploadTemp;
inline boolean saveFileToTemp(String fileName){
File f = LITTLEFS.open(fileName, "r");
if (!f) {
f.close();
return false;
}else{
size_t fileSize = f.size();
uploadTemp = (char*)ps_malloc(fileSize + 1);
for (int i = 0; i < fileSize; i++){
uploadTemp[i] = (char)f.read();
}
uploadTemp[fileSize] = '\0';
}
f.close();
return true;
}
inline boolean revertBackFile(String fileName){
File g = LITTLEFS.open(fileName, "w");
if (!g) {
g.close();
return false;
}else{
g.print(uploadTemp);
}
g.close();
return true;
}
inline boolean matchFileSizes(String fileName,boolean isFileExists){
boolean isCorrect = false;
if(isFileExists){
File writedFile = LITTLEFS.open(fileName, "w");
if( writedFile.size() == sizeof(uploadTemp)){
isCorrect = true;
}else{
isCorrect = false;
}
writedFile.close();
return isCorrect;
}else{
return true;
}
}
void handleFileUpload(AsyncWebServerRequest * request, String filename,size_t index, uint8_t *data, size_t len, bool final) {
boolean isFileExists = false,error = false;
String webResponse = "";
int httpStatus = 200;
// Start of the file upload
if (!index) {
// Make sure that there is a / char at the start of the string
if (!filename.startsWith("/")){ filename = "/" + filename; }
// Check if the file exists
if (LITTLEFS.exists(filename)) {
isFileExists = true;
// Get the file contents for safety reasons
// If it succeded we can create a new file in the palce
if( saveFileToTemp(filename) ){
uploadFile = LITTLEFS.open(filename, "w");
}else{
// If we can not save it abort the upload process.
webResponse = "File NOT Uploaded " + filename;
final = true;error = true;
}
}
}
// If we have no error at this point, we can start to copy the content to the file.
if( !error ){
for (size_t i = 0; i < len; i++) {
uploadFile.write(data[i]);
}
}
// If no more data we can start responding back to the client
if (final) {
uploadFile.close();
// Check if we got any error before.
if( !error && matchFileSizes(filename,isFileExists) ){
// Copyed file is the same, upload success.
if(filename == "/myHomeProgram.json"){initProgram = true;}
webResponse = "File Uploaded " + filename;
}else{
webResponse = "File length mismatch";
revertBackFile(filename);
httpStatus = 500;
}
free(uploadTemp);
AsyncWebServerResponse *response = request->beginResponse(httpStatus, "text/plain", webResponse);
response->addHeader("Access-Control-Allow-Origin","*");
request->send(response);
}
}
EDIT:
Yeah, so it was completely wrong.
I have to do the following things:
Save the file we want to upload if it exist into a temporary char array.
Get the uploaded file into a temporary file on upload.
If everything was a success, copy the contents of the temporary file to the intended file.
If something fails, revert back the saved file to the original and report an error.
Something like this ( still in test ):
char * prevFileTemp;
inline boolean saveFileToTemp(String fileName){
File f = LITTLEFS.open(fileName, "r");
if (!f) {
f.close();
return false;
}else{
size_t fileSize = f.size();
prevFileTemp = (char*)ps_malloc(fileSize + 1);
for (int i = 0; i < fileSize; i++){
prevFileTemp[i] = (char)f.read();
}
}
f.close();
return true;
}
inline boolean revertBackFile(String fileName){
if (LITTLEFS.exists(fileName)) {
Serial.println("Reverting back the file");
File g = LITTLEFS.open(fileName, "w");
if (!g) {
g.close();
return false;
}else{
g.print(prevFileTemp);
}
g.close();
}
return true;
}
static const inline boolean copyContent(String fileName){
File arrivedFile = LITTLEFS.open(uploadTemp, "r");
File newFile = LITTLEFS.open(fileName, "w");
// Check if we can open the files as intended.
if( !arrivedFile || !newFile){
revertBackFile(fileName);
return false;
}
// Copy one file content to another.
for (size_t i = 0; i < arrivedFile.size(); i++) { newFile.write( (char)arrivedFile.read() ); }
// Check the sizes, if no match, abort mission.
if( newFile.size() != arrivedFile.size()){ return false; }
arrivedFile.close();newFile.close();
return true;
}
boolean isFileExists = false,uploadError = false,newFileArrived = false;
String webResponse = "",newArrivalFileName = "";
int httpStatus = 200;
inline void resetVariables(){
isFileExists = false;
uploadError = false;
webResponse = "";
httpStatus = 200;
}
void handleFileUpload(AsyncWebServerRequest * request, String filename,size_t index, uint8_t *data, size_t len, bool final) {
// Start file upload process
if (!index) {
// Reset all the variables
resetVariables();
// Make sure that there is a '/' char at the start of the string
if (!filename.startsWith("/")){ filename = "/" + filename; }
// Open the temporary file for content copy if it is exist
if (LITTLEFS.exists(filename)) {
if( saveFileToTemp(filename) ){
uploadFile = LITTLEFS.open(uploadTemp, "w");
}else{
// If we can not save it abort the upload process.
webResponse = "File NOT Uploaded " + filename;
final = true;uploadError = true;
}
}
}
// If we have no error at this point, we can start to copy the content to the temporary file.
if( !uploadError ){
for (size_t i = 0; i < len; i++) {
uploadFile.write(data[i]);
}
}
// If no more data we can start responding back to the client
if (final) {
if (!filename.startsWith("/")){ filename = "/" + filename; }
uploadFile.close();
if( !uploadError && copyContent(filename) ){
webResponse = "File Uploaded " + filename;
}else{
webResponse = "File length mismatch";
revertBackFile(filename);
httpStatus = 500;
}
free(prevFileTemp);
AsyncWebServerResponse *response = request->beginResponse(httpStatus, "text/plain", webResponse);
response->addHeader("Access-Control-Allow-Origin","*");
request->send(response);
}
}
I am trying to monitor the ~/.local directory according to the Vala documentation I can monitor the home correctly. but I can't monitor the the ~/.local.
initFileMonitor V1:
public void initFileMonitor(){
try {
string homePath = Environment.get_home_dir();
string filePath = homePath + "/.local";
File file = File.new_for_path(filePath);
FileMonitor monitor = file.monitor_directory(FileMonitorFlags.NONE, null);
print ("\nMonitoring: %s\n", file.get_path ());
monitor.changed.connect ((src, dest, event) => {
if (dest != null) {
print ("%s: %s, %s\n", event.to_string (), src.get_path (), dest.get_path ());
} else {
print ("%s: %s\n", event.to_string (), src.get_path ());
}
});
} catch (Error err) {
print ("Error: %s\n", err.message);
}
}
terminal output(no error, no monitoring):
Monitoring: /home/srdr/.local
Because the file monitor is stored in a local variable it is like other variables destroyed (or in GObject terms finalised/destructed) at the end of the function call
To ensure it lives long enough you should make it a field on a class, then the FileMonitor instance is 'owned' by an instance of that class rather than each call to a specific method
Runnable demo (valac demo.vala --pkg gio-2.0)
class FileMonitorDemo {
private FileMonitor monitor;
public void initFileMonitor() {
var path = Path.build_filename(Environment.get_home_dir(), ".local");
var file = File.new_for_path(path);
try {
monitor = file.monitor_directory(NONE);
message ("Monitoring: %s", file.get_path ());
monitor.changed.connect ((src, dest, event) => {
if (dest != null) {
print ("%s: %s, %s\n", event.to_string (), src.get_path (), dest.get_path ());
} else {
print ("%s: %s\n", event.to_string (), src.get_path ());
}
});
} catch (Error err) {
critical ("Error: %s\n", err.message);
}
}
}
void main () {
var filemon = new FileMonitorDemo();
filemon.initFileMonitor();
new MainLoop ().run ();
}
You need to actually run the monitor by creating a main loop and having it wait for events:
new MainLoop ().run ();
I have been using Spring's multipart uploader controllers to upload and store entries from zipped files, but I am finding that the occaisional PNG file being corrupted, where instead of begginning with something like "PNG..." in its byte[], it starts with "fþ»ÀÃgÞÉ" or similar. This seems to happen to the same files on each run. I tried all of this using java.util.ZipEntry and then I tried Apache Compress and found that Apache compress corrupted different files to the Java 7 utility, but always the same files on subsequent runs.
The code (firstly java.util.zip.ZipEntry):
protected void processZipFile(String path, MultipartFile file, String signature) throws IOException {
DateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");
File tempFile = new File(System.getProperty("user.dir") + "/" + file.getName() + df.format(new Date()));
file.transferTo(tempFile);
ZipFile zipFile = null;
try {
zipFile = new ZipFile(tempFile);
LOG.debug("Processing archive with name={}, size={}.", file.getName(), file.getSize());
final Enumeration<? extends ZipEntry> entries = zipFile.entries();
while ( entries.hasMoreElements() )
{
ZipEntry entry = entries.nextElement();
LOG.debug("Processing file={} is directory?={}.", entry.getName(), entry.isDirectory());
// we don't bother processing directories, and we don't process any resource fork info
// from Mac OS X (which does not seem to be transparent to ZipFile).
if (!(entry.isDirectory() || entry.getName().contains("__MACOSX") || entry.getName().contains(".DS_Store"))) {
// if the entry is a file, extract it
Content contentToSave = null;
if(entry.getName().contains("gif") || entry.getName().contains("png") || entry.getName().contains("jpeg")) {
byte[] bytes = readInputStream( zipFile.getInputStream( entry ), entry.getSize() );
LOG.debug("{} is of inflated-length={} from compressed-length={}",
entry.getName(), bytes.length, entry.getCompressedSize());
if(entry.getName().contains("gif")) {
contentToSave = Content.makeImage(path + entry.getName(), Content.GIF, signature, bytes);
} else if (entry.getName().contains("png")) {
contentToSave = Content.makeImage(path + entry.getName(), Content.PNG, signature, bytes);
} else if (entry.getName().contains("jpeg")) {
contentToSave = Content.makeImage(path + entry.getName(), Content.JPEG, signature, bytes);
}
} else {
InputStream is = zipFile.getInputStream(entry);
if (entry.getName().contains("json")) {
contentToSave = Content.makeFile(path + entry.getName(), Content.JSON, signature, convertStreamToString(is));
} else if (entry.getName().contains("js")) {
contentToSave = Content.makeFile(path + entry.getName(), Content.JS, signature, convertStreamToString(is));
} else if (entry.getName().contains("css")) {
contentToSave = Content.makeFile(path + entry.getName(), Content.CSS, signature, convertStreamToString(is));
} else if (entry.getName().contains("xml")) {
contentToSave = Content.makeFile(path + entry.getName(), Content.XML, signature, convertStreamToString(is));
} else if (entry.getName().contains("html")) {
contentToSave = Content.makeFile(path + entry.getName(), Content.HTML, signature, convertStreamToString(is));
}
}
contentService.putOrReplace(contentToSave);
LOG.info("Persisted file: {} from uploaded version.", contentToSave.getName());
}
}
} catch (ZipException e) {
// If I can't create a ZipFile, then this is not a zip file at all and it cannot be processed
// by this method. Its pretty dumb that there's no way to determine whether the contents are zipped through
// the ZipFile API, but that's just one of its many problems.
e.printStackTrace();
LOG.error("{} is not a zipped file, or it is empty", file.getName());
} finally {
zipFile = null;
}
tempFile.delete();
}
And now the same thing for org.apache.commons.compress.archivers.zip.ZipFile:
protected void processZipFile(String path, MultipartFile file, String signature) throws IOException {
DateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");
File tempFile = new File(System.getProperty("user.dir") + "/" + file.getName() + df.format(new Date()));
file.transferTo(tempFile);
ZipFile zipFile = null;
try {
zipFile = new ZipFile(tempFile);
LOG.debug("Processing archive with name={}, size={}.", file.getName(), file.getSize());
final Enumeration<? extends ZipArchiveEntry> entries = zipFile.getEntries();
while ( entries.hasMoreElements() ) {
ZipArchiveEntry entry = entries.nextElement();
LOG.debug("Processing file={} is directory?={}.", entry.getName(), entry.isDirectory());
// we don't bother processing directories, and we don't process any resource fork info
// from Mac OS X (which does not seem to be transparent to ZipFile).
if (!(entry.isDirectory() || entry.getName().contains("__MACOSX") || entry.getName().contains(".DS_Store"))) {
// if the entry is a file, extract it
Content contentToSave = null;
if(entry.getName().contains("gif") || entry.getName().contains("png") || entry.getName().contains("jpeg")) {
byte[] bytes = readInputStream( zipFile.getInputStream( entry ), entry.getSize() );
LOG.debug("{} is of inflated-length={} from compressed-length={}",
entry.getName(), bytes.length, entry.getCompressedSize());
if(entry.getName().contains("gif")) {
contentToSave = Content.makeImage(path + entry.getName(), Content.GIF, signature, bytes);
} else if (entry.getName().contains("png")) {
contentToSave = Content.makeImage(path + entry.getName(), Content.PNG, signature, bytes);
} else if (entry.getName().contains("jpeg")) {
contentToSave = Content.makeImage(path + entry.getName(), Content.JPEG, signature, bytes);
}
} else {
InputStream is = zipFile.getInputStream(entry);
if (entry.getName().contains("json")) {
contentToSave = Content.makeFile(path + entry.getName(), Content.JSON, signature, convertStreamToString(is));
} else if (entry.getName().contains("js")) {
contentToSave = Content.makeFile(path + entry.getName(), Content.JS, signature, convertStreamToString(is));
} else if (entry.getName().contains("css")) {
contentToSave = Content.makeFile(path + entry.getName(), Content.CSS, signature, convertStreamToString(is));
} else if (entry.getName().contains("xml")) {
contentToSave = Content.makeFile(path + entry.getName(), Content.XML, signature, convertStreamToString(is));
} else if (entry.getName().contains("html")) {
contentToSave = Content.makeFile(path + entry.getName(), Content.HTML, signature, convertStreamToString(is));
}
}
contentService.putOrReplace(contentToSave);
LOG.info("Persisted file: {} from uploaded version.", contentToSave.getName());
}
}
} catch (ZipException e) {
e.printStackTrace();
LOG.error("{} is not a zipped file, or it is empty", file.getName());
} catch (IOException e) {
e.printStackTrace();
LOG.error("{} is not a file, or it is empty", file.getName());
} finally {
zipFile = null;
}
tempFile.delete();
}
The two called methods are:
private static byte[] readInputStream( final InputStream is, final long length ) throws IOException {
final byte[] buf = new byte[ (int) length ];
int read = 0;
int cntRead;
while ( ( cntRead = is.read( buf, 0, buf.length ) ) >=0 )
{
read += cntRead;
}
return buf;
}
and:
public String convertStreamToString(InputStream is) throws IOException {
StringBuilder sb = new StringBuilder(2048);
char[] read = new char[128];
try (InputStreamReader ir = new InputStreamReader(is, StandardCharsets.UTF_8)) {
for (int i; -1 != (i = ir.read(read)); sb.append(read, 0, i));
}
// need to remove the ? at teh beginning of some files. This comes from the UTF8 BOM
// that is added to some files saved as UTF8
String out = sb.toString();
String utf8Bom = new String(new char[]{'\ufeff'});
if(out.contains(utf8Bom)) {
out = out.replace(utf8Bom,"");
}
return out;
}
The second one is, of course, not likely part of the problem.
I have googled around and it looks like issues similar to this have been found, but its always been some outside issue. Does anyone know why this might be the case?
I have re-edited some images and found that if I change the image to black and white, or change the hue of the whole image, the problem goes away, but if I add a border or change a single colour the problem remains. It looks like a particular arrangement of bytes in some files tickles a bug in whatever underlying API that both Java's own and Apache's compressed file readers use, but that's just speculation.
EDIT: additional usage shows that the corruption happens in gifs over 10K in size, so perhaps this has something to do with the bug? I have tried arbitrarily doubling the size of the buffer in the call to ReadInputStream(), but it did nothing except overflow the blob size in MySQL in particularly large images (49K became 98K, which was too big).
com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'encoded_content' at row 1
My finding is that this issue arise when the 'packed size' is larger that the actual size, this can happen with png files for example which are already 'zipped' them selves.
I am receiving an odd error with my scanner integration. I am making use of an OPOS scanner in my program. When the program closes I disable, release and close the device, but no other application can use it after my program runs. Also if I restart no application can use it. Not even my application which causes the issue. I did find that if I do not claim the device the issue doesn't happen. I am currently trying to get a fresh copy of the DLL in case the release method is somehow corrupted? Any other ideas?
public bool InitBarcode(bool overrideLGBarcode)
{
Util.LogMessage("Initializing barcode scanner!");
if (_barcodeScanner == null)
{
Util.LogMessage("Barcode scanner was null. instantiating a new one");
_barcodeScanner = new OPOSScanner();
_barcodeScanner.AutoDisable = true;
_barcodeScanner.DataEvent += BarcodeDataEventHandler;
Util.LogMessage("Added event handler");
}
else
{
Util.LogMessage("Barcode scanner was not null");
}
if (_barcodeScanner.Open("STI_USBSCANNER") != 0)
{
Util.LogMessage("Barcode scanner \"STI_USBSCANNER\" could not be opened!");
return false;
}
else
{
Util.LogMessage("STI_USBSCANNER was opened");
}
int result = _barcodeScanner.ClaimDevice(-1);
Util.LogMessage("Claiming barcode scanner returned result: " + result);
_barcodeScanner.DecodeData = true;
_barcodeScanner.DeviceEnabled = true;
_barcodeScanner.DataEventEnabled = true;
return true;
}
public void CloseBarcode()
{
Util.LogMessage("Disabling, Releasing and Closing the barcode scanner!");
_barcodeScanner.DataEvent -= BarcodeDataEventHandler;
Util.LogMessage("Removed event handler");
_barcodeScanner.AutoDisable = false;
_barcodeScanner.DecodeData = false;
_barcodeScanner.DataEventEnabled = false;
_barcodeScanner.DeviceEnabled = false;
if (_barcodeScanner.DeviceEnabled != false)
{
Util.LogMessage("Barcode scanner could not be disabled!");
}
else
{
Util.LogMessage("Barcode scanner was disabled!");
}
int result = _barcodeScanner.ReleaseDevice();
Util.LogMessage("ReleseDevice() yielded result of: " + result);
if (result != 0)
{
Util.LogMessage("Barcode scanner could not be released!");
}
else
{
Util.LogMessage("Barcode scanner was released!");
}
if (_barcodeScanner.Close() != 0)
{
Util.LogMessage("Barcode scanner could not be closed!");
}
else
{
Util.LogMessage("Barcode scanner was closed!");
}
_barcodeScanner = null;
}