/* BASIC2026 portable AcroForm value reader and writer. */
#define B2026_PDF_FORM_MAX 10000
#define B2026_PDF_FORM_DEPTH_MAX 64

typedef struct {
    char *name,*type,*value,*default_value;
    char **options;
    int option_count,option_capacity;
    int flags,page,object_index,*widgets,widget_count,widget_capacity;
    int read_only,required,multiline,password,changed;
} B2026PdfFormField;

typedef struct { B2026PdfFormField *items;int count,capacity,acro_index; } B2026PdfFormList;

static void b2026_pdf_form_free(B2026PdfFormList *list){
    int i,j;if(list==NULL)return;for(i=0;i<list->count;++i){B2026PdfFormField*f=&list->items[i];free(f->name);free(f->type);free(f->value);free(f->default_value);for(j=0;j<f->option_count;++j)free(f->options[j]);free(f->options);free(f->widgets);}free(list->items);memset(list,0,sizeof(*list));list->acro_index=-1;
}
static int b2026_pdf_form_push(B2026PdfFormList*list,B2026PdfFormField*f){
    if(list->count>=B2026_PDF_FORM_MAX)return 0;if(list->count==list->capacity){int cap=list->capacity?list->capacity*2:32;B2026PdfFormField*p;if(cap>B2026_PDF_FORM_MAX)cap=B2026_PDF_FORM_MAX;p=(B2026PdfFormField*)realloc(list->items,(size_t)cap*sizeof(*p));if(p==NULL)return 0;list->items=p;list->capacity=cap;}list->items[list->count++]=*f;return 1;
}
static int b2026_pdf_form_widget_push(B2026PdfFormField*f,int oi){
    if(f->widget_count==f->widget_capacity){int cap=f->widget_capacity?f->widget_capacity*2:4;int*p=(int*)realloc(f->widgets,(size_t)cap*sizeof(*p));if(p==NULL)return 0;f->widgets=p;f->widget_capacity=cap;}f->widgets[f->widget_count++]=oi;return 1;
}
static int b2026_pdf_form_option_push(B2026PdfFormField*f,const char*s){
    if(f->option_count==f->option_capacity){int cap=f->option_capacity?f->option_capacity*2:8;char**p=(char**)realloc(f->options,(size_t)cap*sizeof(*p));if(p==NULL)return 0;f->options=p;f->option_capacity=cap;}f->options[f->option_count]=b2026_strdup_simple(s!=NULL?s:"");if(f->options[f->option_count]==NULL)return 0;++f->option_count;return 1;
}
static int b2026_pdf_form_ref_value(B2026PdfDocument*doc,const unsigned char*s,size_t n){int a,g,oi;if(!b2026_pdf_tf_ref(s,n,&a,&g))return-1;oi=b2026_pdf_object_lookup(doc,a,g);return oi;}
static int b2026_pdf_form_key_ref(B2026PdfDocument*doc,int oi,const char*key){B2026PdfKeyRange r;B2026PdfObject*o;if(oi<0||oi>=doc->object_count)return-1;o=&doc->objects[oi];if(!b2026_pdf_tf_find_key(o->body,o->body_length,key,&r)||!r.found)return-1;return b2026_pdf_form_ref_value(doc,o->body+r.value_start,r.value_end-r.value_start);}
static int b2026_pdf_form_refs(B2026PdfDocument*doc,const unsigned char*s,size_t n,int**out,int*count){
    size_t p=b2026_pdf_tf_space(s,n,0U),end;int*items=NULL,used=0,cap=0;if(p>=n||s[p]!='[')return 0;end=b2026_pdf_tf_value_end(s,n,p,0);++p;while((p=b2026_pdf_tf_space(s,end,p))<end&&s[p]!=']'){size_t ve=b2026_pdf_tf_value_end(s,end,p,0);int oi=b2026_pdf_form_ref_value(doc,s+p,ve-p);if(ve<=p||oi<0){free(items);return 0;}if(used==cap){int nc=cap?cap*2:8;int*q=(int*)realloc(items,(size_t)nc*sizeof(*q));if(q==NULL){free(items);return 0;}items=q;cap=nc;}items[used++]=oi;p=ve;}*out=items;*count=used;return 1;
}
static int b2026_pdf_form_kids(B2026PdfDocument*doc,int oi,int**out,int*count){B2026PdfObject*o;B2026PdfKeyRange r;*out=NULL;*count=0;if(oi<0||oi>=doc->object_count)return 0;o=&doc->objects[oi];if(!b2026_pdf_tf_find_key(o->body,o->body_length,"/Kids",&r))return 0;if(!r.found)return 1;return b2026_pdf_form_refs(doc,o->body+r.value_start,r.value_end-r.value_start,out,count);}
static int b2026_pdf_form_page(B2026PdfDocument*doc,int widget){int p=b2026_pdf_form_key_ref(doc,widget,"/P"),i;if(p>=0)for(i=0;i<doc->page_count;++i)if(doc->page_objects[i]==p)return i+1;return 0;}
static char*b2026_pdf_form_name_value(const unsigned char*body,size_t n,const char*key){char*v=b2026_pdf_dict_name(body,n,key);return v!=NULL?v:b2026_strdup_simple("");}
static char*b2026_pdf_form_string_value(B2026PdfDocument*doc,const unsigned char*body,size_t n,const char*key){char*v=b2026_pdf_dict_string(doc,body,n,key);if(v!=NULL)return v;return b2026_pdf_form_name_value(body,n,key);}
static char*b2026_pdf_form_full_name(const char*prefix,const char*part){size_t a=strlen(prefix!=NULL?prefix:""),b=strlen(part!=NULL?part:"");char*r;if(a==0U)return b2026_strdup_simple(part!=NULL?part:"");if(b==0U)return b2026_strdup_simple(prefix);r=(char*)malloc(a+b+2U);if(r==NULL)return NULL;memcpy(r,prefix,a);r[a]='.';memcpy(r+a+1U,part,b+1U);return r;}
static int b2026_pdf_form_field_exists(B2026PdfFormList*list,const char*name){int i;for(i=0;i<list->count;++i)if(strcmp(list->items[i].name,name)==0)return 1;return 0;}

static int b2026_pdf_form_parse_options(B2026PdfDocument*doc,B2026PdfFormField*f,const unsigned char*body,size_t n){
    B2026PdfKeyRange r;size_t p,end;if(!b2026_pdf_tf_find_key(body,n,"/Opt",&r))return 0;if(!r.found)return 1;p=b2026_pdf_tf_space(body,r.value_end,r.value_start);if(p>=r.value_end||body[p]!='[')return 0;end=r.value_end;++p;while((p=b2026_pdf_tf_space(body,end,p))<end&&body[p]!=']'){size_t ve=b2026_pdf_tf_value_end(body,end,p,0);char*v=NULL;if(ve<=p)return 0;if(body[p]=='['){size_t q=b2026_pdf_tf_space(body,ve,p+1U),qe=b2026_pdf_tf_value_end(body,ve,q,0);if(qe<=q)return 0;v=b2026_pdf_parse_string_value(doc,body,ve,q,0);}else v=b2026_pdf_parse_string_value(doc,body,end,p,0);if(v==NULL||!b2026_pdf_form_option_push(f,v)){free(v);return 0;}free(v);p=ve;}return 1;
}
static int b2026_pdf_form_button_states(B2026PdfDocument*doc,B2026PdfFormField*f,int widget){
    B2026PdfObject*o=&doc->objects[widget];B2026PdfKeyRange ap,nr;char*apcopy=NULL,*ncopy=NULL;const unsigned char*b;size_t n,p;if(!b2026_pdf_tf_find_key(o->body,o->body_length,"/AP",&ap)||!ap.found)return 1;apcopy=b2026_pdf_tf_value_copy(doc,o->body+ap.value_start,ap.value_end-ap.value_start,1);if(apcopy==NULL)return 0;if(!b2026_pdf_tf_find_key((unsigned char*)apcopy,strlen(apcopy),"/N",&nr)||!nr.found){free(apcopy);return 1;}ncopy=b2026_pdf_tf_value_copy(doc,(unsigned char*)apcopy+nr.value_start,nr.value_end-nr.value_start,1);free(apcopy);if(ncopy==NULL)return 0;b=(unsigned char*)ncopy;n=strlen(ncopy);p=0U;while((p=b2026_pdf_tf_space(b,n,p))<n){size_t s,e;if(p+1U<n&&b[p]=='>'&&b[p+1U]=='>')break;if(b[p]!='/'){++p;continue;}s=++p;while(p<n&&!b2026_pdf_is_delim(b[p]))++p;e=p;if(e>s&&!(e-s==3U&&memcmp(b+s,"Off",3U)==0)){char name[256];size_t z=e-s;if(z>=sizeof(name)){free(ncopy);return 0;}memcpy(name,b+s,z);name[z]='\0';{int i,found=0;for(i=0;i<f->option_count;++i)if(strcmp(f->options[i],name)==0)found=1;if(!found&&!b2026_pdf_form_option_push(f,name)){free(ncopy);return 0;}}}p=b2026_pdf_tf_value_end(b,n,p,0);}free(ncopy);return 1;
}

static int b2026_pdf_form_collect_terminal(B2026PdfDocument*doc,int oi,const char*name,const char*ft,int flags,int*k,int kc,B2026PdfFormList*list){
    B2026PdfObject*o=&doc->objects[oi];B2026PdfFormField f;int i;memset(&f,0,sizeof(f));f.object_index=oi;f.flags=flags;f.name=b2026_strdup_simple(name);f.value=b2026_pdf_form_string_value(doc,o->body,o->body_length,"/V");f.default_value=b2026_pdf_form_string_value(doc,o->body,o->body_length,"/DV");if(f.name==NULL||f.value==NULL||f.default_value==NULL)goto fail;f.read_only=(flags&1)!=0;f.required=(flags&2)!=0;f.multiline=(flags&4096)!=0;f.password=(flags&8192)!=0;if(strcmp(ft,"Tx")==0)f.type=b2026_strdup_simple("TEXT");else if(strcmp(ft,"Ch")==0)f.type=b2026_strdup_simple((flags&131072)?"COMBOBOX":"LISTBOX");else if(strcmp(ft,"Btn")==0)f.type=b2026_strdup_simple((flags&65536)?"PUSHBUTTON":((flags&32768)?"RADIO":"CHECKBOX"));else if(strcmp(ft,"Sig")==0)f.type=b2026_strdup_simple("SIGNATURE");else f.type=b2026_strdup_simple("UNKNOWN");if(f.type==NULL)goto fail;if(b2026_pdf_dict_name_is(o->body,o->body_length,"/Subtype","Widget")){if(!b2026_pdf_form_widget_push(&f,oi))goto fail;}for(i=0;i<kc;++i)if(b2026_pdf_dict_name_is(doc->objects[k[i]].body,doc->objects[k[i]].body_length,"/Subtype","Widget")&&!b2026_pdf_form_widget_push(&f,k[i]))goto fail;if(f.widget_count>0)f.page=b2026_pdf_form_page(doc,f.widgets[0]);if(strcmp(ft,"Ch")==0&&!b2026_pdf_form_parse_options(doc,&f,o->body,o->body_length))goto fail;if(strcmp(ft,"Btn")==0)for(i=0;i<f.widget_count;++i)if(!b2026_pdf_form_button_states(doc,&f,f.widgets[i]))goto fail;if(b2026_pdf_form_field_exists(list,f.name)||!b2026_pdf_form_push(list,&f))goto fail;return 1;fail:free(f.name);free(f.type);free(f.value);free(f.default_value);for(i=0;i<f.option_count;++i)free(f.options[i]);free(f.options);free(f.widgets);return 0;
}
static int b2026_pdf_form_walk(B2026PdfDocument*doc,int oi,const char*prefix,const char*inherit_ft,int inherit_flags,int depth,B2026PdfFormList*list,unsigned char*seen){
    B2026PdfObject*o;char*part=NULL,*full=NULL,*local_ft=NULL;const char*ft;int flags=inherit_flags,*kids=NULL,kc=0,i,all_widgets=1,terminal;if(depth>B2026_PDF_FORM_DEPTH_MAX||oi<0||oi>=doc->object_count||seen[oi])return 0;seen[oi]=1U;o=&doc->objects[oi];part=b2026_pdf_dict_string(doc,o->body,o->body_length,"/T");if(part==NULL)part=b2026_strdup_simple("");local_ft=b2026_pdf_dict_name(o->body,o->body_length,"/FT");ft=local_ft!=NULL?local_ft:inherit_ft;if(!b2026_pdf_dict_integer(o->body,o->body_length,"/Ff",&flags))flags=inherit_flags;full=b2026_pdf_form_full_name(prefix,part);if(part==NULL||full==NULL||!b2026_pdf_form_kids(doc,oi,&kids,&kc))goto fail;for(i=0;i<kc;++i)if(!b2026_pdf_dict_name_is(doc->objects[kids[i]].body,doc->objects[kids[i]].body_length,"/Subtype","Widget"))all_widgets=0;terminal=ft!=NULL&&(kc==0||all_widgets||b2026_pdf_dict_name_is(o->body,o->body_length,"/Subtype","Widget"));if(terminal){if(*full=='\0'||!b2026_pdf_form_collect_terminal(doc,oi,full,ft,flags,kids,kc,list))goto fail;}else for(i=0;i<kc;++i)if(!b2026_pdf_form_walk(doc,kids[i],full,ft,flags,depth+1,list,seen))goto fail;free(part);free(full);free(local_ft);free(kids);return 1;fail:free(part);free(full);free(local_ft);free(kids);return 0;
}
static int b2026_pdf_form_collect(B2026PdfDocument*doc,B2026PdfFormList*list){
    B2026PdfObject*root;B2026PdfKeyRange ar,fr;const unsigned char*abody;size_t an;char*direct=NULL;int*fields=NULL,count=0,i,ai;unsigned char*seen=NULL;list->acro_index=-1;if(doc->root_object<0)return 0;root=&doc->objects[doc->root_object];if(!b2026_pdf_tf_find_key(root->body,root->body_length,"/AcroForm",&ar))return 0;if(!ar.found)return 1;ai=b2026_pdf_form_ref_value(doc,root->body+ar.value_start,ar.value_end-ar.value_start);if(ai>=0){list->acro_index=ai;abody=doc->objects[ai].body;an=doc->objects[ai].body_length;}else{direct=b2026_pdf_tf_value_copy(doc,root->body+ar.value_start,ar.value_end-ar.value_start,0);if(direct==NULL)return 0;abody=(unsigned char*)direct;an=strlen(direct);}if(!b2026_pdf_tf_find_key(abody,an,"/Fields",&fr)||!fr.found||!b2026_pdf_form_refs(doc,abody+fr.value_start,fr.value_end-fr.value_start,&fields,&count)){free(direct);return 0;}seen=(unsigned char*)calloc((size_t)doc->object_count,1U);if(seen==NULL){free(direct);free(fields);return 0;}for(i=0;i<count;++i)if(!b2026_pdf_form_walk(doc,fields[i],"",NULL,0,0,list,seen)){free(direct);free(fields);free(seen);return 0;}free(direct);free(fields);free(seen);return 1;
}

static void b2026_pdf_form_pair_number(const char*t,const char*j,const char*e,double v){hash_set_number(t,j,v);hash_set_number(t,e,v);}
static void b2026_pdf_form_pair_string(const char*t,const char*j,const char*e,const char*v){hash_set_string(t,j,v!=NULL?v:"");hash_set_string(t,e,v!=NULL?v:"");}
static void b2026_pdf_form_key(char*out,size_t cap,int i,const char*field){snprintf(out,cap,"%d,%s",i,field);}
static void b2026_pdf_form_index_string(const char*t,int i,const char*j,const char*e,const char*v){char k[160];b2026_pdf_form_key(k,sizeof(k),i,j);hash_set_string(t,k,v!=NULL?v:"");b2026_pdf_form_key(k,sizeof(k),i,e);hash_set_string(t,k,v!=NULL?v:"");}
static void b2026_pdf_form_index_number(const char*t,int i,const char*j,const char*e,double v){char k[160];b2026_pdf_form_key(k,sizeof(k),i,j);hash_set_number(t,k,v);b2026_pdf_form_key(k,sizeof(k),i,e);hash_set_number(t,k,v);}
static int b2026_pdf_form_to_hash(const char*target,B2026PdfDocument*doc,B2026PdfFormList*list){
    HashVariable*h=ensure_local_hash(get_hash_frame(target),target);int i,j;if(h==NULL)return 0;clear_hash_entries(h);b2026_pdf_form_pair_number(target,"成功","ok",1);b2026_pdf_form_pair_string(target,"状態","status",list->count?"OK":"EMPTY");b2026_pdf_form_pair_number(target,"件数","count",list->count);b2026_pdf_form_pair_number(target,"総ページ数","pageCount",doc->page_count);for(i=0;i<list->count;++i){B2026PdfFormField*f=&list->items[i];b2026_pdf_form_index_string(target,i+1,"名前","name",f->name);b2026_pdf_form_index_string(target,i+1,"種類","type",f->type);b2026_pdf_form_index_string(target,i+1,"値","value",f->value);b2026_pdf_form_index_string(target,i+1,"既定値","defaultValue",f->default_value);b2026_pdf_form_index_number(target,i+1,"ページ","page",f->page);b2026_pdf_form_index_number(target,i+1,"読取専用","readOnly",f->read_only);b2026_pdf_form_index_number(target,i+1,"必須","required",f->required);b2026_pdf_form_index_number(target,i+1,"複数行","multiline",f->multiline);b2026_pdf_form_index_number(target,i+1,"パスワード","password",f->password);b2026_pdf_form_index_number(target,i+1,"選択肢数","optionCount",f->option_count);for(j=0;j<f->option_count;++j){char a[160],b[160];snprintf(a,sizeof(a),"%d,選択肢,%d",i+1,j+1);snprintf(b,sizeof(b),"%d,option,%d",i+1,j+1);hash_set_string(target,a,f->options[j]);hash_set_string(target,b,f->options[j]);}}return 1;
}
static int b2026_pdf_form_error(int code,const char*op,const char*path,const char*detail){char msg[4096];snprintf(msg,sizeof(msg),"PDF.%s failed: path=%s: %s",op,path!=NULL?path:"",detail!=NULL?detail:"unknown error / 不明なエラー");basic_set_error_logged(code,msg,op,current_source_path,current_line,"PDF");b2026_try_append_log_line("__PDF_ERROR.log",msg);return 0;}
static int b2026_pdf_form_get(const char*target,int argc,const B2026PdfArg*args){
    B2026PdfDocument doc;B2026PdfFormList list;HashVariable*h;int rc;memset(&doc,0,sizeof(doc));memset(&list,0,sizeof(list));list.acro_index=-1;if(target==NULL||(h=ensure_local_hash(get_hash_frame(target),target))==NULL)return 0;clear_hash_entries(h);if(argc!=1||args[0].kind!=1||args[0].text==NULL)return b2026_pdf_form_error(4414,"GETFORMVALUES","","PDF path is required / PDFパスが必要です");rc=b2026_pdf_load(&doc,args[0].text,0);if(rc<=0){b2026_pdf_form_pair_number(target,"成功","ok",0);b2026_pdf_form_pair_string(target,"状態","status","FAILED");b2026_pdf_form_error(4415,"GETFORMVALUES",args[0].text,b2026_pdf_load_error(rc));goto fail;}if(!b2026_pdf_form_collect(&doc,&list)||!b2026_pdf_form_to_hash(target,&doc,&list)){clear_hash_entries(h);b2026_pdf_form_error(4416,"GETFORMVALUES",args[0].text,"AcroForm field tree is damaged, duplicated, or too deep / AcroFormフィールドツリーが破損・重複しているか深すぎます");goto fail;}b2026_pdf_form_free(&list);b2026_pdf_document_free(&doc);return 1;fail:b2026_pdf_form_free(&list);b2026_pdf_document_free(&doc);return 0;
}

static char*b2026_pdf_form_pdf_name(const char*s){static const char hx[]="0123456789ABCDEF";B2026PdfTextBuffer b;const unsigned char*p=(const unsigned char*)(s!=NULL?s:"");memset(&b,0,sizeof(b));if(!b2026_pdf_text_append_char(&b,'/'))goto fail;while(*p){unsigned char c=*p++;if(c<=0x20U||c>=0x7FU||strchr("#%()/<>[]{}",c)!=NULL){char z[3]={'#',hx[c>>4],hx[c&15U]};if(!b2026_pdf_text_append_bytes(&b,z,3U))goto fail;}else if(!b2026_pdf_text_append_char(&b,(char)c))goto fail;}return b2026_pdf_text_take(&b);fail:free(b.data);return NULL;}
static HashEntry*b2026_pdf_form_input(HashVariable*h,B2026PdfFormField*f,int index){HashEntry*e=find_hash_entry(h,f->name);char k[160];if(e!=NULL)return e;b2026_pdf_form_key(k,sizeof(k),index,"値");e=find_hash_entry(h,k);if(e!=NULL)return e;b2026_pdf_form_key(k,sizeof(k),index,"value");return find_hash_entry(h,k);}
static int b2026_pdf_form_option_index(B2026PdfFormField*f,const char*v){int i;for(i=0;i<f->option_count;++i)if(strcmp(f->options[i],v)==0)return i;return-1;}
static int b2026_pdf_form_is_off(const char*v){return v==NULL||*v=='\0'||strcmp(v,"0")==0||b2026_strcasecmp(v,"OFF")==0||b2026_strcasecmp(v,"FALSE")==0||b2026_strcasecmp(v,"NO")==0||strcmp(v,"いいえ")==0;}
static int b2026_pdf_form_text_appearance(B2026PdfDocument*doc,int widget,const char*value){
    B2026PdfObject*w=&doc->objects[widget];double r[4],width,height,size,y;int latin,japan,gs,ap,nonascii=0,i;B2026PdfTextBuffer content;char dict[512],cmd[1024],ref[96];char*hex=NULL;const char*p=value;if(b2026_pdf_number_array(w->body,w->body_length,"/Rect",r,4)!=4)return 0;width=fabs(r[2]-r[0]);height=fabs(r[3]-r[1]);if(width<=1.0||height<=1.0)return 0;for(i=0;value[i];++i)if((unsigned char)value[i]>=0x80U){nonascii=1;break;}if(!b2026_pdf_pd_fonts(doc,1.0,nonascii,0,&latin,&japan,&gs))return 0;memset(&content,0,sizeof(content));snprintf(cmd,sizeof(cmd),"q 1 1 1 rg 0 0 %.6f %.6f re f 0.55 0.65 0.78 RG 1 w 0.5 0.5 %.6f %.6f re S 2 2 %.6f %.6f re W n\n",width,height,width-1.0,height-1.0,width-4.0,height-4.0);if(!b2026_pdf_text_append_bytes(&content,cmd,strlen(cmd)))goto fail;size=fmin(11.0,fmax(6.0,height*0.44));y=height-size-4.0;while(*p){const char*nl=strchr(p,'\n');size_t len=nl!=NULL?(size_t)(nl-p):strlen(p);char*line=(char*)malloc(len+1U);if(line==NULL)goto fail;memcpy(line,p,len);line[len]='\0';if(nonascii){hex=b2026_pdf_pd_utf16_hex(line);free(line);if(hex==NULL)goto fail;snprintf(cmd,sizeof(cmd),"BT /B2026JP %.6f Tf 0 g 1 0 0 1 4 %.6f Tm <%s> Tj ET\n",size,y,hex);free(hex);hex=NULL;}else{char*raw=b2026_pdf_pd_hex_bytes(line);free(line);if(raw==NULL)goto fail;snprintf(cmd,sizeof(cmd),"BT /B2026HF %.6f Tf 0 g 1 0 0 1 4 %.6f Tm <%s> Tj ET\n",size,y,raw);free(raw);}if(!b2026_pdf_text_append_bytes(&content,cmd,strlen(cmd)))goto fail;y-=size*1.25;if(nl==NULL||y<2.0)break;p=nl+1;}if(!b2026_pdf_text_append_bytes(&content,"Q",1U))goto fail;snprintf(dict,sizeof(dict),"/Type /XObject /Subtype /Form /FormType 1 /BBox [0 0 %.6f %.6f] /Resources << /Font << /B2026HF %d 0 R%s >> >>",width,height,doc->objects[latin].old_number,nonascii?" /B2026JP 0 0 R":"");if(nonascii){char*mark=strstr(dict,"/B2026JP 0 0 R");if(mark!=NULL){char tail[160];snprintf(tail,sizeof(tail),"/B2026JP %d 0 R >> >>",doc->objects[japan].old_number);snprintf(mark,sizeof(dict)-(size_t)(mark-dict),"%s",tail);}}ap=b2026_pdf_tf_add_stream_bytes(doc,dict,(unsigned char*)(content.data!=NULL?content.data:""),content.used);if(ap<0)goto fail;snprintf(ref,sizeof(ref),"<< /N %d 0 R >>",doc->objects[ap].old_number);if(!b2026_pdf_tf_set_key(doc,widget,"/AP",ref,0))goto fail;free(content.data);return 1;fail:free(hex);free(content.data);return 0;
}
static int b2026_pdf_form_set_field(B2026PdfDocument*doc,B2026PdfFormField*f,const char*value){
    char*pdf=NULL,*state=NULL;const char*stored=value;int i,index;if(f->read_only||strcmp(f->type,"SIGNATURE")==0||strcmp(f->type,"PUSHBUTTON")==0||f->password)return 0;if(strcmp(f->type,"TEXT")==0){int maxlen=0;if(b2026_pdf_dict_integer(doc->objects[f->object_index].body,doc->objects[f->object_index].body_length,"/MaxLen",&maxlen)&&maxlen>0&&utf8_codepoint_count(value)>maxlen)return 0;pdf=b2026_pdf_metadata_pdf_hex(value);if(pdf==NULL||!b2026_pdf_tf_set_key(doc,f->object_index,"/V",pdf,0)){free(pdf);return 0;}free(pdf);for(i=0;i<f->widget_count;++i)if(!b2026_pdf_form_text_appearance(doc,f->widgets[i],value))return 0;}else if(strcmp(f->type,"COMBOBOX")==0||strcmp(f->type,"LISTBOX")==0){index=b2026_pdf_form_option_index(f,value);if(index<0&&(!(f->flags&262144)||strcmp(f->type,"COMBOBOX")!=0))return 0;pdf=b2026_pdf_metadata_pdf_hex(value);if(pdf==NULL||!b2026_pdf_tf_set_key(doc,f->object_index,"/V",pdf,0)){free(pdf);return 0;}free(pdf);if(index>=0){char z[64];snprintf(z,sizeof(z),"[%d]",index);if(!b2026_pdf_tf_set_key(doc,f->object_index,"/I",z,0))return 0;}else if(!b2026_pdf_tf_set_key(doc,f->object_index,"/I",NULL,1))return 0;for(i=0;i<f->widget_count;++i)if(!b2026_pdf_form_text_appearance(doc,f->widgets[i],value))return 0;}else if(strcmp(f->type,"CHECKBOX")==0||strcmp(f->type,"RADIO")==0){const char*chosen=value;if(strcmp(f->type,"CHECKBOX")==0){if(b2026_pdf_form_is_off(value))chosen="Off";else if(f->option_count>0)chosen=f->options[0];else chosen="Yes";}else if(b2026_pdf_form_is_off(value))chosen="Off";else if(b2026_pdf_form_option_index(f,value)<0)return 0;stored=chosen;state=b2026_pdf_form_pdf_name(chosen);if(state==NULL||!b2026_pdf_tf_set_key(doc,f->object_index,"/V",state,0)){free(state);return 0;}for(i=0;i<f->widget_count;++i){const char*ws=strcmp(chosen,"Off")==0?"Off":chosen;if(strcmp(f->type,"RADIO")==0){B2026PdfFormField temp;memset(&temp,0,sizeof(temp));if(!b2026_pdf_form_button_states(doc,&temp,f->widgets[i])){free(state);return 0;}if(b2026_pdf_form_option_index(&temp,chosen)<0)ws="Off";{int j;for(j=0;j<temp.option_count;++j)free(temp.options[j]);free(temp.options);}}{char*n=b2026_pdf_form_pdf_name(ws);int ok=n!=NULL&&b2026_pdf_tf_set_key(doc,f->widgets[i],"/AS",n,0);free(n);if(!ok){free(state);return 0;}}}free(state);}else return 0;free(f->value);f->value=b2026_strdup_simple(stored);if(f->value==NULL)return 0;f->changed=1;return 1;
}
static int b2026_pdf_form_apply(B2026PdfDocument*doc,B2026PdfFormList*list,HashVariable*h,int*changed){int i;*changed=0;for(i=0;i<list->count;++i){HashEntry*e=b2026_pdf_form_input(h,&list->items[i],i+1);const char*v;if(e==NULL)continue;v=hash_value_as_text(&e->value);if(v==NULL||strlen(v)>1048576U||!b2026_pdf_form_set_field(doc,&list->items[i],v))return 0;++*changed;}return *changed>0;}
static int b2026_pdf_form_verify(const char*path,B2026PdfFormList*expected){B2026PdfDocument doc;B2026PdfFormList actual;int rc,i,j,ok=0;memset(&doc,0,sizeof(doc));memset(&actual,0,sizeof(actual));actual.acro_index=-1;rc=b2026_pdf_load(&doc,path,0);if(rc<=0||!b2026_pdf_form_collect(&doc,&actual)||actual.count!=expected->count)goto done;for(i=0;i<expected->count;++i)if(expected->items[i].changed){for(j=0;j<actual.count;++j)if(strcmp(actual.items[j].name,expected->items[i].name)==0)break;if(j==actual.count||strcmp(actual.items[j].value,expected->items[i].value)!=0||actual.items[j].widget_count==0){char z[512];snprintf(z,sizeof(z),"form verification mismatch: field=%s expected=%s actual=%s widgets=%d",expected->items[i].name,expected->items[i].value,j<actual.count?actual.items[j].value:"<missing>",j<actual.count?actual.items[j].widget_count:0);b2026_pdf_log_warning(z);goto done;}for(rc=0;rc<actual.items[j].widget_count;++rc){B2026PdfKeyRange ap;B2026PdfObject*w=&doc.objects[actual.items[j].widgets[rc]];if(!b2026_pdf_tf_find_key(w->body,w->body_length,"/AP",&ap)||!ap.found)goto done;}}ok=1;done:b2026_pdf_form_free(&actual);b2026_pdf_document_free(&doc);return ok;}
static const char*b2026_pdf_form_edit(const char*operation,int argc,const B2026PdfArg*args){
    int separate,source_index,rc,i,changed=0;const char*source;char*output=NULL,*stage=NULL;HashVariable*h=NULL;B2026PdfDocument doc;B2026PdfFormList list;B2026PdfPageList pages;const char*result;memset(&doc,0,sizeof(doc));memset(&list,0,sizeof(list));memset(&pages,0,sizeof(pages));list.acro_index=-1;if((argc!=2&&argc!=3)||!b2026_pdf_tf_hash(&args[argc-1],&h))return b2026_pdf_fail(4417,"","SETFORMVALUES requires path$, values{} or output$, source$, values{} / フォーム設定の引数が正しくありません");separate=argc==3;source_index=separate?1:0;if(args[0].kind!=1||args[0].text==NULL||args[source_index].kind!=1||args[source_index].text==NULL)return b2026_pdf_fail(4417,"","PDF path must be a string / PDFパスは文字列で指定してください");source=args[source_index].text;output=b2026_pdf_output_path(args[0].text);if(output==NULL)goto memory_fail;rc=b2026_pdf_load(&doc,source,4);if(rc<=0){b2026_pdf_form_error(4418,operation,source,b2026_pdf_load_error(rc));goto fail;}if(b2026_pdf_memfind(doc.bytes,doc.length,"/XFA",4U)!=NULL||b2026_pdf_memfind(doc.bytes,doc.length,"/JavaScript",11U)!=NULL||b2026_pdf_memfind(doc.bytes,doc.length,"/JS",3U)!=NULL){b2026_pdf_form_error(4419,operation,source,"XFA or JavaScript form was detected; edit refused / XFAまたはJavaScriptフォームを検出したため編集を拒否しました");goto fail;}if(!b2026_pdf_form_collect(&doc,&list)||list.acro_index<0||list.count==0){b2026_pdf_form_error(4420,operation,source,"editable AcroForm fields were not found / 編集可能なAcroFormフィールドがありません");goto fail;}if(!b2026_pdf_form_apply(&doc,&list,h,&changed)){b2026_pdf_form_error(4421,operation,source,"form values are invalid, read-only, unsupported, or no matching field was found / フォーム値が不正・読取専用・未対応、または一致するフィールドがありません");goto fail;}if(!b2026_pdf_tf_set_key(&doc,list.acro_index,"/NeedAppearances","false",0)||!b2026_pdf_tf_set_key(&doc,doc.root_object,"/Type",NULL,1)||!b2026_pdf_tf_set_key(&doc,doc.root_object,"/Pages",NULL,1))goto memory_fail;for(i=0;i<doc.page_count;++i)if(!b2026_pdf_pages_push(&pages,&doc,doc.page_objects[i],-1))goto memory_fail;stage=b2026_atomic_temp_path(output);if(stage==NULL||!b2026_pdf_write_output(stage,&doc,1,&pages,0,0,1)){b2026_pdf_form_error(4422,operation,output,"form PDF could not be staged or exceeded 2 GiB / フォームPDFを準備できないか2GiB上限を超えました");goto fail;}if(!b2026_pdf_form_verify(stage,&list)){b2026_pdf_form_error(4423,operation,output,"post-write form verification failed / 保存後のフォーム検証に失敗しました");goto fail;}if(!b2026_atomic_commit_file(stage,output)){b2026_pdf_form_error(4424,operation,output,"verified PDF could not be committed / 検証済みPDFを保存先へ反映できません");goto fail;}free(stage);stage=NULL;result=runtime_temp_string_copy(output);free(output);free(pages.items);b2026_pdf_form_free(&list);b2026_pdf_document_free(&doc);(void)changed;return result;memory_fail:b2026_pdf_form_error(4425,operation,source,"out of memory / メモリ不足です");fail:if(stage!=NULL){b2026_atomic_discard_file(stage);free(stage);}free(output);free(pages.items);b2026_pdf_form_free(&list);b2026_pdf_document_free(&doc);return runtime_temp_string_copy("");
}
