/* BASIC2026 portable PDF page-box, margin and overlay editor. */
typedef struct { size_t key_start,value_start,value_end,dict_end; int found; } B2026PdfKeyRange;

static size_t b2026_pdf_tf_space(const unsigned char *s,size_t n,size_t p){
    for(;;){while(p<n&&isspace(s[p]))++p;if(p<n&&s[p]=='%'){while(p<n&&s[p]!='\r'&&s[p]!='\n')++p;continue;}break;}return p;
}

static size_t b2026_pdf_tf_value_end(const unsigned char *s,size_t n,size_t p,int depth){
    size_t q;if(depth>128)return n;p=b2026_pdf_tf_space(s,n,p);if(p>=n)return n;
    if(s[p]=='('){int level=1;++p;while(p<n&&level){if(s[p]=='\\'){p+=p+1U<n?2U:1U;continue;}if(s[p]=='(')++level;else if(s[p]==')')--level;++p;}return p;}
    if(s[p]=='['){++p;while((p=b2026_pdf_tf_space(s,n,p))<n&&s[p]!=']')p=b2026_pdf_tf_value_end(s,n,p,depth+1);return p<n?p+1U:p;}
    if(s[p]=='<'&&p+1U<n&&s[p+1U]=='<'){p+=2U;while((p=b2026_pdf_tf_space(s,n,p))<n){if(p+1U<n&&s[p]=='>'&&s[p+1U]=='>')return p+2U;if(s[p]=='/'){++p;while(p<n&&!b2026_pdf_is_delim(s[p]))++p;p=b2026_pdf_tf_value_end(s,n,p,depth+1);}else ++p;}return p;}
    if(s[p]=='<'){++p;while(p<n&&s[p]!='>')++p;return p<n?p+1U:p;}
    if(s[p]=='/'){++p;while(p<n&&!b2026_pdf_is_delim(s[p]))++p;return p;}
    q=p;while(q<n&&!b2026_pdf_is_delim(s[q]))++q;
    if(q>p&&(isdigit(s[p])||s[p]=='+'||s[p]=='-'||s[p]=='.')){size_t r=b2026_pdf_tf_space(s,n,q),t=r;while(t<n&&!b2026_pdf_is_delim(s[t]))++t;if(t>r&&isdigit(s[r])){size_t u=b2026_pdf_tf_space(s,n,t);if(u<n&&s[u]=='R')return u+1U;}}
    return q;
}

static int b2026_pdf_tf_find_key(const unsigned char *body,size_t n,const char *key,B2026PdfKeyRange *out){
    size_t p=0U,klen=strlen(key);memset(out,0,sizeof(*out));
    while(p+1U<n&&!(body[p]=='<'&&body[p+1U]=='<'))++p;if(p+1U>=n)return 0;p+=2U;
    while((p=b2026_pdf_tf_space(body,n,p))<n){size_t ks,ke,vs,ve;if(p+1U<n&&body[p]=='>'&&body[p+1U]=='>'){out->dict_end=p;return 1;}if(body[p]!='/'){++p;continue;}ks=p++;while(p<n&&!b2026_pdf_is_delim(body[p]))++p;ke=p;vs=b2026_pdf_tf_space(body,n,p);ve=b2026_pdf_tf_value_end(body,n,vs,0);if(ke-ks==klen&&memcmp(body+ks,key,klen)==0){out->key_start=ks;out->value_start=vs;out->value_end=ve;out->found=1;}p=ve;}
    return 0;
}

static int b2026_pdf_tf_set_key(B2026PdfDocument *doc,int oi,const char *key,const char *value,int remove){
    B2026PdfObject *o;B2026PdfKeyRange r;B2026PdfTextBuffer out;size_t cut_start,cut_end,insert;
    if(oi<0||oi>=doc->object_count)return 0;o=&doc->objects[oi];if(!b2026_pdf_tf_find_key(o->body,o->body_length,key,&r))return 0;memset(&out,0,sizeof(out));
    cut_start=r.found?r.key_start:r.dict_end;cut_end=r.found?r.value_end:r.dict_end;insert=cut_start;
    if(!b2026_pdf_text_append_bytes(&out,(const char*)o->body,insert))goto fail;
    if(!remove){if(out.used>0U&&!isspace((unsigned char)out.data[out.used-1U])&&!b2026_pdf_text_append_char(&out,' '))goto fail;if(!b2026_pdf_text_append_bytes(&out,key,strlen(key))||!b2026_pdf_text_append_char(&out,' ')||!b2026_pdf_text_append_bytes(&out,value,strlen(value))||!b2026_pdf_text_append_char(&out,' '))goto fail;}
    if(!b2026_pdf_text_append_bytes(&out,(const char*)o->body+cut_end,o->body_length-cut_end))goto fail;
    free(o->body);o->body=(unsigned char*)b2026_pdf_text_take(&out);o->body_length=strlen((char*)o->body);return 1;
fail:free(out.data);return 0;
}

static int b2026_pdf_tf_next_old(B2026PdfDocument *doc){int i,max=0;for(i=0;i<doc->object_count;++i)if(doc->objects[i].old_number>max)max=doc->objects[i].old_number;return max+1;}
static int b2026_pdf_tf_add_body(B2026PdfDocument *doc,const char *body){int number=b2026_pdf_tf_next_old(doc);if(!b2026_pdf_add_object(doc,number,0,(const unsigned char*)body,strlen(body)))return -1;return b2026_pdf_object_lookup(doc,number,0);}
static int b2026_pdf_tf_add_stream(B2026PdfDocument *doc,const char *payload){B2026PdfTextBuffer b;char h[128];int number,index;memset(&b,0,sizeof(b));snprintf(h,sizeof(h),"<< /Length %lu >>\nstream\n",(unsigned long)strlen(payload));if(!b2026_pdf_text_append_bytes(&b,h,strlen(h))||!b2026_pdf_text_append_bytes(&b,payload,strlen(payload))||!b2026_pdf_text_append_bytes(&b,"\nendstream",10U)){free(b.data);return -1;}number=b2026_pdf_tf_next_old(doc);if(!b2026_pdf_add_object(doc,number,0,(unsigned char*)b.data,b.used)){free(b.data);return -1;}free(b.data);index=b2026_pdf_object_lookup(doc,number,0);return index;}

static HashEntry *b2026_pdf_tf_entry(HashVariable *h,const char *jp,const char *en){HashEntry *e;if(h==NULL)return NULL;e=jp!=NULL?find_hash_entry(h,jp):NULL;return e!=NULL?e:(en!=NULL?find_hash_entry(h,en):NULL);}
static int b2026_pdf_tf_number(HashVariable *h,const char *jp,const char *en,double *v,int *present){HashEntry *e=b2026_pdf_tf_entry(h,jp,en);*present=e!=NULL;if(e==NULL)return 1;if(e->value.type!=TYPE_NUMBER||isnan(e->value.val.number)||!isfinite(e->value.val.number))return 0;*v=e->value.val.number;return 1;}
static const char *b2026_pdf_tf_text(HashVariable *h,const char *jp,const char *en){HashEntry *e=b2026_pdf_tf_entry(h,jp,en);return e!=NULL&&e->value.type!=TYPE_NUMBER?hash_value_as_text(&e->value):NULL;}
static int b2026_pdf_tf_true(HashVariable *h,const char *jp,const char *en){HashEntry *e=b2026_pdf_tf_entry(h,jp,en);return e!=NULL&&e->value.type==TYPE_NUMBER&&!isnan(e->value.val.number)&&e->value.val.number!=0.0;}
static double b2026_pdf_tf_unit(HashVariable *h){const char *u=b2026_pdf_tf_text(h,"単位","unit");if(u==NULL||b2026_strcasecmp(u,"PT")==0)return 1.0;if(b2026_strcasecmp(u,"MM")==0)return 72.0/25.4;if(b2026_strcasecmp(u,"CM")==0)return 72.0/2.54;if(b2026_strcasecmp(u,"IN")==0||b2026_strcasecmp(u,"INCH")==0)return 72.0;return -1.0;}

static int b2026_pdf_tf_hash(const B2026PdfArg *arg,HashVariable **out){if(arg==NULL||arg->kind!=3||arg->hash_name==NULL)return 0;*out=find_local_hash(get_hash_frame(arg->hash_name),arg->hash_name);return *out!=NULL;}
static void b2026_pdf_tf_box_text(char out[160],const double b[4]){snprintf(out,160,"[%.17g %.17g %.17g %.17g]",b[0],b[1],b[2],b[3]);}

static int b2026_pdf_tf_setbox_values(HashVariable *h,double userunit,double out[4],int *remove){
    double factor=b2026_pdf_tf_unit(h),x=0,y=0,w=0,hh=0,l=0,b=0,r=0,t=0;int px,py,pw,ph,pl,pb,pr,pt;
    *remove=b2026_pdf_tf_true(h,"削除","remove");if(*remove)return 1;if(factor<=0.0||userunit<=0.0)return 0;
    if(!b2026_pdf_tf_number(h,"x","x",&x,&px)||!b2026_pdf_tf_number(h,"y","y",&y,&py)||!b2026_pdf_tf_number(h,"横幅","width",&w,&pw)||!b2026_pdf_tf_number(h,"縦幅","height",&hh,&ph)||!b2026_pdf_tf_number(h,"左","left",&l,&pl)||!b2026_pdf_tf_number(h,"下","bottom",&b,&pb)||!b2026_pdf_tf_number(h,"右","right",&r,&pr)||!b2026_pdf_tf_number(h,"上","top",&t,&pt))return 0;
    if(px||py||pw||ph){if(!(px&&py&&pw&&ph)||pl||pb||pr||pt||w<=0.0||hh<=0.0)return 0;out[0]=x*factor/userunit;out[1]=y*factor/userunit;out[2]=(x+w)*factor/userunit;out[3]=(y+hh)*factor/userunit;}
    else{if(!(pl&&pb&&pr&&pt)||r<=l||t<=b)return 0;out[0]=l*factor/userunit;out[1]=b*factor/userunit;out[2]=r*factor/userunit;out[3]=t*factor/userunit;}
    return 1;
}

static int b2026_pdf_tf_box_key(const char *s,const char **key){if(s==NULL)return 0;if(b2026_strcasecmp(s,"MEDIA")==0||b2026_strcasecmp(s,"MEDIABOX")==0||strcmp(s,"用紙")==0)*key="/MediaBox";else if(b2026_strcasecmp(s,"CROP")==0||b2026_strcasecmp(s,"CROPBOX")==0||strcmp(s,"表示")==0)*key="/CropBox";else if(b2026_strcasecmp(s,"TRIM")==0||b2026_strcasecmp(s,"TRIMBOX")==0||strcmp(s,"仕上がり")==0)*key="/TrimBox";else if(b2026_strcasecmp(s,"BLEED")==0||b2026_strcasecmp(s,"BLEEDBOX")==0||strcmp(s,"塗り足し")==0)*key="/BleedBox";else if(b2026_strcasecmp(s,"ART")==0||b2026_strcasecmp(s,"ARTBOX")==0||strcmp(s,"アート")==0)*key="/ArtBox";else return 0;return 1;}

static int b2026_pdf_tf_append_contents(B2026PdfDocument *doc,int page_index,int before_index,int after_index){
    B2026PdfObject *page;B2026PdfKeyRange r;B2026PdfTextBuffer v;char ref[64];memset(&v,0,sizeof(v));page=&doc->objects[page_index];if(!b2026_pdf_tf_find_key(page->body,page->body_length,"/Contents",&r))return 0;
    if(!b2026_pdf_text_append_char(&v,'['))goto fail;
    if(before_index>=0){snprintf(ref,sizeof(ref)," %d 0 R",doc->objects[before_index].old_number);if(!b2026_pdf_text_append_bytes(&v,ref,strlen(ref)))goto fail;}
    if(r.found){size_t a=r.value_start,z=r.value_end;a=b2026_pdf_tf_space(page->body,page->body_length,a);while(z>a&&isspace(page->body[z-1U]))--z;if(a<z&&page->body[a]=='['&&page->body[z-1U]==']'){++a;--z;}if(!b2026_pdf_text_append_char(&v,' ')||!b2026_pdf_text_append_bytes(&v,(const char*)page->body+a,z-a))goto fail;}
    if(after_index>=0){snprintf(ref,sizeof(ref)," %d 0 R",doc->objects[after_index].old_number);if(!b2026_pdf_text_append_bytes(&v,ref,strlen(ref)))goto fail;}
    if(!b2026_pdf_text_append_bytes(&v," ]",2U))goto fail;if(!b2026_pdf_tf_set_key(doc,page_index,"/Contents",v.data,0))goto fail;free(v.data);return 1;
fail:free(v.data);return 0;
}

static int b2026_pdf_tf_set_box(B2026PdfDocument *doc,unsigned char *selected,const char *box_name,HashVariable *h){
    const char *key;int i,remove;if(!b2026_pdf_tf_box_key(box_name,&key))return 0;if(strcmp(key,"/MediaBox")==0&&b2026_pdf_tf_true(h,"削除","remove"))return 0;
    for(i=0;i<doc->page_count;++i)if(selected[i]){int oi=doc->page_objects[i];double uu=1.0,b[4],media[4];char value[160];if(b2026_pdf_page_direct_number(doc,oi,"/UserUnit",&uu)<=0)uu=1.0;if(!b2026_pdf_tf_setbox_values(h,uu,b,&remove))return 0;if(remove){if(!b2026_pdf_tf_set_key(doc,oi,key,NULL,1))return 0;continue;}if(strcmp(key,"/MediaBox")!=0&&b2026_pdf_page_box(doc,oi,"/MediaBox",media)){int adjusted=0;if(b[0]<media[0]){b[0]=media[0];adjusted=1;}if(b[1]<media[1]){b[1]=media[1];adjusted=1;}if(b[2]>media[2]){b[2]=media[2];adjusted=1;}if(b[3]>media[3]){b[3]=media[3];adjusted=1;}if(adjusted)b2026_pdf_log_warning("ページボックスをMediaBox内へ補正しました。 / Page box was clamped to MediaBox.");if(b[2]<=b[0]||b[3]<=b[1])return 0;}b2026_pdf_tf_box_text(value,b);if(!b2026_pdf_tf_set_key(doc,oi,key,value,0))return 0;
        if(strcmp(key,"/MediaBox")==0){const char *sub[4]={"/CropBox","/TrimBox","/BleedBox","/ArtBox"};int k,warned=0;for(k=0;k<4;++k){double q[4];if(b2026_pdf_page_direct_box(doc,oi,sub[k],q)>0){if(q[0]<b[0]){q[0]=b[0];warned=1;}if(q[1]<b[1]){q[1]=b[1];warned=1;}if(q[2]>b[2]){q[2]=b[2];warned=1;}if(q[3]>b[3]){q[3]=b[3];warned=1;}if(q[2]<=q[0]||q[3]<=q[1]){if(!b2026_pdf_tf_set_key(doc,oi,sub[k],NULL,1))return 0;}else{b2026_pdf_tf_box_text(value,q);if(!b2026_pdf_tf_set_key(doc,oi,sub[k],value,0))return 0;}}}if(warned)b2026_pdf_log_warning("MediaBox変更に合わせて下位ページボックスを補正しました。 / Subordinate page boxes were clamped after MediaBox changed.");}}
    return 1;
}

static int b2026_pdf_tf_margin_values(HashVariable *h,double factor,double uu,double m[4]){double all=0,v=0;int p=0,i;const char *jp[4]={"上","右","下","左"},*en[4]={"top","right","bottom","left"};if(factor<=0.0||uu<=0.0)return 0;if(!b2026_pdf_tf_number(h,"全体","all",&all,&p))return 0;if(!p)all=0.0;if(all<0.0)return 0;for(i=0;i<4;++i){int q=0;if(!b2026_pdf_tf_number(h,jp[i],en[i],&v,&q))return 0;m[i]=(q?v:all)*factor/uu;if(m[i]<0.0)return 0;}return 1;}

static void b2026_pdf_tf_margin_raw(int rot,const double m[4],double *dl,double *db,double *dr,double *dt,double *dx,double *dy){double top=m[0],right=m[1],bottom=m[2],left=m[3];rot=((rot%360)+360)%360;if(rot==90){*dl=top;*db=left;*dr=bottom;*dt=right;*dx=top;*dy=left;}else if(rot==180){*dl=right;*db=top;*dr=left;*dt=bottom;*dx=right;*dy=top;}else if(rot==270){*dl=bottom;*db=right;*dr=top;*dt=left;*dx=bottom;*dy=right;}else{*dl=left;*db=bottom;*dr=right;*dt=top;*dx=left;*dy=bottom;}}

static int b2026_pdf_tf_shift_number_array(B2026PdfDocument *doc,int oi,const char *key,double dx,double dy){
    B2026PdfObject *o;B2026PdfKeyRange r;B2026PdfTextBuffer b;size_t p,end;int index=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,key,&r))return 0;if(!r.found)return 1;p=b2026_pdf_tf_space(o->body,o->body_length,r.value_start);if(p>=r.value_end||o->body[p]!='[')return 1;end=r.value_end;memset(&b,0,sizeof(b));if(!b2026_pdf_text_append_char(&b,'['))goto fail;++p;while(p<end){char *e;double v;p=b2026_pdf_tf_space(o->body,end,p);if(p>=end||o->body[p]==']')break;if(o->body[p]=='['||o->body[p]==']'){if(!b2026_pdf_text_append_char(&b,(char)o->body[p++]))goto fail;continue;}errno=0;v=strtod((const char*)o->body+p,&e);if(e==(char*)o->body+p||errno==ERANGE||!isfinite(v)){++p;continue;}v+=(index++%2)==0?dx:dy;{char number[64];snprintf(number,sizeof(number)," %.17g",v);if(!b2026_pdf_text_append_bytes(&b,number,strlen(number)))goto fail;}p=(size_t)(e-(char*)o->body);}if(!b2026_pdf_text_append_bytes(&b," ]",2U)||!b2026_pdf_tf_set_key(doc,oi,key,b.data,0))goto fail;free(b.data);return 1;fail:free(b.data);return 0;
}

static int b2026_pdf_tf_shift_annotations(B2026PdfDocument *doc,int page_index,double dx,double dy){
    B2026PdfObject *page=&doc->objects[page_index];B2026PdfKeyRange r;size_t p;if(!b2026_pdf_tf_find_key(page->body,page->body_length,"/Annots",&r))return 0;if(!r.found)return 1;p=r.value_start;while(p<r.value_end){char *e;long a,g;size_t q,u;int oi;if(!isdigit(page->body[p])){++p;continue;}a=strtol((const char*)page->body+p,&e,10);q=b2026_pdf_tf_space(page->body,r.value_end,(size_t)(e-(char*)page->body));if(q>=r.value_end||!isdigit(page->body[q])){++p;continue;}g=strtol((const char*)page->body+q,&e,10);u=b2026_pdf_tf_space(page->body,r.value_end,(size_t)(e-(char*)page->body));if(u<r.value_end&&page->body[u]=='R'&&a>0&&a<=INT_MAX&&g>=0&&g<=INT_MAX&&(oi=b2026_pdf_object_lookup(doc,(int)a,(int)g))>=0){if(!b2026_pdf_tf_shift_number_array(doc,oi,"/Rect",dx,dy)||!b2026_pdf_tf_shift_number_array(doc,oi,"/QuadPoints",dx,dy))return 0;p=u+1U;}else ++p;}return 1;
}

static int b2026_pdf_tf_add_margins(B2026PdfDocument *doc,unsigned char *selected,HashVariable *h){
    int i;double factor=b2026_pdf_tf_unit(h);const char *background=b2026_pdf_tf_text(h,"背景","background");if(background!=NULL&&b2026_strcasecmp(background,"TRANSPARENT")!=0&&strcmp(background,"透明")!=0){size_t z;if(background[0]!='#'||strlen(background)!=7U)return 0;for(z=1U;z<7U;++z)if(!isxdigit((unsigned char)background[z]))return 0;}
    for(i=0;i<doc->page_count;++i)if(selected[i]){int oi=doc->page_objects[i],rot=b2026_pdf_page_inherited_integer(doc,oi,"/Rotate",0),pre,post;double uu=1.0,m[4],media[4],old[4],dl,db,dr,dt,dx,dy;char box[160],payload[512];const char *keys[4]={"/CropBox","/TrimBox","/BleedBox","/ArtBox"};int k;
        if(b2026_pdf_page_direct_number(doc,oi,"/UserUnit",&uu)<=0)uu=1.0;if(!b2026_pdf_tf_margin_values(h,factor,uu,m)||!b2026_pdf_page_box(doc,oi,"/MediaBox",media))return 0;memcpy(old,media,sizeof(old));b2026_pdf_tf_margin_raw(rot,m,&dl,&db,&dr,&dt,&dx,&dy);media[0]-=dl;media[1]-=db;media[2]+=dr;media[3]+=dt;b2026_pdf_tf_box_text(box,media);if(!b2026_pdf_tf_set_key(doc,oi,"/MediaBox",box,0))return 0;
        for(k=0;k<4;++k){double b[4];int direct=b2026_pdf_page_direct_box(doc,oi,keys[k],b);if(direct>0){if(k==0){b[0]-=dl;b[1]-=db;b[2]+=dr;b[3]+=dt;}else{b[0]+=dx;b[1]+=dy;b[2]+=dx;b[3]+=dy;}b2026_pdf_tf_box_text(box,b);if(!b2026_pdf_tf_set_key(doc,oi,keys[k],box,0))return 0;}}
        if(!b2026_pdf_tf_shift_annotations(doc,oi,dx,dy))return 0;
        if(background==NULL||(b2026_strcasecmp(background,"TRANSPARENT")!=0&&strcmp(background,"透明")!=0)){unsigned int rgb=0xFFFFFFU;if(background!=NULL&&background[0]=='#'&&strlen(background)==7U)rgb=(unsigned int)strtoul(background+1,NULL,16);snprintf(payload,sizeof(payload),"q %.6g %.6g %.6g rg %.17g %.17g %.17g %.17g re f Q\nq 1 0 0 1 %.17g %.17g cm",((rgb>>16)&255U)/255.0,((rgb>>8)&255U)/255.0,(rgb&255U)/255.0,media[0],media[1],media[2]-media[0],media[3]-media[1],dx,dy);}else snprintf(payload,sizeof(payload),"q 1 0 0 1 %.17g %.17g cm",dx,dy);
        pre=b2026_pdf_tf_add_stream(doc,payload);post=b2026_pdf_tf_add_stream(doc,"Q");if(pre<0||post<0||!b2026_pdf_tf_append_contents(doc,oi,pre,post))return 0;
    }return 1;
}

static int b2026_pdf_tf_ref(const unsigned char *s,size_t n,int *number,int *generation){
    size_t p=b2026_pdf_tf_space(s,n,0U);char *e;long a,g;if(p>=n||!isdigit(s[p]))return 0;a=strtol((const char*)s+p,&e,10);if(e==(char*)s+p||a<=0||a>INT_MAX)return 0;p=b2026_pdf_tf_space(s,n,(size_t)(e-(char*)s));if(p>=n||!isdigit(s[p]))return 0;g=strtol((const char*)s+p,&e,10);if(e==(char*)s+p||g<0||g>INT_MAX)return 0;p=b2026_pdf_tf_space(s,n,(size_t)(e-(char*)s));if(p>=n||s[p]!='R')return 0;*number=(int)a;*generation=(int)g;return 1;
}

static int b2026_pdf_tf_inherited_value(B2026PdfDocument *doc,int oi,const char *key,const unsigned char **value,size_t *length){
    int depth;for(depth=0;depth<128&&oi>=0;++depth){B2026PdfObject *o=&doc->objects[oi];B2026PdfKeyRange r;int pn,pg;if(!b2026_pdf_tf_find_key(o->body,o->body_length,key,&r))return 0;if(r.found){*value=o->body+r.value_start;*length=r.value_end-r.value_start;return 1;}if(!b2026_pdf_named_ref(o->body,o->body_length,"/Parent",&pn,&pg))break;oi=b2026_pdf_object_lookup(doc,pn,pg);}return 0;
}

static int b2026_pdf_tf_rewrite_refs(B2026PdfTextBuffer *out,const unsigned char *src,size_t n,B2026PdfDocument *from,const int *map){
    size_t p=0U,limit=n;const unsigned char *stream=b2026_pdf_memfind(src,n,"stream",6U);if(stream!=NULL)limit=(size_t)(stream-src);
    while(p<limit){size_t start=p,q,r,u;long a,g;char *e;int oi;char ref[64];if(!isdigit(src[p])){if(!b2026_pdf_text_append_char(out,(char)src[p++]))return 0;continue;}start=p;a=strtol((const char*)src+p,&e,10);q=(size_t)(e-(char*)src);r=b2026_pdf_tf_space(src,limit,q);if(r>=limit||!isdigit(src[r])){if(!b2026_pdf_text_append_char(out,(char)src[p++]))return 0;continue;}g=strtol((const char*)src+r,&e,10);u=b2026_pdf_tf_space(src,limit,(size_t)(e-(char*)src));if(u>=limit||src[u]!='R'||a<=0||a>INT_MAX||g<0||g>INT_MAX||(oi=b2026_pdf_object_lookup(from,(int)a,(int)g))<0||map[oi]<0){if(!b2026_pdf_text_append_char(out,(char)src[p++]))return 0;continue;}snprintf(ref,sizeof(ref),"%d 0 R",map[oi]);if(!b2026_pdf_text_append_bytes(out,ref,strlen(ref)))return 0;p=u+1U;(void)start;}
    return limit==n||b2026_pdf_text_append_bytes(out,(const char*)src+limit,n-limit);
}

static int *b2026_pdf_tf_import(B2026PdfDocument *target,B2026PdfDocument *source){
    int *map=(int*)malloc((size_t)source->object_count*sizeof(*map));int i,next=b2026_pdf_tf_next_old(target);if(map==NULL&&source->object_count>0)return NULL;for(i=0;i<source->object_count;++i)map[i]=next+i;
    for(i=0;i<source->object_count;++i){B2026PdfTextBuffer b;memset(&b,0,sizeof(b));if(!b2026_pdf_tf_rewrite_refs(&b,source->objects[i].body,source->objects[i].body_length,source,map)||!b2026_pdf_add_object(target,map[i],0,(const unsigned char*)(b.data!=NULL?b.data:""),b.used)){free(b.data);free(map);return NULL;}free(b.data);}return map;
}

static int b2026_pdf_tf_stream_bytes(B2026PdfObject *o,unsigned char **data,size_t *length){
    const unsigned char *stream,*payload,*endstream;size_t n;int decoded_length=0;char *decoded;*data=NULL;*length=0U;stream=b2026_pdf_memfind(o->body,o->body_length,"stream",6U);if(stream==NULL)return 0;payload=stream+6U;if(payload<o->body+o->body_length&&*payload=='\r')++payload;if(payload<o->body+o->body_length&&*payload=='\n')++payload;endstream=b2026_pdf_memfind(payload,o->body_length-(size_t)(payload-o->body),"endstream",9U);if(endstream==NULL)return 0;n=(size_t)(endstream-payload);while(n>0U&&(payload[n-1U]=='\r'||payload[n-1U]=='\n'))--n;if(n>INT_MAX)return 0;
    if(b2026_pdf_memfind(o->body,(size_t)(stream-o->body),"/FlateDecode",12U)!=NULL){decoded=stbi_zlib_decode_malloc((const char*)payload,(int)n,&decoded_length);if(decoded==NULL||decoded_length<0){free(decoded);return 0;}*data=(unsigned char*)decoded;*length=(size_t)decoded_length;return 1;}
    if(b2026_pdf_memfind(o->body,(size_t)(stream-o->body),"/Filter",7U)!=NULL)return 0;*data=(unsigned char*)malloc(n+1U);if(*data==NULL)return 0;memcpy(*data,payload,n);(*data)[n]=0;*length=n;return 1;
}

static int b2026_pdf_tf_collect_content(B2026PdfDocument *doc,const unsigned char *value,size_t n,B2026PdfTextBuffer *out,int depth){
    size_t p=0U;int found=0;if(depth>8)return 0;while(p<n){char *e;long a,g;size_t q,r,u;int oi;unsigned char *bytes;size_t length;if(!isdigit(value[p])){++p;continue;}a=strtol((const char*)value+p,&e,10);q=(size_t)(e-(char*)value);r=b2026_pdf_tf_space(value,n,q);if(r>=n||!isdigit(value[r])){++p;continue;}g=strtol((const char*)value+r,&e,10);u=b2026_pdf_tf_space(value,n,(size_t)(e-(char*)value));if(u>=n||value[u]!='R'||a<=0||a>INT_MAX||g<0||g>INT_MAX||(oi=b2026_pdf_object_lookup(doc,(int)a,(int)g))<0){++p;continue;}if(b2026_pdf_tf_stream_bytes(&doc->objects[oi],&bytes,&length)){if(!b2026_pdf_text_append_bytes(out,(const char*)bytes,length)||!b2026_pdf_text_append_char(out,'\n')){free(bytes);return 0;}free(bytes);found=1;}else if(b2026_pdf_tf_collect_content(doc,doc->objects[oi].body,doc->objects[oi].body_length,out,depth+1))found=1;p=u+1U;}return found;
}

static int b2026_pdf_tf_add_stream_bytes(B2026PdfDocument *doc,const char *dictionary,const unsigned char *payload,size_t n){
    B2026PdfTextBuffer b;char length_text[96];int number,index;memset(&b,0,sizeof(b));snprintf(length_text,sizeof(length_text)," /Length %lu >>\nstream\n",(unsigned long)n);if(!b2026_pdf_text_append_bytes(&b,"<< ",3U)||!b2026_pdf_text_append_bytes(&b,dictionary!=NULL?dictionary:"",strlen(dictionary!=NULL?dictionary:""))||!b2026_pdf_text_append_bytes(&b,length_text,strlen(length_text))||!b2026_pdf_text_append_bytes(&b,(const char*)payload,n)||!b2026_pdf_text_append_bytes(&b,"\nendstream",10U)){free(b.data);return -1;}number=b2026_pdf_tf_next_old(doc);if(!b2026_pdf_add_object(doc,number,0,(const unsigned char*)b.data,b.used)){free(b.data);return -1;}free(b.data);index=b2026_pdf_object_lookup(doc,number,0);return index;
}

static char *b2026_pdf_tf_value_copy(B2026PdfDocument *doc,const unsigned char *value,size_t n,int resolve){
    int num,gen,oi;B2026PdfTextBuffer b;memset(&b,0,sizeof(b));if(resolve&&b2026_pdf_tf_ref(value,n,&num,&gen)&&(oi=b2026_pdf_object_lookup(doc,num,gen))>=0){if(!b2026_pdf_text_append_bytes(&b,(const char*)doc->objects[oi].body,doc->objects[oi].body_length))goto fail;}else if(!b2026_pdf_text_append_bytes(&b,(const char*)value,n))goto fail;return b2026_pdf_text_take(&b);fail:free(b.data);return NULL;
}

static char *b2026_pdf_tf_dict_add(const char *dict,const char *name,int number){
    B2026PdfTextBuffer b;size_t n,p;char entry[128];memset(&b,0,sizeof(b));if(dict==NULL)dict="<< >>";n=strlen(dict);p=n;while(p>1U&&!(dict[p-2U]=='>'&&dict[p-1U]=='>'))--p;if(p<=1U)return NULL;p-=2U;if(!b2026_pdf_text_append_bytes(&b,dict,p))goto fail;snprintf(entry,sizeof(entry)," %s %d 0 R >>",name,number);if(!b2026_pdf_text_append_bytes(&b,entry,strlen(entry)))goto fail;return b2026_pdf_text_take(&b);fail:free(b.data);return NULL;
}

static int b2026_pdf_tf_make_target_resources(B2026PdfDocument *doc,int page_index,const char *xname,int form_number,const char *gname,int gs_number){
    const unsigned char *v;size_t n;char *resources=NULL,*xobjects=NULL,*states=NULL,*next=NULL,*ref=NULL;int ri,number,gen,oi;B2026PdfKeyRange r;
    if(b2026_pdf_tf_inherited_value(doc,page_index,"/Resources",&v,&n))resources=b2026_pdf_tf_value_copy(doc,v,n,1);else resources=b2026_strdup_simple("<< >>");if(resources==NULL)goto fail;ri=b2026_pdf_tf_add_body(doc,resources);free(resources);resources=NULL;if(ri<0)goto fail;
    if(!b2026_pdf_tf_find_key(doc->objects[ri].body,doc->objects[ri].body_length,"/XObject",&r))goto fail;if(r.found)xobjects=b2026_pdf_tf_value_copy(doc,doc->objects[ri].body+r.value_start,r.value_end-r.value_start,1);else xobjects=b2026_strdup_simple("<< >>");next=b2026_pdf_tf_dict_add(xobjects,xname,form_number);free(xobjects);xobjects=NULL;if(next==NULL||!b2026_pdf_tf_set_key(doc,ri,"/XObject",next,0))goto fail;free(next);next=NULL;
    if(!b2026_pdf_tf_find_key(doc->objects[ri].body,doc->objects[ri].body_length,"/ExtGState",&r))goto fail;if(r.found)states=b2026_pdf_tf_value_copy(doc,doc->objects[ri].body+r.value_start,r.value_end-r.value_start,1);else states=b2026_strdup_simple("<< >>");next=b2026_pdf_tf_dict_add(states,gname,gs_number);free(states);states=NULL;if(next==NULL||!b2026_pdf_tf_set_key(doc,ri,"/ExtGState",next,0))goto fail;free(next);next=NULL;
    number=doc->objects[ri].old_number;{char buf[64];snprintf(buf,sizeof(buf),"%d 0 R",number);if(!b2026_pdf_tf_set_key(doc,page_index,"/Resources",buf,0))goto fail;}(void)gen;(void)oi;(void)ref;return 1;
fail:free(resources);free(xobjects);free(states);free(next);free(ref);return 0;
}

static void b2026_pdf_tf_raw_to_display(int rot,const double box[4],double x,double y,double *u,double *v){double w=box[2]-box[0],h=box[3]-box[1],px=x-box[0],py=y-box[1];rot=((rot%360)+360)%360;if(rot==90){*u=py;*v=w-px;}else if(rot==180){*u=w-px;*v=h-py;}else if(rot==270){*u=h-py;*v=px;}else{*u=px;*v=py;}}
static void b2026_pdf_tf_display_to_raw(int rot,const double box[4],double u,double v,double *x,double *y){double w=box[2]-box[0],h=box[3]-box[1];rot=((rot%360)+360)%360;if(rot==90){*x=box[0]+w-v;*y=box[1]+u;}else if(rot==180){*x=box[0]+w-u;*y=box[1]+h-v;}else if(rot==270){*x=box[0]+v;*y=box[1]+h-u;}else{*x=box[0]+u;*y=box[1]+v;}}

static int b2026_pdf_tf_overlay_options(HashVariable *h,double target_uu,double ow,double oh,double tw,double th,double *x,double *y,double *w,double *hh,double *angle,double *opacity,const char **blend){
    double factor=b2026_pdf_tf_unit(h),vx=0,vy=0,vw=0,vh=0;int px=0,py=0,pw=0,ph=0,pa=0,po=0;const char *place=b2026_pdf_tf_text(h,"配置","placement");if(factor<=0.0||target_uu<=0.0)return 0;if(!b2026_pdf_tf_number(h,"x","x",&vx,&px)||!b2026_pdf_tf_number(h,"y","y",&vy,&py)||!b2026_pdf_tf_number(h,"横幅","width",&vw,&pw)||!b2026_pdf_tf_number(h,"縦幅","height",&vh,&ph)||!b2026_pdf_tf_number(h,"回転","rotation",angle,&pa)||!b2026_pdf_tf_number(h,"不透明度","opacity",opacity,&po))return 0;if(!pa)*angle=0.0;if(!po)*opacity=1.0;if(*opacity<0.0||*opacity>1.0||pw!=ph||(pw&&(vw<=0.0||vh<=0.0)))return 0;*w=pw?vw*factor/target_uu:ow;*hh=ph?vh*factor/target_uu:oh;
    if(place!=NULL&&(b2026_strcasecmp(place,"FIT")==0||strcmp(place,"合わせる")==0)){double s=fmin(tw/ow,th/oh);*w=ow*s;*hh=oh*s;}else if(place!=NULL&&(b2026_strcasecmp(place,"FILL")==0||strcmp(place,"全面")==0)){double s=fmax(tw/ow,th/oh);*w=ow*s;*hh=oh*s;}else if(place!=NULL&&(b2026_strcasecmp(place,"STRETCH")==0||strcmp(place,"引き伸ばす")==0)){*w=tw;*hh=th;}
    *x=px?vx*factor/target_uu:(tw-*w)/2.0;*y=py?vy*factor/target_uu:(th-*hh)/2.0;*blend=b2026_pdf_tf_text(h,"合成","blend");if(*blend==NULL)*blend="NORMAL";if(b2026_strcasecmp(*blend,"NORMAL")!=0&&b2026_strcasecmp(*blend,"MULTIPLY")!=0&&b2026_strcasecmp(*blend,"SCREEN")!=0)return 0;return 1;
}

static int b2026_pdf_tf_overlay(B2026PdfDocument *target,unsigned char *selected,B2026PdfDocument *overlay,HashVariable *settings){
    int *map=NULL,*overlay_pages=NULL,target_count=0,overlay_count=0,i,j=0;HashEntry *opages=b2026_pdf_tf_entry(settings,"重ねるページ","overlayPages");
    for(i=0;i<target->page_count;++i)if(selected[i])++target_count;if(target_count<=0)return 0;
    if(opages!=NULL){B2026PdfArg a;unsigned char *pick=NULL;memset(&a,0,sizeof(a));if(opages->value.type==TYPE_NUMBER){a.kind=0;a.number=opages->value.val.number;}else{a.kind=1;a.text=hash_value_as_text(&opages->value);}if(!b2026_pdf_parse_page_spec(&a,overlay->page_count,&pick))return 0;for(i=0;i<overlay->page_count;++i)if(pick[i])++overlay_count;overlay_pages=(int*)malloc((size_t)overlay_count*sizeof(*overlay_pages));if(overlay_pages==NULL&&overlay_count>0){free(pick);return 0;}for(i=0,j=0;i<overlay->page_count;++i)if(pick[i])overlay_pages[j++]=i;free(pick);}else{overlay_count=overlay->page_count;overlay_pages=(int*)malloc((size_t)overlay_count*sizeof(*overlay_pages));if(overlay_pages==NULL&&overlay_count>0)return 0;for(i=0;i<overlay_count;++i)overlay_pages[i]=i;}
    if(overlay_count!=1&&overlay_count!=target_count){free(overlay_pages);return 0;}map=b2026_pdf_tf_import(target,overlay);if(map==NULL){free(overlay_pages);return 0;}
    for(i=0,j=0;i<target->page_count;++i)if(selected[i]){int tp=target->page_objects[i],op=overlay->page_objects[overlay_pages[overlay_count==1?0:j]],trot=b2026_pdf_page_inherited_integer(target,tp,"/Rotate",0),orot=b2026_pdf_page_inherited_integer(overlay,op,"/Rotate",0),form,gs,stream;double tb[4],ob[4],tuu=1.0,ouu=1.0,tw,th,ow,oh,x,y,w,h,angle,opacity,p0x,p0y,p1x,p1y,p2x,p2y;const unsigned char *cv,*rv;size_t cn,rn;B2026PdfTextBuffer content,resbuf;char formdict[1024],gsdict[192],payload[512],xname[64],gname[64];const char *blend,*bm;int rold,gold;memset(&content,0,sizeof(content));memset(&resbuf,0,sizeof(resbuf));
        if(!b2026_pdf_page_box(target,tp,"/CropBox",tb)&&!b2026_pdf_page_box(target,tp,"/MediaBox",tb))goto fail;if(!b2026_pdf_page_box(overlay,op,"/CropBox",ob)&&!b2026_pdf_page_box(overlay,op,"/MediaBox",ob))goto fail;if(b2026_pdf_page_direct_number(target,tp,"/UserUnit",&tuu)<=0)tuu=1.0;if(b2026_pdf_page_direct_number(overlay,op,"/UserUnit",&ouu)<=0)ouu=1.0;tw=((trot%180)==0?tb[2]-tb[0]:tb[3]-tb[1]);th=((trot%180)==0?tb[3]-tb[1]:tb[2]-tb[0]);ow=((orot%180)==0?ob[2]-ob[0]:ob[3]-ob[1])*ouu/tuu;oh=((orot%180)==0?ob[3]-ob[1]:ob[2]-ob[0])*ouu/tuu;if(ow<=0.0||oh<=0.0||!b2026_pdf_tf_overlay_options(settings,tuu,ow,oh,tw,th,&x,&y,&w,&h,&angle,&opacity,&blend))goto fail;
        if(!b2026_pdf_tf_inherited_value(overlay,op,"/Contents",&cv,&cn)||!b2026_pdf_tf_collect_content(overlay,cv,cn,&content,0))goto fail;if(b2026_pdf_tf_inherited_value(overlay,op,"/Resources",&rv,&rn)){int num,gen,roi;if(b2026_pdf_tf_ref(rv,rn,&num,&gen)&&(roi=b2026_pdf_object_lookup(overlay,num,gen))>=0){if(!b2026_pdf_tf_rewrite_refs(&resbuf,overlay->objects[roi].body,overlay->objects[roi].body_length,overlay,map))goto fail;}else if(!b2026_pdf_tf_rewrite_refs(&resbuf,rv,rn,overlay,map))goto fail;}else if(!b2026_pdf_text_append_bytes(&resbuf,"<< >>",5U))goto fail;
        snprintf(formdict,sizeof(formdict),"/Type /XObject /Subtype /Form /FormType 1 /BBox [%.17g %.17g %.17g %.17g] /Resources %s",ob[0],ob[1],ob[2],ob[3],resbuf.data!=NULL?resbuf.data:"<< >>");form=b2026_pdf_tf_add_stream_bytes(target,formdict,(const unsigned char*)(content.data!=NULL?content.data:""),content.used);free(content.data);content.data=NULL;free(resbuf.data);resbuf.data=NULL;if(form<0)goto fail;rold=target->objects[form].old_number;
        bm=b2026_strcasecmp(blend,"MULTIPLY")==0?"Multiply":b2026_strcasecmp(blend,"SCREEN")==0?"Screen":"Normal";snprintf(gsdict,sizeof(gsdict),"<< /Type /ExtGState /ca %.17g /CA %.17g /BM /%s >>",opacity,opacity,bm);gs=b2026_pdf_tf_add_body(target,gsdict);if(gs<0)goto fail;gold=target->objects[gs].old_number;snprintf(xname,sizeof(xname),"/B2026Ov%d",rold);snprintf(gname,sizeof(gname),"/B2026Gs%d",gold);if(!b2026_pdf_tf_make_target_resources(target,tp,xname,rold,gname,gold))goto fail;
        {double rad=angle*3.14159265358979323846/180.0,c=cos(rad),s=sin(rad),cx=x+w/2.0,cy=th-y-h/2.0,scale_x=w/ow,scale_y=h/oh;double rx[3]={ob[0],ob[0]+1.0,ob[0]},ry[3]={ob[1],ob[1],ob[1]+1.0},tx[3],ty[3];int q;for(q=0;q<3;++q){double u,v,du,dv,uu,vv;b2026_pdf_tf_raw_to_display(orot,ob,rx[q],ry[q],&u,&v);u*=ouu/tuu;v*=ouu/tuu;du=x+u*scale_x;dv=th-y-h+v*scale_y;uu=c*(du-cx)-s*(dv-cy)+cx;vv=s*(du-cx)+c*(dv-cy)+cy;b2026_pdf_tf_display_to_raw(trot,tb,uu,vv,&tx[q],&ty[q]);}p0x=tx[0];p0y=ty[0];p1x=tx[1];p1y=ty[1];p2x=tx[2];p2y=ty[2];snprintf(payload,sizeof(payload),"q %s gs %.17g %.17g %.17g %.17g %.17g %.17g cm %s Do Q",gname,p1x-p0x,p1y-p0y,p2x-p0x,p2y-p0y,p0x-(p1x-p0x)*ob[0]-(p2x-p0x)*ob[1],p0y-(p1y-p0y)*ob[0]-(p2y-p0y)*ob[1],xname);}
        stream=b2026_pdf_tf_add_stream(target,payload);if(stream<0||!b2026_pdf_tf_append_contents(target,tp,-1,stream))goto fail;++j;}
    free(map);free(overlay_pages);return 1;
fail:free(map);free(overlay_pages);return 0;
}

static const char *b2026_pdf_transform_edit(const char *operation,int argc,const B2026PdfArg *args){
    int separate=0,source_index=0,spec_index=1,hash_index=argc-1,rc,i,is_overlay=strcmp(operation,"OVERLAY")==0;const char *source,*box_name=NULL,*overlay_path=NULL;char *output=NULL;HashVariable *settings=NULL;B2026PdfDocument doc,overlay;B2026PdfPageList pages;unsigned char *selected=NULL;memset(&doc,0,sizeof(doc));memset(&overlay,0,sizeof(overlay));memset(&pages,0,sizeof(pages));
    if(strcmp(operation,"SETBOX")==0){if(argc!=4&&argc!=5)return b2026_pdf_fail(4170,"","invalid SETBOX arguments / ページボックス変更の引数が正しくありません");separate=argc==5;}
    else if(strcmp(operation,"ADDMARGINS")==0){if(argc!=3&&argc!=4)return b2026_pdf_fail(4170,"","invalid ADDMARGINS arguments / 余白追加の引数が正しくありません");separate=argc==4;}
    else if(is_overlay){if(argc<3||argc>5)return b2026_pdf_fail(4170,"","invalid OVERLAY arguments / 重ね描きの引数が正しくありません");separate=argc==5||(argc==4&&args[3].kind!=3);}
    else return b2026_pdf_fail(4170,"","unsupported PDF transform / 未対応のPDF変形です");
    source_index=separate?1:0;spec_index=separate?2:1;if(args[0].kind!=1||(separate&&args[1].kind!=1))return b2026_pdf_fail(4170,"","invalid PDF transform path / PDF変形のパスが正しくありません");
    if(args[hash_index].kind==3){if(!b2026_pdf_tf_hash(&args[hash_index],&settings))return b2026_pdf_fail(4170,"","invalid PDF transform settings / PDF変形設定が正しくありません");}else if(!is_overlay)return b2026_pdf_fail(4170,"","PDF transform settings are required / PDF変形設定が必要です");
    if(strcmp(operation,"SETBOX")==0){int bi=separate?3:2;if(args[bi].kind!=1)return b2026_pdf_fail(4170,"","box name must be a string / ボックス名は文字列で指定してください");box_name=args[bi].text;}
    if(is_overlay){int oi=separate?3:2;if(args[oi].kind!=1)return b2026_pdf_fail(4170,"","overlay PDF path must be a string / 重ねるPDFのパスは文字列で指定してください");overlay_path=args[oi].text;}
    source=args[source_index].text;output=b2026_pdf_output_path(args[0].text);if(source==NULL||output==NULL)goto fail;rc=b2026_pdf_load(&doc,source,1);if(rc<=0){b2026_pdf_fail(4171,source,b2026_pdf_load_error(rc));goto fail;}if(!b2026_pdf_parse_page_spec(&args[spec_index],doc.page_count,&selected)){b2026_pdf_fail(4172,source,"invalid page specification / ページ指定が正しくありません");goto fail;}
    if(strcmp(operation,"SETBOX")==0){if(!b2026_pdf_tf_set_box(&doc,selected,box_name,settings)){b2026_pdf_fail(4173,source,"invalid page-box settings / ページボックス設定が正しくありません");goto fail;}}
    else if(strcmp(operation,"ADDMARGINS")==0){if(!b2026_pdf_tf_add_margins(&doc,selected,settings)){b2026_pdf_fail(4174,source,"invalid margin settings / 余白設定が正しくありません");goto fail;}}
    else{rc=b2026_pdf_load(&overlay,overlay_path,1);if(rc<=0){b2026_pdf_fail(4176,overlay_path,b2026_pdf_load_error(rc));goto fail;}if(!b2026_pdf_tf_overlay(&doc,selected,&overlay,settings)){b2026_pdf_fail(4177,overlay_path,"overlay settings, page mapping, or PDF resources are unsupported / 重ね描きの設定・ページ対応・PDF資源を処理できません");goto fail;}}
    for(i=0;i<doc.page_count;++i)if(!b2026_pdf_pages_push(&pages,&doc,doc.page_objects[i],-1))goto memory_fail;if(!b2026_pdf_write_output(output,&doc,1,&pages,0,0,0)){b2026_pdf_fail(4175,output,"output could not be written atomically or exceeded 2 GiB / 原子的に保存できないか2GiB上限を超えました");goto fail;}
    {const char *result=runtime_temp_string_copy(output);free(selected);free(output);free(pages.items);b2026_pdf_document_free(&overlay);b2026_pdf_document_free(&doc);return result;}
memory_fail:b2026_pdf_fail(4199,source,"out of memory / メモリ不足です");
fail:free(selected);free(output);free(pages.items);b2026_pdf_document_free(&overlay);b2026_pdf_document_free(&doc);return runtime_temp_string_copy("");
}
