/* BASIC2026 portable PDF page-number/header/footer editor.
 * Decorations live in independent content streams.  A stable hexadecimal
 * identifier in each stream makes replacement and later removal deterministic. */
typedef struct {
    const char *slot[6];
    const char *page_spec,*exclude_spec,*odd_even,*number_format,*box_name,*position,*structure,*existing,*digit_font;
    const char *date_format,*time_format,*id;
    double start,digits,font_size,min_font_size,margin,header_y,footer_y,opacity,line_spacing;
    unsigned int color;
    int auto_shrink;
} B2026PdfDecorationSettings;

static const char *b2026_pdf_pd_text(HashVariable *h,const char *jp,const char *en,const char *fallback){
    const char *v=b2026_pdf_tf_text(h,jp,en);return v!=NULL?v:fallback;
}
static int b2026_pdf_pd_number(HashVariable *h,const char *jp,const char *en,double fallback,double *out){
    double v=0.0;int present=0;if(!b2026_pdf_tf_number(h,jp,en,&v,&present))return 0;*out=present?v:fallback;return 1;
}
static int b2026_pdf_pd_color(const char *s,unsigned int *out){
    size_t i;if(s==NULL){*out=0U;return 1;}if(s[0]!='#'||strlen(s)!=7U)return 0;for(i=1U;i<7U;++i)if(!isxdigit((unsigned char)s[i]))return 0;*out=(unsigned int)strtoul(s+1,NULL,16);return 1;
}
static int b2026_pdf_pd_settings(HashVariable *h,int page_number,B2026PdfDecorationSettings *s){
    static const char *jp[6]={"ヘッダー左","ヘッダー中央","ヘッダー右","フッター左","フッター中央","フッター右"};
    static const char *en[6]={"headerLeft","headerCenter","headerRight","footerLeft","footerCenter","footerRight"};
    double factor;const char *color;int i;memset(s,0,sizeof(*s));
    for(i=0;i<6;++i)s->slot[i]=b2026_pdf_tf_text(h,jp[i],en[i]);
    if(page_number&&s->slot[0]==NULL&&s->slot[1]==NULL&&s->slot[2]==NULL&&s->slot[3]==NULL&&s->slot[4]==NULL&&s->slot[5]==NULL)s->slot[4]="%NUMBER%";
    s->page_spec=b2026_pdf_pd_text(h,"対象ページ","pages","ALL");s->exclude_spec=b2026_pdf_tf_text(h,"除外ページ","excludePages");s->odd_even=b2026_pdf_pd_text(h,"偶奇","oddEven","ALL");
    s->number_format=b2026_pdf_pd_text(h,"番号形式","numberFormat","DECIMAL");s->box_name=b2026_pdf_pd_text(h,"基準ボックス","box","CROP");s->position=b2026_pdf_pd_text(h,"描画位置","position","FOREGROUND");s->structure=b2026_pdf_pd_text(h,"構造区分","structure","ARTIFACT");s->existing=b2026_pdf_pd_text(h,"既存装飾","existing","REPLACE");s->digit_font=b2026_pdf_pd_text(h,"数字書体","digitFont","GOTHIC");s->date_format=b2026_pdf_pd_text(h,"日付書式","dateFormat","%Y-%m-%d");s->time_format=b2026_pdf_pd_text(h,"時刻書式","timeFormat","%H:%M:%S");
    s->id=b2026_pdf_tf_text(h,"装飾ID","decorationId");if(s->id==NULL||*s->id=='\0')s->id=page_number?"BASIC2026_PAGE_NUMBER":"BASIC2026_HEADER_FOOTER";
    factor=b2026_pdf_tf_unit(h);if(factor<=0.0)return 0;
    if(!b2026_pdf_pd_number(h,"開始番号","startNumber",1.0,&s->start)||!b2026_pdf_pd_number(h,"桁数","digits",0.0,&s->digits)||!b2026_pdf_pd_number(h,"文字サイズ","fontSize",10.0,&s->font_size)||!b2026_pdf_pd_number(h,"最小文字サイズ","minFontSize",6.0,&s->min_font_size)||!b2026_pdf_pd_number(h,"左右余白","horizontalMargin",12.0*72.0/25.4/factor,&s->margin)||!b2026_pdf_pd_number(h,"ヘッダー位置","headerPosition",10.0*72.0/25.4/factor,&s->header_y)||!b2026_pdf_pd_number(h,"フッター位置","footerPosition",10.0*72.0/25.4/factor,&s->footer_y)||!b2026_pdf_pd_number(h,"不透明度","opacity",1.0,&s->opacity)||!b2026_pdf_pd_number(h,"行間","lineSpacing",1.2,&s->line_spacing))return 0;
    s->margin*=factor;s->header_y*=factor;s->footer_y*=factor;s->auto_shrink=!b2026_pdf_tf_entry(h,"自動縮小","autoShrink")||b2026_pdf_tf_true(h,"自動縮小","autoShrink");
    color=b2026_pdf_tf_text(h,"文字色","color");if(!b2026_pdf_pd_color(color,&s->color))return 0;
    if(!isfinite(s->start)||floor(s->start)!=s->start||s->start<(double)INT_MIN||s->start>(double)INT_MAX||!isfinite(s->digits)||floor(s->digits)!=s->digits||s->digits<0.0||s->digits>32.0||s->font_size<=0.0||s->min_font_size<=0.0||s->min_font_size>s->font_size||s->margin<0.0||s->header_y<0.0||s->footer_y<0.0||s->opacity<0.0||s->opacity>1.0||s->line_spacing<=0.0)return 0;
    if(!(b2026_strcasecmp(s->odd_even,"ALL")==0||strcmp(s->odd_even,"すべて")==0||b2026_strcasecmp(s->odd_even,"ODD")==0||strcmp(s->odd_even,"奇数")==0||b2026_strcasecmp(s->odd_even,"EVEN")==0||strcmp(s->odd_even,"偶数")==0))return 0;
    if(!(b2026_strcasecmp(s->position,"FOREGROUND")==0||strcmp(s->position,"前面")==0||b2026_strcasecmp(s->position,"BACKGROUND")==0||strcmp(s->position,"背面")==0))return 0;
    if(!(b2026_strcasecmp(s->structure,"ARTIFACT")==0||b2026_strcasecmp(s->structure,"CONTENT")==0))return 0;
    if(!(b2026_strcasecmp(s->existing,"REPLACE")==0||b2026_strcasecmp(s->existing,"ADD")==0||b2026_strcasecmp(s->existing,"ERROR")==0))return 0;
    if(!(b2026_strcasecmp(s->digit_font,"GOTHIC")==0||b2026_strcasecmp(s->digit_font,"BUILTIN")==0))return 0;
    return 1;
}

static char *b2026_pdf_pd_hex_bytes(const char *s){
    static const char hex[]="0123456789ABCDEF";size_t i,n=s!=NULL?strlen(s):0U;char *r;if(n>(SIZE_MAX-1U)/2U)return NULL;r=(char*)malloc(n*2U+1U);if(r==NULL)return NULL;for(i=0;i<n;++i){r[i*2U]=hex[((unsigned char)s[i])>>4];r[i*2U+1U]=hex[((unsigned char)s[i])&15U];}r[n*2U]='\0';return r;
}
static int b2026_pdf_pd_stream_marker(B2026PdfObject *o,const char *hex_id,int all){
    const char *prefix="%BASIC2026-DECORATION:";const unsigned char *p=b2026_pdf_memfind(o->body,o->body_length,prefix,strlen(prefix));size_t n;if(p==NULL)return 0;if(all)return 1;p+=strlen(prefix);n=strlen(hex_id);return (size_t)(o->body+o->body_length-p)>n&&memcmp(p,hex_id,n)==0&&(p[n]=='\r'||p[n]=='\n');
}
static int b2026_pdf_pd_contents_refs(B2026PdfDocument *doc,int page,int remove,const char *hex_id,int all,int *matches){
    B2026PdfObject *o=&doc->objects[page];B2026PdfKeyRange r;B2026PdfTextBuffer out;size_t p,end;memset(&out,0,sizeof(out));if(!b2026_pdf_tf_find_key(o->body,o->body_length,"/Contents",&r))return 0;if(!r.found){*matches=0;return 1;}p=b2026_pdf_tf_space(o->body,o->body_length,r.value_start);end=r.value_end;if(!b2026_pdf_text_append_char(&out,'['))goto fail;
    while(p<end){char *e;long a,g;size_t q,u;int oi,marked;if(o->body[p]=='['||o->body[p]==']'||isspace(o->body[p])){++p;continue;}if(!isdigit(o->body[p]))goto fail;a=strtol((const char*)o->body+p,&e,10);q=b2026_pdf_tf_space(o->body,end,(size_t)(e-(char*)o->body));if(q>=end||!isdigit(o->body[q]))goto fail;g=strtol((const char*)o->body+q,&e,10);u=b2026_pdf_tf_space(o->body,end,(size_t)(e-(char*)o->body));if(u>=end||o->body[u]!='R'||a<=0||a>INT_MAX||g<0||g>INT_MAX||(oi=b2026_pdf_object_lookup(doc,(int)a,(int)g))<0)goto fail;marked=b2026_pdf_pd_stream_marker(&doc->objects[oi],hex_id,all);if(marked){++*matches;if(remove)doc->objects[oi].included=0;}if(!(remove&&marked)){char ref[64];snprintf(ref,sizeof(ref)," %ld %ld R",a,g);if(!b2026_pdf_text_append_bytes(&out,ref,strlen(ref)))goto fail;}p=u+1U;}
    if(!b2026_pdf_text_append_bytes(&out," ]",2U))goto fail;if(remove&&!b2026_pdf_tf_set_key(doc,page,"/Contents",out.data,0))goto fail;free(out.data);return 1;
fail:free(out.data);return 0;
}
static int b2026_pdf_pd_remove(B2026PdfDocument *doc,const char *id,int all,int *count){
    char *hex_id=b2026_pdf_pd_hex_bytes(id!=NULL?id:"");int i;*count=0;if(hex_id==NULL)return 0;for(i=0;i<doc->page_count;++i){int n=0;if(!b2026_pdf_pd_contents_refs(doc,doc->page_objects[i],1,hex_id,all,&n)){free(hex_id);return 0;}*count+=n;}free(hex_id);return 1;
}
static int b2026_pdf_pd_has(B2026PdfDocument *doc,const char *id,int *count){
    char *hex_id=b2026_pdf_pd_hex_bytes(id);int i;*count=0;if(hex_id==NULL)return 0;for(i=0;i<doc->page_count;++i){int n=0;if(!b2026_pdf_pd_contents_refs(doc,doc->page_objects[i],0,hex_id,0,&n)){free(hex_id);return 0;}*count+=n;}free(hex_id);return 1;
}
static int b2026_pdf_pd_has_any(B2026PdfDocument *doc,int *count){
    int i;*count=0;for(i=0;i<doc->page_count;++i){int n=0;if(!b2026_pdf_pd_contents_refs(doc,doc->page_objects[i],0,"",1,&n))return 0;*count+=n;}return 1;
}

static char *b2026_pdf_pd_utf16_hex(const char *text){
    const unsigned char *p=(const unsigned char*)(text!=NULL?text:"");B2026PdfTextBuffer b;static const char hx[]="0123456789ABCDEF";memset(&b,0,sizeof(b));while(*p){unsigned int cp;int n;if(p[0]<0x80U){cp=p[0];n=1;}else if((p[0]&0xE0U)==0xC0U&&p[1]){cp=((p[0]&31U)<<6)|(p[1]&63U);n=2;}else if((p[0]&0xF0U)==0xE0U&&p[1]&&p[2]){cp=((p[0]&15U)<<12)|((p[1]&63U)<<6)|(p[2]&63U);n=3;}else if((p[0]&0xF8U)==0xF0U&&p[1]&&p[2]&&p[3]){cp=((p[0]&7U)<<18)|((p[1]&63U)<<12)|((p[2]&63U)<<6)|(p[3]&63U);n=4;}else{cp=0xFFFDU;n=1;}p+=n;if(cp>0x10FFFFU||(cp>=0xD800U&&cp<=0xDFFFU))cp=0xFFFDU;if(cp>0xFFFFU){unsigned int q=cp-0x10000U,u[2]={0xD800U+(q>>10),0xDC00U+(q&1023U)};int k;for(k=0;k<2;++k){char z[4]={hx[(u[k]>>12)&15U],hx[(u[k]>>8)&15U],hx[(u[k]>>4)&15U],hx[u[k]&15U]};if(!b2026_pdf_text_append_bytes(&b,z,4U))goto fail;}}else{char z[4]={hx[(cp>>12)&15U],hx[(cp>>8)&15U],hx[(cp>>4)&15U],hx[cp&15U]};if(!b2026_pdf_text_append_bytes(&b,z,4U))goto fail;}}return b2026_pdf_text_take(&b);fail:free(b.data);return NULL;
}
static double b2026_pdf_pd_width(const char *s,double size){const unsigned char *p=(const unsigned char*)(s!=NULL?s:"");double w=0.0;while(*p){if(*p<0x80U){w+=(*p==' '?0.28:0.56)*size;++p;}else{w+=size;if((*p&0xE0U)==0xC0U&&p[1])p+=2;else if((*p&0xF0U)==0xE0U&&p[1]&&p[2])p+=3;else if((*p&0xF8U)==0xF0U&&p[1]&&p[2]&&p[3])p+=4;else ++p;}}return w;}
static char *b2026_pdf_pd_fit(const char *s,double size,double width){
    const unsigned char *p=(const unsigned char*)(s!=NULL?s:""),*last=p;double used=0.0;size_t n;if(b2026_pdf_pd_width(s,size)<=width)return b2026_strdup_simple(s);while(*p){int span=1;double add;if(*p<0x80U){add=(*p==' '?0.28:0.56)*size;}else{add=size;if((*p&0xE0U)==0xC0U&&p[1])span=2;else if((*p&0xF0U)==0xE0U&&p[1]&&p[2])span=3;else if((*p&0xF8U)==0xF0U&&p[1]&&p[2]&&p[3])span=4;}if(used+add+1.68*size>width)break;used+=add;p+=span;last=p;}n=(size_t)(last-(const unsigned char*)s);{char *r=(char*)malloc(n+4U);if(r==NULL)return NULL;memcpy(r,s,n);memcpy(r+n,"...",4U);return r;}}

static char *b2026_pdf_pd_basename(const char *path,int no_ext){
    const char *a=strrchr(path!=NULL?path:"",'/'),*b=strrchr(path!=NULL?path:"",'\\'),*s;char *r,*dot;size_t n;if(b!=NULL&&(a==NULL||b>a))a=b;s=a!=NULL?a+1:(path!=NULL?path:"");n=strlen(s);r=(char*)malloc(n+1U);if(r==NULL)return NULL;memcpy(r,s,n+1U);if(no_ext&&(dot=strrchr(r,'.'))!=NULL)*dot='\0';return r;
}
static char *b2026_pdf_pd_absolute(const char *path){
    char cwd[4096];size_t a,b;char sep='/';char *r;if(path==NULL)return b2026_strdup_simple("");
#ifdef _WIN32
    if((isalpha((unsigned char)path[0])&&path[1]==':')||path[0]=='\\'||path[0]=='/')return b2026_strdup_simple(path);sep='\\';
#else
    if(path[0]=='/')return b2026_strdup_simple(path);
#endif
    if(b2026_getcwd(cwd,sizeof(cwd))==NULL)return b2026_strdup_simple(path);a=strlen(cwd);b=strlen(path);r=(char*)malloc(a+b+2U);if(r==NULL)return NULL;memcpy(r,cwd,a);r[a]=sep;memcpy(r+a+1U,path,b+1U);return r;
}
static char *b2026_pdf_pd_directory(const char *path){char *r=b2026_strdup_simple(path!=NULL?path:"");char *a,*b;if(r==NULL)return NULL;a=strrchr(r,'/');b=strrchr(r,'\\');if(b!=NULL&&(a==NULL||b>a))a=b;if(a==NULL){r[0]='.';r[1]='\0';}else if(a==r)a[1]='\0';else *a='\0';return r;}
static int b2026_pdf_pd_append(B2026PdfTextBuffer *b,const char *s){return b2026_pdf_text_append_bytes(b,s!=NULL?s:"",strlen(s!=NULL?s:""));}
static char *b2026_pdf_pd_replace(const char *source,const char *key,const char *value){
    B2026PdfTextBuffer b;const char *p=source,*q;size_t n=strlen(key);memset(&b,0,sizeof(b));while((q=strstr(p,key))!=NULL){if(!b2026_pdf_text_append_bytes(&b,p,(size_t)(q-p))||!b2026_pdf_pd_append(&b,value))goto fail;p=q+n;}if(!b2026_pdf_pd_append(&b,p))goto fail;return b2026_pdf_text_take(&b);fail:free(b.data);return NULL;
}
static char *b2026_pdf_pd_number_text(long value,const B2026PdfDecorationSettings *s){
    char buf[128];long n=value;const char *fmt=s->number_format;if(b2026_strcasecmp(fmt,"DECIMAL")==0){int d=(int)s->digits;if(d>0)snprintf(buf,sizeof(buf),"%0*ld",d,n);else snprintf(buf,sizeof(buf),"%ld",n);return b2026_strdup_simple(buf);}if(b2026_strcasecmp(fmt,"ROMAN_UPPER")==0||b2026_strcasecmp(fmt,"ROMAN_LOWER")==0){static const int v[]={1000,900,500,400,100,90,50,40,10,9,5,4,1};static const char *z[]={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};B2026PdfTextBuffer b;int i;memset(&b,0,sizeof(b));if(n<1||n>3999)return NULL;for(i=0;i<13;++i)while(n>=v[i]){if(!b2026_pdf_pd_append(&b,z[i])){free(b.data);return NULL;}n-=v[i];}if(b2026_strcasecmp(fmt,"ROMAN_LOWER")==0)for(i=0;i<(int)b.used;++i)b.data[i]=(char)tolower((unsigned char)b.data[i]);return b2026_pdf_text_take(&b);}if(b2026_strcasecmp(fmt,"ALPHA_UPPER")==0||b2026_strcasecmp(fmt,"ALPHA_LOWER")==0){char rev[64];int k=0,lower=b2026_strcasecmp(fmt,"ALPHA_LOWER")==0;if(n<1)return NULL;while(n>0&&k<60){--n;rev[k++]=(char)((lower?'a':'A')+(n%26));n/=26;}for(n=0;n<k/2;++n){char t=rev[n];rev[n]=rev[k-1-n];rev[k-1-n]=t;}rev[k]='\0';return b2026_strdup_simple(rev);}return NULL;
}
static char *b2026_pdf_pd_expand(const char *source,int page,int pages,int number,int numbers,const B2026PdfDecorationSettings *s,const char *path,const char *title,const char *date,const char *time_text){
    char a[64],b[64];char *num=b2026_pdf_pd_number_text(number,s),*filename=b2026_pdf_pd_basename(path,0),*basename=b2026_pdf_pd_basename(path,1),*absolute=b2026_pdf_pd_absolute(path),*directory=NULL,*r=NULL,*q=NULL;const char *keys[]={"%%","%PAGE%","%PAGES%","%NUMBER%","%NUMBERS%","%FILENAME%","%BASENAME%","%DIRECTORY%","%FILEPATH%","%TITLE%","%DATE%","%TIME%"};const char *vals[12];int i;if(num==NULL||filename==NULL||basename==NULL||absolute==NULL)goto done;directory=b2026_pdf_pd_directory(absolute);if(directory==NULL)goto done;snprintf(a,sizeof(a),"%d",page);snprintf(b,sizeof(b),"%d",pages);vals[0]="\001";vals[1]=a;vals[2]=b;vals[3]=num;{static char total[64];char *nt=b2026_pdf_pd_number_text(numbers,s);if(nt==NULL)goto done;snprintf(total,sizeof(total),"%s",nt);free(nt);vals[4]=total;}vals[5]=filename;vals[6]=basename;vals[7]=directory;vals[8]=absolute;vals[9]=title!=NULL?title:"";vals[10]=date;vals[11]=time_text;r=b2026_strdup_simple(source!=NULL?source:"");if(r==NULL)goto done;for(i=0;i<12;++i){q=b2026_pdf_pd_replace(r,keys[i],vals[i]);free(r);r=q;if(r==NULL)goto done;}for(i=0;r[i];++i)if(r[i]=='\001')r[i]='%';
done:free(num);free(filename);free(basename);free(absolute);free(directory);return r;
}

static int b2026_pdf_pd_font_resources(B2026PdfDocument *doc,int page,int latin_number,int japan_number,int gs_number){
    const unsigned char *v;size_t n;char *resources=NULL,*fonts=NULL,*states=NULL,*next=NULL;int ri,fi;B2026PdfKeyRange r;char ref[64];if(b2026_pdf_tf_inherited_value(doc,page,"/Resources",&v,&n))resources=b2026_pdf_tf_value_copy(doc,v,n,1);else resources=b2026_strdup_simple("<< >>");if(resources==NULL)return 0;ri=b2026_pdf_tf_add_body(doc,resources);free(resources);if(ri<0)return 0;if(!b2026_pdf_tf_find_key(doc->objects[ri].body,doc->objects[ri].body_length,"/Font",&r))return 0;if(r.found)fonts=b2026_pdf_tf_value_copy(doc,doc->objects[ri].body+r.value_start,r.value_end-r.value_start,1);else fonts=b2026_strdup_simple("<< >>");fi=b2026_pdf_tf_add_body(doc,fonts);free(fonts);if(fi<0)return 0;snprintf(ref,sizeof(ref),"%d 0 R",latin_number);if(!b2026_pdf_tf_set_key(doc,fi,"/B2026HF",ref,0))return 0;if(japan_number>0){snprintf(ref,sizeof(ref),"%d 0 R",japan_number);if(!b2026_pdf_tf_set_key(doc,fi,"/B2026JP",ref,0))return 0;}snprintf(ref,sizeof(ref),"%d 0 R",doc->objects[fi].old_number);if(!b2026_pdf_tf_set_key(doc,ri,"/Font",ref,0))return 0;if(gs_number>0){if(!b2026_pdf_tf_find_key(doc->objects[ri].body,doc->objects[ri].body_length,"/ExtGState",&r))return 0;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,"/B2026GS",gs_number);free(states);if(next==NULL||!b2026_pdf_tf_set_key(doc,ri,"/ExtGState",next,0)){free(next);return 0;}free(next);}snprintf(ref,sizeof(ref),"%d 0 R",doc->objects[ri].old_number);return b2026_pdf_tf_set_key(doc,page,"/Resources",ref,0);
}
static int b2026_pdf_pd_fonts(B2026PdfDocument *doc,double opacity,int need_japan,int gothic,int *latin,int *japan,int *gs){
    int descendant;char body[256];*latin=b2026_pdf_tf_add_body(doc,gothic?"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >>":"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>");if(*latin<0)return 0;*japan=-1;if(need_japan){descendant=b2026_pdf_tf_add_body(doc,"<< /Type /Font /Subtype /CIDFontType0 /BaseFont /HeiseiKakuGo-W5 /CIDSystemInfo << /Registry (Adobe) /Ordering (Japan1) /Supplement 5 >> /DW 1000 >>");if(descendant<0)return 0;snprintf(body,sizeof(body),"<< /Type /Font /Subtype /Type0 /BaseFont /HeiseiKakuGo-W5 /Encoding /UniJIS-UTF16-H /DescendantFonts [%d 0 R] >>",doc->objects[descendant].old_number);*japan=b2026_pdf_tf_add_body(doc,body);if(*japan<0)return 0;}*gs=-1;if(opacity<0.999999){snprintf(body,sizeof(body),"<< /Type /ExtGState /ca %.6f /CA %.6f >>",opacity,opacity);*gs=b2026_pdf_tf_add_body(doc,body);if(*gs<0)return 0;}return 1;
}
static int b2026_pdf_pd_box(B2026PdfDocument *doc,int page,const char *name,double box[4]){const char *key;if(!b2026_pdf_tf_box_key(name,&key))return 0;if(b2026_pdf_page_box(doc,page,key,box))return 1;if(strcmp(key,"/CropBox")!=0&&b2026_pdf_page_box(doc,page,"/CropBox",box)){b2026_pdf_log_warning("指定ページボックスがないためCropBoxを使用しました。 / Requested page box was missing; CropBox was used.");return 1;}if(b2026_pdf_page_box(doc,page,"/MediaBox",box)){b2026_pdf_log_warning("指定ページボックスがないためMediaBoxを使用しました。 / Requested page box was missing; MediaBox was used.");return 1;}return 0;}
static void b2026_pdf_pd_matrix(int rot,const double box[4],double *a,double *b,double *c,double *d,double *e,double *f){double x0,y0,x1,y1,x2,y2;b2026_pdf_tf_display_to_raw(rot,box,0,0,&x0,&y0);b2026_pdf_tf_display_to_raw(rot,box,1,0,&x1,&y1);b2026_pdf_tf_display_to_raw(rot,box,0,1,&x2,&y2);*a=x1-x0;*b=y1-y0;*c=x2-x0;*d=y2-y0;*e=x0;*f=y0;}
static void b2026_pdf_pd_time_format(const char *source,char *out,size_t cap){
    B2026PdfTextBuffer b;const char *p=source!=NULL?source:"";memset(&b,0,sizeof(b));if(strchr(p,'%')!=NULL){snprintf(out,cap,"%s",p);return;}while(*p){const char *r=NULL;if(strncmp(p,"YYYY",4U)==0)r="%Y";else if(strncmp(p,"MM",2U)==0)r="%m";else if(strncmp(p,"DD",2U)==0)r="%d";else if(strncmp(p,"HH",2U)==0)r="%H";else if(strncmp(p,"mm",2U)==0)r="%M";else if(strncmp(p,"ss",2U)==0)r="%S";if(r!=NULL){if(!b2026_pdf_pd_append(&b,r))break;p+=strlen(r)==2U&&(r[1]=='Y')?4U:2U;}else{if(!b2026_pdf_text_append_char(&b,*p++))break;}}snprintf(out,cap,"%s",b.data!=NULL?b.data:"");free(b.data);
}
static int b2026_pdf_pd_emit_slot(B2026PdfTextBuffer *out,const char *text,int slot,double page_w,double page_h,const B2026PdfDecorationSettings *s,int page,int pages,int number,int numbers,const char *path,const char *title,const char *date,const char *time_text){
    char *expanded=b2026_pdf_pd_expand(text,page,pages,number,numbers,s,path,title,date,time_text),*cursor;double size=s->font_size,area=(page_w-2.0*s->margin)/3.0,maxw=0.0,x,y,leading;int lines=1,i,align=slot%3;if(expanded==NULL)return 0;for(cursor=expanded;*cursor;++cursor)if(*cursor=='\n')++lines;if(lines>16){free(expanded);return -1;}for(cursor=expanded;;){char *nl=strchr(cursor,'\n');char save=0;if(nl!=NULL){save=*nl;*nl='\0';}maxw=fmax(maxw,b2026_pdf_pd_width(cursor,size));if(nl!=NULL){*nl=save;cursor=nl+1;}else break;}if(maxw>area&&s->auto_shrink)size=fmax(s->min_font_size,size*area/maxw);leading=size*s->line_spacing;cursor=expanded;for(i=0;i<lines;++i){char *nl=strchr(cursor,'\n'),*shown,*hex;char save=0;double w;int nonascii=0,j;if(nl!=NULL){save=*nl;*nl='\0';}shown=b2026_pdf_pd_fit(cursor,size,area);if(nl!=NULL)*nl=save;if(shown==NULL){free(expanded);return 0;}for(j=0;shown[j];++j)if((unsigned char)shown[j]>=0x80U){nonascii=1;break;}w=b2026_pdf_pd_width(shown,size);x=s->margin+(double)(slot%3)*area+(align==0?0.0:(align==1?(area-w)/2.0:area-w));y=slot<3?page_h-s->header_y-size-(double)i*leading:s->footer_y+(double)(lines-1-i)*leading;{char cmd[1024];if(nonascii){hex=b2026_pdf_pd_utf16_hex(shown);if(hex==NULL){free(shown);free(expanded);return 0;}snprintf(cmd,sizeof(cmd),"BT /B2026JP %.6f Tf %.6f %.6f %.6f rg 1 0 0 1 %.6f %.6f Tm <%s> Tj ET\n",size,((s->color>>16)&255U)/255.0,((s->color>>8)&255U)/255.0,(s->color&255U)/255.0,x,y,hex);free(hex);}else{B2026PdfTextBuffer esc;const unsigned char *p=(const unsigned char*)shown;memset(&esc,0,sizeof(esc));while(*p){if((*p=='('||*p==')'||*p=='\\')&&!b2026_pdf_text_append_char(&esc,'\\')){free(esc.data);free(shown);free(expanded);return 0;}if(!b2026_pdf_text_append_char(&esc,(char)*p++)){free(esc.data);free(shown);free(expanded);return 0;}}snprintf(cmd,sizeof(cmd),"BT /B2026HF %.6f Tf %.6f %.6f %.6f rg 1 0 0 1 %.6f %.6f Tm (%s) Tj ET\n",size,((s->color>>16)&255U)/255.0,((s->color>>8)&255U)/255.0,(s->color&255U)/255.0,x,y,esc.data!=NULL?esc.data:"");free(esc.data);}free(shown);if(!b2026_pdf_pd_append(out,cmd)){free(expanded);return 0;}}if(nl!=NULL)cursor=nl+1;}free(expanded);return 1;
}
static int b2026_pdf_pd_add(B2026PdfDocument *doc,const B2026PdfDecorationSettings *s,const char *path,unsigned char *selected,int selected_count){
    int latin,japan,gs,i,k,sequence=0,need_japan=0,path_token=0;char *hex_id=b2026_pdf_pd_hex_bytes(s->id),*title=NULL;time_t now=time(NULL);struct tm local_time;char date[128],clock_text[128],date_format[128],time_format[128];for(k=0;k<6;++k)if(s->slot[k]!=NULL){const unsigned char *q=(const unsigned char*)s->slot[k];if(strstr(s->slot[k],"%FILEPATH%")!=NULL||strstr(s->slot[k],"%DIRECTORY%")!=NULL)path_token=1;while(*q)if(*q++>=0x80U){need_japan=1;break;}}if(path_token&&path!=NULL){const unsigned char *q=(const unsigned char*)path;while(*q)if(*q++>=0x80U){need_japan=1;break;}}if(hex_id==NULL||!b2026_pdf_pd_fonts(doc,s->opacity,need_japan,b2026_strcasecmp(s->digit_font,"GOTHIC")==0,&latin,&japan,&gs)){free(hex_id);return 0;}if(doc->info_object>=0)title=b2026_pdf_dict_string(doc,doc->objects[doc->info_object].body,doc->objects[doc->info_object].body_length,"/Title");if(title==NULL)title=b2026_strdup_simple("");if(title==NULL){free(hex_id);return 0;}
#ifdef _WIN32
    localtime_s(&local_time,&now);
#else
    {struct tm *tmp=localtime(&now);if(tmp!=NULL)local_time=*tmp;else memset(&local_time,0,sizeof(local_time));}
#endif
    b2026_pdf_pd_time_format(s->date_format,date_format,sizeof(date_format));b2026_pdf_pd_time_format(s->time_format,time_format,sizeof(time_format));if(strftime(date,sizeof(date),date_format,&local_time)==0)date[0]='\0';if(strftime(clock_text,sizeof(clock_text),time_format,&local_time)==0)clock_text[0]='\0';
    for(i=0;i<doc->page_count;++i)if(selected[i]){int page=doc->page_objects[i],rot=b2026_pdf_page_inherited_integer(doc,page,"/Rotate",0),stream,k,rc;double box[4],w,h,a,b,c,d,e,f;B2026PdfTextBuffer content;char marker[1024],matrix[256];++sequence;if(!b2026_pdf_pd_box(doc,page,s->box_name,box)){free(hex_id);free(title);return 0;}rot=((rot%360)+360)%360;if(rot%90!=0){free(hex_id);free(title);return 0;}w=(rot==90||rot==270)?box[3]-box[1]:box[2]-box[0];h=(rot==90||rot==270)?box[2]-box[0]:box[3]-box[1];b2026_pdf_pd_matrix(rot,box,&a,&b,&c,&d,&e,&f);memset(&content,0,sizeof(content));snprintf(marker,sizeof(marker),"%%BASIC2026-DECORATION:%s\nq\n",hex_id);if(!b2026_pdf_pd_append(&content,marker))goto fail;snprintf(matrix,sizeof(matrix),"%.12f %.12f %.12f %.12f %.12f %.12f cm\n",a,b,c,d,e,f);if(!b2026_pdf_pd_append(&content,matrix))goto fail;if(gs>=0&&!b2026_pdf_pd_append(&content,"/B2026GS gs\n"))goto fail;if(b2026_strcasecmp(s->structure,"ARTIFACT")==0&&!b2026_pdf_pd_append(&content,"/Artifact BMC\n"))goto fail;for(k=0;k<6;++k)if(s->slot[k]!=NULL&&*s->slot[k]){rc=b2026_pdf_pd_emit_slot(&content,s->slot[k],k,w,h,s,i+1,doc->page_count,(int)s->start+sequence-1,selected_count,path,title,date,clock_text);if(rc<=0){free(content.data);free(hex_id);free(title);return rc;}}if(b2026_strcasecmp(s->structure,"ARTIFACT")==0&&!b2026_pdf_pd_append(&content,"EMC\n"))goto fail;if(!b2026_pdf_pd_append(&content,"Q"))goto fail;stream=b2026_pdf_tf_add_stream(doc,content.data!=NULL?content.data:"");free(content.data);if(stream<0||!b2026_pdf_pd_font_resources(doc,page,doc->objects[latin].old_number,japan>=0?doc->objects[japan].old_number:-1,gs>=0?doc->objects[gs].old_number:-1)||!b2026_pdf_tf_append_contents(doc,page,(b2026_strcasecmp(s->position,"BACKGROUND")==0||strcmp(s->position,"背面")==0)?stream:-1,(b2026_strcasecmp(s->position,"BACKGROUND")==0||strcmp(s->position,"背面")==0)?-1:stream)){free(hex_id);free(title);return 0;}}
    free(hex_id);free(title);return 1;
fail:free(hex_id);free(title);return 0;
}
static int b2026_pdf_pd_selection(B2026PdfDocument *doc,const B2026PdfDecorationSettings *s,unsigned char **out,int *count){
    B2026PdfArg a;unsigned char *selected=NULL,*excluded=NULL;int i,odd=b2026_strcasecmp(s->odd_even,"ODD")==0||strcmp(s->odd_even,"奇数")==0,even=b2026_strcasecmp(s->odd_even,"EVEN")==0||strcmp(s->odd_even,"偶数")==0;memset(&a,0,sizeof(a));a.kind=1;a.text=s->page_spec;if(!b2026_pdf_parse_page_spec(&a,doc->page_count,&selected))return 0;if(s->exclude_spec!=NULL){a.text=s->exclude_spec;if(!b2026_pdf_parse_page_spec(&a,doc->page_count,&excluded)){free(selected);return 0;}}*count=0;for(i=0;i<doc->page_count;++i){if(excluded!=NULL&&excluded[i])selected[i]=0;if(odd&&((i+1)%2)==0)selected[i]=0;if(even&&((i+1)%2)!=0)selected[i]=0;if(selected[i])++*count;}free(excluded);if(*count==0){free(selected);return 0;}*out=selected;return 1;
}
static int b2026_pdf_pd_verify(const char *path,int expected_pages,const char *id,int all,int expect_present){B2026PdfDocument doc;int rc,count=0;memset(&doc,0,sizeof(doc));rc=b2026_pdf_load(&doc,path,0);if(rc<=0||doc.page_count!=expected_pages){b2026_pdf_document_free(&doc);return 0;}if(all){if(!b2026_pdf_pd_has_any(&doc,&count)){b2026_pdf_document_free(&doc);return 0;}}else if(id!=NULL&&!b2026_pdf_pd_has(&doc,id,&count)){b2026_pdf_document_free(&doc);return 0;}b2026_pdf_document_free(&doc);return (id==NULL&&!all)||((count>0)==expect_present);}
static const char *b2026_pdf_page_decoration(const char *operation,int argc,const B2026PdfArg *args){
    int remove=strcmp(operation,"REMOVEPAGEDECORATION")==0,page_number=strcmp(operation,"PAGENUMBER")==0,separate,source_index,rc,i,old_count=0,removed=0,selected_count=0,remove_all=0;const char *source,*remove_id=NULL;char *output=NULL,*stage=NULL;HashVariable *hash=NULL;B2026PdfDecorationSettings settings;B2026PdfDocument doc;B2026PdfPageList pages;unsigned char *selected=NULL;const char *result;memset(&doc,0,sizeof(doc));memset(&pages,0,sizeof(pages));
    if(remove){if(argc!=2&&argc!=3)return b2026_pdf_fail(4220,"","page-decoration removal requires path/settings or output/source/settings / ページ装飾削除の引数が正しくありません");separate=argc==3;}else if(page_number){if(argc<1||argc>3)return b2026_pdf_fail(4220,"","page numbering arguments are invalid / ページ番号の引数が正しくありません");separate=argc==3||(argc==2&&args[1].kind==1);}else{if(argc!=2&&argc!=3)return b2026_pdf_fail(4220,"","page decoration requires path/settings or output/source/settings / ページ装飾の引数が正しくありません");separate=argc==3;}
    source_index=separate?1:0;if(args[0].kind!=1||(separate&&args[1].kind!=1))return b2026_pdf_fail(4220,"","PDF path must be a string / PDFパスは文字列で指定してください");if(args[argc-1].kind==3){if(!b2026_pdf_tf_hash(&args[argc-1],&hash))return b2026_pdf_fail(4220,"","decoration settings do not exist / 装飾設定の連想配列がありません");}else if(!page_number)return b2026_pdf_fail(4220,"","decoration settings are required / 装飾設定が必要です");
    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(4221,source,b2026_pdf_load_error(rc));goto fail;}
    if(remove){remove_id=b2026_pdf_tf_text(hash,"装飾ID","decorationId");remove_all=b2026_pdf_tf_true(hash,"すべて","all");if(!remove_all&&(remove_id==NULL||*remove_id=='\0')){b2026_pdf_fail(4222,source,"decorationId or all=1 is required / 装飾IDまたはすべて=1が必要です");goto fail;}if(!b2026_pdf_pd_remove(&doc,remove_id,remove_all,&removed))goto memory_fail;if(removed==0){b2026_pdf_fail(4223,source,"specified decoration ID was not detected; merged/flattened decorations cannot be removed / 指定された装飾IDを検出できません。統合・平坦化された装飾は削除できません");goto fail;}}
    else{if(!b2026_pdf_pd_settings(hash,page_number,&settings)){b2026_pdf_fail(4222,source,"invalid page-decoration settings / ページ装飾設定が正しくありません");goto fail;}if(!b2026_pdf_pd_has(&doc,settings.id,&old_count))goto memory_fail;if(old_count>0&&b2026_strcasecmp(settings.existing,"ERROR")==0){b2026_pdf_fail(4224,source,"decoration ID already exists / 同じ装飾IDがすでに存在します");goto fail;}if(old_count>0&&b2026_strcasecmp(settings.existing,"REPLACE")==0&&!b2026_pdf_pd_remove(&doc,settings.id,0,&removed))goto memory_fail;if(!b2026_pdf_pd_selection(&doc,&settings,&selected,&selected_count)){b2026_pdf_fail(4225,source,"no pages were selected or page specification is invalid / 対象ページがないかページ指定が正しくありません");goto fail;}rc=b2026_pdf_pd_add(&doc,&settings,source,selected,selected_count);if(rc<0){b2026_pdf_fail(4226,source,"header/footer text exceeds the 16-line limit / ヘッダー・フッター文字列が16行上限を超えています");goto fail;}if(rc==0)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,0)){if(stage!=NULL)b2026_atomic_discard_file(stage);b2026_pdf_fail(4227,output,"decorated PDF could not be written or exceeded 2 GiB / 装飾PDFを保存できないか2GiB上限を超えました");goto fail;}if(!b2026_pdf_pd_verify(stage,doc.page_count,remove?remove_id:settings.id,remove?remove_all:0,remove?0:1)){b2026_atomic_discard_file(stage);b2026_pdf_fail(4228,output,"page-decoration post-write verification failed / ページ装飾の保存後検証に失敗しました");goto fail;}if(!b2026_atomic_commit_file(stage,output)){b2026_atomic_discard_file(stage);b2026_pdf_fail(4229,output,"verified PDF could not be committed / 検証済みPDFを保存先へ反映できません");goto fail;}free(stage);stage=NULL;result=runtime_temp_string_copy(output);free(output);free(selected);free(pages.items);b2026_pdf_document_free(&doc);return result;
memory_fail:b2026_pdf_fail(4199,source,"out of memory or unsupported PDF page resources / メモリ不足または未対応のPDFページ資源です");
fail:if(stage!=NULL){b2026_atomic_discard_file(stage);free(stage);}free(output);free(selected);free(pages.items);b2026_pdf_document_free(&doc);return runtime_temp_string_copy("");
}
