(聲明:我意識到這是文本的一個巨大的牆,但我已經盡了我熬下來的要領。如果你熟悉的libtiff這不是很複雜的問題)迷茫中添加自定義標記時實施_TIFFVGetField
我問過的libtiff郵件列表這個問題了,但我想我可以有一個很好的機會,在這裏,以及如果存在任何人誰與圖書館工作。
我在這裏使用的文件加入我自己的內置標籤庫:http://libtiff.maptools.org/addingtags.html
所以,我加入到tif_dirinfo.c頂部像這樣定義的數組TIFFFieldInfo一個條目:
{ TIFFTAG_CUSTOM_XXX, 4, 4, TIFF_SLONG, FIELD_XXX, 1, 0, "XXX" },
我再添加一個字段中tif_dir.h
定義的TIFFDirectory
結構:
typedef struct {
/* ... */
int32 td_xxx[4];
} TIFFDirectory;
現在我繼續根據指示修改了_TIFFVSetField
和_TIFFVGetField
。這是我遇到問題的地方。
在模仿模式已經存在於庫(見TIFFTAG_YCBCRSUBSAMPLING
實施,這是類似於我在做什麼),我下面的代碼添加到_TIFFVGetField
:
/* existing, standard tag for reference */
case TIFFTAG_YCBCRSUBSAMPLING:
*va_arg(ap, uint16*) = td->td_ycbcrsubsampling[0];
*va_arg(ap, uint16*) = td->td_ycbcrsubsampling[1];
break;
/* my new tag */
case TIFFTAG_CUSTOM_XXX:
*va_arg(ap, int32*) = td->td_xxx[0];
*va_arg(ap, int32*) = td->td_xxx[1];
*va_arg(ap, int32*) = td->td_xxx[2];
*va_arg(ap, int32*) = td->td_xxx[3];
break;
至於我能告訴這是完全不正確的。這裏的意圖是根據int數組填充可變參數列表中的輸入。一個可取之處是,在va_list
提供的參數是該類型的int32
總是和YcBr代碼使用了兩個int16
的。所以,它的工作原理,但我不能複製該實現。
_TIFFVGetField
最終從TIFFWriteNormalTag
在tif_dirwrite.c
中調用。相關的代碼是這樣的:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_IFD:
if (fip->field_passcount) {
uint32* lp;
if (wc == (uint16) TIFF_VARIABLE2) {
TIFFGetField(tif, fip->field_tag, &wc2, &lp);
TDIRSetEntryCount(tif,dir, wc2);
} else { /* Assume TIFF_VARIABLE */
TIFFGetField(tif, fip->field_tag, &wc, &lp);
TDIRSetEntryCount(tif,dir, wc);
}
if (!TIFFWriteLongArray(tif, dir, lp))
return 0;
} else {
if (wc == 1) {
uint32 wp;
/* XXX handle LONG->SHORT conversion */
TIFFGetField(tif, fip->field_tag, &wp);
TDIRSetEntryOff(tif,dir, wp);
} else {
/* ---------------------------------------------------- */
/* this is the code that is called in my scenario */
/* ---------------------------------------------------- */
uint32* lp;
TIFFGetField(tif, fip->field_tag, &lp);
if (!TIFFWriteLongArray(tif, dir, lp))
return 0;
}
}
break;
因此,未初始化的指針lp
聲明,並將其地址傳遞給TIFFGetField
。這反過來設置所使用的va_list(與lp
作爲唯一的參數),並調用TIFFVGetField
,它調用_TIFFVGetField
與供給va_list
和指針到未初始化的指針。
這裏有兩個問題。
首先,這是圖書館如何提取數據(我的代碼,但同樣,下面的模式已經存在)
*va_arg(ap, int32*) = td->td_xxx[0];
這似乎不正確。它將原始指針設置爲int的值。我推斷,也許在我遵循的示例(TIFFTAG_YCBCRSUBSAMPLING)中,這些整數實際上是地址。所以好吧,但即使是這樣,但還有其他問題。
該庫調用va_args
N
次,其中N
是數組中元素的數量。從我看到的變量參數列表中只包含一個參數(指針的地址)。這是(在開始時重要的一點),每標準定義的操作:
如果沒有實際的一個參數,或者如果類型是不符合 實際的一個參數的類型兼容(根據推廣默認參數促銷),的行爲是未定義的。
正確的版本將是
*va_arg(ap, int32**) = td_xxx;
這將設置先前未初始化的指針到數組中,這是有效的。我不喜歡它指向數據本身而不是副本,但不管怎樣;至少它不會崩潰,並給我正確的結果。
我在這裏擔心的是我錯過了一些微妙的東西。這個軟件很舊,被許多人使用。因此,調用這個bug對我來說就像是指責編譯器崩潰一樣,這是幾乎總是錯誤的。
但是,我無法推斷出這種方式是正確的,特別是當庫被多次調用時,庫如何寫入va_arg
的返回值。
任何幫助將不勝感激。提前致謝。