txtStatus.Text = "";
if (!File.Exists(txtOpenLocation.Text))
{
txtStatus.Text = "File Not Found";
return;
}
txtStatus.Text = "File Found";
const string DLL_32BITS = "gsdll32.dll";
const string DLL_64BITS = "gsdll64.dll";
//select DLL based on arch
string NomeGhostscriptDLL;
if (Environment.Is64BitProcess)
{
NomeGhostscriptDLL = DLL_64BITS;
}
else
{
NomeGhostscriptDLL = DLL_32BITS;
}
GhostscriptVersionInfo gvi = new GhostscriptVersionInfo(NomeGhostscriptDLL);
var rasterizer = new GhostscriptRasterizer();
try
{
rasterizer.Open(txtOpenLocation.Text, gvi, true);
Console.WriteLine(rasterizer.PageCount); //This line always prints 0
} catch(Exception er)
{
txtStatus.AppendText("\r\nUnable to Load the File: "+ er.ToString());
return;
}
I have googled on it, but got no solution, and no helpful documentation about the rasterizer.Open() function.
The Console.WriteLine(rasterizer.PageCount); always prints 0, regardless which pdf file I load.
txtStatusis a multiline TextBox in UI. txtOpenLocation is another TextBox in UI, non-editable by user, and its value is set by a OpenFileDialog.
I am using Visual Studio 2019 Community Edition.
Another observation I feel worth mentioning— for every pdf file on my machine, when I try to open any pdf file with either Adobe Acrobat DC or Foxit Reader, first the reader crashes, becomes 'not responsive' for about 10 to 15 seconds and then it opens the pdf file.
I had the same problem yesterday, I downloaded version 9.26 from here https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs926/gs926aw32.exe, and works!
I think this is a bug of ghostscript 9.27 release.
This isn't a bug at all, I suspect, (I certainly do not believe its a Ghostscript bug) but its probably a change in behaviour. Due to reported security vulnerabilities the Ghostscript developers have been removing access to many non-standard PostScript extensions (unique to Ghostscript). Most recently access to the dictionary for processing PDF files has been secured.
My suspicion is that Ghostscript.NET (which is not maintained by the Ghostscript developers) is using one or more non-standard extensions to do the work of retrieving the count of pages. Without knowing what exactly is being used currently I can't be sure of course.
If the developer of Ghostscript.NET would like to contact us and confirm this is the problem then we can discuss the currently supported method for retrieving the count of pages in a PDF file.
It won't help at all to send me a project using Ghostscript.NET, since I don't know anything about it. I'm also not a C# or .NET developer, so the code would likely be meaningless to me.
Ghostscript returns considerable information on the back channel, stdout and/or stderr. These can be redirected to an application-defined data sink. I imagine that Ghostscript.NET will give you some means to retrieve these and if you plan to do any real development involving Ghostscript then I would very strongly reccomend that you find out how to get this information.
When you say 'no error is thrown from Ghostscript' I think you may be confusing Ghostscript and Ghostscript.NET. Without seeing the back channel from Ghostscript I don't see how you can tell if Ghostscript is generating an error.
NB if you plan to distribute your application you must abide by the terms of the AGPL version 3 (which is the license applying to Ghostscript), and that includes shipping a copy of the license, and some means for informing users where they can get the original.
As with the OP and the primary answer to this question, I too encountered this exact issue just yesterday.
I just want to add that for me the suggested version of ghostscript (9.26) wasn't working. It complained that I should be using a 64 bit version.
For those who need that, it's here: https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs926/gs926aw64.exe
I had to just guess at the URL. I'm amazed at how difficult it has been to find older versions.
This issue has been fixed in the latest release v.1.2.2 of GhostScript.NET
The fix was to stop using pdfdict and GS_PDF_ProcSet if the version was over 9.26 as these two functions were made private by the Ghostscript team for security reasons.
I am not very familiar with GhostScript or PostScript, however, I have traced down the issue within the GhostScript.NET code, which uses the gsapi to execute functions. The function that is being executed and failing on gs is within file GhostscriptViewerPdfFormatHandler.cs on the GhostScript.NET Project.
Upon further testing through using both a gs9.26 as recommended by Oswaldo Cotes Solano and comparing the results with gs9.52 using a test script, I have found that GS_PDF_ProcSet is causing a Unrecoverable error, exit code 1 on gs 9.52.
This leads to failure while using the gs9.52 API, however, it is by design since gs9.27 to add security. While -dNOSAFER is not recommended for production ready applications, it will get us by.
An example of the intended execution and result that works in gs9.26 should be similar to:
gswin32c.exe -q -dNOSAFER -sPDFname=c:/pdfs/test.pdf c:/pdfs/pdfpagecount.ps
Executing:
/GSNETViewer_PDFpage {
(%GSNET_VIEWER_PDF_PAGE: ) print dup == flush
pdfgetpage /Page exch store
Page /MediaBox pget
{ (%GSNET_VIEWER_PDF_MEDIA: ) print == flush }
if
Page /CropBox pget
{ (%GSNET_VIEWER_PDF_CROP: ) print == flush }
if
Page /Rotate pget not { 0 } if
(%GSNET_VIEWER_PDF_ROTATE: ) print == flush
} def
Executing:
/Page null def
/Page# 0 def
/PDFSave null def
/DSCPageCount 0 def
Executing:
GS_PDF_ProcSet begin
pdfdict begin
Executing: (C:/pdfs/Output.pdf) (r) file runpdfbegin
Executing: /FirstPage where { pop FirstPage } { 1 } ifelse
Executing: /LastPage where { pop LastPage } { pdfpagecount } ifelse
Executing: flush (%GSNET_VIEWER_PDF_PAGES: ) print exch =only ( ) print =only (
) print flush
%GSNET_VIEWER_PDF_PAGES: 1 1
Executing: process_trailer_attrs
Executing: 1 GSNETViewer_PDFpage
%GSNET_VIEWER_PDF_PAGE: 1
%GSNET_VIEWER_PDF_MEDIA: [0.0 0.0 612.0 792.0]
%GSNET_VIEWER_PDF_CROP: [0.0 0.0 612.0 792.0]
%GSNET_VIEWER_PDF_ROTATE: 0
Executing: Page pdfshowpage_init pdfshowpage_finish
Loading NimbusSans-Regular font from %rom%Resource/Font/NimbusSans-Regular... 4124032 2548352 5183568 3818848 3 done.
showpage, press <return> to continue
While running 2.52 with -dNOSAFER and also adding the -dNOSAFER argument to CLI to avoid the file access error, and the GhostScript.NET source to allow for the same functionality. Although the -dNOSAFER option is not the ideal choice and may have vulnerabilities, to test without diving further in, I've used this method for testing.
C:\Program Files\gs\-\bin>gswin64c.exe -q -dNOSAFER -sPDFname=test.pdf c:/pdfs/pdfpagecount.ps
Error: /undefined in GS_PDF_ProcSet
Operand stack:
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- false 1 %stopped_push 1990 1 3 %oparray_pop 1989 1 3 %oparray_pop 1977 1 3 %oparray_pop 1833 1 3 %oparray_pop --nostringval-- %errorexec_pop .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval--
Dictionary stack:
--dict:738/1123(ro)(G)-- --dict:0/20(G)-- --dict:84/200(L)--
Current allocation mode is local
Current file position is 992
GPL Ghostscript 9.52: Unrecoverable error, exit code 1
Ultimately making a minor change 3 locations of the source has resulted in a working solution with 9.52. I'll do a pull-request with our changes and update the community when a pull request has been issued, otherwise, you can make a pull directly to our fork.
I've had the same problem. I was using c# (.NET) Ghostscript.NET (version 1.2.3). Problem was PDF file name. If it had parenthesis ) or (, then that problem occurs.
I had to rename PDF file in order to escape those characters.
using Ghostscript.NET.Rasterizer;
var strFilePath = "C:\PdfFile(.pdf";
using (var rasterizer = new GhostscriptRasterizer())
{
rasterizer.Open(strFilePath);
var strPageCount = rasterizer.PageCount; //return 0
}
var pattern = "[^A-Za-z0-9 .-]+";
var regEx = new Regex(pattern);
strFilePath = regEx.Replace(strFilePath, "");
using (var rasterizer = new GhostscriptRasterizer())
{
rasterizer.Open(strFilePath);
var strPageCount1 = rasterizer.PageCount; //return number of pages
}
Related
So I am trying to write a cd -like program that can be executed using cmd and after it exits the working directory of the calling cmd process should be changed.
Now before this post is flagged as a duplicate: I am aware of this and this question that were asked for pretty much this exact problem but using Linux instead of Windows as well as being pretty broad and unspecific, and I am aware that similar limitations apply to Windows as well (changing the working directory of my process will not change the parent’s working directory).
There is actually is a working solution to this for linux. However it is using gdb for this, and I would like to achieve this task using only built-in Windows utilities (WinAPI, dotNET, etc.).
What I have tried so far
I did manage to use Cheat Engine and the OpenProcess() / WriteProcessMemory() WinAPI funtions to successfully override cmd's working directory. However this solution feels sloppy and doesn't work well (or at least requires more work to be put into.)
My question
Is there a different (maybe simpler?) way on Windows to achieve this? Like a way to invoke/inject code to the cmd process to execute cd whatever\directory\I\want directly without overriding its memory? I have seen the CreateRemoteThread() functions however I didn't manage to find a way to put them to use.
FYI: I am mainly using C# but C/C++ solutions should help too as long as they are based on the native Microsoft libraries.
This post describes a Windows implementation of a function that launches a child process, creates pipes to stdin and stdout from which a command is sent, and a response is returned. Finally, once all response is captured the child process is terminated. If this sounds familiar it is similar in concept to Linux's popen() function with the exception that this implementation was specifically created to capture the response into a buffer of any command that returns one. (Also included is a variant for use when no-response is expected or needed.)
The full source can be adapted for use within a standalone executable, or as an API. (.dll) Either way, the resulting functions accept and process any command using standard Windows CMD syntax. The function cmd_rsp(...) returns the Windows response via stdout into a self-sizing buffer.
The exported prototypes are:
int __declspec(dllexport) cmd_rsp(const char *command, char **chunk, unsigned int size);
int __declspec(dllexport) cmd_no_rsp(const char *command);
A simple use case when capturing a response:
#include "cmd_rsp.h"
int main(void)
{
char *buf = {0};
buf = calloc(100, 1);//initialize to some initial size
if(!buf)return 0;
cmd_rsp("dir /s", &buf, 100);//buffer will grow to accommodate response as needed.
printf("%s", buf);
free(buf);
return 0;
}
A simple use case when response is not needed:
#include "cmd_rsp.h"
int main(void)
{
cmd_no_rsp("cd C:\\dir1\\dir2");
return 0;
}
A detailed description of purpose and usage is described in the link provided above. To illustrate, here are a few sample command inputs, each in this case change the working directory, then execute a command from that directory:
A command to change to sqlite directory, then execute a query:
cd c:\\tempExtract\\sqlite\\Tools\\sqlite-tools-win32-x86-3250300 && sqlite3.exe .\\extract.db \"select * from event, eventdata where eventType=38 and eventdata .eventid=event.eventid\
A command to change to teraterm directory, then execute a script:
"c:\\Program Files (x86)\\teraterm\" && ttpmacro c:\\DevPhys\\LPCR_2\\play\\Play.ttl
A command to change directory then execute a command to send multiple digital acquisition channel settings.
cd C:\\Dir1\\Dir2\\Dir3\\support\\Exes\\WriteDigChannel && .\\WriteDigChannel.exe P1_CH0 1 && .\\WriteDigChannel.exe P1_C H0 0 && .\\WriteDigChannel.exe P1_CH0 1
A recursive directory search from a specified location:
cd C:\\dir1\\dir2 && dir /s /b
I got it working. As was suggested SendInput finally did the trick.
I used a combination of WinAPI calls to GetForegroundWindow() / SetForegroundWindow() and the Windows Forms System.Windows.Forms.SendKeys.SendWait() Method to achieve what I wanted:
Upon calling my cd-wrapper program (sd.exe) and providing my custom target directory (~/ home) it generates the corresponding command along with the "Enter-Pressed-Event" to be sent to it's parent cmd process.
Here's the complete C# code:
if (args.Length != 1)
{
Console.WriteLine(Directory.GetCurrentDirectory());
return;
}
string targetDirectory = args[0];
string command = string.Empty;
if (targetDirectory.Equals("~"))
{
command = #"pushd C:\Users\fred\Desktop";
}
else if (!Directory.Exists(targetDirectory))
{
Console.WriteLine("I/O Error: No such file or directory.");
return;
}
else
{
command = #"cd " + targetDirectory;
}
Target target = Target.Create(Process.GetCurrentProcess().GetParentProcess());
target.SendKeys(command + "{ENTER}", true);
Note that I kind of started to write a complete Framework for this and similar problems alongside this project that contains all my different approaches to this question and the low level WinAPI calls as well as the Extension methods to get the parent process :D
As it would be a bit overkill to paste all of it's code in this answer, here's the GitHub. If I can find the time I'll go ahead and optimize the code, but for now this'll do. Hope this helps anyone encountering a similar problem :)
Edit:
An even "cleaner" way is to use dll injection to directly make cmd switch it's working directory. While it is a lot harder to get working it has the advantage of not littering the cmd command history as compared to the approach described above. In addition to that cmd seems to be aware of any changes to it's current working directory, so it automatically updates the prompt text. Once I have a fully working example, that allows to dynamically specify the target directory I will post it here :)
I am trying to run a process on a web page that will return its output in realtime. For example if I run 'ping' process it should update my page every time it returns a new line (right now, when I use exec(command, output) I am forced to use -c option and wait until process finishes to see the output on my web page). Is it possible to do this in php?
I am also wondering what is a correct way to kill this kind of process when someone is leaving the page. In case of 'ping' process I am still able to see the process running in the system monitor (what makes sense).
This worked for me:
$cmd = "ping 127.0.0.1";
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
flush();
$process = proc_open($cmd, $descriptorspec, $pipes, realpath('./'), array());
echo "<pre>";
if (is_resource($process)) {
while ($s = fgets($pipes[1])) {
print $s;
flush();
}
}
echo "</pre>";
This is a nice way to show real time output of your shell commands:
<?php
header("Content-type: text/plain");
// tell php to automatically flush after every output
// including lines of output produced by shell commands
disable_ob();
$command = 'rsync -avz /your/directory1 /your/directory2';
system($command);
You will need this function to prevent output buffering:
function disable_ob() {
// Turn off output buffering
ini_set('output_buffering', 'off');
// Turn off PHP output compression
ini_set('zlib.output_compression', false);
// Implicitly flush the buffer(s)
ini_set('implicit_flush', true);
ob_implicit_flush(true);
// Clear, and turn off output buffering
while (ob_get_level() > 0) {
// Get the curent level
$level = ob_get_level();
// End the buffering
ob_end_clean();
// If the current level has not changed, abort
if (ob_get_level() == $level) break;
}
// Disable apache output buffering/compression
if (function_exists('apache_setenv')) {
apache_setenv('no-gzip', '1');
apache_setenv('dont-vary', '1');
}
}
It doesn't work on every server I have tried it on though, I wish I could offer advice on what to look for in your php configuration to determine whether or not you should pull your hair out trying to get this type of behavior to work on your server! Anyone else know?
Here's a dummy example in plain PHP:
<?php
header("Content-type: text/plain");
disable_ob();
for($i=0;$i<10;$i++)
{
echo $i . "\n";
usleep(300000);
}
I hope this helps others who have googled their way here.
Checked all answers, nothing works...
Found solution Here
It works on windows (i think this answer is helpful for users searching over there)
<?php
$a = popen('ping www.google.com', 'r');
while($b = fgets($a, 2048)) {
echo $b."<br>\n";
ob_flush();flush();
}
pclose($a);
?>
A better solution to this old problem using modern HTML5 Server Side Events is described here:
http://www.w3schools.com/html/html5_serversentevents.asp
Example:
http://sink.agiletoolkit.org/realtime/console
Code: https://github.com/atk4/sink/blob/master/admin/page/realtime/console.php#L40
(Implemented as a module in Agile Toolkit framework)
For command-line usage:
function execute($cmd) {
$proc = proc_open($cmd, [['pipe','r'],['pipe','w'],['pipe','w']], $pipes);
while(($line = fgets($pipes[1])) !== false) {
fwrite(STDOUT,$line);
}
while(($line = fgets($pipes[2])) !== false) {
fwrite(STDERR,$line);
}
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
return proc_close($proc);
}
If you're trying to run a file, you may need to give it execute permissions first:
chmod('/path/to/script',0755);
try this (tested on Windows machine + wamp server)
header('Content-Encoding: none;');
set_time_limit(0);
$handle = popen("<<< Your Shell Command >>>", "r");
if (ob_get_level() == 0)
ob_start();
while(!feof($handle)) {
$buffer = fgets($handle);
$buffer = trim(htmlspecialchars($buffer));
echo $buffer . "<br />";
echo str_pad('', 4096);
ob_flush();
flush();
sleep(1);
}
pclose($handle);
ob_end_flush();
I've tried various PHP execution commands on Windows and found that they differ quite a lot.
Don't work for streaming: shell_exec, exec, passthru
Kind of works: proc_open, popen -- "kind of" because you cannot pass arguments to your command (i.e. wont' work with my.exe --something, will work with _my_something.bat).
The best (easiest) approach is:
You must make sure your exe is flushing commands (see printf flushing problem). Without this you will most likely receive batches of about 4096 bytes of text whatever you do.
If you can, use header('Content-Type: text/event-stream'); (instead of header('Content-Type: text/plain; charset=...');). This will not work in all browsers/clients though! Streaming will work without this, but at least first lines will be buffered by the browser.
You also might want to disable cache header('Cache-Control: no-cache');.
Turn off output buffering (either in php.ini or with ini_set('output_buffering', 'off');). This might also have to be done in Apache/Nginx/whatever server you use in front.
Turn of compression (either in php.ini or with ini_set('zlib.output_compression', false);). This might also have to be done in Apache/Nginx/whatever server you use in front.
So in your C++ program you do something like (again, for other solutions see printf flushing problem):
Logger::log(...) {
printf (text);
fflush(stdout);
}
In PHP you do something like:
function setupStreaming() {
// Turn off output buffering
ini_set('output_buffering', 'off');
// Turn off PHP output compression
ini_set('zlib.output_compression', false);
// Disable Apache output buffering/compression
if (function_exists('apache_setenv')) {
apache_setenv('no-gzip', '1');
apache_setenv('dont-vary', '1');
}
}
function runStreamingCommand($cmd){
echo "\nrunning $cmd\n";
system($cmd);
}
...
setupStreaming();
runStreamingCommand($cmd);
First check whether flush() works for you. If it does, good, if it doesn't it probably means the web server is buffering for some reason, for example mod_gzip is enabled.
For something like ping, the easiest technique is to loop within PHP, running "ping -c 1" multiple times, and calling flush() after each output. Assuming PHP is configured to abort when the HTTP connection is closed by the user (which is usually the default, or you can call ignore_user_abort(false) to make sure), then you don't need to worry about run-away ping processes either.
If it's really necessary that you only run the child process once and display its output continuously, that may be more difficult -- you'd probably have to run it in the background, redirect output to a stream, and then have PHP echo that stream back to the user, interspersed with regular flush() calls.
If you're looking to run system commands via PHP look into, the exec documentation.
I wouldn't recommend doing this on a high traffic site though, forking a process for each request is quite a hefty process. Some programs provide the option of writing their process id to a file such that you could check for, and terminate the process at will, but for commands like ping, I'm not sure that's possible, check the man pages.
You may be better served by simply opening a socket on the port you expect to be listening (IE: port 80 for HTTP) on the remote host, that way you know everything is going well in userland, as well as on the network.
If you're attempting to output binary data look into php's header function, and ensure you set the proper content-type, and content-disposition. Review the documentation, for more information on using/disabling the output buffer.
Try changing the php.ini file set "output_buffering = Off". You should be able to get the real time output on the page
Use system command instead of exec.. system command will flush the output
why not just pipe the output into a log file and then use that file to return content to the client. not quite real time but perhaps good enough?
I had the same problem only could do it using Symfony Process Components ( https://symfony.com/doc/current/components/process.html )
Quick example:
<?php
use Symfony\Component\Process\Process;
$process = new Process(['ls', '-lsa']);
$process->run(function ($type, $buffer) {
if (Process::ERR === $type) {
echo 'ERR > '.$buffer;
} else {
echo 'OUT > '.$buffer;
}
});
?>
I am using GDCM library to create a DICOMDIR file. I implemented the code as shown in GDCM docs:
http://gdcm.sourceforge.net/html/GenerateDICOMDIR_8cs-example.html
In the code:
private int GenerateDicomDir(string directory, string outFileName)
{
gdcm.Directory d = new gdcm.Directory();
uint nfiles = d.Load(directory, true);
if (nfiles == 0) return 1;
string descriptor = "Descriptor";
FilenamesType filenames = d.GetFilenames();
gdcm.Trace.DebugOn();
gdcm.DICOMDIRGenerator gen = new DICOMDIRGenerator();
gen.SetFilenames(filenames);
gen.SetDescriptor(descriptor);
if (!gen.Generate())
{
return 1;
}
gdcm.FileMetaInformation.SetSourceApplicationEntityTitle("GenerateDICOMDIR");
gdcm.Writer writer = new Writer();
writer.SetFile(gen.GetFile());
writer.SetFileName(outFileName);
if (!writer.Write())
{
return 1;
}
return 0;
}
The function returns and does not generate a DICOMDIR file. I have added trace debug on but still cannot debug or get any output message.
Is there any way to generate DICOMDIR file for bunch of DICOM files ?
As per the documentation, did you made sure that:
Warning: : PS 3.11 - 2008 / D.3.1 SOP Classes and Transfer Syntaxes
Composite Image & Stand-alone Storage are required to be stored as
Explicit VR Little Endian Uncompressed (1.2.840.10008.1.2.1). When a
DICOM file is found using another Transfer Syntax the generator will
simply stops. Input files should be Explicit VR Little Endian
filenames should be valid VR::CS value (16 bytes, upper case ...)
If you turn verbose debugging you could log the exact error message, see gdcm::Trace for usage.
As per the documentation of gdcm::Trace, you need to pay attention to the following:
Warning: All string messages are removed during compilation time when
compiled with CMAKE_BUILD_TYPE being set to either: Release MinSizeRel
It is recommended to compile with RelWithDebInfo and/or Debug during
prototyping of applications.
You could also use gdcm::Trace::SetStreamToFile, to properly redirect any messages to a file (instead of stdout by default).
Since you use the recursion option of gdcm.Directory, you need to also pay attention that sub-directory name are valid (VR::CS, 16bytes, upper case...).
See also the gdcmgendir man page for more info.
I wrote a small C#/.Net application that is able to read the cookies.sqlite file of Firefox. Since I upgraded to Firefox 4 my application is not able to open the database file:
Executing the line "connection.Open();" (in the code sample below) there will be an execption that says:
"File opened that is not a database file. file is encrypted or is not a database"
This is my program code:
class Program
{
static void Main()
{
const string PATH_TO_DATABASE = #"C:\Users\Boris\Desktop\TEMP\cookies.sqlite";
const string CONNECTION_STRING = #"Data Source=" + PATH_TO_DATABASE;
if (!File.Exists(PATH_TO_DATABASE)) return;
using (SQLiteConnection connection = new SQLiteConnection(CONNECTION_STRING))
{
connection.Open();
using (SQLiteCommand command = new SQLiteCommand("SELECT id, name, host, path FROM moz_cookies", connection))
{
using (SQLiteDataReader read = command.ExecuteReader())
{
while (read.Read())
{
string id = read[0].ToString();
string name = read[1].ToString();
string host = read[2].ToString();
string path = read[3].ToString();
Console.WriteLine("ID: " + id);
Console.WriteLine("Name: " + name);
Console.WriteLine("Host: " + host);
Console.WriteLine("Path: " + path);
}
}
}
}
}
}
I am using the .Net Wrapper DLL for Sqlite v. 3.6.23.1.
The target framework of the application is .Net 2.0.
I was able to open the sqlite database without any problems using an application called SqliteExpert.
It would be great if anybody has an idea!
Regards,
Boris
Firefox 4.0 uses SQLite version 3.7.4. (To see this, download SQLite Manager and run select sqlite_version(); in the "Execute SQL" tab.)
It appears that v3.7.4 creates databases that can't be read by v3.6.23.1. I can't find this explicitly stated in the release notes, but it's clear from comparing the cookies.sqlite file to the file format documentation that the format has changed. Specifically, according to the documentation, byte 19 (0x13) should be 1, but that byte in the cookies.sqlite file is 2. As per the documentation:
If a value greater than 1 is read by
SQLite, then the library will refuse
to open the database.
Like the "write version" described
above, this field exists to facilitate
some degree of forwards compatibility,
in case it is ever required. If a
version of SQLite created in the
future uses a file format that may not
be safely read by older SQLite
versions, then this field will be set
to a value greater than 1.
To read the database, you will need to use the latest version of SQLite; unfortunately System.Data.SQLite hasn't been updated in almost a year. The project has since been taken over by sqlite.org, but downloads are not currently available.
If you don't want to wait for sqlite.org to release a v3.7.x-based .NET wrapper, you could try downloading the source and manually upgrading SQLite.NET/SQLite.Interop/src/sqlite3.c to the latest amalgamation C source file (available here).
EDIT: As noted by sdwilsh, Firefox 4.0 uses Write-Ahead Logging; as the description of that new journal mode states:
Thus, if an older version of SQLite
attempts to connect to an SQLite
database that is operating in WAL
mode, it will report an error along
the lines of "file is encrypted or is
not a database".
I had the same problem. Previously I used a Python script (with sqlite integration) to fetch up data from the cookies.sqlite and perms.sqlite files. The latter still works fine. Indeed, all of the other .sqlite files are readable ... except for cookies.sqlite and places.sqlite. Those two produce the "encrypted or is not a database" error.
Rather than hunt down an upgrade for Python (or sqlite3), I created a patch for the .sqlite files. This C-code changes the bytes at offset 18 and 19 from 2 to 1. I run this on Windows under Cygwin, but it should compile and run on Unix/Linux.
Warning: Don't do this to the original Firefox cookies.sqlite file.
Instead, copy that to a temp file, then run the patch on the copy.
// ffpatch.c
// Edits the specified Firefox .sqlite file.
// Changes 0x0202 to 0x0101 at offset 18/19.
// BEFORE
// 0000000 S Q L i t e f o r m a t 3 \0
// 0000020 004 \0 002 002 \0 # \0 \0 005 034 \0 \0 \0 N
// AFTER
// 0000000 S Q L i t e f o r m a t 3 \0
// 0000020 004 \0 001 001 \0 # \0 \0 005 034 \0 \0 \0 N
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#define PROGNAME "ffpatch"
#define MY_OFFSET 18
int main (int argc, char *argv[])
{
int fd;
char buf[2];
off_t offset;
ssize_t wsize;
if (argc != 2)
{
fprintf(stderr, "usage: %s sqlite-file\n", PROGNAME);
exit(1);
}
if ((fd = open(argv[1], O_RDWR)) == -1)
{
fprintf(stderr, "cannot open %s\n", argv[1]);
exit(1);
}
if ((offset = lseek(fd, MY_OFFSET, SEEK_SET)) != MY_OFFSET)
{
fprintf(stderr, "lseek() failed\n");
exit(1);
}
buf[0] = 1;
buf[1] = 1;
wsize = write(fd, buf, 2);
close(fd);
exit(0);
}
Hello and thanks alot for your answers!
I made my application work this way:
1.
I downloaded the sources of the current ADO.NET Connector for .NET 4.0 here: http://system.data.sqlite.org/index.html/timeline?r=trunk
Maybe you will have to logon on the website first using a anonymous user name and a capcha as passoword.
2.
I obtained the precompiled version of the sqlite3.dll v.3.7.4 by downloading an installing this ADO.NET connector: http://www.devart.com/dotconnect/sqlite/
(You may use the ADO.NET connector libs as an replacement for connector from system.data.sqlite.org as well.
I myself am only interested in the sqlite3.dll.)
3.
After compiling the sources from system.data.sqlite.org I copied the resulting System.Data.Sqlite.dll and the sqlite3.dll to my applications output directory. Please note that both DLLs are compiled either for x86 or x64 machines.
Regards
I think I got your problem. Your db connection is OK. First of all you are using which version of dotnetFramework? Accordingly you can download and use System.Data.SQLite.dll file to your references then your problem may be solved. I think you are using a System.Data.SQLite.dll file that is older one (doesn't match your version of dot net).
I have a gem, roundhouse, which is an application compiled with .NET (C#). Runs on Windows and it should run in a 32 bit process.
To set up my gemspec, I set:
Gem::Specification.new do |s|
s.platform = 'mswin32'
s.name = 'roundhouse'
s.version = version
s.files = Dir['lib/**/*'] + Dir['bin/**/*']
s.bindir = 'bin'
s.executables << 'rh.exe'
When I install the gem, I should be able to type rh.exe from the command line at any path and it should run correctly.
In practice, I'm not seeing this work correctly. This is what I'm getting back:
Window has this for the header: 16 bit MS-DOS Subsystem
C:\WINDOWS\system32\cmd.exe - rh.exe
The NTVDM CPU has encountered an illegal instruction.
CS:xxxx IP:xxxx OP:xx xx xx xx xx Choose 'Close' to terminate the application.
Here is a picture of the issue (link to TwitPic): Error
If I go to the directory where the item was installed, I can run it and it works great. It's just something in the registration of the command to run from anywhere.
I did quite a bit of searching before asking and came up with nothing. It could be that I don't know what I should be searching for. So let me ask the question, is there a way to register an executable with gems for windows executable applications (built with .NET) and have them register properly with the command line? If so, how is that done?
UPDATE:
I found that gems creates a shim in the C:\Ruby\bin directory that points back to the other file. So there is a rh.exe file that is really just a text file. This is its contents:
#!C:/Ruby/bin/ruby.exe
#
# This file was generated by RubyGems.
#
# The application 'roundhouse' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0"
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
version = $1
ARGV.shift
end
gem 'roundhouse', version
load Gem.bin_path('roundhouse', 'rh.exe', version)
if you're distributing it with the file "rh.exe"
then you'll want to create a file
bin/rh
s.executables << 'bin/rh'
then when it's installed gems will create an "rh.bat" file which runs ruby "bin/rh" essentially (as you've seen).
So within bin/rh put something like
result = system(File.dirname(__FILE__) + "/rh.exe" ARGV.join(' '))
exit 1 unless result
result = system(File.dirname(__FILE__) + "/rh.exe " + ARGV.join(' '))
exit 1 unless result
So the endresult should maybe look like? note the space after 'rh.exe'