DrKLO/Telegram · error

%s: can't open %s

Error message

%s: can't open %s

What it means

When the user specifies an ICC profile via the `-icc` option, jpegtran opens it with fopen(icc_filename, READ_BINARY) at jpegtran.c:505. A NULL return means the ICC file path is invalid or inaccessible. Unlike the input JPEG, this error message omits 'for reading' to distinguish it.

Source

Thrown at TMessagesProj/jni/mozjpeg/jpegtran.c:506

    usage();
  }
#endif /* TWO_FILE_COMMANDLINE */

  /* Open the input file. */
  if (file_index < argc) {
    if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) {
      fprintf(stderr, "%s: can't open %s for reading\n", progname,
              argv[file_index]);
      exit(EXIT_FAILURE);
    }
  } else {
    /* default input file is stdin */
    fp = read_stdin();
  }

  if (icc_filename != NULL) {
    if ((icc_file = fopen(icc_filename, READ_BINARY)) == NULL) {
      fprintf(stderr, "%s: can't open %s\n", progname, icc_filename);
      exit(EXIT_FAILURE);
    }
    if (fseek(icc_file, 0, SEEK_END) < 0 ||
        (icc_len = ftell(icc_file)) < 1 ||
        fseek(icc_file, 0, SEEK_SET) < 0) {
      fprintf(stderr, "%s: can't determine size of %s\n", progname,
              icc_filename);
      exit(EXIT_FAILURE);
    }
    if ((icc_profile = (JOCTET *)malloc(icc_len)) == NULL) {
      fprintf(stderr, "%s: can't allocate memory for ICC profile\n", progname);
      fclose(icc_file);
      exit(EXIT_FAILURE);
    }
    if (fread(icc_profile, icc_len, 1, icc_file) < 1) {
      fprintf(stderr, "%s: can't read ICC profile from %s\n", progname,
              icc_filename);
      free(icc_profile);

View on GitHub (pinned to 45ab8f4308)

Solutions

  1. Verify the ICC file exists and is readable with `access(icc_path, R_OK)` before invoking jpegtran
  2. Use an absolute path for the ICC profile file
  3. Extract the ICC profile from the APK assets to internal storage first, then pass that path

Example fix

// before
jpegtran -icc srgb.icc input.jpg -outfile out.jpg

// after
const char *icc = "/data/user/0/app/files/srgb.icc";
if (access(icc, R_OK) != 0) { return -1; }
jpegtran -icc /data/user/0/app/files/srgb.icc input.jpg -outfile out.jpg
Defensive patterns

Strategy: validation

Validate before calling

// Validate ICC profile file before invoking jpegtran -icc
int validate_icc_file(const char *path) {
    if (access(path, R_OK) != 0) return -1;
    struct stat st;
    if (stat(path, &st) != 0) return -1;
    if (!S_ISREG(st.st_mode)) return -1;
    if (st.st_size < 128 || st.st_size > 5*1024*1024) return -1; // ICC profiles are 128B-5MB
    return 0;
}

Prevention

When it happens

Trigger: Passing `-icc profile.icc` where profile.icc does not exist, is a directory, or has restrictive permissions. Also triggered by a typo in the ICC filename or an expired/cleaned-up temp file path.

Common situations: ICC profile file was downloaded to a cache that was cleared. Path is relative and resolves wrong in JNI context. Profile is bundled as an Android asset but the native code receives a path that doesn't resolve on the filesystem.

Related errors


AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14). Data as JSON: /api/errors/60d2438df05036c2. Report an issue: GitHub.