在 Windows 上写入二进制文件时如何强制 1 字节填充 - 适用于 mac,不适用于 win

Posted

技术标签:

【中文标题】在 Windows 上写入二进制文件时如何强制 1 字节填充 - 适用于 mac,不适用于 win【英文标题】:how to force 1 byte padding when writing a binary file on windows - works on mac, not on win 【发布时间】:2011-05-01 18:08:18 【问题描述】:

断章取义很难解释,但我会尝试,因为它让我发疯。

我正在尝试根据 vst 2.4 规范编写一个二进制文件来表示 vst 音频插件的程序和库状态 - 程序是一个声音的参数值,而库是程序的集合(在我的案例 32)。我的程序保存/加载代码在 windows 和 mac 上运行良好。我的银行储蓄代码在 mac 上运行良好——我可以从我的插件中保存状态,并通过 vst 主机的召回机制打开它。我在 mac 上创建的文件可由 mac 主机和 windows 主机加载,表明这是保存“正确”的 vst 银行文件格式。然而,在 Windows 上,我在 vst 银行文件中获得了额外的字节,它不会通过主机机制加载。我认为这是因为在 Windows 上有一些填充。在较小的 vst 程序文件中似乎不会发生这种情况。我在许多不同的地方尝试过#pragma pack(push, 1) 无济于事。谁能建议我可以做些什么来解决这个问题或可能是什么原因?

谢谢

mac 十六进制好:

赢十六进制错误:

这里是代码。 vst fxb 文件格式需要大端数据,因此需要字节交换。更多信息在这里:http://forum.cockos.com/showthread.php?t=78573

bool IPlugBase::SaveBankAsFXB(const char* defaultFileName)

  if (mGraphics)
  
    WDL_String fileName(defaultFileName, strlen(defaultFileName));
    mGraphics->PromptForFile(&fileName, IGraphics::kFileSave, "", "fxb");

    if (fileName.GetLength()) 
    
      FILE* fp = fopen(fileName.Get(), "w");

      VstInt32 chunkMagic = WDL_bswap_if_le('CcnK');
      VstInt32 byteSize = 0;
      VstInt32 fxbMagic;
      VstInt32 fxbVersion = WDL_bswap_if_le(kFXBVersionNum);
      VstInt32 pluginID = WDL_bswap_if_le(GetUniqueID());
      VstInt32 pluginVersion = WDL_bswap_if_le(GetEffectVersion(true));
      VstInt32 numPgms =  WDL_bswap_if_le(NPresets());
      VstInt32 currentPgm = WDL_bswap_if_le(GetCurrentPresetIdx());
      char future[124];
      memset(future, 0, 124);

      unsigned int bnkHeaderSize = 80;
      unsigned int pgmHeaderSize = 84;
      unsigned int pgmSize;
      unsigned int bnkSize; // total size in bytes

      unsigned int bytePos = 0;
      unsigned char *bnk;

      if (DoesStateChunks()) 
      
              //TODO
      
      else 
      
        pgmSize = NParams() * 4;
        bnkSize = bnkHeaderSize + (NPresets() * (pgmHeaderSize + pgmSize));

        bnk = new unsigned char[bnkSize];

        fxbMagic = WDL_bswap_if_le('FxBk');

        // fxb header
        memcpy(bnk + bytePos, &chunkMagic, 4);
        bytePos += 4;
        memcpy(bnk + bytePos, &byteSize, 4);
        bytePos += 4;
        memcpy(bnk + bytePos, &fxbMagic, 4);
        bytePos += 4;
        memcpy(bnk + bytePos, &fxbVersion, 4);
        bytePos += 4;
        memcpy(bnk + bytePos, &pluginID, 4);
        bytePos += 4;
        memcpy(bnk + bytePos, &pluginVersion, 4);
        bytePos += 4;
        memcpy(bnk + bytePos, &numPgms, 4);
        bytePos += 4;
        memcpy(bnk + bytePos, &currentPgm, 4);
        bytePos += 4;
        memcpy(bnk + bytePos, &future, 124);
        bytePos += 124;

        VstInt32 fxpMagic = WDL_bswap_if_le('FxCk'); 
        VstInt32 fxpVersion = WDL_bswap_if_le(kFXPVersionNum);
        VstInt32 numParams = WDL_bswap_if_le(NParams());

        for (int p = 0; p < NPresets(); p++) 
        
          IPreset* pPreset = mPresets.Get(p);

          char prgName[28];
          memset(prgName, 0, 28);
          strcpy(prgName, pPreset->mName);

          //fxp header
          memcpy(bnk + bytePos, &chunkMagic, 4);
          bytePos += 4;
          memcpy(bnk + bytePos, &byteSize, 4);
          bytePos += 4;
          memcpy(bnk + bytePos, &fxpMagic, 4);
          bytePos += 4;
          memcpy(bnk + bytePos, &fxpVersion, 4);
          bytePos += 4;
          memcpy(bnk + bytePos, &pluginID, 4);
          bytePos += 4;
          memcpy(bnk + bytePos, &pluginVersion, 4);
          bytePos += 4;
          memcpy(bnk + bytePos, &numParams, 4);
          bytePos += 4;
          memcpy(bnk + bytePos, &prgName, 28);
          bytePos += 28;

          //fxp data
          for (int i = 0; i< NParams(); i++) 
          
            double v;
            pPreset->mChunk.Get(&v, i * sizeof(double));
            WDL_EndianFloat v32;
            v32.f = (float) mParams.Get(i)->GetNormalized(v);
            unsigned int swapped = WDL_bswap_if_le(v32.int32);

            memcpy(bnk + bytePos, &swapped, 4);
            bytePos += 4;
          
        
      

      fwrite(bnk, bnkSize, 1, fp);
      fclose(fp);

      return true;
    
    return false;
  
  return false;

【问题讨论】:

【参考方案1】:

尝试将您的 fopen 呼叫更改为:

FILE* fp = fopen(fileName.Get(), "wb");

b 请求二进制模式,这应该防止任何类型的文本行尾标记处理。

请参阅 MSDN 上的 fopen 文档,了解在文本模式下会发生什么样的翻译。

【讨论】:

非常感谢!解决了它!

以上是关于在 Windows 上写入二进制文件时如何强制 1 字节填充 - 适用于 mac,不适用于 win的主要内容,如果未能解决你的问题,请参考以下文章

使用 ofstream 写入 txt 文件时强制编码

如何在Windows命令提示符下从十六进制字符串写入二进制文件

如何在文件写入时防止其他人读取/写入文件

如何在 Windows 上使用 Visual C++ 强制加载链接库

windows下如何强制git使用LF而不是CR+LF?

Windows-Service 中的 Serilog 未写入日志文件