Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line breaks and carriage returns not working properly #58

Open
jihu opened this issue Jul 22, 2022 · 3 comments
Open

Line breaks and carriage returns not working properly #58

jihu opened this issue Jul 22, 2022 · 3 comments

Comments

@jihu
Copy link

jihu commented Jul 22, 2022

It seems that this tool doesn't handle line breaks and carriage returns properly.

Example when writing:

  • Modify the "write_metadata" example from this project
  • Change the metadata like this:
const metadata = {
    all: '', // remove all metadata at first
    'Caption-Abstract': 'test-line1\ntest-line2',
}
  • Run code

The output then contains:

{
  "data": null,
  "error": "Error: File not found - test-line2\r\n    1 image files updated\r\n    1 files weren't updated due to errors"
}

As you can see, the line break character causes it to believe that "test-line2" is a file argument.

I noticed this when trying to update the metadata of an image with existing line breaks (\n) and carriage returns (\r). It was part of a field that I didn't intend to modify (so I left it unchanged), but when writing the metadata I got this error:

undefined:1
======== some text [1/6]
^

SyntaxError: Unexpected token = in JSON at position 0
    at JSON.parse (<anonymous>)
    at C:\redacted\node_modules\node-exiftool\src\lib.js:146:37
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

When looking at this (line 146 and the surrounding lines), I see this code:

return {
    data: res[0] ? JSON.parse(res[0]) : null,
    error: res[1] || null,
}

This means that it is expecting json formated output from exiftool in res[0].

Adding some code that prints this data just before the return, I got this:

This is the content of res[0]:
-----------------------------------------------------------------------
======== some text [1/6]
======== some more text [2/6]
======== some more text  [3/6]
======== some more text  [4/6]
======== some more text  [5/6]
======== C:/redacted/some_image.jpg [6/6]
-----------------------------------------------------------------------

The lines with "-----------------------------------------------------------------------" is not part of the output. Here you can see that for some reason exiftool doesn't output json here. Instead it outputs text strings that each was prefixed with a line break or carriage return, except for the last line that is the path to the image processed. And each output is for some reason prefixed with "======== "
When outputting the content of res[1] I get a bunch of exiftool warnings about things that isn't writable (like "Warning: Sorry, ExifToolVersion is not writable"), but at the end there is an error "Error: File not found - ..." for each "some text" line above.

So, clearly, these line breaks and carriage returns is messing up the communication between node-exiftool and exiftool. Sadly I haven't been able to construct a sample jpg that causes this, and because of copyright reasons I can't share the actual image used.

Actually, maybe this is two bugs in one. One bug being the line breaks and/or carriage returns causing incorrect input data to exiftool, and one bug being that node-exiftool always asumes that the output from exiftool is json without checking.

@gdethier
Copy link

@jihu I have the same problem here. It comes from the fact that node-exiftool makes exiftool read an argfile from stdin (i.e. calls exiftool with arguments -@ -). In that "mode", each line is interpreted as a single argument and so, in your example, test-line2 is considered as a new argument passed to the tool.

The solution is actually here, see point (e):

Use the "#[CSTR]" feature to allow C-style escape sequences for a specific line in a -@ argfile

I patched this function so that it enables C-style escape sequences when data written to stdin contain carriage returns and/or new lines. It then looks like this:

function writeStdIn(proc, data, encoding) {
    if(/[\n\r]/.test(data)) {
        proc.stdin.write("#[CSTR]", encoding)
        proc.stdin.write(data.replaceAll(/(\r\n|\n\r|\n|\r)/g, "\\n"), encoding)
    } else {
        proc.stdin.write(data, encoding)
    }
    proc.stdin.write(EOL, encoding)
}

This solution may not be platform independent but it works on Linux at least.

@gdethier
Copy link

For the record, we created a fork and published a package which contains the fix (as well as type definitions for those interested). If anyone has write access to this repository and is willing to keep up maintaining it, I would be happy to create a PR.

@anasshakil
Copy link

Please take a look at my repo. I hope it'll solve your problem
Link: https://github.com/anasshakil/metadata

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants