【问题标题】:C program for steganography用于隐写术的 C 程序
【发布时间】:2021-05-12 03:07:57
【问题描述】:

相对较新的编程,被分配到创建一个 C 程序来编码和解码 2 ppm 图像以接收秘密消息的任务。我想出了代码,但它没有超越 getPPM 函数中的 if 语句的图像格式。关于我可以对我的代码进行哪些更改的任何提示?同样在我的main() 中,我是否传递了正确的参数?

typedef struct NODE {
    char *val;
    struct NODE *next;
} NODE;

/*
   Stores the RGB values of a pixel
 */
typedef struct Pixel {
    int red;
    int green;
    int blue;
} Pixel;

/*
   Stores the contents of a PPM file
 */
typedef struct PPM {
    char *format;
    NODE *comments;
    int width, height;
    int max;
    Pixel *arr;
} PPM;

NODE *copy(NODE *first)
{
    NODE *second = NULL, *previous = NULL;

    while (first != NULL) {
        NODE *temp = (NODE *)malloc(sizeof(NODE));
        temp->val = first->val;
        temp->next = NULL;

        if (second == NULL) {
            second = temp;
            previous = temp;
        } else {
            previous->next = temp;
            previous = temp;
        }
        first = first->next;
    }
    return second;
}

//Copy the PPM File Returning Pointer
struct PPM* createPPM(PPM *old)
{
    PPM* new = (PPM *)malloc(sizeof(PPM));

    strcpy(new->format, old->format);
    new->comments = copy(old->comments);

    new->height = old->height;
    new->width = old->width;
    new->max = old->max;

    new->arr = (Pixel *)malloc(old->height * old->width * sizeof(Pixel));
    memcpy(new->arr, old->arr, old->height * old->width * sizeof(Pixel));

    return new;
}

/*
   Returns the PPM struct from the file fd
 */
PPM *getPPM(FILE *fd) {
    PPM *image = (PPM *)malloc(sizeof(PPM));
    image->format = (char *)malloc(MAX_LEN);

    fgets(fd, MAX_LEN, image->format);
    sscanf(fd, "%s", image->format);

    if (strcmp(image->format, "P3") != 0) {
        printf("Invalid Image Type");
        exit(0);
    }
    char c = getc(fd);
    image->comments = (NODE*)malloc(sizeof(NODE));
    NODE *temp = image->comments;
    while ((c = getc(fd)) == '#') {
        fseek(fd, -1, SEEK_CUR);
        char str[50];
        fgets(str, 50, fd);
        temp->val = (char*)malloc(strnlen(str, 50));
        strcpy(temp->val, str);
        temp->val[strlen(temp->val) - 1] = 0;
        temp->next = (NODE*)malloc(sizeof(NODE));
        temp = temp->next;
        temp->next = NULL;
    }

    fseek(fd, -1, SEEK_CUR);
    fscanf(fd, "%d", &image->width);
    fscanf(fd, "%d", &image->height);
    fscanf(fd, "%d", &image->max);

    image->arr = (Pixel*)malloc(image->height * image->width * sizeof(Pixel));

    int t = 0;
    int j = 0;

    while (j < image->height * image->width) {
        t = fscanf(fd, "%d", &image->arr[j].red);
        t = fscanf(fd, "%d", &image->arr[j].green);
        t = fscanf(fd, "%d", &image->arr[j].blue);
        j = j + 1;
    }

    return image;
}

PPM *loadPPMFromFile(char *filename) {
    FILE *file;

    /* TODO: step 1, open the file */
    file = fopen("C:\\Users\\Olivia\\source\\repos\\f28hs-2020-21-cwk1-c\\PPMfiles", "r");

    /* step 2: Check that file has been loaded correctly; show error otherwise*/
    if (file != NULL) {
        PPM *ppm;
        /* ODO: step 3, get the PPM data from the file with the getPPM function */
        getPPM(file);

        if (ppm == NULL) {
            /* TODO: step 4, display error if file cannot been parsed into a PPM struct*/
            printf("File cannot be parsed.\n");
        }

        /* TODO: step 5, close the file */
        fclose(file);
        /* step 6: return the PPM */
        return ppm;
    } else {
        fclose(file);
        return NULL;
    }
}

/*
   Prints a PPM struct in the format of a PPM file
 */
void showPPM(PPM *ppm) {

    printf("%s\n", ppm->format); //print format

    //print comments
    NODE *n = ppm->comments;
    while (n->next != NULL) {
        printf("%s\n", n->val);
        n = n->next;
    }

    //print width, height and max
    printf("%d %d\n%d\n", ppm->width, ppm->height, ppm->max);

    //print the array containing the pixels
    int j;
    for (j = 0; j < ppm->height * ppm->width; ++j) {
        printf("%d %d %d\n", ppm->arr[j].red, ppm->arr[j].green, ppm->arr[j].blue);
    }

    return;

}

/*
   Encodes text into red field of PPM
   Returns the encoded PPM
 */
PPM *encode(char *text, PPM *i) {
    PPM *str = createPPM(i);
    int random;
    srand((unsigned)time(NULL));
    int randMax = (i->height * i->width) / (strlen(text) + 1);

    random = rand() % randMax;

    if (random < 1) {
        random = 1;
    }

    int k = 0;
    int j = random;

    //Red fields swapped with ASCII int
    while (k < strlen(text)) {
        if (str->arr[j].red == text[k]) {
            j = j + 1; // if the values are the same we encode in the next  pixel.
        } else {
            str->arr[j].red = text[k];
            k = k + 1;
            j = j + random;
        }
    }

    return str;
}


/*
   Compares 2 PPM structs and decodes the message hidden within
   Returns the decoded message if the images have the same dimensions
   Returns NULL otherwise
 */
char *decode(PPM *i1, PPM *i2) {
    int i = 0;
    int j = 0;

    char *str = (char*)malloc(sizeof(char));

    while (i < i1->height * i1->width) {
        if (i1->arr[i].red != i2->arr[i].red) {
            str[j] = i2->arr[i].red;
            j = j + 1;
        }
        i = i + 1;
    }

    str = realloc(str, i);

    return str;
    printf("%s", str);
}

/* TODO: Question 3 */
int main(int argc, char *argv[]) {

    /* check arguments */
    switch (argc) {
    case 2:
        /* TODO: not enough arguments, print an error message */
        printf("Not enough arguments. \n");
        break;
    case 3:
        if (strcmp(argv[1], "e") == 0) { //Argument "e" - encode PPM
            PPM *ppm = loadPPMFromFile(argv[2]);
            createPPM(ppm);

            /*Check that PPM is valid; continue if it is, exit otherwise */
            if (ppm != NULL) {
                PPM *encodedPPM;
                /* TODO: encode the ppm with the text and assign to encodedPPM */
                encodedPPM = encode(argv[2], encodedPPM);
                /*Check that no error occured*/
                if (encodedPPM == NULL) {
                    return EXIT_FAILURE;
                } else {
                    /* TODO: print a confirmation that encoding was successful */
                    printf("Encoding successful. \n");
                    /* TODO: print the PPM to standard output with showPPM */
                    showPPM(encodedPPM);
                    return EXIT_SUCCESS;
                }
            } else {
                return EXIT_FAILURE;
            }
        } else {
            printf("Unrecognised or incomplete command line.\n");
            return EXIT_FAILURE;
        }
        break;
    case 4:
        if (strcmp(argv[1], "d") == 0) { //Argument "d" - decode PPM
            PPM *comparisonPPM;
            PPM *encodedPPM;

            /* TODO: get comparison file filename from argv, load it with
               loadPPMFromFile then assign to comparisonPPM */

            comparisonPPM = loadPPMFromFile(argv[2]);
            /* TODO: get encoded file filename from argv, load it with
               loadPPMFromFile then assign to encodedPPM */

            encodedPPM = loadPPMFromFile(argv[2]);
            /*Check both PPMs are valid; continue if so, exit otherwise */
            if (comparisonPPM != NULL && encodedPPM != NULL) {
                char *decodedMsg;

                /* TODO: decode the encodedPPM with the comparisonPPM and assign to decodedMsg */
                decodedMsg = decode(encodedPPM, comparisonPPM);
                /*Check that the message has been decoded*/
                if (decodedMsg != NULL) {
                    /* TODO: print a confirmation message that the message was decoded */

                    printf("Decoded message:\n");

                    /* TODO: print the decoded message */
                    printf("%p",decodedMsg);
                    return EXIT_SUCCESS;
                } else {
                    return EXIT_FAILURE;
                }
            } else {
                return EXIT_FAILURE;
            }
        } else {
            fprintf(stderr, "Unrecognised or incomplete command line.\n\n");
            return EXIT_FAILURE;
        }
        break;
    default:
        fprintf(stderr, "Unrecognised or incomplete command line.\n\n");
        return EXIT_FAILURE;
    }
}

【问题讨论】:

  • 这是学习使用调试器和/或十六进制编辑器的好时机。使用您的调试器,在受影响的if 语句处设置断点并检查image-&gt;format 的内容以查看它们实际包含的内容。使用十六进制编辑器,检查文​​件的前几个字节以查看它们实际上是什么。这将使您能够更好地描述问题的性质,这是产生解决方案的第一步。
  • char c = getc(fd); - 你的意思是在那里读一个字符吗? - 它被下面的while 循环中的getc 覆盖。
  • 或者在某种程度上你可以用旧的打印语句调试代替调试器检查结束。或者甚至只是增加您现有的错误消息以显示观察到的实际数据。但这些方法可能会尝试打印非文本。
  • 您不需要删除其他问题。我正要写一个答案...
  • 请不要通过破坏您的帖子为他人增加工作量。通过在 Stack Exchange 网络上发帖,您已在 CC BY-SA 4.0 license 下授予 Stack Exchange 分发该内容的不可撤销的权利(即无论您未来的选择如何)。根据 Stack Exchange 政策,帖子的非破坏版本是分发的版本。因此,任何破坏行为都将被撤销。如果您想了解更多关于删除帖子的信息,请参阅:How does deleting work?

标签: c linked-list steganography ppm


【解决方案1】:

“同样在我的 main() 中,我是否传入了正确的参数?”

是的,他们是正确的。

"getPPM 函数中的 if 语句没有通过图像格式"

getPPM 存在几个问题。
在下面的语句中覆盖c

char c = getc(fd);

已经包含在 cmets 中。

如下:

sscanf(fd, "%s", image->format);
if (strcmp(image->format, "P3") != 0)
{

因为sscanf() 会在有新行时选择新行,所以strcmp() 将无法与"P3" 进行比较。 建议执行以下一项或多项操作:

  • 在调试器中运行,在if 处设置断点并查看image-&gt;format 的值
  • if(image-&gt;format != NULL) printf("%s", image-&gt;format) 放在sscanf() 之后
  • 如果您怀疑\n\r\n 可能在缓冲区中,请使用image-&gt;format[strcspn(image-&gt;format, "\r\n")] = 0; 删除它们。

关于以下内容,建议您阅读每个 C 函数的文档,例如fgets()

这个:

fgets(fd, MAX_LEN, image->format);
scanf(...

应该是

if(fgets(image->format, MAX_LEN, fd) != NULL)
{
    scanf(...

(参数位置已更改,并在尝试使用缓冲区之前进行测试。)

旁白:因为这是C,所以跟在malloc 语句之后

PPM* image = (PPM*)malloc(sizeof(PPM));
image->format = (char*)malloc(MAX_LEN);

更多correctly写成

PPM* image = malloc(sizeof(*image));
image->format = malloc(MAX_LEN);

(从malloc() 中删除了演员表,并在第一条语句中注明sizeof argument。适用于整个代码。

【讨论】:

    猜你喜欢
    • 2013-04-21
    • 2013-03-17
    • 1970-01-01
    • 2011-01-01
    • 2011-05-10
    • 2011-09-26
    • 2013-03-24
    • 2011-03-14
    • 2012-06-08
    相关资源
    最近更新 更多